人才上报.
This commit is contained in:
parent
70b0c938ab
commit
2495d39e9e
|
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝向上申报请求
|
||||
/// </summary>
|
||||
[HttpPost("{id}/reject-upgrade")]
|
||||
[Authorize(Policy = "BattalionLevel")] // 营级及以上权限
|
||||
public async Task<IActionResult> 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 });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 师部直接升级团级人才为师级
|
||||
/// </summary>
|
||||
[HttpPost("{id}/direct-upgrade")]
|
||||
[Authorize(Policy = "DivisionLevel")] // 师级权限
|
||||
public async Task<IActionResult> 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 });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,16 @@ public class RejectPersonnelRequest
|
|||
public string? Reason { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝向上申报请求DTO
|
||||
/// </summary>
|
||||
public class RejectUpgradeRequest
|
||||
{
|
||||
[Required(ErrorMessage = "拒绝原因不能为空")]
|
||||
[StringLength(500, ErrorMessage = "拒绝原因长度不能超过500个字符")]
|
||||
public string Comments { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 人员响应DTO
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -778,4 +778,91 @@ public class PersonnelService : IPersonnelService
|
|||
|
||||
return personnel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝向上申报请求
|
||||
/// </summary>
|
||||
public async Task<Personnel> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 师部直接升级团级人才为师级
|
||||
/// </summary>
|
||||
public async Task<Personnel> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ public interface IPersonnelService
|
|||
/// 审批向上申报请求
|
||||
/// </summary>
|
||||
Task<Personnel> ApproveUpgradeAsync(int personnelId, int approvedByUnitId);
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝向上申报请求
|
||||
/// </summary>
|
||||
Task<Personnel> RejectUpgradeAsync(int personnelId, int rejectedByUnitId, string comments);
|
||||
|
||||
/// <summary>
|
||||
/// 师部直接升级团级人才为师级
|
||||
/// </summary>
|
||||
Task<Personnel> DirectUpgradeAsync(int personnelId, int divisionUnitId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -67,5 +67,19 @@ export const personnelApi = {
|
|||
async approveUpgrade(personnelId: number): Promise<Personnel> {
|
||||
const response = await apiClient.post<Personnel>(`/personnel/${personnelId}/approve-upgrade`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 拒绝向上申报请求
|
||||
async rejectUpgrade(personnelId: number, comments: string): Promise<Personnel> {
|
||||
const response = await apiClient.post<Personnel>(`/personnel/${personnelId}/reject-upgrade`, {
|
||||
comments
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 师部直接升级团级人才为师级
|
||||
async directUpgrade(personnelId: number): Promise<Personnel> {
|
||||
const response = await apiClient.post<Personnel>(`/personnel/${personnelId}/direct-upgrade`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,10 +65,10 @@
|
|||
<el-table-column prop="submittedByUnitName" label="所属单位" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="status" label="状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.pendingUpgradeByUnitId" type="primary" effect="dark" size="small">
|
||||
<el-tag v-if="row.pendingUpgradeByUnitId" :type="canApproveUpgrade(row) ? 'warning' : 'primary'" effect="dark" size="small">
|
||||
{{ canApproveUpgrade(row) ? '待审批' : '待上级审批' }}
|
||||
</el-tag>
|
||||
<el-tag v-else :type="getStatusTagType(row.status)" effect="dark" size="small">
|
||||
<el-tag v-else :type="getDisplayStatusType(row)" effect="dark" size="small">
|
||||
{{ getDisplayStatus(row) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
|
|
@ -104,6 +104,11 @@
|
|||
<el-icon><Top /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="row.status === 'Approved' && authStore.canApprove && canDirectUpgrade(row)" content="直接升级" placement="top">
|
||||
<el-button type="success" link size="small" @click="handleDirectUpgrade(row)">
|
||||
<el-icon><Top /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="row.status === 'Approved' && row.pendingUpgradeByUnitId && authStore.canApprove && canApproveUpgrade(row)" content="审批向上申报" placement="top">
|
||||
<el-button type="success" link size="small" @click="handleApproveUpgrade(row)">
|
||||
<el-icon><Check /></el-icon>
|
||||
|
|
@ -114,7 +119,7 @@
|
|||
<el-icon><Edit /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="row.status === 'Pending'" content="删除" placement="top">
|
||||
<el-tooltip v-if="canDelete(row)" content="删除" placement="top">
|
||||
<el-button type="danger" link size="small" @click="handleDelete(row)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
|
|
@ -161,6 +166,36 @@
|
|||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Upgrade Approval Dialog -->
|
||||
<el-dialog v-model="showUpgradeApprovalDialog" title="审批向上申报" width="500px" :close-on-click-modal="false">
|
||||
<el-form :model="upgradeApprovalForm" label-width="100px">
|
||||
<el-descriptions :column="2" border class="approval-info">
|
||||
<el-descriptions-item label="姓名">{{ selectedPerson?.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="职位">{{ selectedPerson?.position }}</el-descriptions-item>
|
||||
<el-descriptions-item label="当前等级">{{ upgradeInfo.currentLevel }}</el-descriptions-item>
|
||||
<el-descriptions-item label="升级后等级">{{ upgradeInfo.newLevel }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin: 16px 0"
|
||||
:title="`批准后,该人才将从${upgradeInfo.currentLevel}升级为${upgradeInfo.newLevel}`"
|
||||
/>
|
||||
<el-form-item label="审批意见" style="margin-top: 20px">
|
||||
<el-input v-model="upgradeApprovalForm.comments" type="textarea" rows="3" placeholder="请输入审批意见(拒绝时必填)" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="showUpgradeApprovalDialog = false">取消</el-button>
|
||||
<el-button type="danger" :loading="approvingUpgrade" @click="submitUpgradeApproval(false)">
|
||||
<el-icon><Close /></el-icon> 拒绝
|
||||
</el-button>
|
||||
<el-button type="success" :loading="approvingUpgrade" @click="submitUpgradeApproval(true)">
|
||||
<el-icon><Check /></el-icon> 批准
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -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<Personnel | null>(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,32 +468,68 @@ async function handleRequestUpgrade(person: Personnel) {
|
|||
}
|
||||
}
|
||||
|
||||
// 师部直接升级团级人才为师级
|
||||
async function handleDirectUpgrade(person: Personnel) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要将 "${person.name}"(团级人才)直接升级为师级人才吗?`,
|
||||
'确认直接升级',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '确认升级',
|
||||
cancelButtonText: '取消'
|
||||
}
|
||||
)
|
||||
|
||||
await personnelApi.directUpgrade(person.id)
|
||||
ElMessage.success('已成功升级为师级人才')
|
||||
await loadPersonnel()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.response?.data?.message || '升级失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 审批向上申报请求
|
||||
async function handleApproveUpgrade(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}。`,
|
||||
'确认审批向上申报',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '批准',
|
||||
cancelButtonText: '取消'
|
||||
selectedPerson.value = person
|
||||
upgradeInfo.value = { currentLevel, newLevel }
|
||||
upgradeApprovalForm.comments = ''
|
||||
showUpgradeApprovalDialog.value = true
|
||||
}
|
||||
)
|
||||
|
||||
await personnelApi.approveUpgrade(person.id)
|
||||
// 提交向上申报审批
|
||||
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) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.response?.data?.message || '审批失败')
|
||||
}
|
||||
} finally {
|
||||
approvingUpgrade.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user