修改国际版本

This commit is contained in:
2026-06-12 16:08:00 +08:00
parent af758a0ccc
commit 836cdaf2dc
38 changed files with 449 additions and 145 deletions
+17 -16
View File
@@ -153,7 +153,8 @@
getUserPhoneNumber
} from '@/util/index.js'
import {
useI18n
useI18n,
showModalI18n
} from '@/utils/i18n.js'
import DeviceDetailSkeleton from '@/components/DeviceDetailSkeleton.vue'
@@ -297,7 +298,7 @@
// 不立即抛出错误,而是记录问题并继续处理
if (!res) {
console.error('API返回数据为空')
uni.showModal({
showModalI18n({
title: '数据异常',
content: 'API返回为空',
showCancel: false
@@ -320,7 +321,7 @@
} else {
// 记录详细信息,不抛出错误
console.warn('获取手机号响应异常:', res.msg || '未知错误')
uni.showModal({
showModalI18n({
title: t('auth.phoneError'),
content: `${t('common.statusCode')}: ${res.code}, ${t('common.message')}: ${res.msg || t('common.none')}`,
showCancel: false
@@ -333,7 +334,7 @@
// 显示更详细的错误信息
let errMsg = err.message || err.toString()
uni.showModal({
showModalI18n({
title: t('auth.phoneGetFailed'),
content: t('common.errorInfo') + ': ' + errMsg,
showCancel: false
@@ -342,7 +343,7 @@
} catch (outerError) {
// uni.hideLoading()
console.error('获取手机号外部错误:', outerError)
uni.showModal({
showModalI18n({
title: t('common.unexpectedError'),
content: t('common.processException') + ': ' + (outerError.message || outerError),
showCancel: false
@@ -413,7 +414,7 @@
// 显示登录提示
const showLoginTip = () => {
uni.showModal({
showModalI18n({
title: t('common.tips'),
content: t('common.loginRequired'),
confirmText: t('auth.goToLogin'),
@@ -567,19 +568,19 @@
// 生成详细说明文本
const getDetailInfoText = () => {
if (isIdrCurrency.value) {
return `不足1${t('time.hour')}按1${t('time.hour')}计费,封顶${displayCurrencySymbol.value}${displayDepositCap.value},持续计费至${displayCurrencySymbol.value}${displayDepositCap.value}视为买断`
const cap = `${displayCurrencySymbol.value}${displayDepositCap.value}`
return t('device.detailBillingIdr', {
hour: t('time.hour'),
cap
})
}
const freeMinutes = getFreeMinutes()
const unitMinutes = getBillingUnitMinutes()
const depositAmount = deviceInfo.value.depositAmount || '99'
// 按分钟计费
if (deviceInfo.value && deviceInfo.value.feeType === 'minute') {
return `不足${unitMinutes}分钟按${unitMinutes}分钟计费,封顶${depositAmount}元,持续计费至${depositAmount}元视为买断`
}
// 按小时计费
return `不足${unitMinutes}分钟按${unitMinutes}分钟计费,封顶${depositAmount}元,持续计费至${depositAmount}元视为买断`
return t('device.detailBillingByUnit', {
unit: unitMinutes,
minute: t('time.minute'),
cap: depositAmount
})
}
// 获取租借按钮文本
+3 -2
View File
@@ -205,7 +205,8 @@
import HomeMainH5 from '../../components/home/HomeMainH5.vue'
import LocationListSheet from '../../components/LocationListSheet.vue'
import {
useI18n
useI18n,
showModalI18n
} from '../../utils/i18n.js'
// 开启右上角分享菜单(仅 mp-weixin 有效)
@@ -1417,7 +1418,7 @@
const expected = expectedUserPhone.value
if (expected && normalizePhone(aliPhone) !== normalizePhone(expected)) {
uni.showModal({
showModalI18n({
title: t('common.tips'),
content: '当前支付宝授权手机号与账号绑定手机号不一致,无法扫码租借,请更换账号或联系管理员。',
showCancel: false
+3 -2
View File
@@ -262,7 +262,8 @@
URL
} from "@/config/url.js"
import {
useI18n
useI18n,
showModalI18n
} from '@/utils/i18n.js'
const {
@@ -1194,7 +1195,7 @@
// 取消订单
const handleCancelOrder = () => {
uni.showModal({
showModalI18n({
title: t('order.confirmCancel'),
content: t('order.confirmCancelContent'),
success: async (res) => {
+45 -37
View File
@@ -24,36 +24,36 @@
<view class="action-item" @click.stop="chooseImage">
<!-- <view class="action-icon">📷</view> -->
<uv-icon name="photo" size="24" color="#fff"></uv-icon>
<text>相册</text>
<text>{{ $t('scan.album') }}</text>
</view>
<view class="action-item" @click.stop="toggleInput">
<!-- <view class="action-icon"></view> -->
<uv-icon name="edit-pen" size="24" color="#fff"></uv-icon>
<text>手动输入</text>
<text>{{ $t('scan.manualInput') }}</text>
</view>
<view class="action-item" @click.stop="goBack">
<!-- <view class="action-icon"></view> -->
<uv-icon name="arrow-left" size="24" color="#fff"></uv-icon>
<text>返回</text>
<text>{{ $t('common.back') }}</text>
</view>
</view>
<!-- 手动输入弹窗 -->
<uv-popup ref="inputPopup" mode="center" round="16" :closeOnClickOverlay="true">
<view class="input-dialog">
<view class="dialog-title">手动输入设备号</view>
<view class="dialog-title">{{ $t('scan.manualInputTitle') }}</view>
<input
v-model="manualDeviceNo"
placeholder="请输入设备上的编号"
:placeholder="$t('scan.deviceNoPlaceholder')"
class="device-input"
type="text"
/>
<view class="dialog-btns">
<button class="cancel-btn" @click="closeInput">取消</button>
<button class="confirm-btn" @click="confirmManualInput">确定</button>
<button class="cancel-btn" @click="closeInput">{{ $t('common.cancel') }}</button>
<button class="confirm-btn" @click="confirmManualInput">{{ $t('common.confirm') }}</button>
</view>
</view>
</uv-popup>
@@ -64,10 +64,13 @@
import { ref, onMounted, onUnmounted } from 'vue';
import { getQueryString } from '../../util/index.js';
import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode';
import { useI18n, showModalI18n } from '@/utils/i18n.js';
const { t } = useI18n();
const inputPopup = ref(null);
const manualDeviceNo = ref('');
const tipText = ref('正在初始化...');
const tipText = ref(t('scan.initializing'));
const scanning = ref(false);
const hasFlash = ref(false);
const flashOn = ref(false);
@@ -93,12 +96,12 @@ const getScanConfig = () => ({
// 初始化扫码
const initScan = async () => {
try {
tipText.value = '正在初始化...';
tipText.value = t('scan.initializing');
console.log('=== 开始初始化扫码 ===');
// 检查浏览器支持
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
throw new Error('您的浏览器不支持摄像头访问');
throw new Error(t('scan.browserNotSupportCamera'));
}
// 等待 DOM 渲染
@@ -107,7 +110,7 @@ const initScan = async () => {
// 检查容器元素
const readerElement = document.getElementById('qr-reader');
if (!readerElement) {
throw new Error('扫码容器元素未找到');
throw new Error(t('scan.containerNotFound'));
}
console.log('✓ 扫码容器元素已找到');
@@ -130,10 +133,10 @@ const initScan = async () => {
const startScanning = async () => {
try {
if (!html5QrCode) {
throw new Error('Html5Qrcode 实例不存在');
throw new Error(t('scan.initFailed'));
}
tipText.value = '正在启动摄像头...';
tipText.value = t('scan.startingCamera');
console.log('=== 开始启动扫描 ===');
console.log('html5QrCode 实例:', html5QrCode);
console.log('html5QrCode.start 方法:', typeof html5QrCode.start);
@@ -155,7 +158,7 @@ const startScanning = async () => {
console.log('start() 调用结果:', startResult);
scanning.value = true;
tipText.value = '将二维码放入框内扫描';
tipText.value = t('scan.alignQRCode');
console.log('✅ 扫描已成功启动');
// 延迟隐藏默认UI
@@ -184,7 +187,7 @@ const startScanning = async () => {
);
scanning.value = true;
tipText.value = '将二维码放入框内扫描';
tipText.value = t('scan.alignQRCode');
console.log('✅ 使用前置摄像头启动成功');
setTimeout(() => {
@@ -215,14 +218,14 @@ const startScanning = async () => {
);
scanning.value = true;
tipText.value = '将二维码放入框内扫描';
tipText.value = t('scan.alignQRCode');
console.log('✅ 使用默认摄像头启动成功');
setTimeout(() => {
hideDefaultUI();
}, 200);
} else {
throw new Error('未找到可用的摄像头');
throw new Error(t('scan.noCameraFound'));
}
} catch (err3) {
console.error('❌ 所有方式都失败:', err3);
@@ -324,43 +327,45 @@ const stopScan = async () => {
const handleInitError = (err) => {
console.error('处理初始化错误:', err);
let errMsg = '初始化失败';
let errMsg = t('scan.initFailed');
let errDetail = '';
if (err.name === 'NotAllowedError' || err.name === 'PermissionDeniedError') {
errMsg = '摄像头权限被拒绝';
errDetail = '请在浏览器设置中允许访问摄像头';
errMsg = t('scan.cameraPermissionDenied');
errDetail = t('scan.cameraPermissionHint');
}
else if (err.name === 'NotFoundError' || err.name === 'DevicesNotFoundError') {
errMsg = '未找到可用的摄像头';
errDetail = '请确保设备有摄像头';
errMsg = t('scan.noCameraFound');
errDetail = t('scan.ensureCameraExists');
}
else if (err.name === 'NotReadableError' || err.name === 'TrackStartError') {
errMsg = '摄像头被占用';
errDetail = '请关闭其他使用摄像头的应用';
errMsg = t('scan.cameraInUse');
errDetail = t('scan.closeOtherCameraApps');
}
else if (err.name === 'NotSupportedError') {
errMsg = '浏览器不支持';
errDetail = '请使用现代浏览器访问';
errMsg = t('scan.browserNotSupported');
errDetail = t('scan.useModernBrowser');
}
// else if (location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
// errMsg = '需要 HTTPS 环境';
// errDetail = '摄像头功能需要在安全环境下使用';
// }
else {
errMsg = err.message || '摄像头启动失败';
errDetail = '请尝试刷新页面或使用其他方式';
errMsg = err.message || t('scan.cameraStartFailed');
errDetail = t('scan.tryRefreshOrAlternative');
}
tipText.value = errMsg;
const fallbackContent = `${errDetail}\n\n${t('scan.errorFallbackHint')}\n1. ${t('scan.errorFallbackAlbum')}\n2. ${t('scan.errorFallbackManual')}`;
// 显示错误提示,提供备选方案
uni.showModal({
showModalI18n({
title: errMsg,
content: errDetail + '\n\n您可以:\n1. 从相册选择二维码图片\n2. 手动输入设备号',
content: fallbackContent,
showCancel: true,
cancelText: '返回',
confirmText: '手动输入',
cancelText: t('common.back'),
confirmText: t('scan.manualInput'),
success: (res) => {
if (res.confirm) {
toggleInput();
@@ -383,7 +388,7 @@ const chooseImage = async () => {
return;
}
uni.showLoading({ title: '正在识别...' });
uni.showLoading({ title: t('scan.recognizing') });
try {
// 先停止摄像头扫描
@@ -422,7 +427,7 @@ const chooseImage = async () => {
// 不要立即返回,等待首页处理完成
console.log('图片识别结果已发送,等待首页处理...');
} else {
uni.showToast({ title: '未识别到二维码', icon: 'none' });
uni.showToast({ title: t('scan.qrNotFound'), icon: 'none' });
// 识别失败,重新启动摄像头扫描
if (wasScanning) {
setTimeout(async () => {
@@ -433,7 +438,7 @@ const chooseImage = async () => {
} catch (err) {
console.error('图片识别失败:', err);
uni.hideLoading();
uni.showToast({ title: '识别失败', icon: 'none' });
uni.showToast({ title: t('scan.recognizeFailed'), icon: 'none' });
// 识别失败,重新启动摄像头扫描
setTimeout(async () => {
try {
@@ -452,7 +457,7 @@ const chooseImage = async () => {
count: 1,
sourceType: ['album'],
success: (res) => {
uni.showToast({ title: '该功能仅在H5环境可用', icon: 'none' });
uni.showToast({ title: t('scan.h5Only'), icon: 'none' });
}
});
// #endif
@@ -477,7 +482,7 @@ const confirmManualInput = () => {
const deviceNo = manualDeviceNo.value.trim();
if (!deviceNo) {
uni.showToast({ title: '请输入设备号', icon: 'none' });
uni.showToast({ title: t('scan.deviceNoRequired'), icon: 'none' });
return;
}
@@ -508,6 +513,9 @@ const goBack = () => {
onMounted(() => {
console.log('扫码页面已挂载');
uni.setNavigationBarTitle({
title: t('scan.title')
});
// 延迟初始化,确保 DOM 已渲染
setTimeout(() => {