From ac25ff124b26024e5debb94b5b3bca78ed99587c Mon Sep 17 00:00:00 2001
From: “wangming” <“wangming@antissoft.com”>
Date: Sat, 13 Dec 2025 00:55:27 +0800
Subject: [PATCH] feat: 添加大项目部老师工资计算、事业部总经理/经理工资计算、健康师额外数据导入修复、OSS URL迁移功能
---
excel/健康师额外数据模板.xlsx | Bin 0 -> 25937 bytes
netcore/src/Application/NCC.API/appsettings.json | 4 ++--
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryInput.cs | 32 ++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryOutput.cs | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs | 10 ++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryInput.cs | 32 ++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryOutput.cs | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs | 5 +++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs | 10 ++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs | 10 ++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs | 5 +++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs | 5 +++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_business_unit_manager_salary_statistics/LqBusinessUnitManagerSalaryStatisticsEntity.cs | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_application_node/LqInventoryUsageApplicationNodeEntity.cs | 4 ++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage_approval_record/LqInventoryUsageApprovalRecordEntity.cs | 4 ++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs | 7 +++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_major_project_teacher_salary_statistics/LqMajorProjectTeacherSalaryStatisticsEntity.cs | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs | 6 ++++++
netcore/src/Modularity/Extend/NCC.Extend/FileUrlMigrationService.cs | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs | 514 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs | 14 ++++++++++----
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs | 33 ++++++++++++++++++++++++++++++++-
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs | 26 +++++++++++++++++++-------
netcore/src/Modularity/Extend/NCC.Extend/LqMajorProjectTeacherSalaryService.cs | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs | 7 +++++++
netcore/src/Modularity/Extend/NCC.Extend/LqSalaryExtraCalculationService.cs | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs | 14 ++++++++++----
netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
sql/创建事业部总经理经理工资统计表.sql | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sql/创建大项目部老师工资统计表.sql | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sql/创建库存使用申请审批流程表.sql | 4 ++++
sql/同步BeautyType字段数据.sql | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sql/添加教育部老师字段.sql | 35 +++++++++++++++++++++++++++++++++++
sql/添加科技部归类字段.sql | 2 +-
sql/重命名科技部归类字段为BeautyType.sql | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
事业部总经理经理工资计算规则梳理.md | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
大项目部老师工资计算规则梳理.md | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
45 files changed, 4509 insertions(+), 70 deletions(-)
create mode 100644 excel/健康师额外数据模板.xlsx
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryInput.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryOutput.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryInput.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryOutput.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_business_unit_manager_salary_statistics/LqBusinessUnitManagerSalaryStatisticsEntity.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_major_project_teacher_salary_statistics/LqMajorProjectTeacherSalaryStatisticsEntity.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/FileUrlMigrationService.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs
create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/LqMajorProjectTeacherSalaryService.cs
create mode 100644 sql/创建事业部总经理经理工资统计表.sql
create mode 100644 sql/创建大项目部老师工资统计表.sql
create mode 100644 sql/同步BeautyType字段数据.sql
create mode 100644 sql/添加教育部老师字段.sql
create mode 100644 sql/重命名科技部归类字段为BeautyType.sql
create mode 100644 事业部总经理经理工资计算规则梳理.md
create mode 100644 大项目部老师工资计算规则梳理.md
diff --git a/excel/健康师额外数据模板.xlsx b/excel/健康师额外数据模板.xlsx
new file mode 100644
index 0000000..7afe8fd
Binary files /dev/null and b/excel/健康师额外数据模板.xlsx differ
diff --git a/netcore/src/Application/NCC.API/appsettings.json b/netcore/src/Application/NCC.API/appsettings.json
index 5272291..bfdb337 100644
--- a/netcore/src/Application/NCC.API/appsettings.json
+++ b/netcore/src/Application/NCC.API/appsettings.json
@@ -189,7 +189,7 @@
"NCC_App": {
"CodeAreasName": "SubDev,Food,Extend,test",
//系统文件路径(末尾必须带斜杆)
- "SystemPath": "Files/",
+ "SystemPath": "/",
//微信公众号允许上传文件类型
"MPUploadFileType": "bmp,png,jpeg,jpg,gif,mp3,wma,wav,amr,mp4",
//微信允许上传文件类型
@@ -213,7 +213,7 @@
"AccessKeySecret": "84dpUAlu2eoyFOIEhFGkZlIy45h0B6",
"Endpoint": "oss-cn-chengdu.aliyuncs.com",
"Region": "cn-chengdu",
- "CustomDomain": "http://oss.lvqianmeiye.com"
+ "CustomDomain": "https://lvqian-erip.oss-cn-chengdu.aliyuncs.com"
},
//================== 系统错误邮件报告反馈相关 ============================== -->
//软件的错误报告
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryInput.cs
new file mode 100644
index 0000000..7973481
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryInput.cs
@@ -0,0 +1,32 @@
+using NCC.Common.Filter;
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqBusinessUnitManagerSalary
+{
+ ///
+ /// 事业部总经理/经理工资查询参数
+ ///
+ public class BusinessUnitManagerSalaryInput : PageInputBase
+ {
+ ///
+ /// 年份
+ ///
+ public int Year { get; set; }
+
+ ///
+ /// 月份
+ ///
+ public int Month { get; set; }
+
+ ///
+ /// 经理类型(0=经理,1=总经理,不传则查询全部)
+ ///
+ public int? ManagerType { get; set; }
+
+ ///
+ /// 员工姓名/账号(可选,用于模糊搜索)
+ ///
+ public string Keyword { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryOutput.cs
new file mode 100644
index 0000000..c6e1ee8
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqBusinessUnitManagerSalary/BusinessUnitManagerSalaryOutput.cs
@@ -0,0 +1,211 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqBusinessUnitManagerSalary
+{
+ ///
+ /// 事业部总经理/经理工资输出
+ ///
+ public class BusinessUnitManagerSalaryOutput
+ {
+ ///
+ /// 主键ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 核算岗位
+ ///
+ public string Position { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 员工ID
+ ///
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工账号
+ ///
+ public string EmployeeAccount { get; set; }
+
+ ///
+ /// 经理类型(0=经理,1=总经理)
+ ///
+ public int ManagerType { get; set; }
+
+ ///
+ /// 是否离职
+ ///
+ public int IsTerminated { get; set; }
+
+ ///
+ /// 门店业绩明细(JSON格式)
+ ///
+ public string StorePerformanceDetail { get; set; }
+
+ ///
+ /// 底薪
+ ///
+ public decimal BaseSalary { get; set; }
+
+ ///
+ /// 提成合计
+ ///
+ public decimal TotalCommission { get; set; }
+
+ ///
+ /// 在店天数
+ ///
+ public decimal WorkingDays { get; set; }
+
+ ///
+ /// 请假天数
+ ///
+ public decimal LeaveDays { get; set; }
+
+ ///
+ /// 核算应发工资
+ ///
+ public decimal CalculatedGrossSalary { get; set; }
+
+ ///
+ /// 最终应发工资
+ ///
+ public decimal FinalGrossSalary { get; set; }
+
+ ///
+ /// 当月培训补贴
+ ///
+ public decimal MonthlyTrainingSubsidy { get; set; }
+
+ ///
+ /// 当月交通补贴
+ ///
+ public decimal MonthlyTransportSubsidy { get; set; }
+
+ ///
+ /// 上月培训补贴
+ ///
+ public decimal LastMonthTrainingSubsidy { get; set; }
+
+ ///
+ /// 上月交通补贴
+ ///
+ public decimal LastMonthTransportSubsidy { get; set; }
+
+ ///
+ /// 补贴合计
+ ///
+ public decimal TotalSubsidy { get; set; }
+
+ ///
+ /// 缺卡扣款
+ ///
+ public decimal MissingCard { get; set; }
+
+ ///
+ /// 迟到扣款
+ ///
+ public decimal LateArrival { get; set; }
+
+ ///
+ /// 请假扣款
+ ///
+ public decimal LeaveDeduction { get; set; }
+
+ ///
+ /// 扣社保
+ ///
+ public decimal SocialInsuranceDeduction { get; set; }
+
+ ///
+ /// 扣除奖励
+ ///
+ public decimal RewardDeduction { get; set; }
+
+ ///
+ /// 扣住宿费
+ ///
+ public decimal AccommodationDeduction { get; set; }
+
+ ///
+ /// 扣学习期费用
+ ///
+ public decimal StudyPeriodDeduction { get; set; }
+
+ ///
+ /// 扣工作服费用
+ ///
+ public decimal WorkClothesDeduction { get; set; }
+
+ ///
+ /// 扣款合计
+ ///
+ public decimal TotalDeduction { get; set; }
+
+ ///
+ /// 发奖金
+ ///
+ public decimal Bonus { get; set; }
+
+ ///
+ /// 退手机押金
+ ///
+ public decimal ReturnPhoneDeposit { get; set; }
+
+ ///
+ /// 退住宿押金
+ ///
+ public decimal ReturnAccommodationDeposit { get; set; }
+
+ ///
+ /// 实发工资
+ ///
+ public decimal ActualSalary { get; set; }
+
+ ///
+ /// 当月是否发放
+ ///
+ public string MonthlyPaymentStatus { get; set; }
+
+ ///
+ /// 支付金额
+ ///
+ public decimal PaidAmount { get; set; }
+
+ ///
+ /// 待支付金额
+ ///
+ public decimal PendingAmount { get; set; }
+
+ ///
+ /// 补发上月
+ ///
+ public decimal LastMonthSupplement { get; set; }
+
+ ///
+ /// 当月支付总额
+ ///
+ public decimal MonthlyTotalPayment { get; set; }
+
+ ///
+ /// 是否锁定
+ ///
+ public int IsLocked { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdateTime { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs
index 4bb526f..f3501d1 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs
@@ -111,5 +111,15 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage
/// 使用批次ID(同一批次申请的使用记录使用相同的批次ID)
///
public string usageBatchId { get; set; }
+
+ ///
+ /// 审批状态(待审批/审批中/已通过/未通过/已退回),通过usageBatchId关联申请表获取
+ ///
+ public string approvalStatus { get; set; }
+
+ ///
+ /// 是否已领取(1-已领取,0-未领取),通过usageBatchId关联申请表获取
+ ///
+ public int? isReceived { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryInput.cs
new file mode 100644
index 0000000..875abc2
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryInput.cs
@@ -0,0 +1,32 @@
+using NCC.Common.Filter;
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqMajorProjectTeacherSalary
+{
+ ///
+ /// 大项目部老师工资查询参数
+ ///
+ public class MajorProjectTeacherSalaryInput : PageInputBase
+ {
+ ///
+ /// 年份
+ ///
+ public int Year { get; set; }
+
+ ///
+ /// 月份
+ ///
+ public int Month { get; set; }
+
+ ///
+ /// 门店ID(可选,用于筛选特定门店)
+ ///
+ public string StoreId { get; set; }
+
+ ///
+ /// 员工姓名/账号(可选,用于模糊搜索)
+ ///
+ public string Keyword { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryOutput.cs
new file mode 100644
index 0000000..42d3c48
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMajorProjectTeacherSalary/MajorProjectTeacherSalaryOutput.cs
@@ -0,0 +1,301 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqMajorProjectTeacherSalary
+{
+ ///
+ /// 大项目部老师工资输出
+ ///
+ public class MajorProjectTeacherSalaryOutput
+ {
+ ///
+ /// 主键ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 门店ID
+ ///
+ public string StoreId { get; set; }
+
+ ///
+ /// 门店名称
+ ///
+ public string StoreName { get; set; }
+
+ ///
+ /// 核算岗位
+ ///
+ public string Position { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 员工ID
+ ///
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工账号
+ ///
+ public string EmployeeAccount { get; set; }
+
+ ///
+ /// 开单业绩
+ ///
+ public decimal OrderAchievement { get; set; }
+
+ ///
+ /// 消耗业绩
+ ///
+ public decimal ConsumeAchievement { get; set; }
+
+ ///
+ /// 退卡业绩
+ ///
+ public decimal RefundAchievement { get; set; }
+
+ ///
+ /// 总业绩
+ ///
+ public decimal TotalPerformance { get; set; }
+
+ ///
+ /// 底薪
+ ///
+ public decimal BaseSalary { get; set; }
+
+ ///
+ /// 业绩提成比例
+ ///
+ public decimal PerformanceCommissionRate { get; set; }
+
+ ///
+ /// 业绩提成金额
+ ///
+ public decimal PerformanceCommissionAmount { get; set; }
+
+ ///
+ /// 提成合计
+ ///
+ public decimal TotalCommission { get; set; }
+
+ ///
+ /// 手工费
+ ///
+ public decimal HandworkFee { get; set; }
+
+ ///
+ /// 在店天数
+ ///
+ public decimal WorkingDays { get; set; }
+
+ ///
+ /// 请假天数
+ ///
+ public decimal LeaveDays { get; set; }
+
+ ///
+ /// 车补
+ ///
+ public decimal TransportationAllowance { get; set; }
+
+ ///
+ /// 少休费
+ ///
+ public decimal LessRest { get; set; }
+
+ ///
+ /// 全勤奖
+ ///
+ public decimal FullAttendance { get; set; }
+
+ ///
+ /// 核算应发工资
+ ///
+ public decimal CalculatedGrossSalary { get; set; }
+
+ ///
+ /// 保底工资
+ ///
+ public decimal GuaranteedSalary { get; set; }
+
+ ///
+ /// 保底请假扣款
+ ///
+ public decimal GuaranteedLeaveDeduction { get; set; }
+
+ ///
+ /// 保底底薪
+ ///
+ public decimal GuaranteedBaseSalary { get; set; }
+
+ ///
+ /// 保底补差
+ ///
+ public decimal GuaranteedSupplement { get; set; }
+
+ ///
+ /// 最终应发工资
+ ///
+ public decimal FinalGrossSalary { get; set; }
+
+ ///
+ /// 当月培训补贴
+ ///
+ public decimal MonthlyTrainingSubsidy { get; set; }
+
+ ///
+ /// 当月交通补贴
+ ///
+ public decimal MonthlyTransportSubsidy { get; set; }
+
+ ///
+ /// 上月培训补贴
+ ///
+ public decimal LastMonthTrainingSubsidy { get; set; }
+
+ ///
+ /// 上月交通补贴
+ ///
+ public decimal LastMonthTransportSubsidy { get; set; }
+
+ ///
+ /// 补贴合计
+ ///
+ public decimal TotalSubsidy { get; set; }
+
+ ///
+ /// 缺卡扣款
+ ///
+ public decimal MissingCard { get; set; }
+
+ ///
+ /// 迟到扣款
+ ///
+ public decimal LateArrival { get; set; }
+
+ ///
+ /// 请假扣款
+ ///
+ public decimal LeaveDeduction { get; set; }
+
+ ///
+ /// 扣社保
+ ///
+ public decimal SocialInsuranceDeduction { get; set; }
+
+ ///
+ /// 扣除奖励
+ ///
+ public decimal RewardDeduction { get; set; }
+
+ ///
+ /// 扣住宿费
+ ///
+ public decimal AccommodationDeduction { get; set; }
+
+ ///
+ /// 扣学习期费用
+ ///
+ public decimal StudyPeriodDeduction { get; set; }
+
+ ///
+ /// 扣工作服费用
+ ///
+ public decimal WorkClothesDeduction { get; set; }
+
+ ///
+ /// 扣款合计
+ ///
+ public decimal TotalDeduction { get; set; }
+
+ ///
+ /// 发奖金
+ ///
+ public decimal Bonus { get; set; }
+
+ ///
+ /// 退手机押金
+ ///
+ public decimal ReturnPhoneDeposit { get; set; }
+
+ ///
+ /// 退住宿押金
+ ///
+ public decimal ReturnAccommodationDeposit { get; set; }
+
+ ///
+ /// 实发工资
+ ///
+ public decimal ActualSalary { get; set; }
+
+ ///
+ /// 当月是否发放
+ ///
+ public string MonthlyPaymentStatus { get; set; }
+
+ ///
+ /// 支付金额
+ ///
+ public decimal PaidAmount { get; set; }
+
+ ///
+ /// 待支付金额
+ ///
+ public decimal PendingAmount { get; set; }
+
+ ///
+ /// 补发上月
+ ///
+ public decimal LastMonthSupplement { get; set; }
+
+ ///
+ /// 当月支付总额
+ ///
+ public decimal MonthlyTotalPayment { get; set; }
+
+ ///
+ /// 是否锁定
+ ///
+ public int IsLocked { get; set; }
+
+ ///
+ /// 是否离职
+ ///
+ public int IsTerminated { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 门店类型
+ ///
+ public int? StoreType { get; set; }
+
+ ///
+ /// 门店类别
+ ///
+ public int? StoreCategory { get; set; }
+
+ ///
+ /// 是否新店
+ ///
+ public string IsNewStore { get; set; }
+
+ ///
+ /// 新店保护阶段
+ ///
+ public int NewStoreProtectionStage { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs
index 50dbc83..a55f2ca 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs
@@ -34,6 +34,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment
public string teacherId { get; set; }
///
+ /// 教育部老师用户ID
+ ///
+ public string educationTeacherId { get; set; }
+
+ ///
/// 备注说明
///
public string remark { get; set; }
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs
index 394d4da..3f7c89b 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs
@@ -43,6 +43,16 @@ namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment
public string teacherName { get; set; }
///
+ /// 教育部老师用户ID
+ ///
+ public string educationTeacherId { get; set; }
+
+ ///
+ /// 教育部老师姓名
+ ///
+ public string educationTeacherName { get; set; }
+
+ ///
/// 备注说明
///
public string remark { get; set; }
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs
index db6b5f9..c9b1ffe 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs
@@ -43,6 +43,16 @@ namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment
public string teacherName { get; set; }
///
+ /// 教育部老师用户ID
+ ///
+ public string educationTeacherId { get; set; }
+
+ ///
+ /// 教育部老师姓名
+ ///
+ public string educationTeacherName { get; set; }
+
+ ///
/// 备注说明
///
public string remark { get; set; }
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs
index 5182254..1e3308c 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs
@@ -26,5 +26,10 @@ namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment
/// 大项目部老师用户ID
///
public string teacherId { get; set; }
+
+ ///
+ /// 教育部老师用户ID
+ ///
+ public string educationTeacherId { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs
index ece1829..702def4 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs
@@ -40,6 +40,11 @@ namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment
public string teacherId { get; set; }
///
+ /// 教育部老师用户ID
+ ///
+ public string educationTeacherId { get; set; }
+
+ ///
/// 备注说明
///
public string remark { get; set; }
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_business_unit_manager_salary_statistics/LqBusinessUnitManagerSalaryStatisticsEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_business_unit_manager_salary_statistics/LqBusinessUnitManagerSalaryStatisticsEntity.cs
new file mode 100644
index 0000000..d13f728
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_business_unit_manager_salary_statistics/LqBusinessUnitManagerSalaryStatisticsEntity.cs
@@ -0,0 +1,273 @@
+using System;
+using NCC.Common.Const;
+using SqlSugar;
+
+namespace NCC.Extend.Entitys.lq_business_unit_manager_salary_statistics
+{
+ ///
+ /// 事业部总经理/经理工资统计表
+ ///
+ [SugarTable("lq_business_unit_manager_salary_statistics")]
+ [Tenant(ClaimConst.TENANT_ID)]
+ public class LqBusinessUnitManagerSalaryStatisticsEntity
+ {
+ ///
+ /// 主键ID
+ ///
+ [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ [SugarColumn(ColumnName = "F_StatisticsMonth", Length = 6)]
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 核算岗位
+ ///
+ [SugarColumn(ColumnName = "F_Position")]
+ public string Position { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeName")]
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 员工ID
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeId")]
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工账号
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeAccount")]
+ public string EmployeeAccount { get; set; }
+
+ ///
+ /// 经理类型(0=经理,1=总经理)
+ ///
+ [SugarColumn(ColumnName = "F_ManagerType")]
+ public int ManagerType { get; set; }
+
+ ///
+ /// 是否离职(0=在职,1=离职)
+ ///
+ [SugarColumn(ColumnName = "F_IsTerminated")]
+ public int IsTerminated { get; set; }
+
+ ///
+ /// 门店业绩明细(JSON格式)
+ ///
+ [SugarColumn(ColumnName = "F_StorePerformanceDetail", ColumnDataType = "TEXT")]
+ public string StorePerformanceDetail { get; set; }
+
+ ///
+ /// 底薪金额(固定4000元)
+ ///
+ [SugarColumn(ColumnName = "F_BaseSalary")]
+ public decimal BaseSalary { get; set; }
+
+ ///
+ /// 提成合计(所有门店提成金额汇总)
+ ///
+ [SugarColumn(ColumnName = "F_TotalCommission")]
+ public decimal TotalCommission { get; set; }
+
+ ///
+ /// 在店天数
+ ///
+ [SugarColumn(ColumnName = "F_WorkingDays")]
+ public decimal WorkingDays { get; set; }
+
+ ///
+ /// 请假天数
+ ///
+ [SugarColumn(ColumnName = "F_LeaveDays")]
+ public decimal LeaveDays { get; set; }
+
+ ///
+ /// 核算应发工资(底薪 + 提成合计)
+ ///
+ [SugarColumn(ColumnName = "F_CalculatedGrossSalary")]
+ public decimal CalculatedGrossSalary { get; set; }
+
+ ///
+ /// 最终应发工资
+ ///
+ [SugarColumn(ColumnName = "F_FinalGrossSalary")]
+ public decimal FinalGrossSalary { get; set; }
+
+ ///
+ /// 当月培训补贴
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTrainingSubsidy")]
+ public decimal MonthlyTrainingSubsidy { get; set; }
+
+ ///
+ /// 当月交通补贴
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTransportSubsidy")]
+ public decimal MonthlyTransportSubsidy { get; set; }
+
+ ///
+ /// 上月培训补贴
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthTrainingSubsidy")]
+ public decimal LastMonthTrainingSubsidy { get; set; }
+
+ ///
+ /// 上月交通补贴
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthTransportSubsidy")]
+ public decimal LastMonthTransportSubsidy { get; set; }
+
+ ///
+ /// 补贴合计
+ ///
+ [SugarColumn(ColumnName = "F_TotalSubsidy")]
+ public decimal TotalSubsidy { get; set; }
+
+ ///
+ /// 缺卡扣款
+ ///
+ [SugarColumn(ColumnName = "F_MissingCard")]
+ public decimal MissingCard { get; set; }
+
+ ///
+ /// 迟到扣款
+ ///
+ [SugarColumn(ColumnName = "F_LateArrival")]
+ public decimal LateArrival { get; set; }
+
+ ///
+ /// 请假扣款
+ ///
+ [SugarColumn(ColumnName = "F_LeaveDeduction")]
+ public decimal LeaveDeduction { get; set; }
+
+ ///
+ /// 扣社保
+ ///
+ [SugarColumn(ColumnName = "F_SocialInsuranceDeduction")]
+ public decimal SocialInsuranceDeduction { get; set; }
+
+ ///
+ /// 扣除奖励
+ ///
+ [SugarColumn(ColumnName = "F_RewardDeduction")]
+ public decimal RewardDeduction { get; set; }
+
+ ///
+ /// 扣住宿费
+ ///
+ [SugarColumn(ColumnName = "F_AccommodationDeduction")]
+ public decimal AccommodationDeduction { get; set; }
+
+ ///
+ /// 扣学习期费用
+ ///
+ [SugarColumn(ColumnName = "F_StudyPeriodDeduction")]
+ public decimal StudyPeriodDeduction { get; set; }
+
+ ///
+ /// 扣工作服费用
+ ///
+ [SugarColumn(ColumnName = "F_WorkClothesDeduction")]
+ public decimal WorkClothesDeduction { get; set; }
+
+ ///
+ /// 扣款合计
+ ///
+ [SugarColumn(ColumnName = "F_TotalDeduction")]
+ public decimal TotalDeduction { get; set; }
+
+ ///
+ /// 发奖金
+ ///
+ [SugarColumn(ColumnName = "F_Bonus")]
+ public decimal Bonus { get; set; }
+
+ ///
+ /// 退手机押金
+ ///
+ [SugarColumn(ColumnName = "F_ReturnPhoneDeposit")]
+ public decimal ReturnPhoneDeposit { get; set; }
+
+ ///
+ /// 退住宿押金
+ ///
+ [SugarColumn(ColumnName = "F_ReturnAccommodationDeposit")]
+ public decimal ReturnAccommodationDeposit { get; set; }
+
+ ///
+ /// 实发工资
+ ///
+ [SugarColumn(ColumnName = "F_ActualSalary")]
+ public decimal ActualSalary { get; set; }
+
+ ///
+ /// 当月是否发放
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyPaymentStatus")]
+ public string MonthlyPaymentStatus { get; set; }
+
+ ///
+ /// 支付金额
+ ///
+ [SugarColumn(ColumnName = "F_PaidAmount")]
+ public decimal PaidAmount { get; set; }
+
+ ///
+ /// 待支付金额
+ ///
+ [SugarColumn(ColumnName = "F_PendingAmount")]
+ public decimal PendingAmount { get; set; }
+
+ ///
+ /// 补发上月
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthSupplement")]
+ public decimal LastMonthSupplement { get; set; }
+
+ ///
+ /// 当月支付总额
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTotalPayment")]
+ public decimal MonthlyTotalPayment { get; set; }
+
+ ///
+ /// 是否锁定(0=未锁定,1=已锁定)
+ ///
+ [SugarColumn(ColumnName = "F_IsLocked")]
+ public int IsLocked { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnName = "F_CreateTime")]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnName = "F_UpdateTime")]
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ [SugarColumn(ColumnName = "F_CreateUser")]
+ public string CreateUser { get; set; }
+
+ ///
+ /// 更新人
+ ///
+ [SugarColumn(ColumnName = "F_UpdateUser")]
+ public string UpdateUser { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs
index a433bd6..24fd153 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs
@@ -143,5 +143,11 @@ namespace NCC.Extend.Entitys.lq_hytk_jksyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs
index 949d03e..785298c 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs
@@ -138,5 +138,11 @@ namespace NCC.Extend.Entitys.lq_hytk_kjbsyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs
index 06b8317..7c71af7 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs
@@ -126,5 +126,11 @@ namespace NCC.Extend.Entitys.lq_hytk_mx
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { 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 e6e28b0..68fa78a 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
@@ -60,3 +60,7 @@ 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 2a98eb9..b9933d3 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
@@ -78,3 +78,7 @@ namespace NCC.Extend.Entitys.lq_inventory_usage_approval_record
+
+
+
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs
index 62095b3..8ab55d5 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs
@@ -106,5 +106,11 @@ namespace NCC.Extend.Entitys.lq_kd_jksyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs
index 4f736fb..e5b4513 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs
@@ -106,5 +106,11 @@ namespace NCC.Extend.Entitys.lq_kd_kjbsyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs
index 924121c..0833783 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs
@@ -119,5 +119,12 @@ namespace NCC.Extend.Entitys.lq_kd_pxmx
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
+
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_major_project_teacher_salary_statistics/LqMajorProjectTeacherSalaryStatisticsEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_major_project_teacher_salary_statistics/LqMajorProjectTeacherSalaryStatisticsEntity.cs
new file mode 100644
index 0000000..c79c3c7
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_major_project_teacher_salary_statistics/LqMajorProjectTeacherSalaryStatisticsEntity.cs
@@ -0,0 +1,381 @@
+using System;
+using NCC.Common.Const;
+using SqlSugar;
+
+namespace NCC.Extend.Entitys.lq_major_project_teacher_salary_statistics
+{
+ ///
+ /// 大项目部老师工资统计表
+ ///
+ [SugarTable("lq_major_project_teacher_salary_statistics")]
+ [Tenant(ClaimConst.TENANT_ID)]
+ public class LqMajorProjectTeacherSalaryStatisticsEntity
+ {
+ ///
+ /// 主键ID
+ ///
+ [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ [SugarColumn(ColumnName = "F_StatisticsMonth", Length = 6)]
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 门店ID
+ ///
+ [SugarColumn(ColumnName = "F_StoreId")]
+ public string StoreId { get; set; }
+
+ ///
+ /// 门店名称
+ ///
+ [SugarColumn(ColumnName = "F_StoreName")]
+ public string StoreName { get; set; }
+
+ ///
+ /// 核算岗位
+ ///
+ [SugarColumn(ColumnName = "F_Position")]
+ public string Position { get; set; }
+
+ ///
+ /// 员工姓名
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeName")]
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 员工ID
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeId")]
+ public string EmployeeId { get; set; }
+
+ ///
+ /// 员工账号
+ ///
+ [SugarColumn(ColumnName = "F_EmployeeAccount")]
+ public string EmployeeAccount { get; set; }
+
+ ///
+ /// 开单业绩
+ ///
+ [SugarColumn(ColumnName = "F_OrderAchievement", DecimalDigits = 2)]
+ public decimal OrderAchievement { get; set; }
+
+ ///
+ /// 消耗业绩
+ ///
+ [SugarColumn(ColumnName = "F_ConsumeAchievement", DecimalDigits = 2)]
+ public decimal ConsumeAchievement { get; set; }
+
+ ///
+ /// 退卡业绩
+ ///
+ [SugarColumn(ColumnName = "F_RefundAchievement", DecimalDigits = 2)]
+ public decimal RefundAchievement { get; set; }
+
+ ///
+ /// 总业绩(开单业绩 + 消耗业绩 + 退卡业绩)
+ ///
+ [SugarColumn(ColumnName = "F_TotalPerformance", DecimalDigits = 2)]
+ public decimal TotalPerformance { get; set; }
+
+ ///
+ /// 底薪金额(固定3000元)
+ ///
+ [SugarColumn(ColumnName = "F_BaseSalary", DecimalDigits = 2)]
+ public decimal BaseSalary { get; set; }
+
+ ///
+ /// 业绩提成比例(百分比,如2.00表示2%,0.00表示无提成)
+ ///
+ [SugarColumn(ColumnName = "F_PerformanceCommissionRate", DecimalDigits = 4)]
+ public decimal PerformanceCommissionRate { get; set; }
+
+ ///
+ /// 业绩提成金额(总业绩 × 业绩提成比例,阶梯式计算)
+ ///
+ [SugarColumn(ColumnName = "F_PerformanceCommissionAmount", DecimalDigits = 2)]
+ public decimal PerformanceCommissionAmount { get; set; }
+
+ ///
+ /// 提成合计(业绩提成金额)
+ ///
+ [SugarColumn(ColumnName = "F_TotalCommission", DecimalDigits = 2)]
+ public decimal TotalCommission { get; set; }
+
+ ///
+ /// 手工费
+ ///
+ [SugarColumn(ColumnName = "F_HandworkFee", DecimalDigits = 2)]
+ public decimal HandworkFee { get; set; }
+
+ ///
+ /// 车补
+ ///
+ [SugarColumn(ColumnName = "F_TransportationAllowance", DecimalDigits = 2)]
+ public decimal TransportationAllowance { get; set; }
+
+ ///
+ /// 少休费
+ ///
+ [SugarColumn(ColumnName = "F_LessRest", DecimalDigits = 2)]
+ public decimal LessRest { get; set; }
+
+ ///
+ /// 全勤奖
+ ///
+ [SugarColumn(ColumnName = "F_FullAttendance", DecimalDigits = 2)]
+ public decimal FullAttendance { get; set; }
+
+ ///
+ /// 在店天数
+ ///
+ [SugarColumn(ColumnName = "F_WorkingDays", DecimalDigits = 2)]
+ public decimal WorkingDays { get; set; }
+
+ ///
+ /// 请假天数
+ ///
+ [SugarColumn(ColumnName = "F_LeaveDays", DecimalDigits = 2)]
+ public decimal LeaveDays { get; set; }
+
+ ///
+ /// 核算应发工资(底薪 + 提成合计 + 其他收入)
+ ///
+ [SugarColumn(ColumnName = "F_CalculatedGrossSalary", DecimalDigits = 2)]
+ public decimal CalculatedGrossSalary { get; set; }
+
+ ///
+ /// 保底工资
+ ///
+ [SugarColumn(ColumnName = "F_GuaranteedSalary", DecimalDigits = 2)]
+ public decimal GuaranteedSalary { get; set; }
+
+ ///
+ /// 保底请假扣款
+ ///
+ [SugarColumn(ColumnName = "F_GuaranteedLeaveDeduction", DecimalDigits = 2)]
+ public decimal GuaranteedLeaveDeduction { get; set; }
+
+ ///
+ /// 保底底薪
+ ///
+ [SugarColumn(ColumnName = "F_GuaranteedBaseSalary", DecimalDigits = 2)]
+ public decimal GuaranteedBaseSalary { get; set; }
+
+ ///
+ /// 保底补差
+ ///
+ [SugarColumn(ColumnName = "F_GuaranteedSupplement", DecimalDigits = 2)]
+ public decimal GuaranteedSupplement { get; set; }
+
+ ///
+ /// 最终应发工资(取核算应发工资和保底工资的较大值)
+ ///
+ [SugarColumn(ColumnName = "F_FinalGrossSalary", DecimalDigits = 2)]
+ public decimal FinalGrossSalary { get; set; }
+
+ ///
+ /// 当月培训补贴
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTrainingSubsidy", DecimalDigits = 2)]
+ public decimal MonthlyTrainingSubsidy { get; set; }
+
+ ///
+ /// 当月交通补贴
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTransportSubsidy", DecimalDigits = 2)]
+ public decimal MonthlyTransportSubsidy { get; set; }
+
+ ///
+ /// 上月培训补贴
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthTrainingSubsidy", DecimalDigits = 2)]
+ public decimal LastMonthTrainingSubsidy { get; set; }
+
+ ///
+ /// 上月交通补贴
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthTransportSubsidy", DecimalDigits = 2)]
+ public decimal LastMonthTransportSubsidy { get; set; }
+
+ ///
+ /// 补贴合计
+ ///
+ [SugarColumn(ColumnName = "F_TotalSubsidy", DecimalDigits = 2)]
+ public decimal TotalSubsidy { get; set; }
+
+ ///
+ /// 缺卡扣款
+ ///
+ [SugarColumn(ColumnName = "F_MissingCard", DecimalDigits = 2)]
+ public decimal MissingCard { get; set; }
+
+ ///
+ /// 迟到扣款
+ ///
+ [SugarColumn(ColumnName = "F_LateArrival", DecimalDigits = 2)]
+ public decimal LateArrival { get; set; }
+
+ ///
+ /// 请假扣款
+ ///
+ [SugarColumn(ColumnName = "F_LeaveDeduction", DecimalDigits = 2)]
+ public decimal LeaveDeduction { get; set; }
+
+ ///
+ /// 扣社保
+ ///
+ [SugarColumn(ColumnName = "F_SocialInsuranceDeduction", DecimalDigits = 2)]
+ public decimal SocialInsuranceDeduction { get; set; }
+
+ ///
+ /// 扣除奖励
+ ///
+ [SugarColumn(ColumnName = "F_RewardDeduction", DecimalDigits = 2)]
+ public decimal RewardDeduction { get; set; }
+
+ ///
+ /// 扣住宿费
+ ///
+ [SugarColumn(ColumnName = "F_AccommodationDeduction", DecimalDigits = 2)]
+ public decimal AccommodationDeduction { get; set; }
+
+ ///
+ /// 扣学习期费用
+ ///
+ [SugarColumn(ColumnName = "F_StudyPeriodDeduction", DecimalDigits = 2)]
+ public decimal StudyPeriodDeduction { get; set; }
+
+ ///
+ /// 扣工作服费用
+ ///
+ [SugarColumn(ColumnName = "F_WorkClothesDeduction", DecimalDigits = 2)]
+ public decimal WorkClothesDeduction { get; set; }
+
+ ///
+ /// 扣款合计
+ ///
+ [SugarColumn(ColumnName = "F_TotalDeduction", DecimalDigits = 2)]
+ public decimal TotalDeduction { get; set; }
+
+ ///
+ /// 发奖金
+ ///
+ [SugarColumn(ColumnName = "F_Bonus", DecimalDigits = 2)]
+ public decimal Bonus { get; set; }
+
+ ///
+ /// 退手机押金
+ ///
+ [SugarColumn(ColumnName = "F_ReturnPhoneDeposit", DecimalDigits = 2)]
+ public decimal ReturnPhoneDeposit { get; set; }
+
+ ///
+ /// 退住宿押金
+ ///
+ [SugarColumn(ColumnName = "F_ReturnAccommodationDeposit", DecimalDigits = 2)]
+ public decimal ReturnAccommodationDeposit { get; set; }
+
+ ///
+ /// 实发工资(最终应发工资 - 扣款合计 + 补贴合计 + 奖金)
+ ///
+ [SugarColumn(ColumnName = "F_ActualSalary", DecimalDigits = 2)]
+ public decimal ActualSalary { get; set; }
+
+ ///
+ /// 当月是否发放
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyPaymentStatus")]
+ public string MonthlyPaymentStatus { get; set; }
+
+ ///
+ /// 支付金额
+ ///
+ [SugarColumn(ColumnName = "F_PaidAmount", DecimalDigits = 2)]
+ public decimal PaidAmount { get; set; }
+
+ ///
+ /// 待支付金额
+ ///
+ [SugarColumn(ColumnName = "F_PendingAmount", DecimalDigits = 2)]
+ public decimal PendingAmount { get; set; }
+
+ ///
+ /// 补发上月
+ ///
+ [SugarColumn(ColumnName = "F_LastMonthSupplement", DecimalDigits = 2)]
+ public decimal LastMonthSupplement { get; set; }
+
+ ///
+ /// 当月支付总额
+ ///
+ [SugarColumn(ColumnName = "F_MonthlyTotalPayment", DecimalDigits = 2)]
+ public decimal MonthlyTotalPayment { get; set; }
+
+ ///
+ /// 是否锁定(0未锁定,1已锁定)
+ ///
+ [SugarColumn(ColumnName = "F_IsLocked")]
+ public int IsLocked { get; set; }
+
+ ///
+ /// 是否离职(0=在职,1=离职)
+ ///
+ [SugarColumn(ColumnName = "F_IsTerminated")]
+ public int IsTerminated { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnName = "F_CreateTime")]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnName = "F_UpdateTime")]
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ [SugarColumn(ColumnName = "F_CreateUser")]
+ public string CreateUser { get; set; }
+
+ ///
+ /// 更新人
+ ///
+ [SugarColumn(ColumnName = "F_UpdateUser")]
+ public string UpdateUser { get; set; }
+
+ ///
+ /// 是否新店
+ ///
+ [SugarColumn(ColumnName = "F_IsNewStore")]
+ public string IsNewStore { get; set; }
+
+ ///
+ /// 新店保护阶段
+ ///
+ [SugarColumn(ColumnName = "F_NewStoreProtectionStage")]
+ public int NewStoreProtectionStage { get; set; }
+
+ ///
+ /// 门店类型
+ ///
+ [SugarColumn(ColumnName = "F_StoreType")]
+ public int? StoreType { get; set; }
+
+ ///
+ /// 门店类别
+ ///
+ [SugarColumn(ColumnName = "F_StoreCategory")]
+ public int? StoreCategory { get; set; }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs
index 4e76dbc..1e4ae53 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs
@@ -42,6 +42,12 @@ namespace NCC.Extend.Entitys.lq_md_major_project_teacher_assignment
public string TeacherId { get; set; }
///
+ /// 教育部老师用户ID
+ ///
+ [SugarColumn(ColumnName = "F_EducationTeacherId")]
+ public string EducationTeacherId { get; set; }
+
+ ///
/// 备注说明
///
[SugarColumn(ColumnName = "F_Remark")]
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs
index 0f2d487..490ba04 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs
@@ -154,5 +154,11 @@ namespace NCC.Extend.Entitys.lq_xh_jksyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
\ No newline at end of file
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs
index 7d9588e..f228156 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs
@@ -136,5 +136,11 @@ namespace NCC.Extend.Entitys.lq_xh_kjbsyj
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科美类型(来源:lq_xmzl.F_BeautyType)
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
\ No newline at end of file
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs
index d2f3217..0a5de56 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs
@@ -112,5 +112,11 @@ namespace NCC.Extend.Entitys.lq_xh_pxmx
///
[SugarColumn(ColumnName = "F_PerformanceType")]
public string PerformanceType { get; set; }
+
+ ///
+ /// 科技部归类
+ ///
+ [SugarColumn(ColumnName = "F_BeautyType")]
+ public string BeautyType { get; set; }
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/FileUrlMigrationService.cs b/netcore/src/Modularity/Extend/NCC.Extend/FileUrlMigrationService.cs
new file mode 100644
index 0000000..56c2038
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/FileUrlMigrationService.cs
@@ -0,0 +1,518 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using NCC.Common.Extension;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.FriendlyException;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using SqlSugar;
+
+namespace NCC.Extend
+{
+ ///
+ /// 文件URL迁移服务 - 将本地文件路径转换为OSS路径
+ ///
+ [ApiDescriptionSettings(Tag = "数据迁移", Name = "FileUrlMigration", Order = 999)]
+ [Route("api/Extend/[controller]")]
+ public class FileUrlMigrationService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarRepository _repository;
+ private readonly SqlSugarScope _db;
+ private readonly ILogger _logger;
+
+ private const string OSS_BASE_URL = "http://oss.lvqianmeiye.com/Files/SystemFile";
+ private const string OLD_URL_PREFIX = "/api/File/Image/annexpic/";
+ private const string OLD_OSS_URL = "http://oss.lvqianmeiye.com";
+ private const string NEW_OSS_URL = "https://lvqian-erip.oss-cn-chengdu.aliyuncs.com";
+
+ ///
+ /// 初始化一个类型的新实例
+ ///
+ /// SqlSugar仓储
+ /// 日志记录器
+ public FileUrlMigrationService(ISqlSugarRepository repository, ILogger logger)
+ {
+ _repository = repository;
+ _db = _repository.Context;
+ _logger = logger;
+ }
+
+ ///
+ /// 迁移所有表的文件URL路径
+ ///
+ ///
+ /// 将数据库中的文件URL从本地路径格式转换为OSS路径格式
+ ///
+ /// 处理的表和字段:
+ /// 1. lq_kd_kdjlb: scwj, hyqz, F_FIleUrl
+ /// 2. lq_xh_feedback: F_BeforeImage, F_AfterImage
+ /// 3. lq_hytk_hytk: F_FileUrl, F_SignatureFile
+ /// 4. lq_purchase_records: F_Attachment
+ ///
+ /// URL转换规则:
+ /// 原格式:/api/File/Image/annexpic/文件名
+ /// 新格式:http://oss.lvqianmeiye.com/Files/SystemFile/文件名
+ ///
+ /// 迁移结果统计
+ [HttpPost("MigrateAllFileUrls")]
+ public async Task MigrateAllFileUrls()
+ {
+ var startTime = DateTime.Now;
+ _logger.LogInformation("开始迁移文件URL路径...");
+
+ var totalResults = new
+ {
+ lq_kd_kdjlb_scwj = await MigrateTableField("lq_kd_kdjlb", "scwj", "F_Id"),
+ lq_kd_kdjlb_hyqz = await MigrateTableField("lq_kd_kdjlb", "hyqz", "F_Id"),
+ lq_kd_kdjlb_F_FIleUrl = await MigrateTableField("lq_kd_kdjlb", "F_FIleUrl", "F_Id"),
+ lq_xh_feedback_F_BeforeImage = await MigrateTableField("lq_xh_feedback", "F_BeforeImage", "F_Id"),
+ lq_xh_feedback_F_AfterImage = await MigrateTableField("lq_xh_feedback", "F_AfterImage", "F_Id"),
+ lq_hytk_hytk_F_FileUrl = await MigrateTableField("lq_hytk_hytk", "F_FileUrl", "F_Id"),
+ lq_hytk_hytk_F_SignatureFile = await MigrateTableField("lq_hytk_hytk", "F_SignatureFile", "F_Id"),
+ lq_purchase_records_F_Attachment = await MigrateTableField("lq_purchase_records", "F_Attachment", "F_Id")
+ };
+
+ var endTime = DateTime.Now;
+ var duration = (endTime - startTime).TotalSeconds;
+
+ // 统计总数
+ var totalProcessed = 0;
+ var totalUpdated = 0;
+ var totalErrors = 0;
+
+ var resultsList = new List
+ {
+ totalResults.lq_kd_kdjlb_scwj,
+ totalResults.lq_kd_kdjlb_hyqz,
+ totalResults.lq_kd_kdjlb_F_FIleUrl,
+ totalResults.lq_xh_feedback_F_BeforeImage,
+ totalResults.lq_xh_feedback_F_AfterImage,
+ totalResults.lq_hytk_hytk_F_FileUrl,
+ totalResults.lq_hytk_hytk_F_SignatureFile,
+ totalResults.lq_purchase_records_F_Attachment
+ };
+
+ foreach (var result in resultsList)
+ {
+ totalProcessed += result.TotalProcessed;
+ totalUpdated += result.TotalUpdated;
+ totalErrors += result.TotalErrors;
+ }
+
+ _logger.LogInformation($"文件URL迁移完成,耗时:{duration:F2}秒,总处理:{totalProcessed},总更新:{totalUpdated},总错误:{totalErrors}");
+
+ return new
+ {
+ success = true,
+ duration = $"{duration:F2}秒",
+ summary = new
+ {
+ totalProcessed,
+ totalUpdated,
+ totalErrors
+ },
+ details = totalResults
+ };
+ }
+
+ ///
+ /// 迁移指定表的指定字段
+ ///
+ private async Task MigrateTableField(string tableName, string fieldName, string primaryKey)
+ {
+ var result = new MigrationResult
+ {
+ TableName = tableName,
+ FieldName = fieldName
+ };
+
+ try
+ {
+ _logger.LogInformation($"开始处理表 {tableName}.{fieldName}");
+
+ // 查询需要处理的数据
+ var sql = $@"
+ SELECT {primaryKey} as Id, {fieldName} as FieldValue
+ FROM {tableName}
+ WHERE {fieldName} IS NOT NULL
+ AND {fieldName} != ''
+ AND {fieldName} != '[]'
+ AND {fieldName} LIKE '%{OLD_URL_PREFIX}%'";
+
+ var records = await _db.Ado.SqlQueryAsync(sql);
+ result.TotalProcessed = records.Count;
+
+ if (records.Count == 0)
+ {
+ _logger.LogInformation($"表 {tableName}.{fieldName} 没有需要处理的数据");
+ return result;
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 找到 {records.Count} 条需要处理的数据");
+
+ // 分批处理,每批100条
+ const int batchSize = 100;
+ var totalBatches = (int)Math.Ceiling((double)records.Count / batchSize);
+
+ for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
+ {
+ var batch = records.Skip(batchIndex * batchSize).Take(batchSize).ToList();
+ var updateList = new List<(string id, string newValue)>();
+
+ foreach (var record in batch)
+ {
+ try
+ {
+ var id = record.Id?.ToString();
+ var fieldValue = record.FieldValue?.ToString();
+
+ if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(fieldValue))
+ continue;
+
+ var newValue = ConvertFileUrlJson(fieldValue);
+ if (newValue != null && newValue != fieldValue)
+ {
+ updateList.Add((id, newValue));
+ }
+ }
+ catch (Exception ex)
+ {
+ result.TotalErrors++;
+ _logger.LogError(ex, $"处理记录时出错,表:{tableName},字段:{fieldName},记录ID:{record.Id}");
+ }
+ }
+
+ // 批量更新
+ if (updateList.Any())
+ {
+ try
+ {
+ _db.BeginTran();
+ foreach (var (id, newValue) in updateList)
+ {
+ // 使用参数化查询防止SQL注入
+ var updateSql = $"UPDATE `{tableName}` SET `{fieldName}` = @Value WHERE `{primaryKey}` = @Id";
+ await _db.Ado.ExecuteCommandAsync(updateSql, new { Value = newValue, Id = id });
+ }
+ _db.CommitTran();
+ result.TotalUpdated += updateList.Count;
+ _logger.LogInformation($"表 {tableName}.{fieldName} 批次 {batchIndex + 1} 成功更新 {updateList.Count} 条记录");
+ }
+ catch (Exception ex)
+ {
+ _db.RollbackTran();
+ result.TotalErrors += updateList.Count;
+ _logger.LogError(ex, $"批量更新时出错,表:{tableName},字段:{fieldName},批次:{batchIndex + 1}");
+ }
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 批次 {batchIndex + 1}/{totalBatches} 处理完成");
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 处理完成,处理:{result.TotalProcessed},更新:{result.TotalUpdated},错误:{result.TotalErrors}");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"处理表 {tableName}.{fieldName} 时发生错误");
+ result.TotalErrors = result.TotalProcessed;
+ }
+
+ return result;
+ }
+
+ ///
+ /// 转换文件URL JSON字符串
+ ///
+ private string ConvertFileUrlJson(string jsonString)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(jsonString) || jsonString.Trim() == "[]")
+ return jsonString;
+
+ // 解析JSON数组
+ var jsonArray = JArray.Parse(jsonString);
+ bool hasChanges = false;
+
+ foreach (var item in jsonArray)
+ {
+ if (item is JObject obj && obj["url"] != null)
+ {
+ var url = obj["url"].ToString();
+ if (url.StartsWith(OLD_URL_PREFIX))
+ {
+ // 提取文件名
+ var fileName = url.Substring(OLD_URL_PREFIX.Length);
+ // 构建新的OSS URL
+ var newUrl = $"{OSS_BASE_URL}/{fileName}";
+ obj["url"] = newUrl;
+ hasChanges = true;
+ }
+ }
+ }
+
+ return hasChanges ? jsonArray.ToString(Formatting.None) : jsonString;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"转换JSON时出错:{jsonString}");
+ return jsonString; // 转换失败时返回原值
+ }
+ }
+
+ ///
+ /// 迁移所有表的OSS URL(将旧OSS地址替换为新OSS地址)
+ ///
+ ///
+ /// 将数据库中的文件URL从旧OSS地址格式转换为新OSS地址格式
+ ///
+ /// 处理的表和字段:
+ /// 1. lq_kd_kdjlb: scwj, hyqz, F_FIleUrl
+ /// 2. lq_xh_feedback: F_BeforeImage, F_AfterImage
+ /// 3. lq_hytk_hytk: F_FileUrl, F_SignatureFile
+ /// 4. lq_purchase_records: F_Attachment
+ ///
+ /// URL转换规则:
+ /// 原格式:http://oss.lvqianmeiye.com/...
+ /// 新格式:https://lvqian-erip.oss-cn-chengdu.aliyuncs.com/...
+ ///
+ /// 迁移结果统计
+ [HttpPost("MigrateOssUrls")]
+ public async Task MigrateOssUrls()
+ {
+ var startTime = DateTime.Now;
+ _logger.LogInformation("开始迁移OSS URL路径...");
+
+ var totalResults = new
+ {
+ lq_kd_kdjlb_scwj = await MigrateOssUrlInTableField("lq_kd_kdjlb", "scwj", "F_Id"),
+ lq_kd_kdjlb_hyqz = await MigrateOssUrlInTableField("lq_kd_kdjlb", "hyqz", "F_Id"),
+ lq_kd_kdjlb_F_FIleUrl = await MigrateOssUrlInTableField("lq_kd_kdjlb", "F_FIleUrl", "F_Id"),
+ lq_xh_feedback_F_BeforeImage = await MigrateOssUrlInTableField("lq_xh_feedback", "F_BeforeImage", "F_Id"),
+ lq_xh_feedback_F_AfterImage = await MigrateOssUrlInTableField("lq_xh_feedback", "F_AfterImage", "F_Id"),
+ lq_hytk_hytk_F_FileUrl = await MigrateOssUrlInTableField("lq_hytk_hytk", "F_FileUrl", "F_Id"),
+ lq_hytk_hytk_F_SignatureFile = await MigrateOssUrlInTableField("lq_hytk_hytk", "F_SignatureFile", "F_Id"),
+ lq_purchase_records_F_Attachment = await MigrateOssUrlInTableField("lq_purchase_records", "F_Attachment", "F_Id")
+ };
+
+ var endTime = DateTime.Now;
+ var duration = (endTime - startTime).TotalSeconds;
+
+ // 统计总数
+ var totalProcessed = 0;
+ var totalUpdated = 0;
+ var totalErrors = 0;
+
+ var resultsList = new List
+ {
+ totalResults.lq_kd_kdjlb_scwj,
+ totalResults.lq_kd_kdjlb_hyqz,
+ totalResults.lq_kd_kdjlb_F_FIleUrl,
+ totalResults.lq_xh_feedback_F_BeforeImage,
+ totalResults.lq_xh_feedback_F_AfterImage,
+ totalResults.lq_hytk_hytk_F_FileUrl,
+ totalResults.lq_hytk_hytk_F_SignatureFile,
+ totalResults.lq_purchase_records_F_Attachment
+ };
+
+ foreach (var result in resultsList)
+ {
+ totalProcessed += result.TotalProcessed;
+ totalUpdated += result.TotalUpdated;
+ totalErrors += result.TotalErrors;
+ }
+
+ _logger.LogInformation($"OSS URL迁移完成,耗时:{duration:F2}秒,总处理:{totalProcessed},总更新:{totalUpdated},总错误:{totalErrors}");
+
+ return new
+ {
+ success = true,
+ duration = $"{duration:F2}秒",
+ summary = new
+ {
+ totalProcessed,
+ totalUpdated,
+ totalErrors
+ },
+ details = totalResults
+ };
+ }
+
+ ///
+ /// 迁移指定表的指定字段中的OSS URL
+ ///
+ private async Task MigrateOssUrlInTableField(string tableName, string fieldName, string primaryKey)
+ {
+ var result = new MigrationResult
+ {
+ TableName = tableName,
+ FieldName = fieldName
+ };
+
+ try
+ {
+ _logger.LogInformation($"开始处理表 {tableName}.{fieldName} 的OSS URL迁移");
+
+ // 查询需要处理的数据(包含旧OSS URL的记录)
+ var sql = $@"
+ SELECT {primaryKey} as Id, {fieldName} as FieldValue
+ FROM {tableName}
+ WHERE {fieldName} IS NOT NULL
+ AND {fieldName} != ''
+ AND {fieldName} != '[]'
+ AND {fieldName} LIKE '%{OLD_OSS_URL}%'";
+
+ var records = await _db.Ado.SqlQueryAsync(sql);
+ result.TotalProcessed = records.Count;
+
+ if (records.Count == 0)
+ {
+ _logger.LogInformation($"表 {tableName}.{fieldName} 没有需要处理的数据");
+ return result;
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 找到 {records.Count} 条需要处理的数据");
+
+ // 分批处理,每批100条
+ const int batchSize = 100;
+ var totalBatches = (int)Math.Ceiling((double)records.Count / batchSize);
+
+ for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
+ {
+ var batch = records.Skip(batchIndex * batchSize).Take(batchSize).ToList();
+ var updateList = new List<(string id, string newValue)>();
+
+ foreach (var record in batch)
+ {
+ try
+ {
+ var id = record.Id?.ToString();
+ var fieldValue = record.FieldValue?.ToString();
+
+ if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(fieldValue))
+ continue;
+
+ var newValue = ReplaceOssUrlInJson(fieldValue);
+ if (newValue != null && newValue != fieldValue)
+ {
+ updateList.Add((id, newValue));
+ }
+ }
+ catch (Exception ex)
+ {
+ result.TotalErrors++;
+ _logger.LogError(ex, $"处理记录时出错,表:{tableName},字段:{fieldName},记录ID:{record.Id}");
+ }
+ }
+
+ // 批量更新
+ if (updateList.Any())
+ {
+ try
+ {
+ _db.BeginTran();
+ foreach (var (id, newValue) in updateList)
+ {
+ // 使用参数化查询防止SQL注入
+ var updateSql = $"UPDATE `{tableName}` SET `{fieldName}` = @Value WHERE `{primaryKey}` = @Id";
+ await _db.Ado.ExecuteCommandAsync(updateSql, new { Value = newValue, Id = id });
+ }
+ _db.CommitTran();
+ result.TotalUpdated += updateList.Count;
+ _logger.LogInformation($"表 {tableName}.{fieldName} 批次 {batchIndex + 1} 成功更新 {updateList.Count} 条记录");
+ }
+ catch (Exception ex)
+ {
+ _db.RollbackTran();
+ result.TotalErrors += updateList.Count;
+ _logger.LogError(ex, $"批量更新时出错,表:{tableName},字段:{fieldName},批次:{batchIndex + 1}");
+ }
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 批次 {batchIndex + 1}/{totalBatches} 处理完成");
+ }
+
+ _logger.LogInformation($"表 {tableName}.{fieldName} 处理完成,处理:{result.TotalProcessed},更新:{result.TotalUpdated},错误:{result.TotalErrors}");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"处理表 {tableName}.{fieldName} 时发生错误");
+ result.TotalErrors = result.TotalProcessed;
+ }
+
+ return result;
+ }
+
+ ///
+ /// 替换JSON字符串中的OSS URL
+ ///
+ private string ReplaceOssUrlInJson(string jsonString)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(jsonString) || jsonString.Trim() == "[]")
+ return jsonString;
+
+ // 如果包含旧OSS URL,直接替换
+ if (jsonString.Contains(OLD_OSS_URL))
+ {
+ var newJsonString = jsonString.Replace(OLD_OSS_URL, NEW_OSS_URL);
+
+ // 如果是JSON数组格式,需要解析并替换
+ try
+ {
+ var jsonArray = JArray.Parse(jsonString);
+ bool hasChanges = false;
+
+ foreach (var item in jsonArray)
+ {
+ if (item is JObject obj && obj["url"] != null)
+ {
+ var url = obj["url"].ToString();
+ if (url.Contains(OLD_OSS_URL))
+ {
+ obj["url"] = url.Replace(OLD_OSS_URL, NEW_OSS_URL);
+ hasChanges = true;
+ }
+ }
+ }
+
+ return hasChanges ? jsonArray.ToString(Formatting.None) : jsonString;
+ }
+ catch
+ {
+ // 如果不是JSON格式,直接替换字符串
+ return newJsonString;
+ }
+ }
+
+ return jsonString;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"替换OSS URL时出错:{jsonString}");
+ return jsonString; // 转换失败时返回原值
+ }
+ }
+
+ ///
+ /// 迁移结果
+ ///
+ private class MigrationResult
+ {
+ public string TableName { get; set; }
+ public string FieldName { get; set; }
+ public int TotalProcessed { get; set; }
+ public int TotalUpdated { get; set; }
+ public int TotalErrors { get; set; }
+ }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs
new file mode 100644
index 0000000..83a8deb
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs
@@ -0,0 +1,514 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using NCC.Common.Filter;
+using NCC.Common.Helper;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.Dto.LqBusinessUnitManagerSalary;
+using NCC.Extend.Entitys.lq_attendance_summary;
+using NCC.Extend.Entitys.lq_hytk_hytk;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_md_general_manager_lifeline;
+using NCC.Extend.Entitys.lq_md_target;
+using NCC.Extend.Entitys.lq_mdxx;
+using NCC.Extend.Entitys.lq_business_unit_manager_salary_statistics;
+using NCC.System.Entitys.Permission;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace NCC.Extend
+{
+ ///
+ /// 事业部总经理/经理薪酬服务
+ ///
+ [ApiDescriptionSettings(Tag = "事业部总经理/经理薪酬服务", Name = "LqBusinessUnitManagerSalary", Order = 304)]
+ [Route("api/Extend/[controller]")]
+ public class LqBusinessUnitManagerSalaryService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarClient _db;
+
+ ///
+ /// 初始化一个类型的新实例
+ ///
+ public LqBusinessUnitManagerSalaryService(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ ///
+ /// 获取事业部总经理/经理工资列表
+ ///
+ /// 查询参数
+ /// 事业部总经理/经理工资分页列表
+ [HttpGet("business-unit-manager")]
+ public async Task GetBusinessUnitManagerSalaryList([FromQuery] BusinessUnitManagerSalaryInput input)
+ {
+ var monthStr = $"{input.Year}{input.Month:D2}";
+
+ // 1. 检查当月是否已生成工资数据
+ var exists = await _db.Queryable()
+ .AnyAsync(x => x.StatisticsMonth == monthStr);
+
+ // 2. 如果没有数据,则进行计算
+ if (!exists)
+ {
+ await CalculateBusinessUnitManagerSalary(input.Year, input.Month);
+ }
+
+ // 3. 查询数据
+ var query = _db.Queryable()
+ .Where(x => x.StatisticsMonth == monthStr);
+
+ if (input.ManagerType.HasValue)
+ {
+ query = query.Where(x => x.ManagerType == input.ManagerType.Value);
+ }
+
+ if (!string.IsNullOrEmpty(input.Keyword))
+ {
+ query = query.Where(x => x.EmployeeName.Contains(input.Keyword) || x.EmployeeAccount.Contains(input.Keyword));
+ }
+
+ var list = await query.Select(x => new BusinessUnitManagerSalaryOutput
+ {
+ Id = x.Id,
+ StatisticsMonth = x.StatisticsMonth,
+ Position = x.Position,
+ EmployeeName = x.EmployeeName,
+ EmployeeId = x.EmployeeId,
+ EmployeeAccount = x.EmployeeAccount,
+ ManagerType = x.ManagerType,
+ IsTerminated = x.IsTerminated,
+ StorePerformanceDetail = x.StorePerformanceDetail,
+ BaseSalary = x.BaseSalary,
+ TotalCommission = x.TotalCommission,
+ WorkingDays = x.WorkingDays,
+ LeaveDays = x.LeaveDays,
+ CalculatedGrossSalary = x.CalculatedGrossSalary,
+ FinalGrossSalary = x.FinalGrossSalary,
+ MonthlyTrainingSubsidy = x.MonthlyTrainingSubsidy,
+ MonthlyTransportSubsidy = x.MonthlyTransportSubsidy,
+ LastMonthTrainingSubsidy = x.LastMonthTrainingSubsidy,
+ LastMonthTransportSubsidy = x.LastMonthTransportSubsidy,
+ TotalSubsidy = x.TotalSubsidy,
+ MissingCard = x.MissingCard,
+ LateArrival = x.LateArrival,
+ LeaveDeduction = x.LeaveDeduction,
+ SocialInsuranceDeduction = x.SocialInsuranceDeduction,
+ RewardDeduction = x.RewardDeduction,
+ AccommodationDeduction = x.AccommodationDeduction,
+ StudyPeriodDeduction = x.StudyPeriodDeduction,
+ WorkClothesDeduction = x.WorkClothesDeduction,
+ TotalDeduction = x.TotalDeduction,
+ Bonus = x.Bonus,
+ ReturnPhoneDeposit = x.ReturnPhoneDeposit,
+ ReturnAccommodationDeposit = x.ReturnAccommodationDeposit,
+ ActualSalary = x.ActualSalary,
+ MonthlyPaymentStatus = x.MonthlyPaymentStatus,
+ PaidAmount = x.PaidAmount,
+ PendingAmount = x.PendingAmount,
+ LastMonthSupplement = x.LastMonthSupplement,
+ MonthlyTotalPayment = x.MonthlyTotalPayment,
+ IsLocked = x.IsLocked,
+ UpdateTime = x.UpdateTime
+ })
+ .ToPagedListAsync(input.currentPage, input.pageSize);
+
+ return PageResult.SqlSugarPageResult(list);
+ }
+
+ ///
+ /// 计算事业部总经理/经理工资
+ ///
+ /// 年份
+ /// 月份
+ ///
+ [HttpPost("calculate/business-unit-manager")]
+ public async Task CalculateBusinessUnitManagerSalary(int year, int month)
+ {
+ var startDate = new DateTime(year, month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+ var monthStr = $"{year}{month:D2}";
+
+ // 1. 获取基础数据
+
+ // 1.1 获取总经理/经理归属信息(从lq_md_general_manager_lifeline表)
+ var lifelineList = await _db.Queryable()
+ .Where(x => x.Month == monthStr)
+ .ToListAsync();
+
+ if (!lifelineList.Any())
+ {
+ // 如果没有归属信息,直接返回
+ return;
+ }
+
+ // 1.2 获取所有不重复的总经理/经理ID(确保所有总经理/经理都被计算)
+ var allManagerIds = lifelineList
+ .Where(x => !string.IsNullOrEmpty(x.GeneralManagerId))
+ .Select(x => x.GeneralManagerId)
+ .Distinct()
+ .ToList();
+
+ // 1.3 按总经理/经理ID分组,获取每个总经理/经理管理的门店
+ var managerStoreDict = lifelineList
+ .Where(x => !string.IsNullOrEmpty(x.GeneralManagerId) && !string.IsNullOrEmpty(x.StoreId))
+ .GroupBy(x => x.GeneralManagerId)
+ .ToDictionary(g => g.Key, g => g.Select(x => x.StoreId).Distinct().ToList());
+
+ // 1.4 门店信息 (lq_mdxx)
+ var storeList = await _db.Queryable().ToListAsync();
+ var storeDict = storeList.Where(x => !string.IsNullOrEmpty(x.Id)).ToDictionary(x => x.Id, x => x);
+
+ // 1.5 门店生命线信息 (lq_md_target)
+ var targetList = await _db.Queryable()
+ .Where(x => x.Month == monthStr)
+ .ToListAsync();
+ var storeLifelineDict = targetList
+ .Where(x => !string.IsNullOrEmpty(x.StoreId))
+ .ToDictionary(x => x.StoreId, x => x.StoreLifeline);
+
+ // 1.6 门店总业绩计算 (开单实付 - 退卡金额)
+ // 开单实付(从lq_kd_kdjlb表统计sfyj字段)
+ var storeBillingList = await _db.Queryable()
+ .Where(x => x.Kdrq >= startDate && x.Kdrq <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Select(x => new { x.Djmd, x.Sfyj })
+ .ToListAsync();
+ var storeBillingDict = storeBillingList
+ .Where(x => !string.IsNullOrEmpty(x.Djmd))
+ .GroupBy(x => x.Djmd)
+ .ToDictionary(g => g.Key, g => g.Sum(x => x.Sfyj));
+
+ // 退卡金额(从lq_hytk_hytk表统计,使用F_ActualRefundAmount,如果没有则使用tkje)
+ var storeRefundList = await _db.Queryable()
+ .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Select(x => new { x.Md, x.ActualRefundAmount, x.Tkje })
+ .ToListAsync();
+ var storeRefundDict = storeRefundList
+ .Where(x => !string.IsNullOrEmpty(x.Md))
+ .GroupBy(x => x.Md)
+ .ToDictionary(g => g.Key, g => g.Sum(x => x.ActualRefundAmount ?? x.Tkje ?? 0));
+
+ // 1.7 考勤数据 (lq_attendance_summary)
+ var attendanceList = await _db.Queryable()
+ .Where(x => x.Year == year && x.Month == month && x.IsEffective == 1)
+ .ToListAsync();
+ var attendanceDict = attendanceList.ToDictionary(x => x.UserId, x => x);
+
+ // 1.8 获取员工信息 (BASE_USER)
+ var userList = await _db.Queryable()
+ .Where(x => allManagerIds.Contains(x.Id))
+ .Select(x => new { x.Id, x.RealName, x.Account, x.IsOnJob })
+ .ToListAsync();
+ var userDict = userList.ToDictionary(x => x.Id, x => x);
+
+ // 2. 按总经理/经理聚合数据
+ var managerStats = new Dictionary();
+
+ foreach (var managerId in allManagerIds)
+ {
+ if (string.IsNullOrEmpty(managerId))
+ {
+ continue;
+ }
+
+ // 获取该总经理/经理的信息
+ var managerLifeline = lifelineList.FirstOrDefault(x => x.GeneralManagerId == managerId);
+ if (managerLifeline == null)
+ {
+ continue;
+ }
+
+ // 2.1 创建工资统计对象
+ var salary = new LqBusinessUnitManagerSalaryStatisticsEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ StatisticsMonth = monthStr,
+ EmployeeId = managerId,
+ ManagerType = managerLifeline.ManagerType,
+ Position = managerLifeline.ManagerType == 1 ? "总经理" : "经理",
+ IsTerminated = 0,
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now,
+ IsLocked = 0
+ };
+
+ // 2.2 填充员工信息
+ if (userDict.ContainsKey(managerId))
+ {
+ var user = userDict[managerId];
+ salary.EmployeeName = user.RealName ?? "";
+ salary.EmployeeAccount = user.Account ?? "";
+ salary.IsTerminated = user.IsOnJob == 0 ? 1 : 0;
+ }
+
+ // 2.3 考勤数据
+ var attendance = attendanceDict.ContainsKey(managerId) ? attendanceDict[managerId] : null;
+ salary.WorkingDays = attendance?.WorkDays ?? 0;
+ salary.LeaveDays = attendance?.LeaveDays ?? 0;
+
+ // 2.4 计算底薪(固定4000元)
+ salary.BaseSalary = 4000m;
+
+ // 2.5 遍历该总经理/经理管理的每个门店,计算提成
+ var storePerformanceDetails = new List();
+ decimal totalCommission = 0m;
+
+ // 获取该总经理/经理管理的门店列表(如果没有管理的门店,则为空列表)
+ var managedStores = managerStoreDict.ContainsKey(managerId) ? managerStoreDict[managerId] : new List();
+ foreach (var storeId in managedStores)
+ {
+ if (string.IsNullOrEmpty(storeId))
+ {
+ continue;
+ }
+
+ // 获取该门店的提成阶梯设置
+ var storeLifelineSetting = lifelineList.FirstOrDefault(x => x.StoreId == storeId && x.GeneralManagerId == managerId);
+ if (storeLifelineSetting == null)
+ {
+ continue;
+ }
+
+ // 获取门店信息
+ var storeName = storeDict.ContainsKey(storeId) ? storeDict[storeId].Dm ?? "" : "";
+
+ // 获取门店生命线(提成门槛)
+ if (!storeLifelineDict.ContainsKey(storeId))
+ {
+ // 门店生命线未设置,跳过该门店
+ storePerformanceDetails.Add(new StorePerformanceDetail
+ {
+ StoreId = storeId,
+ StoreName = storeName,
+ StoreLifeline = 0,
+ BillingPerformance = 0,
+ RefundPerformance = 0,
+ StorePerformance = 0,
+ ReachedLifeline = false,
+ CommissionAmount = 0,
+ CalculationDetail = "门店生命线未设置,无法计算提成"
+ });
+ continue;
+ }
+
+ var storeLifeline = storeLifelineDict[storeId];
+ if (storeLifeline <= 0)
+ {
+ // 门店生命线未设置或为0,跳过该门店
+ storePerformanceDetails.Add(new StorePerformanceDetail
+ {
+ StoreId = storeId,
+ StoreName = storeName,
+ StoreLifeline = 0,
+ BillingPerformance = 0,
+ RefundPerformance = 0,
+ StorePerformance = 0,
+ ReachedLifeline = false,
+ CommissionAmount = 0,
+ CalculationDetail = "门店生命线未设置或为0,无法计算提成"
+ });
+ continue;
+ }
+
+ // 获取门店业绩
+ var billing = storeBillingDict.ContainsKey(storeId) ? storeBillingDict[storeId] : 0;
+ var refund = storeRefundDict.ContainsKey(storeId) ? storeRefundDict[storeId] : 0;
+ var storePerformance = billing - refund;
+
+ // 判断是否达到门店生命线
+ var reachedLifeline = storePerformance >= storeLifeline;
+
+ // 计算提成
+ decimal commissionAmount = 0m;
+ string calculationDetail = "";
+
+ if (reachedLifeline)
+ {
+ // 达到门店生命线,使用提成阶梯计算提成(分段累进)
+ var commissionResult = CalculateStoreCommission(storePerformance, storeLifelineSetting);
+ commissionAmount = commissionResult.Amount;
+ calculationDetail = commissionResult.Detail;
+
+ totalCommission += commissionAmount;
+ }
+ else
+ {
+ calculationDetail = $"业绩{storePerformance:N2}元,未达到门店生命线{storeLifeline:N2}元,无提成";
+ }
+
+ // 添加到门店业绩明细
+ storePerformanceDetails.Add(new StorePerformanceDetail
+ {
+ StoreId = storeId,
+ StoreName = storeName,
+ StoreLifeline = storeLifeline,
+ BillingPerformance = billing,
+ RefundPerformance = refund,
+ StorePerformance = storePerformance,
+ ReachedLifeline = reachedLifeline,
+ Lifeline1 = storeLifelineSetting.Lifeline1,
+ CommissionRate1 = storeLifelineSetting.CommissionRate1,
+ Lifeline2 = storeLifelineSetting.Lifeline2,
+ CommissionRate2 = storeLifelineSetting.CommissionRate2,
+ Lifeline3 = storeLifelineSetting.Lifeline3,
+ CommissionRate3 = storeLifelineSetting.CommissionRate3,
+ CommissionAmount = commissionAmount,
+ CalculationDetail = calculationDetail
+ });
+ }
+
+ // 2.6 保存门店业绩明细(JSON格式)
+ salary.StorePerformanceDetail = storePerformanceDetails.ToJson();
+
+ // 2.7 提成合计
+ salary.TotalCommission = totalCommission;
+
+ // 2.8 计算应发工资
+ salary.CalculatedGrossSalary = salary.BaseSalary + salary.TotalCommission;
+ salary.FinalGrossSalary = salary.CalculatedGrossSalary;
+
+ // 2.9 初始化其他字段(默认值为0)
+ salary.MonthlyTrainingSubsidy = 0;
+ salary.MonthlyTransportSubsidy = 0;
+ salary.LastMonthTrainingSubsidy = 0;
+ salary.LastMonthTransportSubsidy = 0;
+ salary.TotalSubsidy = 0;
+ salary.MissingCard = 0;
+ salary.LateArrival = 0;
+ salary.LeaveDeduction = 0;
+ salary.SocialInsuranceDeduction = 0;
+ salary.RewardDeduction = 0;
+ salary.AccommodationDeduction = 0;
+ salary.StudyPeriodDeduction = 0;
+ salary.WorkClothesDeduction = 0;
+ salary.TotalDeduction = 0;
+ salary.Bonus = 0;
+ salary.ReturnPhoneDeposit = 0;
+ salary.ReturnAccommodationDeposit = 0;
+ salary.ActualSalary = salary.FinalGrossSalary - salary.TotalDeduction + salary.TotalSubsidy + salary.Bonus;
+ salary.MonthlyPaymentStatus = "未发放";
+ salary.PaidAmount = 0;
+ salary.PendingAmount = salary.ActualSalary;
+ salary.LastMonthSupplement = 0;
+ salary.MonthlyTotalPayment = 0;
+
+ managerStats[managerId] = salary;
+ }
+
+ // 3. 保存数据
+ if (managerStats.Any())
+ {
+ // 先删除当月旧数据 (防止重复)
+ await _db.Deleteable()
+ .Where(x => x.StatisticsMonth == monthStr)
+ .ExecuteCommandAsync();
+
+ await _db.Insertable(managerStats.Values.ToList()).ExecuteCommandAsync();
+ }
+ }
+
+ ///
+ /// 计算门店提成(分段累进)
+ ///
+ /// 门店业绩
+ /// 提成阶梯设置
+ /// 提成金额和计算说明
+ private (decimal Amount, string Detail) CalculateStoreCommission(decimal storePerformance, LqMdGeneralManagerLifelineEntity lifelineSetting)
+ {
+ // 验证提成阶梯1和提成比例1必须设置
+ if (lifelineSetting.Lifeline1 <= 0 || lifelineSetting.CommissionRate1 <= 0)
+ {
+ return (0m, "提成阶梯1或提成比例1未设置,无法计算提成");
+ }
+
+ decimal commissionAmount = 0m;
+ string detail = "";
+
+ var lifeline1 = lifelineSetting.Lifeline1;
+ var rate1 = lifelineSetting.CommissionRate1;
+ var lifeline2 = lifelineSetting.Lifeline2 ?? 0;
+ var rate2 = lifelineSetting.CommissionRate2 ?? 0;
+ var lifeline3 = lifelineSetting.Lifeline3 ?? 0;
+ var rate3 = lifelineSetting.CommissionRate3 ?? 0;
+
+ // 分段累进计算
+ if (storePerformance <= lifeline1)
+ {
+ // 业绩 ≤ 提成阶梯1
+ commissionAmount = storePerformance * (rate1 / 100m);
+ detail = $"业绩{storePerformance:N2}元,≤ 提成阶梯1({lifeline1:N2}元),提成 = {storePerformance:N2} × {rate1}% = {commissionAmount:N2}元";
+ }
+ else if (lifeline2 > 0 && storePerformance <= lifeline2)
+ {
+ // 提成阶梯1 < 业绩 ≤ 提成阶梯2
+ var part1 = lifeline1 * (rate1 / 100m);
+ var part2 = (storePerformance - lifeline1) * (rate2 / 100m);
+ commissionAmount = part1 + part2;
+ detail = $"业绩{storePerformance:N2}元,> 提成阶梯1({lifeline1:N2}元) 且 ≤ 提成阶梯2({lifeline2:N2}元),提成 = {lifeline1:N2} × {rate1}% + ({storePerformance:N2} - {lifeline1:N2}) × {rate2}% = {part1:N2} + {part2:N2} = {commissionAmount:N2}元";
+ }
+ else if (lifeline3 > 0 && storePerformance <= lifeline3)
+ {
+ // 提成阶梯2 < 业绩 ≤ 提成阶梯3
+ var part1 = lifeline1 * (rate1 / 100m);
+ var part2 = (lifeline2 - lifeline1) * (rate2 / 100m);
+ var part3 = (storePerformance - lifeline2) * (rate3 / 100m);
+ commissionAmount = part1 + part2 + part3;
+ detail = $"业绩{storePerformance:N2}元,> 提成阶梯2({lifeline2:N2}元) 且 ≤ 提成阶梯3({lifeline3:N2}元),提成 = {lifeline1:N2} × {rate1}% + ({lifeline2:N2} - {lifeline1:N2}) × {rate2}% + ({storePerformance:N2} - {lifeline2:N2}) × {rate3}% = {part1:N2} + {part2:N2} + {part3:N2} = {commissionAmount:N2}元";
+ }
+ else if (lifeline3 > 0)
+ {
+ // 业绩 > 提成阶梯3
+ var part1 = lifeline1 * (rate1 / 100m);
+ var part2 = (lifeline2 - lifeline1) * (rate2 / 100m);
+ var part3 = (lifeline3 - lifeline2) * (rate3 / 100m);
+ var part4 = (storePerformance - lifeline3) * (rate3 / 100m);
+ commissionAmount = part1 + part2 + part3 + part4;
+ detail = $"业绩{storePerformance:N2}元,> 提成阶梯3({lifeline3:N2}元),提成 = {lifeline1:N2} × {rate1}% + ({lifeline2:N2} - {lifeline1:N2}) × {rate2}% + ({lifeline3:N2} - {lifeline2:N2}) × {rate3}% + ({storePerformance:N2} - {lifeline3:N2}) × {rate3}% = {part1:N2} + {part2:N2} + {part3:N2} + {part4:N2} = {commissionAmount:N2}元";
+ }
+ else if (lifeline2 > 0)
+ {
+ // 提成阶梯3未设置,业绩 > 提成阶梯2,按提成比例2计算超出部分
+ var part1 = lifeline1 * (rate1 / 100m);
+ var part2 = (storePerformance - lifeline1) * (rate2 / 100m);
+ commissionAmount = part1 + part2;
+ detail = $"业绩{storePerformance:N2}元,> 提成阶梯2({lifeline2:N2}元),提成阶梯3未设置,提成 = {lifeline1:N2} × {rate1}% + ({storePerformance:N2} - {lifeline1:N2}) × {rate2}% = {part1:N2} + {part2:N2} = {commissionAmount:N2}元";
+ }
+ else
+ {
+ // 只有提成阶梯1,业绩 > 提成阶梯1,按提成比例1计算
+ commissionAmount = storePerformance * (rate1 / 100m);
+ detail = $"业绩{storePerformance:N2}元,> 提成阶梯1({lifeline1:N2}元),提成阶梯2未设置,提成 = {storePerformance:N2} × {rate1}% = {commissionAmount:N2}元";
+ }
+
+ return (commissionAmount, detail);
+ }
+
+ ///
+ /// 门店业绩明细(用于JSON序列化)
+ ///
+ private class StorePerformanceDetail
+ {
+ public string StoreId { get; set; }
+ public string StoreName { get; set; }
+ public decimal StoreLifeline { get; set; }
+ public decimal BillingPerformance { get; set; }
+ public decimal RefundPerformance { get; set; }
+ public decimal StorePerformance { get; set; }
+ public bool ReachedLifeline { get; set; }
+ public decimal Lifeline1 { get; set; }
+ public decimal CommissionRate1 { get; set; }
+ public decimal? Lifeline2 { get; set; }
+ public decimal? CommissionRate2 { get; set; }
+ public decimal? Lifeline3 { get; set; }
+ public decimal? CommissionRate3 { get; set; }
+ public decimal CommissionAmount { get; set; }
+ public string CalculationDetail { get; set; }
+ }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
index af4eb99..577b317 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
@@ -355,6 +355,7 @@ namespace NCC.Extend.LqHytkHytk
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allMxEntities.Add(lqHytkMxEntity);
@@ -384,7 +385,8 @@ namespace NCC.Extend.LqHytkHytk
ItemId = lqHytkMxEntity.Px,
StoreId = newEntity.Md,
ItemName = lqHytkMxEntity.Pxmc,
- PerformanceType = lqHytkMxEntity.PerformanceType
+ PerformanceType = lqHytkMxEntity.PerformanceType,
+ BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
@@ -416,7 +418,8 @@ namespace NCC.Extend.LqHytkHytk
ItemId = lqHytkMxEntity.Px,
StoreId = newEntity.Md,
ItemName = lqHytkMxEntity.Pxmc,
- PerformanceType = lqHytkMxEntity.PerformanceType
+ PerformanceType = lqHytkMxEntity.PerformanceType,
+ BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
@@ -517,6 +520,7 @@ namespace NCC.Extend.LqHytkHytk
TotalPrice = item.F_TotalPrice ?? (item.pxjg * (item.F_ProjectNumber ?? 1)),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allMxEntities.Add(lqHytkMxEntity);
@@ -545,7 +549,8 @@ namespace NCC.Extend.LqHytkHytk
ItemId = lqHytkMxEntity.Px,
StoreId = entity.Md,
ItemName = lqHytkMxEntity.Pxmc,
- PerformanceType = lqHytkMxEntity.PerformanceType
+ PerformanceType = lqHytkMxEntity.PerformanceType,
+ BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
@@ -575,7 +580,8 @@ namespace NCC.Extend.LqHytkHytk
ItemId = lqHytkMxEntity.Px,
StoreId = entity.Md,
ItemName = lqHytkMxEntity.Pxmc,
- PerformanceType = lqHytkMxEntity.PerformanceType
+ PerformanceType = lqHytkMxEntity.PerformanceType,
+ BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
index f5b6d7c..8c53d98 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
@@ -538,7 +538,7 @@ namespace NCC.Extend
{
var sidx = input.sidx == null ? "id" : input.sidx;
- // 查询使用记录信息,关联产品表
+ // 查询使用记录信息,关联产品表(使用Queryable语法,与GetBatchInfoAsync保持一致)
var data = await _db.Queryable((u, product) => u.ProductId == product.Id)
.WhereIF(!string.IsNullOrWhiteSpace(input.ProductId), (u, product) => u.ProductId == input.ProductId)
.WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (u, product) => u.StoreId == input.StoreId)
@@ -562,6 +562,8 @@ namespace NCC.Extend
totalAmount = u.TotalAmount, // 总价(单价 × 数量)
relatedConsumeId = u.RelatedConsumeId,
usageBatchId = u.UsageBatchId,
+ approvalStatus = null, // 审批状态(稍后在内存中补充)
+ isReceived = null, // 是否已领取(稍后在内存中补充)
createUser = u.CreateUser,
createUserName = "",
createTime = u.CreateTime,
@@ -574,6 +576,35 @@ namespace NCC.Extend
.OrderBy(sidx + " " + input.sort)
.ToPagedListAsync(input.currentPage, input.pageSize);
+ // 补充审批状态和是否已领取信息(通过usageBatchId关联申请表)
+ if (data.list.Any())
+ {
+ var batchIds = data.list.Where(x => !string.IsNullOrEmpty(x.usageBatchId))
+ .Select(x => x.usageBatchId)
+ .Distinct()
+ .ToList();
+
+ if (batchIds.Any())
+ {
+ var applicationDict = await _db.Queryable()
+ .Where(x => batchIds.Contains(x.UsageBatchId) && x.IsEffective == StatusEnum.有效.GetHashCode())
+ .Select(x => new { x.UsageBatchId, x.ApprovalStatus, x.IsReceived })
+ .ToListAsync();
+
+ var applicationLookup = applicationDict.ToDictionary(x => x.UsageBatchId, x => new { x.ApprovalStatus, x.IsReceived });
+
+ foreach (var item in data.list)
+ {
+ if (!string.IsNullOrEmpty(item.usageBatchId) && applicationLookup.ContainsKey(item.usageBatchId))
+ {
+ var appInfo = applicationLookup[item.usageBatchId];
+ item.approvalStatus = appInfo.ApprovalStatus;
+ item.isReceived = appInfo.IsReceived;
+ }
+ }
+ }
+ }
+
// 补充用户信息
var userIds = data.list.SelectMany(x => new[] { x.createUser, x.updateUser })
.Where(x => !string.IsNullOrEmpty(x))
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
index 17f8bfa..b4733cf 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
@@ -934,6 +934,7 @@ namespace NCC.Extend.LqKdKdjlb
ActivityId = input.activityId,
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allPxmxEntities.Add(lqKdPxmxEntity);
// 收集该品项关联的健康师业绩
@@ -960,7 +961,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = lqKdPxmxEntity.Px,
ItemName = lqKdPxmxEntity.Pxmc,
StoreId = entity.Djmd,
- PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ PerformanceType = lqKdPxmxEntity.PerformanceType,
+ BeautyType = lqKdPxmxEntity.BeautyType,
});
}
}
@@ -986,7 +988,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = lqKdPxmxEntity.Px,
ItemName = lqKdPxmxEntity.Pxmc,
StoreId = entity.Djmd,
- PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ PerformanceType = lqKdPxmxEntity.PerformanceType,
+ BeautyType = lqKdPxmxEntity.BeautyType,
}
);
}
@@ -1249,7 +1252,7 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = item.ItemId,
IsEffective = StatusEnum.有效.GetHashCode(), // 设置为有效
CreateTime = DateTime.Now, // 设置创建时间
- ItemCategory = await _db.Queryable().Where(x => x.Id == item.DeductId).Select(x => x.Qt2).FirstAsync(),
+ ItemCategory = await _db.Queryable().Where(x => x.Id == item.DeductId).Select(x => x.Qt2).FirstAsync()
};
allDeductEntities.Add(lqKdDeductEntity);
}
@@ -1277,6 +1280,7 @@ namespace NCC.Extend.LqKdKdjlb
ActivityId = input.activityId,
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allPxmxEntities.Add(lqKdPxmxEntity);
@@ -1304,6 +1308,7 @@ namespace NCC.Extend.LqKdKdjlb
StoreId = entity.Djmd,
ItemName = lqKdPxmxEntity.Pxmc,
PerformanceType = lqKdPxmxEntity.PerformanceType,
+ BeautyType = lqKdPxmxEntity.BeautyType,
});
}
}
@@ -1330,6 +1335,7 @@ namespace NCC.Extend.LqKdKdjlb
StoreId = entity.Djmd,
ItemName = lqKdPxmxEntity.Pxmc,
PerformanceType = lqKdPxmxEntity.PerformanceType,
+ BeautyType = lqKdPxmxEntity.BeautyType,
});
}
}
@@ -2878,6 +2884,7 @@ namespace NCC.Extend.LqKdKdjlb
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.BeautyType).FirstAsync(),
};
refundMxEntities.Add(refundMxEntity);
var refundKdyjEntities = _db.Queryable().Where(p => p.Kdpxid == item.BillingItemId).ToList();
@@ -2913,7 +2920,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = refundMxEntity.Px,
StoreId = refundEntity.Md,
ItemName = refundMxEntity.Pxmc,
- PerformanceType = refundMxEntity.PerformanceType
+ PerformanceType = refundMxEntity.PerformanceType,
+ BeautyType = refundMxEntity.BeautyType,
});
}
//查询科技部老师的业绩
@@ -2941,7 +2949,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = refundMxEntity.Px,
StoreId = refundEntity.Md,
ItemName = refundMxEntity.Pxmc,
- PerformanceType = refundMxEntity.PerformanceType
+ PerformanceType = refundMxEntity.PerformanceType,
+ BeautyType = refundMxEntity.BeautyType,
});
}
}
@@ -3025,6 +3034,7 @@ namespace NCC.Extend.LqKdKdjlb
Remark = $"从会员 {fromMember.Khmc} 转入",
ItemCategory = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.BeautyType).FirstAsync(),
};
billingPxmxEntities.Add(billingPxmxEntity);
@@ -3056,7 +3066,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = billingPxmxEntity.Px,
StoreId = billingEntity.Djmd,
ItemName = billingPxmxEntity.Pxmc,
- PerformanceType = billingPxmxEntity.PerformanceType
+ PerformanceType = billingPxmxEntity.PerformanceType,
+ BeautyType = billingPxmxEntity.BeautyType,
});
}
}
@@ -3087,7 +3098,8 @@ namespace NCC.Extend.LqKdKdjlb
ItemId = billingPxmxEntity.Px,
StoreId = billingEntity.Djmd,
ItemName = billingPxmxEntity.Pxmc,
- PerformanceType = billingPxmxEntity.PerformanceType
+ PerformanceType = billingPxmxEntity.PerformanceType,
+ BeautyType = billingPxmxEntity.BeautyType,
});
}
}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqMajorProjectTeacherSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqMajorProjectTeacherSalaryService.cs
new file mode 100644
index 0000000..c2de6aa
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqMajorProjectTeacherSalaryService.cs
@@ -0,0 +1,435 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using NCC.Common.Filter;
+using NCC.Common.Helper;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.Dto.LqMajorProjectTeacherSalary;
+using NCC.Extend.Entitys.lq_attendance_summary;
+using NCC.Extend.Entitys.lq_hytk_hytk;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_md_major_project_teacher_assignment;
+using NCC.Extend.Entitys.lq_md_xdbhsj;
+using NCC.Extend.Entitys.lq_mdxx;
+using NCC.Extend.Entitys.lq_major_project_teacher_salary_statistics;
+using NCC.System.Entitys.Permission;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace NCC.Extend
+{
+ ///
+ /// 大项目部老师薪酬服务
+ ///
+ [ApiDescriptionSettings(Tag = "大项目部老师薪酬服务", Name = "LqMajorProjectTeacherSalary", Order = 303)]
+ [Route("api/Extend/[controller]")]
+ public class LqMajorProjectTeacherSalaryService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarClient _db;
+
+ ///
+ /// 初始化一个类型的新实例
+ ///
+ public LqMajorProjectTeacherSalaryService(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ ///
+ /// 获取大项目部老师工资列表
+ ///
+ /// 查询参数
+ /// 大项目部老师工资分页列表
+ [HttpGet("major-project-teacher")]
+ public async Task GetMajorProjectTeacherSalaryList([FromQuery] MajorProjectTeacherSalaryInput input)
+ {
+ var monthStr = $"{input.Year}{input.Month:D2}";
+
+ // 1. 检查当月是否已生成工资数据
+ var exists = await _db.Queryable()
+ .AnyAsync(x => x.StatisticsMonth == monthStr);
+
+ // 2. 如果没有数据,则进行计算
+ if (!exists)
+ {
+ await CalculateMajorProjectTeacherSalary(input.Year, input.Month);
+ }
+
+ // 3. 查询数据
+ var query = _db.Queryable()
+ .Where(x => x.StatisticsMonth == monthStr);
+
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ query = query.Where(x => x.StoreId == input.StoreId);
+ }
+
+ if (!string.IsNullOrEmpty(input.Keyword))
+ {
+ query = query.Where(x => x.EmployeeName.Contains(input.Keyword) || x.EmployeeAccount.Contains(input.Keyword));
+ }
+
+ var list = await query.Select(x => new MajorProjectTeacherSalaryOutput
+ {
+ Id = x.Id,
+ StatisticsMonth = x.StatisticsMonth,
+ StoreId = x.StoreId,
+ StoreName = x.StoreName,
+ Position = x.Position,
+ EmployeeName = x.EmployeeName,
+ EmployeeId = x.EmployeeId,
+ EmployeeAccount = x.EmployeeAccount,
+ OrderAchievement = x.OrderAchievement,
+ ConsumeAchievement = x.ConsumeAchievement,
+ RefundAchievement = x.RefundAchievement,
+ TotalPerformance = x.TotalPerformance,
+ BaseSalary = x.BaseSalary,
+ PerformanceCommissionRate = x.PerformanceCommissionRate,
+ PerformanceCommissionAmount = x.PerformanceCommissionAmount,
+ TotalCommission = x.TotalCommission,
+ HandworkFee = x.HandworkFee,
+ WorkingDays = x.WorkingDays,
+ LeaveDays = x.LeaveDays,
+ TransportationAllowance = x.TransportationAllowance,
+ LessRest = x.LessRest,
+ FullAttendance = x.FullAttendance,
+ CalculatedGrossSalary = x.CalculatedGrossSalary,
+ GuaranteedSalary = x.GuaranteedSalary,
+ GuaranteedLeaveDeduction = x.GuaranteedLeaveDeduction,
+ GuaranteedBaseSalary = x.GuaranteedBaseSalary,
+ GuaranteedSupplement = x.GuaranteedSupplement,
+ FinalGrossSalary = x.FinalGrossSalary,
+ MonthlyTrainingSubsidy = x.MonthlyTrainingSubsidy,
+ MonthlyTransportSubsidy = x.MonthlyTransportSubsidy,
+ LastMonthTrainingSubsidy = x.LastMonthTrainingSubsidy,
+ LastMonthTransportSubsidy = x.LastMonthTransportSubsidy,
+ TotalSubsidy = x.TotalSubsidy,
+ MissingCard = x.MissingCard,
+ LateArrival = x.LateArrival,
+ LeaveDeduction = x.LeaveDeduction,
+ SocialInsuranceDeduction = x.SocialInsuranceDeduction,
+ RewardDeduction = x.RewardDeduction,
+ AccommodationDeduction = x.AccommodationDeduction,
+ StudyPeriodDeduction = x.StudyPeriodDeduction,
+ WorkClothesDeduction = x.WorkClothesDeduction,
+ TotalDeduction = x.TotalDeduction,
+ Bonus = x.Bonus,
+ ReturnPhoneDeposit = x.ReturnPhoneDeposit,
+ ReturnAccommodationDeposit = x.ReturnAccommodationDeposit,
+ ActualSalary = x.ActualSalary,
+ MonthlyPaymentStatus = x.MonthlyPaymentStatus,
+ PaidAmount = x.PaidAmount,
+ PendingAmount = x.PendingAmount,
+ LastMonthSupplement = x.LastMonthSupplement,
+ MonthlyTotalPayment = x.MonthlyTotalPayment,
+ IsLocked = x.IsLocked,
+ IsTerminated = x.IsTerminated,
+ UpdateTime = x.UpdateTime,
+ StoreType = x.StoreType,
+ StoreCategory = x.StoreCategory,
+ IsNewStore = x.IsNewStore,
+ NewStoreProtectionStage = x.NewStoreProtectionStage
+ })
+ .ToPagedListAsync(input.currentPage, input.pageSize);
+
+ return PageResult.SqlSugarPageResult(list);
+ }
+
+ ///
+ /// 计算大项目部老师工资
+ ///
+ /// 年份
+ /// 月份
+ ///
+ [HttpPost("calculate/major-project-teacher")]
+ public async Task CalculateMajorProjectTeacherSalary(int year, int month)
+ {
+ var startDate = new DateTime(year, month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+ var monthStr = $"{year}{month:D2}";
+ var yearStr = year.ToString();
+ var monthStr2 = month.ToString("D2");
+
+ // 1. 获取基础数据
+
+ // 1.1 获取大项目部老师归属信息(从lq_md_major_project_teacher_assignment表)
+ var assignmentList = await _db.Queryable()
+ .Where(x => x.Year == yearStr && x.Month == monthStr2)
+ .ToListAsync();
+
+ if (!assignmentList.Any())
+ {
+ // 如果没有归属信息,直接返回
+ return;
+ }
+
+ // 1.2 门店信息 (lq_mdxx)
+ var storeList = await _db.Queryable().ToListAsync();
+ var storeDict = storeList.Where(x => !string.IsNullOrEmpty(x.Id)).ToDictionary(x => x.Id, x => x);
+
+ // 1.3 门店新店保护信息 (lq_md_xdbhsj)
+ var newStoreProtectionList = await _db.Queryable()
+ .Where(x => x.Sfqy == 1)
+ .ToListAsync();
+
+ var newStoreProtectionDict = newStoreProtectionList
+ .Where(x => x.Bhkssj <= startDate && x.Bhjssj >= startDate)
+ .GroupBy(x => x.Mdid)
+ .ToDictionary(g => g.Key, g => g.First());
+
+ // 1.4 门店总业绩计算 (开单实付 - 退卡金额)
+ // 开单实付(从lq_kd_kdjlb表统计sfyj字段)
+ var storeBillingList = await _db.Queryable()
+ .Where(x => x.Kdrq >= startDate && x.Kdrq <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Select(x => new { x.Djmd, x.Sfyj })
+ .ToListAsync();
+ var storeBillingDict = storeBillingList
+ .Where(x => !string.IsNullOrEmpty(x.Djmd))
+ .GroupBy(x => x.Djmd)
+ .ToDictionary(g => g.Key, g => g.Sum(x => x.Sfyj));
+
+ // 退卡金额(从lq_hytk_hytk表统计,使用F_ActualRefundAmount,如果没有则使用tkje)
+ var storeRefundList = await _db.Queryable()
+ .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1)
+ .Select(x => new { x.Md, x.ActualRefundAmount, x.Tkje })
+ .ToListAsync();
+ var storeRefundDict = storeRefundList
+ .Where(x => !string.IsNullOrEmpty(x.Md))
+ .GroupBy(x => x.Md)
+ .ToDictionary(g => g.Key, g => g.Sum(x => x.ActualRefundAmount ?? x.Tkje ?? 0));
+
+ // 1.5 考勤数据 (lq_attendance_summary)
+ var attendanceList = await _db.Queryable()
+ .Where(x => x.Year == year && x.Month == month && x.IsEffective == 1)
+ .ToListAsync();
+ var attendanceDict = attendanceList.ToDictionary(x => x.UserId, x => x);
+
+ // 1.6 获取员工信息 (BASE_USER)
+ var teacherIds = assignmentList.Select(x => x.TeacherId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
+ var userList = await _db.Queryable()
+ .Where(x => teacherIds.Contains(x.Id))
+ .Select(x => new { x.Id, x.RealName, x.Account, x.IsOnJob })
+ .ToListAsync();
+ var userDict = userList.ToDictionary(x => x.Id, x => x);
+
+ // 2. 按大项目部老师聚合数据
+ var teacherStats = new Dictionary();
+
+ foreach (var assignment in assignmentList)
+ {
+ if (string.IsNullOrEmpty(assignment.TeacherId) || string.IsNullOrEmpty(assignment.StoreId))
+ {
+ continue;
+ }
+
+ var teacherId = assignment.TeacherId;
+ var storeId = assignment.StoreId;
+
+ // 如果该老师已经处理过(可能有多条归属记录),则合并数据
+ if (teacherStats.ContainsKey(teacherId))
+ {
+ // 如果同一个老师归属于多个门店,需要合并业绩
+ var existingSalary = teacherStats[teacherId];
+
+ // 获取该门店的业绩
+ var additionalBilling = storeBillingDict.ContainsKey(storeId) ? storeBillingDict[storeId] : 0;
+ var additionalRefund = storeRefundDict.ContainsKey(storeId) ? storeRefundDict[storeId] : 0;
+ var additionalStorePerformance = additionalBilling - additionalRefund;
+
+ // 累加业绩
+ existingSalary.OrderAchievement += additionalBilling;
+ existingSalary.RefundAchievement += additionalRefund;
+ existingSalary.TotalPerformance += additionalStorePerformance;
+
+ continue;
+ }
+
+ // 2.1 创建工资统计对象
+ var salary = new LqMajorProjectTeacherSalaryStatisticsEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ StatisticsMonth = monthStr,
+ EmployeeId = teacherId,
+ Position = "大项目部老师",
+ IsTerminated = 0,
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now,
+ IsLocked = 0
+ };
+
+ // 2.2 填充员工信息
+ if (userDict.ContainsKey(teacherId))
+ {
+ var user = userDict[teacherId];
+ salary.EmployeeName = user.RealName ?? "";
+ salary.EmployeeAccount = user.Account ?? "";
+ salary.IsTerminated = user.IsOnJob == 0 ? 1 : 0;
+ }
+
+ // 2.3 填充门店信息
+ if (storeDict.ContainsKey(storeId))
+ {
+ var store = storeDict[storeId];
+ salary.StoreId = storeId;
+ salary.StoreName = store.Dm ?? "";
+ salary.StoreType = store.StoreType;
+ salary.StoreCategory = store.StoreCategory;
+ }
+ else
+ {
+ salary.StoreId = storeId;
+ salary.StoreName = "";
+ }
+
+ // 2.4 新店保护信息
+ if (!string.IsNullOrEmpty(salary.StoreId) && newStoreProtectionDict.ContainsKey(salary.StoreId))
+ {
+ var protection = newStoreProtectionDict[salary.StoreId];
+ salary.IsNewStore = "是";
+ salary.NewStoreProtectionStage = protection.Stage;
+ }
+ else
+ {
+ salary.IsNewStore = "否";
+ salary.NewStoreProtectionStage = 0;
+ }
+
+ // 2.5 统计门店总业绩(开单业绩 - 退卡业绩)
+ var billing = storeBillingDict.ContainsKey(storeId) ? storeBillingDict[storeId] : 0;
+ var refund = storeRefundDict.ContainsKey(storeId) ? storeRefundDict[storeId] : 0;
+ var storeTotalPerformance = billing - refund;
+
+ salary.OrderAchievement = billing; // 开单业绩(门店开单实付)
+ salary.RefundAchievement = refund; // 退卡业绩(门店退卡金额)
+ salary.ConsumeAchievement = 0; // 大项目部老师不统计消耗业绩
+ salary.TotalPerformance = storeTotalPerformance; // 门店总业绩(开单 - 退卡)
+
+ // 2.6 考勤数据
+ var attendance = attendanceDict.ContainsKey(teacherId) ? attendanceDict[teacherId] : null;
+ salary.WorkingDays = attendance?.WorkDays ?? 0;
+ salary.LeaveDays = attendance?.LeaveDays ?? 0;
+
+ // 3. 工资计算
+ if (salary.IsTerminated == 1)
+ {
+ // 离职员工特殊处理(待确认规则)
+ salary.BaseSalary = 0;
+ salary.PerformanceCommissionRate = 0;
+ salary.PerformanceCommissionAmount = 0;
+ salary.TotalCommission = 0;
+ }
+ else
+ {
+ // 在职员工正常计算
+
+ // 3.1 计算底薪(固定3000元)
+ salary.BaseSalary = 3000m;
+
+ // 3.2 计算业绩提成(阶梯式)
+ var performanceCommissionResult = CalculatePerformanceCommission(salary.TotalPerformance);
+ salary.PerformanceCommissionRate = performanceCommissionResult.Rate;
+ salary.PerformanceCommissionAmount = performanceCommissionResult.Amount;
+
+ // 3.3 提成合计(等于业绩提成金额)
+ salary.TotalCommission = salary.PerformanceCommissionAmount;
+ }
+
+ // 3.4 初始化其他字段(默认值为0)
+ salary.HandworkFee = 0;
+ salary.TransportationAllowance = 0;
+ salary.LessRest = 0;
+ salary.FullAttendance = 0;
+ salary.CalculatedGrossSalary = salary.BaseSalary + salary.TotalCommission + salary.HandworkFee;
+ salary.GuaranteedSalary = 0;
+ salary.GuaranteedLeaveDeduction = 0;
+ salary.GuaranteedBaseSalary = 0;
+ salary.GuaranteedSupplement = 0;
+ salary.FinalGrossSalary = salary.CalculatedGrossSalary;
+ salary.MonthlyTrainingSubsidy = 0;
+ salary.MonthlyTransportSubsidy = 0;
+ salary.LastMonthTrainingSubsidy = 0;
+ salary.LastMonthTransportSubsidy = 0;
+ salary.TotalSubsidy = 0;
+ salary.MissingCard = 0;
+ salary.LateArrival = 0;
+ salary.LeaveDeduction = 0;
+ salary.SocialInsuranceDeduction = 0;
+ salary.RewardDeduction = 0;
+ salary.AccommodationDeduction = 0;
+ salary.StudyPeriodDeduction = 0;
+ salary.WorkClothesDeduction = 0;
+ salary.TotalDeduction = 0;
+ salary.Bonus = 0;
+ salary.ReturnPhoneDeposit = 0;
+ salary.ReturnAccommodationDeposit = 0;
+ salary.ActualSalary = salary.FinalGrossSalary - salary.TotalDeduction + salary.TotalSubsidy + salary.Bonus;
+ salary.MonthlyPaymentStatus = "";
+ salary.PaidAmount = 0;
+ salary.PendingAmount = salary.ActualSalary;
+ salary.LastMonthSupplement = 0;
+ salary.MonthlyTotalPayment = 0;
+
+ teacherStats[teacherId] = salary;
+ }
+
+ // 4. 重新计算合并后的业绩提成(如果同一个老师归属于多个门店)
+ foreach (var salary in teacherStats.Values)
+ {
+ if (salary.IsTerminated == 0)
+ {
+ // 重新计算业绩提成(基于合并后的总业绩)
+ var performanceCommissionResult = CalculatePerformanceCommission(salary.TotalPerformance);
+ salary.PerformanceCommissionRate = performanceCommissionResult.Rate;
+ salary.PerformanceCommissionAmount = performanceCommissionResult.Amount;
+ salary.TotalCommission = salary.PerformanceCommissionAmount;
+
+ // 重新计算应发工资
+ salary.CalculatedGrossSalary = salary.BaseSalary + salary.TotalCommission + salary.HandworkFee;
+ salary.FinalGrossSalary = salary.CalculatedGrossSalary;
+ salary.ActualSalary = salary.FinalGrossSalary - salary.TotalDeduction + salary.TotalSubsidy + salary.Bonus;
+ salary.PendingAmount = salary.ActualSalary;
+ }
+ }
+
+ // 5. 保存数据
+ if (teacherStats.Any())
+ {
+ // 先删除当月旧数据 (防止重复)
+ await _db.Deleteable()
+ .Where(x => x.StatisticsMonth == monthStr)
+ .ExecuteCommandAsync();
+
+ await _db.Insertable(teacherStats.Values.ToList()).ExecuteCommandAsync();
+ }
+ }
+
+ ///
+ /// 计算业绩提成(阶梯式)
+ ///
+ /// 总业绩(门店总业绩)
+ /// 提成比例和金额
+ private (decimal Rate, decimal Amount) CalculatePerformanceCommission(decimal totalPerformance)
+ {
+ if (totalPerformance <= 200000m)
+ {
+ // ≤ 20万 → 0%(无提成)
+ return (0m, 0m);
+ }
+ else if (totalPerformance <= 1000000m)
+ {
+ // > 20万 且 ≤ 100万 → 2%
+ return (2m, totalPerformance * 0.02m);
+ }
+ else
+ {
+ // > 100万 → 2.5%
+ return (2.5m, totalPerformance * 0.025m);
+ }
+ }
+ }
+}
+
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs
index 536b56b..ccceb37 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs
@@ -63,6 +63,8 @@ namespace NCC.Extend
month = it.Month,
teacherId = it.TeacherId,
teacherName = SqlFunc.Subqueryable().Where(x => x.Id == it.TeacherId).Select(x => x.RealName),
+ educationTeacherId = it.EducationTeacherId,
+ educationTeacherName = SqlFunc.Subqueryable().Where(x => x.Id == it.EducationTeacherId).Select(x => x.RealName),
remark = it.Remark,
createTime = it.CreateTime,
createUserId = it.CreateUserId,
@@ -91,6 +93,7 @@ namespace NCC.Extend
.WhereIF(!string.IsNullOrEmpty(input.year), p => p.Year == input.year)
.WhereIF(!string.IsNullOrEmpty(input.month), p => p.Month == input.month)
.WhereIF(!string.IsNullOrEmpty(input.teacherId), p => p.TeacherId == input.teacherId)
+ .WhereIF(!string.IsNullOrEmpty(input.educationTeacherId), p => p.EducationTeacherId == input.educationTeacherId)
.Select(it => new LqMdMajorProjectTeacherAssignmentListOutput
{
id = it.Id,
@@ -100,6 +103,8 @@ namespace NCC.Extend
month = it.Month,
teacherId = it.TeacherId,
teacherName = SqlFunc.Subqueryable().Where(x => x.Id == it.TeacherId).Select(x => x.RealName),
+ educationTeacherId = it.EducationTeacherId,
+ educationTeacherName = SqlFunc.Subqueryable().Where(x => x.Id == it.EducationTeacherId).Select(x => x.RealName),
remark = it.Remark,
createTime = it.CreateTime,
createUserId = it.CreateUserId,
@@ -212,6 +217,7 @@ namespace NCC.Extend
entity.Year = input.year;
entity.Month = input.month;
entity.TeacherId = input.teacherId;
+ entity.EducationTeacherId = input.educationTeacherId;
entity.Remark = input.remark;
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = userInfo.userId;
@@ -327,6 +333,7 @@ namespace NCC.Extend
Year = targetYearStr,
Month = targetMonthStr,
TeacherId = x.TeacherId,
+ EducationTeacherId = x.EducationTeacherId,
Remark = x.Remark,
CreateTime = DateTime.Now,
CreateUserId = _userManager.UserId,
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryExtraCalculationService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryExtraCalculationService.cs
index d153b7d..7e15db7 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryExtraCalculationService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqSalaryExtraCalculationService.cs
@@ -152,20 +152,30 @@ namespace NCC.Extend
try
{
var row = dataTable.Rows[i];
- var id = row[0]?.ToString()?.Trim();
- var employeeName = row[1]?.ToString()?.Trim();
- var employeePhone = row[2]?.ToString()?.Trim();
- var yearText = row[3]?.ToString()?.Trim();
- var monthText = row[4]?.ToString()?.Trim();
- var baseRewardPerformanceText = row[5]?.ToString()?.Trim();
- var cooperationRewardPerformanceText = row[6]?.ToString()?.Trim();
- var newCustomerPerformanceText = row[7]?.ToString()?.Trim();
- var newCustomerConversionRateText = row[8]?.ToString()?.Trim();
- var upgradePerformanceText = row[9]?.ToString()?.Trim();
- var upgradeConversionRateText = row[10]?.ToString()?.Trim();
- var upgradeCustomerCountText = row[11]?.ToString()?.Trim();
- var otherPerformanceAddText = row[12]?.ToString()?.Trim();
- var otherPerformanceSubtractText = row[13]?.ToString()?.Trim();
+ // 安全获取列值,如果列不存在则返回空字符串
+ var GetColumnValue = new Func((colIndex) =>
+ {
+ if (colIndex < row.ItemArray.Length)
+ {
+ return row[colIndex]?.ToString()?.Trim() ?? "";
+ }
+ return "";
+ });
+
+ var id = GetColumnValue(0);
+ var employeeName = GetColumnValue(1);
+ var employeePhone = GetColumnValue(2);
+ var yearText = GetColumnValue(3);
+ var monthText = GetColumnValue(4);
+ var baseRewardPerformanceText = GetColumnValue(5);
+ var cooperationRewardPerformanceText = GetColumnValue(6);
+ var newCustomerPerformanceText = GetColumnValue(7);
+ var newCustomerConversionRateText = GetColumnValue(8);
+ var upgradePerformanceText = GetColumnValue(9);
+ var upgradeConversionRateText = GetColumnValue(10);
+ var upgradeCustomerCountText = GetColumnValue(11);
+ var otherPerformanceAddText = GetColumnValue(12);
+ var otherPerformanceSubtractText = GetColumnValue(13);
// 跳过空行
if (string.IsNullOrEmpty(employeeName) && string.IsNullOrEmpty(employeePhone))
@@ -279,30 +289,67 @@ namespace NCC.Extend
{
try
{
- // 1. 根据健康师姓名和电话查找用户ID
- var user = await _db.Queryable()
- .Where(u => u.RealName == item.EmployeeName && u.MobilePhone == item.EmployeePhone)
- .FirstAsync();
-
- if (user == null)
- {
- errorMessages.Add($"健康师 {item.EmployeeName}({item.EmployeePhone}) 不存在");
- failCount++;
- continue;
- }
-
- // 2. 检查是否已存在相同记录(根据健康师ID、年份、月份)
+ // 1. 查找用户ID(优先使用ID,否则通过姓名和电话查找)
+ UserEntity user = null;
LqSalaryExtraCalculationEntity existingRecord = null;
- // 如果提供了ID,先尝试根据ID查找
+ // 如果提供了ID,先尝试根据ID查找现有记录,获取EmployeeId
if (!string.IsNullOrEmpty(item.Id))
{
existingRecord = await _db.Queryable()
.Where(x => x.Id == item.Id)
.FirstAsync();
+
+ if (existingRecord != null)
+ {
+ // 通过EmployeeId查找用户
+ user = await _db.Queryable()
+ .Where(u => u.Id == existingRecord.EmployeeId)
+ .FirstAsync();
+ }
+ }
+
+ // 如果还没有找到用户,通过姓名和电话查找
+ if (user == null)
+ {
+ // 处理姓名:去除"A"前缀
+ var cleanName = item.EmployeeName;
+ if (cleanName.StartsWith("A"))
+ {
+ cleanName = cleanName.Substring(1).Trim();
+ }
+
+ // 处理电话:如果电话是"无"或空,只按姓名查找
+ var phoneIsEmpty = string.IsNullOrWhiteSpace(item.EmployeePhone) ||
+ item.EmployeePhone.Trim() == "无" ||
+ item.EmployeePhone.Trim() == "00000000" ||
+ item.EmployeePhone.Trim().Length < 8; // 排除明显无效的电话
+
+ if (phoneIsEmpty)
+ {
+ // 只按姓名查找(支持原姓名和去除前缀后的姓名)
+ user = await _db.Queryable()
+ .Where(u => u.RealName == item.EmployeeName || u.RealName == cleanName)
+ .FirstAsync();
+ }
+ else
+ {
+ // 同时匹配姓名和电话(支持原姓名和去除前缀后的姓名)
+ user = await _db.Queryable()
+ .Where(u => (u.RealName == item.EmployeeName || u.RealName == cleanName) &&
+ u.MobilePhone == item.EmployeePhone)
+ .FirstAsync();
+ }
+ }
+
+ if (user == null)
+ {
+ errorMessages.Add($"健康师 {item.EmployeeName}({item.EmployeePhone}) 不存在");
+ failCount++;
+ continue;
}
- // 如果没有找到,则根据健康师ID、年份、月份查找
+ // 2. 如果还没有找到现有记录,则根据健康师ID、年份、月份查找
if (existingRecord == null)
{
existingRecord = await _db.Queryable()
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
index b2215fc..8554c6d 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
@@ -939,6 +939,7 @@ namespace NCC.Extend.LqXhHyhk
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allPxmxEntities.Add(lqXhPxmxEntity);
@@ -973,7 +974,8 @@ namespace NCC.Extend.LqXhHyhk
ItemId = lqXhPxmxEntity.Px,
StoreId = entity.Md,
ItemName = lqXhPxmxEntity.Pxmc,
- PerformanceType = lqXhPxmxEntity.PerformanceType
+ PerformanceType = lqXhPxmxEntity.PerformanceType,
+ BeautyType = lqXhPxmxEntity.BeautyType,
}
);
}
@@ -1013,7 +1015,8 @@ namespace NCC.Extend.LqXhHyhk
ItemId = lqXhPxmxEntity.Px,
StoreId = entity.Md,
ItemName = lqXhPxmxEntity.Pxmc,
- PerformanceType = lqXhPxmxEntity.PerformanceType
+ PerformanceType = lqXhPxmxEntity.PerformanceType,
+ BeautyType = lqXhPxmxEntity.BeautyType,
}
);
}
@@ -1317,6 +1320,7 @@ namespace NCC.Extend.LqXhHyhk
ProjectNumber = (decimal)((item.projectNumber ?? 0) + (entity.OvertimeCoefficient * (item.projectNumber ?? 0))),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
+ BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allPxmxEntities.Add(lqXhPxmxEntity);
@@ -1351,7 +1355,8 @@ namespace NCC.Extend.LqXhHyhk
ItemId = lqXhPxmxEntity.Px,
StoreId = entity.Md,
ItemName = lqXhPxmxEntity.Pxmc,
- PerformanceType = lqXhPxmxEntity.PerformanceType
+ PerformanceType = lqXhPxmxEntity.PerformanceType,
+ BeautyType = lqXhPxmxEntity.BeautyType,
}
);
}
@@ -1390,7 +1395,8 @@ namespace NCC.Extend.LqXhHyhk
ItemId = lqXhPxmxEntity.Px,
StoreId = entity.Md,
ItemName = lqXhPxmxEntity.Pxmc,
- PerformanceType = lqXhPxmxEntity.PerformanceType
+ PerformanceType = lqXhPxmxEntity.PerformanceType,
+ BeautyType = lqXhPxmxEntity.BeautyType,
});
}
}
diff --git a/netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs b/netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs
index f340644..1bb7b78 100644
--- a/netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs
+++ b/netcore/src/Modularity/System/NCC.System/Service/Common/FileService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
@@ -64,24 +65,33 @@ namespace NCC.System.Service.Common
if (!this.AllowFileType(fileType, type))
throw NCCException.Oh(ErrorCode.D1800);
var _filePath = GetPathByType(type);
- var _fileName = DateTime.Now.ToString("yyyyMMdd") + "_" + YitIdHelper.NextId().ToString() + Path.GetExtension(file.FileName);
+ var now = DateTime.Now;
+ var _fileName = now.ToString("yyyyMMdd") + "_" + YitIdHelper.NextId().ToString() + Path.GetExtension(file.FileName);
- // annexpic 类型强制使用阿里云OSS存储
+ // annexpic 类型强制使用阿里云OSS存储,并按天生成文件夹(不包含Files/SystemFile前缀)
string forceStoreType = type == "annexpic" ? "aliyun-oss" : null;
- await UploadFileByType(file, _filePath, _fileName, forceStoreType);
+ string uploadFilePath = _filePath;
+ if (type == "annexpic")
+ {
+ // 按天生成文件夹:yyyy/MM/dd(直接使用日期文件夹,不包含Files/SystemFile前缀)
+ var dateFolder = now.ToString("yyyy/MM/dd");
+ uploadFilePath = dateFolder;
+ }
+ await UploadFileByType(file, uploadFilePath, _fileName, forceStoreType);
// 如果是annexpic类型且使用阿里云OSS,返回OSS的完整访问地址
string fileUrl;
if (type == "annexpic")
{
- fileUrl = await GetOSSAccessUrl(_filePath, _fileName);
+ fileUrl = await GetOSSAccessUrl(uploadFilePath, _fileName);
}
else
{
fileUrl = string.Format("/api/File/Image/{0}/{1}", type, _fileName);
}
- return new { name = _fileName, url = fileUrl };
+ // 返回格式与数据库保存格式一致:name(原始文件名), fileId(生成的文件名), url(OSS地址)
+ return new { name = file.FileName, fileId = _fileName, url = fileUrl };
}
///
@@ -94,7 +104,40 @@ namespace NCC.System.Service.Common
[AllowAnonymous]
public async Task GetImg(string type, string fileName)
{
- var filePath = Path.Combine(GetPathByType(type), fileName.Replace("@", "."));
+ var basePath = GetPathByType(type);
+ var actualFileName = fileName.Replace("@", ".");
+
+ // annexpic 类型需要从文件名中提取日期来构建路径(不包含Files/SystemFile前缀)
+ string filePath;
+ if (type == "annexpic")
+ {
+ // 文件名格式:yyyyMMdd_xxx.ext,提取日期部分
+ if (actualFileName.Length >= 8)
+ {
+ var datePart = actualFileName.Substring(0, 8); // 前8位是日期
+ if (DateTime.TryParseExact(datePart, "yyyyMMdd", null, DateTimeStyles.None, out DateTime fileDate))
+ {
+ // 构建日期文件夹路径:yyyy/MM/dd(直接使用日期文件夹,不包含Files/SystemFile前缀)
+ var dateFolder = fileDate.ToString("yyyy/MM/dd");
+ filePath = $"{dateFolder}/{actualFileName}";
+ }
+ else
+ {
+ // 如果无法解析日期,使用原路径(兼容旧文件)
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+ }
+ else
+ {
+ // 文件名长度不足,使用原路径(兼容旧文件)
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+ }
+ else
+ {
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+
// annexpic 类型强制使用阿里云OSS存储
string forceStoreType = type == "annexpic" ? "aliyun-oss" : null;
return await DownloadFileByType(filePath, fileName, forceStoreType);
@@ -193,12 +236,46 @@ namespace NCC.System.Service.Common
var fileName = paramsList.Count > 1 ? paramsList[1] : "";
string type = paramsList.Count > 2 ? paramsList[2] : "";
string exname = paramsList.Count > 3 ? paramsList[3] : "";
- var filePath = Path.Combine(GetPathByType(type), fileName.Replace("@", "."));
+
+ var basePath = GetPathByType(type);
+ var actualFileName = fileName.Replace("@", ".");
+
+ // annexpic 类型需要从文件名中提取日期来构建路径(不包含Files/SystemFile前缀)
+ string filePath;
+ if (type == "annexpic")
+ {
+ // 文件名格式:yyyyMMdd_xxx.ext,提取日期部分
+ if (actualFileName.Length >= 8)
+ {
+ var datePart = actualFileName.Substring(0, 8); // 前8位是日期
+ if (DateTime.TryParseExact(datePart, "yyyyMMdd", null, DateTimeStyles.None, out DateTime fileDate))
+ {
+ // 构建日期文件夹路径:yyyy/MM/dd(直接使用日期文件夹,不包含Files/SystemFile前缀)
+ var dateFolder = fileDate.ToString("yyyy/MM/dd");
+ filePath = $"{dateFolder}/{actualFileName}";
+ }
+ else
+ {
+ // 如果无法解析日期,使用原路径(兼容旧文件)
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+ }
+ else
+ {
+ // 文件名长度不足,使用原路径(兼容旧文件)
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+ }
+ else
+ {
+ filePath = Path.Combine(basePath, actualFileName);
+ }
+
var fileDownloadName = exname;
if (fileDownloadName.IsNullOrWhiteSpace() || fileDownloadName.Split('.').Length < 2)
fileDownloadName = Path.GetFileName(filePath);
if (fileDownloadName.IsNullOrWhiteSpace())
- fileDownloadName = fileName.Replace(GetPathByType(type), "");
+ fileDownloadName = fileName.Replace(basePath, "");
// annexpic 类型强制使用阿里云OSS存储
string forceStoreType = type == "annexpic" ? "aliyun-oss" : null;
return await DownloadFileByType(filePath, fileDownloadName, forceStoreType);
@@ -365,10 +442,21 @@ namespace NCC.System.Service.Common
// 使用Uri对象来解析和替换域名,保留查询参数(签名信息)
var originalUri = new Uri(urlString);
+
+ // 提取域名(去掉协议和端口号)
+ var domainHost = domain.Replace("https://", "").Replace("http://", "").TrimEnd('/');
+ // 如果域名中包含端口号,去掉端口号
+ var colonIndex = domainHost.IndexOf(':');
+ if (colonIndex > 0)
+ {
+ domainHost = domainHost.Substring(0, colonIndex);
+ }
+
var customUri = new UriBuilder(originalUri)
{
Scheme = domain.StartsWith("https://") ? "https" : "http",
- Host = domain.Replace("https://", "").Replace("http://", "").TrimEnd('/'),
+ Host = domainHost,
+ Port = -1, // 使用默认端口(http:80, https:443),不显示在URL中
// 确保保留查询参数(签名信息)
Query = originalUri.Query
};
@@ -626,29 +714,54 @@ namespace NCC.System.Service.Common
throw NCCException.Oh($"不支持的图片格式: {imageFormat}");
}
- // 生成文件名
- var fileName = GenerateImageFileName(input.FileName, imageFormat);
-
// 获取存储路径
var imageType = string.IsNullOrEmpty(input.ImageType) ? "temporary" : input.ImageType;
- var filePath = GetPathByType(imageType);
- // 确保目录存在
- if (!Directory.Exists(filePath))
+ // 所有类型都上传到阿里云OSS存储
+ string uploadFilePath;
+ string fileName;
+ var now = DateTime.Now;
+
+ if (imageType == "annexpic")
+ {
+ // 生成文件名(格式与 Uploader 一致:yyyyMMdd_xxx.ext)
+ fileName = now.ToString("yyyyMMdd") + "_" + YitIdHelper.NextId().ToString() + "." + imageFormat;
+ // 按天生成文件夹:yyyy/MM/dd(直接使用日期文件夹,不包含Files/SystemFile前缀)
+ var dateFolder = now.ToString("yyyy/MM/dd");
+ uploadFilePath = dateFolder;
+ }
+ else
+ {
+ // 生成文件名
+ fileName = GenerateImageFileName(input.FileName, imageFormat);
+ // 获取原始路径,用于OSS存储
+ var originalPath = GetPathByType(imageType).TrimEnd('/').TrimEnd('\\');
+ // 按天生成文件夹:yyyy/MM/dd,并保留原始路径结构
+ var dateFolder = now.ToString("yyyy/MM/dd");
+ uploadFilePath = $"{originalPath}/{dateFolder}";
+ }
+
+ // 上传到OSS
+ var bucketName = KeyVariable.BucketName;
+ var ossPath = $"{uploadFilePath.TrimEnd('/').TrimEnd('\\')}/{fileName}";
+ using (var stream = new MemoryStream(imageData))
{
- Directory.CreateDirectory(filePath);
+ await _oSSServiceFactory.Create("aliyun").PutObjectAsync(bucketName, ossPath, stream);
}
- // 保存图片文件
- var fullPath = Path.Combine(filePath, fileName);
- await File.WriteAllBytesAsync(fullPath, imageData);
+ // 获取OSS的完整访问地址
+ string accessUrl = await GetOSSAccessUrl(uploadFilePath, fileName);
- // 生成访问URL
- var accessUrl = $"/api/File/Image/{imageType}/{fileName}";
+ // 返回格式与数据库保存格式一致:name(原始文件名), fileId(生成的文件名), url(OSS地址)
+ // 对于Base64上传,如果没有提供原始文件名,使用生成的文件名作为name
+ var originalFileName = string.IsNullOrEmpty(input.FileName)
+ ? fileName
+ : $"{input.FileName}.{imageFormat}";
return new
{
- name = fileName,
+ name = originalFileName,
+ fileId = fileName,
url = accessUrl,
fileSize = imageData.Length,
imageFormat = imageFormat.ToUpper(),
diff --git a/sql/创建事业部总经理经理工资统计表.sql b/sql/创建事业部总经理经理工资统计表.sql
new file mode 100644
index 0000000..a205c0b
--- /dev/null
+++ b/sql/创建事业部总经理经理工资统计表.sql
@@ -0,0 +1,198 @@
+-- ============================================
+-- 创建事业部总经理/经理工资统计表
+-- 功能:存储事业部总经理/经理每月的工资计算数据,包括底薪、业绩提成、扣款、补贴、奖金、支付等信息
+-- 创建时间:2025年
+-- ============================================
+
+-- 删除表(如果存在)
+DROP TABLE IF EXISTS lq_business_unit_manager_salary_statistics;
+
+-- ============================================
+-- 创建事业部总经理/经理工资统计表
+-- ============================================
+CREATE TABLE lq_business_unit_manager_salary_statistics (
+ -- 主键
+ F_Id VARCHAR(50) NOT NULL COMMENT '主键ID',
+
+ -- 一、基础信息字段
+ F_StatisticsMonth VARCHAR(6) NOT NULL COMMENT '统计月份(YYYYMM格式)',
+ F_Position VARCHAR(50) NOT NULL COMMENT '核算岗位(总经理/经理)',
+ F_EmployeeName VARCHAR(100) NOT NULL COMMENT '员工姓名',
+ F_EmployeeId VARCHAR(50) NOT NULL COMMENT '员工ID',
+ F_EmployeeAccount VARCHAR(100) NULL COMMENT '员工账号',
+ F_ManagerType INT NOT NULL COMMENT '经理类型(0=经理,1=总经理)',
+ F_IsTerminated INT NOT NULL DEFAULT 0 COMMENT '是否离职(0=在职,1=离职)',
+
+ -- 二、管理的门店信息(JSON格式)
+ F_StorePerformanceDetail TEXT NULL COMMENT '门店业绩明细(JSON格式,记录每个门店的业绩和提成详情)',
+
+ -- 三、底薪相关字段
+ F_BaseSalary DECIMAL(18,2) NOT NULL DEFAULT 4000.00 COMMENT '底薪金额(固定4000元)',
+
+ -- 四、提成相关字段
+ F_TotalCommission DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '提成合计(所有门店提成金额汇总)',
+
+ -- 五、考勤相关字段
+ F_WorkingDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '在店天数',
+ F_LeaveDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假天数',
+
+ -- 六、工资计算字段
+ F_CalculatedGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '核算应发工资(底薪 + 提成合计)',
+ F_FinalGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '最终应发工资(等于核算应发工资)',
+
+ -- 七、补贴相关字段
+ F_MonthlyTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月培训补贴',
+ F_MonthlyTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月交通补贴',
+ F_LastMonthTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月培训补贴',
+ F_LastMonthTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月交通补贴',
+ F_TotalSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补贴合计',
+
+ -- 八、扣款相关字段
+ F_MissingCard DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '缺卡扣款',
+ F_LateArrival DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '迟到扣款',
+ F_LeaveDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假扣款',
+ F_SocialInsuranceDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣社保',
+ F_RewardDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣除奖励',
+ F_AccommodationDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣住宿费',
+ F_StudyPeriodDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣学习期费用',
+ F_WorkClothesDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣工作服费用',
+ F_TotalDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣款合计',
+
+ -- 九、奖金相关字段
+ F_Bonus DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '发奖金',
+ F_ReturnPhoneDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退手机押金',
+ F_ReturnAccommodationDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退住宿押金',
+
+ -- 十、支付相关字段
+ F_ActualSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '实发工资(最终应发工资 - 扣款合计 + 补贴合计 + 奖金)',
+ F_MonthlyPaymentStatus VARCHAR(20) NOT NULL DEFAULT '未发放' COMMENT '当月是否发放(已发放/未发放/部分发放)',
+ F_PaidAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '支付金额',
+ F_PendingAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '待支付金额',
+ F_LastMonthSupplement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补发上月',
+ F_MonthlyTotalPayment DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月支付总额',
+
+ -- 十一、系统字段
+ F_IsLocked INT NOT NULL DEFAULT 0 COMMENT '是否锁定(0=未锁定,1=已锁定)',
+ F_CreateTime DATETIME NOT NULL COMMENT '创建时间',
+ F_UpdateTime DATETIME NOT NULL COMMENT '更新时间',
+ F_CreateUser VARCHAR(50) NULL COMMENT '创建人',
+ F_UpdateUser VARCHAR(50) NULL COMMENT '更新人',
+
+ -- 主键约束
+ PRIMARY KEY (F_Id),
+
+ -- 唯一索引:确保同一员工同一月份只有一条记录
+ UNIQUE KEY `uk_employee_month` (F_EmployeeId, F_StatisticsMonth),
+
+ -- 普通索引
+ KEY `idx_statistics_month` (F_StatisticsMonth),
+ KEY `idx_employee_id` (F_EmployeeId),
+ KEY `idx_employee_account` (F_EmployeeAccount),
+ KEY `idx_manager_type` (F_ManagerType),
+ KEY `idx_is_terminated` (F_IsTerminated),
+ KEY `idx_create_time` (F_CreateTime)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='事业部总经理/经理工资统计表';
+
+-- ============================================
+-- 表结构说明
+-- ============================================
+/*
+表名:lq_business_unit_manager_salary_statistics(事业部总经理/经理工资统计表)
+
+功能说明:
+1. 存储事业部总经理/经理每月的工资计算数据
+2. 包括底薪、业绩提成、扣款、补贴、奖金、支付等信息
+3. 支持按员工、月份查询
+4. 记录管理的门店汇总信息
+
+主要字段说明:
+- F_BaseSalary:底薪(固定4000元)
+- F_StorePerformanceDetail:门店业绩明细(JSON格式,记录每个门店的业绩和提成详情)
+- F_TotalCommission:提成合计(所有门店提成金额汇总)
+
+数据来源:
+- 总经理/经理归属:lq_md_general_manager_lifeline 表(通过F_GeneralManagerId和F_Month获取)
+- 门店生命线:lq_md_target 表的 F_StoreLifeline 字段
+- 提成阶梯:lq_md_general_manager_lifeline 表的 F_Lifeline1/2/3 和 F_CommissionRate1/2/3
+- 开单业绩:lq_kd_kdjlb 表的 sfyj 字段(按门店统计)
+- 退卡业绩:lq_hytk_hytk 表的 F_ActualRefundAmount 或 tkje 字段(按门店统计)
+
+计算公式:
+- 门店总业绩 = 开单业绩 - 退卡业绩
+- 提成计算逻辑:
+ 1. 判断是否达到提成门槛:门店业绩 ≥ 门店生命线?
+ - 如果否 → 该门店提成 = 0
+ - 如果是 → 继续计算提成
+ 2. 如果达到门槛,使用提成阶梯计算提成(分段累进):
+ - 业绩 ≤ 提成阶梯1:提成 = 业绩 × 提成比例1
+ - 提成阶梯1 < 业绩 ≤ 提成阶梯2:提成 = 提成阶梯1 × 提成比例1 + (业绩 - 提成阶梯1) × 提成比例2
+ - 提成阶梯2 < 业绩 ≤ 提成阶梯3:提成 = 提成阶梯1 × 提成比例1 + (提成阶梯2 - 提成阶梯1) × 提成比例2 + (业绩 - 提成阶梯2) × 提成比例3
+ - 业绩 > 提成阶梯3:提成 = 提成阶梯1 × 提成比例1 + (提成阶梯2 - 提成阶梯1) × 提成比例2 + (提成阶梯3 - 提成阶梯2) × 提成比例3 + (业绩 - 提成阶梯3) × 提成比例3
+- 总提成 = SUM(各门店提成金额)
+- 核算应发工资 = 底薪(4000) + 总提成
+- 最终应发工资 = 核算应发工资
+- 实发工资 = 最终应发工资 - 扣款合计 + 补贴合计 + 奖金
+
+门店业绩明细JSON格式示例:
+[
+ {
+ "storeId": "门店ID",
+ "storeName": "门店名称",
+ "storeLifeline": 300000.00,
+ "billingPerformance": 400000.00,
+ "refundPerformance": 50000.00,
+ "storePerformance": 350000.00,
+ "reachedLifeline": true,
+ "lifeline1": 350000.00,
+ "commissionRate1": 1.00,
+ "lifeline2": 400000.00,
+ "commissionRate2": 1.50,
+ "lifeline3": 450000.00,
+ "commissionRate3": 2.00,
+ "commissionAmount": 3500.00,
+ "calculationDetail": "业绩350000元,达到门店生命线300000元,使用提成阶梯1计算:350000 × 1.0% = 3500元"
+ },
+ {
+ "storeId": "门店ID2",
+ "storeName": "门店名称2",
+ "storeLifeline": 250000.00,
+ "billingPerformance": 220000.00,
+ "refundPerformance": 20000.00,
+ "storePerformance": 200000.00,
+ "reachedLifeline": false,
+ "commissionAmount": 0.00,
+ "calculationDetail": "业绩200000元,未达到门店生命线250000元,无提成"
+ }
+]
+
+JSON字段说明:
+- storeId:门店ID
+- storeName:门店名称
+- storeLifeline:门店生命线(从lq_md_target表获取)
+- billingPerformance:门店开单业绩
+- refundPerformance:门店退卡业绩
+- storePerformance:门店总业绩(开单业绩 - 退卡业绩)
+- reachedLifeline:是否达到门店生命线(true/false)
+- lifeline1/2/3:提成阶梯1/2/3(从lq_md_general_manager_lifeline表获取)
+- commissionRate1/2/3:提成比例1/2/3(%)
+- commissionAmount:该门店的提成金额
+- calculationDetail:计算说明(文字描述)
+
+索引说明:
+- 主键索引:F_Id
+- 唯一索引:F_EmployeeId + F_StatisticsMonth(确保同一员工同一月份只有一条记录)
+- 普通索引:
+ - F_StatisticsMonth:按月份查询
+ - F_EmployeeId:按员工查询
+ - F_ManagerType:按经理类型查询(总经理/经理)
+ - F_CreateTime:按创建时间查询
+
+数据校验要求:
+1. 底薪固定为4000元
+2. 门店生命线必须设置,未设置应报错
+3. 提成阶梯1和提成比例1必须设置,未设置应报错
+4. 提成必须按照阶梯式计算(分段累进)
+5. 如果门店业绩 < 门店生命线,则该门店提成为0
+6. 总经理和经理的计算规则相同
+*/
+
diff --git a/sql/创建大项目部老师工资统计表.sql b/sql/创建大项目部老师工资统计表.sql
new file mode 100644
index 0000000..f4535ec
--- /dev/null
+++ b/sql/创建大项目部老师工资统计表.sql
@@ -0,0 +1,167 @@
+-- ============================================
+-- 创建大项目部老师工资统计表
+-- 功能:存储大项目部老师每月的工资计算数据,包括底薪、业绩提成、扣款、补贴、奖金、支付等信息
+-- 创建时间:2025年
+-- ============================================
+
+-- 删除表(如果存在)
+DROP TABLE IF EXISTS lq_major_project_teacher_salary_statistics;
+
+-- ============================================
+-- 创建大项目部老师工资统计表
+-- ============================================
+CREATE TABLE lq_major_project_teacher_salary_statistics (
+ -- 主键
+ F_Id VARCHAR(50) NOT NULL COMMENT '主键ID',
+
+ -- 一、基础信息字段
+ F_StatisticsMonth VARCHAR(6) NOT NULL COMMENT '统计月份(YYYYMM格式)',
+ F_StoreId VARCHAR(50) NOT NULL COMMENT '门店ID',
+ F_StoreName VARCHAR(200) NOT NULL COMMENT '门店名称',
+ F_Position VARCHAR(50) NOT NULL DEFAULT '大项目部老师' COMMENT '核算岗位(固定为"大项目部老师")',
+ F_EmployeeName VARCHAR(100) NOT NULL COMMENT '员工姓名',
+ F_EmployeeId VARCHAR(50) NOT NULL COMMENT '员工ID',
+ F_EmployeeAccount VARCHAR(100) NULL COMMENT '员工账号',
+ F_StoreType INT NULL COMMENT '门店类型(200平/旗舰店)',
+ F_StoreCategory INT NULL COMMENT '门店分类(1=A类,2=B类,3=C类)',
+ F_IsNewStore VARCHAR(10) NULL COMMENT '是否新店(是/否)',
+ F_NewStoreProtectionStage INT NOT NULL DEFAULT 0 COMMENT '新店保护阶段(0/1/2)',
+
+ -- 二、业绩相关字段
+ F_OrderAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '开单业绩(从lq_kd_kjbsyj表统计,根据归属表关联)',
+ F_ConsumeAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '消耗业绩(从lq_xh_kjbsyj表统计,根据归属表关联)',
+ F_RefundAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退卡业绩(从lq_hytk_kjbsyj表统计,根据归属表关联)',
+ F_TotalPerformance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '总业绩(开单业绩 + 消耗业绩 + 退卡业绩,用于业绩提成计算)',
+
+ -- 三、底薪相关字段
+ F_BaseSalary DECIMAL(18,2) NOT NULL DEFAULT 3000.00 COMMENT '底薪金额(固定3000元)',
+
+ -- 四、业绩提成相关字段
+ F_PerformanceCommissionRate DECIMAL(18,4) NOT NULL DEFAULT 0.0000 COMMENT '业绩提成比例(百分比,如2.00表示2%,0.00表示无提成)',
+ F_PerformanceCommissionAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '业绩提成金额(总业绩 × 业绩提成比例,阶梯式计算)',
+ F_TotalCommission DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '提成合计(业绩提成金额)',
+
+ -- 五、其他收入字段
+ F_HandworkFee DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '手工费',
+ F_TransportationAllowance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '车补',
+ F_LessRest DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '少休费',
+ F_FullAttendance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '全勤奖',
+
+ -- 六、考勤相关字段
+ F_WorkingDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '在店天数',
+ F_LeaveDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假天数',
+
+ -- 七、工资计算字段
+ F_CalculatedGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '核算应发工资(底薪 + 提成合计 + 其他收入)',
+ F_GuaranteedSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底工资',
+ F_GuaranteedLeaveDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底请假扣款',
+ F_GuaranteedBaseSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底底薪',
+ F_GuaranteedSupplement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底补差',
+ F_FinalGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '最终应发工资(取核算应发工资和保底工资的较大值)',
+
+ -- 八、补贴相关字段
+ F_MonthlyTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月培训补贴',
+ F_MonthlyTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月交通补贴',
+ F_LastMonthTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月培训补贴',
+ F_LastMonthTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月交通补贴',
+ F_TotalSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补贴合计',
+
+ -- 九、扣款相关字段
+ F_MissingCard DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '缺卡扣款',
+ F_LateArrival DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '迟到扣款',
+ F_LeaveDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假扣款',
+ F_SocialInsuranceDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣社保',
+ F_RewardDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣除奖励',
+ F_AccommodationDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣住宿费',
+ F_StudyPeriodDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣学习期费用',
+ F_WorkClothesDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣工作服费用',
+ F_TotalDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣款合计',
+
+ -- 十、奖金相关字段
+ F_Bonus DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '发奖金',
+ F_ReturnPhoneDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退手机押金',
+ F_ReturnAccommodationDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退住宿押金',
+
+ -- 十一、支付相关字段
+ F_ActualSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '实发工资(最终应发工资 - 扣款合计 + 补贴合计 + 奖金)',
+ F_MonthlyPaymentStatus VARCHAR(20) NOT NULL DEFAULT '未发放' COMMENT '当月是否发放(已发放/未发放/部分发放)',
+ F_PaidAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '支付金额',
+ F_PendingAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '待支付金额',
+ F_LastMonthSupplement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补发上月',
+ F_MonthlyTotalPayment DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月支付总额',
+
+ -- 十二、系统字段
+ F_IsLocked INT NOT NULL DEFAULT 0 COMMENT '是否锁定(0=未锁定,1=已锁定)',
+ F_IsTerminated INT NOT NULL DEFAULT 0 COMMENT '是否离职(0=在职,1=离职)',
+ F_CreateTime DATETIME NOT NULL COMMENT '创建时间',
+ F_UpdateTime DATETIME NOT NULL COMMENT '更新时间',
+ F_CreateUser VARCHAR(50) NULL COMMENT '创建人',
+ F_UpdateUser VARCHAR(50) NULL COMMENT '更新人',
+
+ -- 主键约束
+ PRIMARY KEY (F_Id),
+
+ -- 唯一索引:确保同一员工同一月份只有一条记录
+ UNIQUE KEY `uk_employee_month` (F_EmployeeId, F_StatisticsMonth),
+
+ -- 普通索引
+ KEY `idx_store_id` (F_StoreId),
+ KEY `idx_statistics_month` (F_StatisticsMonth),
+ KEY `idx_employee_id` (F_EmployeeId),
+ KEY `idx_employee_account` (F_EmployeeAccount),
+ KEY `idx_store_category` (F_StoreCategory),
+ KEY `idx_is_terminated` (F_IsTerminated),
+ KEY `idx_create_time` (F_CreateTime)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='大项目部老师工资统计表';
+
+-- ============================================
+-- 表结构说明
+-- ============================================
+/*
+表名:lq_major_project_teacher_salary_statistics(大项目部老师工资统计表)
+
+功能说明:
+1. 存储大项目部老师每月的工资计算数据
+2. 包括底薪、业绩提成、扣款、补贴、奖金、支付等信息
+3. 支持按门店、员工、月份查询
+
+主要字段说明:
+- F_BaseSalary:底薪(固定3000元)
+- F_TotalPerformance:总业绩(开单业绩 + 消耗业绩 + 退卡业绩),用于计算业绩提成
+- F_PerformanceCommissionRate:业绩提成比例(阶梯式:≤20万无提成,>20万且≤100万为2%,>100万为2.5%)
+- F_PerformanceCommissionAmount:业绩提成金额(总业绩 × 业绩提成比例)
+- F_TotalCommission:提成合计(等于业绩提成金额)
+
+数据来源:
+- 老师归属:lq_md_major_project_teacher_assignment 表(每个月归属不一样)
+- 开单业绩:lq_kd_kjbsyj 表(根据归属表关联)
+- 消耗业绩:lq_xh_kjbsyj 表(根据归属表关联)
+- 退卡业绩:lq_hytk_kjbsyj 表(根据归属表关联)
+
+计算公式:
+- 总业绩 = 开单业绩 + 消耗业绩 + 退卡业绩
+- 业绩提成计算(阶梯式):
+ * 总业绩 ≤ 20万:无提成(0%)
+ * 总业绩 > 20万 且 ≤ 100万:2%
+ * 总业绩 > 100万:2.5%
+- 提成金额 = 总业绩 × 对应提成比例
+- 核算应发工资 = 底薪(3000) + 提成合计 + 其他收入
+- 最终应发工资 = MAX(核算应发工资, 保底工资)
+- 实发工资 = 最终应发工资 - 扣款合计 + 补贴合计 + 奖金
+
+索引说明:
+- 主键索引:F_Id
+- 唯一索引:F_EmployeeId + F_StatisticsMonth(确保同一员工同一月份只有一条记录)
+- 普通索引:
+ - F_StoreId:按门店查询
+ - F_StatisticsMonth:按月份查询
+ - F_EmployeeId:按员工查询
+ - F_StoreCategory:按门店分类查询
+ - F_CreateTime:按创建时间查询
+
+数据校验要求:
+1. 底薪固定为3000元
+2. 业绩提成必须按照阶梯式计算
+3. 总业绩必须从归属表关联的业绩数据中统计
+*/
+
diff --git a/sql/创建库存使用申请审批流程表.sql b/sql/创建库存使用申请审批流程表.sql
index 726c469..595ea58 100644
--- a/sql/创建库存使用申请审批流程表.sql
+++ b/sql/创建库存使用申请审批流程表.sql
@@ -104,3 +104,7 @@ WHERE u.`F_UnitPrice` = 0 OR u.`F_UnitPrice` IS NULL;
+
+
+
+
diff --git a/sql/同步BeautyType字段数据.sql b/sql/同步BeautyType字段数据.sql
new file mode 100644
index 0000000..9d26428
--- /dev/null
+++ b/sql/同步BeautyType字段数据.sql
@@ -0,0 +1,268 @@
+-- ============================================
+-- 同步 F_BeautyType 字段数据
+-- ============================================
+-- 说明:从 lq_xmzl 表的 F_BeautyType 字段同步数据到其他相关表
+--
+-- 关联关系:
+-- 1. lq_kd_pxmx: 通过 px 字段关联到 lq_xmzl.F_Id
+-- 2. lq_kd_jksyj: 通过 F_kdpxid 关联到 lq_kd_pxmx,或通过 F_ItemId 直接关联到 lq_xmzl
+-- 3. lq_kd_kjbsyj: 通过 F_kdpxid 关联到 lq_kd_pxmx,或通过 F_ItemId 直接关联到 lq_xmzl
+-- 4. lq_hytk_mx: 通过 px 字段关联到 lq_xmzl.F_Id
+-- 5. lq_hytk_jksyj: 通过 F_tkpxid 关联到 lq_hytk_mx,或通过 F_ItemId 直接关联到 lq_xmzl
+-- 6. lq_hytk_kjbsyj: 通过 F_tkpxid 关联到 lq_hytk_mx,或通过 F_ItemId 直接关联到 lq_xmzl
+-- 7. lq_xh_pxmx: 通过 px 字段关联到 lq_xmzl.F_Id
+-- 8. lq_xh_jksyj: 通过 F_kdpxid 关联到 lq_xh_pxmx,或通过 F_ItemId 直接关联到 lq_xmzl
+-- 9. lq_xh_kjbsyj: 通过 F_hkpxid 关联到 lq_xh_pxmx,或通过 F_ItemId 直接关联到 lq_xmzl
+--
+-- 注意事项:
+-- - 优先使用 F_ItemId 直接关联(如果存在且有效)
+-- - 如果 F_ItemId 为空,则通过关联表间接关联
+-- - 只更新 F_BeautyType 为 NULL 或空字符串的记录
+
+-- ============================================
+-- 1. 同步 lq_kd_pxmx(开单品项明细表)
+-- ============================================
+UPDATE lq_kd_pxmx t1
+INNER JOIN lq_xmzl t2 ON t1.px = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 2. 同步 lq_kd_jksyj(开单健康师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_kd_jksyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_kdpxid 关联到 lq_kd_pxmx,再关联到 lq_xmzl
+UPDATE lq_kd_jksyj t1
+INNER JOIN lq_kd_pxmx t2 ON t1.F_kdpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_kdpxid IS NOT NULL
+ AND t1.F_kdpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 3. 同步 lq_kd_kjbsyj(开单科技部老师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_kd_kjbsyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_kdpxid 关联到 lq_kd_pxmx,再关联到 lq_xmzl
+UPDATE lq_kd_kjbsyj t1
+INNER JOIN lq_kd_pxmx t2 ON t1.F_kdpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_kdpxid IS NOT NULL
+ AND t1.F_kdpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 4. 同步 lq_hytk_mx(退卡品项明细表)
+-- ============================================
+UPDATE lq_hytk_mx t1
+INNER JOIN lq_xmzl t2 ON t1.px = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 5. 同步 lq_hytk_jksyj(退卡健康师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_hytk_jksyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_tkpxid 关联到 lq_hytk_mx,再关联到 lq_xmzl
+UPDATE lq_hytk_jksyj t1
+INNER JOIN lq_hytk_mx t2 ON t1.F_tkpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_tkpxid IS NOT NULL
+ AND t1.F_tkpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 6. 同步 lq_hytk_kjbsyj(退卡科技部老师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_hytk_kjbsyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_tkpxid 关联到 lq_hytk_mx,再关联到 lq_xmzl
+UPDATE lq_hytk_kjbsyj t1
+INNER JOIN lq_hytk_mx t2 ON t1.F_tkpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_tkpxid IS NOT NULL
+ AND t1.F_tkpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 7. 同步 lq_xh_pxmx(耗卡品项明细表)
+-- ============================================
+UPDATE lq_xh_pxmx t1
+INNER JOIN lq_xmzl t2 ON t1.px = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 8. 同步 lq_xh_jksyj(耗卡健康师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_xh_jksyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_kdpxid 关联到 lq_xh_pxmx,再关联到 lq_xmzl
+UPDATE lq_xh_jksyj t1
+INNER JOIN lq_xh_pxmx t2 ON t1.F_kdpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_kdpxid IS NOT NULL
+ AND t1.F_kdpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 9. 同步 lq_xh_kjbsyj(耗卡科技部老师业绩表)
+-- ============================================
+-- 方式1:通过 F_ItemId 直接关联(优先)
+UPDATE lq_xh_kjbsyj t1
+INNER JOIN lq_xmzl t2 ON t1.F_ItemId = t2.F_Id
+SET t1.F_BeautyType = t2.F_BeautyType
+WHERE t2.F_BeautyType IS NOT NULL
+ AND t2.F_BeautyType != ''
+ AND t1.F_ItemId IS NOT NULL
+ AND t1.F_ItemId != ''
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- 方式2:通过 F_hkpxid 关联到 lq_xh_pxmx,再关联到 lq_xmzl
+UPDATE lq_xh_kjbsyj t1
+INNER JOIN lq_xh_pxmx t2 ON t1.F_hkpxid = t2.F_Id
+INNER JOIN lq_xmzl t3 ON t2.px = t3.F_Id
+SET t1.F_BeautyType = t3.F_BeautyType
+WHERE t3.F_BeautyType IS NOT NULL
+ AND t3.F_BeautyType != ''
+ AND t1.F_hkpxid IS NOT NULL
+ AND t1.F_hkpxid != ''
+ AND (t1.F_ItemId IS NULL OR t1.F_ItemId = '')
+ AND (t1.F_BeautyType IS NULL OR t1.F_BeautyType = '');
+
+-- ============================================
+-- 10. 验证同步结果
+-- ============================================
+-- 查看各表同步的数据统计
+-- SELECT
+-- 'lq_kd_pxmx' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_kd_pxmx
+-- UNION ALL
+-- SELECT
+-- 'lq_kd_jksyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_kd_jksyj
+-- UNION ALL
+-- SELECT
+-- 'lq_kd_kjbsyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_kd_kjbsyj
+-- UNION ALL
+-- SELECT
+-- 'lq_hytk_mx' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_hytk_mx
+-- UNION ALL
+-- SELECT
+-- 'lq_hytk_jksyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_hytk_jksyj
+-- UNION ALL
+-- SELECT
+-- 'lq_hytk_kjbsyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_hytk_kjbsyj
+-- UNION ALL
+-- SELECT
+-- 'lq_xh_pxmx' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_xh_pxmx
+-- UNION ALL
+-- SELECT
+-- 'lq_xh_jksyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_xh_jksyj
+-- UNION ALL
+-- SELECT
+-- 'lq_xh_kjbsyj' AS table_name,
+-- COUNT(*) AS total_count,
+-- COUNT(F_BeautyType) AS beauty_type_count,
+-- COUNT(*) - COUNT(F_BeautyType) AS null_count
+-- FROM lq_xh_kjbsyj;
+
diff --git a/sql/添加教育部老师字段.sql b/sql/添加教育部老师字段.sql
new file mode 100644
index 0000000..c0b2319
--- /dev/null
+++ b/sql/添加教育部老师字段.sql
@@ -0,0 +1,35 @@
+-- ============================================
+-- 为门店大项目部老师归属设置表添加教育部老师字段
+-- ============================================
+-- 说明:在 lq_md_major_project_teacher_assignment 表中添加教育部老师字段
+--
+-- 字段说明:
+-- F_EducationTeacherId:教育部老师用户ID,用于存储教育部老师的归属设置
+--
+-- 业务含义:
+-- - 一个门店在一个月份可以同时有大项目部老师和教育部老师
+-- - 教育部老师ID关联BASE_USER.F_Id
+--
+-- 注意事项:
+-- - 字段类型为VARCHAR(50),允许为NULL(因为历史数据可能没有教育部老师)
+-- - 字段位置:放在 F_TeacherId 字段之后
+
+-- ============================================
+-- 添加教育部老师字段
+-- ============================================
+ALTER TABLE lq_md_major_project_teacher_assignment
+ADD COLUMN F_EducationTeacherId VARCHAR(50) NULL COMMENT '教育部老师用户ID' AFTER F_TeacherId;
+
+-- ============================================
+-- 创建索引(可选,如果需要按教育部老师查询)
+-- ============================================
+CREATE INDEX idx_education_teacher_id ON lq_md_major_project_teacher_assignment(F_EducationTeacherId);
+
+-- ============================================
+-- 验证字段创建
+-- ============================================
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_md_major_project_teacher_assignment'
+-- AND COLUMN_NAME = 'F_EducationTeacherId';
+
diff --git a/sql/添加科技部归类字段.sql b/sql/添加科技部归类字段.sql
index 8e8f7a6..49be161 100644
--- a/sql/添加科技部归类字段.sql
+++ b/sql/添加科技部归类字段.sql
@@ -8,7 +8,7 @@
--
-- 业务含义:
-- - 科技部归类用于科技部对品项进行分类统计和分析
--- - 分类值来源于项目资料表(lq_xmzl)的 F_BeautyType 字段(科美类型)
+-- - 分类值来源于项目资料表(lq_xmzl)的 F_BeautyType 字段
--
-- 注意事项:
-- - 字段类型为VARCHAR(50),可存储各种分类值
diff --git a/sql/重命名科技部归类字段为BeautyType.sql b/sql/重命名科技部归类字段为BeautyType.sql
new file mode 100644
index 0000000..26064e6
--- /dev/null
+++ b/sql/重命名科技部归类字段为BeautyType.sql
@@ -0,0 +1,131 @@
+-- ============================================
+-- 重命名科技部归类字段为 F_BeautyType
+-- ============================================
+-- 说明:将已创建的 F_KjbCategory 字段重命名为 F_BeautyType,以便与 lq_xmzl 表的字段名统一
+--
+-- 字段说明:
+-- F_BeautyType:科美类型,用于存储品项的科美类型信息(与 lq_xmzl.F_BeautyType 统一)
+--
+-- 业务含义:
+-- - 科美类型用于对品项进行分类统计和分析
+-- - 分类值来源于项目资料表(lq_xmzl)的 F_BeautyType 字段
+--
+-- 注意事项:
+-- - 此脚本用于重命名已创建的字段
+-- - 字段类型保持不变:VARCHAR(50),允许为NULL
+-- - 字段位置保持不变:在 F_PerformanceType 字段之后
+
+-- ============================================
+-- 1. lq_kd_pxmx(开单品项明细表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_kd_pxmx
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 2. lq_kd_jksyj(开单健康师业绩表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_kd_jksyj
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 3. lq_kd_kjbsyj(开单科技部老师业绩表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_kd_kjbsyj
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 4. lq_hytk_mx(退卡品项明细表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_hytk_mx
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 5. lq_hytk_jksyj(退卡健康师业绩表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_hytk_jksyj
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 6. lq_hytk_kjbsyj(退卡科技部老师业绩表) - 重命名字段
+-- ============================================
+ALTER TABLE lq_hytk_kjbsyj
+CHANGE COLUMN F_KjbCategory F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)';
+
+-- ============================================
+-- 7. lq_xh_pxmx(耗卡品项明细表) - 添加字段
+-- ============================================
+-- 注意:如果字段已存在会报错,可以忽略;如果存在 F_KjbCategory 需要先重命名
+ALTER TABLE lq_xh_pxmx
+ADD COLUMN F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType;
+
+-- ============================================
+-- 8. lq_xh_jksyj(耗卡健康师业绩表) - 添加字段
+-- ============================================
+-- 注意:如果字段已存在会报错,可以忽略;如果存在 F_KjbCategory 需要先重命名
+ALTER TABLE lq_xh_jksyj
+ADD COLUMN F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType;
+
+-- ============================================
+-- 9. lq_xh_kjbsyj(耗卡科技部老师业绩表) - 添加字段
+-- ============================================
+-- 注意:如果字段已存在会报错,可以忽略;如果存在 F_KjbCategory 需要先重命名
+ALTER TABLE lq_xh_kjbsyj
+ADD COLUMN F_BeautyType VARCHAR(50) NULL COMMENT '科美类型(来源:lq_xmzl.F_BeautyType)' AFTER F_PerformanceType;
+
+-- ============================================
+-- 10. 验证字段重命名
+-- ============================================
+-- 验证 lq_kd_pxmx 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_kd_pxmx'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_kd_jksyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_kd_jksyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_kd_kjbsyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_kd_kjbsyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_hytk_mx 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_hytk_mx'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_hytk_jksyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_hytk_jksyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_hytk_kjbsyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_hytk_kjbsyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_xh_pxmx 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_xh_pxmx'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_xh_jksyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_xh_jksyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
+-- 验证 lq_xh_kjbsyj 表
+-- SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT
+-- FROM INFORMATION_SCHEMA.COLUMNS
+-- WHERE TABLE_NAME = 'lq_xh_kjbsyj'
+-- AND COLUMN_NAME = 'F_BeautyType';
+
diff --git a/事业部总经理经理工资计算规则梳理.md b/事业部总经理经理工资计算规则梳理.md
new file mode 100644
index 0000000..56de4d7
--- /dev/null
+++ b/事业部总经理经理工资计算规则梳理.md
@@ -0,0 +1,350 @@
+# 事业部总经理/经理工资计算规则梳理
+
+## 📋 目录
+- [概述](#概述)
+- [计算规则](#计算规则)
+- [数据来源](#数据来源)
+- [归属规则](#归属规则)
+- [计算流程](#计算流程)
+
+---
+
+## 📋 概述
+
+事业部总经理/经理工资由以下几个部分组成:
+1. **底薪**:固定4000元
+2. **提成**:根据管理的门店业绩,使用阶梯式提成计算(基于门店总业绩)
+
+**重要说明**:
+- 每个总经理/经理都会管理多个门店
+- 提成计算基于门店总业绩(开单业绩 - 退卡业绩)
+- 总经理和经理的计算规则相同
+- 必须先达到门店生命线才能计算提成
+
+---
+
+## 💰 计算规则
+
+### 1. 底薪规则
+
+**固定底薪**:4000元
+
+- 无论业绩多少,底薪固定为4000元
+- 不设档位,不设条件
+- 不设考核扣款(与店长、主任不同)
+
+---
+
+### 2. 提成规则(阶梯式)
+
+**提成计算方式**:根据管理的门店业绩,使用阶梯式提成计算
+
+#### 2.1 提成门槛:门店生命线
+
+**重要概念**:门店生命线是提成的**门槛条件**,不是提成阶梯
+
+- **数据来源**:`lq_md_target` 表的 `F_StoreLifeline` 字段
+- **判断条件**:
+ - 如果门店业绩 < 门店生命线 → **无提成**
+ - 如果门店业绩 ≥ 门店生命线 → **可以计算提成**
+
+**重要说明**:
+- 门店生命线是**必须设置的**,未设置应报错
+- 门店生命线是门店级别的指标,用于判断是否达到提成门槛
+
+#### 2.2 提成阶梯设置
+
+**数据来源**:`lq_md_general_manager_lifeline` 表
+
+每个门店都有**三个等级的提成阶梯**,每个等级对应不同的提成比例:
+
+| 等级 | 生命线字段 | 提成比例字段 | 说明 |
+|------|-----------|-------------|------|
+| **等级1** | `F_Lifeline1` | `F_CommissionRate1` | 第一级提成阶梯(必填) |
+| **等级2** | `F_Lifeline2` | `F_CommissionRate2` | 第二级提成阶梯(可选) |
+| **等级3** | `F_Lifeline3` | `F_CommissionRate3` | 第三级提成阶梯(可选) |
+
+**重要说明**:
+- 提成阶梯1和提成比例1为必填项
+- 提成阶梯2、3和对应的提成比例为可选项
+- 每个门店的提成阶梯设置可能不同
+- 提成阶梯由总经理在系统中配置
+
+**注意**:提成阶梯(`lq_md_general_manager_lifeline`)和门店生命线(`lq_md_target.F_StoreLifeline`)是**两个不同的概念**:
+- **门店生命线**:判断是否达到提成门槛
+- **提成阶梯**:计算提成金额的阶梯
+
+#### 2.3 阶梯式提成计算规则
+
+**前提条件**:门店业绩必须 ≥ 门店生命线,否则无提成
+
+**计算逻辑**:根据门店业绩落在哪个提成阶梯区间,使用对应的提成比例计算(分段累进)
+
+**示例**(假设某门店的设置):
+- 门店生命线(`lq_md_target.F_StoreLifeline`)= 300,000元
+- 提成阶梯1 = 350,000元,提成比例1 = 1.0%
+- 提成阶梯2 = 400,000元,提成比例2 = 1.5%
+- 提成阶梯3 = 450,000元,提成比例3 = 2.0%
+
+**计算规则**(分段累进):
+
+1. **业绩 < 门店生命线**:
+ - 提成 = 0(无提成)
+ - 示例:业绩 = 280,000元 → 提成 = 0
+
+2. **门店生命线 ≤ 业绩 ≤ 提成阶梯1**:
+ - 提成 = 业绩 × 提成比例1
+ - 示例:业绩 = 320,000元 → 提成 = 320,000 × 1.0% = 3,200元
+
+3. **提成阶梯1 < 业绩 ≤ 提成阶梯2**:
+ - 提成 = 提成阶梯1 × 提成比例1 + (业绩 - 提成阶梯1) × 提成比例2
+ - 示例:业绩 = 380,000元 → 提成 = 350,000 × 1.0% + (380,000 - 350,000) × 1.5% = 3,500 + 450 = 3,950元
+
+4. **提成阶梯2 < 业绩 ≤ 提成阶梯3**:
+ - 提成 = 提成阶梯1 × 提成比例1 + (提成阶梯2 - 提成阶梯1) × 提成比例2 + (业绩 - 提成阶梯2) × 提成比例3
+ - 示例:业绩 = 420,000元 → 提成 = 350,000 × 1.0% + (400,000 - 350,000) × 1.5% + (420,000 - 400,000) × 2.0% = 3,500 + 750 + 400 = 4,650元
+
+5. **业绩 > 提成阶梯3**:
+ - 提成 = 提成阶梯1 × 提成比例1 + (提成阶梯2 - 提成阶梯1) × 提成比例2 + (提成阶梯3 - 提成阶梯2) × 提成比例3 + (业绩 - 提成阶梯3) × 提成比例3
+ - 示例:业绩 = 500,000元 → 提成 = 350,000 × 1.0% + (400,000 - 350,000) × 1.5% + (450,000 - 400,000) × 2.0% + (500,000 - 450,000) × 2.0% = 3,500 + 750 + 1,000 + 1,000 = 6,250元
+
+**注意**:
+- 如果提成阶梯2或提成阶梯3未设置(为NULL或0),则只使用提成阶梯1计算
+- 如果提成阶梯2设置但提成阶梯3未设置,则业绩超过提成阶梯2的部分按提成比例2计算
+
+#### 2.4 多门店提成汇总
+
+**计算方式**:
+- 总经理/经理管理的所有门店的提成分别计算
+- 将所有门店的提成金额汇总,得到总提成金额
+
+**计算公式**:
+```
+总提成 = SUM(各门店提成金额)
+```
+
+---
+
+## 📊 数据来源
+
+### 1. 总经理/经理列表和门店归属
+
+**数据来源表**:`lq_md_general_manager_lifeline`(总经理门店生命线设置表)
+
+**关键字段**:
+- `F_GeneralManagerId`:总经理/经理用户ID
+- `F_ManagerType`:经理类型(0=经理,1=总经理)
+- `F_StoreId`:门店ID
+- `F_Month`:月份(YYYYMM格式)
+
+**查询方式**:
+1. **获取当月所有的经理和总经理**:
+ ```sql
+ SELECT DISTINCT F_GeneralManagerId, F_ManagerType
+ FROM lq_md_general_manager_lifeline
+ WHERE F_Month = 'YYYYMM'
+ ```
+
+2. **获取总经理/经理管理的门店**:
+ ```sql
+ SELECT F_StoreId
+ FROM lq_md_general_manager_lifeline
+ WHERE F_Month = 'YYYYMM'
+ AND F_GeneralManagerId = '用户ID'
+ ```
+
+**重要说明**:
+- 通过 `lq_md_general_manager_lifeline` 表可以获取当月所有的经理和总经理
+- 通过 `lq_md_general_manager_lifeline` 表可以看到当月总经理和经理管理的门店
+- 每个门店在每个月可以设置一个总经理/经理的提成阶梯
+
+### 2. 门店生命线(提成门槛)
+
+**数据来源表**:`lq_md_target`(门店目标表)
+
+**关键字段**:
+- `F_StoreId`:门店ID
+- `F_Month`:月份(YYYYMM格式)
+- `F_StoreLifeline`:门店生命线(**必须设置**)
+
+**查询条件**:
+- 按门店ID和月份查询:`F_StoreId = '门店ID' AND F_Month = 'YYYYMM'`
+
+**重要说明**:
+- 门店生命线是**必须设置的**,未设置应报错
+- 门店生命线用于判断是否达到提成门槛
+- 如果门店业绩 < 门店生命线,则无提成
+
+### 3. 提成阶梯设置
+
+**数据来源表**:`lq_md_general_manager_lifeline`(总经理门店生命线设置表)
+
+**关键字段**:
+- `F_StoreId`:门店ID
+- `F_Month`:月份(YYYYMM格式)
+- `F_GeneralManagerId`:总经理/经理用户ID
+- `F_Lifeline1`:第一级提成阶梯(必填)
+- `F_CommissionRate1`:第一级提成比例(%,必填)
+- `F_Lifeline2`:第二级提成阶梯(可选)
+- `F_CommissionRate2`:第二级提成比例(%,可选)
+- `F_Lifeline3`:第三级提成阶梯(可选)
+- `F_CommissionRate3`:第三级提成比例(%,可选)
+
+**查询条件**:
+- 按门店ID、月份、总经理/经理ID查询
+- 如果未找到提成阶梯设置,则无法计算提成(应报错或跳过该门店)
+
+### 4. 门店总业绩
+
+**定义**:门店总业绩 = 开单业绩 - 退卡业绩
+
+**数据来源表及字段**:
+
+| 业绩类型 | 数据表 | 字段 | 说明 |
+|---------|--------|------|------|
+| **开单业绩** | `lq_kd_kdjlb` | `sfyj` | 门店开单实付金额 |
+| **退卡业绩** | `lq_hytk_hytk` | `F_ActualRefundAmount` 或 `tkje` | 门店退卡金额 |
+
+**计算方式**:
+```sql
+门店总业绩 = SUM(门店开单实付金额) - SUM(门店退卡金额)
+```
+
+**过滤条件**:
+- 所有表记录必须满足:`F_IsEffective = 1`(有效记录)
+- 按统计月份(YYYYMM格式)过滤时间范围
+- 按门店ID(`djmd` 或 `md`)过滤
+
+**重要说明**:
+- **确认**:提成计算基于门店总业绩(开单 - 退卡)
+
+---
+
+## 👥 归属规则
+
+### 1. 总经理/经理与门店的关联
+
+**关联方式**:
+- 通过 `lq_md_general_manager_lifeline` 表关联
+- 每个门店在每个月可以设置一个总经理/经理的提成阶梯
+- 同一个总经理/经理可以管理多个门店
+
+**重要说明**:
+- 通过 `lq_md_general_manager_lifeline` 表可以获取当月所有的经理和总经理
+- 通过 `lq_md_general_manager_lifeline` 表可以看到当月总经理和经理管理的门店
+
+### 2. 门店生命线和提成阶梯的关系
+
+**两个不同的概念**:
+
+1. **门店生命线**(`lq_md_target.F_StoreLifeline`):
+ - 用于判断是否达到提成门槛
+ - 如果门店业绩 < 门店生命线,则无提成
+ - 如果门店业绩 ≥ 门店生命线,则可以计算提成
+
+2. **提成阶梯**(`lq_md_general_manager_lifeline` 表的 Lifeline1/2/3):
+ - 用于计算提成金额的阶梯
+ - 只有在达到门店生命线的前提下,才使用提成阶梯计算提成
+
+**重要说明**:
+- 门店生命线是**必须设置的**,未设置应报错
+- 提成阶梯1和提成比例1是必填项,未设置应报错
+- 提成阶梯2、3和对应的提成比例为可选项
+
+---
+
+## 🔄 计算流程
+
+### 1. 数据准备
+
+1. **获取总经理/经理列表和门店归属**:
+ - 从 `lq_md_general_manager_lifeline` 表获取当月所有的经理和总经理
+ - 按总经理/经理ID分组,得到每个总经理/经理管理的门店列表
+
+2. **获取门店生命线**:
+ - 从 `lq_md_target` 表获取每个门店的生命线(`F_StoreLifeline`)
+ - 门店生命线是必须设置的,未设置应报错
+
+3. **获取提成阶梯设置**:
+ - 从 `lq_md_general_manager_lifeline` 表获取每个门店的提成阶梯设置
+ - 提成阶梯1和提成比例1是必填项,未设置应报错
+
+4. **获取门店总业绩**:
+ - 从 `lq_kd_kdjlb` 表统计每个门店的开单业绩(`sfyj`)
+ - 从 `lq_hytk_hytk` 表统计每个门店的退卡业绩(`F_ActualRefundAmount` 或 `tkje`)
+ - 计算每个门店的总业绩 = 开单业绩 - 退卡业绩
+
+### 2. 工资计算
+
+**遍历每个总经理/经理**:
+
+1. **初始化工资统计对象**:
+ - 底薪 = 4000元
+ - 总提成 = 0
+
+2. **遍历该总经理/经理管理的每个门店**:
+
+ a. **判断是否达到提成门槛**:
+ - 获取该门店的生命线(`lq_md_target.F_StoreLifeline`)
+ - 获取该门店的总业绩
+ - 如果门店业绩 < 门店生命线 → 该门店提成 = 0,跳过
+ - 如果门店业绩 ≥ 门店生命线 → 继续计算提成
+
+ b. **计算该门店的提成**(如果达到门槛):
+ - 获取该门店的提成阶梯设置(`lq_md_general_manager_lifeline`)
+ - 根据门店业绩和提成阶梯,使用分段累进方式计算提成金额
+ - 累加到总提成
+
+3. **计算最终工资**:
+ - 应发工资 = 底薪 + 总提成
+
+### 3. 数据保存
+
+- 将计算结果保存到工资统计表中(待创建表结构)
+- 如果已存在当月数据,则更新;否则插入新数据
+
+---
+
+## 📝 注意事项
+
+1. **数据一致性**:
+ - 门店业绩计算逻辑必须与其他统计接口保持一致
+ - 门店生命线必须与门店目标表保持一致
+
+2. **数据校验**:
+ - 门店生命线(`lq_md_target.F_StoreLifeline`)必须设置,未设置应报错
+ - 提成阶梯1(`lq_md_general_manager_lifeline.F_Lifeline1`)必须设置,未设置应报错
+ - 提成比例1(`lq_md_general_manager_lifeline.F_CommissionRate1`)必须设置,未设置应报错
+ - 如果门店未在 `lq_md_general_manager_lifeline` 表中设置,则无法计算该门店的提成
+
+3. **边界情况**:
+ - 如果门店没有业绩数据,业绩为0,未达到门店生命线,提成为0
+ - 如果门店业绩 < 门店生命线,提成为0
+ - 如果总经理/经理没有管理的门店,总提成为0,应发工资 = 底薪(4000元)
+ - 如果提成阶梯2或提成阶梯3未设置,则只使用提成阶梯1计算
+
+4. **计算精度**:
+ - 涉及金额计算时,建议保留2位小数
+ - 提成比例以百分比形式存储(如:1.0表示1%)
+
+5. **总经理和经理**:
+ - 总经理和经理的计算规则相同
+ - 都使用门店生命线来判断是否达到提成门槛
+ - 都使用 `lq_md_general_manager_lifeline` 表的提成阶梯来计算提成
+
+6. **保底工资**:
+ - 暂时不考虑保底工资规则
+
+---
+
+## 📋 参考文档
+
+- [项目信息-薪酬规则与名词解释.md](./项目信息-薪酬规则与名词解释.md)
+- [店长工资计算规则梳理.md](./店长工资计算规则梳理.md)
+- [主任工资计算规则梳理.md](./主任工资计算规则梳理.md)
+- [大项目部老师工资计算规则梳理.md](./大项目部老师工资计算规则梳理.md)
+
+---
+
+**最后更新时间**:2025年1月
+
diff --git a/大项目部老师工资计算规则梳理.md b/大项目部老师工资计算规则梳理.md
new file mode 100644
index 0000000..e31ed0e
--- /dev/null
+++ b/大项目部老师工资计算规则梳理.md
@@ -0,0 +1,253 @@
+# 大项目部老师工资计算规则梳理
+
+## 📋 目录
+- [计算规则](#计算规则)
+- [数据来源](#数据来源)
+- [归属规则](#归属规则)
+- [计算流程](#计算流程)
+
+---
+
+## 💰 计算规则
+
+### 1. 底薪规则
+
+**固定底薪**:3000元
+
+- 无论业绩多少,底薪固定为3000元
+- 不设档位,不设条件
+
+---
+
+### 2. 业绩提成规则(阶梯式)
+
+业绩提成基于**总业绩**计算,采用阶梯式方式:
+
+| 总业绩范围 | 提成比例 | 说明 |
+|-----------|---------|------|
+| ≤ 20万 | 0% | 无提成 |
+| > 20万 且 ≤ 100万 | 2% | 按2%计算提成 |
+| > 100万 | 2.5% | 按2.5%计算提成 |
+
+**计算说明**:
+- 提成金额 = 总业绩 × 对应提成比例
+- 采用阶梯式计算,不同区间按不同比例计算
+- **注意**:不是分段累进,而是整个总业绩按对应比例计算
+
+**示例**:
+- 总业绩 = 15万 → 提成 = 0(无提成)
+- 总业绩 = 50万 → 提成 = 50万 × 2% = 1万
+- 总业绩 = 120万 → 提成 = 120万 × 2.5% = 3万
+
+---
+
+## 📊 数据来源
+
+### 总业绩(TotalPerformance)
+
+**定义**:门店总业绩 = 开单业绩 - 退卡业绩
+
+**重要说明**:
+- **大项目部老师计算的是门店总业绩,不是个人业绩**
+- 大项目部老师和科技部老师是两个不同的岗位
+- 根据归属表 `lq_md_major_project_teacher_assignment` 确定该老师在某个月归属于哪个门店
+- 然后统计该门店在该月的总业绩(开单业绩 - 退卡业绩)
+
+**数据来源表及字段**:
+
+| 业绩类型 | 数据表 | 字段 | 说明 |
+|---------|--------|------|------|
+| **开单业绩** | `lq_kd_kdjlb` | `sfyj` | 门店开单实付金额(根据归属表关联的门店ID统计) |
+| **退卡业绩** | `lq_hytk_hytk` | `F_ActualRefundAmount` 或 `tkje` | 门店退卡金额(根据归属表关联的门店ID统计) |
+
+**计算方式**:
+```sql
+门店总业绩 = SUM(门店开单实付金额) - SUM(门店退卡金额)
+```
+
+**过滤条件**:
+- 所有表记录必须满足:`F_IsEffective = 1`(有效记录)
+- 按统计月份(YYYYMM格式)过滤时间范围
+- **关键**:根据 `lq_md_major_project_teacher_assignment` 归属表关联
+ - 关联条件:`lq_md_major_project_teacher_assignment.F_TeacherId = 大项目部老师ID`
+ - 关联条件:`lq_md_major_project_teacher_assignment.F_Year = 统计年份`
+ - 关联条件:`lq_md_major_project_teacher_assignment.F_Month = 统计月份`
+ - 关联条件:`lq_md_major_project_teacher_assignment.F_StoreId = 门店ID`
+ - 然后统计该门店在该月的开单业绩和退卡业绩
+
+**注意**:
+- 大项目部老师的归属每个月可能不一样
+- 需要根据归属表来确定该老师在该月份归属于哪个门店
+- **统计的是门店的总业绩,不是个人业绩**
+- 如果同一个老师在某个月归属于多个门店,需要合并多个门店的业绩
+
+---
+
+## 🔗 归属规则
+
+### 归属表:`lq_md_major_project_teacher_assignment`
+
+**表结构**:
+- `F_Id`:主键ID
+- `F_StoreId`:门店ID
+- `F_Year`:年份(YYYY格式)
+- `F_Month`:月份(MM格式)
+- `F_TeacherId`:大项目部老师用户ID
+- `F_EducationTeacherId`:教育部老师用户ID(可选)
+- `F_Remark`:备注说明
+
+**归属规则**:
+- 每个大项目部老师每个月可能归属于不同的门店
+- 归属信息存储在 `lq_md_major_project_teacher_assignment` 表中
+- 统计工资时,需要根据该表来确定:
+ 1. 该老师在该月份归属于哪个门店
+ 2. 该门店的业绩数据中,哪些属于该老师
+
+**关联逻辑**:
+1. 根据 `F_Year` 和 `F_Month` 确定统计月份
+2. 根据 `F_TeacherId` 确定大项目部老师
+3. 根据 `F_StoreId` 确定归属门店
+4. 统计该门店在该月份的业绩数据(开单、消耗、退卡)
+5. 根据业绩表中的老师ID字段关联到该大项目部老师
+
+**业绩关联方式**(待确认):
+- 开单业绩:`lq_kd_kjbsyj` 表中的 `kjblszh` 或 `kjbls` 字段
+- 消耗业绩:`lq_xh_kjbsyj` 表中的 `kjblszh` 或 `kjbls` 字段
+- 退卡业绩:`lq_hytk_kjbsyj` 表中的 `kjblszh` 或 `kjbls` 字段
+
+**注意**:
+- 需要确认大项目部老师的业绩是如何关联的
+- 可能需要通过 `BASE_USER` 表的账号或ID来关联
+- 或者通过其他关联字段来确定
+
+---
+
+## ⚠️ 特殊规则
+
+### 离职员工规则
+
+**适用条件**:
+- 员工状态:`BASE_USER.F_IsOnJob = 0`(离职)
+
+**计算规则**:
+- 离职员工的工资计算规则待确认
+- 可能需要特殊处理(如:只计算在职期间的业绩)
+
+---
+
+## 📝 计算流程
+
+### 1. 数据准备阶段
+
+1. **获取归属信息**
+ - 从 `lq_md_major_project_teacher_assignment` 表查询指定月份的所有归属记录
+ - 按 `F_TeacherId` 和 `F_StoreId` 分组
+
+2. **获取业绩数据**
+ - 开单业绩:从 `lq_kd_kjbsyj` 表统计
+ - 消耗业绩:从 `lq_xh_kjbsyj` 表统计
+ - 退卡业绩:从 `lq_hytk_kjbsyj` 表统计
+ - 按统计月份过滤时间范围
+ - 按归属门店和老师ID关联
+
+3. **获取员工信息**
+ - 从 `BASE_USER` 表获取员工基本信息
+ - 包括:姓名、账号、门店信息等
+
+### 2. 业绩统计阶段
+
+1. **计算开单业绩**
+ - 根据归属表关联的开单业绩数据
+ - 按大项目部老师ID汇总
+
+2. **计算消耗业绩**
+ - 根据归属表关联的消耗业绩数据
+ - 按大项目部老师ID汇总
+
+3. **计算退卡业绩**
+ - 根据归属表关联的退卡业绩数据
+ - 按大项目部老师ID汇总
+
+4. **计算总业绩**
+ - 总业绩 = 开单业绩 + 消耗业绩 + 退卡业绩
+
+### 3. 工资计算阶段
+
+1. **计算底薪**
+ - 底薪 = 3000元(固定)
+
+2. **计算业绩提成**
+ - 判断总业绩范围:
+ - ≤ 20万:提成比例 = 0%
+ - > 20万 且 ≤ 100万:提成比例 = 2%
+ - > 100万:提成比例 = 2.5%
+ - 提成金额 = 总业绩 × 提成比例
+
+3. **计算其他收入**
+ - 手工费、车补、少休费、全勤奖等(默认0)
+
+4. **计算核算应发工资**
+ - 核算应发工资 = 底薪 + 提成合计 + 其他收入
+
+5. **计算最终应发工资**
+ - 最终应发工资 = MAX(核算应发工资, 保底工资)
+ - 如果没有保底工资,则等于核算应发工资
+
+6. **计算实发工资**
+ - 实发工资 = 最终应发工资 - 扣款合计 + 补贴合计 + 奖金
+
+### 4. 数据保存阶段
+
+1. **保存工资统计记录**
+ - 保存到 `lq_major_project_teacher_salary_statistics` 表
+ - 确保同一员工同一月份只有一条记录(唯一索引)
+
+2. **更新状态**
+ - 设置 `F_IsLocked = 0`(未锁定)
+ - 设置 `F_IsTerminated`(根据员工状态)
+
+---
+
+## ❓ 待确认问题
+
+1. **业绩关联方式**
+ - 大项目部老师的业绩是如何关联的?
+ - 是通过 `BASE_USER` 表的账号或ID来关联吗?
+ - 还是通过其他字段来确定?
+
+2. **归属门店的业绩统计**
+ - 如果一个大项目部老师在某个月归属于某个门店,那么:
+ - 该门店的所有业绩都算他的吗?
+ - 还是只统计该门店中他参与的业绩?
+
+3. **离职员工处理**
+ - 离职员工的工资计算规则是什么?
+ - 是否需要特殊处理?
+
+4. **保底工资**
+ - 大项目部老师是否有保底工资?
+ - 保底工资的计算规则是什么?
+
+---
+
+## 📌 总结
+
+### 核心规则
+1. **底薪**:固定3000元
+2. **业绩提成**:阶梯式计算
+ - ≤ 20万:0%
+ - > 20万 且 ≤ 100万:2%
+ - > 100万:2.5%
+
+### 关键点
+1. **归属表关联**:需要根据 `lq_md_major_project_teacher_assignment` 表来确定归属关系
+2. **业绩统计**:需要根据归属表关联的业绩数据来统计
+3. **月份归属**:每个月的归属可能不一样,需要按月统计
+
+### 下一步
+1. 确认业绩关联方式
+2. 确认归属门店的业绩统计规则
+3. 确认离职员工处理规则
+4. 确认保底工资规则
+5. 实现计算逻辑
+
--
libgit2 0.21.4