完善手工开票页面文案国际化

This commit is contained in:
andy
2026-07-17 14:52:36 +07:00
parent 94484dbf14
commit 7dfaea7245
7 changed files with 121 additions and 55 deletions

View File

@@ -5,14 +5,7 @@
>
<header class="invoice-page__header">
<div class="invoice-page__title">
<h1>创建 Invoice</h1>
<span class="draft-badge">
<i
class="pi pi-pencil"
aria-hidden="true"
/>
草稿
</span>
<h1>{{ t('manualInvoice.createTitle') }}</h1>
</div>
<div class="source-summary">
<span>当前来源</span>
@@ -70,9 +63,10 @@
</select>
<input
v-model.trim="form.recipient.company"
data-testid="recipient-company-input"
type="text"
autocomplete="off"
placeholder="输入 Company"
:placeholder="t('manualInvoice.companyInputPlaceholder')"
required
>
</div>
@@ -101,9 +95,10 @@
</select>
<input
v-model.trim="form.recipient.attention"
data-testid="recipient-attention-input"
type="text"
autocomplete="off"
placeholder="输入 Attention"
:placeholder="t('manualInvoice.attentionInputPlaceholder')"
required
>
</div>
@@ -113,8 +108,9 @@
<span class="field-label">Address</span>
<textarea
v-model.trim="form.recipient.address"
data-testid="recipient-address"
rows="3"
placeholder="输入客户完整账单地址"
:placeholder="t('manualInvoice.addressInputPlaceholder')"
required
/>
</label>
@@ -189,7 +185,6 @@
autocomplete="off"
required
>
<small class="field__hint">Group Name Group Code 在本流程中为同一字段</small>
</label>
<div class="field">
@@ -290,7 +285,7 @@
v-model.trim="form.booking.room_rate_note"
data-testid="booking-room-rate-note"
type="text"
placeholder="例如 includingBF"
:placeholder="t('manualInvoice.roomRateNotePlaceholder')"
autocomplete="off"
>
</label>
@@ -377,7 +372,7 @@
class="pi pi-plus"
aria-hidden="true"
/>
新增一行
{{ t('manualInvoice.addCharge') }}
</button>
</div>
</header>
@@ -395,14 +390,14 @@
type="button"
class="remove-button"
:disabled="form.charges.length === 1"
:aria-label="`删除第 ${index + 1} `"
:aria-label="t('manualInvoice.removeChargeLineAria', { index: index + 1 })"
@click="removeCharge(index)"
>
<i
class="pi pi-trash"
aria-hidden="true"
/>
删除
{{ t('manualInvoice.removeCharge') }}
</button>
</header>
@@ -504,7 +499,7 @@
class="pi pi-file-pdf"
aria-hidden="true"
/>
{{ submitting ? '生成中' : '确认并生成 PDF' }}
{{ submitting ? t('manualInvoice.generating') : t('manualInvoice.generate') }}
</button>
</footer>
@@ -773,7 +768,7 @@ const submitting = ref(false)
const downloadingPdf = ref(false)
const messages = ref<string[]>([])
const technicalDetails = ref<string[]>([])
const downloadMessage = ref('')
const downloadMessageKey = ref('')
const alertTone = ref<'error' | 'success'>('error')
const generationResult = ref<ManualInvoiceGenerationResult | null>(null)
const documentDatesEdited = ref(false)
@@ -785,6 +780,7 @@ const recipientContacts = computed(() => {
const primaryCharge = computed<ChargeForm>(() => form.charges[0] as ChargeForm)
const sourceGroupName = computed(() => form.booking.group_name.trim() || '未填写')
const downloadMessage = computed(() => (downloadMessageKey.value ? t(downloadMessageKey.value) : ''))
const previewTotals = computed(() => {
const total = form.charges.reduce((sum, charge) => sum + lineAmount(charge), 0)
@@ -884,7 +880,7 @@ function lineAmount(charge: ChargeForm): number {
async function submitInvoice(): Promise<void> {
technicalDetails.value = []
downloadMessage.value = ''
downloadMessageKey.value = ''
messages.value = validateForm()
alertTone.value = 'error'
if (messages.value.length > 0) {
@@ -913,7 +909,7 @@ async function downloadPdf(): Promise<void> {
}
downloadingPdf.value = true
downloadMessage.value = ''
downloadMessageKey.value = ''
try {
const response = await fetch(pdfUrl, { credentials: 'omit' })
if (!response.ok) {
@@ -924,7 +920,7 @@ async function downloadPdf(): Promise<void> {
triggerBrowserDownload(objectUrl, createPdfFileName(result.invoice_generation_id))
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 0)
} catch {
downloadMessage.value = t('manualInvoice.downloadFallback')
downloadMessageKey.value = 'manualInvoice.downloadFallback'
window.open(pdfUrl, '_blank', 'noopener,noreferrer')
} finally {
downloadingPdf.value = false
@@ -1253,19 +1249,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
line-height: 1.15;
}
.draft-badge {
display: inline-flex;
align-items: center;
gap: 6px;
flex: 0 0 auto;
border-radius: 999px;
background: #fff5df;
color: #c87905;
font-size: 10px;
font-weight: 900;
padding: 6px 9px;
}
.source-summary {
display: grid;
justify-items: end;
@@ -1425,14 +1408,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
outline-offset: 2px;
}
.field__hint {
display: block;
min-height: 16px;
color: var(--th-color-slate-500);
font-size: 11px;
line-height: 1.45;
}
.directory-control {
display: grid;
min-width: 0;