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;
|
cell.Style.Border.OutsideBorder = ClosedXML.Excel.XLBorderStyleValues.Thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置照片列宽度
|
||||||
|
worksheet.Column(3).Width = 15;
|
||||||
|
|
||||||
// 填充数据(从第4行开始)
|
// 填充数据(从第4行开始)
|
||||||
int row = 4;
|
int row = 4;
|
||||||
int seq = 1;
|
int seq = 1;
|
||||||
|
var webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
|
||||||
|
|
||||||
foreach (var p in personnelList)
|
foreach (var p in personnelList)
|
||||||
{
|
{
|
||||||
worksheet.Cell(row, 1).Value = seq++;
|
worksheet.Cell(row, 1).Value = seq++;
|
||||||
worksheet.Cell(row, 2).Value = p.Name;
|
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, 4).Value = p.Unit ?? p.SubmittedByUnit?.Name ?? "";
|
||||||
worksheet.Cell(row, 5).Value = p.Position;
|
worksheet.Cell(row, 5).Value = p.Position;
|
||||||
worksheet.Cell(row, 6).Value = p.Rank;
|
worksheet.Cell(row, 6).Value = p.Rank;
|
||||||
|
|
@ -1381,6 +1420,19 @@ public class PersonnelController : BaseApiController
|
||||||
continue;
|
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 birthDate = GetNullIfEmpty(row.Cell(13).GetString());
|
||||||
var age = CalculateAge(birthDate);
|
var age = CalculateAge(birthDate);
|
||||||
|
|
||||||
|
|
@ -1389,7 +1441,7 @@ public class PersonnelController : BaseApiController
|
||||||
Name = name,
|
Name = name,
|
||||||
Gender = "男", // 默认性别,模板中没有性别列
|
Gender = "男", // 默认性别,模板中没有性别列
|
||||||
Age = age,
|
Age = age,
|
||||||
IdNumber = GetNullIfEmpty(row.Cell(7).GetString()) ?? "", // 士兵证号
|
IdNumber = idNumber ?? "", // 士兵证号
|
||||||
Unit = unit,
|
Unit = unit,
|
||||||
Position = position,
|
Position = position,
|
||||||
Rank = rank,
|
Rank = rank,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,13 @@ public class PersonnelService : IPersonnelService
|
||||||
.FirstOrDefaultAsync(p => p.Id == id);
|
.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)
|
public async Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false)
|
||||||
{
|
{
|
||||||
if (includeSubordinates)
|
if (includeSubordinates)
|
||||||
|
|
@ -111,11 +118,20 @@ public class PersonnelService : IPersonnelService
|
||||||
// 例如:营级单位提交的人才,团级审批后应为"营级人才"
|
// 例如:营级单位提交的人才,团级审批后应为"营级人才"
|
||||||
actualLevel = (PersonnelLevel)(int)personnel.SubmittedByUnit!.Level;
|
actualLevel = (PersonnelLevel)(int)personnel.SubmittedByUnit!.Level;
|
||||||
|
|
||||||
// 验证审批单位层级必须高于提交单位层级(数值越小层级越高)
|
// 师部(最高级别)可以审批自己提交的人才,此时人才等级为师级
|
||||||
var unitLevelValue = (int)approvedByUnit.Level;
|
if (approvedByUnit.Level == OrganizationalLevel.Division &&
|
||||||
var submittedUnitLevelValue = (int)personnel.SubmittedByUnit!.Level;
|
personnel.SubmittedByUnitId == approvedByUnitId)
|
||||||
if (unitLevelValue >= submittedUnitLevelValue)
|
{
|
||||||
throw new ArgumentException("审批单位层级必须高于提交单位层级");
|
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)
|
else if (previousStatus == PersonnelStatus.Approved)
|
||||||
{
|
{
|
||||||
|
|
@ -584,7 +600,11 @@ public class PersonnelService : IPersonnelService
|
||||||
if (personnel.Status == PersonnelStatus.Rejected)
|
if (personnel.Status == PersonnelStatus.Rejected)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 本单位不能审批自己提交的人员,必须由上级单位审批
|
// 师部(最高级别)可以审批所有人员,包括自己提交的
|
||||||
|
if (user.OrganizationalUnit!.Level == OrganizationalLevel.Division)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 非师部:本单位不能审批自己提交的人员,必须由上级单位审批
|
||||||
if (user.OrganizationalUnitId == personnel.SubmittedByUnitId)
|
if (user.OrganizationalUnitId == personnel.SubmittedByUnitId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace MilitaryTrainingManagement.Services.Interfaces;
|
||||||
public interface IPersonnelService
|
public interface IPersonnelService
|
||||||
{
|
{
|
||||||
Task<Personnel?> GetByIdAsync(int id);
|
Task<Personnel?> GetByIdAsync(int id);
|
||||||
|
Task<Personnel?> GetByIdNumberAsync(string idNumber);
|
||||||
Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false);
|
Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false);
|
||||||
Task<Personnel> CreateAsync(Personnel personnel);
|
Task<Personnel> CreateAsync(Personnel personnel);
|
||||||
Task<Personnel> UpdateAsync(Personnel personnel);
|
Task<Personnel> UpdateAsync(Personnel personnel);
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,9 @@ function getPieOption(regiment: RegimentAllocationStats) {
|
||||||
const consumed = regiment.totalConsumed
|
const consumed = regiment.totalConsumed
|
||||||
const remaining = regiment.totalQuota - consumed
|
const remaining = regiment.totalQuota - consumed
|
||||||
|
|
||||||
|
// 当配额为0时,显示全灰色
|
||||||
|
const hasData = regiment.totalQuota > 0
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
|
|
@ -130,10 +133,14 @@ function getPieOption(regiment: RegimentAllocationStats) {
|
||||||
labelLine: {
|
labelLine: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
data: [
|
data: hasData
|
||||||
{ value: consumed, name: '已消耗', itemStyle: { color: '#67C23A' } },
|
? [
|
||||||
{ value: remaining > 0 ? remaining : 0, name: '剩余', itemStyle: { color: '#E4E7ED' } }
|
{ 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) {
|
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) {
|
} catch (error: any) {
|
||||||
ElMessage.error(error.response?.data?.message || '导入失败')
|
// 解析后端返回的错误信息
|
||||||
|
const errorMsg = error.response?.data?.message || '导入失败'
|
||||||
|
// 转换常见的英文错误为中文
|
||||||
|
const chineseMsg = translateErrorMessage(errorMsg)
|
||||||
|
ElMessage.error(chineseMsg)
|
||||||
} finally {
|
} finally {
|
||||||
importing.value = false
|
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) {
|
function handleView(person: Personnel) {
|
||||||
router.push(`/personnel/${person.id}`)
|
router.push(`/personnel/${person.id}`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user