feat: 支持接单部门负责人编辑可接任务明细

This commit is contained in:
Your Name 2026-02-27 15:57:21 +08:00
parent 4697dec964
commit c63f08732f
2 changed files with 88 additions and 24 deletions

View File

@ -1775,16 +1775,18 @@ public class TaskService {
@Transactional(rollbackFor = Exception.class)
public void updateTask(Long id, Task task, Long userId) {
Task existTask = getTaskById(id);
String status = existTask.getStatus();
boolean receivingDeptLeader = isReceivingDeptLeader(userId);
boolean leaderCanEditPending = receivingDeptLeader && "pending".equals(status);
// 验证权限:只有任务发布人才能更新任务
// 验证权限:任务发布人、管理员,或接单部门负责人(仅待接单任务)可以更新任务
boolean isAdmin = isAdminUser(userId);
if (!isAdmin && !userId.equals(existTask.getPublisherId())) {
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人可以更新任务");
if (!isAdmin && !userId.equals(existTask.getPublisherId()) && !leaderCanEditPending) {
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人或接单部门负责人(待接单任务)可以更新任务");
}
// 允许更新的任务状态:草稿、待审核(需求/接单部门审核)、被驳回
// 不允许更新的状态:进行中(in_progress)、已完成(completed)、已取消(cancelled)
String status = existTask.getStatus();
String approvalStatus = existTask.getApprovalStatus();
boolean canUpdate = "draft".equals(status) ||
@ -1818,8 +1820,11 @@ public class TaskService {
@Transactional(rollbackFor = Exception.class)
public void updatePipelineTask(Long id, com.designhub.dto.PipelineTaskDTO dto, Long userId) {
Task existTask = getTaskById(id);
String status = existTask.getStatus();
boolean receivingDeptLeader = isReceivingDeptLeader(userId);
boolean leaderCanEditPending = receivingDeptLeader && "pending".equals(status);
// 验证权限:任务发布人、一级需求任务的明细完善人可以更新任务
// 验证权限:任务发布人、一级需求任务的明细完善人、接单部门负责人(待接单任务)可以更新任务
boolean isAdmin = isAdminUser(userId);
// 对于一级需求任务,明细完善人在任何可编辑状态下都可以更新(包括草稿状态)
boolean isPrimaryTaskDetailCompleter = existTask.getIsPrimaryTask() != null
@ -1842,8 +1847,9 @@ public class TaskService {
}
}
if (!isAdmin && !userId.equals(existTask.getPublisherId()) && !isPrimaryTaskDetailCompleter && !isDemandDeptMemberForPrimaryTask) {
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人或指定的明细完善人可以更新任务");
if (!isAdmin && !userId.equals(existTask.getPublisherId()) && !isPrimaryTaskDetailCompleter
&& !isDemandDeptMemberForPrimaryTask && !leaderCanEditPending) {
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人、指定的明细完善人或接单部门负责人(待接单任务)可以更新任务");
}
// 验证任务是否是流水线任务
@ -1859,7 +1865,6 @@ public class TaskService {
// 允许更新的任务状态:草稿、待审核(需求/接单部门审核)、被驳回、待完善明细
// 不允许更新的状态:进行中(in_progress)、已完成(completed)、已取消(cancelled)
String status = existTask.getStatus();
String approvalStatus = existTask.getApprovalStatus();
boolean canUpdate = "draft".equals(status) ||
@ -2790,6 +2795,26 @@ public class TaskService {
}
}
/**
* 检查用户是否是任一接单部门负责人
*/
private boolean isReceivingDeptLeader(Long userId) {
if (userId == null) {
return false;
}
try {
Long count = departmentMapper.selectCount(new LambdaQueryWrapper<Department>()
.eq(Department::getLeaderId, userId)
.eq(Department::getDeptType, "receiving")
.eq(Department::getStatus, 1)
.eq(Department::getDeleted, 0));
return count != null && count > 0;
} catch (Exception e) {
log.warn("检查接单部门负责人失败: userId={}, error={}", userId, e.getMessage());
return false;
}
}
private void validateAllowedDemandTypes(Department department, Long demandTypeId) {
if (department == null || !StringUtils.hasText(department.getAllowedDemandTypes()) || demandTypeId == null) {
return;

View File

@ -344,6 +344,14 @@
>
查看详情
</button>
<button
v-if="canEditAvailableTaskDetail(task)"
class="btn btn-secondary"
style="flex: 1"
@click.stop="handleEditAvailableTaskDetail(task)"
>
编辑明细
</button>
<button
:class="[
'btn',
@ -2342,22 +2350,30 @@
<!-- 根据任务状态显示不同的操作按钮 -->
<div class="detail-actions">
<!-- 可接任务:显示抢单 -->
<a-button
v-if="selectedTask.status === 'pending'"
:type="canGrabTask(selectedTask).canGrab ? 'primary' : 'default'"
:style="{
backgroundColor: canGrabTask(selectedTask).canGrab ? '#31f08b' : '#999',
borderColor: canGrabTask(selectedTask).canGrab ? '#31f08b' : '#999',
color: '#fff',
cursor: canGrabTask(selectedTask).canGrab ? 'pointer' : 'not-allowed',
opacity: canGrabTask(selectedTask).canGrab ? 1 : 0.6
}"
size="large"
block
:disabled="!canGrabTask(selectedTask).canGrab"
@click="handleGrabFromDetail">
{{ canGrabTask(selectedTask).canGrab ? '确认抢单' : `不可接单(${canGrabTask(selectedTask).reason})` }}
</a-button>
<div v-if="selectedTask.status === 'pending'" class="action-buttons">
<a-button
v-if="canEditAvailableTaskDetail(selectedTask)"
size="large"
@click="handleEditAvailableTaskDetail(selectedTask)"
>
编辑任务明细
</a-button>
<a-button
:type="canGrabTask(selectedTask).canGrab ? 'primary' : 'default'"
:style="{
backgroundColor: canGrabTask(selectedTask).canGrab ? '#31f08b' : '#999',
borderColor: canGrabTask(selectedTask).canGrab ? '#31f08b' : '#999',
color: '#fff',
cursor: canGrabTask(selectedTask).canGrab ? 'pointer' : 'not-allowed',
opacity: canGrabTask(selectedTask).canGrab ? 1 : 0.6
}"
size="large"
:block="!canEditAvailableTaskDetail(selectedTask)"
:disabled="!canGrabTask(selectedTask).canGrab"
@click="handleGrabFromDetail">
{{ canGrabTask(selectedTask).canGrab ? '确认抢单' : `不可接单(${canGrabTask(selectedTask).reason})` }}
</a-button>
</div>
<!-- 进行中任务:显示更新进度和完结 -->
<div v-else-if="selectedTask.status === 'in_progress'" class="action-buttons">
@ -3474,6 +3490,14 @@ const canViewAvailableTaskAttachmentInfo = computed(() => {
return false
})
// 可接任务:接单部门负责人可编辑待接单主任务明细
const canEditAvailableTaskDetail = (task: TaskOrSubTask | null | undefined) => {
if (!task) return false
if (task.status !== 'pending') return false
if (Number((task as any).isSubTask) === 1 || !!task.itemId) return false
return canViewAvailableTaskAttachmentInfo.value
}
// 加载配置数据(从全局store加载)
const loadConfigs = async () => {
try {
@ -5702,6 +5726,21 @@ const handleEditRejectedTask = (task: Task) => {
})
}
const handleEditAvailableTaskDetail = (task: TaskOrSubTask) => {
if (!task?.id) {
message.error('任务ID不存在,无法编辑')
return
}
detailDrawerVisible.value = false
router.push({
path: '/tasks/create',
query: {
editId: task.id,
mode: 'edit'
}
})
}
const handleCompleteTask = (task: TaskOrSubTask) => {
const isSubTask = task.isSubTask
const taskType = isSubTask ? '子任务' : '任务'