fix: 修复多个问题

1. 修复部门负责人看不到任务关联信息(品牌、类目、平台)
   - TaskService.getTaskById增加fillTaskRelatedInfo方法填充所有关联信息

2. 修复调整任务类型数量时积分同步显示
   - 审核弹窗添加预估积分实时计算和显示

3. 修复流水线任务拆分后母任务不再显示在任务大厅
   - TaskMapper添加is_pipeline=0条件

4. 修复驳回任务显示'草稿'问题
   - 驳回时保存rejectReason到数据库
   - 前端正确判断并显示'已驳回'状态

5. 修复重新编辑被驳回任务时数据丢失问题
   - loadTaskForEdit完善所有字段加载
   - 显示驳回原因提示用户修改
   - 添加remark字段到formData

6. 修复进行中任务卡片缺少'指定'标签显示
This commit is contained in:
Your Name 2026-01-05 11:21:16 +08:00
parent 3ba4a5f7f7
commit 571388f414
5 changed files with 143 additions and 12 deletions

View File

@ -36,7 +36,7 @@ public interface TaskMapper extends BaseMapper<Task> {
"LEFT JOIN category c ON t.category_id = c.id " +
"LEFT JOIN platform p ON t.platform_id = p.id " +
"LEFT JOIN sys_user approver ON t.current_approver_id = approver.id " +
"WHERE t.status = 'pending' AND t.release_type = 'recruitment' AND t.approval_status = 'approved' AND t.deleted = 0" +
"WHERE t.status = 'pending' AND t.release_type = 'recruitment' AND t.approval_status = 'approved' AND t.deleted = 0 AND (t.is_pipeline = 0 OR t.is_pipeline IS NULL)" +
"<if test='taskTypeId != null'> AND t.task_type_id = #{taskTypeId}</if>" +
"<if test='demandTypeId != null'> AND t.demand_type_id = #{demandTypeId}</if>" +
"<if test='brandId != null'> AND t.brand_id = #{brandId}</if>" +

View File

@ -170,6 +170,7 @@ public class TaskApprovalService {
task.setApprovalStatus("rejected_by_demand");
task.setStatus("draft");
task.setRejectReason(reason); // 保存驳回原因
task.setCurrentApproverId(null);
task.setCurrentApproverRole(null);
taskMapper.updateById(task);
@ -461,6 +462,7 @@ public class TaskApprovalService {
task.setApprovalStatus("rejected_by_receiving");
task.setStatus("draft");
task.setRejectReason(reason); // 保存驳回原因
task.setCurrentApproverId(demandDept.getLeaderId());
task.setCurrentApproverRole("demand_leader");
taskMapper.updateById(task);

View File

@ -12,6 +12,9 @@ import com.designhub.exception.BusinessException;
import com.designhub.mapper.TaskAuditLogMapper;
import com.designhub.mapper.TaskAssignLogMapper;
import com.designhub.mapper.TaskMapper;
import com.designhub.mapper.BrandMapper;
import com.designhub.mapper.CategoryMapper;
import com.designhub.mapper.PlatformMapper;
import com.designhub.vo.DashboardStatsVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -40,6 +43,9 @@ public class TaskService {
private final TaskMapper taskMapper;
private final TaskAuditLogMapper taskAuditLogMapper;
private final TaskAssignLogMapper taskAssignLogMapper;
private final BrandMapper brandMapper;
private final CategoryMapper categoryMapper;
private final PlatformMapper platformMapper;
private final TeamScorePoolService teamScorePoolService;
private final ConfigService configService;
private final DelayPenaltyService delayPenaltyService;
@ -723,8 +729,76 @@ public class TaskService {
if (task == null) {
throw new BusinessException(ResultCode.TASK_NOT_EXIST);
}
// 填充关联信息
fillTaskRelatedInfo(task);
return task;
}
/**
* 填充任务关联信息(品牌、类目、平台、发布人等)
*/
private void fillTaskRelatedInfo(Task task) {
// 填充品牌名称
if (task.getBrandId() != null) {
Brand brand = brandMapper.selectById(task.getBrandId());
if (brand != null) {
task.setBrandName(brand.getName());
}
}
// 填充类目名称
if (task.getCategoryId() != null) {
Category category = categoryMapper.selectById(task.getCategoryId());
if (category != null) {
task.setCategoryName(category.getName());
}
}
// 填充平台名称
if (task.getPlatformId() != null) {
Platform platform = platformMapper.selectById(task.getPlatformId());
if (platform != null) {
task.setPlatformName(platform.getName());
}
}
// 填充发布人名称
if (task.getPublisherId() != null) {
User publisher = userService.getUserById(task.getPublisherId());
if (publisher != null) {
task.setPublisherName(publisher.getRealName() != null ? publisher.getRealName() : publisher.getUsername());
}
}
// 填充发布人部门名称
if (task.getPublisherDeptId() != null) {
Department dept = departmentService.getDepartmentById(task.getPublisherDeptId());
if (dept != null) {
task.setPublisherDeptName(dept.getDeptName());
}
}
// 填充接收人名称
if (task.getReceiverId() != null) {
User receiver = userService.getUserById(task.getReceiverId());
if (receiver != null) {
task.setReceiverName(receiver.getRealName() != null ? receiver.getRealName() : receiver.getUsername());
}
}
// 填充当前审核人名称
if (task.getCurrentApproverId() != null) {
User approver = userService.getUserById(task.getCurrentApproverId());
if (approver != null) {
task.setCurrentApproverName(approver.getRealName() != null ? approver.getRealName() : approver.getUsername());
}
}
// 填充子任务统计信息
fillSubTaskStats(task);
}
/**
* 更新任务

View File

@ -467,6 +467,7 @@ const formData = reactive({
categoryId: undefined,
spuInfo: '',
attachmentUrl: '',
remark: '', // 备注信息
releaseType: 'default',
// receiverId: undefined, // 已移除,改用子任务指定
isUrgent: false
@ -796,7 +797,7 @@ const handleSubmit = async () => {
spuInfo: formData.spuInfo,
taskSubType: formData.taskSubType,
attachmentUrl: attachmentUrl,
remark: '',
remark: formData.remark || '',
priority: formData.isUrgent ? 3 : 1, // 0-低 1-普通 2-高 3-紧急
releaseType: formData.releaseType, // 发布类型
receiverId: undefined // 主任务不设接收人,由子任务指定
@ -1042,7 +1043,7 @@ const loadTaskForEdit = async (taskId: number) => {
const task = response.data
if (task) {
// 填充表单数据
// 填充基本表单数据
formData.title = task.title || ''
formData.taskSubType = task.taskSubType || ''
formData.brandId = task.brandId
@ -1051,32 +1052,50 @@ const loadTaskForEdit = async (taskId: number) => {
formData.spuInfo = task.spuInfo || ''
formData.remark = task.remark || ''
formData.releaseType = task.releaseType || 'recruitment'
formData.isUrgent = task.isUrgent === 1 || task.isUrgent === true
// 处理任务类型
// 处理任务类型和数量
if (task.taskTypeIds) {
const typeIds = task.taskTypeIds.split(',').map((id: string) => parseInt(id.trim()))
// 尝试获取每个类型对应的数量(如果有taskItems,从中获取)
formData.taskTypes = typeIds.map((typeId: number, index: number) => ({
taskTypeId: typeId,
quantity: index === 0 ? (task.quantity || 1) : 1,
receiverId: task.receiverId
}))
} else if (task.taskTypeId) {
// 兼容单任务类型
formData.taskTypes = [{
taskTypeId: task.taskTypeId,
quantity: task.quantity || 1,
receiverId: task.receiverId
}]
}
// 处理附件
// 处理附件 - 完整加载原有附件
if (task.attachmentUrl) {
formData.attachmentUrl = task.attachmentUrl
// 将附件URL转换为fileList格式
const urls = task.attachmentUrl.split(',').filter((u: string) => u.trim())
fileList.value = urls.map((url: string, index: number) => ({
uid: `existing-${index}`,
name: `附件${index + 1}`,
status: 'done',
url: url.trim()
}))
fileList.value = urls.map((url: string, index: number) => {
const fileName = url.split('/').pop() || `附件${index + 1}`
return {
uid: `existing-${index}`,
name: fileName,
status: 'done' as const,
url: url.trim()
}
})
}
editMode.value = true
editTaskId.value = taskId
// 显示驳回原因提示(如果是被驳回的任务)
if (task.rejectReason) {
message.warning(`驳回原因:${task.rejectReason},请修改后重新提交`)
}
console.log('任务数据加载成功:', task)
}
} catch (error) {

View File

@ -800,6 +800,10 @@
<Icon name="layers" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
子任务
</span>
<span v-if="task.releaseType === 'assigned'" class="badge badge-assigned">
<Icon name="target" size="sm" color="#1890ff" style="margin-right: 4px; vertical-align: middle;" />
指定
</span>
<span class="badge badge-in-progress">
<Icon name="clock" size="sm" color="#31f08b" style="margin-right: 4px; vertical-align: middle;" />
进行中
@ -1894,6 +1898,19 @@
</a-button>
</div>
</div>
<!-- 预估积分显示 -->
<div class="score-summary" style="margin-top: 16px; padding: 12px; background: linear-gradient(135deg, #1a3a2a 0%, #0d1f16 100%); border-radius: 8px; border: 1px solid #31f08b33;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span style="color: #888; font-size: 14px;">预估总积分</span>
<span style="color: #31f08b; font-size: 24px; font-weight: 600;">{{ approveEstimatedScore }} 分</span>
</div>
<div style="margin-top: 8px; font-size: 12px; color: #666;">
<span v-for="(item, index) in approveTaskTypes" :key="index" style="margin-right: 12px;">
{{ getTaskTypeName(item.typeId) }}: {{ getTaskTypeUnitScore(item.typeId) }} × {{ item.quantity }}
</span>
</div>
</div>
</div>
<!-- 接单方式 -->
@ -2389,6 +2406,20 @@ const getTaskTypeName = (typeId: number) => {
return type?.name || '未知类型'
}
// 获取任务类型单位积分
const getTaskTypeUnitScore = (typeId: number) => {
const type = demandTypes.value.find(t => t.id === typeId)
return type?.unitScore || 0
}
// 计算审核弹窗中的预估总积分
const approveEstimatedScore = computed(() => {
return approveTaskTypes.value.reduce((total, item) => {
const unitScore = getTaskTypeUnitScore(item.typeId)
return total + (unitScore * item.quantity)
}, 0)
})
// 格式化时间
const formatTime = (time: string | undefined) => {
if (!time) return '--'
@ -3888,10 +3919,15 @@ const handleConfigUpdate = async (event: CustomEvent) => {
// 获取任务状态文本(增强版,支持区分驳回和草稿)
const getTaskStatusText = (status: string, task?: any) => {
// 如果有task对象,检查approvalStatus来区分驳回和草稿
if (task && status === 'draft') {
if (task) {
// 检查是否被驳回(无论status是draft还是rejected)
if (task.approvalStatus === 'rejected_by_demand' || task.approvalStatus === 'rejected_by_receiving') {
return '已驳回'
}
// 检查status是否是rejected
if (status === 'rejected') {
return '已驳回'
}
}
const statusMap: Record<string, string> = {