style:甘特图适配中英文

pull/1/head
黄伟杰 4 weeks ago
parent 5416bdbdac
commit 4f481974a5

@ -4406,5 +4406,91 @@ export default {
statusStored: 'Stored', statusStored: 'Stored',
statusStarted: 'Started' statusStarted: 'Started'
} }
},
GanttChart: {
Index: {
searchTimeLabel: 'Query Time',
startPlaceholder: 'Start Time',
endPlaceholder: 'End Time',
deviceLabel: 'Device',
devicePlaceholder: 'Please select device',
buttonSearch: 'Search',
buttonReset: 'Reset'
},
CardView: {
legendScheduled: 'Scheduled',
legendMerged: 'Merged',
legendPaused: 'Paused',
legendPendingStorage: 'Pending Storage',
legendStored: 'Stored',
statPlanCount: 'Plans',
statCapacity: 'Capacity',
planCodeLabel: 'Plan Code:',
productLabel: 'Product:',
planNumberLabel: 'Plan Qty:',
deliveryDateLabel: 'Delivery Date:',
startLabel: 'Start:',
endLabel: 'End:',
emptyDescription: 'No Plans',
statusScheduled: 'Scheduled',
statusMerged: 'Merged',
statusPaused: 'Paused',
statusPendingStorage: 'Pending Storage',
statusStored: 'Stored',
statusUnknown: 'Unknown'
},
GanttPanel: {
detailTitle: 'Schedule Info',
deviceNameLabel: 'Device Name',
deviceIdLabel: 'Device ID',
capacityLabel: 'Capacity',
dailyAvgLabel: 'Daily Avg Report',
dataCollectionCapacityLabel: 'DC Capacity',
planCountLabel: 'Plan Count',
planDetailTitle: 'Plan Details',
planCodeColon: 'Plan Code: ',
planNumberColon: 'Plan Qty: ',
deliveryDateColon: 'Delivery Date: ',
startColon: 'Start: ',
endColon: 'End: ',
latestStartColon: 'Latest Start: ',
emptyDescription: 'No Schedule Info',
adjustTaskTitle: 'Adjust Task',
deviceLabel: 'Device',
devicePlaceholder: 'Please select device',
startDateLabel: 'Start Date',
startDatePlaceholder: 'Please select start date',
durationLabel: 'Days',
buttonCancel: 'Cancel',
buttonConfirm: 'Confirm',
editStartDateTitle: 'Edit Start Time',
startTimeLabel: 'Start Time',
startTimePlaceholder: 'Please select start time',
warningCompleteDeviceDate: 'Please complete device and start date',
warningValidTime: 'Please select a valid time',
columnTaskName: 'Task Name',
columnStartTime: 'Start Time',
columnDays: 'Days',
scaleMonthFormat: 'MMM YYYY',
tooltipTaskDetail: 'Task Detail',
tooltipTaskCode: 'Task Code: ',
tooltipProduct: 'Product: ',
tooltipDetailId: 'Detail ID: ',
tooltipPlanNumber: 'Plan Qty: ',
tooltipStart: 'Start: ',
tooltipEnd: 'End: ',
tooltipLatestStart: 'Latest Start: ',
tooltipSummary: 'Summary',
tooltipDevice: 'Device: ',
tooltipDetailCount: 'Detail Count: ',
tooltipTotalPlanNumber: 'Total Plan Qty: ',
tooltipEarliestStart: 'Earliest Start: ',
tooltipLatestEnd: 'Latest End: ',
statusScheduled: 'Scheduled',
statusStarted: 'Started',
statusPaused: 'Paused',
statusPendingStorage: 'Pending Storage',
statusStored: 'Stored'
}
} }
} }

