清理手工开票页面冗余文案

This commit is contained in:
andy
2026-07-17 17:24:19 +07:00
parent 56db5cacee
commit 7930d59359
5 changed files with 31 additions and 82 deletions

View File

@@ -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.',

View File

@@ -295,6 +295,7 @@ export default {
total: 'Total',
addCharge: 'เพิ่มแถว',
removeCharge: 'ลบ',
chargeLineLabel: 'แถวที่ {index}',
removeChargeLineAria: 'ลบแถวที่ {index}',
maxChargesReached: 'V1 รองรับได้สูงสุด 10 รายการค่าใช้จ่าย',
previewDisclaimer: 'ยอดนี้เป็นเพียงตัวอย่าง ยอดสุดท้ายให้ยึด totals จากหลังบ้าน',

View File

@@ -295,6 +295,7 @@ export default {
total: 'Total',
addCharge: '新增一行',
removeCharge: '删除',
chargeLineLabel: '第 {index} 行',
removeChargeLineAria: '删除第 {index} 行',
maxChargesReached: '第一版最多支持 10 条费用明细。',
previewDisclaimer: '前端仅做金额预览,最终金额以后端返回 totals 为准。',

View File

@@ -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 () => {

View File

@@ -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;