diff --git a/backend/src/main/java/com/designhub/dto/PipelineTaskDTO.java b/backend/src/main/java/com/designhub/dto/PipelineTaskDTO.java index 9b41de8..b9a445a 100644 --- a/backend/src/main/java/com/designhub/dto/PipelineTaskDTO.java +++ b/backend/src/main/java/com/designhub/dto/PipelineTaskDTO.java @@ -48,6 +48,7 @@ public class PipelineTaskDTO { private Long receiverId; // 指定接收人ID(assigned模式使用) private List productBarcodes; // 商品条码列表(已验证库存) private String previewImage; // 预览图URL + private Boolean asDraft; // 是否保存为草稿(不触发审核流程) /** * 子任务项DTO diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index 063347d..f7f05c3 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -360,11 +360,21 @@ public class TaskService { } } - // 【两级审核流程】初始化审核状态 - initApprovalStatus(task); + // 🔥 是否保存为草稿(不触发审核流程) + boolean asDraft = dto.getAsDraft() != null && dto.getAsDraft(); + + if (asDraft) { + // 草稿模式:保持草稿状态,不初始化审核流程 + task.setStatus("draft"); + task.setApprovalStatus("draft"); + log.info("保存为草稿模式,不触发审核流程"); + } else { + // 【两级审核流程】初始化审核状态 + initApprovalStatus(task); + } taskMapper.insert(task); - log.info("主任务创建成功,ID: {}, 任务编号: {}", task.getId(), task.getTaskNo()); + log.info("主任务创建成功,ID: {}, 任务编号: {}, 草稿模式: {}", task.getId(), task.getTaskNo(), asDraft); // **步骤1:按接单部门和设计师自动分组** // 遍历任务类型列表,根据接单部门和设计师分组 @@ -643,8 +653,10 @@ public class TaskService { log.info("流水线任务创建完成,主任务ID: {}, 子任务数: {}, 部门数: {}", task.getId(), groupedItems.size(), deptToGroups.size()); - // 【两级审核流程】发送审核通知给部门负责人 - sendApprovalNotification(task); + // 【两级审核流程】发送审核通知给部门负责人(草稿模式不发送) + if (!asDraft) { + sendApprovalNotification(task); + } return task.getId(); } diff --git a/frontend/src/views/CreateTask.vue b/frontend/src/views/CreateTask.vue index 4f78b2b..f8b2abd 100644 --- a/frontend/src/views/CreateTask.vue +++ b/frontend/src/views/CreateTask.vue @@ -539,6 +539,14 @@ 取消 + + + 保存草稿 + () // 提交状态 const submitting = ref(false) +const savingDraft = ref(false) const loading = ref(false) // 团队积分余额 @@ -1365,6 +1374,92 @@ const handleCancel = () => { router.back() } +// 保存草稿 +const handleSaveDraft = async () => { + savingDraft.value = true + + try { + // 基本验证:至少需要标题 + if (!formData.title || formData.title.trim() === '') { + message.warning('请至少填写任务标题') + savingDraft.value = false + return + } + + // 构建附件URL(如果有上传的文件) + const attachmentUrls = fileList.value + .filter(file => { + return file.status === 'done' && ( + file.response?.fileUrl || + file.response?.data?.[0] || + file.url + ) + }) + .map(file => { + return file.response?.fileUrl || + file.response?.data?.[0] || + file.url || + '' + }) + .filter(url => url) + + const attachmentUrl = attachmentUrls.length > 0 ? attachmentUrls.join(',') : formData.attachmentUrl + + // 获取有效的任务类型(允许部分填写) + const validTaskTypes = formData.taskTypes.filter(item => item.taskTypeId) + + // 构建草稿数据 + const draftData = { + title: formData.title, + isPipeline: true, + pipelineMode: 'sequential', + items: validTaskTypes.map((item, index) => ({ + taskTypeId: item.taskTypeId!, + quantity: item.quantity || 1, + sortOrder: index + 1, + selectedDesignerId: item.selectedDesignerId || undefined, + selectedDeptId: item.selectedDeptId || undefined + })), + brandId: formData.brandId || undefined, + categoryId: formData.categoryId || undefined, + platformId: formData.platformId || undefined, + spuInfo: formData.spuInfo || undefined, + taskSubType: formData.taskSubType || undefined, + attachmentUrl: attachmentUrl || undefined, + previewImage: formData.previewImage || undefined, + releaseType: formData.releaseType || 'recruitment', + asDraft: true // 标记为草稿 + } + + let response + if (editMode.value && taskId.value) { + // 编辑模式:更新草稿 + response = await taskApi.updateTask(taskId.value, { ...draftData, status: 'draft' }) + } else { + // 新建模式:创建草稿 + response = await taskApi.createPipelineTask(draftData) + } + + if (response.code === 200) { + message.success('草稿保存成功') + // 如果是新建,更新为编辑模式 + if (!editMode.value && response.data?.id) { + router.replace({ + path: '/tasks/create', + query: { taskId: response.data.id, mode: 'edit' } + }) + } + } else { + message.error(response.msg || '保存草稿失败') + } + } catch (error: any) { + console.error('保存草稿失败:', error) + message.error(error.msg || error.message || '保存草稿失败') + } finally { + savingDraft.value = false + } +} + // 提交 const handleSubmit = async () => { if (!formRef.value) return