@ -4624,5 +4624,91 @@ export default {
statusStored: '已入库', statusStored: '已入库',
statusStarted: '已开工' statusStarted: '已开工'
} }
},
GanttChart: {
Index: {
searchTimeLabel: '查询时间',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
deviceLabel: '设备',
devicePlaceholder: '请选择设备',
buttonSearch: '查询',
buttonReset: '重置'
},
CardView: {
legendScheduled: '已排产',
legendMerged: '已并工',
legendPaused: '暂停',
legendPendingStorage: '待入库',
legendStored: '已入库',
statPlanCount: '计划数',
statCapacity: '产能',
planCodeLabel: '计划编号:',
productLabel: '产品:',
planNumberLabel: '计划数量:',
deliveryDateLabel: '交货日期:',
startLabel: '开始:',
endLabel: '结束:',
emptyDescription: '暂无计划',
statusScheduled: '已排产',
statusMerged: '已并工',
statusPaused: '暂停',
statusPendingStorage: '待入库',
statusStored: '已入库',
statusUnknown: '未知'
},
GanttPanel: {
detailTitle: '计划信息',
deviceNameLabel: '设备名称',
deviceIdLabel: '设备ID',
capacityLabel: '产能',
dailyAvgLabel: '每日报工平均值',
dataCollectionCapacityLabel: '数据采集产能',
planCountLabel: '计划条数',
planDetailTitle: '计划明细',
planCodeColon: '计划编码:',
planNumberColon: '计划数量:',
deliveryDateColon: '交货日期:',
startColon: '开始:',
endColon: '结束:',
latestStartColon: '最晚开工:',
emptyDescription: '暂无计划信息',
adjustTaskTitle: '调整任务',
deviceLabel: '设备',
devicePlaceholder: '请选择设备',
startDateLabel: '开始日期',
startDatePlaceholder: '请选择开始日期',
durationLabel: '天数',
buttonCancel: '取消',
buttonConfirm: '确定',
editStartDateTitle: '修改开始时间',
startTimeLabel: '开始时间',
startTimePlaceholder: '请选择开始时间',
warningCompleteDeviceDate: '请完善设备和开始日期',
warningValidTime: '请选择有效的时间',
columnTaskName: '任务名称',
columnStartTime: '开始时间',
columnDays: '天数',
scaleMonthFormat: 'YYYY年M月',
tooltipTaskDetail: '任务明细',
tooltipTaskCode: '任务单:',
tooltipProduct: '产品:',
tooltipDetailId: '明细ID',
tooltipPlanNumber: '计划数量:',
tooltipStart: '开始:',
tooltipEnd: '结束:',
tooltipLatestStart: '最晚开工:',
tooltipSummary: '汇总',
tooltipDevice: '设备:',
tooltipDetailCount: '任务明细条数:',
tooltipTotalPlanNumber: '计划总数:',
tooltipEarliestStart: '最早计划开始:',
tooltipLatestEnd: '最晚计划结束:',
statusScheduled: '已排产',
statusStarted: '已开工',
statusPaused: '暂停',
statusPendingStorage: '待入库',
statusStored: '已入库'
}
} }
} }

