feat: 任务卡片增加任务类型明细显示
This commit is contained in:
parent
638d8e2451
commit
4838e17262
@ -41,6 +41,11 @@ public class TaskItem implements Serializable {
|
||||
*/
|
||||
private Long taskTypeId;
|
||||
|
||||
/**
|
||||
* 任务类型明细 (JSON数组: [{typeId, typeName, quantity, unitScore, totalScore}])
|
||||
*/
|
||||
private String typeDetails;
|
||||
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
|
||||
@ -420,6 +420,8 @@ public class TaskService {
|
||||
BigDecimal groupTotalHours = BigDecimal.ZERO;
|
||||
int groupTotalQuantity = 0;
|
||||
StringBuilder taskTypeIds = new StringBuilder();
|
||||
// 构建任务类型明细 JSON 数组
|
||||
java.util.List<java.util.Map<String, Object>> typeDetailsList = new java.util.ArrayList<>();
|
||||
|
||||
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : groupItems) {
|
||||
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
|
||||
@ -436,6 +438,15 @@ public class TaskService {
|
||||
taskTypeIds.append(",");
|
||||
}
|
||||
taskTypeIds.append(itemDto.getTaskTypeId());
|
||||
|
||||
// 添加任务类型明细
|
||||
java.util.Map<String, Object> detail = new java.util.LinkedHashMap<>();
|
||||
detail.put("typeId", itemDto.getTaskTypeId());
|
||||
detail.put("typeName", demandType.getName());
|
||||
detail.put("quantity", itemDto.getQuantity());
|
||||
detail.put("unitScore", demandType.getUnitScore());
|
||||
detail.put("totalScore", itemScore);
|
||||
typeDetailsList.add(detail);
|
||||
}
|
||||
|
||||
// 创建子任务
|
||||
@ -444,6 +455,13 @@ public class TaskService {
|
||||
item.setItemNo(generateTaskItemNo(task.getTaskNo(), itemIndex));
|
||||
item.setGroupNo(groupNo);
|
||||
item.setTaskTypeId(groupFirstTaskTypeId.get(groupNo)); // 使用第一个任务类型ID
|
||||
// 保存任务类型明细 JSON
|
||||
try {
|
||||
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
|
||||
item.setTypeDetails(objectMapper.writeValueAsString(typeDetailsList));
|
||||
} catch (Exception e) {
|
||||
log.warn("序列化任务类型明细失败: {}", e.getMessage());
|
||||
}
|
||||
item.setQuantity(groupTotalQuantity);
|
||||
item.setUnitScore(groupTotalScore / groupTotalQuantity); // 平均单价
|
||||
item.setTotalScore(groupTotalScore);
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
-- V10__add_task_type_details.sql
|
||||
|
||||
-- 添加任务类型明细字段到子任务表
|
||||
ALTER TABLE `task_item`
|
||||
ADD COLUMN `type_details` JSON NULL COMMENT '任务类型明细(JSON数组: [{typeId, typeName, quantity, unitScore, totalScore}])' AFTER `task_type_id`;
|
||||
|
||||
@ -240,7 +240,7 @@
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">预估积分</span>
|
||||
<span class="value text-brand">{{ task.score || '--' }} 分</span>
|
||||
<span class="value text-brand">{{ task.totalScore || task.score || '--' }} 分</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">数量</span>
|
||||
@ -256,6 +256,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务类型明细 -->
|
||||
<div v-if="parseTypeDetails(task.typeDetails).length > 0" class="type-details-section">
|
||||
<div class="type-details-title">任务类型明细</div>
|
||||
<div class="type-details-list">
|
||||
<div v-for="(detail, idx) in parseTypeDetails(task.typeDetails)" :key="idx" class="type-detail-item">
|
||||
<span class="type-name">└ {{ detail.typeName }}</span>
|
||||
<span class="type-score">x{{ detail.quantity }} = {{ detail.totalScore }}分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务详情 -->
|
||||
<div class="task-details">
|
||||
<div v-if="task.brandName" class="detail-item">
|
||||
@ -541,7 +552,7 @@
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">预估积分</span>
|
||||
<span class="value text-brand">{{ task.score }} 分</span>
|
||||
<span class="value text-brand">{{ task.totalScore || task.score }} 分</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">数量</span>
|
||||
@ -557,6 +568,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务类型明细 -->
|
||||
<div v-if="parseTypeDetails(task.typeDetails).length > 0" class="type-details-section">
|
||||
<div class="type-details-title">任务类型明细</div>
|
||||
<div class="type-details-list">
|
||||
<div v-for="(detail, idx) in parseTypeDetails(task.typeDetails)" :key="idx" class="type-detail-item">
|
||||
<span class="type-name">└ {{ detail.typeName }}</span>
|
||||
<span class="type-score">x{{ detail.quantity }} = {{ detail.totalScore }}分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务详情 -->
|
||||
<div class="task-details">
|
||||
<div class="detail-item">
|
||||
@ -850,7 +872,7 @@
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">预估积分</span>
|
||||
<span class="value text-brand">{{ task.score }} 分</span>
|
||||
<span class="value text-brand">{{ task.totalScore || task.score }} 分</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">数量</span>
|
||||
@ -866,6 +888,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务类型明细 -->
|
||||
<div v-if="parseTypeDetails(task.typeDetails).length > 0" class="type-details-section">
|
||||
<div class="type-details-title">任务类型明细</div>
|
||||
<div class="type-details-list">
|
||||
<div v-for="(detail, idx) in parseTypeDetails(task.typeDetails)" :key="idx" class="type-detail-item">
|
||||
<span class="type-name">└ {{ detail.typeName }}</span>
|
||||
<span class="type-score">x{{ detail.quantity }} = {{ detail.totalScore }}分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务详情 -->
|
||||
<div class="task-details">
|
||||
<div class="detail-item">
|
||||
@ -2341,6 +2374,14 @@ import { useConfigStore } from '@/stores/config'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// 扩展Task类型以支持子任务字段
|
||||
interface TaskTypeDetail {
|
||||
typeId: number
|
||||
typeName: string
|
||||
quantity: number
|
||||
unitScore: number
|
||||
totalScore: number
|
||||
}
|
||||
|
||||
interface TaskOrSubTask extends Task {
|
||||
isSubTask?: boolean // 是否为子任务
|
||||
itemId?: number // 子任务ID
|
||||
@ -2351,6 +2392,7 @@ interface TaskOrSubTask extends Task {
|
||||
submitTime?: string // 提交时间
|
||||
taskTypeName?: string // 任务类型名称(子任务直接返回)
|
||||
prevDownloadUrl?: string // 前置子任务的素材下载链接
|
||||
typeDetails?: string | TaskTypeDetail[] // 任务类型明细(JSON字符串或解析后的数组)
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
@ -2540,6 +2582,18 @@ const getTaskTypeName = (typeId: number, taskTypeName?: string, taskSubType?: st
|
||||
return type?.name || '未知类型'
|
||||
}
|
||||
|
||||
// 解析任务类型明细
|
||||
const parseTypeDetails = (typeDetails: string | TaskTypeDetail[] | undefined): TaskTypeDetail[] => {
|
||||
if (!typeDetails) return []
|
||||
if (Array.isArray(typeDetails)) return typeDetails
|
||||
try {
|
||||
return JSON.parse(typeDetails) as TaskTypeDetail[]
|
||||
} catch (e) {
|
||||
console.warn('解析任务类型明细失败:', e)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// 获取任务类型单位积分
|
||||
const getTaskTypeUnitScore = (typeId: number) => {
|
||||
const type = demandTypes.value.find(t => t.id === typeId)
|
||||
@ -5031,6 +5085,50 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// 任务类型明细
|
||||
.type-details-section {
|
||||
background: rgba($brand-primary, 0.05);
|
||||
border: 1px solid rgba($brand-primary, 0.2);
|
||||
border-radius: 8px;
|
||||
padding: $space-sm $space-md;
|
||||
margin-bottom: $space-md;
|
||||
|
||||
.type-details-title {
|
||||
font-size: $font-size-xs;
|
||||
color: $text-tertiary;
|
||||
margin-bottom: $space-xs;
|
||||
}
|
||||
|
||||
.type-details-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.type-detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: $font-size-sm;
|
||||
padding: 2px 0;
|
||||
|
||||
.type-name {
|
||||
color: $text-secondary;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.type-score {
|
||||
color: $brand-primary;
|
||||
font-weight: $font-weight-medium;
|
||||
margin-left: $space-md;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 任务详情
|
||||
.task-details {
|
||||
display: grid;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user