diff --git a/backend/src/main/java/com/designhub/entity/DemandType.java b/backend/src/main/java/com/designhub/entity/DemandType.java index 7546343..fdda901 100644 --- a/backend/src/main/java/com/designhub/entity/DemandType.java +++ b/backend/src/main/java/com/designhub/entity/DemandType.java @@ -47,10 +47,10 @@ public class DemandType implements Serializable { private Integer unitScoreInt; /** - * 预估工时(小时) + * 预估工时(小时,支持小数如0.05表示3分钟) */ @TableField("estimated_hours") - private Integer estimatedHours; + private BigDecimal estimatedHours; /** * 类型描述 diff --git a/frontend/src/views/CreateTask.vue b/frontend/src/views/CreateTask.vue index a7e1521..d63717b 100644 --- a/frontend/src/views/CreateTask.vue +++ b/frontend/src/views/CreateTask.vue @@ -15,6 +15,22 @@ 管理员身份,无需积分即可发起任务 本次任务预估消耗: {{ estimatedScore }} 分 + + +
+
+ 累计时效: + {{ formattedEstimatedTime }} +
+
+ 预计完成: + {{ estimatedDeadline }} +
+
+ + 按8小时/工作日计算,超过8小时按整天计算 +
+
@@ -884,6 +900,75 @@ const estimatedScore = computed(() => { return totalScore }) +// 计算累计时效(小时) +const estimatedTotalHours = computed(() => { + let totalHours = 0 + + for (const item of formData.taskTypes) { + if (item.taskTypeId && item.quantity > 0) { + const selectedType = taskTypes.value.find(t => t.id === item.taskTypeId) + if (selectedType && selectedType.estimatedHours) { + totalHours += selectedType.estimatedHours * item.quantity + } + } + } + + return totalHours +}) + +// 格式化时效显示 +const formattedEstimatedTime = computed(() => { + const hours = estimatedTotalHours.value + if (hours === 0) return '--' + + if (hours < 1) { + return `${Math.round(hours * 60)}分钟` + } else if (hours < 24) { + const h = Math.floor(hours) + const m = Math.round((hours - h) * 60) + return m > 0 ? `${h}小时${m}分钟` : `${h}小时` + } else { + const days = Math.floor(hours / 24) + const remainHours = Math.round(hours % 24) + return remainHours > 0 ? `${days}天${remainHours}小时` : `${days}天` + } +}) + +// 计算预计完成时间(考虑8小时工作制) +const estimatedDeadline = computed(() => { + const totalHours = estimatedTotalHours.value + if (totalHours === 0) return '--' + + const now = new Date() + const WORK_HOURS_PER_DAY = 8 // 每天工作8小时 + + // 计算需要多少个工作日 + let workDays = Math.floor(totalHours / WORK_HOURS_PER_DAY) + let remainingHours = totalHours % WORK_HOURS_PER_DAY + + // 如果超过8小时,按24小时(1天)计算 + if (totalHours > WORK_HOURS_PER_DAY) { + // 超过8小时的部分,每8小时算1个工作日,但日历上是24小时 + const totalDays = Math.ceil(totalHours / WORK_HOURS_PER_DAY) + const deadline = new Date(now.getTime() + totalDays * 24 * 60 * 60 * 1000) + return formatDeadline(deadline) + } else { + // 8小时内,当天完成 + const deadline = new Date(now.getTime() + totalHours * 60 * 60 * 1000) + return formatDeadline(deadline) + } +}) + +// 格式化截止时间 +const formatDeadline = (date: Date) => { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hour = String(date.getHours()).padStart(2, '0') + const minute = String(date.getMinutes()).padStart(2, '0') + return `${year}-${month}-${day} ${hour}:${minute}` +} + // 计算流水线分组 const pipelineGroups = computed(() => { if (formData.taskTypes.length === 0) { @@ -1621,6 +1706,44 @@ onUnmounted(() => { strong { color: $brand-primary; + } +} + +.time-estimate { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: $space-md; + margin-top: $space-md; + padding: $space-md; + background: rgba(255, 255, 255, 0.03); + border-radius: $radius-small; + border: 1px solid rgba(255, 255, 255, 0.06); + + .estimate-item { + display: flex; + align-items: center; + gap: $space-xs; + + .estimate-label { + color: $text-tertiary; + font-size: $font-size-sm; + } + + .estimate-value { + color: $brand-primary; + font-weight: 600; + font-size: $font-size-base; + } + } + + .estimate-tip { + flex-basis: 100%; + display: flex; + align-items: center; + font-size: $font-size-xs; + color: $text-tertiary; + margin-top: $space-xs; font-weight: $font-weight-semibold; } } diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index 8333387..fc19887 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -1265,14 +1265,19 @@ - + +
+ + 时效会根据任务数量累计计算(如5个任务×0.05小时=0.25小时) +