feat:国际化多语言适配

This commit is contained in:
2025-10-29 15:48:40 +08:00
parent 985d739324
commit 3d67dc928d
41 changed files with 2636 additions and 2801 deletions
+20 -15
View File
@@ -14,23 +14,23 @@
@click="$emit('select', item)">
<view class="position-info">
<view class="position-name">{{ item.name }}</view>
<view class="tag-row">
<view class="status-tag rent" v-if="isRentable(item)"><text>可租借</text></view>
<view class="status-tag return" v-if="isReturnable(item)"><text>可归还</text></view>
</view>
<view class="position-time" v-if="item.workTime && item.workTime !== '0'"><text>营业时间{{ item.workTime }}</text>
</view>
</view>
<view class="position-actions">
<view class="distance-info" v-if="item.distance"><text>{{ item.distance }}</text></view>
<view class="nav-btn" @click.stop="$emit('navigate', item)"><text>导航</text></view>
<view class="tag-row">
<view class="status-tag rent" v-if="isRentable(item)"><text>{{ $t('location.rent') }}</text></view>
<view class="status-tag return" v-if="isReturnable(item)"><text>{{ $t('location.return') }}</text></view>
</view>
<view class="position-time" v-if="item.workTime && item.workTime !== '0'"><text>{{ $t('location.businessHours') }}{{ item.workTime }}</text>
</view>
</view>
<view class="position-actions">
<view class="distance-info" v-if="item.distance"><text>{{ item.distance }}</text></view>
<view class="nav-btn" @click.stop="$emit('navigate', item)"><text>{{ $t('location.navigate') }}</text></view>
</view>
</view>
<view class="empty-state" v-if="!isLoading && (!positions || positions.length === 0)">
<image class="empty-icon" src="/static/scan-icon.png" mode="aspectFit" />
<text class="empty-text">附近暂无设备</text>
</view>
<view class="empty-state" v-if="!isLoading && (!positions || positions.length === 0)">
<image class="empty-icon" src="/static/scan-icon.png" mode="aspectFit" />
<text class="empty-text">{{ $t('home.noNearbyDevice') }}</text>
</view>
</view>
</view>
</view>
@@ -39,12 +39,17 @@
<script setup>
import { computed } from 'vue'
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
const $t = instance?.proxy?.$t || ((key) => key)
const props = defineProps({
show: { type: Boolean, default: false },
expanded: { type: Boolean, default: false },
positions: { type: Array, default: () => [] },
isLoading: { type: Boolean, default: false },
title: { type: String, default: '附近设备场地' }
title: { type: String, default: '' }
})
const isRentable = (item) => {
+8 -22
View File
@@ -36,7 +36,7 @@
<view class="map-loading" v-if="isLoading">
<view class="loading-content">
<view class="loading-spinner"></view>
<text>地图加载中...</text>
<text>{{ $t('common.loadingMap') }}</text>
</view>
</view>
</view>
@@ -58,28 +58,13 @@
calculateDistanceSync
} from '../utils/mapUtils.js'
// 获取 i18n 实例
const instance = getCurrentInstance()
const $t = instance?.proxy?.$t || ((key) => key)
// 引用折叠面板组件的ref
const collapseRef = ref(null)
// 使用指南步骤
const guideSteps = ref([{
title: '扫码使用',
desc: '找到附近设备,扫描设备上的二维码'
},
{
title: '免押金支付',
desc: '无需支付押金,使用支付分免押即可完成租借'
},
{
title: '开始使用',
desc: '设备自动解锁,风扇弹出后取出即可开始使用'
},
{
title: '归还设备',
desc: '使用完毕后,按照设备规格要求将风扇还入即可结束订单'
}
])
// Props
const props = defineProps({
userLocation: {
@@ -436,8 +421,9 @@ const handleSearch = () => {
right: 0;
bottom: 0;
width: 94vw;
height: var(--map-height, 78vh);
height: calc(100% - 20rpx); /* 减少高度,避免覆盖底部按钮 */
margin: 20rpx;
margin-bottom: 0; /* 底部不需要边距 */
border-radius: 20rpx;
overflow: hidden;
@@ -520,7 +506,7 @@ const handleSearch = () => {
.map-side-controls {
position: absolute;
right: 20rpx;
bottom: 20rpx;
bottom: 160rpx; /* 向上移动,避免被底部按钮遮挡 */
display: flex;
flex-direction: column;
align-items: center;
+19 -16
View File
@@ -11,18 +11,18 @@
<view class="payment-badge wx-score" v-if="order.payWay == 'wx_score_pay'">
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="badge-icon"></image>
<view class="badge-text">
<text>微信支付分</text>
<text>{{ $t('order.wxPayScore') }}</text>
<text class="divider">|</text>
<text class="highlight">免押租借</text>
<text class="highlight">{{ $t('order.depositFree') }}</text>
</view>
</view>
<view class="payment-badge member" v-else-if="order.payWay == 'wx_member_pay'">
<text class="badge-text">会员订单</text>
<text class="badge-text">{{ $t('order.memberOrder') }}</text>
</view>
<view class="payment-badge deposit" v-else>
<text class="badge-text">微信支付</text>
<text class="badge-text">{{ $t('order.wxPay') }}</text>
<text class="divider">|</text>
<text class="badge-text">押金租借</text>
<text class="badge-text">{{ $t('order.depositPay') }}</text>
</view>
</view>
</view>
@@ -39,11 +39,11 @@
<!-- 订单时间信息 -->
<view class="order-times">
<view class="time-row">
<text class="time-label">租借地点</text>
<text class="time-label">{{ $t('order.rentLocation') }}</text>
<text class="time-value">{{ order.deviceName || order.positionName }}</text>
</view>
<view class="time-row">
<text class="time-label">租借时间</text>
<text class="time-label">{{ $t('order.rentTime') }}</text>
<text class="time-value">{{ order.startTime }}</text>
</view>
<view class="arrow" @click="onDetails">
@@ -59,7 +59,7 @@
<!-- 订单底部 -->
<view class="order-footer">
<view class="footer-left">
<view v-if="isInUse" class="renting"><text class="dot"></text>租借中</view>
<view v-if="isInUse" class="renting"><text class="dot"></text>{{ $t('order.renting') }}</view>
<view v-else-if="isFinished" class="meta">
<view class="meta-item"><text class="dot"></text>{{ usedDurationText }}</view>
<view class="meta-item"><text class="currency"></text>{{ displayAmount }}</view>
@@ -68,19 +68,22 @@
<view class="actions">
<!-- 待支付状态显示支付和取消按钮 -->
<view v-if="isWaitingForPayment" class="action-item primary" @click="onPay">立即支付</view>
<view v-if="isWaitingForPayment" class="action-item secondary" @click="onCancel">取消订单</view>
<view v-if="isWaitingForPayment" class="action-item primary" @click="onPay">{{ $t('order.payNow') }}</view>
<view v-if="isWaitingForPayment" class="action-item secondary" @click="onCancel">{{ $t('order.cancelOrder') }}</view>
<!-- 使用中状态显示归还设备按钮 -->
<view v-if="isInUse" class="action-item primary" @click="onReturn">快速归还</view>
<view v-if="isInUse" class="action-item primary" @click="onReturn">{{ $t('order.quickReturn') }}</view>
<!-- 查看详情按钮对所有订单都显示 -->
<!-- <view class="action-item secondary" >查看详情</view> -->
<!-- <view class="action-item secondary" >{{ $t('order.viewDetails') }}</view> -->
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
import { computed, getCurrentInstance } from 'vue';
const instance = getCurrentInstance()
const $t = instance?.proxy?.$t || ((key) => key)
const props = defineProps({
order: { type: Object, required: true },
@@ -125,7 +128,7 @@
const isInUse = computed(() => normalizedStatus.value === 'in_used');
const isFinished = computed(() => normalizedStatus.value === 'used_done');
const titleText = computed(() => props.order.deviceName ? '租借风扇' : '租借风扇');
const titleText = computed(() => $t('order.rentFan'));
// 显示金额(优先后端给定字段)
const displayAmount = computed(() => props.order.amount || props.order.payAmount || props.order.actualDeviceAmount || props.order.currentFee || '0.00');
@@ -139,8 +142,8 @@
const minutes = Math.floor(diffMs / 60000);
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
if (hours > 0) return `${hours}小时${mins}分钟`;
return `${mins}分钟`;
if (hours > 0) return `${hours}${$t('time.hour')}${mins}${$t('time.minute')}`;
return `${mins}${$t('time.minute')}`;
});
function parseDate(str) {