优化V4订单事项办理页视觉交互
This commit is contained in:
@@ -26,44 +26,11 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ReservationV4RoomInformationCard
|
||||
v-if="isRoomInformationCard"
|
||||
class="task-card-section__fields"
|
||||
:card="card"
|
||||
:model-value="modelValue"
|
||||
:read-only="readOnly"
|
||||
:editable-keys="editableKeys"
|
||||
:validation-errors="validationErrors"
|
||||
:hotel-id="hotelId"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
<template v-else>
|
||||
<ReservationV4RoomingListCard
|
||||
v-if="isRoomingListCard"
|
||||
:order-reference="orderReference"
|
||||
:target-locator="targetLocator"
|
||||
:bound-order-id="boundOrderId"
|
||||
:bound-order-display-name="boundOrderDisplayName"
|
||||
/>
|
||||
<ReservationV4PaymentAttachmentPreview
|
||||
v-else-if="isPaymentCard"
|
||||
:card="card"
|
||||
:source-message-id="sourceMessageId"
|
||||
/>
|
||||
<ReservationV4TraceCard
|
||||
v-else-if="isTraceCard"
|
||||
:card="card"
|
||||
:model-value="modelValue"
|
||||
:read-only="readOnly"
|
||||
:editable-keys="editableKeys"
|
||||
:validation-errors="validationErrors"
|
||||
:hotel-id="hotelId"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
<ReservationV4TaskCardFieldRenderer
|
||||
v-else
|
||||
<div class="task-card-section__body">
|
||||
<ReservationV4RoomInformationCard
|
||||
v-if="isRoomInformationCard"
|
||||
class="task-card-section__fields"
|
||||
:fields="visibleFields"
|
||||
:card="card"
|
||||
:model-value="modelValue"
|
||||
:read-only="readOnly"
|
||||
:editable-keys="editableKeys"
|
||||
@@ -71,50 +38,85 @@
|
||||
:hotel-id="hotelId"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-if="actionErrors.length"
|
||||
class="action-message action-message--error"
|
||||
>
|
||||
<p
|
||||
v-for="message in actionErrors"
|
||||
:key="message"
|
||||
>
|
||||
{{ message }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="successMessage"
|
||||
class="action-message action-message--success"
|
||||
>
|
||||
{{ successMessage }}
|
||||
</p>
|
||||
|
||||
<div
|
||||
v-if="card.card_status === 'REVIEW_REQUIRED'"
|
||||
class="review-box"
|
||||
>
|
||||
<label>
|
||||
<span>{{ t('taskV4.confirmedOrderId') }}</span>
|
||||
<input
|
||||
name="v4_confirmed_order_id"
|
||||
:value="reviewForm.confirmed_order_id"
|
||||
:placeholder="t('taskV4.confirmedOrderIdPlaceholder')"
|
||||
@input="updateReviewForm('confirmed_order_id', $event)"
|
||||
>
|
||||
</label>
|
||||
<label>
|
||||
<span>{{ t('taskV4.reviewReason') }}</span>
|
||||
<textarea
|
||||
name="v4_review_reason"
|
||||
:value="reviewForm.reason"
|
||||
:placeholder="t('taskV4.reviewReasonPlaceholder')"
|
||||
rows="3"
|
||||
@input="updateReviewForm('reason', $event)"
|
||||
<template v-else>
|
||||
<ReservationV4RoomingListCard
|
||||
v-if="isRoomingListCard"
|
||||
:order-reference="orderReference"
|
||||
:target-locator="targetLocator"
|
||||
:bound-order-id="boundOrderId"
|
||||
:bound-order-display-name="boundOrderDisplayName"
|
||||
/>
|
||||
</label>
|
||||
<ReservationV4PaymentAttachmentPreview
|
||||
v-else-if="isPaymentCard"
|
||||
:card="card"
|
||||
:source-message-id="sourceMessageId"
|
||||
/>
|
||||
<ReservationV4TraceCard
|
||||
v-else-if="isTraceCard"
|
||||
:card="card"
|
||||
:model-value="modelValue"
|
||||
:read-only="readOnly"
|
||||
:editable-keys="editableKeys"
|
||||
:validation-errors="validationErrors"
|
||||
:hotel-id="hotelId"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
<ReservationV4TaskCardFieldRenderer
|
||||
v-else
|
||||
class="task-card-section__fields"
|
||||
:fields="visibleFields"
|
||||
:model-value="modelValue"
|
||||
:read-only="readOnly"
|
||||
:editable-keys="editableKeys"
|
||||
:validation-errors="validationErrors"
|
||||
:hotel-id="hotelId"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-if="actionErrors.length"
|
||||
class="action-message action-message--error"
|
||||
>
|
||||
<p
|
||||
v-for="message in actionErrors"
|
||||
:key="message"
|
||||
>
|
||||
{{ message }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="successMessage"
|
||||
class="action-message action-message--success"
|
||||
>
|
||||
{{ successMessage }}
|
||||
</p>
|
||||
|
||||
<div
|
||||
v-if="card.card_status === 'REVIEW_REQUIRED'"
|
||||
class="review-box"
|
||||
>
|
||||
<label>
|
||||
<span>{{ t('taskV4.confirmedOrderId') }}</span>
|
||||
<input
|
||||
name="v4_confirmed_order_id"
|
||||
:value="reviewForm.confirmed_order_id"
|
||||
:placeholder="t('taskV4.confirmedOrderIdPlaceholder')"
|
||||
@input="updateReviewForm('confirmed_order_id', $event)"
|
||||
>
|
||||
</label>
|
||||
<label>
|
||||
<span>{{ t('taskV4.reviewReason') }}</span>
|
||||
<textarea
|
||||
name="v4_review_reason"
|
||||
:value="reviewForm.reason"
|
||||
:placeholder="t('taskV4.reviewReasonPlaceholder')"
|
||||
rows="3"
|
||||
@input="updateReviewForm('reason', $event)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -261,15 +263,18 @@ function handlePrimaryAction(): void {
|
||||
<style scoped>
|
||||
.task-card-section {
|
||||
overflow: hidden;
|
||||
border-color: var(--th-color-slate-200);
|
||||
box-shadow: var(--th-shadow-sm);
|
||||
}
|
||||
|
||||
.task-card-section__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
border-bottom: 1px solid var(--th-color-slate-200);
|
||||
padding: 20px;
|
||||
background: linear-gradient(180deg, var(--th-color-white), var(--th-color-slate-50));
|
||||
padding: 18px 20px;
|
||||
}
|
||||
|
||||
.task-card-section__heading {
|
||||
@@ -289,21 +294,27 @@ function handlePrimaryAction(): void {
|
||||
.card-notice-list {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
border-bottom: 1px solid var(--th-color-slate-100);
|
||||
background: var(--th-color-slate-50);
|
||||
border-bottom: 1px solid var(--th-color-slate-200);
|
||||
background: var(--th-color-info-bg);
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.card-notice-list p {
|
||||
margin: 0;
|
||||
color: var(--th-color-slate-600);
|
||||
color: var(--th-color-slate-700);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
font-weight: 800;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.task-card-section__body {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
padding: 18px 20px 16px;
|
||||
}
|
||||
|
||||
.task-card-section__fields {
|
||||
padding: 0 20px 18px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
@@ -337,7 +348,9 @@ function handlePrimaryAction(): void {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
padding: 0 20px 20px;
|
||||
border-top: 1px solid var(--th-color-slate-100);
|
||||
background: var(--th-color-white);
|
||||
padding: 14px 20px 18px;
|
||||
}
|
||||
|
||||
.task-card-section__footer-actions {
|
||||
@@ -351,9 +364,10 @@ function handlePrimaryAction(): void {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
|
||||
gap: 12px;
|
||||
align-items: end;
|
||||
border-top: 1px solid var(--th-color-slate-200);
|
||||
background: linear-gradient(180deg, var(--th-color-white), var(--th-color-slate-50));
|
||||
padding: 16px 20px 18px;
|
||||
border: 1px solid var(--th-color-warning-bg);
|
||||
border-radius: var(--th-radius-md);
|
||||
background: var(--th-color-warning-bg);
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.review-box label {
|
||||
@@ -362,9 +376,9 @@ function handlePrimaryAction(): void {
|
||||
}
|
||||
|
||||
.review-box span {
|
||||
color: var(--th-color-slate-500);
|
||||
color: var(--th-color-slate-700);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.review-box input,
|
||||
@@ -386,10 +400,10 @@ function handlePrimaryAction(): void {
|
||||
}
|
||||
|
||||
.action-message {
|
||||
margin: 0 20px 18px;
|
||||
margin: 0;
|
||||
border-radius: var(--th-radius-sm);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
font-weight: 800;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
@@ -414,18 +428,23 @@ function handlePrimaryAction(): void {
|
||||
.card-order-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--th-color-blue-600);
|
||||
min-height: 38px;
|
||||
border: 1px solid var(--th-color-slate-200);
|
||||
border-radius: var(--th-radius-sm);
|
||||
background: var(--th-color-white);
|
||||
color: var(--th-color-slate-700);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
padding: 8px 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card-order-link:hover {
|
||||
text-decoration: underline;
|
||||
border-color: var(--th-color-blue-600);
|
||||
color: var(--th-color-blue-600);
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.task-card-section__header,
|
||||
.review-box {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -572,6 +572,16 @@ export default {
|
||||
title: 'Reservation item handling',
|
||||
subtitle: 'Handle the current reservation item from the source email.',
|
||||
orderTaskSummary: 'Item summary',
|
||||
handlingDesk: 'Handling overview',
|
||||
handlingDeskHint: 'Check the order clue and source, then confirm each item.',
|
||||
sourceEmail: 'Source email',
|
||||
sourceSender: 'Sender',
|
||||
sourceReceivedAt: 'Received at',
|
||||
cardProgress: 'Card progress',
|
||||
totalCards: 'Total',
|
||||
pendingCards: 'Pending',
|
||||
reviewCards: 'Review',
|
||||
confirmedCards: 'Confirmed',
|
||||
orderTaskId: 'Item ID',
|
||||
orderReference: 'Order reference',
|
||||
targetBookingType: 'Booking type',
|
||||
|
||||
@@ -572,6 +572,16 @@ export default {
|
||||
title: 'จัดการรายการจอง',
|
||||
subtitle: 'จัดการรายการจองปัจจุบันจากอีเมลต้นทาง',
|
||||
orderTaskSummary: 'สรุปรายการ',
|
||||
handlingDesk: 'ภาพรวมการจัดการ',
|
||||
handlingDeskHint: 'ตรวจข้อมูลออเดอร์และอีเมลต้นทาง แล้วค่อยยืนยันแต่ละรายการ',
|
||||
sourceEmail: 'อีเมลต้นทาง',
|
||||
sourceSender: 'ผู้ส่ง',
|
||||
sourceReceivedAt: 'เวลาที่ได้รับ',
|
||||
cardProgress: 'ความคืบหน้าการ์ด',
|
||||
totalCards: 'ทั้งหมด',
|
||||
pendingCards: 'รอยืนยัน',
|
||||
reviewCards: 'รอตรวจสอบ',
|
||||
confirmedCards: 'ยืนยันแล้ว',
|
||||
orderTaskId: 'รหัสรายการ',
|
||||
orderReference: 'อ้างอิงออเดอร์',
|
||||
targetBookingType: 'ประเภทการจอง',
|
||||
|
||||
@@ -572,6 +572,16 @@ export default {
|
||||
title: '订单事项办理',
|
||||
subtitle: '按来源邮件办理当前订单事项',
|
||||
orderTaskSummary: '事项摘要',
|
||||
handlingDesk: '办理概览',
|
||||
handlingDeskHint: '先核对订单线索和来源,再逐张确认事项。',
|
||||
sourceEmail: '来源邮件',
|
||||
sourceSender: '发件人',
|
||||
sourceReceivedAt: '收到时间',
|
||||
cardProgress: '卡片进度',
|
||||
totalCards: '全部',
|
||||
pendingCards: '待确认',
|
||||
reviewCards: '待复核',
|
||||
confirmedCards: '已确认',
|
||||
orderTaskId: '事项编号',
|
||||
orderReference: '订单引用',
|
||||
targetBookingType: '预订类型',
|
||||
|
||||
@@ -145,6 +145,30 @@ describe('reservation V4 pages', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('presents the order task as a restrained handling desk summary', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||
|
||||
const wrapper = await mountWithPlugins(
|
||||
ReservationV4OrderTaskDetailView,
|
||||
'/reservation/order-tasks/9001',
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const summary = wrapper.find('.handling-summary')
|
||||
expect(summary.exists()).toBe(true)
|
||||
expect(summary.text()).toContain('GRP-001')
|
||||
expect(summary.text()).toContain('Booking Request')
|
||||
expect(summary.text()).toContain('guest@example.test')
|
||||
expect(summary.text()).toContain(zhCN.taskV4.cardProgress)
|
||||
expect(summary.text()).toContain('3')
|
||||
expect(summary.text()).toContain('2')
|
||||
expect(summary.text()).toContain(zhCN.taskV4.pendingCards)
|
||||
expect(summary.text()).toContain(zhCN.taskV4.confirmedCards)
|
||||
expect(summary.text()).not.toContain('9001')
|
||||
expect(summary.text()).not.toContain(zhCN.taskV4.orderTaskId)
|
||||
})
|
||||
|
||||
it('keeps task card layout classes and places the primary card action in the card footer', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
detail.business_cards[0]!.card_type = 'VOUCHER'
|
||||
@@ -162,12 +186,15 @@ describe('reservation V4 pages', () => {
|
||||
|
||||
expect(wrapper.findAll('.task-card-section')).toHaveLength(2)
|
||||
expect(wrapper.find('.task-card-section__header').exists()).toBe(true)
|
||||
expect(wrapper.find('.task-card-section__body').exists()).toBe(true)
|
||||
expect(wrapper.find('.card-meta-grid').exists()).toBe(false)
|
||||
expect(wrapper.find('details.safe-payload').exists()).toBe(false)
|
||||
expect(wrapper.find('.task-card-section__header .primary-button').exists()).toBe(false)
|
||||
expect(wrapper.find('.task-card-section__footer .card-order-link').exists()).toBe(false)
|
||||
const firstCard = wrapper.find('.task-card-section')
|
||||
const footer = firstCard.find('.task-card-section__footer')
|
||||
expect(footer.exists()).toBe(true)
|
||||
expect(firstCard.find('.task-card-section__body').exists()).toBe(true)
|
||||
const cardChildren = Array.from(firstCard.element.children)
|
||||
expect(cardChildren[cardChildren.length - 1]).toBe(footer.element)
|
||||
expect(footer.find('.task-card-section__footer-actions .primary-button').text()).toContain(zhCN.taskV4.confirmCard)
|
||||
@@ -1375,7 +1402,8 @@ describe('reservation V4 pages', () => {
|
||||
it('keeps the per-card primary action right aligned on narrow screens', () => {
|
||||
expect(taskCardSectionSource).toContain('@media (max-width: 980px)')
|
||||
expect(taskCardSectionSource).toContain('.task-card-section__footer-actions')
|
||||
expect(taskCardSectionSource).toContain('padding: 0 20px 20px')
|
||||
expect(taskCardSectionSource).toContain('border-top: 1px solid var(--th-color-slate-100)')
|
||||
expect(taskCardSectionSource).toContain('padding: 14px 20px 18px')
|
||||
expect(taskCardSectionSource).toContain('justify-content: flex-end')
|
||||
expect(taskCardSectionSource).toContain('.task-card-section__footer {\n align-items: flex-end;\n }')
|
||||
})
|
||||
|
||||
@@ -28,52 +28,63 @@
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<template v-else-if="detail">
|
||||
<section class="th-section summary-section">
|
||||
<div class="th-section-header">
|
||||
<section class="th-section handling-summary">
|
||||
<div class="handling-summary__hero">
|
||||
<div>
|
||||
<h2 class="th-section-title">
|
||||
{{ t('taskV4.orderTaskSummary') }}
|
||||
</h2>
|
||||
<p class="th-muted">
|
||||
{{ detail.source_message_summary?.subject ?? t('taskList.noSourceSubject') }}
|
||||
</p>
|
||||
<span class="handling-summary__eyebrow">{{ t('taskV4.handlingDesk') }}</span>
|
||||
<h2>{{ displayOrderReference }}</h2>
|
||||
<p>{{ detail.source_message_summary?.subject ?? t('taskList.noSourceSubject') }}</p>
|
||||
</div>
|
||||
<ReservationStatusBadge :status="detail.order_task.order_task_status" />
|
||||
</div>
|
||||
|
||||
<div class="summary-grid">
|
||||
<div>
|
||||
<span>{{ t('taskV4.orderReference') }}</span>
|
||||
<strong>{{ displayOrderReference }}</strong>
|
||||
<div class="handling-summary__content">
|
||||
<div class="handling-summary__facts">
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetBookingType') }}</span>
|
||||
<strong>{{ bookingTypeLabel }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetLocator') }}</span>
|
||||
<strong>{{ targetLocator }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetResolutionStatus') }}</span>
|
||||
<strong>{{ targetResolutionLabel }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.sourceSender') }}</span>
|
||||
<strong>{{ detail.source_message_summary?.sender_summary ?? '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.sourceReceivedAt') }}</span>
|
||||
<strong>{{ formatReservationDateTime(detail.order_task.source_received_at) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetBookingType') }}</span>
|
||||
<strong>{{ bookingTypeLabel }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetLocator') }}</span>
|
||||
<strong>{{ targetLocator }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.targetResolutionStatus') }}</span>
|
||||
<strong>{{ targetResolutionLabel }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('taskV4.cardCounts') }}</span>
|
||||
<strong>
|
||||
{{ t('taskList.cardCountsTotal', { total: detail.card_counts.total_count }) }}
|
||||
</strong>
|
||||
<small>
|
||||
{{ t('taskList.cardCountsPending', { count: detail.card_counts.pending_confirm_count }) }}
|
||||
·
|
||||
{{ t('taskList.cardCountsReview', { count: detail.card_counts.review_required_count }) }}
|
||||
·
|
||||
{{ t('taskList.cardCountsConfirmed', { count: detail.card_counts.confirmed_count }) }}
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('task.sourceReceivedAt') }}</span>
|
||||
<strong>{{ formatReservationDateTime(detail.order_task.source_received_at) }}</strong>
|
||||
|
||||
<div
|
||||
class="handling-progress"
|
||||
:aria-label="t('taskV4.cardProgress')"
|
||||
>
|
||||
<span class="handling-progress__label">{{ t('taskV4.cardProgress') }}</span>
|
||||
<div class="handling-progress__items">
|
||||
<div class="handling-progress__item handling-progress__item--total">
|
||||
<span>{{ t('taskV4.totalCards') }}</span>
|
||||
<strong>{{ detail.card_counts.total_count }}</strong>
|
||||
</div>
|
||||
<div class="handling-progress__item handling-progress__item--pending">
|
||||
<span>{{ t('taskV4.pendingCards') }}</span>
|
||||
<strong>{{ detail.card_counts.pending_confirm_count }}</strong>
|
||||
</div>
|
||||
<div class="handling-progress__item handling-progress__item--review">
|
||||
<span>{{ t('taskV4.reviewCards') }}</span>
|
||||
<strong>{{ detail.card_counts.review_required_count }}</strong>
|
||||
</div>
|
||||
<div class="handling-progress__item handling-progress__item--confirmed">
|
||||
<span>{{ t('taskV4.confirmedCards') }}</span>
|
||||
<strong>{{ detail.card_counts.confirmed_count }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -662,39 +673,127 @@ function formatApiError(error: unknown, fallback: string): {
|
||||
color: var(--th-color-danger);
|
||||
}
|
||||
|
||||
.summary-section,
|
||||
.handling-summary,
|
||||
.diagnostics-section,
|
||||
.card-stack {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
padding: 0 20px 20px;
|
||||
.handling-summary {
|
||||
border-color: color-mix(in srgb, var(--th-color-slate-200) 80%, var(--th-color-blue-600));
|
||||
box-shadow: var(--th-shadow-panel);
|
||||
}
|
||||
|
||||
.summary-grid div {
|
||||
.handling-summary__hero {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
border-bottom: 1px solid var(--th-color-slate-200);
|
||||
background: linear-gradient(180deg, var(--th-color-white), var(--th-color-slate-50));
|
||||
padding: 22px 24px 18px;
|
||||
}
|
||||
|
||||
.handling-summary__eyebrow {
|
||||
color: var(--th-color-info);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.handling-summary__hero h2,
|
||||
.handling-summary__hero p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.handling-summary__hero h2 {
|
||||
margin-top: 6px;
|
||||
color: var(--th-color-slate-900);
|
||||
font-size: 24px;
|
||||
line-height: 1.2;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.handling-summary__hero p {
|
||||
margin-top: 8px;
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.handling-summary__content {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
|
||||
gap: 20px;
|
||||
padding: 18px 24px 22px;
|
||||
}
|
||||
|
||||
.handling-summary__facts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.handling-summary__facts div {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.summary-grid span {
|
||||
.handling-summary__facts span,
|
||||
.handling-progress__label,
|
||||
.handling-progress__item span {
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.summary-grid strong {
|
||||
.handling-summary__facts strong {
|
||||
color: var(--th-color-slate-900);
|
||||
font-size: 13px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.summary-grid small {
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 12px;
|
||||
.handling-progress {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 10px;
|
||||
border: 1px solid var(--th-color-slate-200);
|
||||
border-radius: var(--th-radius-md);
|
||||
background: var(--th-color-slate-50);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.handling-progress__items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.handling-progress__item {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
border-radius: var(--th-radius-sm);
|
||||
background: var(--th-color-white);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.handling-progress__item strong {
|
||||
color: var(--th-color-slate-900);
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.handling-progress__item--pending strong {
|
||||
color: var(--th-color-info);
|
||||
}
|
||||
|
||||
.handling-progress__item--review strong {
|
||||
color: var(--th-color-warning);
|
||||
}
|
||||
|
||||
.handling-progress__item--confirmed strong {
|
||||
color: var(--th-color-success);
|
||||
}
|
||||
|
||||
.card-stack {
|
||||
@@ -757,7 +856,19 @@ function formatApiError(error: unknown, fallback: string): {
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.summary-grid {
|
||||
.page-heading {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.handling-summary__content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.handling-summary__hero {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.handling-summary__facts {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user