@ -2,7 +2,7 @@
<div class="schedule-preview-wrap"> <div class="schedule-preview-wrap">
<div ref="ganttContainerRef" class="schedule-gantt-container" :style="{ height }"></div> <div ref="ganttContainerRef" class="schedule-gantt-container" :style="{ height }"></div>
<div class="schedule-detail-panel"> <div class="schedule-detail-panel">
<div class="schedule-detail-title">计划信息</div> <div class="schedule-detail-title">{{ t('GanttChart.GanttPanel.detailTitle') }}</div>
<div v-if="!editable" class="schedule-status-legend"> <div v-if="!editable" class="schedule-status-legend">
<div <div
v-for="item in sortedPlanStatusList" v-for="item in sortedPlanStatusList"
@ -16,14 +16,14 @@
</div> </div>
<template v-if="activePreviewDevice"> <template v-if="activePreviewDevice">
<el-descriptions :column="1" border size="small"> <el-descriptions :column="1" border size="small">
<el-descriptions-item label="设备名称">{{ activePreviewDevice.deviceName }}</el-descriptions-item> <el-descriptions-item :label="t('GanttChart.GanttPanel.deviceNameLabel')">{{ activePreviewDevice.deviceName }}</el-descriptions-item>
<el-descriptions-item label="设备ID">{{ activePreviewDevice.deviceId }}</el-descriptions-item> <el-descriptions-item :label="t('GanttChart.GanttPanel.deviceIdLabel')">{{ activePreviewDevice.deviceId }}</el-descriptions-item>
<el-descriptions-item label="产能">{{ activePreviewDevice.ratedCapacity ?? '-' }}</el-descriptions-item> <el-descriptions-item :label="t('GanttChart.GanttPanel.capacityLabel')">{{ activePreviewDevice.ratedCapacity ?? '-' }}</el-descriptions-item>
<el-descriptions-item v-if="'dailyAverageValue' in activePreviewDevice" label="每日报工平均值">{{ activePreviewDevice.dailyAverageValue ?? '-' }}</el-descriptions-item> <el-descriptions-item v-if="'dailyAverageValue' in activePreviewDevice" :label="t('GanttChart.GanttPanel.dailyAvgLabel')">{{ activePreviewDevice.dailyAverageValue ?? '-' }}</el-descriptions-item>
<el-descriptions-item v-if="'dataCollectionCapacity' in activePreviewDevice" label="数据采集产能">{{ activePreviewDevice.dataCollectionCapacity ?? '-' }}</el-descriptions-item> <el-descriptions-item v-if="'dataCollectionCapacity' in activePreviewDevice" :label="t('GanttChart.GanttPanel.dataCollectionCapacityLabel')">{{ activePreviewDevice.dataCollectionCapacity ?? '-' }}</el-descriptions-item>
<el-descriptions-item label="计划条数">{{ activePreviewDevice.plans?.length ?? 0 }}</el-descriptions-item> <el-descriptions-item :label="t('GanttChart.GanttPanel.planCountLabel')">{{ activePreviewDevice.plans?.length ?? 0 }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<div class="schedule-plan-list-title">计划明细</div> <div class="schedule-plan-list-title">{{ t('GanttChart.GanttPanel.planDetailTitle') }}</div>
<div class="schedule-plan-list"> <div class="schedule-plan-list">
<div <div
v-for="(plan, index) in activePreviewTask ? [activePreviewTask] : (activePreviewDevice?.plans ?? [])" v-for="(plan, index) in activePreviewTask ? [activePreviewTask] : (activePreviewDevice?.plans ?? [])"
@ -40,60 +40,60 @@
{{ PLAN_STATUS_COLOR_MAP[plan.planStatus].label }} {{ PLAN_STATUS_COLOR_MAP[plan.planStatus].label }}
</span> </span>
</div> </div>
<div>计划编码{{ plan.taskCode ?? '-' }}</div> <div>{{ t('GanttChart.GanttPanel.planCodeColon') }}{{ plan.taskCode ?? '-' }}</div>
<div>计划数量{{ plan.planNumber ?? '-' }}</div> <div>{{ t('GanttChart.GanttPanel.planNumberColon') }}{{ plan.planNumber ?? '-' }}</div>
<div>交货日期{{ plan.deliveryDateStr ?? '-' }}</div> <div>{{ t('GanttChart.GanttPanel.deliveryDateColon') }}{{ plan.deliveryDateStr ?? '-' }}</div>
<div>开始{{ plan.planStartTimeStr || '-' }}</div> <div>{{ t('GanttChart.GanttPanel.startColon') }}{{ plan.planStartTimeStr || '-' }}</div>
<div>结束{{ plan.planEndTimeStr || '-' }}</div> <div>{{ t('GanttChart.GanttPanel.endColon') }}{{ plan.planEndTimeStr || '-' }}</div>
<div>最晚开工{{ plan.latestStartTimeStr || '-' }}</div> <div>{{ t('GanttChart.GanttPanel.latestStartColon') }}{{ plan.latestStartTimeStr || '-' }}</div>
</div> </div>
</div> </div>
</template> </template>
<el-empty v-else description="暂无计划信息" :image-size="80" /> <el-empty v-else :description="t('GanttChart.GanttPanel.emptyDescription')" :image-size="80" />
</div> </div>
</div> </div>
<el-dialog v-if="props.editable" v-model="taskAdjustDialogVisible" title="调整任务" width="420px" append-to-body> <el-dialog v-if="props.editable" v-model="taskAdjustDialogVisible" :title="t('GanttChart.GanttPanel.adjustTaskTitle')" width="420px" append-to-body>
<el-form label-width="90px"> <el-form label-width="90px">
<el-form-item label="设备"> <el-form-item :label="t('GanttChart.GanttPanel.deviceLabel')">
<el-select v-model="taskAdjustForm.deviceTaskId" placeholder="请选择设备" class="!w-full"> <el-select v-model="taskAdjustForm.deviceTaskId" :placeholder="t('GanttChart.GanttPanel.devicePlaceholder')" class="!w-full">
<el-option v-for="item in previewDeviceOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in previewDeviceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="开始日期"> <el-form-item :label="t('GanttChart.GanttPanel.startDateLabel')">
<el-date-picker <el-date-picker
v-model="taskAdjustForm.startDate" v-model="taskAdjustForm.startDate"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="请选择开始日期" :placeholder="t('GanttChart.GanttPanel.startDatePlaceholder')"
class="!w-full" class="!w-full"
/> />
</el-form-item> </el-form-item>
<el-form-item label="天数"> <el-form-item :label="t('GanttChart.GanttPanel.durationLabel')">
<el-input-number v-model="taskAdjustForm.duration" :min="1" :max="365" class="!w-full" /> <el-input-number v-model="taskAdjustForm.duration" :min="1" :max="365" class="!w-full" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="taskAdjustDialogVisible = false">取消</el-button> <el-button @click="taskAdjustDialogVisible = false">{{ t('GanttChart.GanttPanel.buttonCancel') }}</el-button>
<el-button type="primary" @click="handleTaskAdjustSubmit"></el-button> <el-button type="primary" @click="handleTaskAdjustSubmit">{{ t('GanttChart.GanttPanel.buttonConfirm') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-if="props.editable" v-model="startDateEditorVisible" title="修改开始时间" width="360px" append-to-body> <el-dialog v-if="props.editable" v-model="startDateEditorVisible" :title="t('GanttChart.GanttPanel.editStartDateTitle')" width="360px" append-to-body>
<el-form label-width="80px"> <el-form label-width="80px">
<el-form-item label="开始时间"> <el-form-item :label="t('GanttChart.GanttPanel.startTimeLabel')">
<el-date-picker <el-date-picker
v-model="startDateEditorValue" v-model="startDateEditorValue"
type="datetime" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择开始时间" :placeholder="t('GanttChart.GanttPanel.startTimePlaceholder')"
class="!w-full" class="!w-full"
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="startDateEditorVisible = false">取消</el-button> <el-button @click="startDateEditorVisible = false">{{ t('GanttChart.GanttPanel.buttonCancel') }}</el-button>
<el-button type="primary" @click="handleStartDateEditorSubmit"></el-button> <el-button type="primary" @click="handleStartDateEditorSubmit">{{ t('GanttChart.GanttPanel.buttonConfirm') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
@ -102,16 +102,19 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { gantt } from 'dhtmlx-gantt' import { gantt } from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css' import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import { useI18n } from '@/hooks/web/useI18n'
defineOptions({ name: 'ScheduleGanttPanel' }) defineOptions({ name: 'ScheduleGanttPanel' })
const { t } = useI18n()
// //
const PLAN_STATUS_COLOR_MAP = { const PLAN_STATUS_COLOR_MAP = {
1: { label: '已排产', color: '#409eff', textColor: '#ffffff', sort: 1 }, 1: { label: t('GanttChart.GanttPanel.statusScheduled'), color: '#409eff', textColor: '#ffffff', sort: 1 },
8: { label: '已开工', color: '#67c23a', textColor: '#ffffff', sort: 2 }, 8: { label: t('GanttChart.GanttPanel.statusStarted'), color: '#67c23a', textColor: '#ffffff', sort: 2 },
3: { label: '暂停', color: '#e6a23c', textColor: '#ffffff', sort: 3 }, 3: { label: t('GanttChart.GanttPanel.statusPaused'), color: '#e6a23c', textColor: '#ffffff', sort: 3 },
4: { label: '待入库', color: '#f56c6c', textColor: '#ffffff', sort: 4 }, 4: { label: t('GanttChart.GanttPanel.statusPendingStorage'), color: '#f56c6c', textColor: '#ffffff', sort: 4 },
5: { label: '已入库', color: '#8e7cc3', textColor: '#ffffff', sort: 5 }, 5: { label: t('GanttChart.GanttPanel.statusStored'), color: '#8e7cc3', textColor: '#ffffff', sort: 5 },
} }
const sortedPlanStatusList = Object.entries(PLAN_STATUS_COLOR_MAP) const sortedPlanStatusList = Object.entries(PLAN_STATUS_COLOR_MAP)
@ -339,25 +342,25 @@ const buildTaskTooltipHtml = (task: any, start?: Date, end?: Date) => {
const plan = task?._planData const plan = task?._planData
if (plan) { if (plan) {
return ` return `
<div><b>任务明细</b></div> <div><b>${t('GanttChart.GanttPanel.tooltipTaskDetail')}</b></div>
<div>任务单${plan.taskCode ?? '-'}</div> <div>${t('GanttChart.GanttPanel.tooltipTaskCode')}${plan.taskCode ?? '-'}</div>
<div>产品${plan.productCode ?? '-'} / ${plan.productName ?? '-'}</div> <div>${t('GanttChart.GanttPanel.tooltipProduct')}${plan.productCode ?? '-'} / ${plan.productName ?? '-'}</div>
<div>明细ID${plan.taskDetailId ?? '-'}</div> <div>${t('GanttChart.GanttPanel.tooltipDetailId')}${plan.taskDetailId ?? '-'}</div>
<div>计划数量${plan.planNumber ?? '-'}</div> <div>${t('GanttChart.GanttPanel.tooltipPlanNumber')}${plan.planNumber ?? '-'}</div>
<div>开始${formatTooltipDateTime(start ?? task?.start_date)}</div> <div>${t('GanttChart.GanttPanel.tooltipStart')}${formatTooltipDateTime(start ?? task?.start_date)}</div>
<div>结束${formatTooltipDateTime(end ?? task?.end_date)}</div> <div>${t('GanttChart.GanttPanel.tooltipEnd')}${formatTooltipDateTime(end ?? task?.end_date)}</div>
<div>最晚开工${formatTooltipDateTime(plan.latestStartTimeStr)}</div> <div>${t('GanttChart.GanttPanel.tooltipLatestStart')}${formatTooltipDateTime(plan.latestStartTimeStr)}</div>
` `
} }
const device = task?._deviceData const device = task?._deviceData
const summary = getDeviceTaskSummary(task) const summary = getDeviceTaskSummary(task)
return ` return `
<div><b>汇总</b></div> <div><b>${t('GanttChart.GanttPanel.tooltipSummary')}</b></div>
<div>设备${device?.deviceName ?? '-'}</div> <div>${t('GanttChart.GanttPanel.tooltipDevice')}${device?.deviceName ?? '-'}</div>
<div>任务明细条数${summary.planCount}</div> <div>${t('GanttChart.GanttPanel.tooltipDetailCount')}${summary.planCount}</div>
<div>计划总数${summary.totalPlanNumber}</div> <div>${t('GanttChart.GanttPanel.tooltipTotalPlanNumber')}${summary.totalPlanNumber}</div>
<div>最早计划开始${summary.earliestStart}</div> <div>${t('GanttChart.GanttPanel.tooltipEarliestStart')}${summary.earliestStart}</div>
<div>最晚计划结束${summary.latestEnd}</div> <div>${t('GanttChart.GanttPanel.tooltipLatestEnd')}${summary.latestEnd}</div>
` `
} }
const getTaskByTooltipNode = (node: HTMLElement) => { const getTaskByTooltipNode = (node: HTMLElement) => {
@ -617,7 +620,7 @@ const openTaskAdjustDialog = (task: any) => {
const handleTaskAdjustSubmit = () => { const handleTaskAdjustSubmit = () => {
if (!taskAdjustTaskId.value || !props.editable) return if (!taskAdjustTaskId.value || !props.editable) return
if (!taskAdjustForm.deviceTaskId || !taskAdjustForm.startDate) { if (!taskAdjustForm.deviceTaskId || !taskAdjustForm.startDate) {
message.warning('请完善设备和开始日期') message.warning(t('GanttChart.GanttPanel.warningCompleteDeviceDate'))
return return
} }
const task = gantt.getTask(taskAdjustTaskId.value) const task = gantt.getTask(taskAdjustTaskId.value)
@ -643,7 +646,7 @@ const handleStartDateEditorSubmit = () => {
} }
const newStart = dayjs(startDateEditorValue.value) const newStart = dayjs(startDateEditorValue.value)
if (!newStart.isValid()) { if (!newStart.isValid()) {
message.warning('请选择有效的时间') message.warning(t('GanttChart.GanttPanel.warningValidTime'))
return return
} }
const duration = Math.max(Number(task.duration) || 1, 1) const duration = Math.max(Number(task.duration) || 1, 1)
@ -717,14 +720,14 @@ const initGanttPreview = () => {
gantt.config.columns = [ gantt.config.columns = [
{ {
name: 'text', name: 'text',
label: '任务名称', label: t('GanttChart.GanttPanel.columnTaskName'),
tree: true, tree: true,
width: '*', width: '*',
min_width: 200 min_width: 200
}, },
{ {
name: 'start_date', name: 'start_date',
label: '开始时间', label: t('GanttChart.GanttPanel.columnStartTime'),
align: 'center', align: 'center',
width: 210, width: 210,
template: (task: any) => template: (task: any) =>
@ -734,7 +737,7 @@ const initGanttPreview = () => {
}, },
{ {
name: 'duration', name: 'duration',
label: '天数', label: t('GanttChart.GanttPanel.columnDays'),
align: 'center', align: 'center',
width: 60, width: 60,
template: (task: any) => template: (task: any) =>
@ -750,7 +753,7 @@ const initGanttPreview = () => {
] ]
gantt.config.scales = [ gantt.config.scales = [
{ unit: 'month', step: 1, format: (date) => dayjs(date).format('YYYY年M月') }, { unit: 'month', step: 1, format: (date) => dayjs(date).format(t('GanttChart.GanttPanel.scaleMonthFormat')) },
{ unit: 'day', step: 1, format: (date) => dayjs(date).format('MM-DD') } { unit: 'day', step: 1, format: (date) => dayjs(date).format('MM-DD') }
] ]

@ -1,49 +1,40 @@
<template> <template>
<div class="schedule-card-view" :class="{ 'fullscreen-mode': isFullscreen }"> <div class="schedule-card-view" :class="{ 'fullscreen-mode': isFullscreen }">
<!-- 工具栏 -->
<div class="schedule-toolbar"> <div class="schedule-toolbar">
<div class="schedule-legend"> <div class="schedule-legend">
<div class="legend-item"> <div class="legend-item">
<div class="legend-color" style="background: #5dade2"></div> <div class="legend-color" style="background: #5dade2"></div>
<span>已排产</span> <span>{{ t('GanttChart.CardView.legendScheduled') }}</span>
</div> </div>
<div class="legend-item"> <div class="legend-item">
<div class="legend-color" style="background: #52c41a"></div> <div class="legend-color" style="background: #52c41a"></div>
<span>已并工</span> <span>{{ t('GanttChart.CardView.legendMerged') }}</span>
</div> </div>
<div class="legend-item"> <div class="legend-item">
<div class="legend-color" style="background: #faad14"></div> <div class="legend-color" style="background: #faad14"></div>
<span>暂停</span> <span>{{ t('GanttChart.CardView.legendPaused') }}</span>
</div> </div>
<div class="legend-item"> <div class="legend-item">
<div class="legend-color" style="background: #ff7875"></div> <div class="legend-color" style="background: #ff7875"></div>
<span>待入库</span> <span>{{ t('GanttChart.CardView.legendPendingStorage') }}</span>
</div> </div>
<div class="legend-item"> <div class="legend-item">
<div class="legend-color" style="background: #b37feb"></div> <div class="legend-color" style="background: #b37feb"></div>
<span>已入库</span> <span>{{ t('GanttChart.CardView.legendStored') }}</span>
</div> </div>
</div> </div>
<div class="toolbar-actions"> <div class="toolbar-actions">
<el-button <el-button circle @click="emit('refresh')">
circle
@click="emit('refresh')"
>
<el-icon><Refresh /></el-icon> <el-icon><Refresh /></el-icon>
</el-button> </el-button>
<el-button <el-button circle @click="toggleFullscreen">
circle
@click="toggleFullscreen"
>
<el-icon><FullScreen /></el-icon> <el-icon><FullScreen /></el-icon>
</el-button> </el-button>
</div> </div>
</div> </div>
<!-- 设备卡片列表 -->
<div class="device-cards-container"> <div class="device-cards-container">
<div v-for="device in scheduleList" :key="device.deviceId" class="device-card"> <div v-for="device in scheduleList" :key="device.deviceId" class="device-card">
<!-- 设备信息头 -->
<div class="device-header"> <div class="device-header">
<div class="device-info"> <div class="device-info">
<div class="device-name">{{ device.deviceName }}</div> <div class="device-name">{{ device.deviceName }}</div>
@ -51,17 +42,16 @@
</div> </div>
<div class="device-stats"> <div class="device-stats">
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">计划数</span> <span class="stat-label">{{ t('GanttChart.CardView.statPlanCount') }}</span>
<span class="stat-value">{{ device.plans?.length || 0 }}</span> <span class="stat-value">{{ device.plans?.length || 0 }}</span>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">产能</span> <span class="stat-label">{{ t('GanttChart.CardView.statCapacity') }}</span>
<span class="stat-value">{{ device.ratedCapacity || '-' }}</span> <span class="stat-value">{{ device.ratedCapacity || '-' }}</span>
</div> </div>
</div> </div>
</div> </div>
<!-- 计划卡片列表 -->
<div class="plans-container"> <div class="plans-container">
<div <div
v-for="plan in device.plans" v-for="plan in device.plans"
@ -77,36 +67,35 @@
</div> </div>
<div class="plan-content"> <div class="plan-content">
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">计划编号:</span> <span class="plan-label">{{ t('GanttChart.CardView.planCodeLabel') }}</span>
<span class="plan-value">{{ plan.taskCode }}</span> <span class="plan-value">{{ plan.taskCode }}</span>
</div> </div>
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">产品:</span> <span class="plan-label">{{ t('GanttChart.CardView.productLabel') }}</span>
<span class="plan-value">{{ plan.productCode }} / {{ plan.productName }}</span> <span class="plan-value">{{ plan.productCode }} / {{ plan.productName }}</span>
</div> </div>
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">计划数量:</span> <span class="plan-label">{{ t('GanttChart.CardView.planNumberLabel') }}</span>
<span class="plan-value">{{ plan.planNumber }}</span> <span class="plan-value">{{ plan.planNumber }}</span>
</div> </div>
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">交货日期:</span> <span class="plan-label">{{ t('GanttChart.CardView.deliveryDateLabel') }}</span>
<span class="plan-value">{{ plan.deliveryDateStr || '-' }}</span> <span class="plan-value">{{ plan.deliveryDateStr || '-' }}</span>
</div> </div>
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">开始:</span> <span class="plan-label">{{ t('GanttChart.CardView.startLabel') }}</span>
<span class="plan-value">{{ plan.planStartTimeStr }}</span> <span class="plan-value">{{ plan.planStartTimeStr }}</span>
</div> </div>
<div class="plan-row"> <div class="plan-row">
<span class="plan-label">结束:</span> <span class="plan-label">{{ t('GanttChart.CardView.endLabel') }}</span>
<span class="plan-value">{{ plan.planEndTimeStr }}</span> <span class="plan-value">{{ plan.planEndTimeStr }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- 空状态 -->
<div v-if="!device.plans || device.plans.length === 0" class="empty-state"> <div v-if="!device.plans || device.plans.length === 0" class="empty-state">
<el-empty description="暂无计划" :image-size="40" /> <el-empty :description="t('GanttChart.CardView.emptyDescription')" :image-size="40" />
</div> </div>
</div> </div>
</div> </div>
@ -115,8 +104,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { FullScreen, Refresh } from '@element-plus/icons-vue' import { FullScreen, Refresh } from '@element-plus/icons-vue'
import { useI18n } from '@/hooks/web/useI18n'
defineOptions({ name: 'ScheduleCardView' }) defineOptions({ name: 'ScheduleCardView' })
const { t } = useI18n()
type UnifiedPlan = { type UnifiedPlan = {
planId: number planId: number
planCode: string planCode: string
@ -167,17 +160,25 @@ onBeforeUnmount(() => {
} }
}) })
// const PLAN_STATUS_I18N_MAP: Record<number, string> = {
const planStatusMap: Record<number, { label: string; color: string }> = { 1: 'GanttChart.CardView.statusScheduled',
1: { label: '已排产', color: '#5dade2' }, 3: 'GanttChart.CardView.statusMerged',
3: { label: '已并工', color: '#52c41a' }, 5: 'GanttChart.CardView.statusPaused',
5: { label: '暂停', color: '#faad14' }, 8: 'GanttChart.CardView.statusPendingStorage',
8: { label: '待入库', color: '#ff7875' }, 9: 'GanttChart.CardView.statusStored'
9: { label: '已入库', color: '#b37feb' } }
const planStatusMap: Record<number, { color: string }> = {
1: { color: '#5dade2' },
3: { color: '#52c41a' },
5: { color: '#faad14' },
8: { color: '#ff7875' },
9: { color: '#b37feb' }
} }
const getPlanStatusLabel = (status: number) => { const getPlanStatusLabel = (status: number) => {
return planStatusMap[status]?.label || '未知' const i18nKey = PLAN_STATUS_I18N_MAP[status]
return i18nKey ? t(i18nKey) : t('GanttChart.CardView.statusUnknown')
} }
const getPlanStatusColor = (status: number) => { const getPlanStatusColor = (status: number) => {
@ -251,7 +252,6 @@ const getPlanStatusColor = (status: number) => {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
/* 隐藏滚动条但保留滚动功能 */
.device-cards-container::-webkit-scrollbar { .device-cards-container::-webkit-scrollbar {
height: 6px; height: 6px;
} }

@ -1,25 +1,25 @@
<template> <template>
<ContentWrap> <ContentWrap>
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto"> <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto">
<el-form-item label="查询时间" prop="range"> <el-form-item :label="t('GanttChart.Index.searchTimeLabel')" prop="range">
<el-date-picker <el-date-picker
v-model="queryRange" v-model="queryRange"
type="datetimerange" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
range-separator="-" range-separator="-"
start-placeholder="开始时间" :start-placeholder="t('GanttChart.Index.startPlaceholder')"
end-placeholder="结束时间" :end-placeholder="t('GanttChart.Index.endPlaceholder')"
class="!w-360px" class="!w-360px"
/> />
</el-form-item> </el-form-item>
<el-form-item label="设备" prop="deviceIds"> <el-form-item :label="t('GanttChart.Index.deviceLabel')" prop="deviceIds">
<el-select v-model="queryParams.deviceIds" placeholder="请选择设备" clearable multiple collapse-tags class="!w-240px"> <el-select v-model="queryParams.deviceIds" :placeholder="t('GanttChart.Index.devicePlaceholder')" clearable multiple collapse-tags class="!w-240px">
<el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />查询</el-button> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />{{ t('GanttChart.Index.buttonSearch') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />{{ t('GanttChart.Index.buttonReset') }}</el-button>
<el-button circle @click="toggleViewMode"> <el-button circle @click="toggleViewMode">
<el-icon><Switch /></el-icon> <el-icon><Switch /></el-icon>
</el-button> </el-button>
@ -46,9 +46,12 @@ import { PlanApi } from '@/api/mes/plan'
import ScheduleGanttPanel from '@/views/mes/components/ScheduleGanttPanel.vue' import ScheduleGanttPanel from '@/views/mes/components/ScheduleGanttPanel.vue'
import ScheduleCardView from '@/views/mes/ganttChart/components/ScheduleCardView.vue' import ScheduleCardView from '@/views/mes/ganttChart/components/ScheduleCardView.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useI18n } from '@/hooks/web/useI18n'
defineOptions({ name: 'MesGanttChart' }) defineOptions({ name: 'MesGanttChart' })
const { t } = useI18n()
type UnifiedPlan = { type UnifiedPlan = {
taskId: string | number taskId: string | number
taskDetailId: string | number taskDetailId: string | number

Loading…
Cancel
Save