部分页面实现中文替换为支持翻译的英文1

This commit is contained in:
jingrow 2025-12-28 23:36:50 +08:00
parent 62922ef899
commit a8e68da076
6 changed files with 73 additions and 71 deletions

View File

@ -11,7 +11,7 @@
:loading="$resources.createAlipayOrder.loading || loading"
@click="processAlipayPayment"
>
使用支付宝支付
{{ $t('Pay with Alipay') }}
</Button>
</div>
</div>
@ -49,18 +49,18 @@ export default {
},
validate() {
if (this.amount <= 0) {
throw new DashboardError('支付金额必须大于0');
throw new DashboardError(this.$t('Payment amount must be greater than 0'));
}
if (this.amount < this.minimumAmount) {
throw new DashboardError('金额低于最低要求金额');
throw new DashboardError(this.$t('Amount is below the minimum required amount'));
}
},
onSuccess(response) {
window.open(response.payment_url, '_blank');
toast.success('支付页面已在新窗口打开');
toast.success(this.$t('Payment page opened in new window'));
//
// Optional: check payment status
// this.checkPaymentStatus(response.order_id);
}
};
@ -71,7 +71,7 @@ export default {
this.$resources.createAlipayOrder.submit();
},
//
// Optional: method to check payment status
checkPaymentStatus(orderId) {
const checkInterval = setInterval(() => {
this.$call('jcloud.api.billing.check_payment_status', {
@ -80,15 +80,15 @@ export default {
}).then(result => {
if (result && result.status === 'Success') {
clearInterval(checkInterval);
toast.success('支付成功!账户已充值');
toast.success(this.$t('Payment successful! Account has been recharged'));
this.$emit('payment-success');
}
}).catch(err => {
console.error('检查支付状态出错:', err);
console.error('Error checking payment status:', err);
});
}, 3000);
// 5
// Stop checking after 5 minutes
setTimeout(() => {
clearInterval(checkInterval);
}, 300000);

View File

@ -1,7 +1,7 @@
<template>
<div>
<FormControl
:label="`支付金额`"
:label="$t('Payment Amount')"
class="mb-3"
v-model.number="creditsToBuy"
name="amount"
@ -19,7 +19,7 @@
</div>
<div class="mt-4">
<div class="text-xs text-gray-600">支付方式</div>
<div class="text-xs text-gray-600">{{ $t('Payment Method') }}</div>
<div class="mt-1.5 grid grid-cols-1 gap-2 sm:grid-cols-2">
<label
class="payment-option"
@ -54,7 +54,7 @@
</div>
<div class="text-xs text-gray-500 mt-2 mb-4" v-if="$team.pg.currency === 'CNY'">
使用{{ paymentGateway === 'Alipay' ? '支付宝' : '微信' }}支付快速便捷余额将在支付成功后立即到账
{{ $t('Pay with {method}, fast and convenient. Balance will be credited immediately after successful payment.', { method: paymentGateway === 'Alipay' ? $t('Alipay') : $t('WeChat Pay') }) }}
</div>
<BuyPrepaidCreditsAlipay
@ -91,7 +91,7 @@ export default {
},
data() {
return {
paymentGateway: 'Alipay', // 使
paymentGateway: 'Alipay', // Default to Alipay
creditsToBuy: this.minimumAmount || 0,
amountError: ''
};
@ -208,7 +208,7 @@ export default {
background-color: #22AC38;
}
/* 响应式设计 */
/* Responsive design */
@media (max-width: 640px) {
.payment-options {
flex-direction: column;

View File

@ -11,11 +11,11 @@
:loading="$resources.createWeChatPayOrder.loading || loading"
@click="processWeChatPayment"
>
使用微信支付
{{ $t('Pay with WeChat Pay') }}
</Button>
</div>
<!-- 使用Teleport将弹窗移到body下 -->
<!-- Use Teleport to move modal to body -->
<Teleport to="body">
<div v-if="showQRCode" class="wechat-qrcode-overlay">
<div class="wechat-qrcode-modal">
@ -31,20 +31,20 @@
</div>
<div class="text-center mb-5">
<div class="text-sm text-gray-600 mb-2">扫一扫付款</div>
<div class="text-3xl font-bold text-[#FF0036]">{{ amount }} </div>
<div class="text-sm text-gray-600 mb-2">{{ $t('Scan to Pay (CNY)') }}</div>
<div class="text-3xl font-bold text-[#FF0036]">{{ amount }} {{ $t('CNY') }}</div>
</div>
<div class="flex justify-center">
<div v-if="qrCodeImage" class="qrcode-container">
<img :src="qrCodeImage" alt="微信支付二维码" class="qrcode-image" />
<img :src="qrCodeImage" :alt="$t('WeChat Pay QR Code')" class="qrcode-image" />
</div>
<div v-else class="qrcode-loading"></div>
</div>
<div class="mt-5 text-center text-sm">
<div class="text-gray-600">请使用微信扫描二维码完成支付</div>
<div class="text-gray-500 mt-1">二维码有效期 15 分钟</div>
<div class="text-gray-600">{{ $t('Please scan the QR code with WeChat to complete payment') }}</div>
<div class="text-gray-500 mt-1">{{ $t('QR code valid for 15 minutes') }}</div>
</div>
</div>
</div>
@ -55,7 +55,7 @@
<script>
import { toast } from 'vue-sonner';
import { DashboardError } from '../utils/error';
import { Teleport } from 'vue'; // Teleport
import { Teleport } from 'vue'; // Ensure Teleport is imported
import WeChatPayLogo from '../logo/WeChatPayLogo.vue';
export default {
@ -94,14 +94,14 @@ export default {
},
validate() {
if (this.amount <= 0) {
throw new DashboardError('支付金额必须大于0');
throw new DashboardError(this.$t('Payment amount must be greater than 0'));
}
if (this.amount < this.minimumAmount) {
throw new DashboardError('金额低于最低要求金额');
throw new DashboardError(this.$t('Amount is below the minimum required amount'));
}
},
onSuccess(response) {
console.log('微信支付响应:', response);
console.log('WeChat Pay response:', response);
this.orderId = response.order_id;
this.qrCodeUrl = response.qr_code_url;
this.qrCodeImage = response.qr_code_image;
@ -118,11 +118,12 @@ export default {
payment_type: 'wechatpay'
},
onSuccess(data) {
// Check for success status (handles both English and Chinese status values from backend)
if (data && (data.status === 'Success' || data.status === '已支付' || data.status === '交易成功')) {
this.stopPaymentCheck();
this.closeQRCode();
this.$emit('payment-success');
toast.success('支付成功');
toast.success(this.$t('Payment successful'));
}
}
};
@ -181,7 +182,7 @@ export default {
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}
/* 全新的弹窗样式 */
/* Modal overlay styles */
.wechat-qrcode-overlay {
position: fixed;
top: 0;
@ -192,7 +193,7 @@ export default {
display: flex;
align-items: center;
justify-content: center;
z-index: 99999; /* 极高的z-index确保在最上层 */
z-index: 99999; /* Very high z-index to ensure it's on top */
}
.wechat-qrcode-modal {

View File

@ -4,9 +4,9 @@
<div class="flex flex-col gap-2.5 px-4 py-3">
<div class="flex items-center justify-between">
<div class="flex flex-col gap-1.5">
<div class="text-lg font-semibold">账单费用</div>
<div class="text-lg font-semibold">{{ t('Billing Charges') }}</div>
<div class="text-gray-700">
<span>下次扣款日期 </span>
<span>{{ t('Next billing date') }} </span>
<span>{{ currentMonthEnd() }}</span>
</div>
</div>
@ -15,14 +15,14 @@
<div class="flex gap-2 text-gray-700">
<i-lucide-credit-card class="h-4 w-4" />
<div>
<span>当前账单金额为 </span>
<span>{{ t('Current billing amount is') }} </span>
<span class="font-medium text-gray-900">
{{ currency }} {{ currentBillingAmount?.toFixed(2) || '0.00' }}
</span>
</div>
</div>
<div>
<Button label="查看账单明细" @click="showInvoiceDialog = true" />
<Button :label="t('View Invoice Details')" @click="showInvoiceDialog = true" />
</div>
</div>
</div>
@ -33,12 +33,12 @@
<div class="flex h-7 items-center gap-2 text-gray-800">
<i-lucide-receipt class="h-4 w-4" />
<div>
<span>未支付金额为 </span>
<span>{{ t('Unpaid amount is') }} </span>
<span>{{ currency }} {{ unpaidAmount.data?.toFixed(2) }}</span>
</div>
</div>
<div>
<Button variant="solid" label="立即支付" @click="payNow" />
<Button variant="solid" :label="t('Pay Now')" @click="payNow" />
</div>
</div>
</div>
@ -56,8 +56,10 @@ import UpcomingInvoiceDialog from './UpcomingInvoiceDialog.vue';
import { Button, createResource } from 'jingrow-ui';
import { ref, computed, inject } from 'vue';
import { confirmDialog } from '../../utils/components';
import { useI18n } from '../../composables/useI18n';
import router from '../../router';
const { t } = useI18n();
const team = inject('team');
const { currentBillingAmount, upcomingInvoice, unpaidInvoices } =
inject('billing');
@ -76,7 +78,7 @@ const unpaidAmount = createResource({
const currentMonthEnd = () => {
const date = new Date();
const lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
return lastDay.toLocaleDateString('zh-CN', {
return lastDay.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
@ -96,11 +98,10 @@ function payUnpaidInvoices() {
showAddPrepaidCreditsDialog.value = true;
} else {
confirmDialog({
title: '多张未支付发票',
message:
'您有多张未支付发票。请从发票页面支付它们',
title: t('Multiple Unpaid Invoices'),
message: t('You have multiple unpaid invoices. Please pay them from the invoices page.'),
primaryAction: {
label: '前往发票',
label: t('Go to Invoices'),
variant: 'solid',
onClick: ({ hide }) => {
router.push({ name: 'BillingInvoices' });

View File

@ -1,7 +1,7 @@
<template>
<div>
<FormControl
:label="`支付金额`"
:label="$t('Payment Amount')"
class="mb-3"
v-model.number="creditsToBuy"
name="amount"
@ -18,7 +18,7 @@
</div>
<div class="mt-4">
<div class="text-xs text-gray-600">支付方式</div>
<div class="text-xs text-gray-600">{{ $t('Payment Method') }}</div>
<div class="mt-1.5 grid grid-cols-1 gap-2 sm:grid-cols-2">
<label
class="payment-option"
@ -53,7 +53,7 @@
</div>
<div class="text-xs text-gray-500 mt-2 mb-4" v-if="$team.pg.currency === 'CNY'">
使用{{ paymentGateway === 'Alipay' ? '支付宝' : '微信' }}支付快速便捷余额将在支付成功后立即到账
{{ $t('Pay with {method}, fast and convenient. Balance will be credited immediately after successful payment.', { method: paymentGateway === 'Alipay' ? $t('Alipay') : $t('WeChat Pay') }) }}
</div>
<BuyPrepaidCreditsAlipay
@ -86,7 +86,7 @@ export default {
},
data() {
return {
paymentGateway: 'Alipay', // 使
paymentGateway: 'Alipay', // Default to Alipay
creditsToBuy: this.minimumAmount
};
},
@ -215,7 +215,7 @@ export default {
background-color: #22AC38;
}
/* 响应式设计 */
/* Responsive design */
@media (max-width: 640px) {
.payment-options {
flex-direction: column;

View File

@ -11,7 +11,7 @@
v-if="showInvoice.status === 'Empty'"
class="text-base text-gray-600"
>
无内容显示
{{ $t('No content to display') }}
</div>
<InvoiceTable v-else :invoiceId="showInvoice.name" />
</template>
@ -75,43 +75,43 @@ export default {
return [
{
type: 'select',
label: '类型',
label: this.$t('Type'),
class: !this.$isMobile ? 'w-36' : '',
fieldname: 'type',
options: [
{ label: '', value: '' },
{ label: '订阅', value: 'Subscription' },
{ label: '余额支付', value: 'Prepaid Credits' },
{ label: this.$t('Subscription'), value: 'Subscription' },
{ label: this.$t('Prepaid Credits'), value: 'Prepaid Credits' },
],
},
{
type: 'select',
label: '状态',
label: this.$t('Status'),
class: !this.$isMobile ? 'w-36' : '',
fieldname: 'status',
options: [
{ label: '', value: '' },
{ label: '待开具', value: 'Draft' },
{ label: '已创建', value: 'Invoice Created' },
{ label: '未支付', value: 'Unpaid' },
{ label: '已支付', value: 'Paid' },
{ label: '已退款', value: 'Refunded' },
{ label: '无法收款', value: 'Uncollectible' },
{ label: '已收款', value: 'Collected' },
{ label: '空白', value: 'Empty' },
{ label: this.$t('Draft'), value: 'Draft' },
{ label: this.$t('Invoice Created'), value: 'Invoice Created' },
{ label: this.$t('Unpaid'), value: 'Unpaid' },
{ label: this.$t('Paid'), value: 'Paid' },
{ label: this.$t('Refunded'), value: 'Refunded' },
{ label: this.$t('Uncollectible'), value: 'Uncollectible' },
{ label: this.$t('Collected'), value: 'Collected' },
{ label: this.$t('Empty'), value: 'Empty' },
],
},
];
},
columns: [
{
label: '发票',
label: this.$t('Invoice'),
fieldname: 'name',
class: 'font-medium',
format(value, row) {
if (row.type == 'Subscription') {
let end = dayjsLocal(row.period_end);
// YYYY-MM
// Format as YYYY-MM
return end.format('YYYY-MM');
} else if (row.type == 'Partnership Fees') {
return 'Partnership Fees';
@ -121,41 +121,41 @@ export default {
width: 0.8,
},
{
label: '状态',
label: this.$t('Status'),
fieldname: 'status',
type: 'Badge',
width: '150px',
},
{
label: '日期',
label: this.$t('Date'),
fieldname: 'due_date',
format(value, row) {
if (row.type == 'Subscription') {
let start = dayjsLocal(row.period_start);
let end = dayjsLocal(row.period_end);
// YYYY-MM-DD
// Format as YYYY-MM-DD
return `${start.format('YYYY-MM-DD')} - ${end.format('YYYY-MM-DD')}`;
}
// YYYY-MM-DD
// Format as YYYY-MM-DD
return dayjsLocal(value).format('YYYY-MM-DD');
},
},
{
label: '总计',
label: this.$t('Total'),
fieldname: 'total',
format: this.formatCurrency,
align: 'right',
width: 0.6,
},
{
label: '已支付金额',
label: this.$t('Amount Paid'),
fieldname: 'amount_paid',
format: this.formatCurrency,
align: 'right',
width: 0.6,
},
{
label: '应付金额',
label: this.$t('Amount Due'),
fieldname: 'amount_due',
format: this.formatCurrency,
align: 'right',
@ -168,7 +168,7 @@ export default {
Button: ({ row }) => {
if (row.invoice_pdf || row.mpesa_invoice_pdf) {
return {
label: '下载发票',
label: this.$t('Download Invoice'),
slots: {
prefix: icon('download'),
},
@ -183,7 +183,7 @@ export default {
}
if (row.status === 'Unpaid' && row.amount_due > 0) {
return {
label: '立即支付',
label: this.$t('Pay Now'),
slots: {
prefix: icon('external-link'),
},
@ -210,10 +210,10 @@ export default {
onClick(e) {
e.stopPropagation();
confirmDialog({
title: '支付失败',
message: `<div class="space-y-4"><p class="text-base">您使用尾号为 <strong>${row.stripe_payment_failed_card}</strong> 的卡支付此发票失败,原因如下:</p><div class="text-sm font-mono text-gray-600 rounded p-2 bg-gray-100">${row.stripe_payment_error}</div><p class="text-base">请更改您的支付方式以支付此发票。</p></div>`,
title: this.$t('Payment Failed'),
message: `<div class="space-y-4"><p class="text-base">${this.$t('Payment for this invoice failed using card ending in')} <strong>${row.stripe_payment_failed_card}</strong>. ${this.$t('Reason:')}</p><div class="text-sm font-mono text-gray-600 rounded p-2 bg-gray-100">${row.stripe_payment_error}</div><p class="text-base">${this.$t('Please update your payment method to pay this invoice.')}</p></div>`,
primaryAction: {
label: '更改支付方式',
label: this.$t('Update Payment Method'),
variant: 'solid',
onClick: ({ hide }) => {
hide();