feat: 需求部门我发起的任务列表增加撤回编辑功能,撤回时同步返还部门积分
This commit is contained in:
parent
681e22fec3
commit
f72a06ed22
@ -476,6 +476,24 @@ public class TaskController {
|
||||
return Result.success("任务已驳回");
|
||||
}
|
||||
|
||||
@Operation(summary = "撤回任务", description = "发起人撤回未被抢单的任务进行编辑,撤回后任务变为草稿状态")
|
||||
@PostMapping("/{id}/withdraw")
|
||||
public Result<String> withdrawTask(
|
||||
@PathVariable Long id,
|
||||
@RequestHeader("Authorization") String authHeader) {
|
||||
|
||||
log.info("撤回任务: taskId={}", id);
|
||||
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
||||
Long userId = jwtUtil.getUserIdFromToken(token);
|
||||
|
||||
try {
|
||||
taskService.withdrawTask(id, userId);
|
||||
return Result.success("任务已撤回,可以进行编辑");
|
||||
} catch (RuntimeException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "根据任务编号删除任务", description = "管理员根据任务编号删除任务及其所有子任务(仅管理员可用)")
|
||||
@DeleteMapping("/by-task-no/{taskNo}")
|
||||
public Result<String> deleteTaskByTaskNo(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.designhub.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.designhub.common.ResultCode;
|
||||
@ -2134,6 +2135,93 @@ public class TaskService {
|
||||
log.info("任务 {} 评分成功: {} 星", taskId, rating);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回任务(用于编辑后重新发布)
|
||||
* 只有任务发起人可以撤回,且任务必须未被抢单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void withdrawTask(Long taskId, Long userId) {
|
||||
log.info("用户 {} 撤回任务 {} 进行编辑", userId, taskId);
|
||||
|
||||
Task task = getTaskById(taskId);
|
||||
|
||||
// 验证权限(必须是任务发布人)
|
||||
if (!userId.equals(task.getPublisherId())) {
|
||||
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人可以撤回任务");
|
||||
}
|
||||
|
||||
// 验证任务状态
|
||||
// 可以撤回的状态:pending(待接单)、pending_demand_approval(待需求部门审核)、pending_receiving_approval(待接单部门审核)
|
||||
String status = task.getStatus();
|
||||
String approvalStatus = task.getApprovalStatus();
|
||||
|
||||
boolean canWithdraw = false;
|
||||
boolean needRefundScore = false; // 是否需要返还积分
|
||||
|
||||
// 待接单状态可以撤回(已审核通过,需要返还积分)
|
||||
if ("pending".equals(status)) {
|
||||
canWithdraw = true;
|
||||
needRefundScore = true; // pending状态说明已审核通过,积分已扣除,需要返还
|
||||
}
|
||||
|
||||
// 待审核状态也可以撤回(未审核通过,不需要返还积分)
|
||||
if (approvalStatus != null && (approvalStatus.contains("pending"))) {
|
||||
canWithdraw = true;
|
||||
// 待审核状态积分还未扣除,不需要返还
|
||||
}
|
||||
|
||||
if (!canWithdraw) {
|
||||
throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "只有待接单或待审核的任务可以撤回");
|
||||
}
|
||||
|
||||
// 检查任务是否已被抢单(receiverId 不为空说明已被抢单)
|
||||
if (task.getReceiverId() != null) {
|
||||
throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "任务已被接单,无法撤回");
|
||||
}
|
||||
|
||||
// 检查流水线任务的子任务是否有被抢单的
|
||||
if (task.getIsPipeline() != null && task.getIsPipeline() == 1) {
|
||||
List<TaskItem> items = taskItemMapper.selectList(
|
||||
new LambdaQueryWrapper<TaskItem>()
|
||||
.eq(TaskItem::getTaskId, taskId)
|
||||
.isNotNull(TaskItem::getReceiverId)
|
||||
);
|
||||
if (!items.isEmpty()) {
|
||||
throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "部分子任务已被接单,无法撤回");
|
||||
}
|
||||
}
|
||||
|
||||
// 返还积分(只有pending状态的任务需要返还,因为审核通过后才会扣除积分)
|
||||
if (needRefundScore && task.getPublisherDeptId() != null && task.getScore() != null) {
|
||||
int scoreToRefund = task.getScore().intValue();
|
||||
teamScorePoolService.addScore(task.getPublisherDeptId(), scoreToRefund);
|
||||
log.info("任务撤回,返还部门积分: taskId={}, deptId={}, score={}",
|
||||
taskId, task.getPublisherDeptId(), scoreToRefund);
|
||||
}
|
||||
|
||||
// 更新任务状态为草稿
|
||||
task.setStatus("draft");
|
||||
task.setApprovalStatus(null); // 清除审批状态
|
||||
task.setCurrentApproverId(null);
|
||||
task.setCurrentApproverRole(null);
|
||||
task.setAuditStatus("draft"); // 重置审核状态
|
||||
task.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
taskMapper.updateById(task);
|
||||
|
||||
// 如果是流水线任务,也需要重置子任务状态
|
||||
if (task.getIsPipeline() != null && task.getIsPipeline() == 1) {
|
||||
taskItemMapper.update(null,
|
||||
new LambdaUpdateWrapper<TaskItem>()
|
||||
.eq(TaskItem::getTaskId, taskId)
|
||||
.set(TaskItem::getStatus, "pending")
|
||||
.set(TaskItem::getUpdateTime, LocalDateTime.now())
|
||||
);
|
||||
}
|
||||
|
||||
log.info("任务 {} 已撤回为草稿状态,可以进行编辑", taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消任务
|
||||
*/
|
||||
|
||||
@ -671,6 +671,16 @@ export const confirmTaskProductFilled = (taskId: number) => {
|
||||
}
|
||||
|
||||
|
||||
// ==================== 任务撤回 ====================
|
||||
|
||||
/**
|
||||
* 撤回任务(用于编辑后重新发布)
|
||||
* 只有任务发起人可以撤回,且任务必须未被抢单
|
||||
*/
|
||||
export const withdrawTask = (taskId: number) => {
|
||||
return request.post<any>(`/tasks/${taskId}/withdraw`)
|
||||
}
|
||||
|
||||
// ==================== 管理员任务管理 ====================
|
||||
|
||||
/**
|
||||
|
||||
@ -1452,6 +1452,19 @@
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 撤回编辑按钮(待接单或待审核且未被抢单的任务) -->
|
||||
<div v-if="canWithdrawTask(task)" class="task-actions" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid rgba(49, 240, 139, 0.2);">
|
||||
<a-button
|
||||
type="default"
|
||||
size="small"
|
||||
@click.stop="handleWithdrawTask(task)"
|
||||
:loading="withdrawingTaskId === task.id"
|
||||
style="width: 100%;">
|
||||
<Icon name="rotate-ccw" size="sm" style="margin-right: 4px;" />
|
||||
撤回编辑
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 被驳回或草稿任务的操作按钮 -->
|
||||
<div v-if="['rejected', 'draft'].includes(task.status) || task.approvalStatus?.includes('rejected')" class="task-actions" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid rgba(49, 240, 139, 0.2);">
|
||||
<a-button
|
||||
@ -2284,6 +2297,7 @@ const userDeptId = ref<number | null>(null)
|
||||
const userDeptName = ref<string>('')
|
||||
const userDeptType = ref<string>('')
|
||||
const exportLoading = ref(false) // 导出加载状态
|
||||
const withdrawingTaskId = ref<number | null>(null) // 正在撤回的任务ID
|
||||
|
||||
// 获取当前有效的部门类型(根据选择的视角)
|
||||
const effectiveDeptType = computed(() => {
|
||||
@ -5033,6 +5047,77 @@ const handleDownloadPrevAssets = (task: TaskOrSubTask) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断任务是否可以撤回
|
||||
const canWithdrawTask = (task: Task) => {
|
||||
// 已被驳回或草稿状态的任务不显示撤回按钮(它们有自己的编辑按钮)
|
||||
if (['rejected', 'draft'].includes(task.status) || task.approvalStatus?.includes('rejected')) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 已完成、已取消的任务不能撤回
|
||||
if (['completed', 'cancelled'].includes(task.status)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 已被抢单的任务不能撤回(receiverId 不为空)
|
||||
if (task.receiverId) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 进行中的任务不能撤回
|
||||
if (task.status === 'in_progress') {
|
||||
return false
|
||||
}
|
||||
|
||||
// 待接单或待审核的任务可以撤回
|
||||
if (task.status === 'pending') {
|
||||
return true
|
||||
}
|
||||
|
||||
// 审批状态中包含 pending 的可以撤回
|
||||
if (task.approvalStatus?.includes('pending')) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 撤回任务
|
||||
const handleWithdrawTask = async (task: Task) => {
|
||||
if (!task.id) return
|
||||
|
||||
Modal.confirm({
|
||||
title: '撤回任务',
|
||||
content: h('div', [
|
||||
h('p', `确认撤回任务【${task.title}】?`),
|
||||
h('p', { style: 'color: #999; font-size: 13px; margin-top: 8px;' }, '撤回后任务将变为草稿状态,您可以进行编辑后重新发布。')
|
||||
]),
|
||||
okText: '确认撤回',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
try {
|
||||
withdrawingTaskId.value = task.id!
|
||||
await taskApi.withdrawTask(task.id!)
|
||||
message.success('任务已撤回,正在跳转到编辑页面...')
|
||||
|
||||
// 撤回成功后跳转到编辑页面
|
||||
router.push({
|
||||
path: '/tasks/create',
|
||||
query: {
|
||||
editId: task.id,
|
||||
mode: 'edit'
|
||||
}
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.error('撤回任务失败:', error)
|
||||
message.error(error.response?.data?.message || error.message || '撤回任务失败')
|
||||
} finally {
|
||||
withdrawingTaskId.value = null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleEditRejectedTask = (task: Task) => {
|
||||
// 跳转到创建任务页面,并传入任务ID作为编辑标识
|
||||
router.push({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user