fix: keep appointment calendar day previews compact

This commit is contained in:
2026-10-09 12:03:25 +08:00
parent 8bf0e2260e
commit 8a2f3378f6
3 changed files with 27 additions and 9 deletions
@@ -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')
@@ -84,13 +84,13 @@ defineExpose({ selectedDate, mode })
<div v-loading="loading" class="calendar-grid" :class="{ 'week-grid': mode === 'week' }">
<button v-for="date in dates" :key="date" type="button" class="calendar-day"
:class="{ selected: selectedDate === date, outside: mode === 'month' && date.slice(0, 7) !== selectedDate.slice(0, 7) }"
:aria-label="`${date},${(grouped.get(date) || []).length} 项安排`" :aria-pressed="selectedDate === date" @click="select(date)">
:title="`${date},共 ${(grouped.get(date) || []).length} 条安排`" :aria-label="`${date},${(grouped.get(date) || []).length} 项安排`" :aria-pressed="selectedDate === date" @click="select(date)">
<span class="day-number">{{ mode === 'week' ? `${Number(date.slice(5, 7))}月` : '' }}{{ Number(date.slice(8)) }}</span>
<span class="day-events">
<span v-for="event in (grouped.get(date) || []).slice(0, mode === 'month' ? 3 : 12)" :key="event.key" class="event-chip" :class="event.type" :title="`${event.time} ${event.title}`">
<span v-for="event in (grouped.get(date) || []).slice(0, 3)" :key="event.key" class="event-chip" :class="event.type" :title="`${event.time} ${event.title} · 当天共 ${(grouped.get(date) || []).length} 条安排`">
{{ event.title }}<small v-if="mode === 'week'">{{ event.time }}</small>
</span>
<span v-if="(grouped.get(date) || []).length > (mode === 'month' ? 3 : 12)" class="event-more">另有 {{ (grouped.get(date) || []).length - (mode === 'month' ? 3 : 12) }} 项</span>
<span v-if="(grouped.get(date) || []).length > 3" class="event-more">还有 {{ (grouped.get(date) || []).length - 3 }} 条</span>
</span>
</button>
</div>
@@ -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; }
@@ -12,7 +12,7 @@
| 到港详情 | 当天安排右侧只读 | 使用货柜/船节点事实,无逐行详情请求,无模拟到港数据 |
| 删除预约 | 二次确认 | 显式提示全部货物解除预约关联;独立删除权限,已关联有效排车拒绝删除 |
| 月/周切换 | 顶部切换与前后按钮 | 周模式按7天移动,修正原型仍按月移动的问题 |
| 多条安排 | 日历标签、右侧明细 | 日格限制显示数量并提示剩余条目,右侧全部展示 |
| 多条安排 | 日历标签、右侧明细 | 月/周日格均最多显示3条,超出显示“还有N条”,悬停显示当天总数;日格固定高度,右侧全部展示并独立滚动 |
预约结束时间未明确时允许为空;不把预计装车时间当结束时间。预约号、目的仓和货物来源遵守服务端合同。日历范围最多42天,每次范围变化查询预约与到港各一次;选择范围内日期不发送请求。候选只在用户点击查询时分页读取,跨页选择保留,重新查询清空。