diff --git a/src/views/oa/erp/erpProjectPlan/gantt.vue b/src/views/oa/erp/erpProjectPlan/gantt.vue index d7341f7..367c305 100644 --- a/src/views/oa/erp/erpProjectPlan/gantt.vue +++ b/src/views/oa/erp/erpProjectPlan/gantt.vue @@ -30,8 +30,8 @@ {{ taskList.length }} - - {{ formatDisplayDate(new Date()) }} + + {{ lastPlanEndDate }} @@ -129,6 +129,25 @@ const planStatusLabel = computed(() => { return statusMap.value[planDetail.value.projectPlanStatus] || planDetail.value.projectPlanStatus; }); +const lastPlanEndDate = computed(() => { + if (!taskList.value.length) { + return '-'; + } + let maxTs: number | null = null; + taskList.value.forEach(task => { + const ts = toTimestamp(task.planEnd); + if (ts !== null) { + if (maxTs === null || ts > maxTs) { + maxTs = ts; + } + } + }); + if (maxTs === null) { + return '-'; + } + return formatDisplayDate(new Date(maxTs)); +}); + const projectPlanId = computed(() => route.params.projectPlanId as string); const renderGanttItem = (params: any, api: any) => { @@ -180,41 +199,65 @@ const updateChart = () => { let min = Number.POSITIVE_INFINITY; let max = Number.NEGATIVE_INFINITY; - const planData = taskList.value - .map((task, index) => { - const start = toTimestamp(task.planStart); - const end = toTimestamp(task.planEnd); - if (start === null || end === null || end < start) { - return null; - } + const planBarData: any[] = []; + const planPointData: any[] = []; + + taskList.value.forEach((task, index) => { + const start = toTimestamp(task.planStart); + const end = toTimestamp(task.planEnd); + if (start === null || end === null) { + return; + } + // 同一天的任务使用散点展示,避免零宽度矩形不可见 + if (end <= start) { + min = Math.min(min, start); + max = Math.max(max, start); + planPointData.push({ + name: task.taskName, + value: [start, index], + task + }); + } else { min = Math.min(min, start); max = Math.max(max, end); - return { + planBarData.push({ name: task.taskName, value: [index, start, end], task - }; - }) - .filter(Boolean) as Array<{ name: string; value: [number, number, number]; task: GanttTask }>; + }); + } + }); - const actualData = showActual.value - ? (taskList.value - .map((task, index) => { - const start = toTimestamp(task.realStart); - const end = toTimestamp(task.realEnd); - if (start === null || end === null || end < start) { - return null; - } - min = Math.min(min, start); - max = Math.max(max, end); - return { - name: `${task.taskName}-实际`, - value: [index, start, end], - task - }; - }) - .filter(Boolean) as Array<{ name: string; value: [number, number, number]; task: GanttTask }>) - : []; + const actualBarData: any[] = []; + const actualPointData: any[] = []; + + if (showActual.value) { + taskList.value.forEach((task, index) => { + const start = toTimestamp(task.realStart); + const end = toTimestamp(task.realEnd); + if (start === null || end === null) { + return; + } + // 实际进度同一天也使用散点展示 + if (end <= start) { + min = Math.min(min, start); + max = Math.max(max, start); + actualPointData.push({ + name: `${task.taskName}-实际`, + value: [start, index], + task + }); + } else { + min = Math.min(min, start); + max = Math.max(max, end); + actualBarData.push({ + name: `${task.taskName}-实际`, + value: [index, start, end], + task + }); + } + }); + } if (min === Number.POSITIVE_INFINITY || max === Number.NEGATIVE_INFINITY) { const now = Date.now(); @@ -223,24 +266,42 @@ const updateChart = () => { } const series: any[] = []; - if (planData.length) { + if (planBarData.length) { series.push({ name: '计划进度', type: 'custom', renderItem: renderGanttItem, itemStyle: { color: '#91cc75', opacity: 0.9 }, encode: { x: [1, 2], y: 0 }, - data: planData + data: planBarData }); } - if (actualData.length) { + if (planPointData.length) { + series.push({ + name: '计划进度(单日)', + type: 'scatter', + symbolSize: 10, + itemStyle: { color: '#91cc75', opacity: 0.9 }, + data: planPointData + }); + } + if (actualBarData.length) { series.push({ name: '实际进度', type: 'custom', renderItem: renderGanttItem, itemStyle: { color: '#5470c6', opacity: 0.75 }, encode: { x: [1, 2], y: 0 }, - data: actualData + data: actualBarData + }); + } + if (actualPointData.length) { + series.push({ + name: '实际进度(单日)', + type: 'scatter', + symbolSize: 10, + itemStyle: { color: '#5470c6', opacity: 0.75 }, + data: actualPointData }); }