diff --git a/src/MilitaryTrainingManagement/Controllers/PersonnelController.cs b/src/MilitaryTrainingManagement/Controllers/PersonnelController.cs
index dea19f6..be69084 100644
--- a/src/MilitaryTrainingManagement/Controllers/PersonnelController.cs
+++ b/src/MilitaryTrainingManagement/Controllers/PersonnelController.cs
@@ -704,7 +704,8 @@ public class PersonnelController : BaseApiController
// 检查权限:只有提交单位或上级单位可以删除
var unitId = GetCurrentUnitId();
- if (unitId == null)
+ var userLevel = GetCurrentUnitLevel();
+ if (unitId == null || userLevel == null)
{
return Unauthorized();
}
@@ -722,10 +723,19 @@ public class PersonnelController : BaseApiController
}
}
- // 只能删除待审批状态的人员
- if (personnel.Status != PersonnelStatus.Pending)
+ // 待审批状态的人员可以直接删除
+ // 已批准状态的人员,只有审批单位或更高级别单位可以删除
+ if (personnel.Status == PersonnelStatus.Approved)
{
- return BadRequest(new { message = "只能删除待审批状态的人员记录" });
+ // 检查当前用户单位层级是否足够高(数值越小层级越高)
+ var personnelLevelValue = personnel.ApprovedLevel.HasValue ? (int)personnel.ApprovedLevel.Value : 4;
+ var userLevelValue = (int)userLevel.Value;
+
+ // 用户层级必须高于或等于人员等级才能删除
+ if (userLevelValue > personnelLevelValue)
+ {
+ return BadRequest(new { message = "您的权限不足以删除该等级的人员" });
+ }
}
try
@@ -787,4 +797,52 @@ public class PersonnelController : BaseApiController
}
}
+ ///
+ /// 拒绝向上申报请求
+ ///
+ [HttpPost("{id}/reject-upgrade")]
+ [Authorize(Policy = "BattalionLevel")] // 营级及以上权限
+ public async Task RejectUpgrade(int id, [FromBody] RejectUpgradeRequest request)
+ {
+ var unitId = GetCurrentUnitId();
+ if (unitId == null)
+ {
+ return Unauthorized();
+ }
+
+ try
+ {
+ var personnel = await _personnelService.RejectUpgradeAsync(id, unitId.Value, request.Comments);
+ return Ok(MapToResponse(personnel));
+ }
+ catch (ArgumentException ex)
+ {
+ return BadRequest(new { message = ex.Message });
+ }
+ }
+
+ ///
+ /// 师部直接升级团级人才为师级
+ ///
+ [HttpPost("{id}/direct-upgrade")]
+ [Authorize(Policy = "DivisionLevel")] // 师级权限
+ public async Task DirectUpgrade(int id)
+ {
+ var unitId = GetCurrentUnitId();
+ if (unitId == null)
+ {
+ return Unauthorized();
+ }
+
+ try
+ {
+ var personnel = await _personnelService.DirectUpgradeAsync(id, unitId.Value);
+ return Ok(MapToResponse(personnel));
+ }
+ catch (ArgumentException ex)
+ {
+ return BadRequest(new { message = ex.Message });
+ }
+ }
+
}
diff --git a/src/MilitaryTrainingManagement/Models/DTOs/PersonnelDTOs.cs b/src/MilitaryTrainingManagement/Models/DTOs/PersonnelDTOs.cs
index e056bd6..1e09331 100644
--- a/src/MilitaryTrainingManagement/Models/DTOs/PersonnelDTOs.cs
+++ b/src/MilitaryTrainingManagement/Models/DTOs/PersonnelDTOs.cs
@@ -122,6 +122,16 @@ public class RejectPersonnelRequest
public string? Reason { get; set; }
}
+///
+/// 拒绝向上申报请求DTO
+///
+public class RejectUpgradeRequest
+{
+ [Required(ErrorMessage = "拒绝原因不能为空")]
+ [StringLength(500, ErrorMessage = "拒绝原因长度不能超过500个字符")]
+ public string Comments { get; set; } = string.Empty;
+}
+
///
/// 人员响应DTO
///
diff --git a/src/MilitaryTrainingManagement/Services/Implementations/PersonnelService.cs b/src/MilitaryTrainingManagement/Services/Implementations/PersonnelService.cs
index 3148fd2..8779777 100644
--- a/src/MilitaryTrainingManagement/Services/Implementations/PersonnelService.cs
+++ b/src/MilitaryTrainingManagement/Services/Implementations/PersonnelService.cs
@@ -778,4 +778,91 @@ public class PersonnelService : IPersonnelService
return personnel;
}
+
+ ///
+ /// 拒绝向上申报请求
+ ///
+ public async Task RejectUpgradeAsync(int personnelId, int rejectedByUnitId, string comments)
+ {
+ var personnel = await _context.Personnel
+ .Include(p => p.SubmittedByUnit)
+ .Include(p => p.ApprovedByUnit)
+ .Include(p => p.PendingUpgradeByUnit)
+ .FirstOrDefaultAsync(p => p.Id == personnelId);
+
+ if (personnel == null)
+ throw new ArgumentException("人员记录不存在");
+
+ if (!personnel.PendingUpgradeByUnitId.HasValue)
+ throw new ArgumentException("该人员没有待处理的向上申报请求");
+
+ var rejectedByUnit = await _context.OrganizationalUnits.FindAsync(rejectedByUnitId);
+ if (rejectedByUnit == null)
+ throw new ArgumentException("审批单位不存在");
+
+ var previousLevel = personnel.ApprovedLevel;
+
+ // 清除待申报标记,保持原有等级不变
+ personnel.PendingUpgradeByUnitId = null;
+
+ await _context.SaveChangesAsync();
+
+ // 记录审批历史
+ var userId = await GetUserIdByUnitAsync(rejectedByUnitId);
+ await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Rejected,
+ PersonnelStatus.Approved, PersonnelStatus.Approved, previousLevel, previousLevel,
+ userId, rejectedByUnitId, $"向上申报被拒绝:{comments}");
+
+ _logger.LogInformation("人员 {PersonnelId} 向上申报已被单位 {UnitId} 拒绝,原因:{Comments}",
+ personnelId, rejectedByUnitId, comments);
+
+ return personnel;
+ }
+
+ ///
+ /// 师部直接升级团级人才为师级
+ ///
+ public async Task DirectUpgradeAsync(int personnelId, int divisionUnitId)
+ {
+ var personnel = await _context.Personnel
+ .Include(p => p.SubmittedByUnit)
+ .Include(p => p.ApprovedByUnit)
+ .FirstOrDefaultAsync(p => p.Id == personnelId);
+
+ if (personnel == null)
+ throw new ArgumentException("人员记录不存在");
+
+ if (personnel.Status != PersonnelStatus.Approved)
+ throw new ArgumentException("只有已审批的人员才能升级");
+
+ if (personnel.ApprovedLevel != PersonnelLevel.Regiment)
+ throw new ArgumentException("只能升级团级人才");
+
+ var divisionUnit = await _context.OrganizationalUnits.FindAsync(divisionUnitId);
+ if (divisionUnit == null)
+ throw new ArgumentException("单位不存在");
+
+ if (divisionUnit.Level != OrganizationalLevel.Division)
+ throw new ArgumentException("只有师部可以直接升级团级人才");
+
+ var previousLevel = personnel.ApprovedLevel;
+
+ // 直接升级为师级
+ personnel.ApprovedLevel = PersonnelLevel.Division;
+ personnel.ApprovedByUnitId = divisionUnitId;
+ personnel.ApprovedAt = DateTime.UtcNow;
+
+ await _context.SaveChangesAsync();
+
+ // 记录审批历史
+ var userId = await GetUserIdByUnitAsync(divisionUnitId);
+ await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.LevelUpgraded,
+ PersonnelStatus.Approved, PersonnelStatus.Approved, previousLevel, PersonnelLevel.Division,
+ userId, divisionUnitId, "师部直接升级团级人才为师级");
+
+ _logger.LogInformation("人员 {PersonnelId} 已被师部 {UnitId} 直接升级为师级",
+ personnelId, divisionUnitId);
+
+ return personnel;
+ }
}
diff --git a/src/MilitaryTrainingManagement/Services/Interfaces/IPersonnelService.cs b/src/MilitaryTrainingManagement/Services/Interfaces/IPersonnelService.cs
index a21b71e..3fd5dab 100644
--- a/src/MilitaryTrainingManagement/Services/Interfaces/IPersonnelService.cs
+++ b/src/MilitaryTrainingManagement/Services/Interfaces/IPersonnelService.cs
@@ -85,6 +85,16 @@ public interface IPersonnelService
/// 审批向上申报请求
///
Task ApproveUpgradeAsync(int personnelId, int approvedByUnitId);
+
+ ///
+ /// 拒绝向上申报请求
+ ///
+ Task RejectUpgradeAsync(int personnelId, int rejectedByUnitId, string comments);
+
+ ///
+ /// 师部直接升级团级人才为师级
+ ///
+ Task DirectUpgradeAsync(int personnelId, int divisionUnitId);
}
///
diff --git a/src/frontend/src/api/personnel.ts b/src/frontend/src/api/personnel.ts
index c290713..11e8f59 100644
--- a/src/frontend/src/api/personnel.ts
+++ b/src/frontend/src/api/personnel.ts
@@ -67,5 +67,19 @@ export const personnelApi = {
async approveUpgrade(personnelId: number): Promise {
const response = await apiClient.post(`/personnel/${personnelId}/approve-upgrade`)
return response.data
+ },
+
+ // 拒绝向上申报请求
+ async rejectUpgrade(personnelId: number, comments: string): Promise {
+ const response = await apiClient.post(`/personnel/${personnelId}/reject-upgrade`, {
+ comments
+ })
+ return response.data
+ },
+
+ // 师部直接升级团级人才为师级
+ async directUpgrade(personnelId: number): Promise {
+ const response = await apiClient.post(`/personnel/${personnelId}/direct-upgrade`)
+ return response.data
}
}
diff --git a/src/frontend/src/views/personnel/PersonnelList.vue b/src/frontend/src/views/personnel/PersonnelList.vue
index 6d00575..5706a0c 100644
--- a/src/frontend/src/views/personnel/PersonnelList.vue
+++ b/src/frontend/src/views/personnel/PersonnelList.vue
@@ -65,10 +65,10 @@
-
+
{{ canApproveUpgrade(row) ? '待审批' : '待上级审批' }}
-
+
{{ getDisplayStatus(row) }}
@@ -104,6 +104,11 @@
+
+
+
+
+
@@ -114,7 +119,7 @@
-
+
@@ -161,6 +166,36 @@
+
+
+
+
+
+ {{ selectedPerson?.name }}
+ {{ selectedPerson?.position }}
+ {{ upgradeInfo.currentLevel }}
+ {{ upgradeInfo.newLevel }}
+
+
+
+
+
+
+
+ 取消
+
+ 拒绝
+
+
+ 批准
+
+
+
@@ -182,8 +217,11 @@ const loading = ref(false)
const statusFilter = ref('')
const searchKeyword = ref('')
const showApprovalDialog = ref(false)
+const showUpgradeApprovalDialog = ref(false)
const approving = ref(false)
+const approvingUpgrade = ref(false)
const selectedPerson = ref(null)
+const upgradeInfo = ref<{ currentLevel: string; newLevel: string }>({ currentLevel: '', newLevel: '' })
const pagination = reactive({
pageNumber: 1,
@@ -196,6 +234,10 @@ const approvalForm = reactive({
level: 'Company'
})
+const upgradeApprovalForm = reactive({
+ comments: ''
+})
+
function getStatusName(status: PersonnelStatus): string {
switch (status) {
case PersonnelStatus.Pending: return '待审批'
@@ -218,6 +260,19 @@ function getDisplayStatus(person: Personnel): string {
return getStatusName(person.status)
}
+// 根据当前用户判断显示的状态标签类型
+function getDisplayStatusType(person: Personnel): string {
+ if (person.status === PersonnelStatus.Pending) {
+ // 待审批状态:判断当前用户是否能审批
+ if (canApprovePersonnel(person)) {
+ return 'warning' // 待审批 - 黄色
+ } else {
+ return 'primary' // 待上级审批 - 蓝色
+ }
+ }
+ return getStatusTagType(person.status)
+}
+
function getStatusTagType(status: PersonnelStatus): string {
switch (status) {
case PersonnelStatus.Pending: return 'warning'
@@ -296,20 +351,27 @@ function canUpgrade(person: Personnel): boolean {
// 2. 不是师级人才(师级不能再向上)
// 3. 没有待处理的向上申报请求
// 4. 当前用户是审批单位(可以发起向上申报)
- // 或者:师部可以直接升级团级人才
+ // 注意:师部对团级人才使用"直接升级",不显示"向上申报"
if (!authStore.user || !person.approvedLevel || !person.approvedByUnitId) return false
if (person.approvedLevel === PersonnelLevel.Division) return false
if (person.pendingUpgradeByUnitId) return false // 已有待处理的向上申报
- // 当前用户单位是审批单位,可以发起向上申报
- if (person.approvedByUnitId === authStore.user.organizationalUnitId) return true
-
- // 特殊情况:师部可以直接升级团级人才为师级
+ // 师部对团级人才使用直接升级,不显示向上申报
if (authStore.organizationalLevelNum === 1 && person.approvedLevel === PersonnelLevel.Regiment) {
- return true
+ return false
}
- return false
+ // 当前用户单位是审批单位,可以发起向上申报
+ return person.approvedByUnitId === authStore.user.organizationalUnitId
+}
+
+// 判断是否可以直接升级(师部直接升级团级人才为师级)
+function canDirectUpgrade(person: Personnel): boolean {
+ if (!authStore.user || !person.approvedLevel) return false
+ if (person.pendingUpgradeByUnitId) return false // 已有待处理的向上申报
+
+ // 只有师部可以直接升级团级人才为师级
+ return authStore.organizationalLevelNum === 1 && person.approvedLevel === PersonnelLevel.Regiment
}
// 判断是否可以审批向上申报请求
@@ -349,6 +411,32 @@ function canApprovePersonnel(person: Personnel): boolean {
return true
}
+// 判断是否可以删除该人员
+function canDelete(person: Personnel): boolean {
+ if (!authStore.user) return false
+
+ const userLevelNum = authStore.organizationalLevelNum
+
+ // 待审批状态:提交单位或上级单位可以删除
+ if (person.status === PersonnelStatus.Pending) {
+ return true
+ }
+
+ // 已批准状态:用户层级必须高于或等于人员等级才能删除
+ if (person.status === PersonnelStatus.Approved && person.approvedLevel) {
+ const personnelLevelNum = {
+ 'Division': 1,
+ 'Regiment': 2,
+ 'Battalion': 3,
+ 'Company': 4
+ }[person.approvedLevel] || 4
+
+ return userLevelNum <= personnelLevelNum
+ }
+
+ return false
+}
+
function handleApprove(person: Personnel) {
selectedPerson.value = person
approvalForm.comments = ''
@@ -380,35 +468,71 @@ async function handleRequestUpgrade(person: Personnel) {
}
}
-// 审批向上申报请求
-async function handleApproveUpgrade(person: Personnel) {
+// 师部直接升级团级人才为师级
+async function handleDirectUpgrade(person: Personnel) {
try {
- const currentLevel = getLevelName(person.approvedLevel!)
- // 计算升级后的等级
- const levelOrder = ['Company', 'Battalion', 'Regiment', 'Division']
- const currentIndex = levelOrder.indexOf(person.approvedLevel || 'Company')
- const newLevel = currentIndex < levelOrder.length - 1 ? getLevelName(levelOrder[currentIndex + 1] as PersonnelLevel) : currentLevel
-
await ElMessageBox.confirm(
- `确定要批准 "${person.name}" 的向上申报请求吗?\n批准后,该人才将从${currentLevel}升级为${newLevel}。`,
- '确认审批向上申报',
+ `确定要将 "${person.name}"(团级人才)直接升级为师级人才吗?`,
+ '确认直接升级',
{
type: 'warning',
- confirmButtonText: '批准',
+ confirmButtonText: '确认升级',
cancelButtonText: '取消'
}
)
- await personnelApi.approveUpgrade(person.id)
- ElMessage.success('向上申报已批准,人才等级已升级')
+ await personnelApi.directUpgrade(person.id)
+ ElMessage.success('已成功升级为师级人才')
await loadPersonnel()
} catch (error: any) {
if (error !== 'cancel') {
- ElMessage.error(error.response?.data?.message || '审批失败')
+ ElMessage.error(error.response?.data?.message || '升级失败')
}
}
}
+// 审批向上申报请求
+async function handleApproveUpgrade(person: Personnel) {
+ const currentLevel = getLevelName(person.approvedLevel!)
+ // 计算升级后的等级
+ const levelOrder = ['Company', 'Battalion', 'Regiment', 'Division']
+ const currentIndex = levelOrder.indexOf(person.approvedLevel || 'Company')
+ const newLevel = currentIndex < levelOrder.length - 1 ? getLevelName(levelOrder[currentIndex + 1] as PersonnelLevel) : currentLevel
+
+ selectedPerson.value = person
+ upgradeInfo.value = { currentLevel, newLevel }
+ upgradeApprovalForm.comments = ''
+ showUpgradeApprovalDialog.value = true
+}
+
+// 提交向上申报审批
+async function submitUpgradeApproval(approved: boolean) {
+ if (!selectedPerson.value) return
+
+ // 拒绝时必须填写原因
+ if (!approved && !upgradeApprovalForm.comments.trim()) {
+ ElMessage.warning('请填写拒绝原因')
+ return
+ }
+
+ approvingUpgrade.value = true
+ try {
+ if (approved) {
+ await personnelApi.approveUpgrade(selectedPerson.value.id)
+ ElMessage.success('向上申报已批准,人才等级已升级')
+ } else {
+ await personnelApi.rejectUpgrade(selectedPerson.value.id, upgradeApprovalForm.comments)
+ ElMessage.success('向上申报已拒绝')
+ }
+ showUpgradeApprovalDialog.value = false
+ await loadPersonnel()
+ } catch (error: any) {
+ ElMessage.error(error.response?.data?.message || '审批失败')
+ } finally {
+ approvingUpgrade.value = false
+ }
+}
+
async function submitApproval(approved: boolean) {
if (!selectedPerson.value) return