清理手工开票页面冗余文案
This commit is contained in:
@@ -295,6 +295,7 @@ export default {
|
||||
total: 'Total',
|
||||
addCharge: 'Add row',
|
||||
removeCharge: 'Remove',
|
||||
chargeLineLabel: 'Row {index}',
|
||||
removeChargeLineAria: 'Remove row {index}',
|
||||
maxChargesReached: 'V1 supports up to 10 charge lines.',
|
||||
previewDisclaimer: 'The frontend only previews amounts. Backend totals are authoritative.',
|
||||
|
||||
@@ -295,6 +295,7 @@ export default {
|
||||
total: 'Total',
|
||||
addCharge: 'เพิ่มแถว',
|
||||
removeCharge: 'ลบ',
|
||||
chargeLineLabel: 'แถวที่ {index}',
|
||||
removeChargeLineAria: 'ลบแถวที่ {index}',
|
||||
maxChargesReached: 'V1 รองรับได้สูงสุด 10 รายการค่าใช้จ่าย',
|
||||
previewDisclaimer: 'ยอดนี้เป็นเพียงตัวอย่าง ยอดสุดท้ายให้ยึด totals จากหลังบ้าน',
|
||||
|
||||
@@ -295,6 +295,7 @@ export default {
|
||||
total: 'Total',
|
||||
addCharge: '新增一行',
|
||||
removeCharge: '删除',
|
||||
chargeLineLabel: '第 {index} 行',
|
||||
removeChargeLineAria: '删除第 {index} 行',
|
||||
maxChargesReached: '第一版最多支持 10 条费用明细。',
|
||||
previewDisclaimer: '前端仅做金额预览,最终金额以后端返回 totals 为准。',
|
||||
|
||||
@@ -258,16 +258,31 @@ describe('ReservationManualInvoiceView', () => {
|
||||
expect((wrapper.find('[data-testid="booking-room-rate-note"]').element as HTMLInputElement).placeholder).toBe(
|
||||
'e.g. including BF',
|
||||
)
|
||||
expect(wrapper.find('.control-caption').exists()).toBe(false)
|
||||
expect(wrapper.find('[data-testid="manual-invoice-add-charge"]').text()).toContain('Add row')
|
||||
expect(wrapper.find('[data-testid="manual-invoice-submit"]').text()).toContain('Confirm and generate PDF')
|
||||
expect(wrapper.text()).toContain('Row 1')
|
||||
expect(wrapper.text()).not.toContain('第 1 行')
|
||||
|
||||
await wrapper.find('[data-testid="manual-invoice-add-charge"]').trigger('click')
|
||||
|
||||
expect(wrapper.findAll('.remove-button')[1]?.text()).toContain('Remove')
|
||||
expect(wrapper.findAll('.remove-button')[1]?.attributes('aria-label')).toBe('Remove row 2')
|
||||
expect(wrapper.text()).toContain('Row 2')
|
||||
expect(wrapper.text()).not.toContain('新增一行')
|
||||
expect(wrapper.text()).not.toContain('确认并生成 PDF')
|
||||
expect(wrapper.text()).not.toContain('例如 includingBF')
|
||||
expect(wrapper.text()).not.toContain('金额')
|
||||
expect(wrapper.text()).not.toContain('说明')
|
||||
})
|
||||
|
||||
it('passes current locale to native date inputs', () => {
|
||||
const wrapper = mountView({ locale: 'th-TH' })
|
||||
|
||||
expect(wrapper.find('[data-testid="document-booking-date"]').attributes('lang')).toBe('th-TH')
|
||||
expect(wrapper.find('[data-testid="booking-arrival-date"]').attributes('lang')).toBe('th-TH')
|
||||
expect(wrapper.find('[data-testid="booking-departure-date"]').attributes('lang')).toBe('th-TH')
|
||||
expect(wrapper.find('[data-testid="document-due-date"]').attributes('lang')).toBe('th-TH')
|
||||
})
|
||||
|
||||
it('marks required fields and highlights empty inputs after submit', async () => {
|
||||
@@ -326,16 +341,11 @@ describe('ReservationManualInvoiceView', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('shows final-format date previews like the invoice prototype', async () => {
|
||||
it('does not render final-format date preview blocks', () => {
|
||||
const wrapper = mountView()
|
||||
|
||||
await wrapper.find('[data-testid="booking-arrival-date"]').setValue('2026-08-02')
|
||||
await wrapper.find('[data-testid="booking-departure-date"]').setValue('2026-08-05')
|
||||
await wrapper.find('[data-testid="document-due-date"]').setValue('2026-07-22')
|
||||
|
||||
expect(wrapper.find('[data-testid="arrival-date-preview"]').text()).toContain('02/08/2026')
|
||||
expect(wrapper.find('[data-testid="departure-date-preview"]').text()).toContain('05/08/2026')
|
||||
expect(wrapper.find('[data-testid="due-date-preview"]').text()).toContain('22/07/2026')
|
||||
expect(wrapper.find('.date-preview').exists()).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('最终格式')
|
||||
})
|
||||
|
||||
it('keeps primary reservation controls bound to the first charge line', async () => {
|
||||
|
||||
@@ -206,18 +206,12 @@
|
||||
v-model="form.document.booking_date"
|
||||
data-testid="document-booking-date"
|
||||
type="date"
|
||||
:lang="locale"
|
||||
:class="validationClass('booking-date')"
|
||||
v-bind="validationAria('booking-date')"
|
||||
required
|
||||
@input="markDocumentDatesEdited"
|
||||
>
|
||||
<output
|
||||
class="date-preview"
|
||||
for="invoice-booking-date"
|
||||
>
|
||||
<small>最终格式</small>
|
||||
<strong>{{ formatDatePreview(form.document.booking_date) }}</strong>
|
||||
</output>
|
||||
</div>
|
||||
<p
|
||||
v-if="fieldError('booking-date')"
|
||||
@@ -279,18 +273,11 @@
|
||||
v-model="form.booking.arrival_date"
|
||||
data-testid="booking-arrival-date"
|
||||
type="date"
|
||||
:lang="locale"
|
||||
:class="validationClass('arrival-date')"
|
||||
v-bind="validationAria('arrival-date')"
|
||||
required
|
||||
>
|
||||
<output
|
||||
class="date-preview"
|
||||
data-testid="arrival-date-preview"
|
||||
for="invoice-arrival-date"
|
||||
>
|
||||
<small>最终格式</small>
|
||||
<strong>{{ formatDatePreview(form.booking.arrival_date) }}</strong>
|
||||
</output>
|
||||
</div>
|
||||
<p
|
||||
v-if="fieldError('arrival-date')"
|
||||
@@ -315,18 +302,11 @@
|
||||
v-model="form.booking.departure_date"
|
||||
data-testid="booking-departure-date"
|
||||
type="date"
|
||||
:lang="locale"
|
||||
:class="validationClass('departure-date')"
|
||||
v-bind="validationAria('departure-date')"
|
||||
required
|
||||
>
|
||||
<output
|
||||
class="date-preview"
|
||||
data-testid="departure-date-preview"
|
||||
for="invoice-departure-date"
|
||||
>
|
||||
<small>最终格式</small>
|
||||
<strong>{{ formatDatePreview(form.booking.departure_date) }}</strong>
|
||||
</output>
|
||||
</div>
|
||||
<p
|
||||
v-if="fieldError('departure-date')"
|
||||
@@ -351,19 +331,12 @@
|
||||
v-model="form.document.due_date"
|
||||
data-testid="document-due-date"
|
||||
type="date"
|
||||
:lang="locale"
|
||||
:class="validationClass('due-date')"
|
||||
v-bind="validationAria('due-date')"
|
||||
required
|
||||
@input="markDocumentDatesEdited"
|
||||
>
|
||||
<output
|
||||
class="date-preview"
|
||||
data-testid="due-date-preview"
|
||||
for="invoice-due-date"
|
||||
>
|
||||
<small>最终格式</small>
|
||||
<strong>{{ formatDatePreview(form.document.due_date) }}</strong>
|
||||
</output>
|
||||
</div>
|
||||
<p
|
||||
v-if="fieldError('due-date')"
|
||||
@@ -381,7 +354,6 @@
|
||||
</div>
|
||||
<div class="room-rate-control">
|
||||
<label>
|
||||
<span class="control-caption control-caption--required">金额</span>
|
||||
<div class="number-control">
|
||||
<input
|
||||
v-model="primaryCharge.rate"
|
||||
@@ -408,7 +380,6 @@
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="control-caption">说明</span>
|
||||
<input
|
||||
v-model.trim="form.booking.room_rate_note"
|
||||
data-testid="booking-room-rate-note"
|
||||
@@ -549,7 +520,7 @@
|
||||
:data-testid="`charge-row-${index}`"
|
||||
>
|
||||
<header class="charge-line__header">
|
||||
<strong>第 {{ index + 1 }} 行</strong>
|
||||
<strong>{{ t('manualInvoice.chargeLineLabel', { index: index + 1 }) }}</strong>
|
||||
<button
|
||||
type="button"
|
||||
class="remove-button"
|
||||
@@ -1472,17 +1443,6 @@ function formatMoney(value: number, currency: string): string {
|
||||
}).format(value)
|
||||
}
|
||||
|
||||
function formatDatePreview(value: string): string {
|
||||
if (!value) {
|
||||
return '—'
|
||||
}
|
||||
const [year, month, day] = value.split('-')
|
||||
if (!year || !month || !day) {
|
||||
return '—'
|
||||
}
|
||||
return `${day}/${month}/${year}`
|
||||
}
|
||||
|
||||
function formatGenerationStatus(status: string): string {
|
||||
const key = `manualInvoice.statuses.${status}`
|
||||
return te(key) ? t(key) : status
|
||||
@@ -1744,15 +1704,13 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
box-shadow: 0 0 0 3px rgb(225 29 72 / 12%), inset 0 0 0 1px rgb(225 29 72 / 8%);
|
||||
}
|
||||
|
||||
.date-control input.is-invalid + .date-preview,
|
||||
.number-control input.is-invalid + .number-suffix {
|
||||
border-color: #e11d48;
|
||||
background: #fff1f3;
|
||||
color: #be123c;
|
||||
}
|
||||
|
||||
.field-label--required::after,
|
||||
.control-caption--required::after {
|
||||
.field-label--required::after {
|
||||
content: "*";
|
||||
margin-left: 4px;
|
||||
color: #e11d48;
|
||||
@@ -1778,19 +1736,20 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.date-control,
|
||||
.date-control {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.number-control {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.date-control input,
|
||||
.number-control input {
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
|
||||
.date-preview,
|
||||
.number-suffix {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
@@ -1801,20 +1760,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.date-preview {
|
||||
min-width: 118px;
|
||||
}
|
||||
|
||||
.date-preview small {
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.date-preview strong {
|
||||
color: var(--th-color-slate-600);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.number-suffix {
|
||||
place-items: center;
|
||||
min-width: 62px;
|
||||
@@ -1836,12 +1781,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.control-caption {
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.add-button,
|
||||
.remove-button,
|
||||
.generate-button,
|
||||
@@ -2204,17 +2143,14 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.date-control,
|
||||
.number-control {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.date-control input,
|
||||
.number-control input {
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
.date-preview,
|
||||
.number-suffix {
|
||||
min-height: 42px;
|
||||
border-top: 0;
|
||||
|
||||
Reference in New Issue
Block a user