bug修改
This commit is contained in:
parent
599fa05ae6
commit
0cd0fce8c2
|
|
@ -1177,14 +1177,53 @@ public class PersonnelController : BaseApiController
|
|||
cell.Style.Border.OutsideBorder = ClosedXML.Excel.XLBorderStyleValues.Thin;
|
||||
}
|
||||
|
||||
// 设置照片列宽度
|
||||
worksheet.Column(3).Width = 15;
|
||||
|
||||
// 填充数据(从第4行开始)
|
||||
int row = 4;
|
||||
int seq = 1;
|
||||
var webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
|
||||
|
||||
foreach (var p in personnelList)
|
||||
{
|
||||
worksheet.Cell(row, 1).Value = seq++;
|
||||
worksheet.Cell(row, 2).Value = p.Name;
|
||||
worksheet.Cell(row, 3).Value = ""; // 照片列留空
|
||||
|
||||
// 处理照片 - 2寸照片比例 35mm x 49mm (约 3:4)
|
||||
worksheet.Row(row).Height = 70; // 设置行高
|
||||
if (!string.IsNullOrEmpty(p.PhotoPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
// PhotoPath 格式如 "/uploads/xxx.jpg",需要转换为实际文件路径
|
||||
var photoRelativePath = p.PhotoPath.TrimStart('/').Replace("/", Path.DirectorySeparatorChar.ToString());
|
||||
var photoFullPath = Path.Combine(webRootPath, photoRelativePath);
|
||||
|
||||
if (System.IO.File.Exists(photoFullPath))
|
||||
{
|
||||
var picture = worksheet.AddPicture(photoFullPath);
|
||||
// 先移动到目标单元格
|
||||
var targetCell = worksheet.Cell(row, 3);
|
||||
picture.MoveTo(targetCell, 18, 3); // 偏移实现居中
|
||||
// 2寸照片比例:宽35mm 高49mm,按比例缩放 (38 x 53 像素)
|
||||
picture.WithSize(38, 53);
|
||||
}
|
||||
else
|
||||
{
|
||||
worksheet.Cell(row, 3).Value = "图片不存在";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
worksheet.Cell(row, 3).Value = "图片加载失败";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
worksheet.Cell(row, 3).Value = "";
|
||||
}
|
||||
|
||||
worksheet.Cell(row, 4).Value = p.Unit ?? p.SubmittedByUnit?.Name ?? "";
|
||||
worksheet.Cell(row, 5).Value = p.Position;
|
||||
worksheet.Cell(row, 6).Value = p.Rank;
|
||||
|
|
@ -1381,6 +1420,19 @@ public class PersonnelController : BaseApiController
|
|||
continue;
|
||||
}
|
||||
|
||||
// 检查士兵证号是否重复
|
||||
var idNumber = GetNullIfEmpty(row.Cell(7).GetString());
|
||||
if (!string.IsNullOrEmpty(idNumber))
|
||||
{
|
||||
var existingPersonnel = await _personnelService.GetByIdNumberAsync(idNumber);
|
||||
if (existingPersonnel != null)
|
||||
{
|
||||
failCount++;
|
||||
importResults.Add(new { row = row.RowNumber(), success = false, message = $"士兵证号 {idNumber} 已存在" });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var birthDate = GetNullIfEmpty(row.Cell(13).GetString());
|
||||
var age = CalculateAge(birthDate);
|
||||
|
||||
|
|
@ -1389,7 +1441,7 @@ public class PersonnelController : BaseApiController
|
|||
Name = name,
|
||||
Gender = "男", // 默认性别,模板中没有性别列
|
||||
Age = age,
|
||||
IdNumber = GetNullIfEmpty(row.Cell(7).GetString()) ?? "", // 士兵证号
|
||||
IdNumber = idNumber ?? "", // 士兵证号
|
||||
Unit = unit,
|
||||
Position = position,
|
||||
Rank = rank,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,13 @@ public class PersonnelService : IPersonnelService
|
|||
.FirstOrDefaultAsync(p => p.Id == id);
|
||||
}
|
||||
|
||||
public async Task<Personnel?> GetByIdNumberAsync(string idNumber)
|
||||
{
|
||||
if (string.IsNullOrEmpty(idNumber)) return null;
|
||||
return await _context.Personnel
|
||||
.FirstOrDefaultAsync(p => p.IdNumber == idNumber);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false)
|
||||
{
|
||||
if (includeSubordinates)
|
||||
|
|
@ -111,11 +118,20 @@ public class PersonnelService : IPersonnelService
|
|||
// 例如:营级单位提交的人才,团级审批后应为"营级人才"
|
||||
actualLevel = (PersonnelLevel)(int)personnel.SubmittedByUnit!.Level;
|
||||
|
||||
// 验证审批单位层级必须高于提交单位层级(数值越小层级越高)
|
||||
var unitLevelValue = (int)approvedByUnit.Level;
|
||||
var submittedUnitLevelValue = (int)personnel.SubmittedByUnit!.Level;
|
||||
if (unitLevelValue >= submittedUnitLevelValue)
|
||||
throw new ArgumentException("审批单位层级必须高于提交单位层级");
|
||||
// 师部(最高级别)可以审批自己提交的人才,此时人才等级为师级
|
||||
if (approvedByUnit.Level == OrganizationalLevel.Division &&
|
||||
personnel.SubmittedByUnitId == approvedByUnitId)
|
||||
{
|
||||
actualLevel = PersonnelLevel.Division;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 验证审批单位层级必须高于提交单位层级(数值越小层级越高)
|
||||
var unitLevelValue = (int)approvedByUnit.Level;
|
||||
var submittedUnitLevelValue = (int)personnel.SubmittedByUnit!.Level;
|
||||
if (unitLevelValue >= submittedUnitLevelValue)
|
||||
throw new ArgumentException("审批单位层级必须高于提交单位层级");
|
||||
}
|
||||
}
|
||||
else if (previousStatus == PersonnelStatus.Approved)
|
||||
{
|
||||
|
|
@ -584,7 +600,11 @@ public class PersonnelService : IPersonnelService
|
|||
if (personnel.Status == PersonnelStatus.Rejected)
|
||||
return false;
|
||||
|
||||
// 本单位不能审批自己提交的人员,必须由上级单位审批
|
||||
// 师部(最高级别)可以审批所有人员,包括自己提交的
|
||||
if (user.OrganizationalUnit!.Level == OrganizationalLevel.Division)
|
||||
return true;
|
||||
|
||||
// 非师部:本单位不能审批自己提交的人员,必须由上级单位审批
|
||||
if (user.OrganizationalUnitId == personnel.SubmittedByUnitId)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace MilitaryTrainingManagement.Services.Interfaces;
|
|||
public interface IPersonnelService
|
||||
{
|
||||
Task<Personnel?> GetByIdAsync(int id);
|
||||
Task<Personnel?> GetByIdNumberAsync(string idNumber);
|
||||
Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false);
|
||||
Task<Personnel> CreateAsync(Personnel personnel);
|
||||
Task<Personnel> UpdateAsync(Personnel personnel);
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ function getPieOption(regiment: RegimentAllocationStats) {
|
|||
const consumed = regiment.totalConsumed
|
||||
const remaining = regiment.totalQuota - consumed
|
||||
|
||||
// 当配额为0时,显示全灰色
|
||||
const hasData = regiment.totalQuota > 0
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
|
|
@ -130,10 +133,14 @@ function getPieOption(regiment: RegimentAllocationStats) {
|
|||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: consumed, name: '已消耗', itemStyle: { color: '#67C23A' } },
|
||||
{ value: remaining > 0 ? remaining : 0, name: '剩余', itemStyle: { color: '#E4E7ED' } }
|
||||
]
|
||||
data: hasData
|
||||
? [
|
||||
{ value: consumed, name: '已消耗', itemStyle: { color: '#67C23A' } },
|
||||
{ value: remaining > 0 ? remaining : 0, name: '剩余', itemStyle: { color: '#E4E7ED' } }
|
||||
]
|
||||
: [
|
||||
{ value: 1, name: '无配额', itemStyle: { color: '#E4E7ED' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -669,11 +669,27 @@ async function handleFileChange(event: Event) {
|
|||
}
|
||||
|
||||
if (result.failCount > 0) {
|
||||
ElMessage.warning(`${result.failCount}条记录导入失败`)
|
||||
console.log('导入失败详情:', result.results.filter(r => !r.success))
|
||||
// 获取失败记录的详细信息
|
||||
const failedResults = result.results.filter((r: any) => !r.success)
|
||||
const failMessages = failedResults.slice(0, 3).map((r: any) => `第${r.row}行: ${r.message}`).join('\n')
|
||||
const moreCount = failedResults.length > 3 ? `\n...还有${failedResults.length - 3}条失败` : ''
|
||||
|
||||
ElMessageBox.alert(
|
||||
`${result.failCount}条记录导入失败:\n\n${failMessages}${moreCount}`,
|
||||
'导入失败详情',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '知道了'
|
||||
}
|
||||
)
|
||||
console.log('导入失败详情:', failedResults)
|
||||
}
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.message || '导入失败')
|
||||
// 解析后端返回的错误信息
|
||||
const errorMsg = error.response?.data?.message || '导入失败'
|
||||
// 转换常见的英文错误为中文
|
||||
const chineseMsg = translateErrorMessage(errorMsg)
|
||||
ElMessage.error(chineseMsg)
|
||||
} finally {
|
||||
importing.value = false
|
||||
// 清空文件选择,允许重复选择同一文件
|
||||
|
|
@ -681,6 +697,17 @@ async function handleFileChange(event: Event) {
|
|||
}
|
||||
}
|
||||
|
||||
// 将英文错误信息转换为中文
|
||||
function translateErrorMessage(msg: string): string {
|
||||
if (msg.includes('duplicate key') || msg.includes('unique index') || msg.includes('IX_Personnel_IdNumber')) {
|
||||
return '导入失败:存在重复的士兵证号'
|
||||
}
|
||||
if (msg.includes('entity changes')) {
|
||||
return '导入失败:数据保存出错,请检查数据格式'
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
function handleView(person: Personnel) {
|
||||
router.push(`/personnel/${person.id}`)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user