v1.4.6 - bugfix
This commit is contained in:
@@ -48,6 +48,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
autoSortByStartDate: false,
|
||||
allowDragAndResize: true,
|
||||
enableTaskRowMove: false,
|
||||
assigneeOptions: () => [],
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -128,6 +129,10 @@ interface Props {
|
||||
allowDragAndResize?: boolean
|
||||
// 是否启用TaskRow拖拽移动功能(默认为 false)
|
||||
enableTaskRowMove?: boolean
|
||||
// 指派人员选项列表(用于TaskDrawer中的assignee下拉菜单)
|
||||
// 格式:{ key?: string | number, value: string | number, label: string }
|
||||
// key 为可选项,若不存在则使用 value 作为选项的唯一标识
|
||||
assigneeOptions?: Array<{ key?: string | number; value: string | number; label: string }>
|
||||
}
|
||||
|
||||
// TaskList的固定总长度(所有列的最小宽度之和 + 边框等额外空间)
|
||||
@@ -2328,6 +2333,7 @@ function handleMilestoneDialogDelete(milestoneId: number) {
|
||||
v-model:visible="taskDrawerVisible"
|
||||
:task="taskDrawerTask"
|
||||
:is-edit="taskDrawerEditMode"
|
||||
:assignee-options="props.assigneeOptions"
|
||||
@submit="handleTaskDrawerSubmit"
|
||||
@close="taskDrawerVisible = false"
|
||||
@start-timer="handleStartTimer"
|
||||
|
||||
+48
-15
@@ -243,7 +243,26 @@ const taskBarStyle = computed(() => {
|
||||
const startDate = createLocalDate(currentStartDate)
|
||||
const endDate = createLocalDate(currentEndDate)
|
||||
const baseStart = parsedBaseStartDate.value
|
||||
if (!startDate || !endDate || !baseStart) {
|
||||
|
||||
// 如果startDate和endDate都不存在,返回0宽度(实际不会渲染,由shouldRenderTaskBar控制)
|
||||
if (!startDate && !endDate) {
|
||||
return {
|
||||
left: '0px',
|
||||
width: '0px',
|
||||
height: `${props.rowHeight - 10}px`,
|
||||
top: '4px',
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染时使用有效日期:如果只有startDate或endDate,用它来计算开始和结束位置
|
||||
// 注意:不修改原始的startDate/endDate变量,只用于渲染计算
|
||||
const renderStartDate = startDate || endDate
|
||||
const renderEndDate = endDate || startDate
|
||||
const renderBaseStart = baseStart
|
||||
|
||||
// 安全检查:renderStartDate和renderEndDate必定存在(因为上面已经检查过)
|
||||
// 但baseStart可能不存在,如果不存在则无法计算位置
|
||||
if (!renderStartDate || !renderEndDate || !renderBaseStart) {
|
||||
return {
|
||||
left: '0px',
|
||||
width: '0px',
|
||||
@@ -258,12 +277,12 @@ const taskBarStyle = computed(() => {
|
||||
// 小时视图:按分钟精确计算位置(需要考虑时间部分)
|
||||
if (props.currentTimeScale === TimelineScale.HOUR) {
|
||||
// 确保 baseStart 是当天的 00:00:00
|
||||
const baseStartOfDay = new Date(baseStart)
|
||||
const baseStartOfDay = new Date(renderBaseStart)
|
||||
baseStartOfDay.setHours(0, 0, 0, 0)
|
||||
|
||||
// 处理没有时间部分的日期字符串
|
||||
let adjustedStartDate = startDate
|
||||
let adjustedEndDate = endDate
|
||||
let adjustedStartDate = renderStartDate
|
||||
let adjustedEndDate = renderEndDate
|
||||
|
||||
// 检查原始日期字符串是否包含时间部分
|
||||
const originalStartStr = currentStartDate || props.task.startDate
|
||||
@@ -274,13 +293,13 @@ const taskBarStyle = computed(() => {
|
||||
typeof originalStartStr === 'string' &&
|
||||
/^\d{4}-\d{2}-\d{2}$/.test(originalStartStr.trim())
|
||||
) {
|
||||
adjustedStartDate = new Date(startDate)
|
||||
adjustedStartDate = new Date(renderStartDate)
|
||||
adjustedStartDate.setHours(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
// 如果endDate没有时间部分(格式为YYYY-MM-DD),设置为次日00:00
|
||||
if (typeof originalEndStr === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(originalEndStr.trim())) {
|
||||
adjustedEndDate = new Date(endDate)
|
||||
adjustedEndDate = new Date(renderEndDate)
|
||||
adjustedEndDate.setDate(adjustedEndDate.getDate() + 1)
|
||||
adjustedEndDate.setHours(0, 0, 0, 0)
|
||||
}
|
||||
@@ -299,15 +318,19 @@ const taskBarStyle = computed(() => {
|
||||
|
||||
// 将日期标准化为当天的00:00:00,忽略时间部分
|
||||
const startDateOnly = new Date(
|
||||
startDate.getFullYear(),
|
||||
startDate.getMonth(),
|
||||
startDate.getDate(),
|
||||
renderStartDate.getFullYear(),
|
||||
renderStartDate.getMonth(),
|
||||
renderStartDate.getDate(),
|
||||
)
|
||||
const endDateOnly = new Date(
|
||||
renderEndDate.getFullYear(),
|
||||
renderEndDate.getMonth(),
|
||||
renderEndDate.getDate(),
|
||||
)
|
||||
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate())
|
||||
const baseStartOnly = new Date(
|
||||
baseStart.getFullYear(),
|
||||
baseStart.getMonth(),
|
||||
baseStart.getDate(),
|
||||
renderBaseStart.getFullYear(),
|
||||
renderBaseStart.getMonth(),
|
||||
renderBaseStart.getDate(),
|
||||
)
|
||||
|
||||
if (
|
||||
@@ -429,6 +452,15 @@ const parsedEndDate = computed(() => createLocalDate(props.task.endDate || ''))
|
||||
// 缓存解析后的基准开始日期
|
||||
const parsedBaseStartDate = computed(() => createLocalDate(props.startDate))
|
||||
|
||||
// 判断是否应该渲染TaskBar:只考虑startDate和endDate,都不存在时不渲染
|
||||
const shouldRenderTaskBar = computed(() => {
|
||||
const currentStartDate = tempTaskData.value?.startDate || props.task.startDate
|
||||
const currentEndDate = tempTaskData.value?.endDate || props.task.endDate
|
||||
|
||||
// 只要startDate或endDate有一个存在就渲染
|
||||
return !!(currentStartDate || currentEndDate)
|
||||
})
|
||||
|
||||
// 计算任务状态和颜色
|
||||
const taskStatus = computed(() => {
|
||||
// 父级任务(Story类型)使用与新建按钮一致的配色
|
||||
@@ -2240,6 +2272,7 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="shouldRenderTaskBar"
|
||||
ref="barRef"
|
||||
class="task-bar"
|
||||
:style="{
|
||||
@@ -2336,8 +2369,8 @@ onUnmounted(() => {
|
||||
<!-- 图片头像 -->
|
||||
<img v-if="task.avatar" :src="task.avatar" :alt="task.assignee || 'avatar'" />
|
||||
<!-- 文字头像(负责人首字母) -->
|
||||
<span v-else-if="task.assignee" class="avatar-text">
|
||||
{{ task.assignee.charAt(0).toUpperCase() }}
|
||||
<span v-else-if="task.assigneeName" class="avatar-text">
|
||||
{{ task.assigneeName.charAt(0).toUpperCase() }}
|
||||
</span>
|
||||
<!-- 默认灰色用户图标 -->
|
||||
<svg v-else class="avatar-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
@@ -9,11 +9,18 @@ import ConfirmTimerDialog from './ConfirmTimerDialog.vue'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import '../styles/app.css'
|
||||
|
||||
interface AssigneeOption {
|
||||
key?: string | number
|
||||
value: string | number
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
task?: Task | null
|
||||
isEdit?: boolean
|
||||
onDelete?: (task: Task) => void
|
||||
assigneeOptions?: AssigneeOption[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -21,6 +28,13 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
task: null,
|
||||
isEdit: false,
|
||||
onDelete: undefined,
|
||||
assigneeOptions: () => [
|
||||
{ value: 'zhangsan', label: '张三' },
|
||||
{ value: 'lisi', label: '李四' },
|
||||
{ value: 'wangwu', label: '王五' },
|
||||
{ value: 'zhaoliu', label: '赵六' },
|
||||
{ value: 'qianqi', label: '钱七' },
|
||||
],
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -628,6 +642,17 @@ function confirmTimer(desc: string) {
|
||||
// desc 可用于后续业务
|
||||
handleStartTimer(desc)
|
||||
}
|
||||
|
||||
// 处理负责人变更
|
||||
const handleAssigneeChanged = (value: string) => {
|
||||
// 通过value过滤props.assigneeOptions获取对应的label
|
||||
const selected = props.assigneeOptions?.find(option => option.value === value)
|
||||
if (selected) {
|
||||
// 这里可以根据需要处理选中的负责人信息
|
||||
// 例如,可以将负责人名称存储在formData中
|
||||
formData.assigneeName = selected.label
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -788,13 +813,15 @@ function confirmTimer(desc: string) {
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="task-assignee">{{ t.assignee }}</label>
|
||||
<select id="task-assignee" v-model="formData.assignee" class="form-select">
|
||||
<select id="task-assignee" v-model="formData.assignee" class="form-select" @change="handleAssigneeChanged">
|
||||
<option value="">{{ t.selectAssignee }}</option>
|
||||
<option value="张三">张三</option>
|
||||
<option value="李四">李四</option>
|
||||
<option value="王五">王五</option>
|
||||
<option value="赵六">赵六</option>
|
||||
<option value="钱七">钱七</option>
|
||||
<option
|
||||
v-for="assignee in props.assigneeOptions"
|
||||
:key="assignee.key ?? assignee.value"
|
||||
:value="assignee.value"
|
||||
>
|
||||
{{ assignee.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user