diff --git a/antis-ncc-admin/.env.development b/antis-ncc-admin/.env.development index 4c02e12..e9a4583 100644 --- a/antis-ncc-admin/.env.development +++ b/antis-ncc-admin/.env.development @@ -2,6 +2,6 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true # VUE_APP_BASE_API = 'https://erp.lvqianmeiye.com' -VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com' -# VUE_APP_BASE_API = 'http://localhost:2011' +# VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com' +VUE_APP_BASE_API = 'http://localhost:2011' VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket' diff --git a/netcore/src/Modularity/Common/NCC.Common/Filter/PageInputBase.cs b/netcore/src/Modularity/Common/NCC.Common/Filter/PageInputBase.cs index c126f2c..3dfb0d7 100644 --- a/netcore/src/Modularity/Common/NCC.Common/Filter/PageInputBase.cs +++ b/netcore/src/Modularity/Common/NCC.Common/Filter/PageInputBase.cs @@ -21,7 +21,7 @@ namespace NCC.Common.Filter /// /// 每页行数 /// - public virtual int pageSize { get; set; } = 50; + public virtual int pageSize { get; set; } = 20; /// /// 排序字段:sortField diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByJksQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByJksQueryInput.cs new file mode 100644 index 0000000..7094e3c --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByJksQueryInput.cs @@ -0,0 +1,38 @@ +using NCC.Common.Filter; + +namespace NCC.Extend.Entitys.Dto.LqXhHyhk +{ + /// + /// 根据健康师ID查询耗卡列表输入 + /// + public class LqXhHyhkListByJksQueryInput : PageInputBase + { + /// + /// 健康师ID(必填) + /// + public string jksId { get; set; } + + /// + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string startTime { get; set; } + + /// + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string endTime { get; set; } + + /// + /// 门店ID(可选) + /// + public string md { get; set; } + + /// + /// 是否有效(可选,0=全部,1=有效,2=无效) + /// + public int isEffective { get; set; } = 1; + } +} + + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByKjbQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByKjbQueryInput.cs new file mode 100644 index 0000000..1931498 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListByKjbQueryInput.cs @@ -0,0 +1,38 @@ +using NCC.Common.Filter; + +namespace NCC.Extend.Entitys.Dto.LqXhHyhk +{ + /// + /// 根据科技部老师ID查询耗卡列表输入 + /// + public class LqXhHyhkListByKjbQueryInput : PageInputBase + { + /// + /// 科技部老师ID(必填) + /// + public string kjblsId { get; set; } + + /// + /// 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string startTime { get; set; } + + /// + /// 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// + public string endTime { get; set; } + + /// + /// 门店ID(可选) + /// + public string md { get; set; } + + /// + /// 是否有效(可选,0=全部,1=有效,2=无效) + /// + public int isEffective { get; set; } = 1; + } +} + + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListOutput.cs index 5d67139..01c61e3 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListOutput.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using NCC.Extend.Entitys.Dto.LqXhJksyj; +using NCC.Extend.Entitys.Dto.LqXhKjbsyj; using NCC.Extend.Entitys.Dto.LqXhPxmx; namespace NCC.Extend.Entitys.Dto.LqXhHyhk @@ -110,5 +112,15 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk /// public decimal? overtimeSgfy { get; set; } + /// + /// 健康师业绩列表 + /// + public List lqXhJksyjList { get; set; } + + /// + /// 科技部老师业绩列表 + /// + public List lqXhKjbsyjList { get; set; } + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListQueryInput.cs index d612c3f..3741c4c 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqXhHyhk/LqXhHyhkListQueryInput.cs @@ -79,5 +79,15 @@ namespace NCC.Extend.Entitys.Dto.LqXhHyhk /// public int isEffective { get; set; } = 0; + /// + /// 健康师ID(可选,用于过滤该健康师参与的耗卡) + /// + public string jksId { get; set; } + + /// + /// 科技部老师ID(可选,用于过滤该老师参与的耗卡) + /// + public string kjblsId { get; set; } + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetCrInput.cs index b08d789..cf25315 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetCrInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetCrInput.cs @@ -57,6 +57,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdTarget public decimal educationDepartmentTarget { get; set; } = 0; /// + /// 大项目部业绩目标 + /// + public decimal majorProjectDepartmentTarget { get; set; } = 0; + + /// /// 事业部总经理 /// public string businessUnitGeneralManager { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetInfoOutput.cs index 4815f50..9e1edc7 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetInfoOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetInfoOutput.cs @@ -58,6 +58,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdTarget public decimal educationDepartmentTarget { get; set; } /// + /// 大项目部业绩目标 + /// + public decimal majorProjectDepartmentTarget { get; set; } + + /// /// 事业部总经理 /// public string businessUnitGeneralManager { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetListOutput.cs index 9c43a9c..f30ee1e 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetListOutput.cs @@ -58,6 +58,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdTarget public decimal educationDepartmentTarget { get; set; } /// + /// 大项目部业绩目标 + /// + public decimal majorProjectDepartmentTarget { get; set; } + + /// /// 事业部总经理 /// public string businessUnitGeneralManager { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetUpInput.cs index 39e2295..e2620c0 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetUpInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/Dto/LqMdTarget/LqMdTargetUpInput.cs @@ -57,6 +57,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdTarget public decimal educationDepartmentTarget { get; set; } = 0; /// + /// 大项目部业绩目标 + /// + public decimal majorProjectDepartmentTarget { get; set; } = 0; + + /// /// 事业部总经理 /// public string businessUnitGeneralManager { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_target/LqMdTargetEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_target/LqMdTargetEntity.cs index bbc7f65..7af08e6 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_target/LqMdTargetEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_target/LqMdTargetEntity.cs @@ -72,6 +72,12 @@ namespace NCC.Extend.Entitys.lq_md_target public decimal EducationDepartmentTarget { get; set; } = 0; /// + /// 大项目部业绩目标 + /// + [SugarColumn(ColumnName = "F_MajorProjectDepartmentTarget")] + public decimal MajorProjectDepartmentTarget { get; set; } = 0; + + /// /// 事业部总经理 /// [SugarColumn(ColumnName = "F_BusinessUnitGeneralManager")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs index e525506..fe5f308 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs @@ -191,7 +191,7 @@ namespace NCC.Extend /// 返回说明: /// - StoreId: 门店ID /// - StoreName: 门店名称 - /// - TargetPerformance: 目标业绩(生命线,来自门店信息表) + /// - TargetPerformance: 目标业绩(门店目标业绩,来自门店目标表lq_md_target的F_StoreTarget字段,根据开始时间所在月份获取,如果未查询到则为0) /// - BillingPerformance: 开单业绩(开单业绩总和) /// - RefundPerformance: 退款业绩(退卡业绩总和) /// - ActualPerformance: 实际业绩(开单业绩 - 退款业绩) @@ -210,6 +210,9 @@ namespace NCC.Extend // 获取时间范围 var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + // 根据开始时间确定月份(YYYYMM格式) + var month = startDate.ToString("yyyyMM"); + // 构建门店过滤条件 var storeFilter = ""; if (input.StoreIds != null && input.StoreIds.Any()) @@ -223,8 +226,8 @@ namespace NCC.Extend SELECT store.F_Id as StoreId, store.dm as StoreName, - -- 目标业绩(生命线) - COALESCE(store.xsyj, 0) as TargetPerformance, + -- 目标业绩(门店目标业绩,来自门店目标表) + COALESCE(target.F_StoreTarget, 0) as TargetPerformance, -- 开单业绩总和 COALESCE(( SELECT SUM(billing.sfyj) @@ -236,7 +239,7 @@ namespace NCC.Extend ), 0) as BillingPerformance, -- 退款业绩总和(退卡业绩) COALESCE(( - SELECT SUM(refund.tkje) + SELECT SUM(refund.F_ActualRefundAmount) FROM lq_hytk_hytk refund WHERE refund.md = store.F_Id AND refund.F_IsEffective = 1 @@ -244,6 +247,7 @@ namespace NCC.Extend AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}' ), 0) as RefundPerformance FROM lq_mdxx store + LEFT JOIN lq_md_target target ON target.F_StoreId = store.F_Id AND target.F_Month = '{month}' WHERE 1=1 {storeFilter} ORDER BY (BillingPerformance - RefundPerformance) DESC"; @@ -298,10 +302,10 @@ namespace NCC.Extend /// 返回说明: /// - BusinessUnitId: 事业部ID /// - BusinessUnitName: 事业部名称 - /// - TargetPerformance: 目标业绩(管理门店的生命线总和) + /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target的F_BusinessUnitTarget字段,根据开始时间所在月份获取,通过F_BusinessUnit字段关联,如果未查询到则为0) /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) - /// - StoreCount: 门店数量 + /// - StoreCount: 门店数量(根据门店目标表中归属该事业部的门店数统计) /// /// 查询参数 /// 事业部业绩完成情况列表 @@ -315,6 +319,9 @@ namespace NCC.Extend // 获取时间范围 var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + // 根据开始时间确定月份(YYYYMM格式) + var month = startDate.ToString("yyyyMM"); + // 构建事业部过滤条件 var businessUnitFilter = ""; if (input.BusinessUnitIds != null && input.BusinessUnitIds.Any()) @@ -329,10 +336,10 @@ namespace NCC.Extend SELECT o.F_Id as BusinessUnitId, o.F_FullName as BusinessUnitName, - COALESCE(SUM(store.xsyj), 0) as TargetPerformance, - COUNT(DISTINCT store.F_Id) as StoreCount + COALESCE(SUM(target.F_BusinessUnitTarget), 0) as TargetPerformance, + COUNT(DISTINCT target.F_StoreId) as StoreCount FROM base_organize o - LEFT JOIN lq_mdxx store ON store.syb = o.F_Id + LEFT JOIN lq_md_target target ON target.F_BusinessUnit = o.F_Id AND target.F_Month = '{month}' WHERE o.F_Category = 'department' AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') @@ -432,10 +439,10 @@ namespace NCC.Extend /// 返回说明: /// - DepartmentId: 部门ID /// - DepartmentName: 部门名称(教育一部、教育二部、科技一部、科技二部、大项目一部、大项目二部) - /// - TargetPerformance: 目标业绩(管理门店的生命线总和) + /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target,根据部门类型使用对应字段:教育部使用F_EducationDepartmentTarget,科技部使用F_TechDepartmentTarget,大项目部使用F_MajorProjectDepartmentTarget,根据开始时间所在月份获取,通过对应归属字段关联,如果未查询到则为0) /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) - /// - StoreCount: 门店数量 + /// - StoreCount: 门店数量(根据门店目标表中归属该部门的门店数统计) /// /// 查询参数 /// 天王团业绩完成情况列表 @@ -449,6 +456,9 @@ namespace NCC.Extend // 获取时间范围 var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + // 根据开始时间确定月份(YYYYMM格式) + var month = startDate.ToString("yyyyMM"); + // 构建部门过滤条件 var departmentFilter = ""; if (input.DepartmentIds != null && input.DepartmentIds.Any()) @@ -457,12 +467,12 @@ namespace NCC.Extend departmentFilter = $"AND o.F_Id IN ('{filterDeptIdsStr}')"; } - // 天王团部门信息(字段名和部门名称的映射) - var tianwangDepartments = new Dictionary + // 天王团部门信息(字段名、目标字段名和部门名称的映射) + var tianwangDepartments = new Dictionary { - { "jyb", ("jyb", new[] { "教育一部", "教育二部" }) }, - { "kjb", ("kjb", new[] { "科技一部", "科技二部" }) }, - { "dxmb", ("dxmb", new[] { "大项目一部", "大项目二部" }) } + { "jyb", ("F_EducationDepartment", "F_EducationDepartmentTarget", new[] { "教育一部", "教育二部" }) }, + { "kjb", ("F_TechDepartment", "F_TechDepartmentTarget", new[] { "科技一部", "科技二部" }) }, + { "dxmb", ("F_MajorProjectDepartment", "F_MajorProjectDepartmentTarget", new[] { "大项目一部", "大项目二部" }) } }; // 分步查询,提高效率 @@ -480,10 +490,10 @@ namespace NCC.Extend SELECT o.F_Id as DepartmentId, o.F_FullName as DepartmentName, - COALESCE(SUM(store.xsyj), 0) as TargetPerformance, - COUNT(DISTINCT store.F_Id) as StoreCount + COALESCE(SUM(target.{deptType.Value.targetFieldName}), 0) as TargetPerformance, + COUNT(DISTINCT target.F_StoreId) as StoreCount FROM base_organize o - LEFT JOIN lq_mdxx store ON store.{deptType.Key} = o.F_Id + LEFT JOIN lq_md_target target ON target.{deptType.Value.fieldName} = o.F_Id AND target.F_Month = '{month}' WHERE o.F_Category = 'department' AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) AND o.F_FullName IN ('{deptNamesStr}') @@ -608,7 +618,7 @@ namespace NCC.Extend /// - ManagerId: 经理用户ID /// - ManagerName: 经理姓名 /// - StoreId/StoreName: 门店信息 - /// - Target1/2/3: 目标业绩一/二/三阶段(smx1/smx2/smx3) + /// - Target1/2/3: 目标业绩一/二/三阶段(来自门店总经理生命线设置表lq_md_general_manager_lifeline的F_Lifeline1/F_Lifeline2/F_Lifeline3字段,根据开始时间所在月份获取,如果未查询到则为0) /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) /// - CompletionRate1/2/3: 完成率各阶段(百分比) /// @@ -624,38 +634,41 @@ namespace NCC.Extend // 获取时间范围 var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + // 根据开始时间确定月份(YYYYMM格式) + var month = startDate.ToString("yyyyMM"); + // 构建经理过滤条件 var managerFilter = ""; if (!string.IsNullOrWhiteSpace(input.ManagerId)) { - managerFilter = $"AND target.zjl_userid = '{input.ManagerId}'"; + managerFilter = $"AND target.F_GeneralManagerId = '{input.ManagerId}'"; } // SQL查询:获取经理在各门店的目标业绩和完成业绩 var sql = $@" SELECT - target.zjl_userid as ManagerId, + target.F_GeneralManagerId as ManagerId, u.F_RealName as ManagerName, - target.md_id as StoreId, + target.F_StoreId as StoreId, store.dm as StoreName, - target.smx1 as Target1, - target.smx2 as Target2, - target.smx3 as Target3, + target.F_Lifeline1 as Target1, + target.F_Lifeline2 as Target2, + target.F_Lifeline3 as Target3, -- 完成业绩 COALESCE(( SELECT SUM(billing.sfyj) FROM lq_kd_kdjlb billing - WHERE billing.djmd = target.md_id + WHERE billing.djmd = target.F_StoreId AND billing.F_IsEffective = 1 AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' ), 0) as CompletedPerformance - FROM lq_zjl_mdsmxsz target - INNER JOIN BASE_USER u ON target.zjl_userid = u.F_Id - INNER JOIN lq_mdxx store ON target.md_id = store.F_Id - WHERE target.deletemark = 0 + FROM lq_md_general_manager_lifeline target + INNER JOIN BASE_USER u ON target.F_GeneralManagerId = u.F_Id + INNER JOIN lq_mdxx store ON target.F_StoreId = store.F_Id + WHERE target.F_Month = '{month}' {managerFilter} - ORDER BY target.zjl_userid, store.dm"; + ORDER BY target.F_GeneralManagerId, store.dm"; var result = await _db.Ado.SqlQueryAsync(sql); @@ -712,10 +725,10 @@ namespace NCC.Extend /// 返回说明: /// - ManagerId: 经理用户ID /// - ManagerName: 经理姓名 - /// - TotalTarget1/2/3: 总目标业绩一/二/三阶段 + /// - TotalTarget1/2/3: 总目标业绩一/二/三阶段(来自门店总经理生命线设置表lq_md_general_manager_lifeline的F_Lifeline1/F_Lifeline2/F_Lifeline3字段,根据开始时间所在月份获取并汇总) /// - TotalCompletedPerformance: 总完成业绩(指定时间范围内的开单业绩总和) /// - TotalCompletionRate1/2/3: 总完成率各阶段 - /// - StoreCount: 管理门店数量 + /// - StoreCount: 管理门店数量(根据门店总经理生命线设置表中归属该经理的门店数统计) /// /// 查询参数 /// 经理汇总业绩完成情况列表 @@ -729,37 +742,40 @@ namespace NCC.Extend // 获取时间范围 var (startDate, endDate) = GetTimeRange(input.StartTime, input.EndTime); + // 根据开始时间确定月份(YYYYMM格式) + var month = startDate.ToString("yyyyMM"); + // 构建经理过滤条件 var managerFilter = ""; if (!string.IsNullOrWhiteSpace(input.ManagerId)) { - managerFilter = $"AND target.zjl_userid = '{input.ManagerId}'"; + managerFilter = $"AND target.F_GeneralManagerId = '{input.ManagerId}'"; } // SQL查询:获取经理汇总业绩 var sql = $@" SELECT - target.zjl_userid as ManagerId, + target.F_GeneralManagerId as ManagerId, u.F_RealName as ManagerName, - SUM(target.smx1) as TotalTarget1, - COALESCE(SUM(target.smx2), 0) as TotalTarget2, - COALESCE(SUM(target.smx3), 0) as TotalTarget3, - COUNT(DISTINCT target.md_id) as StoreCount, + SUM(target.F_Lifeline1) as TotalTarget1, + COALESCE(SUM(target.F_Lifeline2), 0) as TotalTarget2, + COALESCE(SUM(target.F_Lifeline3), 0) as TotalTarget3, + COUNT(DISTINCT target.F_StoreId) as StoreCount, -- 总完成业绩 SUM(COALESCE(( SELECT SUM(billing.sfyj) FROM lq_kd_kdjlb billing - WHERE billing.djmd = target.md_id + WHERE billing.djmd = target.F_StoreId AND billing.F_IsEffective = 1 AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' ), 0)) as TotalCompletedPerformance - FROM lq_zjl_mdsmxsz target - INNER JOIN BASE_USER u ON target.zjl_userid = u.F_Id - INNER JOIN lq_mdxx store ON target.md_id = store.F_Id - WHERE target.deletemark = 0 + FROM lq_md_general_manager_lifeline target + INNER JOIN BASE_USER u ON target.F_GeneralManagerId = u.F_Id + INNER JOIN lq_mdxx store ON target.F_StoreId = store.F_Id + WHERE target.F_Month = '{month}' {managerFilter} - GROUP BY target.zjl_userid, u.F_RealName + GROUP BY target.F_GeneralManagerId, u.F_RealName ORDER BY TotalCompletedPerformance DESC"; var result = await _db.Ado.SqlQueryAsync(sql); diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs index 5c38b7e..3189ddf 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqMdGeneralManagerLifelineService.cs @@ -66,7 +66,7 @@ namespace NCC.Extend.LqMdGeneralManagerLifeline [HttpGet("")] public async Task GetList([FromQuery] LqMdGeneralManagerLifelineListQueryInput input) { - var sidx = input.sidx == null ? "F_Id" : input.sidx; + var sidx = input.sidx == null ? "id" : input.sidx; var data = await _db.Queryable() .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Contains(input.storeId)) .WhereIF(!string.IsNullOrEmpty(input.month), p => p.Month == input.month) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqMdTargetService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqMdTargetService.cs index 11806c3..67f6751 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqMdTargetService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqMdTargetService.cs @@ -67,7 +67,8 @@ namespace NCC.Extend.LqMdTarget [HttpGet("")] public async Task GetList([FromQuery] LqMdTargetListQueryInput input) { - var sidx = input.sidx == null ? "F_Id" : input.sidx; + var sidx = input.sidx == null ? "id" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; var data = await _db.Queryable() .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Contains(input.storeId)) .WhereIF(!string.IsNullOrEmpty(input.month), p => p.Month == input.month) @@ -87,6 +88,7 @@ namespace NCC.Extend.LqMdTarget businessUnitTarget = it.BusinessUnitTarget, techDepartmentTarget = it.TechDepartmentTarget, educationDepartmentTarget = it.EducationDepartmentTarget, + majorProjectDepartmentTarget = it.MajorProjectDepartmentTarget, businessUnitGeneralManager = it.BusinessUnitGeneralManager, businessUnitManager = it.BusinessUnitManager, storeTarget = it.StoreTarget, @@ -102,7 +104,7 @@ namespace NCC.Extend.LqMdTarget updateUser = it.UpdateUser, }) .MergeTable() - .OrderBy(sidx + " " + input.sort) + .OrderBy($"{sidx} {sort}") .ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(data); } @@ -151,43 +153,67 @@ namespace NCC.Extend.LqMdTarget public async Task BatchCreateByStores([FromQuery] string month) { var userInfo = await _userManager.GetUserInfo(); + if (userInfo == null || string.IsNullOrEmpty(userInfo.userId)) + { + throw NCCException.Oh("用户信息获取失败,请重新登录"); + } // 验证月份格式 if (string.IsNullOrEmpty(month) || month.Length != 6 || !Regex.IsMatch(month, @"^\d{6}$")) { - throw NCCException.Oh(ErrorCode.COM1000, "月份格式必须为YYYYMM(如:202501)"); + throw NCCException.Oh("月份格式必须为YYYYMM(如:202501)"); } //查询门店列表 - var storeList = await _db.Queryable().Where(p => p.Status == StatusEnum.有效.GetHashCode()).Select(p => p.Id).ToListAsync(); + var storeList = await _db.Queryable().Select(p => p.Id).ToListAsync(); + + if (storeList == null || storeList.Count == 0) + { + return new { success = true, message = "没有有效的门店数据", createdCount = 0 }; + } + // 删除设置月份的所有门店数据 await _db.Deleteable().Where(p => p.Month == month).ExecuteCommandAsync(); + // 批量创建 - var entities = storeList.Select(storeId => new LqMdTargetEntity + var entities = new List(); + foreach (var storeId in storeList) + { + if (string.IsNullOrEmpty(storeId)) + continue; + + entities.Add(new LqMdTargetEntity + { + Id = YitIdHelper.NextId().ToString(), + StoreId = storeId, + Month = month, + BusinessUnit = "", + TechDepartment = "", + EducationDepartment = "", + MajorProjectDepartment = "", + BusinessUnitTarget = 0, + TechDepartmentTarget = 0, + EducationDepartmentTarget = 0, + BusinessUnitGeneralManager = "", + BusinessUnitManager = "", + StoreTarget = 0, + StoreLifeline = 0, + StoreConsumeTarget = 0, + StoreProjectTarget = 0, + StoreHeadcountTarget = 0, + AssistantHeadcountTargetStage1 = 0, + AssistantHeadcountTargetStage2 = 0, + CreateTime = DateTime.Now, + CreateUser = userInfo.userId, + }); + } + + if (entities.Count == 0) { - Id = YitIdHelper.NextId().ToString(), - StoreId = storeId, - Month = month, - BusinessUnit = "", - TechDepartment = "", - EducationDepartment = "", - MajorProjectDepartment = "", - BusinessUnitTarget = 0, - TechDepartmentTarget = 0, - EducationDepartmentTarget = 0, - BusinessUnitGeneralManager = "", - BusinessUnitManager = "", - StoreTarget = 0, - StoreLifeline = 0, - StoreConsumeTarget = 0, - StoreProjectTarget = 0, - StoreHeadcountTarget = 0, - AssistantHeadcountTargetStage1 = 0, - AssistantHeadcountTargetStage2 = 0, - CreateTime = DateTime.Now, - CreateUser = userInfo.userId, - }).ToList(); + return new { success = true, message = "没有有效的门店数据可创建", createdCount = 0 }; + } + var isOk = await _db.Insertable(entities).ExecuteCommandAsync(); if (!(isOk > 0)) - throw NCCException.Oh(ErrorCode.COM1000); + throw NCCException.Oh(ErrorCode.COM1000, "批量创建失败"); return new { success = true, message = $"成功创建{isOk}条记录", createdCount = isOk }; } #endregion diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index 97ac2e7..cd79bb8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -3644,7 +3644,7 @@ namespace NCC.Extend.LqStatistics SELECT COALESCE(SUM(pxmx.F_ProjectNumber), 0) as Count FROM lq_kd_jksyj jksyj INNER JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id - WHERE jksyj.jkszh = '{userId}' + WHERE jksyj.jks = '{userId}' AND jksyj.F_IsEffective = 1 AND DATE_FORMAT(jksyj.yjsj, '%Y%m') = '{month}'"; diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs index 5df76b8..ff2ed7d 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs @@ -172,12 +172,361 @@ namespace NCC.Extend.LqXhHyhk /// /// 获取会员耗卡列表 /// - /// 请求参数 - /// + /// + /// 根据多种条件查询会员耗卡记录列表,支持分页、排序、筛选等功能 + /// + /// 示例请求: + /// GET /api/Extend/LqXhHyhk/GetList?currentPage=1&pageSize=10&jksId=健康师ID&startTime=2025-01-01&endTime=2025-01-31 + /// + /// 传入参数说明: + /// - currentPage: 当前页码(必填,默认1) + /// - pageSize: 每页数量(必填,默认10) + /// - sidx: 排序字段(可选,默认"id") + /// - sort: 排序方式(可选,ASC/DESC,默认DESC) + /// - keyword: 关键字搜索(可选,搜索会员名称、账号、手机号) + /// - id: 耗卡编号(可选,模糊匹配) + /// - md: 门店ID(可选,精确匹配) + /// - mdbh: 门店编号(可选,模糊匹配) + /// - mdmc: 门店名称(可选,模糊匹配) + /// - hy: 会员ID(可选,精确匹配) + /// - hyzh: 会员账号(可选,模糊匹配) + /// - hymc: 会员名称(可选,模糊匹配) + /// - gklx: 顾客类型(可选,精确匹配) + /// - sfykjb: 是否有科技部(可选,精确匹配) + /// - hksj: 耗卡时间(可选,格式:开始时间,结束时间,如:2025-01-01,2025-01-31) + /// - czry: 操作人员ID(可选,精确匹配) + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认0) + /// - jksId: 健康师ID(可选,传入后只返回该健康师参与的耗卡记录) + /// - kjblsId: 科技部老师ID(可选,传入后只返回该老师参与的耗卡记录) + /// + /// 返回结果说明: + /// - code: 响应状态码(200=成功) + /// - msg: 响应消息 + /// - data: 分页数据对象 + /// - list: 耗卡记录列表,每个记录包含: + /// - id: 耗卡编号 + /// - md: 门店ID + /// - mdbh: 门店编号 + /// - mdmc: 门店名称 + /// - hy: 会员ID + /// - hyzh: 会员账号 + /// - hymc: 会员名称 + /// - memberPhone: 会员手机号 + /// - gklx: 顾客类型 + /// - xfje: 消费金额 + /// - sgfy: 手工费用 + /// - sfykjb: 是否有科技部 + /// - hksj: 耗卡时间 + /// - czry: 操作人员ID + /// - isEffective: 是否有效 + /// - signatureFile: 签名文件 + /// - overtimeCoefficient: 加班系数(NULL或0表示非加班单,大于0表示加班单) + /// - originalSgfy: 原始手工费(用户输入的原始值) + /// - overtimeSgfy: 加班手工费(加班计算后的增量值) + /// - ConsumeDetails: 耗卡明细列表(品项明细),每个明细包含: + /// - id: 明细编号 + /// - consumeInfoId: 耗卡记录ID + /// - billingItemId: 开单品项明细表ID + /// - px: 品项编号 + /// - pxmc: 品项名称 + /// - pxjg: 品项价格 + /// - memberId: 会员ID + /// - createTime: 创建时间 + /// - projectNumber: 项目次数 + /// - originalProjectNumber: 原始项目次数 + /// - overtimeProjectNumber: 加班项目次数 + /// - sourceType: 来源类型(开卡/赠送/其他) + /// - totalPrice: 合计金额(品项价格 × 项目次数) + /// - isEffective: 是否有效 + /// - lqXhJksyjList: 健康师业绩列表,每个业绩包含: + /// - id: 业绩编号 + /// - glkdbh: 关联耗卡编号 + /// - jks: 健康师ID + /// - jksxm: 健康师姓名 + /// - jkszh: 健康师账号 + /// - jksyj: 健康师业绩 + /// - yjsj: 业绩时间 + /// - jsjId: 金三角ID + /// - kdpxid: 耗卡品项ID + /// - laborCost: 手工费 + /// - kdpxNumber: 耗卡品项次数 + /// - originalKdpxNumber: 原始耗卡品项次数 + /// - overtimeKdpxNumber: 加班耗卡品项次数 + /// - originalLaborCost: 原始手工费 + /// - overtimeLaborCost: 加班手工费 + /// - isAccompanied: 是否陪同(0=否,1=是) + /// - accompaniedProjectNumber: 陪同项目数 + /// - memberId: 会员ID + /// - memberName: 会员名称 + /// - lqXhKjbsyjList: 科技部老师业绩列表,每个业绩包含: + /// - id: 业绩编号 + /// - glkdbh: 关联耗卡编号 + /// - kjbls: 科技部老师ID + /// - kjblsxm: 科技部老师姓名 + /// - kjblszh: 科技部老师账号 + /// - kjblsyj: 科技部老师业绩 + /// - yjsj: 业绩时间 + /// - hkpxid: 耗卡品项ID + /// - laborCost: 手工费 + /// - hdpxNumber: 耗卡品项次数 + /// - originalHdpxNumber: 原始耗卡品项次数 + /// - overtimeHdpxNumber: 加班耗卡品项次数 + /// - originalLaborCost: 原始手工费 + /// - overtimeLaborCost: 加班手工费 + /// - pagination: 分页信息 + /// - total: 总记录数 + /// - pageSize: 每页数量 + /// - currentPage: 当前页码 + /// - totalPages: 总页数 + /// + /// 查询参数 + /// 分页的耗卡记录列表,包含耗卡基本信息、耗卡明细、健康师业绩、科技部老师业绩 + /// 成功返回耗卡列表 + /// 参数错误 + /// 服务器内部错误 [HttpGet("")] public async Task GetList([FromQuery] LqXhHyhkListQueryInput input) { var sidx = input.sidx == null ? "id" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; + List queryHksj = input.hksj != null ? input.hksj.Split(',').ToObeject>() : null; + DateTime? startHksj = queryHksj != null ? Ext.GetDateTime(queryHksj.First()) : null; + DateTime? endHksj = queryHksj != null ? Ext.GetDateTime(queryHksj.Last()) : null; + + // 根据是否传入健康师ID或科技部老师ID来决定查询方式 + ISugarQueryable query = null; + + // 如果两个都传入了,需要同时JOIN两个表 + if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId)) + { + query = _db.Queryable( + (jksyj, kjbsyj, hyhk) => jksyj.Glkdbh == hyhk.Id && kjbsyj.Glkdbh == hyhk.Id) + .Where((jksyj, kjbsyj, hyhk) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Where((jksyj, kjbsyj, hyhk) => kjbsyj.Kjblszh == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((jksyj, kjbsyj, hyhk) => hyhk) + .Distinct() + .MergeTable(); // 将多表结果集变成单表,后续可以使用it别名 + } + // 如果只传入了健康师ID,需要通过JOIN健康师业绩表来过滤 + else if (!string.IsNullOrEmpty(input.jksId)) + { + query = _db.Queryable( + (jksyj, hyhk) => jksyj.Glkdbh == hyhk.Id) + .Where((jksyj, hyhk) => jksyj.Jkszh == input.jksId && jksyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((jksyj, hyhk) => hyhk) + .Distinct() + .MergeTable(); // 将多表结果集变成单表,后续可以使用it别名 + } + // 如果只传入了科技部老师ID,需要通过JOIN科技部老师业绩表来过滤 + else if (!string.IsNullOrEmpty(input.kjblsId)) + { + query = _db.Queryable( + (kjbsyj, hyhk) => kjbsyj.Glkdbh == hyhk.Id) + .Where((kjbsyj, hyhk) => kjbsyj.Kjblszh == input.kjblsId && kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) + .Select((kjbsyj, hyhk) => hyhk) + .Distinct() + .MergeTable(); // 将多表结果集变成单表,后续可以使用it别名 + } + // 如果都没有传入,直接查询耗卡表 + else + { + query = _db.Queryable(); + } + + var data = await query + .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Hymc.Contains(input.keyword) || p.Hyzh.Contains(input.keyword) || p.MemberPhone.Contains(input.keyword)) + .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id)) + .WhereIF(!string.IsNullOrEmpty(input.md), p => p.Md.Equals(input.md)) + .WhereIF(!string.IsNullOrEmpty(input.mdbh), p => p.Mdbh.Contains(input.mdbh)) + .WhereIF(!string.IsNullOrEmpty(input.mdmc), p => p.Mdmc.Contains(input.mdmc)) + .WhereIF(!string.IsNullOrEmpty(input.hy), p => p.Hy.Equals(input.hy)) + .WhereIF(!string.IsNullOrEmpty(input.hyzh), p => p.Hyzh.Contains(input.hyzh)) + .WhereIF(!string.IsNullOrEmpty(input.hymc), p => p.Hymc.Contains(input.hymc)) + .WhereIF(!string.IsNullOrEmpty(input.gklx), p => p.Gklx.Equals(input.gklx)) + .WhereIF(!string.IsNullOrEmpty(input.sfykjb), p => p.Sfykjb.Equals(input.sfykjb)) + .WhereIF(queryHksj != null, p => p.Hksj >= new DateTime(startHksj.ToDate().Year, startHksj.ToDate().Month, startHksj.ToDate().Day, 0, 0, 0)) + .WhereIF(queryHksj != null, p => p.Hksj <= new DateTime(endHksj.ToDate().Year, endHksj.ToDate().Month, endHksj.ToDate().Day, 23, 59, 59)) + .WhereIF(!string.IsNullOrEmpty(input.czry), p => p.Czry.Equals(input.czry)) + .WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective) + .Select(it => new LqXhHyhkListOutput + { + id = it.Id, + md = it.Md, + mdbh = it.Mdbh, + mdmc = it.Mdmc, + hy = it.Hy, + hyzh = it.Hyzh, + hymc = SqlFunc.Subqueryable().Where(w => w.Id == it.Hy).Select(w => w.Khmc), + gklx = it.Gklx, + xfje = SqlFunc.ToString(it.Xfje), + sgfy = SqlFunc.ToString(it.Sgfy), + sfykjb = it.Sfykjb, + hksj = it.Hksj, + czry = it.Czry, + memberPhone = SqlFunc.Subqueryable().Where(w => w.Id == it.Hy).Select(w => w.Sjh), + isEffective = it.IsEffective, + signatureFile = it.SignatureFile, + overtimeCoefficient = it.OvertimeCoefficient, + originalSgfy = it.OriginalSgfy, + overtimeSgfy = it.OvertimeSgfy, + }) + .MergeTable() + .OrderBy($"{sidx} {sort}") + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的耗卡记录ID列表 + var consumeIds = data.list.Select(x => x.id).ToList(); + + // 批量查询耗卡明细 + var consumeDetails = new List(); + if (consumeIds.Any()) + { + consumeDetails = await _db.Queryable() + .Where(x => consumeIds.Contains(x.ConsumeInfoId) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqXhPxmxInfoOutput + { + id = x.Id, + consumeInfoId = x.ConsumeInfoId, + billingItemId = x.BillingItemId, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + memberId = x.MemberId, + createTime = x.CreateTIme, + projectNumber = x.ProjectNumber, + originalProjectNumber = x.OriginalProjectNumber, + overtimeProjectNumber = x.OvertimeProjectNumber, + sourceType = x.SourceType, + totalPrice = x.TotalPrice, + isEffective = x.IsEffective, + }) + .ToListAsync(); + } + + // 按耗卡记录ID分组耗卡明细 + var consumeDetailsGrouped = consumeDetails.GroupBy(x => x.consumeInfoId) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 批量查询健康师业绩(性能优化:一次性查询所有耗卡的健康师业绩) + var jksyjList = new List(); + if (consumeIds.Any()) + { + // 先查询业绩数据 + var jksyjEntities = await _db.Queryable() + .Where(x => consumeIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .ToListAsync(); + + // 批量查询耗卡记录获取会员ID + var hyhkList = await _db.Queryable() + .Where(x => consumeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Hy }) + .ToListAsync(); + var hyhkDict = hyhkList.ToDictionary(x => x.Id, x => x.Hy); + + // 批量查询会员信息 + var memberIds = hyhkDict.Values.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var memberList = new List<(string Id, string Khmc)>(); + if (memberIds.Any()) + { + var memberData = await _db.Queryable() + .Where(x => memberIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Khmc }) + .ToListAsync(); + memberList = memberData.Select(x => (x.Id, x.Khmc)).ToList(); + } + var memberDict = memberList.ToDictionary(x => x.Id, x => x.Khmc); + + // 转换为输出DTO + jksyjList = jksyjEntities.Select(x => new LqXhJksyjInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + jks = x.Jks, + jksxm = x.Jksxm, + jkszh = x.Jkszh, + jksyj = x.Jksyj?.ToString() ?? "0", + yjsj = x.Yjsj, + jsjId = x.JsjId, + kdpxid = x.Kdpxid, + laborCost = x.LaborCost, + kdpxNumber = x.KdpxNumber, + originalKdpxNumber = x.OriginalKdpxNumber, + overtimeKdpxNumber = x.OvertimeKdpxNumber, + originalLaborCost = x.OriginalLaborCost, + overtimeLaborCost = x.OvertimeLaborCost, + isAccompanied = x.IsAccompanied, + accompaniedProjectNumber = x.AccompaniedProjectNumber, + memberId = hyhkDict.ContainsKey(x.Glkdbh) ? hyhkDict[x.Glkdbh] : null, + memberName = hyhkDict.ContainsKey(x.Glkdbh) && memberDict.ContainsKey(hyhkDict[x.Glkdbh]) + ? memberDict[hyhkDict[x.Glkdbh]] + : null, + }).ToList(); + } + + // 批量查询科技部老师业绩(性能优化:一次性查询所有耗卡的科技部老师业绩) + var kjbsyjList = new List(); + if (consumeIds.Any()) + { + kjbsyjList = await _db.Queryable() + .Where(x => consumeIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqXhKjbsyjInfoOutput + { + id = x.Id, + glkdbh = x.Glkdbh, + kjbls = x.Kjbls, + kjblsxm = x.Kjblsxm, + kjblszh = x.Kjblszh, + kjblsyj = SqlFunc.ToString(x.Kjblsyj), + yjsj = x.Yjsj, + hkpxid = x.Hkpxid, + laborCost = x.LaborCost, + hdpxNumber = x.HdpxNumber, + originalHdpxNumber = x.OriginalHdpxNumber, + overtimeHdpxNumber = x.OvertimeHdpxNumber, + originalLaborCost = x.OriginalLaborCost, + overtimeLaborCost = x.OvertimeLaborCost, + }) + .ToListAsync(); + } + + // 按耗卡记录ID分组健康师业绩 + var jksyjGrouped = jksyjList.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 按耗卡记录ID分组科技部老师业绩 + var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个耗卡记录分配耗卡明细、健康师业绩和科技部老师业绩 + foreach (var item in data.list) + { + item.ConsumeDetails = consumeDetailsGrouped.ContainsKey(item.id) + ? consumeDetailsGrouped[item.id] + : new List(); + + item.lqXhJksyjList = jksyjGrouped.ContainsKey(item.id) + ? jksyjGrouped[item.id] + : new List(); + + item.lqXhKjbsyjList = kjbsyjGrouped.ContainsKey(item.id) + ? kjbsyjGrouped[item.id] + : new List(); + } + + return PageResult.SqlSugarPageResult(data); + } + #endregion + + #region 获取会员耗卡列表(备份) + /// + /// 获取会员耗卡列表 + /// + /// 请求参数 + /// + [HttpGet("GetListBak")] + public async Task GetListBak([FromQuery] LqXhHyhkListQueryInput input) + { + var sidx = input.sidx == null ? "id" : input.sidx; List queryHksj = input.hksj != null ? input.hksj.Split(',').ToObeject>() : null; DateTime? startHksj = queryHksj != null ? Ext.GetDateTime(queryHksj.First()) : null; DateTime? endHksj = queryHksj != null ? Ext.GetDateTime(queryHksj.Last()) : null; @@ -263,6 +612,294 @@ namespace NCC.Extend.LqXhHyhk } #endregion + #region 根据健康师ID获取耗卡列表 + /// + /// 根据健康师ID获取耗卡列表 + /// + /// + /// 根据健康师ID查询该健康师参与的所有耗卡记录,支持时间周期查询和分页 + /// + /// 示例请求: + /// GET /api/Extend/LqXhHyhk/GetListByJksId?jksId=健康师ID&startTime=2025-01-01&endTime=2025-01-31&currentPage=1&pageSize=10 + /// + /// 参数说明: + /// - jksId: 健康师ID(必填) + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - md: 门店ID(可选) + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 返回说明: + /// - 返回格式与GetList接口相同,包含耗卡基本信息及耗卡明细列表 + /// + /// 查询参数 + /// 耗卡列表(分页) + /// 查询成功 + /// 参数错误 + /// 服务器内部错误 + [HttpGet("GetListByJksId")] + public async Task GetListByJksId([FromQuery] LqXhHyhkListByJksQueryInput input) + { + try + { + if (string.IsNullOrEmpty(input.jksId)) + { + throw NCCException.Oh("健康师ID不能为空"); + } + + var sidx = input.sidx == null ? "hksj" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; + + // 解析时间范围 + DateTime? startDate = null; + DateTime? endDate = null; + if (!string.IsNullOrEmpty(input.startTime)) + { + startDate = Ext.GetDateTime(input.startTime); + } + if (!string.IsNullOrEmpty(input.endTime)) + { + endDate = Ext.GetDateTime(input.endTime); + // 如果只传了日期,则设置为当天的23:59:59 + if (endDate.HasValue && !input.endTime.Contains(":")) + { + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59); + } + } + + // 通过健康师业绩表关联查询耗卡记录 + var data = await _db.Queryable( + (jksyj, hyhk) => jksyj.Glkdbh == hyhk.Id) + .Where((jksyj, hyhk) => jksyj.Jkszh == input.jksId) + .WhereIF(input.isEffective != 0, (jksyj, hyhk) => jksyj.IsEffective == input.isEffective && hyhk.IsEffective == input.isEffective) + .WhereIF(input.isEffective == 0, (jksyj, hyhk) => jksyj.IsEffective == StatusEnum.有效.GetHashCode() && hyhk.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, (jksyj, hyhk) => hyhk.Hksj >= startDate.Value) + .WhereIF(endDate.HasValue, (jksyj, hyhk) => hyhk.Hksj <= endDate.Value) + .WhereIF(!string.IsNullOrEmpty(input.md), (jksyj, hyhk) => hyhk.Md == input.md) + .Select((jksyj, hyhk) => new LqXhHyhkListOutput + { + id = hyhk.Id, + md = hyhk.Md, + mdbh = hyhk.Mdbh, + mdmc = hyhk.Mdmc, + hy = hyhk.Hy, + hyzh = hyhk.Hyzh, + hymc = SqlFunc.Subqueryable().Where(w => w.Id == hyhk.Hy).Select(w => w.Khmc), + gklx = hyhk.Gklx, + xfje = SqlFunc.ToString(hyhk.Xfje), + sgfy = SqlFunc.ToString(hyhk.Sgfy), + sfykjb = hyhk.Sfykjb, + hksj = hyhk.Hksj, + czry = hyhk.Czry, + memberPhone = SqlFunc.Subqueryable().Where(w => w.Id == hyhk.Hy).Select(w => w.Sjh), + isEffective = hyhk.IsEffective, + signatureFile = hyhk.SignatureFile, + overtimeCoefficient = hyhk.OvertimeCoefficient, + originalSgfy = hyhk.OriginalSgfy, + overtimeSgfy = hyhk.OvertimeSgfy, + }) + .MergeTable() + .Distinct() // 去重,因为一个耗卡可能对应多个健康师业绩记录 + .OrderBy($"{sidx} {sort}") + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的耗卡记录ID列表 + var consumeIds = data.list.Select(x => x.id).ToList(); + + // 批量查询耗卡明细 + var consumeDetails = new List(); + if (consumeIds.Any()) + { + consumeDetails = await _db.Queryable() + .Where(x => consumeIds.Contains(x.ConsumeInfoId) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqXhPxmxInfoOutput + { + id = x.Id, + consumeInfoId = x.ConsumeInfoId, + billingItemId = x.BillingItemId, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + memberId = x.MemberId, + createTime = x.CreateTIme, + projectNumber = x.ProjectNumber, + originalProjectNumber = x.OriginalProjectNumber, + overtimeProjectNumber = x.OvertimeProjectNumber, + sourceType = x.SourceType, + totalPrice = x.TotalPrice, + isEffective = x.IsEffective, + }) + .ToListAsync(); + } + + // 按耗卡记录ID分组耗卡明细 + var consumeDetailsGrouped = consumeDetails.GroupBy(x => x.consumeInfoId) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个耗卡记录分配耗卡明细 + foreach (var item in data.list) + { + item.ConsumeDetails = consumeDetailsGrouped.ContainsKey(item.id) + ? consumeDetailsGrouped[item.id] + : new List(); + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, $"根据健康师ID获取耗卡列表失败 - 健康师ID: {input?.jksId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}"); + throw NCCException.Oh($"根据健康师ID获取耗卡列表失败: {ex.Message}"); + } + } + #endregion + + #region 根据科技部老师ID获取耗卡列表 + /// + /// 根据科技部老师ID获取耗卡列表 + /// + /// + /// 根据科技部老师ID查询该老师参与的所有耗卡记录,支持时间周期查询和分页 + /// + /// 示例请求: + /// GET /api/Extend/LqXhHyhk/GetListByKjbId?kjblsId=科技部老师ID&startTime=2025-01-01&endTime=2025-01-31&currentPage=1&pageSize=10 + /// + /// 参数说明: + /// - kjblsId: 科技部老师ID(必填) + /// - startTime: 开始时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - endTime: 结束时间(可选,格式:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss) + /// - md: 门店ID(可选) + /// - isEffective: 是否有效(可选,0=全部,1=有效,2=无效,默认1) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 返回说明: + /// - 返回格式与GetList接口相同,包含耗卡基本信息及耗卡明细列表 + /// + /// 查询参数 + /// 耗卡列表(分页) + /// 查询成功 + /// 参数错误 + /// 服务器内部错误 + [HttpGet("GetListByKjbId")] + public async Task GetListByKjbId([FromQuery] LqXhHyhkListByKjbQueryInput input) + { + try + { + if (string.IsNullOrEmpty(input.kjblsId)) + { + throw NCCException.Oh("科技部老师ID不能为空"); + } + + var sidx = input.sidx == null ? "hksj" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; + + // 解析时间范围 + DateTime? startDate = null; + DateTime? endDate = null; + if (!string.IsNullOrEmpty(input.startTime)) + { + startDate = Ext.GetDateTime(input.startTime); + } + if (!string.IsNullOrEmpty(input.endTime)) + { + endDate = Ext.GetDateTime(input.endTime); + // 如果只传了日期,则设置为当天的23:59:59 + if (endDate.HasValue && !input.endTime.Contains(":")) + { + endDate = new DateTime(endDate.Value.Year, endDate.Value.Month, endDate.Value.Day, 23, 59, 59); + } + } + + // 通过科技部老师业绩表关联查询耗卡记录 + var data = await _db.Queryable( + (kjbsyj, hyhk) => kjbsyj.Glkdbh == hyhk.Id) + .Where((kjbsyj, hyhk) => kjbsyj.Kjblszh == input.kjblsId) + .WhereIF(input.isEffective != 0, (kjbsyj, hyhk) => kjbsyj.IsEffective == input.isEffective && hyhk.IsEffective == input.isEffective) + .WhereIF(input.isEffective == 0, (kjbsyj, hyhk) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode() && hyhk.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, (kjbsyj, hyhk) => hyhk.Hksj >= startDate.Value) + .WhereIF(endDate.HasValue, (kjbsyj, hyhk) => hyhk.Hksj <= endDate.Value) + .WhereIF(!string.IsNullOrEmpty(input.md), (kjbsyj, hyhk) => hyhk.Md == input.md) + .Select((kjbsyj, hyhk) => new LqXhHyhkListOutput + { + id = hyhk.Id, + md = hyhk.Md, + mdbh = hyhk.Mdbh, + mdmc = hyhk.Mdmc, + hy = hyhk.Hy, + hyzh = hyhk.Hyzh, + hymc = SqlFunc.Subqueryable().Where(w => w.Id == hyhk.Hy).Select(w => w.Khmc), + gklx = hyhk.Gklx, + xfje = SqlFunc.ToString(hyhk.Xfje), + sgfy = SqlFunc.ToString(hyhk.Sgfy), + sfykjb = hyhk.Sfykjb, + hksj = hyhk.Hksj, + czry = hyhk.Czry, + memberPhone = SqlFunc.Subqueryable().Where(w => w.Id == hyhk.Hy).Select(w => w.Sjh), + isEffective = hyhk.IsEffective, + signatureFile = hyhk.SignatureFile, + overtimeCoefficient = hyhk.OvertimeCoefficient, + originalSgfy = hyhk.OriginalSgfy, + overtimeSgfy = hyhk.OvertimeSgfy, + }) + .MergeTable() + .Distinct() // 去重,因为一个耗卡可能对应多个科技部老师业绩记录 + .OrderBy($"{sidx} {sort}") + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 获取当前页的耗卡记录ID列表 + var consumeIds = data.list.Select(x => x.id).ToList(); + + // 批量查询耗卡明细 + var consumeDetails = new List(); + if (consumeIds.Any()) + { + consumeDetails = await _db.Queryable() + .Where(x => consumeIds.Contains(x.ConsumeInfoId) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqXhPxmxInfoOutput + { + id = x.Id, + consumeInfoId = x.ConsumeInfoId, + billingItemId = x.BillingItemId, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + memberId = x.MemberId, + createTime = x.CreateTIme, + projectNumber = x.ProjectNumber, + originalProjectNumber = x.OriginalProjectNumber, + overtimeProjectNumber = x.OvertimeProjectNumber, + sourceType = x.SourceType, + totalPrice = x.TotalPrice, + isEffective = x.IsEffective, + }) + .ToListAsync(); + } + + // 按耗卡记录ID分组耗卡明细 + var consumeDetailsGrouped = consumeDetails.GroupBy(x => x.consumeInfoId) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 为每个耗卡记录分配耗卡明细 + foreach (var item in data.list) + { + item.ConsumeDetails = consumeDetailsGrouped.ContainsKey(item.id) + ? consumeDetailsGrouped[item.id] + : new List(); + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, $"根据科技部老师ID获取耗卡列表失败 - 科技部老师ID: {input?.kjblsId}, 开始时间: {input?.startTime}, 结束时间: {input?.endTime}"); + throw NCCException.Oh($"根据科技部老师ID获取耗卡列表失败: {ex.Message}"); + } + } + #endregion + #region 新建会员耗卡 /// /// 新建会员耗卡 diff --git a/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs b/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs index 0df2a6e..88c785a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs @@ -17,7 +17,7 @@ namespace NCC.Extend.Utils //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188 //测试地址 //https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83 - private const string WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188"; + private const string WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=496f1add-122b-43fc-9e38-0ca79c48b33f"; private const string WEBHOOK_URL_TEST = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83"; public WeChatBotService(HttpClient httpClient) @@ -37,6 +37,7 @@ namespace NCC.Extend.Utils var requestData = new { webhookUrl = WEBHOOK_URL, + // webhookUrl = WEBHOOK_URL_TEST, content = content, mentionedList = (string)null, mentionedMobileList = (string)null,