From 3d57a2884cecf02957022981900e25312717630d Mon Sep 17 00:00:00 2001 From: “wangming” <“wangming@antissoft.com”> Date: Fri, 9 Jan 2026 23:35:53 +0800 Subject: [PATCH] fix: 修复事业部总经理/经理工资计算接口ValueTuple访问错误 --- netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- sql/为事业部总经理经理工资表添加员工确认字段.sql | 19 +++++++++++++++++++ sql/为所有工资表添加员工确认字段.sql | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/为所有工资表添加员工确认字段_安全版.sql | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 509 insertions(+), 9 deletions(-) create mode 100644 sql/为事业部总经理经理工资表添加员工确认字段.sql create mode 100644 sql/为所有工资表添加员工确认字段.sql create mode 100644 sql/为所有工资表添加员工确认字段_安全版.sql diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs index 1dafebc..a0116f8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqBusinessUnitManagerSalaryService.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using NCC.Common.Enum; using NCC.Common.Filter; using NCC.Common.Helper; using NCC.Dependency; using NCC.DynamicApiController; using NCC.Extend.Entitys.Dto.LqBusinessUnitManagerSalary; +using NCC.Extend.Entitys.Dto.LqSalary; using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_attendance_summary; using NCC.Extend.Entitys.lq_cooperation_cost; @@ -17,13 +19,17 @@ 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.Extend.Entitys.lq_store_expense; +using NCC.FriendlyException; using NCC.System.Entitys.Permission; using SqlSugar; using System; using System.Collections.Generic; +using System.Data; +using System.IO; using System.Linq; using System.Threading.Tasks; using Yitter.IdGenerator; +using Microsoft.AspNetCore.Http; namespace NCC.Extend { @@ -35,13 +41,15 @@ namespace NCC.Extend public class LqBusinessUnitManagerSalaryService : IDynamicApiController, ITransient { private readonly ISqlSugarClient _db; + private readonly ILogger _logger; /// /// 初始化一个类型的新实例 /// - public LqBusinessUnitManagerSalaryService(ISqlSugarClient db) + public LqBusinessUnitManagerSalaryService(ISqlSugarClient db, ILogger logger) { _db = db; + _logger = logger; } /// @@ -387,8 +395,8 @@ namespace NCC.Extend // 计算提成(必须满足提成阶梯1才能有提成资格,使用毛利计算) var commissionResult = CalculateStoreCommission(grossProfit, storeLifelineSetting); - var commissionAmount = commissionResult.Amount; - var calculationDetail = commissionResult.Detail; + var commissionAmount = commissionResult.Item1; + var calculationDetail = commissionResult.Item2; totalCommission += commissionAmount; @@ -468,12 +476,41 @@ namespace NCC.Extend // 3. 保存数据 if (managerStats.Any()) { - // 先删除当月旧数据 (防止重复) - await _db.Deleteable() - .Where(x => x.StatisticsMonth == monthStr) - .ExecuteCommandAsync(); - - await _db.Insertable(managerStats.Values.ToList()).ExecuteCommandAsync(); + var existingRecords = await _db.Queryable() + .Where(x => x.StatisticsMonth == monthStr).ToListAsync(); + var existingDict = existingRecords.Where(x => !string.IsNullOrEmpty(x.EmployeeId)) + .GroupBy(x => x.EmployeeId).ToDictionary(g => g.Key, g => g.First()); + var recordsToInsert = new List(); + var recordsToUpdate = new List(); + var skippedCount = 0; + foreach (var salary in managerStats.Values) + { + if (existingDict.ContainsKey(salary.EmployeeId)) + { + var existing = existingDict[salary.EmployeeId]; + if (existing.IsLocked == 1 || existing.EmployeeConfirmStatus == 1) { skippedCount++; continue; } + salary.Id = existing.Id; + salary.EmployeeConfirmStatus = existing.EmployeeConfirmStatus; + salary.EmployeeConfirmTime = existing.EmployeeConfirmTime; + salary.EmployeeConfirmRemark = existing.EmployeeConfirmRemark; + salary.IsLocked = existing.IsLocked; + salary.CreateTime = existing.CreateTime; + salary.CreateUser = existing.CreateUser; + recordsToUpdate.Add(salary); + } + else + { + salary.Id = YitIdHelper.NextId().ToString(); + salary.EmployeeConfirmStatus = 0; + salary.IsLocked = 0; + salary.CreateTime = DateTime.Now; + salary.CreateUser = ""; + recordsToInsert.Add(salary); + } + } + if (recordsToInsert.Any()) await _db.Insertable(recordsToInsert).ExecuteCommandAsync(); + if (recordsToUpdate.Any()) await _db.Updateable(recordsToUpdate).ExecuteCommandAsync(); + if (skippedCount > 0) _logger.LogWarning($"计算工资时跳过了 {skippedCount} 条已锁定或已确认的记录(月份:{monthStr})"); } } @@ -595,6 +632,238 @@ namespace NCC.Extend public decimal CommissionAmount { get; set; } public string CalculationDetail { get; set; } } + + #region 员工工资确认 + + [HttpPost("confirm")] + public async Task ConfirmSalary([FromBody] SalaryConfirmInput input) + { + try + { + if (string.IsNullOrWhiteSpace(input.Id) || string.IsNullOrWhiteSpace(input.EmployeeId)) + throw NCCException.Oh("工资记录ID和员工ID不能为空"); + var salary = await _db.Queryable() + .Where(s => s.Id == input.Id && s.EmployeeId == input.EmployeeId).FirstAsync(); + if (salary == null) throw NCCException.Oh("工资记录不存在或不属于该员工"); + if (salary.EmployeeConfirmStatus == 1) throw NCCException.Oh("该工资条已确认,不能重复确认"); + if (salary.IsLocked != 1) throw NCCException.Oh("该工资条尚未锁定,请等待管理员锁定后再确认"); + salary.EmployeeConfirmStatus = 1; + salary.EmployeeConfirmTime = DateTime.Now; + salary.EmployeeConfirmRemark = input.Remark; + salary.UpdateTime = DateTime.Now; + await _db.Updateable(salary).ExecuteCommandAsync(); + return "确认成功"; + } + catch (Exception ex) + { + throw NCCException.Oh($"确认工资条失败: {ex.Message}"); + } + } + + #endregion + + #region 导入工资 + + /// + /// 从Excel导入事业部总经理工资数据 + /// + /// Excel文件 + /// 导入结果 + [HttpPost("import")] + public async Task ImportSalaryFromExcel(IFormFile file) + { + try + { + if (file == null || file.Length == 0) + throw NCCException.Oh("请选择要上传的Excel文件"); + + var allowedExtensions = new[] { ".xlsx", ".xls" }; + var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant(); + if (!allowedExtensions.Contains(fileExtension)) + throw NCCException.Oh("只支持.xlsx和.xls格式的Excel文件"); + + var recordsToInsert = new List(); + var recordsToUpdate = new List(); + var errorMessages = new List(); + var successCount = 0; + var failCount = 0; + var skippedCount = 0; + + var tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + Path.GetExtension(file.FileName)); + try + { + using (var stream = new FileStream(tempFilePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + var dataTable = ExcelImportHelper.ToDataTable(tempFilePath, 0, 0); + if (dataTable.Rows.Count == 0) + throw NCCException.Oh("Excel文件中没有数据行"); + + Func ParseDecimal = (str) => + { + if (string.IsNullOrWhiteSpace(str)) return 0; + var cleaned = str.Trim().Replace(",", "").Replace(",", "").Replace("¥", "").Replace("$", "").Replace("元", "").Replace("%", "").Replace(" ", ""); + return decimal.TryParse(cleaned, out decimal result) ? result : 0; + }; + + Func ParseInt = (str) => + { + if (string.IsNullOrWhiteSpace(str)) return 0; + var cleaned = str.Trim().Replace(",", "").Replace(",", "").Replace(" ", ""); + return int.TryParse(cleaned, out int result) ? result : 0; + }; + + for (int i = 1; i < dataTable.Rows.Count; i++) + { + try + { + var row = dataTable.Rows[i]; + Func GetColumnValue = (colIndex) => colIndex < row.ItemArray.Length && row[colIndex] != null ? row[colIndex].ToString().Trim() : ""; + + var firstColumnValue = GetColumnValue(0); + bool isOldFormat = !string.IsNullOrWhiteSpace(firstColumnValue) && (firstColumnValue == "员工姓名" || (!long.TryParse(firstColumnValue, out _) && firstColumnValue.Length > 20)); + + int employeeNameIndex = isOldFormat ? 0 : 1; + int offset = isOldFormat ? 0 : 1; + + var id = isOldFormat ? "" : GetColumnValue(0); + var employeeName = GetColumnValue(employeeNameIndex); + + if (string.IsNullOrWhiteSpace(id) && string.IsNullOrWhiteSpace(employeeName)) + continue; + + if (string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(employeeName)) + { + var matchedRecord = await _db.Queryable() + .Where(x => x.EmployeeName == employeeName) + .OrderBy(x => x.CreateTime, OrderByType.Desc) + .FirstAsync(); + if (matchedRecord != null) id = matchedRecord.Id; + } + + if (string.IsNullOrWhiteSpace(employeeName)) + { + errorMessages.Add($"第{i + 1}行:员工姓名不能为空"); + failCount++; + continue; + } + + LqBusinessUnitManagerSalaryStatisticsEntity existing = null; + if (!string.IsNullOrWhiteSpace(id)) + { + existing = await _db.Queryable() + .Where(x => x.Id == id).FirstAsync(); + + if (existing != null && (existing.IsLocked == 1 || existing.EmployeeConfirmStatus == 1)) + { + skippedCount++; + failCount++; + continue; + } + } + + var entity = existing ?? new LqBusinessUnitManagerSalaryStatisticsEntity + { + Id = string.IsNullOrWhiteSpace(id) ? YitIdHelper.NextId().ToString() : id, + EmployeeConfirmStatus = 0, + IsLocked = 0, + CreateTime = DateTime.Now, + CreateUser = "" + }; + + // Excel字段映射(事业部总经理工资35列:员工姓名,员工账号,核算岗位,经理类型,统计月份,底薪,提成合计,在店天数,请假天数,核算应发工资...) + entity.EmployeeName = employeeName; + entity.EmployeeAccount = GetColumnValue(1 + offset); + entity.Position = GetColumnValue(2 + offset); + var managerTypeStr = GetColumnValue(3 + offset); + entity.ManagerType = managerTypeStr == "总经理" || managerTypeStr == "1" ? 1 : 0; + entity.StatisticsMonth = GetColumnValue(4 + offset); + entity.BaseSalary = ParseDecimal(GetColumnValue(5 + offset)); + entity.TotalCommission = ParseDecimal(GetColumnValue(6 + offset)); + entity.WorkingDays = ParseDecimal(GetColumnValue(7 + offset)); + entity.LeaveDays = ParseDecimal(GetColumnValue(8 + offset)); + entity.CalculatedGrossSalary = ParseDecimal(GetColumnValue(9 + offset)); + entity.FinalGrossSalary = ParseDecimal(GetColumnValue(10 + offset)); + entity.MonthlyTrainingSubsidy = ParseDecimal(GetColumnValue(11 + offset)); + entity.MonthlyTransportSubsidy = ParseDecimal(GetColumnValue(12 + offset)); + entity.LastMonthTrainingSubsidy = ParseDecimal(GetColumnValue(13 + offset)); + entity.LastMonthTransportSubsidy = ParseDecimal(GetColumnValue(14 + offset)); + entity.TotalSubsidy = ParseDecimal(GetColumnValue(15 + offset)); + entity.MissingCard = ParseDecimal(GetColumnValue(16 + offset)); + entity.LateArrival = ParseDecimal(GetColumnValue(17 + offset)); + entity.LeaveDeduction = ParseDecimal(GetColumnValue(18 + offset)); + entity.SocialInsuranceDeduction = ParseDecimal(GetColumnValue(19 + offset)); + entity.RewardDeduction = ParseDecimal(GetColumnValue(20 + offset)); + entity.AccommodationDeduction = ParseDecimal(GetColumnValue(21 + offset)); + entity.StudyPeriodDeduction = ParseDecimal(GetColumnValue(22 + offset)); + entity.WorkClothesDeduction = ParseDecimal(GetColumnValue(23 + offset)); + entity.TotalDeduction = ParseDecimal(GetColumnValue(24 + offset)); + entity.Bonus = ParseDecimal(GetColumnValue(25 + offset)); + entity.ReturnPhoneDeposit = ParseDecimal(GetColumnValue(26 + offset)); + entity.ReturnAccommodationDeposit = ParseDecimal(GetColumnValue(27 + offset)); + entity.LastMonthSupplement = ParseDecimal(GetColumnValue(28 + offset)); + entity.ActualSalary = ParseDecimal(GetColumnValue(29 + offset)); + entity.MonthlyPaymentStatus = GetColumnValue(30 + offset); + entity.PaidAmount = ParseDecimal(GetColumnValue(31 + offset)); + entity.PendingAmount = ParseDecimal(GetColumnValue(32 + offset)); + entity.MonthlyTotalPayment = ParseDecimal(GetColumnValue(33 + offset)); + var isTerminatedStr = GetColumnValue(34 + offset); + entity.IsTerminated = isTerminatedStr == "离职" || isTerminatedStr == "1" ? 1 : 0; + + if (existing != null) + { + entity.EmployeeId = existing.EmployeeId; + entity.StorePerformanceDetail = existing.StorePerformanceDetail; + } + else + { + if (!string.IsNullOrWhiteSpace(employeeName)) + { + var user = await _db.Queryable() + .Where(u => u.RealName == employeeName).FirstAsync(); + if (user != null) entity.EmployeeId = user.Id; + } + } + + entity.UpdateTime = DateTime.Now; + if (existing != null) recordsToUpdate.Add(entity); + else recordsToInsert.Add(entity); + successCount++; + } + catch (Exception ex) + { + errorMessages.Add($"第{i + 1}行数据处理失败: {ex.Message}"); + failCount++; + } + } + } + finally + { + if (File.Exists(tempFilePath)) File.Delete(tempFilePath); + } + + if (recordsToInsert.Any()) await _db.Insertable(recordsToInsert).ExecuteCommandAsync(); + if (recordsToUpdate.Any()) await _db.Updateable(recordsToUpdate).ExecuteCommandAsync(); + + return new + { + success = true, + message = $"导入完成:成功 {successCount} 条,失败 {failCount} 条,跳过 {skippedCount} 条(已锁定或已确认)", + successCount, + failCount, + skippedCount, + errors = errorMessages + }; + } + catch (Exception ex) + { + throw NCCException.Oh($"导入事业部总经理工资数据失败: {ex.Message}"); + } + } + + #endregion } } diff --git a/sql/为事业部总经理经理工资表添加员工确认字段.sql b/sql/为事业部总经理经理工资表添加员工确认字段.sql new file mode 100644 index 0000000..61cc9bf --- /dev/null +++ b/sql/为事业部总经理经理工资表添加员工确认字段.sql @@ -0,0 +1,19 @@ +-- ============================================ +-- 为事业部总经理/经理工资统计表添加员工确认字段 +-- 功能:支持员工确认工资条,确认后工资数据不可修改 +-- 创建时间:2025年 +-- ============================================ + +-- 为事业部总经理/经理工资统计表添加员工确认字段 +ALTER TABLE lq_business_unit_manager_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 验证字段是否添加成功 +SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'lq_business_unit_manager_salary_statistics' + AND COLUMN_NAME LIKE '%Confirm%' +ORDER BY ORDINAL_POSITION; diff --git a/sql/为所有工资表添加员工确认字段.sql b/sql/为所有工资表添加员工确认字段.sql new file mode 100644 index 0000000..9fc89bf --- /dev/null +++ b/sql/为所有工资表添加员工确认字段.sql @@ -0,0 +1,84 @@ +-- ============================================ +-- 为所有工资表添加员工确认字段 +-- 功能:支持员工确认工资条,确认后工资数据不可修改 +-- 创建时间:2025年 +-- 说明:lq_employee_salary_statistics 表在创建时已包含这些字段,无需添加 +-- ============================================ + +-- 注意:MySQL不支持 ADD COLUMN IF NOT EXISTS 语法 +-- 如果字段已存在,执行时会报错,可以忽略该错误或先检查字段是否存在 + +-- 1. 健康师工资统计表 +ALTER TABLE lq_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 2. 科技部老师工资统计表 +ALTER TABLE lq_tech_teacher_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 3. 店助工资统计表 +ALTER TABLE lq_assistant_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 4. 店长工资统计表 +ALTER TABLE lq_store_manager_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 5. 主任工资统计表 +ALTER TABLE lq_director_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 6. 大项目部老师工资统计表 +ALTER TABLE lq_major_project_teacher_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 7. 大项目主管工资统计表 +ALTER TABLE lq_major_project_director_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 8. 科技部总经理工资统计表 +ALTER TABLE lq_tech_general_manager_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- 9. 事业部总经理/经理工资统计表 +ALTER TABLE lq_business_unit_manager_salary_statistics +ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT '员工确认状态(0=未确认,1=已确认)', +ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT '员工确认时间', +ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT '员工确认备注'; + +-- ============================================ +-- 验证字段是否添加成功 +-- ============================================ +SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME IN ( + 'lq_salary_statistics', + 'lq_tech_teacher_salary_statistics', + 'lq_assistant_salary_statistics', + 'lq_store_manager_salary_statistics', + 'lq_director_salary_statistics', + 'lq_major_project_teacher_salary_statistics', + 'lq_major_project_director_salary_statistics', + 'lq_tech_general_manager_salary_statistics', + 'lq_business_unit_manager_salary_statistics', + 'lq_employee_salary_statistics' + ) + AND COLUMN_NAME LIKE '%Confirm%' +ORDER BY TABLE_NAME, ORDINAL_POSITION; diff --git a/sql/为所有工资表添加员工确认字段_安全版.sql b/sql/为所有工资表添加员工确认字段_安全版.sql new file mode 100644 index 0000000..8e69b00 --- /dev/null +++ b/sql/为所有工资表添加员工确认字段_安全版.sql @@ -0,0 +1,128 @@ +-- ============================================ +-- 为所有工资表添加员工确认字段(安全版) +-- 功能:支持员工确认工资条,确认后工资数据不可修改 +-- 创建时间:2025年 +-- 说明:此版本会先检查字段是否存在,避免重复添加 +-- ============================================ + +-- 说明:lq_employee_salary_statistics 表在创建时已包含这些字段,无需添加 + +-- 使用存储过程安全添加字段(如果字段不存在则添加) +DELIMITER $$ + +DROP PROCEDURE IF EXISTS AddEmployeeConfirmFields$$ + +CREATE PROCEDURE AddEmployeeConfirmFields() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE tableName VARCHAR(100); + DECLARE tableCursor CURSOR FOR + SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME IN ( + 'lq_salary_statistics', + 'lq_tech_teacher_salary_statistics', + 'lq_assistant_salary_statistics', + 'lq_store_manager_salary_statistics', + 'lq_director_salary_statistics', + 'lq_major_project_teacher_salary_statistics', + 'lq_major_project_director_salary_statistics', + 'lq_tech_general_manager_salary_statistics', + 'lq_business_unit_manager_salary_statistics' + ); + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + OPEN tableCursor; + read_loop: LOOP + FETCH tableCursor INTO tableName; + IF done THEN + LEAVE read_loop; + END IF; + + -- 检查并添加 F_EmployeeConfirmStatus + SET @sql = CONCAT('SELECT COUNT(*) INTO @colCount FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = ''', tableName, ''' + AND COLUMN_NAME = ''F_EmployeeConfirmStatus'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + IF @colCount = 0 THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' + ADD COLUMN F_EmployeeConfirmStatus INT NOT NULL DEFAULT 0 COMMENT ''员工确认状态(0=未确认,1=已确认)'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + SELECT CONCAT('已为表 ', tableName, ' 添加字段 F_EmployeeConfirmStatus') AS result; + END IF; + + -- 检查并添加 F_EmployeeConfirmTime + SET @sql = CONCAT('SELECT COUNT(*) INTO @colCount FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = ''', tableName, ''' + AND COLUMN_NAME = ''F_EmployeeConfirmTime'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + IF @colCount = 0 THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' + ADD COLUMN F_EmployeeConfirmTime DATETIME NULL COMMENT ''员工确认时间'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + SELECT CONCAT('已为表 ', tableName, ' 添加字段 F_EmployeeConfirmTime') AS result; + END IF; + + -- 检查并添加 F_EmployeeConfirmRemark + SET @sql = CONCAT('SELECT COUNT(*) INTO @colCount FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = ''', tableName, ''' + AND COLUMN_NAME = ''F_EmployeeConfirmRemark'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + IF @colCount = 0 THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' + ADD COLUMN F_EmployeeConfirmRemark VARCHAR(500) NULL COMMENT ''员工确认备注'''); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + SELECT CONCAT('已为表 ', tableName, ' 添加字段 F_EmployeeConfirmRemark') AS result; + END IF; + + END LOOP; + CLOSE tableCursor; +END$$ + +DELIMITER ; + +-- 执行存储过程 +CALL AddEmployeeConfirmFields(); + +-- 删除存储过程 +DROP PROCEDURE IF EXISTS AddEmployeeConfirmFields; + +-- ============================================ +-- 验证字段是否添加成功 +-- ============================================ +SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME IN ( + 'lq_salary_statistics', + 'lq_tech_teacher_salary_statistics', + 'lq_assistant_salary_statistics', + 'lq_store_manager_salary_statistics', + 'lq_director_salary_statistics', + 'lq_major_project_teacher_salary_statistics', + 'lq_major_project_director_salary_statistics', + 'lq_tech_general_manager_salary_statistics', + 'lq_business_unit_manager_salary_statistics', + 'lq_employee_salary_statistics' + ) + AND COLUMN_NAME LIKE '%Confirm%' +ORDER BY TABLE_NAME, ORDINAL_POSITION; -- libgit2 0.21.4