feat(appointment): complete customer receiving and trip continuation workflows

This commit is contained in:
2026-10-16 15:41:56 +08:00
parent 148085286d
commit 45f662ecf2
45 changed files with 2042 additions and 131 deletions
@@ -25,7 +25,7 @@ function arrivalCount(date: string) { return props.arrivals.filter(row => row.ar
<div class="work-layers"><span class="muted">显示类型</span><label v-for="type in workTypes" :key="type" :data-type="type"><input type="checkbox" :checked="types.includes(type)" @change="toggle(type, ($event.target as HTMLInputElement).checked)">{{ typeLabels[type] }}</label><label><input type="checkbox" :checked="reference" @change="emit('reference', ($event.target as HTMLInputElement).checked)">到港参考</label></div>
<div class="calendar-counts" aria-live="polite">
<span v-if="loading">正在读取工作统计…</span><span v-else-if="failed">工作统计加载失败</span><span v-else-if="!types.length">未勾选工作类型,全局待办仍可查看</span>
<template v-else-if="calendar"><strong>当前显示区间 {{ calendar.from }} ~ {{ calendar.to }} · {{ calendar.total }} 项工作</strong><span>待安排 {{ calendar.counts.pending }}</span><span>已落实 {{ calendar.counts.confirmed }}</span><span>无需预约 {{ calendar.counts.noBookingRequired }}</span><span>需复核 {{ calendar.counts.review }}</span><span>已完成 {{ calendar.counts.completed }}</span></template>
<template v-else-if="calendar"><strong>当前显示区间 {{ calendar.from }} ~ {{ calendar.to }} · {{ calendar.total }} 项工作</strong><span :class="{ 'is-zero': calendar.counts.pending === 0 }">待安排 {{ calendar.counts.pending }}</span><span :class="{ 'is-zero': calendar.counts.confirmed === 0 }">已落实 {{ calendar.counts.confirmed }}</span><span :class="{ 'is-zero': calendar.counts.noBookingRequired === 0 }">无需预约 {{ calendar.counts.noBookingRequired }}</span><span :class="{ 'is-zero': calendar.counts.review === 0 }">需复核 {{ calendar.counts.review }}</span><span :class="{ 'is-zero': calendar.counts.completed === 0 }">已完成 {{ calendar.counts.completed }}</span></template>
</div>
<div class="weekdays"><span v-for="day in ['一', '二', '三', '四', '五', '六', '日']" :key="day">周{{ day }}</span></div>
<div class="calendar-days">
@@ -48,25 +48,29 @@ function arrivalCount(date: string) { return props.arrivals.filter(row => row.ar
.work-layers, .calendar-counts { padding: var(--admin-space-2) var(--admin-space-5); border-top: 1px solid var(--cc-border); }
.work-layers label { display: inline-flex; align-items: center; gap: var(--admin-space-2); cursor: pointer; }
.calendar-counts { min-height: 24px; font-size: var(--admin-font-caption); }
.calendar-counts .is-zero { color: var(--el-text-color-secondary); }
.weekdays, .calendar-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.weekdays { text-align: center; padding-block: var(--admin-space-3); background: var(--el-fill-color-light); }
.work-day { min-height: 112px; box-sizing: border-box; border-top: 1px solid var(--cc-border); border-right: 1px solid var(--cc-border); padding: var(--admin-space-1); }
.week-view .work-day { min-height: 240px; }
.weekdays span:nth-last-child(-n+2) { color: var(--el-text-color-secondary); }
.work-day { height: 146px; min-height: 146px; max-height: 146px; box-sizing: border-box; border-top: 1px solid var(--cc-border); border-right: 1px solid var(--cc-border); padding: var(--admin-space-1); }
.week-view .work-day { height: 270px; min-height: 270px; max-height: 270px; }
.work-day:nth-child(7n) { border-right: 0; }
.outside { background: var(--el-fill-color-lighter); }
.work-calendar .day-heading { display: flex; align-items: center; gap: var(--admin-space-1); width: 100%; border: 0; padding: 0; min-height: 24px; background: transparent; margin-bottom: var(--admin-space-1); }
.date-number { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; border-radius: 50%; }
.date-number { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; border-radius: 50%; font-weight: 600; font-variant-numeric: tabular-nums; }
.is-today .date-number { color: var(--el-color-white); background: var(--el-color-primary); font-weight: 600; }
.today-mark { color: var(--el-color-primary); font-size: var(--admin-font-caption); }
.day-total { margin-left: auto; color: var(--el-text-color-secondary); font-size: var(--admin-font-caption); }
.work-day.is-selected { box-shadow: inset 0 0 0 2px var(--el-color-primary); background: var(--el-color-primary-light-9); }
.outside .day-heading { color: var(--el-text-color-secondary); }
.type-counts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: minmax(24px, auto); gap: 2px; }
.work-calendar .type-counts button { display: flex; align-items: center; justify-content: space-between; gap: 2px; border: 1px solid currentColor; padding: 0 3px; font-size: var(--admin-font-caption); background: transparent; min-width: 0; min-height: 24px; white-space: nowrap; }
.type-counts button[aria-pressed=true] { background: var(--admin-surface); box-shadow: inset 0 0 0 1px currentColor; }
.type-counts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: minmax(24px, auto); gap: var(--admin-space-1); }
.work-calendar .type-counts button { display: flex; align-items: center; justify-content: space-between; gap: 2px; border: 1px solid color-mix(in srgb, currentColor 20%, transparent); padding: 0 var(--admin-space-1); font-size: var(--admin-font-caption); background: color-mix(in srgb, currentColor 7%, var(--admin-surface)); min-width: 0; min-height: 24px; white-space: nowrap; }
.work-calendar .type-counts button:hover:not(:disabled) { border-color: currentColor; background: color-mix(in srgb, currentColor 12%, var(--admin-surface)); }
.work-calendar .type-counts button[aria-pressed=true] { border-color: currentColor; background: color-mix(in srgb, currentColor 14%, var(--admin-surface)); box-shadow: inset 0 0 0 1px currentColor; }
.type-counts b { font-variant-numeric: tabular-nums; }
[data-type=PICKUP] { color: var(--el-color-primary); } [data-type=WAREHOUSE_RECEIPT] { color: #8356ad; } [data-type=DELIVERY] { color: #27815c; } [data-type=TRANSPORT] { color: #b26a12; } [data-type=EMPTY_RETURN] { color: #a64f69; }
.work-calendar .arrival-reference { border: 0; background: transparent; padding: 0; min-height: 24px; font-size: var(--admin-font-caption); color: var(--el-text-color-secondary); }
.work-calendar .arrival-reference { display: block; border: 0; background: transparent; padding: 0 var(--admin-space-1); margin-top: var(--admin-space-1); min-height: 24px; font-size: var(--admin-font-caption); color: var(--el-text-color-secondary); }
.work-calendar .arrival-reference:hover { color: var(--el-text-color-regular); background: var(--el-fill-color-light); }
footer { padding: var(--admin-space-3) var(--admin-space-5); }
button { font: inherit; cursor: pointer; border-radius: var(--admin-radius); min-height: var(--admin-control-height); color: inherit; border: 1px solid var(--cc-border); background: var(--admin-surface); padding: 0 var(--admin-space-3); }
.view-switch { display: inline-flex; }