feat: 任务时效累计计算,支持分钟级精度和工作日计算
This commit is contained in:
parent
e6308b937f
commit
a2fd8a63b0
@ -47,10 +47,10 @@ public class DemandType implements Serializable {
|
||||
private Integer unitScoreInt;
|
||||
|
||||
/**
|
||||
* 预估工时(小时)
|
||||
* 预估工时(小时,支持小数如0.05表示3分钟)
|
||||
*/
|
||||
@TableField("estimated_hours")
|
||||
private Integer estimatedHours;
|
||||
private BigDecimal estimatedHours;
|
||||
|
||||
/**
|
||||
* 类型描述
|
||||
|
||||
@ -15,6 +15,22 @@
|
||||
<span v-if="isAdmin" style="color: #31f08b;">管理员身份,无需积分即可发起任务</span>
|
||||
<span v-else>本次任务预估消耗: <strong>{{ estimatedScore }}</strong> 分</span>
|
||||
</div>
|
||||
|
||||
<!-- 时效预估 -->
|
||||
<div v-if="estimatedTotalHours > 0" class="time-estimate">
|
||||
<div class="estimate-item">
|
||||
<span class="estimate-label">累计时效:</span>
|
||||
<span class="estimate-value">{{ formattedEstimatedTime }}</span>
|
||||
</div>
|
||||
<div class="estimate-item">
|
||||
<span class="estimate-label">预计完成:</span>
|
||||
<span class="estimate-value">{{ estimatedDeadline }}</span>
|
||||
</div>
|
||||
<div class="estimate-tip">
|
||||
<Icon name="info" size="xs" style="margin-right: 4px; opacity: 0.6;" />
|
||||
<span>按8小时/工作日计算,超过8小时按整天计算</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务表单 -->
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1265,14 +1265,19 @@
|
||||
</a-form-item>
|
||||
|
||||
<!-- 预计时长(二级和三级分类都可以设置) -->
|
||||
<a-form-item v-if="formData.demandType.addLevel === 'level2' || formData.demandType.addLevel === 'level3'" label="预计时长(小时)">
|
||||
<a-form-item v-if="formData.demandType.addLevel === 'level2' || formData.demandType.addLevel === 'level3'" label="单个任务耗时(小时)">
|
||||
<a-input-number
|
||||
v-model:value="formData.demandType.estimatedHours"
|
||||
:min="0"
|
||||
:precision="1"
|
||||
:precision="2"
|
||||
:step="0.05"
|
||||
style="width: 100%"
|
||||
placeholder="请输入预计时长"
|
||||
placeholder="单个任务耗时(如0.05=3分钟,1=1小时)"
|
||||
/>
|
||||
<div class="form-tip">
|
||||
<Icon name="info" size="sm" color="#6B6B6B" style="margin-right: 4px;" />
|
||||
时效会根据任务数量累计计算(如5个任务×0.05小时=0.25小时)
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="描述">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user