From a34feddd4a4f0ee848b3d8670d65e5cdbfd0f26b Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sun, 27 Sep 2026 22:07:54 +0800 Subject: [PATCH] feat(admin): narrow sailing calendar to read-only display --- .../pages/SailingCalendarView.vue | 59 +++---------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/src/modules/sailing-calendar/pages/SailingCalendarView.vue b/src/modules/sailing-calendar/pages/SailingCalendarView.vue index 3e62ef19..5b809f3d 100644 --- a/src/modules/sailing-calendar/pages/SailingCalendarView.vue +++ b/src/modules/sailing-calendar/pages/SailingCalendarView.vue @@ -20,15 +20,13 @@ import { getSailingVolumeDetail, listSailingChannels, listSailingCalendar, - listSailingExceptions, listSailingTemplates, previewSailingTemplateGeneration, - reassignSailingAssignment, updateSailingChannel, updateSailingTemplate, updateSailing, } from '../api/platformSailingCalendar' -import type { SailingAssignment, SailingBookingAdvice, SailingCalendarEntry, SailingCalendarFilterOptions, SailingCalendarResponse, SailingChannelResource, SailingChannelSaveRequest, SailingChannelSourceType, SailingExceptionPage, SailingHistory, SailingSaveRequest, SailingStatus, SailingTemplateResource, SailingTemplateSaveRequest, SailingVolumeDetail } from '../types' +import type { SailingBookingAdvice, SailingCalendarEntry, SailingCalendarFilterOptions, SailingCalendarResponse, SailingChannelResource, SailingChannelSaveRequest, SailingChannelSourceType, SailingHistory, SailingSaveRequest, SailingStatus, SailingTemplateResource, SailingTemplateSaveRequest, SailingVolumeDetail } from '../types' interface CalendarCell { date: string; day: number; currentMonth: boolean; records: SailingCalendarEntry[] } @@ -40,10 +38,6 @@ const data = ref(null) const loading = ref(false) const error = ref(null) const query = reactive({ warehouseId: '', channelCode: '', departurePortCode: '', destinationPortCode: '', keyword: '', status: '' as '' | SailingStatus }) -const exceptionsOpen = ref(false) -const exceptionsLoading = ref(false) -const exceptionsError = ref(null) -const exceptions = ref({ records: [], page: 1, size: 20, total: 0, pages: 0 }) const selectedSailing = ref(null) const dialogOpen = ref(false) const dialogMode = ref<'create' | 'edit'>('create') @@ -57,10 +51,6 @@ const volumeDetail = ref(null) const adviceOpen = ref(false) const adviceLoading = ref(false) const bookingAdvice = ref(null) -const reassignmentOpen = ref(false) -const reassignmentSaving = ref(false) -const reassignmentAssignment = ref(null) -const reassignmentForm = reactive({ targetSailingId: '', targetSailingVersion: 0, reason: '' }) const form = reactive(blankForm()) const managementOpen = ref(false) const managementTab = ref<'channels' | 'templates'>('channels') @@ -125,10 +115,10 @@ const summaryCards = computed(() => { const summary = data.value?.summary return [ { label: '已收实测', value: decimal(summary?.actualReceivedCbm || 0), tone: 'blue' }, - { label: '准时可赶实收', value: decimal(summary?.catchableReceivedCbm || 0), tone: 'green' }, - { label: '晚到实收', value: decimal(summary?.lateReceivedCbm || 0), tone: 'orange' }, - { label: '预计可赶', value: decimal(summary?.catchableForecastCbm || 0), tone: 'green' }, - { label: '风险 / 未安排', value: decimal(summary?.riskUnmatchedCbm || 0), tone: 'orange' }, + { label: '截止前参考实收', value: decimal(summary?.catchableReceivedCbm || 0), tone: 'green' }, + { label: '截止后 / 风险实收', value: decimal(summary?.lateReceivedCbm || 0), tone: 'orange' }, + { label: '预计参考量', value: decimal(summary?.catchableForecastCbm || 0), tone: 'green' }, + { label: '待确认货量', value: decimal(summary?.riskUnmatchedCbm || 0), tone: 'orange' }, { label: '已订柜 / 建议', value: `${summary?.bookedContainerCount || 0} / ${summary?.recommendedContainerCount || 0}`, tone: 'purple' }, { label: '待补柜', value: String(summary?.pendingContainerCount || 0), tone: 'red' }, ] @@ -136,11 +126,6 @@ const summaryCards = computed(() => { const canCreate = computed(() => access.can('platform:firstleg:sailing-calendar:create')) const canEdit = computed(() => access.can('platform:firstleg:sailing-calendar:edit')) const canManageTemplates = computed(() => access.can('platform:firstleg:sailing-template:manage')) -const canReassign = computed(() => access.can('platform:firstleg:sailing-volume:exception-reassign')) -const reassignmentTargets = computed(() => (data.value?.records || []).filter((record) => { - const source = selectedSailing.value - return record.id !== source?.id && record.status === 'OPEN' && record.warehouseId === source?.warehouseId && record.channelCode === source?.channelCode && record.departurePortCode === source?.departurePortCode && record.destinationPortCode === source?.destinationPortCode -})) async function load() { loading.value = true @@ -156,18 +141,6 @@ async function load() { loading.value = false } } -async function openExceptions() { - exceptionsOpen.value = true - exceptionsLoading.value = true - exceptionsError.value = null - try { - exceptions.value = await listSailingExceptions({ warehouseId: query.warehouseId || undefined, channelCode: query.channelCode || undefined, page: 1, size: 50 }) - } catch (cause) { - exceptionsError.value = getApiErrorDetails(cause, '异常待办加载失败') - } finally { - exceptionsLoading.value = false - } -} function changeMonth(delta: number) { const next = parseMonth(month.value) next.setMonth(next.getMonth() + delta) @@ -251,19 +224,6 @@ async function generateTemplate(row: unknown) { try { await ElMessageBox.confirm(`确认按模板“${templateRow.templateNo}”生成选定有效期内的船期?重复日期会由服务端跳过。`, '批量生成船期', { type: 'warning', confirmButtonText: '确认生成', cancelButtonText: '返回' }); templateGenerateLoading.value = true; const result = await generateSailingTemplate(templateRow.id, { from: templateRow.effectiveFrom, to: templateRow.effectiveTo || `${month.value}-28` }); ElMessage.success(`生成完成:${result.generatedCount} 个,跳过 ${result.skippedCount} 个`); await load(); await openManagement('templates') } catch (cause) { if (cause !== 'cancel') ElMessage.error(getApiErrorDetails(cause, '批量生成失败').message) } finally { templateGenerateLoading.value = false } } function formatWeekdays(value: unknown) { return Array.isArray(value) ? value.map((day: unknown) => ['一', '二', '三', '四', '五', '六', '日'][Number(day) - 1]).join('、') : '—' } -function openReassignment(row: unknown) { reassignmentAssignment.value = row as SailingAssignment; Object.assign(reassignmentForm, { targetSailingId: '', targetSailingVersion: 0, reason: '' }); reassignmentOpen.value = true } -async function saveReassignment() { - const target = reassignmentTargets.value.find((record) => record.id === reassignmentForm.targetSailingId) - if (!selectedSailing.value || !reassignmentAssignment.value || !target || !reassignmentForm.reason.trim()) { ElMessage.error('请选择符合仓库、渠道和航线的目标船期,并填写重新安排原因'); return } - reassignmentSaving.value = true - try { - await reassignSailingAssignment(selectedSailing.value.id, { assignmentId: reassignmentAssignment.value.id, targetSailingId: target.id, expectedAssignmentVersion: reassignmentAssignment.value.assignmentVersion ?? 1, expectedTargetVersion: target.version, reason: reassignmentForm.reason.trim() }) - ElMessage.success('已提交重新安排') - reassignmentOpen.value = false - await openVolumeDetail() - await load() - } catch (cause) { ElMessage.error(getApiErrorDetails(cause, '重新安排提交失败').message) } finally { reassignmentSaving.value = false } -} function openCreate() { dialogMode.value = 'create'; Object.assign(form, blankForm()); dialogOpen.value = true } function openEdit(record: SailingCalendarEntry) { dialogMode.value = 'edit'; Object.assign(form, { templateId: null, channelId: null, warehouseId: record.warehouseId, warehouseName: record.warehouseName, channelCode: record.channelCode, channelName: record.channelName, vesselName: record.vesselName, voyageNo: record.voyageNo, departurePortCode: record.departurePortCode, departurePortName: record.departurePortName || '', destinationPortCode: record.destinationPortCode, destinationPortName: record.destinationPortName || '', etdAt: record.etdAt.slice(0, 19), etaAt: null, cutoffAt: record.cutoffAt.slice(0, 19), sourceType: 'MANUAL', plannedCapacityCbm: null, remark: record.remark || '', expectedVersion: record.version }); dialogOpen.value = true } function onEtdChanged() { if (dialogMode.value === 'create') form.cutoffAt = cutoffFor(form.etdAt) } @@ -329,7 +289,6 @@ onMounted(() => void load()) 重置 - 待安排 / 异常 渠道与周模板 新增船期 @@ -346,10 +305,8 @@ onMounted(() => void load()) -
此清单不受当前月份限制,只展示当前权限和筛选范围内仍待处理的未安排、晚到货量。
-
-
- 当前月没有可选目标,请先切换月份后再打开详情。
+
+
停用渠道仍保留历史船期,但不能新建模板或生成未来船期。新增渠道
按周几生成前先预览,生成操作使用服务端幂等键。新增周模板
周{{ ['一', '二', '三', '四', '五', '六', '日'][day - 1] }}

生成预览({{ templatePreview.length }} 条)

@@ -359,3 +316,5 @@ onMounted(() => void load()) + +