diff --git a/src/modules/appointment-calendar/AppointmentCalendarPanel.test.ts b/src/modules/appointment-calendar/AppointmentCalendarPanel.test.ts index 4870fa91..141ca57d 100644 --- a/src/modules/appointment-calendar/AppointmentCalendarPanel.test.ts +++ b/src/modules/appointment-calendar/AppointmentCalendarPanel.test.ts @@ -25,6 +25,22 @@ describe('appointment calendar interactions', () => { expect(wrapper.emitted('range')?.at(-1)).toEqual([{ from: '2026-09-28', to: '2026-10-05' }]) }) + it('keeps busy days to three previews in both views and exposes the full count', async () => { + const wrapper = render() + await wrapper.setProps({ events: Array.from({ length: 233 }, (_, index) => ({ + key: `arrival-${index}`, type: 'arrival' as const, date: '2026-09-24', time: '09:00', + title: `船舶 ${index}`, fields: [], + })) }) + for (const view of ['month', 'week']) { + if (view === 'week') await wrapper.get('[aria-label="预约视图"]').findAll('button')[1]!.trigger('click') + const day = wrapper.get('[aria-label="2026-09-24,233 项安排"]') + expect(day.findAll('.event-chip')).toHaveLength(3) + expect(day.attributes('title')).toContain('共 233 条安排') + expect(day.get('.event-more').text()).toBe('还有 230 条') + expect(wrapper.findAll('.detail-event')).toHaveLength(233) + } + }) + it('uses the selected day for creation and emits edit/delete only from detail actions', async () => { const wrapper = render() await wrapper.findAll('button').find(button => button.text() === '+ 新增预约')!.trigger('click') diff --git a/src/modules/appointment-calendar/AppointmentCalendarPanel.vue b/src/modules/appointment-calendar/AppointmentCalendarPanel.vue index 108e3896..dfa6a354 100644 --- a/src/modules/appointment-calendar/AppointmentCalendarPanel.vue +++ b/src/modules/appointment-calendar/AppointmentCalendarPanel.vue @@ -84,13 +84,13 @@ defineExpose({ selectedDate, mode })
@@ -131,19 +131,21 @@ defineExpose({ selectedDate, mode }) .weekdays, .calendar-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); } .weekdays { text-align: center; color: #8491a5; background: #f8faff; padding: 12px 14px; font-size: 13px; } .calendar-grid { gap: 7px; padding: 12px; background: #fbfcff; } -.calendar-day { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; min-height: 100px; padding: 8px; border: 1px solid #e5eaf2; border-radius: 8px; background: #fff; text-align: left; cursor: pointer; color: inherit; font: inherit; overflow: hidden; } +.calendar-day { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; height: 128px; min-width: 0; padding: 8px; border: 1px solid #e5eaf2; border-radius: 8px; background: #fff; text-align: left; cursor: pointer; color: inherit; font: inherit; overflow: hidden; } .calendar-day.outside { background: #f7f8fa; color: #98a2b3; } +.calendar-day:hover { border-color: #bac8ed; background: #f8faff; } .calendar-day.selected { border-color: #617ce9; background: #f5f7ff; } .calendar-day:focus-visible, .nav-button:focus-visible, .view-toggle button:focus-visible { outline: 2px solid #4167d8; outline-offset: 2px; } .day-number { display: block; font-size: 12px; font-weight: 600; } -.day-events { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; } -.event-chip { display: block; padding: 4px 6px; border-radius: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; } +.day-events { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; } +.event-chip { display: block; padding: 3px 6px; line-height: 16px; border-radius: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; } .arrival { --event-bg: #edf3ff; --event-fg: #3765d4; } .delivery { --event-bg: #e8f8f1; --event-fg: #18845f; } .event-chip, .event-type { background: var(--event-bg); color: var(--event-fg); } -.event-chip small { display: block; margin-top: 4px; } +.event-chip small { display: block; margin-top: 2px; font-size: 11px; opacity: .8; } +.event-more { padding: 1px 6px; line-height: 16px; } .event-more, .empty-day { color: #667085; font-size: 12px; } -.week-grid .calendar-day { min-height: 350px; align-content: start; } +.week-grid .calendar-day { height: 220px; } .calendar-detail { align-self: start; } .calendar-detail > header { padding: 18px; border-bottom: 1px solid #edf0f6; } .calendar-detail > header > strong { font-size: 17px; } diff --git a/src/modules/appointment-calendar/PROTOTYPE_MATRIX.md b/src/modules/appointment-calendar/PROTOTYPE_MATRIX.md index 37f47e98..c5095740 100644 --- a/src/modules/appointment-calendar/PROTOTYPE_MATRIX.md +++ b/src/modules/appointment-calendar/PROTOTYPE_MATRIX.md @@ -12,7 +12,7 @@ | 到港详情 | 当天安排右侧只读 | 使用货柜/船节点事实,无逐行详情请求,无模拟到港数据 | | 删除预约 | 二次确认 | 显式提示全部货物解除预约关联;独立删除权限,已关联有效排车拒绝删除 | | 月/周切换 | 顶部切换与前后按钮 | 周模式按7天移动,修正原型仍按月移动的问题 | -| 多条安排 | 日历标签、右侧明细 | 日格限制显示数量并提示剩余条目,右侧全部展示 | +| 多条安排 | 日历标签、右侧明细 | 月/周日格均最多显示3条,超出显示“还有N条”,悬停显示当天总数;日格固定高度,右侧全部展示并独立滚动 | 预约结束时间未明确时允许为空;不把预计装车时间当结束时间。预约号、目的仓和货物来源遵守服务端合同。日历范围最多42天,每次范围变化查询预约与到港各一次;选择范围内日期不发送请求。候选只在用户点击查询时分页读取,跨页选择保留,重新查询清空。