feat:国际化多语言适配
This commit is contained in:
@@ -8,11 +8,39 @@
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
|
||||
// 注意:语言初始化已移至 main.js,确保每次 reLaunch 都能正确加载新语言
|
||||
},
|
||||
onShow: async function() {
|
||||
// 手动登录模式:不再自动登录
|
||||
// 如需保留可开关逻辑,可在此读取配置决定是否执行 autoLogin
|
||||
console.log('========================================')
|
||||
console.log('=== App onShow 被调用 ===')
|
||||
console.log('时间戳:', new Date().toLocaleTimeString())
|
||||
|
||||
// 检查并更新语言(uni.reLaunch 会触发 onShow)
|
||||
try {
|
||||
const savedLang = uni.getStorageSync('language')
|
||||
console.log('App onShow - 缓存中的语言:', savedLang)
|
||||
|
||||
// 获取当前 i18n 实例并检查语言
|
||||
if (this.$i18n) {
|
||||
const currentLocale = this.$i18n.locale
|
||||
console.log('App onShow - 当前 i18n locale:', currentLocale)
|
||||
|
||||
if (savedLang && savedLang !== currentLocale) {
|
||||
console.log('=== App onShow 检测到语言变化 ===')
|
||||
console.log('旧语言:', currentLocale)
|
||||
console.log('新语言:', savedLang)
|
||||
|
||||
// 强制更新语言
|
||||
this.$i18n.locale = savedLang
|
||||
console.log('App onShow - 语言已更新为:', this.$i18n.locale)
|
||||
console.log('App onShow - 测试翻译:', this.$t('common.loading'))
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('App onShow - 语言检查失败:', e)
|
||||
}
|
||||
|
||||
console.log('========================================')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
# Uni-Fans API 接口文档
|
||||
|
||||
本文档详细说明了 Uni-Fans 应用中使用的所有接口,包括参数说明和使用示例。
|
||||
|
||||
## 目录
|
||||
|
||||
1. [订单查询接口](#1-订单查询接口)
|
||||
2. [设备信息查询接口](#2-设备信息查询接口)
|
||||
3. [订单套餐更新接口](#3-订单套餐更新接口)
|
||||
4. [用户余额更新接口](#4-用户余额更新接口)
|
||||
5. [微信支付订单创建接口](#5-微信支付订单创建接口)
|
||||
6. [设备租借指令接口](#6-设备租借指令接口)
|
||||
|
||||
## 1. 订单查询接口
|
||||
|
||||
### 描述
|
||||
根据订单ID查询订单详细信息。
|
||||
|
||||
### 接口信息
|
||||
- **方法名**: `queryById`
|
||||
- **请求方式**: GET
|
||||
- **URL**: `/app/order/query/{orderId}`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| orderId | String | 是 | 订单ID |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"orderId": "订单ID",
|
||||
"orderNo": "订单编号",
|
||||
"deviceNo": "设备编号",
|
||||
"createTime": "创建时间",
|
||||
"phone": "联系电话",
|
||||
"depositAmount": "押金金额",
|
||||
"packageTime": "套餐时间(分钟)",
|
||||
"packagePrice": "套餐价格"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const orderInfo = await queryById('12345');
|
||||
if (orderInfo.code === 200) {
|
||||
// 处理订单信息
|
||||
console.log(orderInfo.data);
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 设备信息查询接口
|
||||
|
||||
### 描述
|
||||
根据设备编号查询设备详细信息。
|
||||
|
||||
### 接口信息
|
||||
- **方法名**: `getDeviceInfo`
|
||||
- **请求方式**: GET
|
||||
- **URL**: `/app/device/info/{deviceNo}`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| deviceNo | String | 是 | 设备编号 |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"device": {
|
||||
"deviceNo": "设备编号",
|
||||
"deviceName": "设备名称",
|
||||
"deviceStatus": "设备状态",
|
||||
"depositAmount": "押金金额",
|
||||
"feeType": "收费类型(hour/times)",
|
||||
"feeConfig": "费用配置JSON字符串"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const deviceInfo = await getDeviceInfo('D001');
|
||||
if (deviceInfo.code === 200) {
|
||||
// 处理设备信息
|
||||
console.log(deviceInfo.data.device);
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 订单套餐更新接口
|
||||
|
||||
### 描述
|
||||
更新订单的套餐信息。
|
||||
|
||||
### 接口信息
|
||||
- **方法名**: `updateOrderPackage`
|
||||
- **请求方式**: POST
|
||||
- **URL**: `/app/order/update-package`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| orderId | String | 是 | 订单ID |
|
||||
| packageTime | Number | 是 | 套餐时间(分钟) |
|
||||
| packagePrice | Number | 是 | 套餐价格 |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const result = await updateOrderPackage({
|
||||
orderId: '12345',
|
||||
packageTime: 360, // 6小时(分钟)
|
||||
packagePrice: 30 // 30元
|
||||
});
|
||||
if (result.code === 200) {
|
||||
console.log('套餐更新成功');
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 用户余额更新接口
|
||||
|
||||
### 描述
|
||||
支付成功后更新用户余额信息。
|
||||
|
||||
### 接口信息
|
||||
- **方法名**: `updateUserBalance`
|
||||
- **请求方式**: POST
|
||||
- **URL**: `/app/user/update-balance`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| orderId | String | 是 | 订单ID |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"userId": "用户ID",
|
||||
"balance": "更新后余额"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const result = await updateUserBalance('12345');
|
||||
if (result.code === 200) {
|
||||
console.log('用户余额更新成功');
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 微信支付订单创建接口
|
||||
|
||||
### 描述
|
||||
创建微信支付订单。
|
||||
|
||||
### 接口信息
|
||||
- **请求方式**: GET
|
||||
- **URL**: `/app/wx-payment/create/{orderNo}`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| orderNo | String | 是 | 订单编号 |
|
||||
|
||||
### 请求头
|
||||
|
||||
| 参数名 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- |
|
||||
| Authorization | 是 | Bearer 认证令牌 |
|
||||
| Clientid | 是 | 客户端ID |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"appId": "微信应用ID",
|
||||
"timeStamp": "时间戳",
|
||||
"nonceStr": "随机字符串",
|
||||
"package": "预支付交易会话标识",
|
||||
"signType": "签名类型",
|
||||
"paySign": "签名"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const res = await uni.request({
|
||||
url: `${URL}/app/wx-payment/create/${orderNo}`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||
'Clientid': uni.getStorageSync('client_id')
|
||||
}
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const payParams = res.data.data;
|
||||
await uni.requestPayment({
|
||||
...payParams,
|
||||
success: () => {
|
||||
console.log('支付成功');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('支付失败:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 设备租借指令接口
|
||||
|
||||
### 描述
|
||||
发送设备租借指令。
|
||||
|
||||
### 接口信息
|
||||
- **请求方式**: POST
|
||||
- **URL**: `/app/device/sendRentCommand`
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- | ---- |
|
||||
| orderId | String | 是 | 订单ID |
|
||||
|
||||
### 请求头
|
||||
|
||||
| 参数名 | 必须 | 描述 |
|
||||
| ----- | ---- | ---- |
|
||||
| Content-Type | 是 | application/x-www-form-urlencoded |
|
||||
| Authorization | 是 | Bearer 认证令牌 |
|
||||
| Clientid | 是 | 客户端ID |
|
||||
|
||||
### 响应参数
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```javascript
|
||||
const res = await uni.request({
|
||||
url: `${URL}/app/device/sendRentCommand`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
orderId: '12345'
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||
'Clientid': uni.getStorageSync('client_id')
|
||||
}
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('租借指令发送成功');
|
||||
}
|
||||
```
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器
|
||||
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||
export const URL = "http://192.168.5.120:8080" //本地调试
|
||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||
// export const URL = "http://192.168.5.120:8080" //本地调试
|
||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||
|
||||
export const appid = "wx2165f0be356ae7a9" //小程序appid
|
||||
+608
@@ -0,0 +1,608 @@
|
||||
export default {
|
||||
common: {
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel',
|
||||
and: 'and',
|
||||
submit: 'Submit',
|
||||
processing: 'Processing',
|
||||
submitting: 'Submitting',
|
||||
save: 'Save',
|
||||
loadFailed: 'Load failed',
|
||||
statusCode: 'Status Code',
|
||||
message: 'Message',
|
||||
none: 'None',
|
||||
unexpectedError: 'Unexpected Error',
|
||||
processException: 'Process exception',
|
||||
errorInfo: 'Error Info',
|
||||
edit: 'Edit',
|
||||
delete: 'Delete',
|
||||
search: 'Search',
|
||||
loading: 'Loading...',
|
||||
loadingData: 'Loading data...',
|
||||
loadingLocation: 'Getting location...',
|
||||
loadingMap: 'Loading map...',
|
||||
loadingPosition: 'Loading locations...',
|
||||
noData: 'No data',
|
||||
success: 'Success',
|
||||
failed: 'Failed',
|
||||
retry: 'Retry',
|
||||
back: 'Back',
|
||||
next: 'Next',
|
||||
complete: 'Complete',
|
||||
more: 'More',
|
||||
close: 'Close',
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
all: 'All',
|
||||
tips: 'Tips',
|
||||
notice: 'Notice',
|
||||
warning: 'Warning',
|
||||
error: 'Error',
|
||||
networkError: 'Network Error',
|
||||
systemError: 'System Error',
|
||||
authFailed: 'Authentication Failed',
|
||||
unauthorized: 'Unauthorized',
|
||||
loginRequired: 'Please login first',
|
||||
operationSuccess: 'Operation successful',
|
||||
operationFailed: 'Operation failed',
|
||||
refresh: 'Refresh',
|
||||
pull: 'Pull to refresh',
|
||||
release: 'Release to refresh'
|
||||
},
|
||||
|
||||
nav: {
|
||||
home: 'Home',
|
||||
my: 'Me',
|
||||
orders: 'Orders',
|
||||
settings: 'Settings',
|
||||
back: 'Back',
|
||||
title: 'FengDianZhe'
|
||||
},
|
||||
|
||||
app: {
|
||||
name: 'FengDianZhe',
|
||||
slogan: 'Fan & Power Bank Rental',
|
||||
fullName: 'FengDianZhe',
|
||||
welcome: 'Welcome'
|
||||
},
|
||||
|
||||
home: {
|
||||
title: 'FengDianZhe',
|
||||
nearbyDevices: 'Nearby',
|
||||
scanToUse: 'Scan',
|
||||
personalCenter: 'Profile',
|
||||
useGuide: 'Guide',
|
||||
navigate: 'Navigate',
|
||||
relocate: 'Relocate',
|
||||
search: 'Search',
|
||||
service: 'Service',
|
||||
searchPlaceholder: 'Search locations',
|
||||
nearbyDeviceLocation: 'Nearby',
|
||||
noNearbyDevice: 'No devices nearby',
|
||||
relocating: 'Locating...',
|
||||
locateSuccess: 'Located',
|
||||
locateFailed: 'Location failed',
|
||||
invalidQRCode: 'Invalid QR code',
|
||||
scanFailed: 'Scan failed',
|
||||
noticeTitle: 'Notice',
|
||||
getLocationFailed: 'Location unavailable'
|
||||
},
|
||||
|
||||
guide: {
|
||||
title: 'How to Use',
|
||||
step1Title: 'Scan QR Code',
|
||||
step1Desc: 'Find a device and scan its QR code',
|
||||
step2Title: 'No Deposit',
|
||||
step2Desc: 'Rent with WeChat Pay Score, no deposit needed',
|
||||
step3Title: 'Start Using',
|
||||
step3Desc: 'Device unlocks, take out the fan',
|
||||
step4Title: 'Return',
|
||||
step4Desc: 'Insert fan back when done'
|
||||
},
|
||||
|
||||
location: {
|
||||
rent: 'Available',
|
||||
return: 'Returnable',
|
||||
navigate: 'Navigate',
|
||||
distance: 'Distance',
|
||||
businessHours: 'Business Hours: ',
|
||||
navigateHere: 'Navigate Here',
|
||||
coordinateError: 'Invalid location coordinates',
|
||||
notExist: 'Location does not exist'
|
||||
},
|
||||
|
||||
device: {
|
||||
reportError: 'Report Error',
|
||||
scanToUse: 'Scan to Use',
|
||||
deviceInfo: 'Device Info',
|
||||
deviceNo: 'Device No.',
|
||||
location: 'Location',
|
||||
businessHours: 'Business Hours',
|
||||
pricing: 'Pricing',
|
||||
pricingText: '$0.7/hour, $5/24 hours, Max $125',
|
||||
getDeviceInfoFailed: 'Failed to get device info',
|
||||
available: 'Available',
|
||||
offline: 'Offline',
|
||||
pricingRules: 'Pricing Rules',
|
||||
capLimit: ' Cap',
|
||||
usageInstructions: 'Usage Instructions',
|
||||
checkBeforeUse: 'Please check if the device is in good condition before use',
|
||||
autoChargeOvertime: 'Overtime will be charged automatically by hour',
|
||||
useInDesignatedArea: 'Please use the device in designated area',
|
||||
rentDepositFree: 'Rent Deposit-free',
|
||||
wxPayScoreDesc: 'WeChat Pay Score | 550+ points enjoy',
|
||||
checking: 'Checking',
|
||||
deviceNoNotRecognized: 'Device number not recognized',
|
||||
processFailed: 'Process failed, please try again later',
|
||||
sharedFan: 'Shared Fan',
|
||||
deviceNoRequired: 'Device number is required',
|
||||
rentFailed: 'Device rent failed',
|
||||
rentSuccess: 'Rent successful',
|
||||
rentFailedRetry: 'Rent failed, please retry',
|
||||
getPayParamsFailed: 'Failed to get payment parameters',
|
||||
payScoreFailedCancelled: 'Pay score call failed, order cancelled'
|
||||
},
|
||||
|
||||
order: {
|
||||
myOrders: 'My Orders',
|
||||
noOrderRecord: 'No order records',
|
||||
getOrderListFailed: 'Failed to get order list',
|
||||
confirmCancelContent: 'Are you sure to cancel this order?',
|
||||
orderDetail: 'Order Detail',
|
||||
orderNo: 'Order No.',
|
||||
orderStatus: 'Order Status',
|
||||
deviceNo: 'Device No.',
|
||||
rentLocation: 'Rent Location',
|
||||
rentTime: 'Rent Time',
|
||||
returnTime: 'Return Time',
|
||||
startTime: 'Start Time',
|
||||
endTime: 'End Time',
|
||||
duration: 'Duration',
|
||||
amount: 'Amount',
|
||||
totalAmount: 'Total Amount',
|
||||
payAmount: 'Pay Amount',
|
||||
deposit: 'Deposit',
|
||||
rentFee: 'Rent Fee',
|
||||
payNow: 'Pay Now',
|
||||
cancelOrder: 'Cancel Order',
|
||||
quickReturn: 'Quick Return',
|
||||
returnDevice: 'Return Device',
|
||||
viewDetails: 'View Details',
|
||||
orderCompleted: 'Order Completed',
|
||||
orderCancelled: 'Order Cancelled',
|
||||
waitingForPayment: 'Pending',
|
||||
inUse: 'In Use',
|
||||
finished: 'Finished',
|
||||
cancelled: 'Cancelled',
|
||||
renting: 'Renting',
|
||||
rentFan: 'Rent Fan',
|
||||
noOrder: 'No orders in use',
|
||||
getOrderFailed: 'Failed to get order',
|
||||
paymentSuccess: 'Payment successful',
|
||||
paymentFailed: 'Payment failed',
|
||||
cancelSuccess: 'Cancelled successfully',
|
||||
cancelFailed: 'Cancel failed',
|
||||
returnSuccess: 'Returned successfully',
|
||||
returnFailed: 'Return failed',
|
||||
confirmCancel: 'Confirm to cancel order?',
|
||||
confirmReturn: 'Confirm to return device?',
|
||||
wxPayScore: 'WeChat Pay Score',
|
||||
depositFree: 'Deposit-free',
|
||||
memberOrder: 'Member Order',
|
||||
wxPay: 'WeChat Pay',
|
||||
depositPay: 'Deposit Pay',
|
||||
paymentInProgress: 'Payment in Progress',
|
||||
paymentFailedRetry: 'Payment failed, please try again',
|
||||
pleasePaySoon: 'Please complete payment soon',
|
||||
pleaseReturnInTime: 'Please take good care of the device and return it in time',
|
||||
returnedThankYou: 'Your fan has been returned, thank you for using',
|
||||
used: 'Used',
|
||||
rentInfo: 'Rent Information',
|
||||
fanNo: 'Fan No.',
|
||||
rentMethod: 'Rent Method',
|
||||
returnLocation: 'Return Location',
|
||||
paid: 'Paid',
|
||||
canExpressReturn: ' later for express return',
|
||||
pauseBilling: 'Pause Billing',
|
||||
rentAgain: 'Rent Again',
|
||||
backToHome: 'Back to Home',
|
||||
feeAppeal: 'Fee Appeal',
|
||||
orderIdRequired: 'Order ID is required',
|
||||
refundSuccess: 'Refund request successful',
|
||||
refundFailed: 'Refund request failed',
|
||||
orderNotExist: 'Order info does not exist',
|
||||
currentFee: 'Current Fee',
|
||||
returnInstructions: 'Return Instructions',
|
||||
ensureDeviceIntact: 'Please ensure the device is intact',
|
||||
insertFanBack: 'Insert the fan back to original or empty slot',
|
||||
autoDetectReturn: 'System will auto-detect return and process refund',
|
||||
autoJumpAfterReturn: 'Will auto-jump to success page after return',
|
||||
refreshStatus: 'Refresh Status',
|
||||
countdown: 'Countdown',
|
||||
pauseAndExpress: 'Pause billing, express return',
|
||||
orderInfoMissing: 'Order info missing',
|
||||
returnSuccessMessage: 'Fan returned successfully, remaining deposit will be refunded',
|
||||
noOrderInUse: 'No order in use found',
|
||||
pleaseRefreshManually: 'Please refresh manually to check return status',
|
||||
cancelling: 'Cancelling order',
|
||||
cancelFailedContactService: 'Cancel failed, please contact customer service',
|
||||
getOrderStatusFailed: 'Failed to get order status',
|
||||
syncSuccess: 'Status synced successfully',
|
||||
syncFailed: 'Sync failed'
|
||||
},
|
||||
|
||||
user: {
|
||||
clickToLogin: 'Login',
|
||||
loginPrompt: 'Login to continue',
|
||||
personalCenter: 'Profile',
|
||||
depositBalance: 'Balance',
|
||||
withdraw: 'Withdraw',
|
||||
commonServices: 'Services',
|
||||
quickReturn: 'Quick Return',
|
||||
quickReturnDesc: '(View active orders)',
|
||||
expressReturn: 'Express Return',
|
||||
myOrders: 'Orders',
|
||||
customerService: 'Support',
|
||||
feedback: 'Feedback',
|
||||
businessLicense: 'License',
|
||||
cooperation: 'Partner',
|
||||
settings: 'Settings',
|
||||
userAgreement: 'Terms',
|
||||
privacyPolicy: 'Privacy',
|
||||
version: 'v',
|
||||
logout: 'Logout',
|
||||
confirmLogout: 'Logout?',
|
||||
logoutSuccess: 'Logged out',
|
||||
getUserInfoFailed: 'Failed',
|
||||
updateSuccess: 'Updated',
|
||||
updateFailed: 'Failed',
|
||||
avatarUpdated: 'Avatar updated',
|
||||
avatarUploadFailed: 'Upload failed',
|
||||
noAvatar: 'No avatar',
|
||||
noAvatarUrl: 'Failed',
|
||||
avatarDownloadFailed: 'Download failed',
|
||||
notLoggedIn: 'Not logged in',
|
||||
phoneNotBound: 'No phone',
|
||||
balanceDesc: 'Available for rental'
|
||||
},
|
||||
|
||||
auth: {
|
||||
authTitle: 'Phone Login',
|
||||
authDesc: 'We need your phone for service and contact',
|
||||
getPhoneNumber: 'Login with Phone',
|
||||
notNow: 'Skip',
|
||||
authRequired: 'Login Required',
|
||||
authSuccess: 'Success',
|
||||
authFailed: 'Failed',
|
||||
loginTitle: 'Login',
|
||||
loginDesc: 'Login for better experience',
|
||||
getUserInfoSuccess: 'Success',
|
||||
getUserInfoFailed: 'Failed',
|
||||
pleaseUseInWechat: 'Use in WeChat',
|
||||
agreeToTerms: 'I agree to',
|
||||
pleaseAgreeToTerms: 'Please agree to terms',
|
||||
loginSuccess: 'Login successful',
|
||||
loginFailed: 'Login failed',
|
||||
phoneCancelled: 'Cancelled',
|
||||
goToLogin: 'Login',
|
||||
authDescShort: 'Phone number required for service',
|
||||
phoneRequired: 'Phone required',
|
||||
getting: 'Loading...',
|
||||
phoneSuccess: 'Success',
|
||||
phoneError: 'Error',
|
||||
phoneGetFailed: 'Failed',
|
||||
authCodeFailed: 'Auth failed'
|
||||
},
|
||||
|
||||
payment: {
|
||||
paymentAmount: 'Amount',
|
||||
paymentMethod: 'Method',
|
||||
wechatPay: 'WeChat',
|
||||
alipay: 'Alipay',
|
||||
balance: 'Balance',
|
||||
payNow: 'Pay',
|
||||
paying: 'Processing...',
|
||||
paymentSuccess: 'Success',
|
||||
paymentFailed: 'Failed',
|
||||
paymentCancelled: 'Cancelled',
|
||||
orderPayment: 'Payment',
|
||||
waitingForPayment: 'Pending',
|
||||
pleasePayIn15Min: 'Pay within 15 min',
|
||||
orderInfo: 'Order',
|
||||
createTime: 'Created',
|
||||
contactPhone: 'Phone',
|
||||
feeInfo: 'Fee',
|
||||
deposit: 'Deposit',
|
||||
package: 'Package',
|
||||
total: 'Total',
|
||||
paymentFailedRetry: 'Payment failed, retry?',
|
||||
createPayOrderFailed: 'Failed'
|
||||
},
|
||||
|
||||
feedback: {
|
||||
title: 'Feedback',
|
||||
placeholder: 'Describe the issue',
|
||||
submit: 'Submit',
|
||||
submitSuccess: 'Submitted',
|
||||
submitFailed: 'Failed',
|
||||
contentRequired: 'Enter details',
|
||||
issueType: 'Type',
|
||||
issueDescription: 'Description',
|
||||
imageUpload: 'Photo (Optional)',
|
||||
uploadImage: 'Upload',
|
||||
contactInfo: 'Contact',
|
||||
contactPlaceholder: 'Your phone',
|
||||
pleaseSelectType: 'Select type',
|
||||
pleaseDescribe: 'Describe issue',
|
||||
pleaseContact: 'Leave contact',
|
||||
imageUploadFailed: 'Upload failed',
|
||||
deviceFault: 'Device Fault',
|
||||
chargingIssue: 'Charging',
|
||||
usageSuggestion: 'Suggestion',
|
||||
other: 'Other'
|
||||
},
|
||||
|
||||
help: {
|
||||
title: 'Customer Service',
|
||||
commonQuestions: 'Common Questions',
|
||||
contactUs: 'Contact Us',
|
||||
phone: 'Phone',
|
||||
email: 'Email',
|
||||
workingHours: 'Working Hours',
|
||||
functionDeveloping: 'Feature in development'
|
||||
},
|
||||
|
||||
settings: {
|
||||
title: 'Settings',
|
||||
language: 'Language',
|
||||
languageSetting: 'Language Setting',
|
||||
chinese: '简体中文',
|
||||
english: 'English',
|
||||
notification: 'Notification',
|
||||
privacy: 'Privacy',
|
||||
about: 'About',
|
||||
clearCache: 'Clear Cache',
|
||||
cacheCleared: 'Cache cleared',
|
||||
logout: 'Logout',
|
||||
confirmLogout: 'Confirm to logout?',
|
||||
logoutSuccess: 'Logout successful'
|
||||
},
|
||||
|
||||
express: {
|
||||
title: 'Express Return',
|
||||
addReturn: 'New Return',
|
||||
returnRecord: 'Records',
|
||||
expressNo: 'Tracking No.',
|
||||
expressCompany: 'Courier',
|
||||
sendTime: 'Sent',
|
||||
receivedTime: 'Received',
|
||||
status: 'Status',
|
||||
pending: 'Pending',
|
||||
shipped: 'Shipped',
|
||||
received: 'Received',
|
||||
detail: 'Detail',
|
||||
recipientInfo: 'Ship To',
|
||||
recipientName: 'FengDianZhe 18163601305',
|
||||
recipientAddress: 'Rm 623, Bldg A2, Xinchanghai Park, Luogu St, Yuelu, Changsha, Hunan',
|
||||
copyAllInfo: 'Copy All',
|
||||
recipient: 'To',
|
||||
recipientAddressLabel: 'Address',
|
||||
copySuccess: 'Copied',
|
||||
copyFailed: 'Failed',
|
||||
noReturnRecord: 'No records',
|
||||
toFill: 'Fill',
|
||||
userPhone: 'Phone',
|
||||
billingPaused: 'Paused',
|
||||
completed: 'Done',
|
||||
processing: 'Processing',
|
||||
getListFailed: 'Load failed',
|
||||
loadFailed: 'Failed',
|
||||
returnCompleted: 'Return Completed',
|
||||
returnCompletedDesc: 'Your express has been successfully returned',
|
||||
processingDesc: 'Processing your return request',
|
||||
pendingDesc: 'Waiting to process return request',
|
||||
expressInfo: 'Express Info',
|
||||
trackingNo: 'Tracking No.',
|
||||
packageType: 'Package Type',
|
||||
packageWeight: 'Package Weight',
|
||||
returnInfo: 'Return Info',
|
||||
returnAddress: 'Return Address',
|
||||
returnTime: 'Return Time',
|
||||
processTime: 'Process Time',
|
||||
completeTime: 'Complete Time',
|
||||
remarkInfo: 'Remark Info',
|
||||
copyTrackingNo: 'Copy Tracking No.',
|
||||
trackingNoCopied: 'Tracking number copied',
|
||||
workingHours: 'Mon-Sun 09:00-22:00',
|
||||
call: 'Call',
|
||||
returnDetail: 'Return Detail',
|
||||
getDetailFailed: 'Failed to get detail',
|
||||
fillExpress: 'Express Return',
|
||||
openTime: 'Start Time',
|
||||
fillExpressInfo: 'Fill Express Return Info',
|
||||
contactPhone: 'Contact Phone',
|
||||
fillTrackingPlaceholder: 'Enter tracking number to fill',
|
||||
trackingPlaceholder: 'Enter tracking number (optional)',
|
||||
confirmFill: 'Confirm Fill',
|
||||
submitInfo: 'Submit Info',
|
||||
orderNoMissing: 'Order number missing',
|
||||
getRecordFailed: 'Failed to get record',
|
||||
existingReturnNotice: 'Express return request exists, go to fill tracking number?',
|
||||
goToFill: 'Go to Fill',
|
||||
alreadyHasRecord: 'Return record already exists',
|
||||
pleaseEnterValidPhone: 'Please enter valid contact phone',
|
||||
pleaseEnterTrackingNo: 'Please enter tracking number',
|
||||
filling: 'Filling',
|
||||
fillSuccess: 'Fill successful',
|
||||
fillFailed: 'Fill failed',
|
||||
submitSuccess: 'Submit successful',
|
||||
submitFailed: 'Submit failed'
|
||||
},
|
||||
|
||||
join: {
|
||||
title: 'Cooperation',
|
||||
cooperationTitle: 'Cooperation Method',
|
||||
contactUs: 'Contact Us',
|
||||
phone: 'Phone',
|
||||
email: 'Email',
|
||||
submit: 'Submit Application',
|
||||
name: 'Name',
|
||||
contactPhone: 'Contact',
|
||||
city: 'City',
|
||||
intention: 'Intention',
|
||||
placeholder: 'Please briefly describe your cooperation intention...',
|
||||
submitSuccess: 'Submitted successfully, we will contact you soon',
|
||||
submitFailed: 'Submit failed, please try again later',
|
||||
pageLoadFailed: 'Page load failed'
|
||||
},
|
||||
|
||||
legal: {
|
||||
agreement: 'User Agreement',
|
||||
privacy: 'Privacy Policy',
|
||||
termsOfService: 'Terms of Service',
|
||||
lastUpdate: 'Last Update',
|
||||
applicableToService: 'Applicable to "FengDianZhe" shared fan rental service',
|
||||
footerNotice: 'If you have questions about this agreement, please go to "My-Customer Service"',
|
||||
footerNoticePolicy: 'If you have questions about this policy, please go to "My-Customer Service"'
|
||||
},
|
||||
|
||||
search: {
|
||||
title: 'Find Device',
|
||||
placeholder: 'Enter location name or address',
|
||||
history: 'Search History',
|
||||
clear: 'Clear History',
|
||||
noResult: 'No results found',
|
||||
searching: 'Searching...',
|
||||
invalidCoordinate: 'Invalid coordinates',
|
||||
positionInfoError: 'Location info error'
|
||||
},
|
||||
|
||||
share: {
|
||||
title: 'FengDianZhe - Shared Fan & Power Bank',
|
||||
path: '/pages/index/index'
|
||||
},
|
||||
|
||||
error: {
|
||||
networkError: 'Network connection failed',
|
||||
serverError: 'Server error',
|
||||
timeout: 'Request timeout',
|
||||
unknown: 'Unknown error',
|
||||
tryAgain: 'Please try again later'
|
||||
},
|
||||
|
||||
time: {
|
||||
hour: 'hour',
|
||||
minute: 'minute',
|
||||
second: 'second',
|
||||
day: 'day',
|
||||
week: 'week',
|
||||
month: 'month',
|
||||
year: 'year',
|
||||
justNow: 'Just now',
|
||||
minutesAgo: 'minutes ago',
|
||||
hoursAgo: 'hours ago',
|
||||
daysAgo: 'days ago',
|
||||
yesterday: 'Yesterday',
|
||||
today: 'Today',
|
||||
tomorrow: 'Tomorrow'
|
||||
},
|
||||
|
||||
unit: {
|
||||
yuan: 'CNY',
|
||||
meter: 'm',
|
||||
km: 'km',
|
||||
piece: 'pc',
|
||||
times: 'times'
|
||||
},
|
||||
|
||||
waiting: {
|
||||
title: 'Ejecting',
|
||||
preparing: 'Preparing...',
|
||||
longTimeNotice: 'Taking too long? Contact staff',
|
||||
deviceEjecting: 'Ejecting...',
|
||||
rentFailed: 'Rental failed',
|
||||
timeout: 'Timeout'
|
||||
},
|
||||
|
||||
success: {
|
||||
paymentSuccess: 'Payment Successful',
|
||||
paymentSuccessDesc: 'Your order has been paid successfully',
|
||||
orderInfo: 'Order Info',
|
||||
paymentAmount: 'Payment Amount',
|
||||
paymentTime: 'Payment Time',
|
||||
deviceStatus: 'Device Status',
|
||||
preparingDevice: 'Preparing your device, please wait...',
|
||||
deviceReady: 'Device ready, please take your fan',
|
||||
deviceFailed: 'Device ejection failed, please contact customer service',
|
||||
backToHome: 'Back to Home',
|
||||
viewOrder: 'View Order',
|
||||
returnSuccess: 'Return Successful',
|
||||
returnSuccessDesc: 'Your fan has been returned, fee deducted from deposit',
|
||||
usedTime: 'Used Time',
|
||||
packageTime: 'Package Time',
|
||||
extraTime: 'Extra Time',
|
||||
returnTime: 'Return Time',
|
||||
packageFee: 'Package Fee',
|
||||
extraFee: 'Extra Fee',
|
||||
totalFee: 'Total Fee',
|
||||
depositAmount: 'Deposit',
|
||||
refundAmount: 'Refund Amount',
|
||||
refundStatus: 'Refund Status',
|
||||
refundNotice: 'Refund Notice',
|
||||
refundNotice1: 'Deposit balance needs to be manually withdrawn',
|
||||
refundNotice2: 'Withdrawal will be refunded to original payment account within 1-3 business days',
|
||||
refundNotice3: 'If you have questions, please contact customer service',
|
||||
applyRefund: 'Apply Refund',
|
||||
refundWaiting: 'Pending',
|
||||
refundProcessing: 'Processing',
|
||||
refundSuccess: 'Refunded',
|
||||
refundFailed: 'Failed'
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'Deposit Management',
|
||||
depositBalance: 'Deposit Balance',
|
||||
withdraw: 'Withdraw',
|
||||
withdrawRecord: 'Withdraw Record',
|
||||
withdrawAmount: 'Withdraw Amount',
|
||||
withdrawStatus: 'Withdraw Status',
|
||||
applyWithdraw: 'Apply Withdraw',
|
||||
withdrawSuccess: 'Withdraw successful',
|
||||
withdrawFailed: 'Withdraw failed',
|
||||
noBalance: 'No balance to withdraw',
|
||||
confirmWithdraw: 'Confirm Withdraw',
|
||||
withdrawDesc: 'Deposit will be refunded to original account within 0-7 business days',
|
||||
withdrawing: 'Withdrawing...',
|
||||
withdrawSubmitted: 'Withdraw request submitted',
|
||||
withdrawNotice: 'Withdraw Notice',
|
||||
withdrawNotice1: 'Withdrawal will be refunded to original payment account',
|
||||
withdrawNotice2: 'Withdrawal expected to arrive within 0-7 business days',
|
||||
withdrawNotice3: 'If delayed, please contact customer service',
|
||||
depositRecord: 'Deposit Record',
|
||||
orderNotReturned: 'Current order not returned, please return before withdraw',
|
||||
alreadyRefunded: 'Deposit already refunded',
|
||||
refundProcessing: 'Refund processing, please wait'
|
||||
},
|
||||
|
||||
userProfile: {
|
||||
title: 'Personal Info',
|
||||
avatar: 'Avatar',
|
||||
nickname: 'Nickname',
|
||||
phone: 'Phone',
|
||||
edit: 'Edit',
|
||||
save: 'Save',
|
||||
cancel: 'Cancel',
|
||||
clickToChange: 'Click to change avatar',
|
||||
notSet: 'Not set',
|
||||
notBound: 'Not bound',
|
||||
balance: 'Balance',
|
||||
enterNickname: 'Enter new nickname',
|
||||
nicknameRequired: 'Nickname cannot be empty',
|
||||
saving: 'Saving...',
|
||||
nicknameUpdated: 'Nickname updated successfully',
|
||||
updateFailed: 'Update failed',
|
||||
uploading: 'Uploading...'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import zhCN from './zh-CN.js'
|
||||
import enUS from './en-US.js'
|
||||
|
||||
export default {
|
||||
'zh-CN': zhCN,
|
||||
'en-US': enUS
|
||||
}
|
||||
|
||||
+608
@@ -0,0 +1,608 @@
|
||||
export default {
|
||||
common: {
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
and: '和',
|
||||
submit: '提交',
|
||||
processing: '处理中',
|
||||
submitting: '提交中',
|
||||
save: '保存',
|
||||
loadFailed: '加载失败',
|
||||
statusCode: '状态码',
|
||||
message: '消息',
|
||||
none: '无',
|
||||
unexpectedError: '意外错误',
|
||||
processException: '处理过程发生异常',
|
||||
errorInfo: '错误信息',
|
||||
edit: '编辑',
|
||||
delete: '删除',
|
||||
search: '搜索',
|
||||
loading: '加载中...',
|
||||
loadingData: '正在获取数据...',
|
||||
loadingLocation: '正在获取位置信息...',
|
||||
loadingMap: '地图加载中...',
|
||||
loadingPosition: '正在获取场地信息...',
|
||||
noData: '暂无数据',
|
||||
success: '成功',
|
||||
failed: '失败',
|
||||
retry: '重试',
|
||||
back: '返回',
|
||||
next: '下一步',
|
||||
complete: '完成',
|
||||
more: '更多',
|
||||
close: '关闭',
|
||||
yes: '是',
|
||||
no: '否',
|
||||
all: '全部',
|
||||
tips: '提示',
|
||||
notice: '通知',
|
||||
warning: '警告',
|
||||
error: '错误',
|
||||
networkError: '网络错误',
|
||||
systemError: '系统错误',
|
||||
authFailed: '认证失败',
|
||||
unauthorized: '未授权',
|
||||
loginRequired: '请先登录',
|
||||
operationSuccess: '操作成功',
|
||||
operationFailed: '操作失败',
|
||||
refresh: '刷新',
|
||||
pull: '下拉刷新',
|
||||
release: '释放刷新'
|
||||
},
|
||||
|
||||
nav: {
|
||||
home: '首页',
|
||||
my: '我的',
|
||||
orders: '订单',
|
||||
settings: '设置',
|
||||
back: '返回',
|
||||
title: '风电者共享风扇&暖手充电宝'
|
||||
},
|
||||
|
||||
app: {
|
||||
name: '风电者',
|
||||
slogan: '共享风扇暖手充电宝',
|
||||
fullName: '风电者 - 共享风扇暖手充电宝',
|
||||
welcome: '欢迎使用风电者'
|
||||
},
|
||||
|
||||
home: {
|
||||
title: '风电者共享风扇&暖手充电宝',
|
||||
nearbyDevices: '附近设备',
|
||||
scanToUse: '扫码使用',
|
||||
personalCenter: '个人中心',
|
||||
useGuide: '使用指南',
|
||||
navigate: '导航',
|
||||
relocate: '重新定位',
|
||||
search: '搜索',
|
||||
service: '客服',
|
||||
searchPlaceholder: '搜索附近场地',
|
||||
nearbyDeviceLocation: '附近设备场地',
|
||||
noNearbyDevice: '附近暂无设备',
|
||||
relocating: '重新定位中...',
|
||||
locateSuccess: '定位成功',
|
||||
locateFailed: '定位失败,请检查定位权限',
|
||||
invalidQRCode: '无效的设备二维码',
|
||||
scanFailed: '扫码失败',
|
||||
noticeTitle: '通知公告',
|
||||
getLocationFailed: '获取位置失败,显示默认地图'
|
||||
},
|
||||
|
||||
guide: {
|
||||
title: '使用指南',
|
||||
step1Title: '扫码使用',
|
||||
step1Desc: '找到附近设备,扫描设备上的二维码',
|
||||
step2Title: '免押金支付',
|
||||
step2Desc: '无需支付押金,使用支付分免押即可完成租借',
|
||||
step3Title: '开始使用',
|
||||
step3Desc: '设备自动解锁,风扇弹出后取出即可开始使用',
|
||||
step4Title: '归还设备',
|
||||
step4Desc: '使用完毕后,按照设备规格要求将风扇还入即可结束订单'
|
||||
},
|
||||
|
||||
location: {
|
||||
rent: '可租借',
|
||||
return: '可归还',
|
||||
navigate: '导航',
|
||||
distance: '距离',
|
||||
businessHours: '营业时间:',
|
||||
navigateHere: '导航去这',
|
||||
coordinateError: '该场地坐标信息异常',
|
||||
notExist: '场地不存在'
|
||||
},
|
||||
|
||||
device: {
|
||||
reportError: '设备报错',
|
||||
scanToUse: '扫码使用',
|
||||
deviceInfo: '设备信息',
|
||||
deviceNo: '设备号',
|
||||
location: '地点',
|
||||
businessHours: '营业时间',
|
||||
pricing: '计费',
|
||||
pricingText: '5元/小时,36元/24小时,总计¥899元',
|
||||
getDeviceInfoFailed: '获取设备信息失败',
|
||||
available: '可使用',
|
||||
offline: '离线',
|
||||
pricingRules: '计费规则',
|
||||
capLimit: '元封顶',
|
||||
usageInstructions: '使用说明',
|
||||
checkBeforeUse: '请在使用前检查设备是否完好',
|
||||
autoChargeOvertime: '超出使用时间将自动按小时计费',
|
||||
useInDesignatedArea: '请在指定区域内使用设备',
|
||||
rentDepositFree: '免押金租借',
|
||||
wxPayScoreDesc: '微信支付分 | 550分以上优享',
|
||||
checking: '检查中',
|
||||
deviceNoNotRecognized: '未识别到设备编号',
|
||||
processFailed: '处理失败,请稍后重试',
|
||||
sharedFan: '共享风扇',
|
||||
deviceNoRequired: '设备号不能为空',
|
||||
rentFailed: '设备租借失败',
|
||||
rentSuccess: '租借成功',
|
||||
rentFailedRetry: '租借失败,请重试',
|
||||
getPayParamsFailed: '获取支付参数失败',
|
||||
payScoreFailedCancelled: '支付分调用失败,订单已取消'
|
||||
},
|
||||
|
||||
order: {
|
||||
myOrders: '我的订单',
|
||||
noOrderRecord: '暂无订单记录',
|
||||
getOrderListFailed: '获取订单列表失败',
|
||||
confirmCancelContent: '确定要取消此订单吗?',
|
||||
orderDetail: '订单详情',
|
||||
orderNo: '订单号',
|
||||
orderStatus: '订单状态',
|
||||
deviceNo: '设备号',
|
||||
rentLocation: '租借地点',
|
||||
rentTime: '租借时间',
|
||||
returnTime: '归还时间',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
duration: '使用时长',
|
||||
amount: '金额',
|
||||
totalAmount: '总金额',
|
||||
payAmount: '支付金额',
|
||||
deposit: '押金',
|
||||
rentFee: '租金',
|
||||
payNow: '立即支付',
|
||||
cancelOrder: '取消订单',
|
||||
quickReturn: '快速归还',
|
||||
returnDevice: '归还设备',
|
||||
viewDetails: '查看详情',
|
||||
orderCompleted: '订单已完成',
|
||||
orderCancelled: '订单已取消',
|
||||
waitingForPayment: '待支付',
|
||||
inUse: '使用中',
|
||||
finished: '已完成',
|
||||
cancelled: '已取消',
|
||||
renting: '租借中',
|
||||
rentFan: '租借风扇',
|
||||
noOrder: '暂无使用中的订单',
|
||||
getOrderFailed: '获取订单失败',
|
||||
paymentSuccess: '支付成功',
|
||||
paymentFailed: '支付失败',
|
||||
cancelSuccess: '取消成功',
|
||||
cancelFailed: '取消失败',
|
||||
returnSuccess: '归还成功',
|
||||
returnFailed: '归还失败',
|
||||
confirmCancel: '确认取消订单?',
|
||||
confirmReturn: '确认归还设备?',
|
||||
wxPayScore: '微信支付分',
|
||||
depositFree: '免押租借',
|
||||
memberOrder: '会员订单',
|
||||
wxPay: '微信支付',
|
||||
depositPay: '押金租借',
|
||||
paymentInProgress: '支付中',
|
||||
paymentFailedRetry: '支付失败,请重新支付',
|
||||
pleasePaySoon: '请尽快完成支付',
|
||||
pleaseReturnInTime: '请妥善保管设备,使用完毕后及时归还',
|
||||
returnedThankYou: '您的风扇已归还,感谢使用',
|
||||
used: '已使用',
|
||||
rentInfo: '租借信息',
|
||||
fanNo: '风扇编号',
|
||||
rentMethod: '租借方式',
|
||||
returnLocation: '归还地点',
|
||||
paid: '已支付',
|
||||
canExpressReturn: '后可快递归还',
|
||||
pauseBilling: '暂停计费',
|
||||
rentAgain: '再次租借',
|
||||
backToHome: '返回首页',
|
||||
feeAppeal: '费用申诉',
|
||||
orderIdRequired: '订单ID不能为空',
|
||||
refundSuccess: '退款申请成功',
|
||||
refundFailed: '退款申请失败',
|
||||
orderNotExist: '订单信息不存在',
|
||||
currentFee: '当前费用',
|
||||
returnInstructions: '归还说明',
|
||||
ensureDeviceIntact: '请确保设备完好无损',
|
||||
insertFanBack: '将风扇插入原位置或空闲插口',
|
||||
autoDetectReturn: '系统将自动检测归还并处理退款',
|
||||
autoJumpAfterReturn: '归还成功后将自动跳转到成功页面',
|
||||
refreshStatus: '刷新状态',
|
||||
countdown: '倒计时',
|
||||
pauseAndExpress: '暂停计费,快递归还',
|
||||
orderInfoMissing: '缺少订单信息',
|
||||
returnSuccessMessage: '风扇已归还成功,剩余押金将退还到您的账户',
|
||||
noOrderInUse: '未找到使用中的订单',
|
||||
pleaseRefreshManually: '请手动刷新查看归还状态',
|
||||
cancelling: '取消订单中',
|
||||
cancelFailedContactService: '取消订单失败,请联系客服',
|
||||
getOrderStatusFailed: '订单状态查询失败',
|
||||
syncSuccess: '状态同步成功',
|
||||
syncFailed: '同步状态失败'
|
||||
},
|
||||
|
||||
user: {
|
||||
clickToLogin: '点击登录',
|
||||
loginPrompt: '授权登录后可查看订单与资产',
|
||||
personalCenter: '个人中心',
|
||||
depositBalance: '押金余额',
|
||||
withdraw: '提现',
|
||||
commonServices: '常用服务',
|
||||
quickReturn: '快速归还',
|
||||
quickReturnDesc: '(直接查看使用中的订单)',
|
||||
expressReturn: '快递归还记录',
|
||||
myOrders: '我的订单',
|
||||
customerService: '客服中心',
|
||||
feedback: '投诉与建议',
|
||||
businessLicense: '营业资质',
|
||||
cooperation: '合作加盟',
|
||||
settings: '设置',
|
||||
userAgreement: '《用户协议》',
|
||||
privacyPolicy: '《隐私政策》',
|
||||
version: 'v',
|
||||
logout: '退出登录',
|
||||
confirmLogout: '确认退出登录?',
|
||||
logoutSuccess: '退出成功',
|
||||
getUserInfoFailed: '获取用户信息失败',
|
||||
updateSuccess: '信息更新成功',
|
||||
updateFailed: '更新用户信息失败',
|
||||
avatarUpdated: '头像已更新',
|
||||
avatarUploadFailed: '头像更新失败',
|
||||
noAvatar: '未选择头像',
|
||||
noAvatarUrl: '未获取到头像地址',
|
||||
avatarDownloadFailed: '头像下载失败',
|
||||
notLoggedIn: '未登录',
|
||||
phoneNotBound: '未绑定手机号',
|
||||
balanceDesc: '可用于租借设备'
|
||||
},
|
||||
|
||||
auth: {
|
||||
authTitle: '授权获取手机号',
|
||||
authDesc: '为了提供更好的服务和紧急联系,需要授权获取您的手机号',
|
||||
getPhoneNumber: '手机号快捷登录',
|
||||
notNow: '暂不授权',
|
||||
authRequired: '需要授权',
|
||||
authSuccess: '授权成功',
|
||||
authFailed: '授权失败',
|
||||
loginTitle: '登录',
|
||||
loginDesc: '为保障使用体验,请先完成登录',
|
||||
getUserInfoSuccess: '获取用户信息成功',
|
||||
getUserInfoFailed: '获取用户信息失败',
|
||||
pleaseUseInWechat: '请在微信小程序中使用此功能',
|
||||
agreeToTerms: '我已阅读并同意',
|
||||
pleaseAgreeToTerms: '请先阅读并同意《用户协议》和《隐私政策》',
|
||||
loginSuccess: '登录成功',
|
||||
loginFailed: '登录失败',
|
||||
phoneCancelled: '已取消手机号授权',
|
||||
goToLogin: '去登录',
|
||||
authDescShort: '为了提供更好的服务,需要授权获取您的手机号',
|
||||
phoneRequired: '需要授权手机号才能使用设备',
|
||||
getting: '获取中...',
|
||||
phoneSuccess: '手机号获取成功',
|
||||
phoneError: '获取手机号异常',
|
||||
phoneGetFailed: '获取手机号失败',
|
||||
authCodeFailed: '获取授权码失败'
|
||||
},
|
||||
|
||||
payment: {
|
||||
paymentAmount: '支付金额',
|
||||
paymentMethod: '支付方式',
|
||||
wechatPay: '微信支付',
|
||||
alipay: '支付宝',
|
||||
balance: '余额支付',
|
||||
payNow: '立即支付',
|
||||
paying: '支付中...',
|
||||
paymentSuccess: '支付成功',
|
||||
paymentFailed: '支付失败',
|
||||
paymentCancelled: '支付已取消',
|
||||
orderPayment: '订单支付',
|
||||
waitingForPayment: '等待支付',
|
||||
pleasePayIn15Min: '请在15分钟内完成支付',
|
||||
orderInfo: '订单信息',
|
||||
createTime: '创建时间',
|
||||
contactPhone: '联系电话',
|
||||
feeInfo: '费用信息',
|
||||
deposit: '押金',
|
||||
package: '套餐',
|
||||
total: '合计',
|
||||
paymentFailedRetry: '支付失败,请重试',
|
||||
createPayOrderFailed: '创建支付订单失败'
|
||||
},
|
||||
|
||||
feedback: {
|
||||
title: '投诉与建议',
|
||||
placeholder: '请详细描述您遇到的问题,以便我们更好地为您解决',
|
||||
submit: '提交反馈',
|
||||
submitSuccess: '反馈成功',
|
||||
submitFailed: '反馈失败',
|
||||
contentRequired: '请输入内容',
|
||||
issueType: '问题类型',
|
||||
issueDescription: '问题描述',
|
||||
imageUpload: '图片上传(选填)',
|
||||
uploadImage: '上传图片',
|
||||
contactInfo: '联系方式',
|
||||
contactPlaceholder: '请留下您的手机号,方便我们联系您',
|
||||
pleaseSelectType: '请选择问题类型',
|
||||
pleaseDescribe: '请描述您的问题',
|
||||
pleaseContact: '请留下联系方式',
|
||||
imageUploadFailed: '图片上传失败',
|
||||
deviceFault: '设备故障',
|
||||
chargingIssue: '收费问题',
|
||||
usageSuggestion: '使用建议',
|
||||
other: '其他'
|
||||
},
|
||||
|
||||
help: {
|
||||
title: '客服中心',
|
||||
commonQuestions: '常见问题',
|
||||
contactUs: '联系我们',
|
||||
phone: '电话',
|
||||
email: '邮箱',
|
||||
workingHours: '工作时间',
|
||||
functionDeveloping: '功能开发中'
|
||||
},
|
||||
|
||||
settings: {
|
||||
title: '设置',
|
||||
language: '语言',
|
||||
languageSetting: '语言设置',
|
||||
chinese: '简体中文',
|
||||
english: 'English',
|
||||
notification: '通知',
|
||||
privacy: '隐私',
|
||||
about: '关于',
|
||||
clearCache: '清除缓存',
|
||||
cacheCleared: '缓存已清除',
|
||||
logout: '退出登录',
|
||||
confirmLogout: '确认退出登录?',
|
||||
logoutSuccess: '退出成功'
|
||||
},
|
||||
|
||||
express: {
|
||||
title: '快递归还',
|
||||
addReturn: '添加归还',
|
||||
returnRecord: '快递归还记录',
|
||||
expressNo: '快递单号',
|
||||
expressCompany: '快递公司',
|
||||
sendTime: '寄出时间',
|
||||
receivedTime: '签收时间',
|
||||
status: '状态',
|
||||
pending: '待处理',
|
||||
shipped: '已寄出',
|
||||
received: '已签收',
|
||||
detail: '详情',
|
||||
recipientInfo: '收件信息',
|
||||
recipientName: '风电者 18163601305',
|
||||
recipientAddress: '湖南省长沙市岳麓区麓谷街道新长海尖科技园A2栋623',
|
||||
copyAllInfo: '一键复制全部信息',
|
||||
recipient: '收件人',
|
||||
recipientAddressLabel: '收件地址',
|
||||
copySuccess: '全部信息已复制',
|
||||
copyFailed: '复制失败',
|
||||
noReturnRecord: '暂无归还记录',
|
||||
toFill: '待填写',
|
||||
userPhone: '用户电话',
|
||||
billingPaused: '暂停计费中',
|
||||
completed: '已完成',
|
||||
processing: '处理中',
|
||||
getListFailed: '获取列表失败',
|
||||
loadFailed: '加载失败',
|
||||
returnCompleted: '归还完成',
|
||||
returnCompletedDesc: '您的快递已成功归还',
|
||||
processingDesc: '正在处理您的归还请求',
|
||||
pendingDesc: '等待处理归还申请',
|
||||
expressInfo: '快递信息',
|
||||
trackingNo: '运单号',
|
||||
packageType: '包裹类型',
|
||||
packageWeight: '包裹重量',
|
||||
returnInfo: '归还信息',
|
||||
returnAddress: '归还地址',
|
||||
returnTime: '归还时间',
|
||||
processTime: '处理时间',
|
||||
completeTime: '完成时间',
|
||||
remarkInfo: '备注信息',
|
||||
copyTrackingNo: '复制运单号',
|
||||
trackingNoCopied: '运单号已复制',
|
||||
workingHours: '周一至周日 09:00-22:00',
|
||||
call: '拨打',
|
||||
returnDetail: '归还详情',
|
||||
getDetailFailed: '获取详情失败',
|
||||
fillExpress: '快递归还',
|
||||
openTime: '开始时间',
|
||||
fillExpressInfo: '填写快递归还信息',
|
||||
contactPhone: '联系电话',
|
||||
fillTrackingPlaceholder: '请输入需要补填的快递单号',
|
||||
trackingPlaceholder: '请输入快递单号(可先留空)',
|
||||
confirmFill: '确认补填',
|
||||
submitInfo: '提交信息',
|
||||
orderNoMissing: '缺少订单号',
|
||||
getRecordFailed: '获取记录失败',
|
||||
existingReturnNotice: '已存在快递归还申请,是否前往补填快递单号?',
|
||||
goToFill: '去补填',
|
||||
alreadyHasRecord: '已有归还记录',
|
||||
pleaseEnterValidPhone: '请填写有效联系电话',
|
||||
pleaseEnterTrackingNo: '请填写快递单号',
|
||||
filling: '补填中',
|
||||
fillSuccess: '补填成功',
|
||||
fillFailed: '补填失败',
|
||||
submitSuccess: '提交成功',
|
||||
submitFailed: '提交失败'
|
||||
},
|
||||
|
||||
join: {
|
||||
title: '合作加盟',
|
||||
cooperationTitle: '合作方式',
|
||||
contactUs: '联系我们',
|
||||
phone: '联系电话',
|
||||
email: '联系邮箱',
|
||||
submit: '提交申请',
|
||||
name: '姓名',
|
||||
contactPhone: '联系方式',
|
||||
city: '所在城市',
|
||||
intention: '合作意向',
|
||||
placeholder: '请简要说明您的合作意向...',
|
||||
submitSuccess: '提交成功,我们会尽快联系您',
|
||||
submitFailed: '提交失败,请稍后重试',
|
||||
pageLoadFailed: '页面加载失败'
|
||||
},
|
||||
|
||||
legal: {
|
||||
agreement: '用户协议',
|
||||
privacy: '隐私政策',
|
||||
termsOfService: '服务条款',
|
||||
lastUpdate: '最后更新',
|
||||
applicableToService: '适用于"风电者"共享风扇租借服务',
|
||||
footerNotice: '如对本协议有疑问,请前往"我的-客服"咨询',
|
||||
footerNoticePolicy: '如对本政策有疑问,请前往"我的-客服"咨询'
|
||||
},
|
||||
|
||||
search: {
|
||||
title: '查找设备',
|
||||
placeholder: '请输入场地名称或地址',
|
||||
history: '搜索历史',
|
||||
clear: '清除历史',
|
||||
noResult: '暂无搜索结果',
|
||||
searching: '搜索中...',
|
||||
invalidCoordinate: '该位置坐标无效',
|
||||
positionInfoError: '场地信息异常'
|
||||
},
|
||||
|
||||
share: {
|
||||
title: '风电者 - 共享风扇暖手充电宝',
|
||||
path: '/pages/index/index'
|
||||
},
|
||||
|
||||
error: {
|
||||
networkError: '网络连接失败',
|
||||
serverError: '服务器错误',
|
||||
timeout: '请求超时',
|
||||
unknown: '未知错误',
|
||||
tryAgain: '请稍后重试'
|
||||
},
|
||||
|
||||
time: {
|
||||
hour: '小时',
|
||||
minute: '分钟',
|
||||
second: '秒',
|
||||
day: '天',
|
||||
week: '周',
|
||||
month: '月',
|
||||
year: '年',
|
||||
justNow: '刚刚',
|
||||
minutesAgo: '分钟前',
|
||||
hoursAgo: '小时前',
|
||||
daysAgo: '天前',
|
||||
yesterday: '昨天',
|
||||
today: '今天',
|
||||
tomorrow: '明天'
|
||||
},
|
||||
|
||||
unit: {
|
||||
yuan: '元',
|
||||
meter: '米',
|
||||
km: '公里',
|
||||
piece: '个',
|
||||
times: '次'
|
||||
},
|
||||
|
||||
waiting: {
|
||||
title: '设备弹出中',
|
||||
preparing: '正在为您弹出设备',
|
||||
longTimeNotice: '若长时间未弹出,请联系现场工作人员或稍后重试',
|
||||
deviceEjecting: '设备弹出中,请稍候',
|
||||
rentFailed: '设备租借失败,订单已取消',
|
||||
timeout: '等待超时,请稍后重试'
|
||||
},
|
||||
|
||||
success: {
|
||||
paymentSuccess: '支付成功',
|
||||
paymentSuccessDesc: '您的订单已支付成功',
|
||||
orderInfo: '订单信息',
|
||||
paymentAmount: '支付金额',
|
||||
paymentTime: '支付时间',
|
||||
deviceStatus: '设备状态',
|
||||
preparingDevice: '正在准备您的设备,请稍候...',
|
||||
deviceReady: '设备已弹出,请取走您的风扇',
|
||||
deviceFailed: '弹出设备失败,请联系客服',
|
||||
backToHome: '返回首页',
|
||||
viewOrder: '查看订单',
|
||||
returnSuccess: '归还成功',
|
||||
returnSuccessDesc: '您的风扇已归还,费用已从押金中扣除',
|
||||
usedTime: '使用时长',
|
||||
packageTime: '套餐时长',
|
||||
extraTime: '超出时长',
|
||||
returnTime: '归还时间',
|
||||
packageFee: '套餐费用',
|
||||
extraFee: '超时费用',
|
||||
totalFee: '总费用',
|
||||
depositAmount: '押金',
|
||||
refundAmount: '退还金额',
|
||||
refundStatus: '退还状态',
|
||||
refundNotice: '退款说明',
|
||||
refundNotice1: '押金剩余金额需要您手动申请提现',
|
||||
refundNotice2: '提现申请提交后将在1-3个工作日内退还到原支付账户',
|
||||
refundNotice3: '如有疑问,请联系客服',
|
||||
applyRefund: '申请退款',
|
||||
refundWaiting: '待申请',
|
||||
refundProcessing: '处理中',
|
||||
refundSuccess: '已退款',
|
||||
refundFailed: '退款失败'
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: '押金管理',
|
||||
depositBalance: '押金余额',
|
||||
withdraw: '提现',
|
||||
withdrawRecord: '提现记录',
|
||||
withdrawAmount: '提现金额',
|
||||
withdrawStatus: '提现状态',
|
||||
applyWithdraw: '申请提现',
|
||||
withdrawSuccess: '提现成功',
|
||||
withdrawFailed: '提现失败',
|
||||
noBalance: '无可提现余额',
|
||||
confirmWithdraw: '确认提现',
|
||||
withdrawDesc: '押金将原路退回,预计0-7个工作日到账',
|
||||
withdrawing: '提现中...',
|
||||
withdrawSubmitted: '提现申请已提交',
|
||||
withdrawNotice: '提现说明',
|
||||
withdrawNotice1: '提现金额将原路退回支付账户',
|
||||
withdrawNotice2: '提现申请提交后预计0-7个工作日到账',
|
||||
withdrawNotice3: '如超时未收到,请联系客服处理',
|
||||
depositRecord: '押金记录',
|
||||
orderNotReturned: '当前订单尚未归还,请归还后再提现',
|
||||
alreadyRefunded: '押金已退还,无需重复提现',
|
||||
refundProcessing: '押金退还处理中,请耐心等待'
|
||||
},
|
||||
|
||||
userProfile: {
|
||||
title: '个人信息',
|
||||
avatar: '头像',
|
||||
nickname: '昵称',
|
||||
phone: '手机号',
|
||||
edit: '编辑',
|
||||
save: '保存',
|
||||
cancel: '取消',
|
||||
clickToChange: '点击头像更换',
|
||||
notSet: '未设置',
|
||||
notBound: '未绑定',
|
||||
balance: '余额',
|
||||
enterNickname: '请输入新昵称',
|
||||
nicknameRequired: '昵称不能为空',
|
||||
saving: '保存中...',
|
||||
nicknameUpdated: '昵称修改成功',
|
||||
updateFailed: '修改失败',
|
||||
uploading: '上传中...'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,139 @@
|
||||
import App from './App'
|
||||
import { orderMonitor } from './utils/orderMonitor.js'
|
||||
|
||||
import uView from "uview-ui";
|
||||
|
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import './uni.promisify.adaptor'
|
||||
Vue.config.productionTip = false
|
||||
|
||||
// 注册全局订单监控服务
|
||||
Vue.prototype.$orderMonitor = orderMonitor
|
||||
|
||||
App.mpType = 'app'
|
||||
Vue.use(uView)
|
||||
const app = new Vue({
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { createSSRApp } from 'vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import zhCN from './locale/zh-CN.js'
|
||||
import enUS from './locale/en-US.js'
|
||||
import uView from "uview-ui"
|
||||
|
||||
// 获取系统语言
|
||||
const getSystemLanguage = () => {
|
||||
let language = 'zh-CN'
|
||||
try {
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
if (systemInfo && systemInfo.language) {
|
||||
language = systemInfo.language === 'zh' || systemInfo.language.indexOf('zh') === 0
|
||||
? 'zh-CN'
|
||||
: 'en-US'
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取系统语言失败:', e)
|
||||
}
|
||||
return language
|
||||
}
|
||||
|
||||
// 获取用户选择的语言
|
||||
const getSavedLanguage = () => {
|
||||
try {
|
||||
const savedLang = uni.getStorageSync('language')
|
||||
if (savedLang) {
|
||||
return savedLang
|
||||
}
|
||||
const systemLang = getSystemLanguage()
|
||||
uni.setStorageSync('language', systemLang)
|
||||
return systemLang
|
||||
} catch (e) {
|
||||
console.error('语言设置出错:', e)
|
||||
return 'zh-CN'
|
||||
}
|
||||
}
|
||||
|
||||
// 创建 i18n 实例(Vue 3)
|
||||
let i18nInstance = null
|
||||
|
||||
function getI18nInstance() {
|
||||
// 每次都重新读取当前语言
|
||||
const currentLang = getSavedLanguage()
|
||||
|
||||
console.log('=== getI18nInstance 被调用 ===')
|
||||
console.log('缓存中的语言:', currentLang)
|
||||
console.log('当前 i18n 实例存在?', !!i18nInstance)
|
||||
console.log('当前 i18n.global.locale:', i18nInstance?.global?.locale)
|
||||
|
||||
// 检查是否需要更新语言
|
||||
if (i18nInstance && i18nInstance.global.locale !== currentLang) {
|
||||
console.log('=== 检测到语言变化,强制更新 ===')
|
||||
console.log('旧语言:', i18nInstance.global.locale)
|
||||
console.log('新语言:', currentLang)
|
||||
|
||||
// 直接更新 locale(这应该会触发所有组件重新渲染)
|
||||
i18nInstance.global.locale = currentLang
|
||||
|
||||
console.log('i18n.global.locale 已更新为:', i18nInstance.global.locale)
|
||||
console.log('测试翻译 (common.loading):', i18nInstance.global.t('common.loading'))
|
||||
console.log('测试翻译 (home.title):', i18nInstance.global.t('home.title'))
|
||||
console.log('===================================')
|
||||
|
||||
return i18nInstance
|
||||
}
|
||||
|
||||
// 首次创建实例
|
||||
if (!i18nInstance) {
|
||||
console.log('=== 首次创建 i18n 实例 ===')
|
||||
|
||||
i18nInstance = createI18n({
|
||||
legacy: true, // 使用 Legacy API 模式,支持全局 $t
|
||||
locale: currentLang,
|
||||
fallbackLocale: 'zh-CN',
|
||||
messages: {
|
||||
'zh-CN': zhCN,
|
||||
'en-US': enUS
|
||||
},
|
||||
silentTranslationWarn: true,
|
||||
silentFallbackWarn: true
|
||||
})
|
||||
|
||||
console.log('i18n 实例已创建,语言:', currentLang)
|
||||
console.log('测试翻译 (common.loading):', i18nInstance.global.t('common.loading'))
|
||||
console.log('测试翻译 (home.title):', i18nInstance.global.t('home.title'))
|
||||
console.log('============================')
|
||||
}
|
||||
|
||||
return i18nInstance
|
||||
}
|
||||
|
||||
export function createApp() {
|
||||
console.log('========================================')
|
||||
console.log('=== createApp 被调用 ===')
|
||||
console.log('时间戳:', new Date().toLocaleTimeString())
|
||||
console.log('========================================')
|
||||
|
||||
const app = createSSRApp(App)
|
||||
|
||||
// 注册全局订单监控服务到VUE3
|
||||
// 使用 uView
|
||||
app.use(uView)
|
||||
|
||||
// 获取或更新 i18n 实例
|
||||
const i18n = getI18nInstance()
|
||||
|
||||
// 使用 i18n
|
||||
app.use(i18n)
|
||||
|
||||
// 手动注入 $i18n 到全局属性(确保组件可以访问)
|
||||
app.config.globalProperties.$i18n = i18n.global
|
||||
|
||||
// 注册全局订单监控服务
|
||||
app.config.globalProperties.$orderMonitor = orderMonitor
|
||||
|
||||
// 注册全局语言切换方法(注意:建议使用 reLaunch 来切换语言以确保完全刷新)
|
||||
app.config.globalProperties.$setLanguage = (lang) => {
|
||||
console.log('$setLanguage 被调用,语言:', lang)
|
||||
uni.setStorageSync('language', lang)
|
||||
// 更新 i18n 实例的语言
|
||||
if (i18n && i18n.global) {
|
||||
i18n.global.locale = lang
|
||||
console.log('i18n.global.locale 已更新为:', i18n.global.locale)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('=== Vue 3 应用创建完成 ===')
|
||||
console.log('最终 locale:', i18n.global.locale)
|
||||
console.log('app.config.globalProperties.$t 存在?', !!app.config.globalProperties.$t)
|
||||
console.log('app.config.globalProperties.$i18n 存在?', !!app.config.globalProperties.$i18n)
|
||||
console.log('测试 $t 调用:', i18n.global.t('common.loading'))
|
||||
console.log('===========================')
|
||||
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
Generated
-1764
File diff suppressed because it is too large
Load Diff
+14
-13
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@climblee/uv-ui": "^1.1.20",
|
||||
"axios": "^1.7.9",
|
||||
"axios-miniprogram-adapter": "0.3.4",
|
||||
"uniapp-axios-adapter": "^0.3.2",
|
||||
"uview-ui": "1.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.57.1",
|
||||
"sass-loader": "^13.2.0"
|
||||
}
|
||||
}
|
||||
{
|
||||
"dependencies": {
|
||||
"@climblee/uv-ui": "^1.1.20",
|
||||
"axios": "^1.7.9",
|
||||
"axios-miniprogram-adapter": "0.3.4",
|
||||
"uniapp-axios-adapter": "^0.3.2",
|
||||
"uview-ui": "1.8.8",
|
||||
"vue-i18n": "9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.57.1",
|
||||
"sass-loader": "^13.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
+46
-46
@@ -16,34 +16,34 @@
|
||||
"enableShareTimeline": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人中心",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
{
|
||||
"path": "pages/userProfile/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人信息",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"path": "pages/setting/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -67,19 +67,19 @@
|
||||
{
|
||||
"path": "pages/deposit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "押金管理"
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "租借记录"
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/payment",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单支付",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -87,7 +87,7 @@
|
||||
{
|
||||
"path": "pages/expressReturn/addExpressReturn",
|
||||
"style": {
|
||||
"navigationBarTitleText": "快递归还",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -95,19 +95,19 @@
|
||||
{
|
||||
"path": "pages/feedback/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "投诉与建议"
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/help/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "帮助中心"
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/device/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设备详情",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -116,13 +116,13 @@
|
||||
{
|
||||
"path": "pages/serve/bagCheck/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "共享风扇"
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/return/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单详情",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -130,7 +130,7 @@
|
||||
{
|
||||
"path": "pages/order/success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "支付成功",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -138,7 +138,7 @@
|
||||
{
|
||||
"path": "pages/order/return-success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "归还成功",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -146,7 +146,7 @@
|
||||
{
|
||||
"path": "pages/order/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单详情",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -154,14 +154,14 @@
|
||||
{
|
||||
"path": "pages/expressReturn/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "快递归还列表",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/expressReturn/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "归还详情",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -169,7 +169,7 @@
|
||||
{
|
||||
"path": "pages/search/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "查找设备",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -177,7 +177,7 @@
|
||||
{
|
||||
"path": "pages/position/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "附近设备详情",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -185,7 +185,7 @@
|
||||
{
|
||||
"path": "pages/join/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "合作加盟",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -193,7 +193,7 @@
|
||||
{
|
||||
"path": "pages/waiting/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设备弹出中",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -201,7 +201,7 @@
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "共享风扇",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
|
||||
+24
-20
@@ -2,27 +2,27 @@
|
||||
<view class="deposit-container">
|
||||
<!-- 押金金额卡片 -->
|
||||
<view class="deposit-card">
|
||||
<view class="title">押金余额</view>
|
||||
<view class="title">{{ $t('deposit.depositBalance') }}</view>
|
||||
<view class="amount">¥{{ depositAmount }}</view>
|
||||
<button class="withdraw-btn" @click="handleWithdraw" :disabled="depositAmount <= 0">提现</button>
|
||||
<button class="withdraw-btn" @click="handleWithdraw" :disabled="depositAmount <= 0">{{ $t('deposit.withdraw') }}</button>
|
||||
</view>
|
||||
|
||||
<!-- 提现说明 -->
|
||||
<view class="notice-card">
|
||||
<view class="notice-title">
|
||||
<view class="dot"></view>
|
||||
<text>提现说明</text>
|
||||
<text>{{ $t('deposit.withdrawNotice') }}</text>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<view class="notice-item">1. 提现金额将原路退回支付账户</view>
|
||||
<view class="notice-item">2. 提现申请提交后预计0-7个工作日到账</view>
|
||||
<view class="notice-item">3. 如超时未收到,请联系客服处理</view>
|
||||
<view class="notice-item">1. {{ $t('deposit.withdrawNotice1') }}</view>
|
||||
<view class="notice-item">2. {{ $t('deposit.withdrawNotice2') }}</view>
|
||||
<view class="notice-item">3. {{ $t('deposit.withdrawNotice3') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 押金记录 -->
|
||||
<view class="record-card" v-if="records.length > 0">
|
||||
<view class="record-title">押金记录</view>
|
||||
<view class="record-title">{{ $t('deposit.depositRecord') }}</view>
|
||||
<view class="record-list">
|
||||
<view class="record-item" v-for="(item, index) in records" :key="index">
|
||||
<view class="record-info">
|
||||
@@ -53,6 +53,10 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('deposit.title')
|
||||
})
|
||||
// this.loadUserInfo()
|
||||
},
|
||||
onShow() {
|
||||
@@ -84,7 +88,7 @@ export default {
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
uni.showToast({
|
||||
title: '获取用户信息失败',
|
||||
title: this.$t('user.getUserInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -92,7 +96,7 @@ export default {
|
||||
async handleWithdraw() {
|
||||
if (parseFloat(this.depositAmount) <= 0) {
|
||||
uni.showToast({
|
||||
title: '无可提现余额',
|
||||
title: this.$t('deposit.noBalance'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -111,12 +115,12 @@ export default {
|
||||
// }
|
||||
|
||||
uni.showModal({
|
||||
title: '确认提现',
|
||||
content: '押金将原路退回,预计0-7个工作日到账',
|
||||
title: this.$t('deposit.confirmWithdraw'),
|
||||
content: this.$t('deposit.withdrawDesc'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({
|
||||
title: '提现中...'
|
||||
title: this.$t('deposit.withdrawing')
|
||||
})
|
||||
|
||||
try {
|
||||
@@ -127,7 +131,7 @@ export default {
|
||||
if (result.code === 200) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '提现申请已提交',
|
||||
title: this.$t('deposit.withdrawSubmitted'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
@@ -144,26 +148,26 @@ export default {
|
||||
this.loadUserInfo()
|
||||
}, 1500)
|
||||
} else {
|
||||
throw new Error(result.msg || '提现失败')
|
||||
throw new Error(result.msg || this.$t('deposit.withdrawFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提现失败:', error)
|
||||
uni.hideLoading()
|
||||
|
||||
// 更详细的错误处理
|
||||
let errorMessage = '提现失败,请稍后再试';
|
||||
let errorMessage = this.$t('deposit.withdrawFailed');
|
||||
|
||||
// 如果有具体错误信息,使用它
|
||||
if (error.message) {
|
||||
// 常见错误消息处理
|
||||
if (error.message.includes('尚未归还')) {
|
||||
errorMessage = '当前订单尚未归还,请归还后再提现';
|
||||
errorMessage = this.$t('deposit.orderNotReturned');
|
||||
} else if (error.message.includes('已退还')) {
|
||||
errorMessage = '押金已退还,无需重复提现';
|
||||
errorMessage = this.$t('deposit.alreadyRefunded');
|
||||
} else if (error.message.includes('处理中')) {
|
||||
errorMessage = '押金退还处理中,请耐心等待';
|
||||
errorMessage = this.$t('deposit.refundProcessing');
|
||||
} else if (error.message.includes('余额为0')) {
|
||||
errorMessage = '账户余额为0,无法提现';
|
||||
errorMessage = this.$t('deposit.noBalance');
|
||||
} else {
|
||||
// 使用后端返回的具体错误消息
|
||||
errorMessage = error.message;
|
||||
@@ -172,7 +176,7 @@ export default {
|
||||
|
||||
// 显示错误提示
|
||||
uni.showModal({
|
||||
title: '提现失败',
|
||||
title: this.$t('deposit.withdrawFailed'),
|
||||
content: errorMessage,
|
||||
showCancel: false
|
||||
})
|
||||
|
||||
+55
-49
@@ -12,7 +12,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="device-id">
|
||||
<text class="id-label">设备号:</text>
|
||||
<text class="id-label">{{ $t('device.deviceNo') }}:</text>
|
||||
<text class="id-value">{{ deviceId }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -20,17 +20,17 @@
|
||||
<!-- 计费规则 -->
|
||||
<view class="card pricing-card">
|
||||
<view class="card-header">
|
||||
<text class="card-title">计费规则</text>
|
||||
<text class="card-title">{{ $t('device.pricingRules') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="pricing-banner">
|
||||
<view class="pricing-main">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price">{{ deviceFeeConfig.maxHourPrice || '5.00' }}</text>
|
||||
<text class="unit">/小时</text>
|
||||
<text class="unit">/{{ $t('time.hour') }}</text>
|
||||
</view>
|
||||
<view class="cap-badge">
|
||||
<text class="cap-text">{{ deviceInfo.depositAmount || '99' }}元封顶</text>
|
||||
<text class="cap-text">{{ deviceInfo.depositAmount || '99' }}{{ $t('device.capLimit') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -51,20 +51,20 @@
|
||||
<!-- 使用说明 -->
|
||||
<view class="card notice-card">
|
||||
<view class="card-header">
|
||||
<text class="card-title">使用说明</text>
|
||||
<text class="card-title">{{ $t('device.usageInstructions') }}</text>
|
||||
</view>
|
||||
<view class="notice-items">
|
||||
<view class="notice-item">
|
||||
<view class="notice-dot"></view>
|
||||
<text class="notice-text">请在使用前检查设备是否完好</text>
|
||||
<text class="notice-text">{{ $t('device.checkBeforeUse') }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="notice-dot"></view>
|
||||
<text class="notice-text">超出使用时间将自动按小时计费</text>
|
||||
<text class="notice-text">{{ $t('device.autoChargeOvertime') }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="notice-dot"></view>
|
||||
<text class="notice-text">请在指定区域内使用设备</text>
|
||||
<text class="notice-text">{{ $t('device.useInDesignatedArea') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -73,11 +73,11 @@
|
||||
<view class="footer">
|
||||
<button class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||||
@click="handleRent('wx-score-pay')">
|
||||
<text>{{ hasActiveOrder ? '归还设备' : '免押金租借' }}</text>
|
||||
<text>{{ hasActiveOrder ? $t('order.returnDevice') : $t('device.rentDepositFree') }}</text>
|
||||
</button>
|
||||
<view class="wechat-credit">
|
||||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="wx-icon"></image>
|
||||
<text class="credit-text">微信支付分 <text class="divider">|</text> 550分以上优享</text>
|
||||
<text class="credit-text">{{ $t('device.wxPayScoreDesc') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -86,17 +86,17 @@
|
||||
<view class="popup-mask" @click.stop></view>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">授权获取手机号</text>
|
||||
<text class="popup-title">{{ $t('auth.authTitle') }}</text>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<view class="auth-desc">
|
||||
<text>为了提供更好的服务,需要授权获取您的手机号</text>
|
||||
<text>{{ $t('auth.authDescShort') }}</text>
|
||||
</view>
|
||||
<button class="auth-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
||||
一键获取手机号
|
||||
{{ $t('auth.getPhoneNumber') }}
|
||||
</button>
|
||||
<view class="auth-cancel" @click="showPhoneAuthPopup = false">
|
||||
<text>暂不授权</text>
|
||||
<text>{{ $t('auth.notNow') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -133,6 +133,9 @@
|
||||
getUserInfo,
|
||||
getUserPhoneNumber
|
||||
} from '@/util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 响应式状态
|
||||
const deviceInfo = ref({})
|
||||
@@ -143,7 +146,7 @@
|
||||
const batteryLevel = ref(95)
|
||||
const hasActiveOrder = ref(false)
|
||||
const deviceStatus = reactive({
|
||||
text: '可使用',
|
||||
get text() { return $t('device.available') },
|
||||
class: 'available'
|
||||
})
|
||||
const isLoggedIn = ref(true)
|
||||
@@ -164,6 +167,9 @@
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('device.deviceInfo')
|
||||
})
|
||||
await checkUserPhone()
|
||||
await fetchDeviceInfo()
|
||||
})
|
||||
@@ -195,7 +201,7 @@
|
||||
// 用户拒绝授权的情况
|
||||
if (e.detail.errMsg && e.detail.errMsg.includes('deny')) {
|
||||
uni.showToast({
|
||||
title: '需要授权手机号才能使用设备',
|
||||
title: $t('auth.phoneRequired'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -204,7 +210,7 @@
|
||||
// 获取到授权code
|
||||
if (e.detail.code) {
|
||||
uni.showLoading({
|
||||
title: '获取中...'
|
||||
title: $t('auth.getting')
|
||||
})
|
||||
|
||||
console.log('获取到的授权code:', e.detail.code)
|
||||
@@ -236,15 +242,15 @@
|
||||
showPhoneAuthPopup.value = false
|
||||
|
||||
uni.showToast({
|
||||
title: '手机号获取成功',
|
||||
title: $t('auth.phoneSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
// 记录详细信息,不抛出错误
|
||||
console.warn('获取手机号响应异常:', res.msg || '未知错误')
|
||||
uni.showModal({
|
||||
title: '获取手机号异常',
|
||||
content: `状态码: ${res.code}, 消息: ${res.msg || '无'}`,
|
||||
title: $t('auth.phoneError'),
|
||||
content: `${$t('common.statusCode')}: ${res.code}, ${$t('common.message')}: ${res.msg || $t('common.none')}`,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
@@ -256,8 +262,8 @@
|
||||
// 显示更详细的错误信息
|
||||
let errMsg = err.message || err.toString()
|
||||
uni.showModal({
|
||||
title: '获取手机号失败',
|
||||
content: '错误信息: ' + errMsg,
|
||||
title: $t('auth.phoneGetFailed'),
|
||||
content: $t('common.errorInfo') + ': ' + errMsg,
|
||||
showCancel: false
|
||||
})
|
||||
})
|
||||
@@ -265,14 +271,14 @@
|
||||
uni.hideLoading()
|
||||
console.error('获取手机号外部错误:', outerError)
|
||||
uni.showModal({
|
||||
title: '意外错误',
|
||||
content: '处理过程发生异常: ' + (outerError.message || outerError),
|
||||
title: $t('common.unexpectedError'),
|
||||
content: $t('common.processException') + ': ' + (outerError.message || outerError),
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '获取授权码失败',
|
||||
title: $t('auth.authCodeFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -296,16 +302,16 @@
|
||||
deviceLocation.value = res.data.position.name
|
||||
}
|
||||
|
||||
// 更新设备状态
|
||||
if (deviceInfo.value.status) {
|
||||
if (deviceInfo.value.status === 'online') {
|
||||
deviceStatus.text = '可使用'
|
||||
deviceStatus.class = 'available'
|
||||
} else if (deviceInfo.value.status === 'offline') {
|
||||
deviceStatus.text = '离线'
|
||||
deviceStatus.class = 'offline'
|
||||
}
|
||||
// 更新设备状态
|
||||
if (deviceInfo.value.status) {
|
||||
if (deviceInfo.value.status === 'online') {
|
||||
deviceStatus.text = $t('device.available')
|
||||
deviceStatus.class = 'available'
|
||||
} else if (deviceInfo.value.status === 'offline') {
|
||||
deviceStatus.text = $t('device.offline')
|
||||
deviceStatus.class = 'offline'
|
||||
}
|
||||
}
|
||||
if (deviceInfo.value.feeConfig) {
|
||||
deviceFeeConfig.value = JSON.parse(deviceInfo.value.feeConfig)[0] || {}
|
||||
} else {
|
||||
@@ -321,9 +327,9 @@
|
||||
// 显示登录提示
|
||||
const showLoginTip = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录后再操作',
|
||||
confirmText: '去登录',
|
||||
title: $t('common.tips'),
|
||||
content: $t('common.loginRequired'),
|
||||
confirmText: $t('auth.goToLogin'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
@@ -358,7 +364,7 @@
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '订单状态查询失败',
|
||||
title: $t('order.getOrderStatusFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -444,6 +450,9 @@
|
||||
// 提交租借订单
|
||||
const submitRentOrder = async (payWay) => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: $t('common.processing')
|
||||
})
|
||||
// --- 第一步:先请求订阅消息(必须在用户点击的同步上下文中)---
|
||||
if (payWay === 'wx-score-pay') {
|
||||
console.log('准备请求订阅消息(在异步操作之前),时间:', new Date().toLocaleTimeString());
|
||||
@@ -471,14 +480,11 @@
|
||||
}
|
||||
// --- 订阅消息请求完成 ---
|
||||
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
})
|
||||
console.log(deviceId.value);
|
||||
// 调用设备租借接口
|
||||
const rentResult = await rentPowerBank(deviceId.value, phoneNumber.value)
|
||||
if (rentResult.code !== 200) {
|
||||
throw new Error(rentResult.msg || '设备租借失败')
|
||||
throw new Error(rentResult.msg || $t('device.rentFailed'))
|
||||
}
|
||||
|
||||
// 获取后端返回的订单信息
|
||||
@@ -556,14 +562,14 @@
|
||||
// 用户取消授权,需要取消订单
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '取消订单中'
|
||||
title: $t('order.cancelling')
|
||||
});
|
||||
const cancelRes = await cancelOrder({ orderId: order.orderNo });
|
||||
console.log('订单取消结果:', cancelRes);
|
||||
uni.hideLoading();
|
||||
|
||||
uni.showToast({
|
||||
title: '已取消订单',
|
||||
title: $t('order.orderCancelled'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
@@ -578,7 +584,7 @@
|
||||
console.error('取消订单失败:', cancelError);
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '取消订单失败,请联系客服',
|
||||
title: $t('order.cancelFailedContactService'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -589,7 +595,7 @@
|
||||
// 支付分调用异常,也需要取消订单
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '取消订单中'
|
||||
title: $t('order.cancelling')
|
||||
});
|
||||
const cancelRes = await cancelOrder({ orderId: order.orderNo });
|
||||
console.log('订单取消结果:', cancelRes);
|
||||
@@ -600,7 +606,7 @@
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '支付分调用失败,订单已取消',
|
||||
title: $t('device.payScoreFailedCancelled'),
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
@@ -612,7 +618,7 @@
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res?.msg || '获取支付参数失败',
|
||||
title: res?.msg || $t('device.getPayParamsFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -620,7 +626,7 @@
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: error.message || '租借失败,请重试',
|
||||
title: error.message || $t('device.rentFailedRetry'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,32 +3,32 @@
|
||||
<!-- 订单摘要卡片 -->
|
||||
<view class="order-summary-card" v-if="orderInfo.orderNo">
|
||||
<view class="summary-row">
|
||||
<view class="label">订单号</view>
|
||||
<view class="label">{{ $t('order.orderNo') }}</view>
|
||||
<view class="value">{{ orderInfo.orderNo }}</view>
|
||||
</view>
|
||||
<view class="summary-row" v-if="orderInfo.deviceNo">
|
||||
<view class="label">设备号</view>
|
||||
<view class="label">{{ $t('order.deviceNo') }}</view>
|
||||
<view class="value">{{ orderInfo.deviceNo }}</view>
|
||||
</view>
|
||||
<view class="summary-row" v-if="orderInfo.startTime">
|
||||
<view class="label">开放时间</view>
|
||||
<view class="label">{{ $t('express.openTime') }}</view>
|
||||
<view class="value">{{ orderInfo.startTime }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section">
|
||||
<view class="form-title">填写快递归还信息</view>
|
||||
<view class="form-title">{{ $t('express.fillExpressInfo') }}</view>
|
||||
|
||||
<view class="input-wrapper">
|
||||
<view class="input-label">联系电话</view>
|
||||
<view class="input-label">{{ $t('express.contactPhone') }}</view>
|
||||
<input class="input-field" type="number" v-model="phone" maxlength="20" />
|
||||
</view>
|
||||
|
||||
<view class="input-wrapper">
|
||||
<view class="input-label">快递单号</view>
|
||||
<view class="input-label">{{ $t('express.expressNo') }}</view>
|
||||
<input class="input-field" type="text" v-model="trackingNumber"
|
||||
:placeholder="isFillMode ? '请输入需要补填的快递单号' : '请输入快递单号(可先留空)'" maxlength="40" />
|
||||
:placeholder="isFillMode ? $t('express.fillTrackingPlaceholder') : $t('express.trackingPlaceholder')" maxlength="40" />
|
||||
</view>
|
||||
|
||||
<view class="tips" v-if="tipsText">{{ tipsText }}</view>
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-btn" :class="{ disabled: submitting }" @click="!submitting && handleSubmit()">
|
||||
{{ isFillMode ? '确认补填' : '提交信息' }}
|
||||
{{ isFillMode ? $t('express.confirmFill') : $t('express.submitInfo') }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -44,7 +44,9 @@
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
reactive
|
||||
reactive,
|
||||
getCurrentInstance,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad
|
||||
@@ -58,6 +60,15 @@
|
||||
getExpressReturnDetail,
|
||||
fillExpressTrackingNumber
|
||||
} from '@/config/api/expressReturn.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('express.fillExpress')
|
||||
})
|
||||
})
|
||||
|
||||
const orderId = ref('')
|
||||
const recordId = ref('')
|
||||
@@ -85,7 +96,7 @@
|
||||
|
||||
if (!orderId.value) {
|
||||
uni.showToast({
|
||||
title: '缺少订单号',
|
||||
title: $t('express.orderNoMissing'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -100,7 +111,7 @@
|
||||
const loadOrder = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
title: $t('common.loading')
|
||||
})
|
||||
const res = await queryById(orderId.value)
|
||||
if (res?.code === 200 && res.data) {
|
||||
@@ -110,11 +121,11 @@
|
||||
// 默认联系电话可回填订单上的手机号(若有)
|
||||
if (res.data.phone && !phone.value) phone.value = res.data.phone
|
||||
} else {
|
||||
throw new Error(res?.msg || '获取订单失败')
|
||||
throw new Error(res?.msg || $t('order.getOrderFailed'))
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({
|
||||
title: e.message || '加载失败',
|
||||
title: e.message || $t('express.loadFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -125,7 +136,7 @@
|
||||
const loadRecordAndOrderByRecord = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
title: $t('common.loading')
|
||||
})
|
||||
const res = await getExpressReturnDetail(recordId.value)
|
||||
if (res?.code === 200 && res.data) {
|
||||
@@ -135,11 +146,11 @@
|
||||
}
|
||||
if (res.data.userPhone && !phone.value) phone.value = res.data.userPhone
|
||||
} else {
|
||||
throw new Error(res?.msg || '获取记录失败')
|
||||
throw new Error(res?.msg || $t('express.getRecordFailed'))
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({
|
||||
title: e.message || '加载失败',
|
||||
title: e.message || $t('express.loadFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -155,10 +166,10 @@
|
||||
if (rec.status === 0) {
|
||||
recordId.value = rec.id
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '已存在快递归还申请,是否前往补填快递单号?',
|
||||
confirmText: '去补填',
|
||||
cancelText: '取消',
|
||||
title: $t('common.tips'),
|
||||
content: $t('express.existingReturnNotice'),
|
||||
confirmText: $t('express.goToFill'),
|
||||
cancelText: $t('common.cancel'),
|
||||
success: (r) => {
|
||||
if (r.confirm) {
|
||||
uni.redirectTo({
|
||||
@@ -170,7 +181,7 @@
|
||||
return
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '已有归还记录',
|
||||
title: $t('express.alreadyHasRecord'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -190,14 +201,14 @@
|
||||
const digits = (phone.value || '').replace(/\D/g, '')
|
||||
if (!digits || digits.length < 5) {
|
||||
uni.showToast({
|
||||
title: '请填写有效联系电话',
|
||||
title: $t('express.pleaseEnterValidPhone'),
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (isFillMode.value && !trackingNumber.value) {
|
||||
uni.showToast({
|
||||
title: '请填写快递单号',
|
||||
title: $t('express.pleaseEnterTrackingNo'),
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
|
||||
@@ -16,23 +16,23 @@
|
||||
<!-- 快递信息卡片 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">
|
||||
<text class="title-text">快递信息</text>
|
||||
<text class="title-text">{{ $t('express.expressInfo') }}</text>
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">快递公司</text>
|
||||
<text class="label">{{ $t('express.expressCompany') }}</text>
|
||||
<text class="value">{{ detailData.expressCompany }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">运单号</text>
|
||||
<text class="label">{{ $t('express.trackingNo') }}</text>
|
||||
<text class="value tracking-number">{{ detailData.trackingNumber }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">包裹类型</text>
|
||||
<text class="label">{{ $t('express.packageType') }}</text>
|
||||
<text class="value">{{ detailData.packageType }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">包裹重量</text>
|
||||
<text class="label">{{ $t('express.packageWeight') }}</text>
|
||||
<text class="value">{{ detailData.weight }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -41,23 +41,23 @@
|
||||
<!-- 归还信息卡片 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">
|
||||
<text class="title-text">归还信息</text>
|
||||
<text class="title-text">{{ $t('express.returnInfo') }}</text>
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">归还地址</text>
|
||||
<text class="label">{{ $t('express.returnAddress') }}</text>
|
||||
<text class="value address">{{ detailData.returnAddress }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">归还时间</text>
|
||||
<text class="label">{{ $t('express.returnTime') }}</text>
|
||||
<text class="value">{{ detailData.returnTime }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">处理时间</text>
|
||||
<text class="label">{{ $t('express.processTime') }}</text>
|
||||
<text class="value">{{ detailData.processTime || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">完成时间</text>
|
||||
<text class="label">{{ $t('express.completeTime') }}</text>
|
||||
<text class="value">{{ detailData.completeTime || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -66,7 +66,7 @@
|
||||
<!-- 备注信息卡片 -->
|
||||
<view class="info-card" v-if="detailData.remark">
|
||||
<view class="card-title">
|
||||
<text class="title-text">备注信息</text>
|
||||
<text class="title-text">{{ $t('express.remarkInfo') }}</text>
|
||||
</view>
|
||||
<view class="remark-content">
|
||||
<text class="remark-text">{{ detailData.remark }}</text>
|
||||
@@ -76,10 +76,10 @@
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-buttons">
|
||||
<button class="action-btn primary" @click="handleCopyTracking">
|
||||
<text class="btn-text">复制运单号</text>
|
||||
<text class="btn-text">{{ $t('express.copyTrackingNo') }}</text>
|
||||
</button>
|
||||
<button class="action-btn secondary" @click="handleContactService">
|
||||
<text class="btn-text">联系客服</text>
|
||||
<text class="btn-text">{{ $t('user.customerService') }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -89,6 +89,9 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getExpressReturnDetail } from '@/config/api/expressReturn.js'
|
||||
import { getCustomerPhone } from '@/util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 详情数据
|
||||
const detailData = ref({
|
||||
@@ -128,21 +131,21 @@ const getStatusIcon = (status) => {
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const textMap = {
|
||||
'completed': '归还完成',
|
||||
'processing': '处理中',
|
||||
'pending': '待处理'
|
||||
'completed': $t('express.returnCompleted'),
|
||||
'processing': $t('express.processing'),
|
||||
'pending': $t('express.pending')
|
||||
}
|
||||
return textMap[status] || '待处理'
|
||||
return textMap[status] || $t('express.pending')
|
||||
}
|
||||
|
||||
// 获取状态描述
|
||||
const getStatusDesc = (status) => {
|
||||
const descMap = {
|
||||
'completed': '您的快递已成功归还',
|
||||
'processing': '正在处理您的归还请求',
|
||||
'pending': '等待处理归还申请'
|
||||
'completed': $t('express.returnCompletedDesc'),
|
||||
'processing': $t('express.processingDesc'),
|
||||
'pending': $t('express.pendingDesc')
|
||||
}
|
||||
return descMap[status] || '等待处理归还申请'
|
||||
return descMap[status] || $t('express.pendingDesc')
|
||||
}
|
||||
|
||||
// 复制运单号
|
||||
@@ -151,7 +154,7 @@ const handleCopyTracking = () => {
|
||||
data: detailData.value.trackingNumber,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '运单号已复制',
|
||||
title: $t('express.trackingNoCopied'),
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -162,10 +165,10 @@ const handleCopyTracking = () => {
|
||||
const handleContactService = () => {
|
||||
const customerPhone = getCustomerPhone()
|
||||
uni.showModal({
|
||||
title: '联系客服',
|
||||
content: `客服电话:${customerPhone}\n工作时间:周一至周日 09:00-22:00`,
|
||||
confirmText: '拨打',
|
||||
cancelText: '取消',
|
||||
title: $t('user.customerService'),
|
||||
content: `${$t('help.phone')}:${customerPhone}\n${$t('help.workingHours')}:${$t('express.workingHours')}`,
|
||||
confirmText: $t('express.call'),
|
||||
cancelText: $t('common.cancel'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.makePhoneCall({
|
||||
@@ -178,12 +181,16 @@ const handleContactService = () => {
|
||||
|
||||
// 页面加载时获取详情数据
|
||||
onMounted(async () => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('express.returnDetail')
|
||||
})
|
||||
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
const options = currentPage.options || {}
|
||||
if (!options.id) return
|
||||
try {
|
||||
uni.showLoading({ title: '加载中' })
|
||||
uni.showLoading({ title: $t('common.loading') })
|
||||
const res = await getExpressReturnDetail(options.id)
|
||||
if (res && res.code === 200 && res.data) {
|
||||
const r = res.data
|
||||
@@ -201,10 +208,10 @@ onMounted(async () => {
|
||||
remark: r.remark || ''
|
||||
}
|
||||
} else {
|
||||
throw new Error(res?.msg || '获取详情失败')
|
||||
throw new Error(res?.msg || $t('express.getDetailFailed'))
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
|
||||
uni.showToast({ title: e.message || $t('express.loadFailed'), icon: 'none' })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<view class="express-return-container">
|
||||
<!-- 收件信息卡片 -->
|
||||
<view class="recipient-info-card">
|
||||
<view class="info-header">收件信息</view>
|
||||
<view class="info-header">{{ $t('express.recipientInfo') }}</view>
|
||||
<view class="info-content">
|
||||
<text class="recipient-name">风电者 18163601305</text>
|
||||
<text class="recipient-address">湖南省长沙市岳麓区麓谷街道新长海尖科技园A2栋623</text>
|
||||
<text class="recipient-name">{{ $t('express.recipientName') }}</text>
|
||||
<text class="recipient-address">{{ $t('express.recipientAddress') }}</text>
|
||||
</view>
|
||||
<view class="copy-all-btn" @click="copyAllInfo">
|
||||
<text class="btn-text">一键复制全部信息</text>
|
||||
<text class="btn-text">{{ $t('express.copyAllInfo') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
<text class="status-label">{{ getStatusText(item.status) }}</text>
|
||||
</view>
|
||||
<view class="content-body">
|
||||
<text class="info-text">订单号:{{ item.orderId || '' }}</text>
|
||||
<text class="info-text">快递单号:{{ item.trackingNumber || '待填写' }}</text>
|
||||
<text class="info-text">用户电话:{{ item.userPhone || '' }}</text>
|
||||
<text class="info-text">{{ $t('order.orderNo') }}:{{ item.orderId || '' }}</text>
|
||||
<text class="info-text">{{ $t('express.expressNo') }}:{{ item.trackingNumber || $t('express.toFill') }}</text>
|
||||
<text class="info-text">{{ $t('express.userPhone') }}:{{ item.userPhone || '' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="returnList.length === 0">
|
||||
<view class="empty-icon">📦</view>
|
||||
<text class="empty-text">暂无归还记录</text>
|
||||
<text class="empty-text">{{ $t('express.noReturnRecord') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -52,11 +52,21 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getExpressReturnList } from '@/config/api/expressReturn.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
const returnList = ref([])
|
||||
const loading = ref(false)
|
||||
const query = ref({ pageNum: 1, pageSize: 20 })
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('express.returnRecord')
|
||||
})
|
||||
loadList()
|
||||
})
|
||||
|
||||
// 收件信息
|
||||
const recipientName = '风电者 18163601305'
|
||||
const recipientAddress = '湖南省长沙市岳麓区麓谷街道新长海尖科技园A2栋623'
|
||||
@@ -83,10 +93,10 @@ const loadList = async () => {
|
||||
remark: r.remark
|
||||
}))
|
||||
} else {
|
||||
throw new Error(res?.msg || '获取列表失败')
|
||||
throw new Error(res?.msg || $t('express.getListFailed'))
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
|
||||
uni.showToast({ title: e.message || $t('express.loadFailed'), icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -108,27 +118,27 @@ const getStatusClass = (status) => ({
|
||||
}[status] || 'status-pending')
|
||||
|
||||
const getStatusText = (status) => ({
|
||||
'completed': '暂停计费中',
|
||||
'processing': '暂停计费中',
|
||||
'pending': '暂停计费中'
|
||||
}[status] || '暂停计费中')
|
||||
'completed': $t('express.billingPaused'),
|
||||
'processing': $t('express.billingPaused'),
|
||||
'pending': $t('express.billingPaused')
|
||||
}[status] || $t('express.billingPaused'))
|
||||
|
||||
const getStatusBadge = (status) => ({
|
||||
'completed': '已完成',
|
||||
'processing': '处理中',
|
||||
'pending': '待处理'
|
||||
}[status] || '待处理')
|
||||
'completed': $t('express.completed'),
|
||||
'processing': $t('express.processing'),
|
||||
'pending': $t('express.pending')
|
||||
}[status] || $t('express.pending'))
|
||||
|
||||
// 一键复制全部信息
|
||||
const copyAllInfo = () => {
|
||||
const allInfo = `收件人:${recipientName}\n收件地址:${recipientAddress}`
|
||||
const allInfo = `${$t('express.recipient')}:${recipientName}\n${$t('express.recipientAddressLabel')}:${recipientAddress}`
|
||||
uni.setClipboardData({
|
||||
data: allInfo,
|
||||
success: () => {
|
||||
uni.showToast({ title: '全部信息已复制', icon: 'success' })
|
||||
uni.showToast({ title: $t('express.copySuccess'), icon: 'success' })
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '复制失败', icon: 'none' })
|
||||
uni.showToast({ title: $t('express.copyFailed'), icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -144,7 +154,6 @@ const handleItemClick = (item) => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadList)
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
+51
-41
@@ -1,58 +1,59 @@
|
||||
<template>
|
||||
<view class="feedback-container">
|
||||
<!-- <form> -->
|
||||
<!-- 问题类型选择 -->
|
||||
<view class="type-section">
|
||||
<view class="section-title">问题类型</view>
|
||||
<view class="type-grid">
|
||||
<view v-for="(type, index) in types" :key="index" class="type-item"
|
||||
:class="{ active: selectedType === index }" @click="selectType(index)">
|
||||
{{ type }}
|
||||
</view>
|
||||
<!-- 问题类型选择 -->
|
||||
<view class="type-section">
|
||||
<view class="section-title">{{ $t('feedback.issueType') }}</view>
|
||||
<view class="type-grid">
|
||||
<view v-for="(type, index) in types" :key="index" class="type-item"
|
||||
:class="{ active: selectedType === index }" @click="selectType(index)">
|
||||
{{ type }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 问题描述 -->
|
||||
<view class="description-section">
|
||||
<view class="section-title">问题描述</view>
|
||||
<textarea class="description-input" v-model="description" placeholder="请详细描述您遇到的问题,以便我们更好地为您解决"
|
||||
maxlength="500" name="description" />
|
||||
<view class="word-count">{{ description.length }}/500</view>
|
||||
</view>
|
||||
<!-- 问题描述 -->
|
||||
<view class="description-section">
|
||||
<view class="section-title">{{ $t('feedback.issueDescription') }}</view>
|
||||
<textarea class="description-input" v-model="description" :placeholder="$t('feedback.placeholder')"
|
||||
maxlength="500" name="description" />
|
||||
<view class="word-count">{{ description.length }}/500</view>
|
||||
</view>
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<view class="upload-section">
|
||||
<view class="section-title">图片上传(选填)</view>
|
||||
<!-- 图片上传 -->
|
||||
<view class="upload-section">
|
||||
<view class="section-title">{{ $t('feedback.imageUpload') }}</view>
|
||||
<view class="upload-grid">
|
||||
<view class="upload-item" v-for="(img, index) in images" :key="index">
|
||||
<image :src="img" mode="aspectFill" />
|
||||
<view class="delete-btn" @click="deleteImage(index)">×</view>
|
||||
</view>
|
||||
<view class="upload-btn" @click="chooseImage" v-if="images.length < 3">
|
||||
<text class="plus">+</text>
|
||||
<text class="tip">上传图片</text>
|
||||
</view>
|
||||
<view class="upload-btn" @click="chooseImage" v-if="images.length < 3">
|
||||
<text class="plus">+</text>
|
||||
<text class="tip">{{ $t('feedback.uploadImage') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系方式 -->
|
||||
<view class="contact-section">
|
||||
<view class="section-title">联系方式</view>
|
||||
<input class="contact-input" v-model="contact" placeholder="请留下您的手机号,方便我们联系您" type="number"
|
||||
maxlength="11" name="contact" />
|
||||
</view>
|
||||
<!-- 联系方式 -->
|
||||
<view class="contact-section">
|
||||
<view class="section-title">{{ $t('feedback.contactInfo') }}</view>
|
||||
<input class="contact-input" v-model="contact" :placeholder="$t('feedback.contactPlaceholder')" type="number"
|
||||
maxlength="11" name="contact" />
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-section">
|
||||
<view class="submit-btn" @click="submitFeedback">提交反馈</view>
|
||||
</view>
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-section">
|
||||
<view class="submit-btn" @click="submitFeedback">{{ $t('feedback.submit') }}</view>
|
||||
</view>
|
||||
<!-- </form> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
ref,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import {
|
||||
URL,
|
||||
@@ -64,9 +65,18 @@
|
||||
import {
|
||||
addUserFeedback
|
||||
} from '../../config/api/feedback'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('feedback.title')
|
||||
})
|
||||
})
|
||||
|
||||
// 响应式数据
|
||||
const types = ref(['设备故障', '收费问题', '使用建议', '其他'])
|
||||
const types = ref([$t('feedback.deviceFault'), $t('feedback.chargingIssue'), $t('feedback.usageSuggestion'), $t('feedback.other')])
|
||||
const selectedType = ref(-1)
|
||||
const paramsType = ref('')
|
||||
const description = ref('')
|
||||
@@ -113,7 +123,7 @@
|
||||
const submitFeedback = async () => {
|
||||
if (selectedType.value === -1) {
|
||||
uni.showToast({
|
||||
title: '请选择问题类型',
|
||||
title: $t('feedback.pleaseSelectType'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -121,7 +131,7 @@
|
||||
|
||||
if (!description.value.trim()) {
|
||||
uni.showToast({
|
||||
title: '请描述您的问题',
|
||||
title: $t('feedback.pleaseDescribe'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -129,13 +139,13 @@
|
||||
|
||||
if (!contact.value) {
|
||||
uni.showToast({
|
||||
title: '请留下联系方式',
|
||||
title: $t('feedback.pleaseContact'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (types.value[selectedType.value] == '设备故障' || types.value[selectedType.value] == '收费问题') {
|
||||
if (types.value[selectedType.value] == $t('feedback.deviceFault') || types.value[selectedType.value] == $t('feedback.chargingIssue')) {
|
||||
paramsType.value = 'complain'
|
||||
} else {
|
||||
paramsType.value = 'suggestion'
|
||||
@@ -164,7 +174,7 @@
|
||||
// 兼容后端返回 { code: 200 } 或 HTTP 200 情况
|
||||
if ((res.statusCode === 200) && ((res.data && res.data.code === 200) || res.data === true || res.data?.success === true)) {
|
||||
uni.showToast({
|
||||
title: '反馈成功',
|
||||
title: $t('feedback.submitSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -173,14 +183,14 @@
|
||||
return
|
||||
}
|
||||
uni.showToast({
|
||||
title: (res.data && (res.data.msg || res.data.message)) || '反馈失败',
|
||||
title: (res.data && (res.data.msg || res.data.message)) || $t('feedback.submitFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('feedback request failed:', err)
|
||||
uni.showToast({
|
||||
title: '网络错误,请稍后重试',
|
||||
title: $t('error.networkError'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
<!-- 联系客服 -->
|
||||
<view class="contact-card">
|
||||
<view class="contact-title">{{ HELP_CONTENT.CONTACT.TITLE }}</view>
|
||||
<view class="contact-title">{{ $t('help.contactUs') }}</view>
|
||||
<view class="contact-content">
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ HELP_CONTENT.CONTACT.PHONE.LABEL }}</text>
|
||||
<text class="label">{{ $t('help.phone') }}</text>
|
||||
<text class="value" @click="makePhoneCall">{{ customerPhone }}</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.LABEL }}</text>
|
||||
<text class="label">{{ $t('help.workingHours') }}</text>
|
||||
<text class="value">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.VALUE }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -51,6 +51,10 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('help.title')
|
||||
})
|
||||
// 从缓存读取客服电话
|
||||
this.customerPhone = getCustomerPhone()
|
||||
},
|
||||
|
||||
+60
-34
@@ -1,19 +1,23 @@
|
||||
<template>
|
||||
<view class="container fullscreen">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="navbar-content" :style="{ height: navBarHeight + 'px' }">
|
||||
<text class="navbar-title">风电者共享风扇&暖手充电宝</text>
|
||||
</view>
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="navbar-content" :style="{ height: navBarHeight + 'px' }">
|
||||
<text class="navbar-title">{{ $t('home.title') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="map-notice" v-if="noticeText" @click="openNoticePopup">
|
||||
</view>
|
||||
|
||||
<!-- 顶部信息区域(通知、招商等) -->
|
||||
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'px' }">
|
||||
<!-- 通知栏 -->
|
||||
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
|
||||
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
|
||||
icon="volume"></uv-notice-bar>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view class="main-content" :style="{ paddingTop: (statusBarHeight) + 'px' }">
|
||||
<!-- 内容区域 -->
|
||||
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
|
||||
<!-- 全屏地图组件 -->
|
||||
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
||||
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
||||
@@ -25,7 +29,7 @@
|
||||
<view v-if="isLoading || !userLocation" class="map-loading-placeholder">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner"></view>
|
||||
<text>正在获取位置信息...</text>
|
||||
<text>{{ $t('common.loadingLocation') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -36,28 +40,28 @@
|
||||
<view class="icon-wrap">
|
||||
<image class="action-icon" src="/static/map.png" mode="aspectFit" />
|
||||
</view>
|
||||
<text class="action-label">附近设备</text>
|
||||
<text class="action-label">{{ $t('home.nearbyDevices') }}</text>
|
||||
</view> -->
|
||||
|
||||
<view class="action-btn secondary small btn-nearby" @click="openPopup">
|
||||
<view class="icon-wrap">
|
||||
<image src="/static/use_help.png" class="action-icon" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="action-label">使用指南</text>
|
||||
<text class="action-label">{{ $t('home.useGuide') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="action-btn primary btn-scan" @click="handleScan">
|
||||
<view class="icon-wrap">
|
||||
<image class="action-icon" src="/static/scan-icon.png" mode="aspectFill" />
|
||||
</view>
|
||||
<text class="primary-label">扫码使用</text>
|
||||
<text class="primary-label">{{ $t('home.scanToUse') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="action-btn secondary small btn-my" @click="goMy">
|
||||
<view class="icon-wrap">
|
||||
<image class="action-icon" src="/static/user.png" mode="aspectFit" />
|
||||
</view>
|
||||
<text class="action-label">个人中心</text>
|
||||
<text class="action-label">{{ $t('home.personalCenter') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -67,7 +71,7 @@
|
||||
:expanded="isExpanded"
|
||||
:positions="filteredPositions"
|
||||
:isLoading="isLoading"
|
||||
title="附近设备场地"
|
||||
:title="$t('home.nearbyDeviceLocation')"
|
||||
@close="hideLocationList"
|
||||
@select="selectPositionFromPopup"
|
||||
@navigate="navigateToPosition"
|
||||
@@ -77,7 +81,7 @@
|
||||
<view class="loading-overlay" v-if="isLoading">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner"></view>
|
||||
<text>正在获取场地信息...</text>
|
||||
<text>{{ $t('common.loadingPosition') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -86,17 +90,17 @@
|
||||
<view class="popup-mask" @click.stop="showPhoneAuthPopup = false"></view>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">授权获取手机号</text>
|
||||
<text class="popup-title">{{ $t('auth.authTitle') }}</text>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<view class="auth-desc">
|
||||
<text>为了提供更好的服务和紧急联系,需要授权获取您的手机号</text>
|
||||
<text>{{ $t('auth.authDesc') }}</text>
|
||||
</view>
|
||||
<button class="auth-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
||||
<text>一键获取手机号</text>
|
||||
<text>{{ $t('auth.getPhoneNumber') }}</text>
|
||||
</button>
|
||||
<view class="auth-cancel" @click="showPhoneAuthPopup = false">
|
||||
<text>暂不授权</text>
|
||||
<text>{{ $t('auth.notNow') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -106,7 +110,7 @@
|
||||
<uv-popup ref="guidePopup" mode="center" round="24" :overlay="true" :closeOnClickOverlay="false" :safeAreaInsetBottom="false">
|
||||
<view class="guide-popup">
|
||||
<view class="guide-header">
|
||||
<text class="guide-title">使用指南</text>
|
||||
<text class="guide-title">{{ $t('guide.title') }}</text>
|
||||
<!-- <view class="guide-close" @click="closeGuidePopup">
|
||||
<uv-icon name="close" size="20"></uv-icon>
|
||||
</view> -->
|
||||
@@ -115,8 +119,8 @@
|
||||
<view class="guide-step" v-for="(step, idx) in guideSteps" :key="idx">
|
||||
<view class="step-index">{{ idx + 1 }}</view>
|
||||
<view class="step-info">
|
||||
<view class="step-title">{{ step.title }}</view>
|
||||
<view class="step-desc">{{ step.desc }}</view>
|
||||
<view class="step-title">{{ $t('guide.step' + (idx + 1) + 'Title') }}</view>
|
||||
<view class="step-desc">{{ $t('guide.step' + (idx + 1) + 'Desc') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -133,7 +137,7 @@
|
||||
<uv-popup ref="noticePopup" mode="center" round="24" :overlay="true" :closeOnClickOverlay="true" :safeAreaInsetBottom="false">
|
||||
<view class="notice-popup">
|
||||
<view class="notice-header">
|
||||
<text class="notice-title">通知公告</text>
|
||||
<text class="notice-title">{{ $t('home.noticeTitle') }}</text>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<text class="notice-text">{{ noticeText }}</text>
|
||||
@@ -182,6 +186,8 @@
|
||||
// 注意:从 pages/index/ 目录访问 components/ 需要使用 ../../components/ 路径
|
||||
import MapComponent from '../../components/MapComponent.vue'
|
||||
import LocationListSheet from '../../components/LocationListSheet.vue'
|
||||
import { useI18n } from '../../utils/i18n.js'
|
||||
|
||||
// 开启右上角分享菜单(仅 mp-weixin 有效)
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.showShareMenu({
|
||||
@@ -190,6 +196,8 @@
|
||||
})
|
||||
// #endif
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 响应式数据
|
||||
const searchKeyword = ref('')
|
||||
const userLocation = ref(null)
|
||||
@@ -205,6 +213,7 @@
|
||||
// 导航栏高度相关
|
||||
const statusBarHeight = ref(0)
|
||||
const navBarHeight = ref(44) // 默认导航栏内容高度
|
||||
const noticeHeight = ref(0) // 通知栏高度
|
||||
|
||||
// 使用指南步骤
|
||||
const guideSteps = ref([
|
||||
@@ -240,6 +249,11 @@
|
||||
const res = await getNoticeTextData(parasm);
|
||||
noticeText.value = res.data.noticeContent;
|
||||
|
||||
// 设置通知栏高度
|
||||
if (res.data.noticeContent) {
|
||||
noticeHeight.value = 50 // 通知栏高度约50px
|
||||
}
|
||||
|
||||
// 将通知内容存储到本地缓存
|
||||
try {
|
||||
uni.setStorageSync('noticeContent', res.data.noticeContent);
|
||||
@@ -400,7 +414,7 @@ const noticePopup = ref(null)
|
||||
} catch (error) {
|
||||
console.error('获取位置失败:', error)
|
||||
uni.showToast({
|
||||
title: '获取位置失败,显示默认地图',
|
||||
title: $t('home.getLocationFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -578,7 +592,7 @@ const noticePopup = ref(null)
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: '定位成功',
|
||||
title: $t('home.locateSuccess'),
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
@@ -587,7 +601,7 @@ const noticePopup = ref(null)
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: e.errMsg || '定位失败,请检查定位权限',
|
||||
title: e.errMsg || $t('home.locateFailed'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
@@ -691,7 +705,7 @@ const noticePopup = ref(null)
|
||||
|
||||
if (!deviceNo) {
|
||||
uni.showToast({
|
||||
title: '无效的设备二维码',
|
||||
title: $t('home.invalidQRCode'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -830,16 +844,18 @@ const closeNoticePopup = () => {
|
||||
export default {
|
||||
// 分享给朋友
|
||||
onShareAppMessage() {
|
||||
const $t = this.$t || ((key) => key)
|
||||
return {
|
||||
title: '风电者 - 共享风扇暖手充电宝',
|
||||
title: $t('share.title'),
|
||||
path: '/pages/index/index',
|
||||
// imageUrl: '/static/logo.png'
|
||||
}
|
||||
},
|
||||
// 朋友圈
|
||||
onShareTimeline() {
|
||||
const $t = this.$t || ((key) => key)
|
||||
return {
|
||||
title: '风电者 - 共享风扇暖手充电宝',
|
||||
title: $t('share.title'),
|
||||
query: '',
|
||||
// imageUrl: '/static/logo.png'
|
||||
}
|
||||
@@ -889,6 +905,8 @@ const closeNoticePopup = () => {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 180rpx; /* 为底部按钮留出空间 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 顶部Logo和通知栏 */
|
||||
@@ -1376,7 +1394,7 @@ const closeNoticePopup = () => {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
bottom: 180rpx; /* 为底部按钮留出空间 */
|
||||
background: #f6f7fb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1502,11 +1520,19 @@ const closeNoticePopup = () => {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.map-notice {
|
||||
/* 顶部信息区域 */
|
||||
.top-info-section {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.notice-wrapper {
|
||||
margin: 0 20rpx;
|
||||
margin-top: 10rpx;
|
||||
padding: 10rpx 0;
|
||||
border-radius: 20rpx;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
/* 使用指南弹窗样式 */
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
ref,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 外部网页地址
|
||||
const webUrl = ref('https://joininvestment.gxfs123.com/')
|
||||
@@ -24,13 +27,16 @@
|
||||
const handleError = (e) => {
|
||||
console.error('web-view 加载错误:', e)
|
||||
uni.showToast({
|
||||
title: '页面加载失败',
|
||||
title: $t('join.pageLoadFailed'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('join.title')
|
||||
})
|
||||
console.log('招商页面加载,外部网址:', webUrl.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<view class="legal-page">
|
||||
<view class="header">
|
||||
<view class="title">用户协议</view>
|
||||
<view class="subtitle">适用于“风电者”共享风扇租借服务(最后更新:{{ effectiveDate }})</view>
|
||||
<view class="title">{{ $t('legal.agreement') }}</view>
|
||||
<view class="subtitle">{{ $t('legal.applicableToService') }}({{ $t('legal.lastUpdate') }}:{{ effectiveDate }})</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="content" scroll-y>
|
||||
@@ -71,12 +71,21 @@
|
||||
<view class="p">15.2 协议条款如被认定无效或不可执行,不影响其他条款的效力与执行。</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer">如对本协议有疑问,请前往“我的-客服”咨询</view>
|
||||
<view class="footer">{{ $t('legal.footerNotice') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('legal.agreement')
|
||||
})
|
||||
})
|
||||
|
||||
const brandName = '风电者'
|
||||
const companyName = '深圳乐慕智云科技有限公司'
|
||||
|
||||
+14
-4
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<view class="legal-page">
|
||||
<view class="header">
|
||||
<view class="title">隐私政策</view>
|
||||
<view class="subtitle">适用于“风电者”共享风扇租借服务(最后更新:{{ effectiveDate }})</view>
|
||||
<view class="title">{{ $t('legal.privacy') }}</view>
|
||||
<view class="subtitle">{{ $t('legal.applicableToService') }}({{ $t('legal.lastUpdate') }}:{{ effectiveDate }})</view>
|
||||
</view>
|
||||
|
||||
<view class="card notice">
|
||||
@@ -56,14 +56,24 @@
|
||||
<view class="p">10.1 您可通过“我的-客服”与我们联系以行使前述权利或就本政策提出疑问。</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer">如对本政策有疑问,请前往“我的-客服”咨询</view>
|
||||
<view class="footer">{{ $t('legal.footerNoticePolicy') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
ref,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('legal.privacy')
|
||||
})
|
||||
})
|
||||
|
||||
const brandName = '风电者'
|
||||
const companyName = '深圳乐慕智云科技有限公司'
|
||||
|
||||
+41
-31
@@ -2,18 +2,18 @@
|
||||
<view class="login-container">
|
||||
<view class="logo">
|
||||
<image src="/static/logo.png" mode="aspectFit" />
|
||||
<text class="app-name">风电者共享风扇&充电宝</text>
|
||||
<text class="app-name">{{ $t('app.slogan') }}</text>
|
||||
</view>
|
||||
|
||||
<view class="title">登录您的账号</view>
|
||||
<view class="subtitle">为保障使用体验,请先完成登录</view>
|
||||
<view class="title">{{ $t('auth.loginTitle') }}</view>
|
||||
<view class="subtitle">{{ $t('auth.loginDesc') }}</view>
|
||||
|
||||
<!-- 微信一键手机号快捷登录(推荐) -->
|
||||
<button v-if="!isAgreed" class="btn primary" @click="handleLoginClick">
|
||||
手机号快捷登录
|
||||
{{ $t('auth.getPhoneNumber') }}
|
||||
</button>
|
||||
<button v-else class="btn primary" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
||||
手机号快捷登录
|
||||
{{ $t('auth.getPhoneNumber') }}
|
||||
</button>
|
||||
|
||||
<!-- 仅微信登录(不授权手机号时使用) -->
|
||||
@@ -24,10 +24,10 @@
|
||||
<label class="agreement-label">
|
||||
<checkbox value="agreed" :checked="isAgreed" color="#07c160" class="agreement-checkbox" />
|
||||
<text class="agreement-text">
|
||||
我已阅读并同意
|
||||
<text class="link" @tap.stop="go('/pages/legal/agreement')">《用户协议》</text>
|
||||
和
|
||||
<text class="link" @tap.stop="go('/pages/legal/privacy')">《隐私政策》</text>
|
||||
{{ $t('auth.agreeToTerms') }}
|
||||
<text class="link" @tap.stop="go('/pages/legal/agreement')">{{ $t('user.userAgreement') }}</text>
|
||||
{{ $t('common.and') }}
|
||||
<text class="link" @tap.stop="go('/pages/legal/privacy')">{{ $t('user.privacyPolicy') }}</text>
|
||||
</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
@@ -36,9 +36,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 设置页面标题
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('auth.loginTitle')
|
||||
})
|
||||
})
|
||||
|
||||
const redirect = ref('/pages/index/index')
|
||||
const isAgreed = ref(false) // 是否同意协议
|
||||
@@ -67,23 +77,23 @@
|
||||
return
|
||||
}
|
||||
|
||||
// 未勾选,弹窗提示
|
||||
uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '请先阅读并同意《用户协议》和《隐私政策》',
|
||||
confirmText: '同意',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 用户点击同意,自动勾选
|
||||
isAgreed.value = true
|
||||
resolve()
|
||||
} else {
|
||||
// 用户点击取消
|
||||
reject(new Error('需要同意协议才能登录'))
|
||||
}
|
||||
// 未勾选,弹窗提示
|
||||
uni.showModal({
|
||||
title: $t('common.tips'),
|
||||
content: $t('auth.pleaseAgreeToTerms'),
|
||||
confirmText: $t('common.confirm'),
|
||||
cancelText: $t('common.cancel'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 用户点击同意,自动勾选
|
||||
isAgreed.value = true
|
||||
resolve()
|
||||
} else {
|
||||
// 用户点击取消
|
||||
reject(new Error('需要同意协议才能登录'))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -108,8 +118,8 @@
|
||||
// 先检查是否同意协议
|
||||
await checkAgreement()
|
||||
|
||||
await wxLogin()
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
await wxLogin()
|
||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
||||
await navigateAfterLogin()
|
||||
} catch (error) {
|
||||
if (error.message !== '需要同意协议才能登录') {
|
||||
@@ -120,7 +130,7 @@
|
||||
|
||||
const onGetPhoneNumber = async (e) => {
|
||||
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||
uni.showToast({ title: '已取消手机号授权', icon: 'none' })
|
||||
uni.showToast({ title: $t('auth.phoneCancelled'), icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,10 +139,10 @@
|
||||
await wxLogin()
|
||||
// 再用微信返回的临时 code 换取手机号
|
||||
await getUserPhoneNumber(e.detail.code)
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
||||
await navigateAfterLogin()
|
||||
} catch (error) {
|
||||
uni.showToast({ title: error.message || '登录失败', icon: 'none' })
|
||||
uni.showToast({ title: error.message || $t('auth.loginFailed'), icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-22
@@ -6,8 +6,8 @@
|
||||
<image v-else class="avatar" src="@/static/head.png" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="user-text">
|
||||
<view class="nickname">{{ userInfo.nickName || '点击登录' }}</view>
|
||||
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : '授权登录后可查看订单与资产' }}</view>
|
||||
<view class="nickname">{{ userInfo.nickName || $t('user.clickToLogin') }}</view>
|
||||
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : $t('user.loginPrompt') }}</view>
|
||||
</view>
|
||||
<uv-icon type="right" size="16" color="#999"></uv-icon>
|
||||
</view>
|
||||
@@ -32,56 +32,56 @@
|
||||
<view class="list-item" @click="handleQuickReturn">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/express_return.png" mode="aspectFit"></image>
|
||||
<text class="title">快速归还<text style="font-size: 18rpx;">(直接查看使用中的订单)</text></text>
|
||||
<text class="title">{{ $t('user.quickReturn') }}<text style="font-size: 18rpx;">{{ $t('user.quickReturnDesc') }}</text></text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="list-item" @click="navigateTo('/pages/expressReturn/index')" v-if="showMenuItem">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/express.png" mode="aspectFit"></image>
|
||||
<text class="title">快递归还记录</text>
|
||||
<text class="title">{{ $t('user.expressReturn') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="list-item" @click="navigateTo('/pages/order/index')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/orderList.png" mode="aspectFit"></image>
|
||||
<text class="title">我的订单</text>
|
||||
<text class="title">{{ $t('user.myOrders') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="list-item" @click="navigateTo('/pages/help/index')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/customer-service.png" mode="aspectFit"></image>
|
||||
<text class="title">客服中心</text>
|
||||
<text class="title">{{ $t('user.customerService') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="list-item" @click="navigateTo('/pages/feedback/index')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/suggess.png" mode="aspectFit"></image>
|
||||
<text class="title">投诉与建议</text>
|
||||
<text class="title">{{ $t('user.feedback') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<!-- <view class="list-item" @click="navigateTo('/pages/legal/agreement')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/business-licence.png" mode="aspectFit"></image>
|
||||
<text class="title">营业资质</text>
|
||||
<text class="title">{{ $t('user.businessLicense') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view> -->
|
||||
<view class="list-item" @click="navigateTo('/pages/join/index')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/peopleInWork.png" mode="aspectFit"></image>
|
||||
<text class="title">合作加盟</text>
|
||||
<text class="title">{{ $t('user.cooperation') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="list-item" @click="navigateTo('/pages/setting/index')">
|
||||
<view class="left">
|
||||
<image class="icon" src="/static/setting.png" mode="aspectFit"></image>
|
||||
<text class="title">设置</text>
|
||||
<text class="title">{{ $t('user.settings') }}</text>
|
||||
</view>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
@@ -90,11 +90,11 @@
|
||||
|
||||
<view class="footer-agreements">
|
||||
<view class="link-box">
|
||||
<text class="link" @click="navigateTo('/pages/legal/agreement')">《用户协议》</text>
|
||||
<text class="link" @click="navigateTo('/pages/legal/agreement')">{{ $t('user.userAgreement') }}</text>
|
||||
<text class="sep">|</text>
|
||||
<text class="link" @click="navigateTo('/pages/legal/privacy')">《隐私政策》</text>
|
||||
<text class="link" @click="navigateTo('/pages/legal/privacy')">{{ $t('user.privacyPolicy') }}</text>
|
||||
</view>
|
||||
<view class="version">v{{ appVersion }}</view>
|
||||
<view class="version">{{ $t('user.version') }}{{ appVersion }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 保留授权弹窗,暂不启用 -->
|
||||
@@ -133,8 +133,11 @@ import {
|
||||
import {
|
||||
URL
|
||||
} from '../../config/url.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
// 设置页执行退出登录,此页不再直接调用
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 响应式状态
|
||||
const userInfo = ref({});
|
||||
const deposit = ref('0.00');
|
||||
@@ -147,6 +150,9 @@ import {
|
||||
|
||||
// 页面加载时初始化
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('user.personalCenter')
|
||||
})
|
||||
getInfo();
|
||||
initVersion();
|
||||
});
|
||||
@@ -186,7 +192,7 @@ import {
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取用户信息失败',
|
||||
title: $t('user.getUserInfoFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -269,7 +275,7 @@ import {
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '暂无使用中的订单',
|
||||
title: $t('order.noOrder'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -277,7 +283,7 @@ import {
|
||||
uni.hideLoading();
|
||||
console.error('获取使用中订单失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取订单失败',
|
||||
title: $t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -300,7 +306,7 @@ import {
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({
|
||||
title: '请在微信小程序中使用此功能',
|
||||
title: $t('auth.pleaseUseInWechat'),
|
||||
icon: 'none'
|
||||
})
|
||||
// #endif
|
||||
@@ -404,7 +410,7 @@ import {
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({
|
||||
title: '请在微信小程序中使用此功能',
|
||||
title: $t('auth.pleaseUseInWechat'),
|
||||
icon: 'none'
|
||||
});
|
||||
closeAuthPopup();
|
||||
@@ -433,7 +439,7 @@ import {
|
||||
// });
|
||||
|
||||
uni.showToast({
|
||||
title: '信息更新成功',
|
||||
title: $t('user.updateSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
@@ -442,7 +448,7 @@ import {
|
||||
} catch (error) {
|
||||
console.error('更新用户信息失败:', error);
|
||||
uni.showToast({
|
||||
title: '更新用户信息失败',
|
||||
title: $t('user.updateFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -511,7 +517,7 @@ import {
|
||||
// 关于我们
|
||||
const handleAboutUs = () => {
|
||||
uni.showToast({
|
||||
title: '功能开发中',
|
||||
title: $t('help.functionDeveloping'),
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
@@ -519,7 +525,7 @@ import {
|
||||
// 隐私政策
|
||||
const handlePrivacyPolicy = () => {
|
||||
uni.showToast({
|
||||
title: '功能开发中',
|
||||
title: $t('help.functionDeveloping'),
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
+58
-53
@@ -19,9 +19,9 @@
|
||||
<view class="info-col">
|
||||
<view class="info-value-wrapper">
|
||||
<text class="info-value-large">{{ getOrderFee() }}</text>
|
||||
<text class="info-value-unit">元</text>
|
||||
<text class="info-value-unit">{{ $t('unit.yuan') }}</text>
|
||||
</view>
|
||||
<view class="info-label">订单金额</view>
|
||||
<view class="info-label">{{ $t('order.totalAmount') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fee-rule">
|
||||
@@ -31,39 +31,39 @@
|
||||
|
||||
<!-- 租借信息卡片 -->
|
||||
<view class="rent-card">
|
||||
<view class="rent-title">租借信息</view>
|
||||
<view class="rent-title">{{ $t('order.rentInfo') }}</view>
|
||||
<view class="rent-item">
|
||||
<view class="rent-label">订单编号</view>
|
||||
<view class="rent-label">{{ $t('order.orderNo') }}</view>
|
||||
<view class="rent-value">{{ orderInfo.orderNo || '-' }}</view>
|
||||
</view>
|
||||
<view class="rent-item">
|
||||
<view class="rent-label">风扇编号</view>
|
||||
<view class="rent-label">{{ $t('order.fanNo') }}</view>
|
||||
<view class="rent-value">{{ deviceId || '-' }}</view>
|
||||
</view>
|
||||
<view class="rent-item">
|
||||
<view class="rent-label">租借时间</view>
|
||||
<view class="rent-label">{{ $t('order.rentTime') }}</view>
|
||||
<view class="rent-value">{{ orderInfo.startTime || '-' }}</view>
|
||||
</view>
|
||||
<view class="rent-item">
|
||||
<view class="rent-label">租借地点</view>
|
||||
<view class="rent-value">{{ orderInfo.positionName || '新佳宜(九天银河店)' }}</view>
|
||||
<view class="rent-label">{{ $t('order.rentLocation') }}</view>
|
||||
<view class="rent-value">{{ orderInfo.positionName || '-' }}</view>
|
||||
</view>
|
||||
<view class="rent-item">
|
||||
<view class="rent-label">租借方式</view>
|
||||
<view class="rent-label">{{ $t('order.rentMethod') }}</view>
|
||||
<view class="rent-value">{{ getPayWayText() }}</view>
|
||||
</view>
|
||||
<view class="rent-item" v-if="isOrderCompleted() && orderInfo.endTime">
|
||||
<view class="rent-label">归还时间</view>
|
||||
<view class="rent-label">{{ $t('order.returnTime') }}</view>
|
||||
<view class="rent-value">{{ orderInfo.endTime }}</view>
|
||||
</view>
|
||||
<view class="rent-item" v-if="isOrderCompleted() && orderInfo.returnPosition">
|
||||
<view class="rent-label">归还地点</view>
|
||||
<view class="rent-value">{{ orderInfo.returnPosition || '新佳宜(九天银河店)' }}</view>
|
||||
<view class="rent-label">{{ $t('order.returnLocation') }}</view>
|
||||
<view class="rent-value">{{ orderInfo.returnPosition || '-' }}</view>
|
||||
</view>
|
||||
<view class="rent-paid" v-if="isOrderCompleted()">
|
||||
<text class="paid-label">已支付</text>
|
||||
<text class="paid-label">{{ $t('order.paid') }}</text>
|
||||
<text class="paid-value">{{ orderInfo.currentFee || orderInfo.payAmount || '10' }}</text>
|
||||
<text class="paid-unit">元</text>
|
||||
<text class="paid-unit">{{ $t('unit.yuan') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -73,16 +73,16 @@
|
||||
<template v-if="orderInfo.orderStatus === 'in_used'">
|
||||
<view class="bottom-icon-btn" @click="contactService">
|
||||
<image src="/static/customer-service.png" class="icon" mode="aspectFit"></image>
|
||||
<text>客服中心</text>
|
||||
<text>{{ $t('user.customerService') }}</text>
|
||||
</view>
|
||||
<view v-if="!showExpressAction" class="countdown-btn">
|
||||
{{ formatCountdown(countdownRemaining) }}后可快递归还
|
||||
{{ formatCountdown(countdownRemaining) }}{{ $t('order.canExpressReturn') }}
|
||||
</view>
|
||||
<view v-if="showExpressAction" class="action-btn secondary" @click="expressRetrunOrder">
|
||||
暂停计费
|
||||
{{ $t('order.pauseBilling') }}
|
||||
</view>
|
||||
<view v-if="showExpressAction" class="action-btn primary" @click="quickReturn">
|
||||
快速归还
|
||||
{{ $t('order.quickReturn') }}
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -90,26 +90,26 @@
|
||||
<template v-if="isOrderCompleted()">
|
||||
<view class="bottom-icon-btn" @click="handleWithdraw" v-if="!orderInfo.isWithdrawn && orderInfo.refundAmount > 0">
|
||||
<image src="/static/suggess.png" class="icon" mode="aspectFit"></image>
|
||||
<text>费用申诉</text>
|
||||
<text>{{ $t('order.feeAppeal') }}</text>
|
||||
</view>
|
||||
<view class="bottom-icon-btn" @click="contactService">
|
||||
<image src="/static/customer-service.png" class="icon" mode="aspectFit"></image>
|
||||
<text>客服中心</text>
|
||||
<text>{{ $t('user.customerService') }}</text>
|
||||
</view>
|
||||
<view class="action-btn primary" @click="rentAgain">
|
||||
再次租借
|
||||
{{ $t('order.rentAgain') }}
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 待支付状态 -->
|
||||
<template v-if="orderInfo.orderStatus === 'waiting_for_payment'">
|
||||
<view class="action-btn secondary" @click="handleCancelOrder">取消订单</view>
|
||||
<view class="action-btn primary" @click="handlePayment">立即支付</view>
|
||||
<view class="action-btn secondary" @click="handleCancelOrder">{{ $t('order.cancelOrder') }}</view>
|
||||
<view class="action-btn primary" @click="handlePayment">{{ $t('order.payNow') }}</view>
|
||||
</template>
|
||||
|
||||
<!-- 已取消状态 -->
|
||||
<template v-if="orderInfo.orderStatus === 'order_cancelled'">
|
||||
<view class="action-btn primary full-width" @click="goToHome">返回首页</view>
|
||||
<view class="action-btn primary full-width" @click="goToHome">{{ $t('order.backToHome') }}</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
@@ -168,6 +168,11 @@
|
||||
onLoad(options) {
|
||||
console.log('订单详情页加载,参数:', JSON.stringify(options))
|
||||
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('order.orderDetail')
|
||||
})
|
||||
|
||||
this.isPageActive = true
|
||||
|
||||
// 从缓存读取通知内容(计费规则)
|
||||
@@ -241,27 +246,27 @@
|
||||
// 获取订单状态文字
|
||||
getOrderStatusText() {
|
||||
const statusMap = {
|
||||
'waiting_for_payment': '待支付',
|
||||
'payment_in_progress': '支付中',
|
||||
'payment_successful': '支付成功',
|
||||
'in_used': '使用中',
|
||||
'payment_failed': '支付失败',
|
||||
'order_cancelled': '已取消',
|
||||
'used_done': '已完成',
|
||||
'used_down': '已完成'
|
||||
'waiting_for_payment': this.$t('order.waitingForPayment'),
|
||||
'payment_in_progress': this.$t('order.paymentInProgress'),
|
||||
'payment_successful': this.$t('order.paymentSuccess'),
|
||||
'in_used': this.$t('order.inUse'),
|
||||
'payment_failed': this.$t('order.paymentFailed'),
|
||||
'order_cancelled': this.$t('order.cancelled'),
|
||||
'used_done': this.$t('order.finished'),
|
||||
'used_down': this.$t('order.finished')
|
||||
}
|
||||
return statusMap[this.orderInfo.orderStatus] || '订单详情'
|
||||
return statusMap[this.orderInfo.orderStatus] || this.$t('order.orderDetail')
|
||||
},
|
||||
|
||||
// 获取状态描述
|
||||
getStatusDesc() {
|
||||
const descMap = {
|
||||
'waiting_for_payment': '请尽快完成支付',
|
||||
'in_used': '请妥善保管设备,使用完毕后及时归还',
|
||||
'used_done': '您的风扇已归还,感谢使用',
|
||||
'used_down': '您的风扇已归还,感谢使用',
|
||||
'order_cancelled': '订单已取消',
|
||||
'payment_failed': '支付失败,请重新支付'
|
||||
'waiting_for_payment': this.$t('order.pleasePaySoon'),
|
||||
'in_used': this.$t('order.pleaseReturnInTime'),
|
||||
'used_done': this.$t('order.returnedThankYou'),
|
||||
'used_down': this.$t('order.returnedThankYou'),
|
||||
'order_cancelled': this.$t('order.orderCancelled'),
|
||||
'payment_failed': this.$t('order.paymentFailedRetry')
|
||||
}
|
||||
return descMap[this.orderInfo.orderStatus] || ''
|
||||
},
|
||||
@@ -293,11 +298,11 @@
|
||||
// 获取支付方式文本
|
||||
getPayWayText() {
|
||||
const payWayMap = {
|
||||
'wx_score_pay': '免押租借',
|
||||
'wx_member_pay': '会员订单',
|
||||
'wx_pay': '押金租借'
|
||||
'wx_score_pay': this.$t('order.depositFree'),
|
||||
'wx_member_pay': this.$t('order.memberOrder'),
|
||||
'wx_pay': this.$t('order.depositPay')
|
||||
}
|
||||
return payWayMap[this.orderInfo.payWay] || '免押租借'
|
||||
return payWayMap[this.orderInfo.payWay] || this.$t('order.depositFree')
|
||||
},
|
||||
|
||||
// 格式化倒计时(显示为 HH:MM:SS 格式)
|
||||
@@ -393,7 +398,7 @@
|
||||
// 获取使用时长标签文本
|
||||
getUsedTimeLabel() {
|
||||
// 使用中状态显示"已使用",已完成状态显示"使用时长"
|
||||
return this.orderInfo.orderStatus === 'in_used' ? '已使用' : '使用时长'
|
||||
return this.orderInfo.orderStatus === 'in_used' ? this.$t('order.used') : this.$t('order.duration')
|
||||
},
|
||||
|
||||
// 获取订单费用(不含单位)
|
||||
@@ -549,7 +554,7 @@
|
||||
|
||||
try {
|
||||
if (!this.orderInfo.orderId) {
|
||||
throw new Error('订单ID不能为空')
|
||||
throw new Error(this.$t('order.orderIdRequired'))
|
||||
}
|
||||
|
||||
const result = await queryById(this.orderInfo.orderId)
|
||||
@@ -762,13 +767,13 @@
|
||||
// 取消订单
|
||||
handleCancelOrder() {
|
||||
uni.showModal({
|
||||
title: '确认取消',
|
||||
content: '确定要取消此订单吗?',
|
||||
title: this.$t('order.confirmCancel'),
|
||||
content: this.$t('order.confirmCancelContent'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: this.$t('common.processing')
|
||||
})
|
||||
const result = await cancelOrder({
|
||||
orderId: this.orderInfo.orderId
|
||||
@@ -776,17 +781,17 @@
|
||||
if (result.code === 200) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '订单已取消',
|
||||
title: this.$t('order.cancelSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
await this.getOrderDetails()
|
||||
} else {
|
||||
throw new Error(result.msg || '取消订单失败')
|
||||
throw new Error(result.msg || this.$t('order.cancelFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: error.message || '取消订单失败',
|
||||
title: error.message || this.$t('order.cancelFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -821,7 +826,7 @@
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
uni.showToast({
|
||||
title: '退款申请成功',
|
||||
title: this.$t('order.refundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
@@ -837,7 +842,7 @@
|
||||
} catch (error) {
|
||||
console.error('退款申请错误:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '退款申请失败',
|
||||
title: error.message || this.$t('order.refundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
|
||||
+42
-32
@@ -10,12 +10,12 @@
|
||||
|
||||
<!-- 订单列表 -->
|
||||
<view class="order-list">
|
||||
<view class="empty-state" v-if="orderList.length === 0">
|
||||
<view class="empty-icon">
|
||||
<image src="/static/orderList.png" mode="aspectFill" class="empty-icon"></image>
|
||||
</view>
|
||||
<text class="empty-text">暂无订单记录</text>
|
||||
<view class="empty-state" v-if="orderList.length === 0">
|
||||
<view class="empty-icon">
|
||||
<image src="/static/orderList.png" mode="aspectFill" class="empty-icon"></image>
|
||||
</view>
|
||||
<text class="empty-text">{{ $t('order.noOrderRecord') }}</text>
|
||||
</view>
|
||||
|
||||
<OrderItemCard
|
||||
v-for="(order, index) in orderList"
|
||||
@@ -56,6 +56,16 @@
|
||||
import {
|
||||
URL
|
||||
} from '../../config/url.js';
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 设置页面标题
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('order.myOrders')
|
||||
})
|
||||
})
|
||||
|
||||
// 初始化状态
|
||||
const currentTab = ref(0);
|
||||
@@ -64,62 +74,62 @@
|
||||
// 订单状态映射
|
||||
const orderStatusMap = reactive({
|
||||
'0': {
|
||||
text: '待支付',
|
||||
get text() { return $t('order.waitingForPayment') },
|
||||
class: 'status-waiting'
|
||||
},
|
||||
'1': {
|
||||
text: '使用中',
|
||||
get text() { return $t('order.inUse') },
|
||||
class: 'status-using'
|
||||
},
|
||||
'2': {
|
||||
text: '已完成',
|
||||
get text() { return $t('order.finished') },
|
||||
class: 'status-finished'
|
||||
},
|
||||
'3': {
|
||||
text: '已取消',
|
||||
get text() { return $t('order.cancelled') },
|
||||
class: 'status-cancelled'
|
||||
},
|
||||
'waiting_for_payment': {
|
||||
text: '待支付',
|
||||
get text() { return $t('order.waitingForPayment') },
|
||||
class: 'status-waiting'
|
||||
},
|
||||
'in_used': {
|
||||
text: '使用中',
|
||||
get text() { return $t('order.inUse') },
|
||||
class: 'status-using'
|
||||
},
|
||||
'used_done': {
|
||||
text: '已完成',
|
||||
get text() { return $t('order.finished') },
|
||||
class: 'status-finished'
|
||||
},
|
||||
'order_cancelled': {
|
||||
text: '已取消',
|
||||
get text() { return $t('order.cancelled') },
|
||||
class: 'status-cancelled'
|
||||
},
|
||||
'express_return': {
|
||||
text: '快递归还',
|
||||
get text() { return $t('express.title') },
|
||||
class: 'status-express-return'
|
||||
}
|
||||
});
|
||||
|
||||
// 订单状态标签
|
||||
const orderStatusTabs = reactive([{
|
||||
text: '全部',
|
||||
get text() { return $t('common.all') },
|
||||
status: []
|
||||
},
|
||||
{
|
||||
text: '待付款',
|
||||
get text() { return $t('order.waitingForPayment') },
|
||||
status: ['waiting_for_payment']
|
||||
},
|
||||
{
|
||||
text: '使用中',
|
||||
get text() { return $t('order.inUse') },
|
||||
status: ['in_used']
|
||||
},
|
||||
{
|
||||
text: '已完成',
|
||||
get text() { return $t('order.finished') },
|
||||
status: ['used_done']
|
||||
},
|
||||
{
|
||||
text: '已取消',
|
||||
get text() { return $t('order.cancelled') },
|
||||
status: ['order_cancelled']
|
||||
}
|
||||
]);
|
||||
@@ -212,7 +222,7 @@
|
||||
} catch (error) {
|
||||
console.error('获取订单列表失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取订单列表失败',
|
||||
title: $t('order.getOrderListFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -224,14 +234,14 @@
|
||||
const res = await getOrderByOrderNoScorePayStatus(order.orderNo);
|
||||
if (res.code === 200) {
|
||||
uni.showToast({
|
||||
title: '状态同步成功',
|
||||
title: $t('order.syncSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
await loadOrderList(orderStatusTabs[currentTab.value].status);
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '同步状态失败',
|
||||
title: $t('order.syncFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -258,7 +268,7 @@
|
||||
const handlePayment = async (order) => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: $t('common.processing')
|
||||
});
|
||||
|
||||
// 调用后端创建微信支付订单接口
|
||||
@@ -279,7 +289,7 @@
|
||||
...payParams,
|
||||
success: async () => {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
title: $t('payment.paymentSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
@@ -295,7 +305,7 @@
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('支付失败:', err);
|
||||
throw new Error('支付失败,请重试');
|
||||
throw new Error($t('payment.paymentFailedRetry'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -306,7 +316,7 @@
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: error.message || '支付失败',
|
||||
title: error.message || $t('payment.paymentFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -316,12 +326,12 @@
|
||||
const handleCancelOrder = async (order) => {
|
||||
try {
|
||||
uni.showModal({
|
||||
title: '确认取消',
|
||||
content: '确定要取消此订单吗?',
|
||||
title: $t('order.confirmCancel'),
|
||||
content: $t('order.confirmCancelContent'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: $t('common.processing')
|
||||
});
|
||||
|
||||
const result = await cancelOrder({
|
||||
@@ -331,14 +341,14 @@
|
||||
if (result) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '订单已取消',
|
||||
title: $t('order.cancelSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 刷新订单列表
|
||||
await loadOrderList();
|
||||
} else {
|
||||
throw new Error(result.msg || '取消订单失败');
|
||||
throw new Error(result.msg || $t('order.cancelFailed'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,7 +356,7 @@
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: error.message || '取消订单失败',
|
||||
title: error.message || $t('order.cancelFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
|
||||
+29
-24
@@ -9,38 +9,38 @@
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-card">
|
||||
<view class="card-title">订单信息</view>
|
||||
<view class="card-title">{{ $t('payment.orderInfo') }}</view>
|
||||
<view class="info-item">
|
||||
<text class="label">订单号</text>
|
||||
<text class="label">{{ $t('order.orderNo') }}</text>
|
||||
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">设备号</text>
|
||||
<text class="label">{{ $t('order.deviceNo') }}</text>
|
||||
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">创建时间</text>
|
||||
<text class="label">{{ $t('payment.createTime') }}</text>
|
||||
<text class="value">{{ orderInfo.createTime || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">联系电话</text>
|
||||
<text class="label">{{ $t('payment.contactPhone') }}</text>
|
||||
<text class="value">{{ orderInfo.phone || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 费用信息 -->
|
||||
<view class="price-card">
|
||||
<view class="card-title">费用信息</view>
|
||||
<view class="card-title">{{ $t('payment.feeInfo') }}</view>
|
||||
<view class="price-item">
|
||||
<text class="label">押金</text>
|
||||
<text class="label">{{ $t('payment.deposit') }}</text>
|
||||
<text class="value">¥{{ orderInfo.deposit || '99.00' }}</text>
|
||||
</view>
|
||||
<view class="price-item">
|
||||
<text class="label">套餐</text>
|
||||
<text class="value">{{ packageInfo.price }}元/{{ packageInfo.time }}小时</text>
|
||||
<text class="label">{{ $t('payment.package') }}</text>
|
||||
<text class="value">{{ packageInfo.price }}{{ $t('unit.yuan') }}/{{ packageInfo.time }}{{ $t('time.hour') }}</text>
|
||||
</view>
|
||||
<view class="price-item total">
|
||||
<text class="label">合计</text>
|
||||
<text class="label">{{ $t('payment.total') }}</text>
|
||||
<text class="value">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -51,10 +51,10 @@
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar">
|
||||
<view class="total-amount">
|
||||
<text>合计:</text>
|
||||
<text>{{ $t('payment.total') }}:</text>
|
||||
<text class="amount">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
<view class="pay-btn" @click="handlePayment">立即支付</view>
|
||||
<view class="pay-btn" @click="handlePayment">{{ $t('payment.payNow') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -81,8 +81,8 @@ export default {
|
||||
passedTotalAmount: null,
|
||||
passedDepositAmount: null,
|
||||
orderStatus: {
|
||||
text: '等待支付',
|
||||
desc: '请在15分钟内完成支付',
|
||||
get text() { return this.$t('payment.waitingForPayment') },
|
||||
get desc() { return this.$t('payment.pleasePayIn15Min') },
|
||||
class: 'waiting'
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,11 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('payment.orderPayment')
|
||||
})
|
||||
|
||||
if (options && options.orderId) {
|
||||
this.orderId = options.orderId
|
||||
|
||||
@@ -141,9 +146,9 @@ export default {
|
||||
}
|
||||
|
||||
this.loadOrderInfo()
|
||||
} else {
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '订单信息不存在',
|
||||
title: this.$t('order.orderNotExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -158,7 +163,7 @@ export default {
|
||||
async loadOrderInfo() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
title: this.$t('common.loading')
|
||||
})
|
||||
|
||||
const res = await queryById(this.orderId)
|
||||
@@ -238,7 +243,7 @@ export default {
|
||||
async handlePayment() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: this.$t('common.processing')
|
||||
})
|
||||
|
||||
// 调用后端创建微信支付订单接口
|
||||
@@ -259,7 +264,7 @@ export default {
|
||||
...payParams,
|
||||
success: async () => {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
title: this.$t('payment.paymentSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
@@ -279,7 +284,7 @@ export default {
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('支付失败:', err)
|
||||
throw new Error('支付失败,请重试')
|
||||
throw new Error(this.$t('payment.paymentFailedRetry'))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -298,7 +303,7 @@ export default {
|
||||
async sendRentCommand() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: this.$t('common.processing')
|
||||
})
|
||||
|
||||
// 调用发送租借指令的接口
|
||||
@@ -307,7 +312,7 @@ export default {
|
||||
if (res.code === 200) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '租借成功',
|
||||
title: this.$t('device.rentSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
@@ -318,12 +323,12 @@ export default {
|
||||
})
|
||||
}, 1500)
|
||||
} else {
|
||||
throw new Error(res.msg || '租借失败')
|
||||
throw new Error(res.msg || this.$t('device.rentFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: error.message || '租借失败',
|
||||
title: error.message || this.$t('device.rentFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,82 +3,82 @@
|
||||
<!-- 支付成功状态 -->
|
||||
<view class="status-card">
|
||||
<view class="status-icon success"></view>
|
||||
<view class="status-text">归还成功</view>
|
||||
<view class="status-desc">您的风扇已归还,费用已从押金中扣除</view>
|
||||
<view class="status-text">{{ $t('success.returnSuccess') }}</view>
|
||||
<view class="status-desc">{{ $t('success.returnSuccessDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-card">
|
||||
<view class="card-title">订单信息</view>
|
||||
<view class="card-title">{{ $t('success.orderInfo') }}</view>
|
||||
<view class="info-item">
|
||||
<text class="label">订单号</text>
|
||||
<text class="label">{{ $t('order.orderNo') }}</text>
|
||||
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">设备号</text>
|
||||
<text class="label">{{ $t('order.deviceNo') }}</text>
|
||||
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">使用时长</text>
|
||||
<text class="label">{{ $t('success.usedTime') }}</text>
|
||||
<text class="value">{{ orderInfo.usedTime || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">套餐时长</text>
|
||||
<text class="value">{{ orderInfo.packageTime || '1小时' }}</text>
|
||||
<text class="label">{{ $t('success.packageTime') }}</text>
|
||||
<text class="value">{{ orderInfo.packageTime || '1' + $t('time.hour') }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">超出时长</text>
|
||||
<text class="value">{{ orderInfo.extraTime || '0分钟' }}</text>
|
||||
<text class="label">{{ $t('success.extraTime') }}</text>
|
||||
<text class="value">{{ orderInfo.extraTime || '0' + $t('time.minute') }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">归还时间</text>
|
||||
<text class="label">{{ $t('success.returnTime') }}</text>
|
||||
<text class="value">{{ orderInfo.endTime || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 费用信息 -->
|
||||
<view class="refund-card">
|
||||
<view class="card-title">费用信息</view>
|
||||
<view class="card-title">{{ $t('payment.feeInfo') }}</view>
|
||||
<view class="info-item">
|
||||
<text class="label">套餐费用</text>
|
||||
<text class="label">{{ $t('success.packageFee') }}</text>
|
||||
<text class="value">¥{{ orderInfo.packagePrice || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">超时费用</text>
|
||||
<text class="label">{{ $t('success.extraFee') }}</text>
|
||||
<text class="value">¥{{ orderInfo.extraFee || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">总费用</text>
|
||||
<text class="label">{{ $t('success.totalFee') }}</text>
|
||||
<text class="value">¥{{ orderInfo.currentFee || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">押金</text>
|
||||
<text class="label">{{ $t('success.depositAmount') }}</text>
|
||||
<text class="value">¥{{ orderInfo.deposit || '99.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">退还金额</text>
|
||||
<text class="label">{{ $t('success.refundAmount') }}</text>
|
||||
<text class="value highlight">¥{{ orderInfo.refundAmount || '99.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">退还状态</text>
|
||||
<text class="label">{{ $t('success.refundStatus') }}</text>
|
||||
<text class="value" :class="orderInfo.withdrawStatus || 'waiting'">{{ getWithdrawStatusText() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退款说明卡片 -->
|
||||
<view class="notice-card">
|
||||
<view class="card-title">退款说明</view>
|
||||
<view class="card-title">{{ $t('success.refundNotice') }}</view>
|
||||
<view class="notice-content">
|
||||
<view>1. 押金剩余金额需要您手动申请提现</view>
|
||||
<view>2. 提现申请提交后将在1-3个工作日内退还到原支付账户</view>
|
||||
<view>3. 如有疑问,请联系客服</view>
|
||||
<view>1. {{ $t('success.refundNotice1') }}</view>
|
||||
<view>2. {{ $t('success.refundNotice2') }}</view>
|
||||
<view>3. {{ $t('success.refundNotice3') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="button-group">
|
||||
<button class="primary-btn" @click="handleWithdraw" v-if="!orderInfo.isWithdrawn && orderInfo.refundAmount > 0">申请退款</button>
|
||||
<button class="primary-btn" @click="goToHome">返回首页</button>
|
||||
<button class="primary-btn" @click="handleWithdraw" v-if="!orderInfo.isWithdrawn && orderInfo.refundAmount > 0">{{ $t('success.applyRefund') }}</button>
|
||||
<button class="primary-btn" @click="goToHome">{{ $t('success.backToHome') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -107,12 +107,17 @@ export default {
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('success.returnSuccess')
|
||||
})
|
||||
|
||||
if (options && options.orderId) {
|
||||
this.orderId = options.orderId;
|
||||
this.loadOrderInfo();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '订单ID不能为空',
|
||||
title: this.$t('order.orderIdRequired'),
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
@@ -124,18 +129,18 @@ export default {
|
||||
// 获取退款状态文本
|
||||
getWithdrawStatusText() {
|
||||
const statusMap = {
|
||||
'waiting': '待申请',
|
||||
'processing': '处理中',
|
||||
'success': '已退款',
|
||||
'failed': '退款失败'
|
||||
'waiting': this.$t('success.refundWaiting'),
|
||||
'processing': this.$t('success.refundProcessing'),
|
||||
'success': this.$t('success.refundSuccess'),
|
||||
'failed': this.$t('success.refundFailed')
|
||||
};
|
||||
return statusMap[this.orderInfo.withdrawStatus] || '待申请';
|
||||
return statusMap[this.orderInfo.withdrawStatus] || this.$t('success.refundWaiting');
|
||||
},
|
||||
|
||||
// 加载订单信息
|
||||
async loadOrderInfo() {
|
||||
try {
|
||||
uni.showLoading({ title: '加载中' });
|
||||
uni.showLoading({ title: this.$t('common.loading') });
|
||||
|
||||
const result = await queryById(this.orderId);
|
||||
if (result.code === 200 && result.data) {
|
||||
@@ -216,7 +221,7 @@ export default {
|
||||
} catch (error) {
|
||||
console.error('加载订单信息错误:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '获取订单信息失败',
|
||||
title: error.message || this.$t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
@@ -227,7 +232,7 @@ export default {
|
||||
// 申请退款
|
||||
async handleWithdraw() {
|
||||
try {
|
||||
uni.showLoading({ title: '处理中' });
|
||||
uni.showLoading({ title: this.$t('common.processing') });
|
||||
|
||||
const res = await uni.request({
|
||||
url: `${URL || 'http://127.0.0.1:8080'}/app/withdraw/add/${this.orderInfo.orderNo}`,
|
||||
@@ -241,7 +246,7 @@ export default {
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
uni.showToast({
|
||||
title: '退款申请成功',
|
||||
title: this.$t('order.refundSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
@@ -254,12 +259,12 @@ export default {
|
||||
this.loadOrderInfo();
|
||||
}, 1500);
|
||||
} else {
|
||||
throw new Error(res.data.msg || '退款申请失败');
|
||||
throw new Error(res.data.msg || this.$t('order.refundFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('退款申请错误:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '退款申请失败',
|
||||
title: error.message || this.$t('order.refundFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
|
||||
+26
-19
@@ -3,27 +3,27 @@
|
||||
<!-- 支付成功状态 -->
|
||||
<view class="status-card">
|
||||
<view class="status-icon success"></view>
|
||||
<view class="status-text">支付成功</view>
|
||||
<view class="status-desc">您的订单已支付成功</view>
|
||||
<view class="status-text">{{ $t('success.paymentSuccess') }}</view>
|
||||
<view class="status-desc">{{ $t('success.paymentSuccessDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-card">
|
||||
<view class="card-title">订单信息</view>
|
||||
<view class="card-title">{{ $t('success.orderInfo') }}</view>
|
||||
<view class="info-item">
|
||||
<text class="label">订单号</text>
|
||||
<text class="label">{{ $t('order.orderNo') }}</text>
|
||||
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">设备号</text>
|
||||
<text class="label">{{ $t('order.deviceNo') }}</text>
|
||||
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">支付金额</text>
|
||||
<text class="label">{{ $t('success.paymentAmount') }}</text>
|
||||
<text class="value">¥{{ orderInfo.amount || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">支付时间</text>
|
||||
<text class="label">{{ $t('success.paymentTime') }}</text>
|
||||
<text class="value">{{ orderInfo.payTime || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -38,8 +38,8 @@
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="button-group">
|
||||
<button class="primary-btn" @click="goToHome">返回首页</button>
|
||||
<button class="secondary-btn" @click="goToOrderList">查看订单</button>
|
||||
<button class="primary-btn" @click="goToHome">{{ $t('success.backToHome') }}</button>
|
||||
<button class="secondary-btn" @click="goToOrderList">{{ $t('success.viewOrder') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -54,11 +54,18 @@ export default {
|
||||
orderId: '',
|
||||
orderInfo: {},
|
||||
isLoading: true,
|
||||
deviceMessage: '正在准备您的设备,请稍候...',
|
||||
deviceMessage: '',
|
||||
hasTriggeredDevice: false
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('success.paymentSuccess')
|
||||
})
|
||||
|
||||
this.deviceMessage = this.$t('success.preparingDevice')
|
||||
|
||||
if (options && options.orderId) {
|
||||
this.orderId = options.orderId
|
||||
this.loadOrderInfo()
|
||||
@@ -70,7 +77,7 @@ export default {
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '订单信息不存在',
|
||||
title: this.$t('order.orderNotExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -82,7 +89,7 @@ export default {
|
||||
async loadOrderInfo() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '加载中'
|
||||
title: this.$t('common.loading')
|
||||
})
|
||||
|
||||
const res = await queryById(this.orderId)
|
||||
@@ -118,7 +125,7 @@ export default {
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: error.message || '获取订单信息失败',
|
||||
title: error.message || this.$t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -134,7 +141,7 @@ export default {
|
||||
this.hasTriggeredDevice = true
|
||||
uni.$emit('orderSuccess:' + this.orderId)
|
||||
this.isLoading = true
|
||||
this.deviceMessage = '正在准备您的设备,请稍候...'
|
||||
this.deviceMessage = this.$t('success.preparingDevice')
|
||||
|
||||
try {
|
||||
console.log(`准备触发弹出风扇,orderId: ${this.orderId}`)
|
||||
@@ -144,19 +151,19 @@ export default {
|
||||
console.log('确认支付并弹出风扇结果:', JSON.stringify(result))
|
||||
|
||||
if (result && result.code === 200) {
|
||||
this.deviceMessage = '设备已弹出,请取走您的风扇'
|
||||
this.deviceMessage = this.$t('success.deviceReady')
|
||||
uni.showToast({
|
||||
title: '风扇已弹出',
|
||||
title: this.$t('success.deviceReady'),
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
throw new Error((result && result.msg) || '弹出风扇失败')
|
||||
throw new Error((result && result.msg) || this.$t('success.deviceFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('弹出风扇错误:', error)
|
||||
this.deviceMessage = '弹出设备失败,请联系客服'
|
||||
this.deviceMessage = this.$t('success.deviceFailed')
|
||||
uni.showToast({
|
||||
title: error.message || '弹出风扇失败,请联系客服',
|
||||
title: error.message || this.$t('success.deviceFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
|
||||
+20
-20
@@ -8,7 +8,7 @@
|
||||
<!-- 场地信息卡片 -->
|
||||
<view class="info-card">
|
||||
<!-- 场地名称 -->
|
||||
<view class="position-name">{{ positionInfo.name || '加载中...' }}</view>
|
||||
<view class="position-name">{{ positionInfo.name || $t('common.loading') }}</view>
|
||||
|
||||
<!-- 地址信息 -->
|
||||
<view class="info-item" v-if="positionInfo.location">
|
||||
@@ -19,30 +19,30 @@
|
||||
<!-- 营业时间 -->
|
||||
<view class="info-item" v-if="positionInfo.workTime && positionInfo.workTime !== '0'">
|
||||
<image src="/static/device-time.png" class="item-icon" mode="aspectFit"></image>
|
||||
<text class="item-text">营业时间:{{ positionInfo.workTime }}</text>
|
||||
<text class="item-text">{{ $t('location.businessHours') }}{{ positionInfo.workTime }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 计费信息 -->
|
||||
<view class="info-item">
|
||||
<image src="/static/device-price.png" class="item-icon" mode="aspectFit"></image>
|
||||
<text class="item-text">计费:{{ pricingText }}</text>
|
||||
<text class="item-text">{{ $t('device.pricing') }}:{{ pricingText }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 按钮组 -->
|
||||
<view class="button-group">
|
||||
<view style="display: flex;flex-direction: row;gap: 10rpx;">
|
||||
<view class="status-btn" v-if="isRentable">可租借</view>
|
||||
<view class="status-btn" v-if="isReturnable">可归还</view>
|
||||
<view class="status-btn" v-if="isRentable">{{ $t('location.rent') }}</view>
|
||||
<view class="status-btn" v-if="isReturnable">{{ $t('location.return') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="nav-btn" @click.stop="navigateToPosition">导航去这</view>
|
||||
<view class="nav-btn" @click.stop="navigateToPosition">{{ $t('location.navigateHere') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="footer-actions">
|
||||
<button class="action-btn btn-outline" @click="reportError">设备报错</button>
|
||||
<button class="action-btn btn-primary" @click="scanCode">扫码使用</button>
|
||||
<button class="action-btn btn-outline" @click="reportError">{{ $t('device.reportError') }}</button>
|
||||
<button class="action-btn btn-primary" @click="scanCode">{{ $t('device.scanToUse') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -93,7 +93,7 @@
|
||||
const loadPositionDetail = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
title: $t('common.loading')
|
||||
})
|
||||
|
||||
const res = await uni.request({
|
||||
@@ -111,10 +111,10 @@
|
||||
if (position) {
|
||||
positionInfo.value = position
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '场地不存在',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.showToast({
|
||||
title: this.$t('location.notExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} else if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
||||
uni.reLaunch({
|
||||
@@ -124,7 +124,7 @@
|
||||
} catch (e) {
|
||||
console.error('加载场地详情失败:', e)
|
||||
uni.showToast({
|
||||
title: '加载失败',
|
||||
title: $t('common.loadFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -135,7 +135,7 @@
|
||||
const navigateToPosition = () => {
|
||||
if (!positionInfo.value.latitude || !positionInfo.value.longitude) {
|
||||
uni.showToast({
|
||||
title: '该场地坐标信息异常',
|
||||
title: $t('location.coordinateError'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -150,7 +150,7 @@
|
||||
longitude < -180 || longitude > 180 ||
|
||||
(latitude === 0 && longitude === 0)) {
|
||||
uni.showToast({
|
||||
title: '该场地坐标信息异常',
|
||||
title: $t('location.coordinateError'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -185,10 +185,10 @@
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('扫码失败:', err)
|
||||
uni.showToast({
|
||||
title: '扫码失败',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.showToast({
|
||||
title: this.$t('home.scanFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+63
-58
@@ -4,13 +4,13 @@
|
||||
<view class="order-card">
|
||||
<view class="order-header">
|
||||
<text class="title">{{ getOrderStatusText() }}</text>
|
||||
<text class="order-no">订单号:{{ orderInfo.orderNo || '-' }}</text>
|
||||
<text class="order-no">{{ $t('order.orderNo') }}:{{ orderInfo.orderNo || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="device-info">
|
||||
<view class="device-left">
|
||||
<view class="device-name">共享风扇</view>
|
||||
<view class="device-id">设备号:{{ deviceId }}</view>
|
||||
<view class="device-name">{{ $t('device.sharedFan') }}</view>
|
||||
<view class="device-id">{{ $t('order.deviceNo') }}:{{ deviceId }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式标识 -->
|
||||
@@ -19,41 +19,41 @@
|
||||
<view class="payment-badge wx-score" v-if="orderInfo.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="orderInfo.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-if="orderInfo.payWay == 'wx_pay'">
|
||||
<text class="badge-text">押金租借</text>
|
||||
<text class="badge-text">{{ $t('order.depositPay') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="time-info">
|
||||
<view class="time-item">
|
||||
<text class="label">开始时间</text>
|
||||
<text class="label">{{ $t('order.startTime') }}</text>
|
||||
<text class="value">{{ orderInfo.startTime }}</text>
|
||||
</view>
|
||||
<view class="time-item" v-if="orderInfo.endTime">
|
||||
<text class="label">结束时间</text>
|
||||
<text class="label">{{ $t('order.endTime') }}</text>
|
||||
<text class="value">{{ orderInfo.endTime }}</text>
|
||||
</view>
|
||||
<view class="time-item" v-if="orderInfo.orderStatus === 'in_used'">
|
||||
<text class="label">已使用时长</text>
|
||||
<text class="label">{{ $t('order.used') }}</text>
|
||||
<text class="value highlight">{{ orderInfo.usedTime }}</text>
|
||||
</view>
|
||||
<view class="time-item" v-if="orderInfo.orderStatus === 'in_used'">
|
||||
<text class="label">当前费用</text>
|
||||
<text class="label">{{ $t('order.currentFee') }}</text>
|
||||
<text class="value">¥{{ orderInfo.currentFee }}</text>
|
||||
</view>
|
||||
<view class="time-item" v-if="orderInfo.phone">
|
||||
<text class="label">联系电话</text>
|
||||
<text class="label">{{ $t('payment.contactPhone') }}</text>
|
||||
<text class="value">{{ orderInfo.phone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -69,42 +69,42 @@
|
||||
|
||||
<!-- 费用信息卡片 -->
|
||||
<view class="notice-card" v-if="orderInfo.depositAmount || orderInfo.packageTime">
|
||||
<view class="notice-title">费用信息</view>
|
||||
<view class="notice-title">{{ $t('payment.feeInfo') }}</view>
|
||||
<view class="notice-list">
|
||||
<view class="notice-item" v-if="orderInfo.depositAmount">
|
||||
<view class="dot"></view>
|
||||
<text>押金:¥{{ orderInfo.depositAmount }}</text>
|
||||
<text>{{ $t('payment.deposit') }}:¥{{ orderInfo.depositAmount }}</text>
|
||||
</view>
|
||||
<view class="notice-item" v-if="orderInfo.packageTime && orderInfo.packagePrice">
|
||||
<view class="dot"></view>
|
||||
<text>套餐:¥{{ orderInfo.packagePrice }}元 / {{ formatTime(orderInfo.packageTime) }}</text>
|
||||
<text>{{ $t('payment.package') }}:¥{{ orderInfo.packagePrice }}{{ $t('unit.yuan') }} / {{ formatTime(orderInfo.packageTime) }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="dot"></view>
|
||||
<text>合计:¥{{ orderInfo.payAmount || 0 }}</text>
|
||||
<text>{{ $t('payment.total') }}:¥{{ orderInfo.payAmount || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 归还说明 -->
|
||||
<view class="notice-card" v-if="orderInfo.orderStatus === 'in_used'">
|
||||
<view class="notice-title">归还说明</view>
|
||||
<view class="notice-title">{{ $t('order.returnInstructions') }}</view>
|
||||
<view class="notice-list">
|
||||
<view class="notice-item">
|
||||
<view class="dot"></view>
|
||||
<text>请确保设备完好无损</text>
|
||||
<text>{{ $t('order.ensureDeviceIntact') }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="dot"></view>
|
||||
<text>将风扇插入原位置或空闲插口</text>
|
||||
<text>{{ $t('order.insertFanBack') }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="dot"></view>
|
||||
<text>系统将自动检测归还并处理退款</text>
|
||||
<text>{{ $t('order.autoDetectReturn') }}</text>
|
||||
</view>
|
||||
<view class="notice-item">
|
||||
<view class="dot"></view>
|
||||
<text>归还成功后将自动跳转到成功页面</text>
|
||||
<text>{{ $t('order.autoJumpAfterReturn') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -117,25 +117,25 @@
|
||||
<view class="bottom-bar">
|
||||
<!-- 使用中状态显示归还相关操作 -->
|
||||
<view v-if="orderInfo.orderStatus === 'in_used'" class="action-item secondary" @click="checkReturnStatus">
|
||||
刷新状态</view>
|
||||
{{ $t('order.refreshStatus') }}</view>
|
||||
<view v-if="orderInfo.orderStatus === 'in_used' && !showExpressAction" class="action-item primary">
|
||||
倒计时{{ formatHms(countdownRemaining) }}
|
||||
{{ $t('order.countdown') }}{{ formatHms(countdownRemaining) }}
|
||||
</view>
|
||||
<view v-if="orderInfo.orderStatus === 'in_used' && showExpressAction" class="action-item primary" @click="expressRetrunOrder">
|
||||
暂停计费,快递归还
|
||||
{{ $t('order.pauseAndExpress') }}
|
||||
</view>
|
||||
|
||||
<!-- 已完成状态显示查看详情和返回首页 -->
|
||||
<view v-if="orderInfo.orderStatus === 'used_done' || orderInfo.orderStatus === 'used_down'"
|
||||
class="action-item secondary" @click="goToHome">返回首页</view>
|
||||
class="action-item secondary" @click="goToHome">{{ $t('order.backToHome') }}</view>
|
||||
<view v-if="orderInfo.orderStatus === 'used_done' || orderInfo.orderStatus === 'used_down'"
|
||||
class="action-item primary" @click="viewOrderDetails">查看详情</view>
|
||||
class="action-item primary" @click="viewOrderDetails">{{ $t('order.viewDetails') }}</view>
|
||||
|
||||
<!-- 待支付状态显示支付和取消操作 -->
|
||||
<view v-if="orderInfo.orderStatus === 'waiting_for_payment'" class="action-item secondary"
|
||||
@click="handleCancelOrder">取消订单</view>
|
||||
@click="handleCancelOrder">{{ $t('order.cancelOrder') }}</view>
|
||||
<view v-if="orderInfo.orderStatus === 'waiting_for_payment'" class="action-item primary"
|
||||
@click="handlePayment">立即支付</view>
|
||||
@click="handlePayment">{{ $t('order.payNow') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -190,6 +190,11 @@
|
||||
onLoad(options) {
|
||||
console.log('Return page loaded with options:', JSON.stringify(options))
|
||||
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('order.orderDetail')
|
||||
})
|
||||
|
||||
// 标记页面为活跃状态
|
||||
this.isPageActive = true
|
||||
|
||||
@@ -209,7 +214,7 @@
|
||||
} else {
|
||||
// 缺少必要参数
|
||||
uni.showToast({
|
||||
title: '缺少订单信息',
|
||||
title: this.$t('order.orderInfoMissing'),
|
||||
icon: 'none'
|
||||
})
|
||||
|
||||
@@ -406,9 +411,9 @@
|
||||
|
||||
// 显示归还成功弹窗
|
||||
uni.showModal({
|
||||
title: '归还成功',
|
||||
content: '风扇已归还成功,剩余押金将退还到您的账户',
|
||||
confirmText: '查看详情',
|
||||
title: this.$t('order.returnSuccess'),
|
||||
content: this.$t('order.returnSuccessMessage'),
|
||||
confirmText: this.$t('order.viewDetails'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 跳转到归还成功页面查看详情
|
||||
@@ -428,17 +433,17 @@
|
||||
// 根据订单状态获取对应的文字显示
|
||||
getOrderStatusText() {
|
||||
const statusMap = {
|
||||
'waiting_for_payment': '待支付',
|
||||
'payment_in_progress': '支付中',
|
||||
'payment_successful': '支付成功',
|
||||
'in_used': '使用中',
|
||||
'payment_failed': '支付失败',
|
||||
'order_cancelled': '已取消',
|
||||
'used_done': '已完成',
|
||||
'used_down': '已完成'
|
||||
'waiting_for_payment': this.$t('order.waitingForPayment'),
|
||||
'payment_in_progress': this.$t('order.paymentInProgress'),
|
||||
'payment_successful': this.$t('order.paymentSuccess'),
|
||||
'in_used': this.$t('order.inUse'),
|
||||
'payment_failed': this.$t('order.paymentFailed'),
|
||||
'order_cancelled': this.$t('order.cancelled'),
|
||||
'used_done': this.$t('order.finished'),
|
||||
'used_down': this.$t('order.finished')
|
||||
}
|
||||
|
||||
return statusMap[this.orderInfo.orderStatus] || '使用中'
|
||||
return statusMap[this.orderInfo.orderStatus] || this.$t('order.inUse')
|
||||
},
|
||||
|
||||
// 获取订单详情
|
||||
@@ -453,7 +458,7 @@
|
||||
// uni.showLoading({ title: '加载中' })
|
||||
|
||||
if (!this.orderInfo.orderId) {
|
||||
throw new Error('订单ID不能为空')
|
||||
throw new Error(this.$t('order.orderIdRequired'))
|
||||
}
|
||||
|
||||
const result = await queryById(this.orderInfo.orderId)
|
||||
@@ -527,7 +532,7 @@
|
||||
} catch (error) {
|
||||
console.error('获取订单详情错误:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '获取订单信息失败',
|
||||
title: error.message || this.$t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
|
||||
@@ -679,12 +684,12 @@
|
||||
if (this.currentStatusChecks >= this.maxStatusChecks) {
|
||||
this.clearStatusCheckTimer()
|
||||
|
||||
// 提示用户手动刷新
|
||||
uni.showToast({
|
||||
title: '请手动刷新查看归还状态',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
// 提示用户手动刷新
|
||||
uni.showToast({
|
||||
title: this.$t('order.pleaseRefreshManually'),
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.log('页面已不活跃,停止状态检查计时器')
|
||||
@@ -701,7 +706,7 @@
|
||||
// uni.showLoading({ title: '加载中' })
|
||||
|
||||
if (!this.deviceId) {
|
||||
throw new Error('设备号不能为空')
|
||||
throw new Error(this.$t('device.deviceNoRequired'))
|
||||
}
|
||||
|
||||
// 这里调用API查询该设备的使用中订单
|
||||
@@ -742,12 +747,12 @@
|
||||
// 获取详细订单信息
|
||||
this.getOrderDetails()
|
||||
} else {
|
||||
throw new Error('未找到使用中的订单')
|
||||
throw new Error(this.$t('order.noOrderInUse'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('通过设备号查询订单失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '获取订单信息失败',
|
||||
title: error.message || this.$t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
|
||||
@@ -795,13 +800,13 @@
|
||||
// 取消订单
|
||||
handleCancelOrder() {
|
||||
uni.showModal({
|
||||
title: '确认取消',
|
||||
content: '确定要取消此订单吗?',
|
||||
title: this.$t('order.confirmCancel'),
|
||||
content: this.$t('order.confirmCancelContent'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中'
|
||||
title: this.$t('common.processing')
|
||||
});
|
||||
const result = await cancelOrder({
|
||||
orderId: this.orderInfo.orderId
|
||||
@@ -809,17 +814,17 @@
|
||||
if (result.code === 200) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '订单已取消',
|
||||
title: this.$t('order.cancelSuccess'),
|
||||
icon: 'success'
|
||||
});
|
||||
await this.getOrderDetails();
|
||||
} else {
|
||||
throw new Error(result.msg || '取消订单失败');
|
||||
throw new Error(result.msg || this.$t('order.cancelFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: error.message || '取消订单失败',
|
||||
title: error.message || this.$t('order.cancelFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
|
||||
+28
-21
@@ -12,8 +12,8 @@
|
||||
<view class="list-wrap">
|
||||
<view class="panel">
|
||||
<view class="filter-tabs">
|
||||
<view class="tab" :class="{ active: activeTab === 'rent' }" @click="setTab('rent')">可租借</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'return' }" @click="setTab('return')">可归还</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'rent' }" @click="setTab('rent')">{{ $t('location.rent') }}</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'return' }" @click="setTab('return')">{{ $t('location.return') }}</view>
|
||||
</view>
|
||||
<scroll-view class="list-scroll" scroll-y="true">
|
||||
<view class="card" :class="{ available: isRentable(item), invalid: !isValidCoordinate(item.latitude, item.longitude) }"
|
||||
@@ -28,16 +28,16 @@
|
||||
<view class="row sub" v-if="item.location">
|
||||
<text class="addr">{{ item.location }}</text>
|
||||
</view>
|
||||
<view class="row meta" v-if="item.workTime && item.workTime !== '0'">
|
||||
<text class="time">营业时间:{{ item.workTime }}</text>
|
||||
</view>
|
||||
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
||||
<text class="time" style="color: #ff6b6b;">坐标信息异常</text>
|
||||
</view>
|
||||
<view class="tags">
|
||||
<view class="tag rent" v-if="isRentable(item)">可租借</view>
|
||||
<view class="tag return" v-if="isReturnable(item)">可归还</view>
|
||||
</view>
|
||||
<view class="row meta" v-if="item.workTime && item.workTime !== '0'">
|
||||
<text class="time">{{ $t('location.businessHours') }}{{ item.workTime }}</text>
|
||||
</view>
|
||||
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
||||
<text class="time" style="color: #ff6b6b;">{{ $t('location.coordinateError') }}</text>
|
||||
</view>
|
||||
<view class="tags">
|
||||
<view class="tag rent" v-if="isRentable(item)">{{ $t('location.rent') }}</view>
|
||||
<view class="tag return" v-if="isReturnable(item)">{{ $t('location.return') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="actions">
|
||||
|
||||
@@ -50,10 +50,10 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="empty-state" v-if="!isLoading && (!positionList || positionList.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 && (!positionList || positionList.length === 0)">
|
||||
<image class="empty-icon" src="/static/scan-icon.png" mode="aspectFit" />
|
||||
<text class="empty-text">{{ $t('home.noNearbyDevice') }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -75,6 +75,16 @@
|
||||
getRegeo,
|
||||
calculateDistanceSync
|
||||
} from '../../utils/mapUtils.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('search.title')
|
||||
})
|
||||
init()
|
||||
})
|
||||
|
||||
const userLocation = ref(null)
|
||||
const positionList = ref([])
|
||||
@@ -208,7 +218,7 @@
|
||||
const navigateToPosition = (position) => {
|
||||
if (!isValidCoordinate(position.latitude, position.longitude)) {
|
||||
uni.showToast({
|
||||
title: '该位置坐标无效',
|
||||
title: $t('search.invalidCoordinate'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -226,7 +236,7 @@
|
||||
const goToPositionDetail = (position) => {
|
||||
if (!position.positionId) {
|
||||
uni.showToast({
|
||||
title: '场地信息异常',
|
||||
title: $t('search.positionInfoError'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -236,9 +246,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -25,15 +25,21 @@
|
||||
},
|
||||
async onLoad(option) {
|
||||
console.log('bagCheck onLoad option:', option);
|
||||
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('device.checking')
|
||||
})
|
||||
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '处理中...',
|
||||
title: this.$t('common.processing'),
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 检查是否传入设备编号
|
||||
if (!option || !option.deviceNo) {
|
||||
throw new Error('未识别到设备编号');
|
||||
throw new Error(this.$t('device.deviceNoNotRecognized'));
|
||||
}
|
||||
|
||||
const deviceNo = option.deviceNo;
|
||||
@@ -97,10 +103,10 @@
|
||||
error.message.includes('未识别到设备编号') ||
|
||||
error.message.includes('网络请求失败') ||
|
||||
error.message.includes('服务器错误')
|
||||
)) {
|
||||
) ) {
|
||||
console.error('扫码检查订单失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '处理失败,请稍后重试',
|
||||
title: error.message || this.$t('device.processFailed'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
+110
-6
@@ -1,18 +1,27 @@
|
||||
<template>
|
||||
<view class="setting-page">
|
||||
<view class="group">
|
||||
<view class="item" @click="showLanguageSelector">
|
||||
<text class="label">{{ $t('settings.language') }}</text>
|
||||
<view class="right">
|
||||
<text class="value">{{ currentLanguageText }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="group">
|
||||
<view class="item" @click="navigateTo('/pages/legal/agreement')">
|
||||
<text class="label">用户协议</text>
|
||||
<text class="label">{{ $t('user.userAgreement') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="item" @click="navigateTo('/pages/legal/privacy')">
|
||||
<text class="label">隐私政策</text>
|
||||
<text class="label">{{ $t('user.privacyPolicy') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="group">
|
||||
<view class="item" @click="handleLogout">
|
||||
<text class="label">退出登录</text>
|
||||
<text class="label">{{ $t('user.logout') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
@@ -20,21 +29,105 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, getCurrentInstance } from 'vue'
|
||||
import { userLogout } from '@/config/api/user.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 获取全局 i18n 实例
|
||||
const instance = getCurrentInstance()
|
||||
const globalI18n = instance?.appContext?.config?.globalProperties?.$i18n
|
||||
|
||||
// 设置页面标题
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('settings.title')
|
||||
})
|
||||
})
|
||||
|
||||
// 当前语言
|
||||
const currentLanguage = ref(uni.getStorageSync('language') || 'zh-CN')
|
||||
|
||||
// 当前语言文本显示
|
||||
const currentLanguageText = computed(() => {
|
||||
return currentLanguage.value === 'zh-CN' ? '简体中文' : 'English'
|
||||
})
|
||||
|
||||
const navigateTo = (url) => {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
// 显示语言选择器
|
||||
const showLanguageSelector = () => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['简体中文', 'English'],
|
||||
success: (res) => {
|
||||
const lang = res.tapIndex === 0 ? 'zh-CN' : 'en-US'
|
||||
if (lang !== currentLanguage.value) {
|
||||
console.log('========================================')
|
||||
console.log('=== 用户选择切换语言 ===')
|
||||
console.log('旧语言:', currentLanguage.value)
|
||||
console.log('新语言:', lang)
|
||||
|
||||
// 1. 保存到缓存
|
||||
uni.setStorageSync('language', lang)
|
||||
console.log('✓ 语言已保存到缓存')
|
||||
|
||||
// 2. 立即更新 i18n 实例(重要!)
|
||||
if (globalI18n) {
|
||||
console.log('✓ 正在更新 globalI18n.locale...')
|
||||
console.log(' 更新前:', globalI18n.locale)
|
||||
globalI18n.locale = lang
|
||||
console.log(' 更新后:', globalI18n.locale)
|
||||
console.log('✓ 测试翻译:', globalI18n.t('common.loading'))
|
||||
} else {
|
||||
console.warn('✗ globalI18n 不存在!')
|
||||
console.warn(' instance:', !!instance)
|
||||
console.warn(' appContext:', !!instance?.appContext)
|
||||
console.warn(' globalProperties:', !!instance?.appContext?.config?.globalProperties)
|
||||
}
|
||||
|
||||
// 3. 更新当前语言状态
|
||||
currentLanguage.value = lang
|
||||
|
||||
console.log('========================================')
|
||||
|
||||
// 4. 提示用户
|
||||
uni.showToast({
|
||||
title: lang === 'zh-CN' ? '语言已切换,正在刷新...' : 'Language switched, refreshing...',
|
||||
icon: 'none',
|
||||
duration: 800
|
||||
})
|
||||
|
||||
// 5. 延迟后重新加载应用(确保 i18n 更新已生效)
|
||||
setTimeout(() => {
|
||||
console.log('=== 准备 reLaunch 到首页 ===')
|
||||
// 使用 reLaunch 完全重启应用
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
success: () => {
|
||||
console.log('✓ 页面已重新加载')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('✗ 页面重载失败:', err)
|
||||
}
|
||||
})
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
title: $t('common.tips'),
|
||||
content: $t('user.confirmLogout'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
const response = await userLogout();
|
||||
if (response.code == 200) {
|
||||
uni.showToast({ title: '退出成功', icon: 'none' })
|
||||
uni.showToast({ title: $t('user.logoutSuccess'), icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
@@ -77,4 +170,15 @@ const handleLogout = async () => {
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
</style>
|
||||
+27
-15
@@ -6,40 +6,40 @@
|
||||
<image :src="userInfo.avatar || '/static/images/default-avatar.png'" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="nickname">{{ userInfo.nickName || '未登录' }}</text>
|
||||
<text class="phone">{{ userInfo.phone || '未绑定手机号' }}</text>
|
||||
<text class="nickname">{{ userInfo.nickName || $t('user.notLoggedIn') }}</text>
|
||||
<text class="phone">{{ userInfo.phone || $t('user.phoneNotBound') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 余额卡片 -->
|
||||
<view class="balance-card">
|
||||
<view class="balance-title">余额</view>
|
||||
<view class="balance-title">{{ $t('userProfile.balance') }}</view>
|
||||
<view class="balance-amount">¥{{ userInfo.balanceAmount || '0.00' }}</view>
|
||||
<view class="balance-desc">可用于租借设备</view>
|
||||
<view class="balance-desc">{{ $t('user.balanceDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-list">
|
||||
<view class="menu-item" @click="navigateTo('/pages/order/list')">
|
||||
<view class="menu-item" @click="navigateTo('/pages/order/index')">
|
||||
<text class="menu-icon">📋</text>
|
||||
<text class="menu-text">我的订单</text>
|
||||
<text class="menu-text">{{ $t('user.myOrders') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/user/feedback')">
|
||||
<view class="menu-item" @click="navigateTo('/pages/feedback/index')">
|
||||
<text class="menu-icon">💬</text>
|
||||
<text class="menu-text">意见反馈</text>
|
||||
<text class="menu-text">{{ $t('user.feedback') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/user/about')">
|
||||
<view class="menu-item" @click="navigateTo('/pages/help/index')">
|
||||
<text class="menu-icon">ℹ️</text>
|
||||
<text class="menu-text">关于我们</text>
|
||||
<text class="menu-text">{{ $t('help.title') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-btn" @click="handleLogout" v-if="isLogin">
|
||||
<text>退出登录</text>
|
||||
<text>{{ $t('user.logout') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -55,6 +55,12 @@ export default {
|
||||
isLogin: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('user.personalCenter')
|
||||
})
|
||||
},
|
||||
onShow() {
|
||||
this.loadUserInfo()
|
||||
},
|
||||
@@ -90,16 +96,22 @@ export default {
|
||||
},
|
||||
handleLogout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
title: this.$t('common.tips'),
|
||||
content: this.$t('user.confirmLogout'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
this.isLogin = false
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
uni.showToast({
|
||||
title: this.$t('user.logoutSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
+26
-20
@@ -9,15 +9,15 @@
|
||||
<button class="avatar-choose-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"></button>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="avatar-tip">点击头像更换</view>
|
||||
</view>
|
||||
<view class="avatar-tip">{{ $t('userProfile.clickToChange') }}</view>
|
||||
</view>
|
||||
|
||||
<view class="form-section">
|
||||
<!-- 昵称编辑区域 -->
|
||||
<view class="form-item nickname-item" :class="{ editing: isEditingNickname }">
|
||||
<view class="label">昵称</view>
|
||||
<view class="label">{{ $t('userProfile.nickname') }}</view>
|
||||
<view class="value" v-if="!isEditingNickname" @click="startEditNickname">
|
||||
<text class="value-text">{{ userInfo.nickName || '未设置' }}</text>
|
||||
<text class="value-text">{{ userInfo.nickName || $t('userProfile.notSet') }}</text>
|
||||
<uv-icon name="edit-pen" size="16" color="#999999"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
@@ -27,25 +27,25 @@
|
||||
<input
|
||||
class="nickname-input"
|
||||
v-model="newNickname"
|
||||
placeholder="请输入新昵称"
|
||||
:placeholder="$t('userProfile.enterNickname')"
|
||||
maxlength="20"
|
||||
:focus="true"
|
||||
/>
|
||||
<view class="edit-buttons">
|
||||
<button class="cancel-btn" @click="cancelEditNickname">取消</button>
|
||||
<button class="save-btn" @click="saveNickname">保存</button>
|
||||
<button class="cancel-btn" @click="cancelEditNickname">{{ $t('common.cancel') }}</button>
|
||||
<button class="save-btn" @click="saveNickname">{{ $t('common.save') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">手机号</view>
|
||||
<view class="label">{{ $t('userProfile.phone') }}</view>
|
||||
<view class="value">
|
||||
<text class="value-text">{{ userInfo.phone ? maskPhone(userInfo.phone) : '未绑定' }}</text>
|
||||
<text class="value-text">{{ userInfo.phone ? maskPhone(userInfo.phone) : $t('userProfile.notBound') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item" v-if="userInfo.balanceAmount !== undefined">
|
||||
<view class="label">余额</view>
|
||||
<view class="label">{{ $t('userProfile.balance') }}</view>
|
||||
<view class="value">
|
||||
<text class="value-text amount">¥{{ userInfo.balanceAmount || '0.00' }}</text>
|
||||
</view>
|
||||
@@ -57,6 +57,9 @@
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { getMyIndexInfo, uploadUserAvatar, updateUserInfo } from '../../config/api/user.js';
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
// 响应式状态
|
||||
const userInfo = ref({
|
||||
@@ -71,6 +74,9 @@ const isEditingNickname = ref(false);
|
||||
|
||||
// 页面加载时初始化
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('userProfile.title')
|
||||
})
|
||||
loadUserInfo();
|
||||
});
|
||||
|
||||
@@ -96,7 +102,7 @@ const loadUserInfo = async () => {
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取用户信息失败',
|
||||
title: $t('user.getUserInfoFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
@@ -132,13 +138,13 @@ const onChooseAvatar = async (e) => {
|
||||
const avatarLocalPath = e?.detail?.avatarUrl;
|
||||
if (!avatarLocalPath) {
|
||||
uni.showToast({
|
||||
title: '未选择头像',
|
||||
title: $t('user.noAvatar'),
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.showLoading({
|
||||
title: '上传中...',
|
||||
title: $t('userProfile.uploading'),
|
||||
mask: true
|
||||
});
|
||||
const uploadRes = await uploadUserAvatar(avatarLocalPath);
|
||||
@@ -151,14 +157,14 @@ const onChooseAvatar = async (e) => {
|
||||
uni.setStorageSync('userInfo', userInfo.value);
|
||||
}
|
||||
uni.showToast({
|
||||
title: '头像更新成功',
|
||||
title: $t('user.avatarUpdated'),
|
||||
icon: 'success'
|
||||
});
|
||||
await loadUserInfo();
|
||||
} catch (err) {
|
||||
console.error('选择/上传头像失败:', err);
|
||||
uni.showToast({
|
||||
title: '头像更新失败',
|
||||
title: $t('user.avatarUploadFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
@@ -182,7 +188,7 @@ const cancelEditNickname = () => {
|
||||
const saveNickname = async () => {
|
||||
if (!newNickname.value || !newNickname.value.trim()) {
|
||||
uni.showToast({
|
||||
title: '昵称不能为空',
|
||||
title: $t('userProfile.nicknameRequired'),
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
@@ -190,7 +196,7 @@ const saveNickname = async () => {
|
||||
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '保存中...',
|
||||
title: $t('userProfile.saving'),
|
||||
mask: true
|
||||
});
|
||||
|
||||
@@ -222,19 +228,19 @@ const saveNickname = async () => {
|
||||
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '昵称修改成功',
|
||||
title: $t('userProfile.nicknameUpdated'),
|
||||
icon: 'success'
|
||||
});
|
||||
isEditingNickname.value = false;
|
||||
} else {
|
||||
throw new Error(res.message || '修改失败');
|
||||
throw new Error(res.message || $t('userProfile.updateFailed'));
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('修改昵称失败:', error);
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: error.message || '修改失败',
|
||||
title: error.message || $t('userProfile.updateFailed'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
|
||||
+11
-5
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="waiting-container">
|
||||
<view class="title">设备弹出中,请稍候</view>
|
||||
<view class="title">{{ $t('waiting.title') }}</view>
|
||||
<view class="progress-wrapper">
|
||||
<view class="progress-circle">
|
||||
<view class="progress-left">
|
||||
@@ -11,12 +11,12 @@
|
||||
</view>
|
||||
<view class="progress-inner">
|
||||
<text class="percent">{{ progress }}%</text>
|
||||
<text class="hint">正在为您弹出设备</text>
|
||||
<text class="hint">{{ $t('waiting.preparing') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="desc">若长时间未弹出,请联系现场工作人员或稍后重试</view>
|
||||
<view class="desc">{{ $t('waiting.longTimeNotice') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { onLoad, onUnload } from '@dcloudio/uni-app'
|
||||
import { getOrderByOrderNoScorePayStatus, cancelOrder } from '@/config/api/order.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
const progress = ref(0)
|
||||
const leftRotateDeg = ref(0)
|
||||
@@ -83,7 +86,7 @@
|
||||
await cancelOrder({ orderId: orderNo.value })
|
||||
}
|
||||
} catch (e) {}
|
||||
uni.showToast({ title: '设备租借失败,订单已取消', icon: 'none' })
|
||||
uni.showToast({ title: $t('waiting.rentFailed'), icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 800)
|
||||
@@ -111,7 +114,7 @@
|
||||
// 超时保护:例如 60 秒
|
||||
timeoutTimer = setTimeout(() => {
|
||||
stopAllTimers()
|
||||
uni.showToast({ title: '等待超时,请稍后重试', icon: 'none' })
|
||||
uni.showToast({ title: $t('waiting.timeout'), icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 800)
|
||||
@@ -119,6 +122,9 @@
|
||||
}
|
||||
|
||||
onLoad((query) => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: $t('waiting.title')
|
||||
})
|
||||
if (query && query.orderNo) {
|
||||
orderNo.value = query.orderNo
|
||||
}
|
||||
|
||||
Generated
+219
@@ -23,6 +23,9 @@ importers:
|
||||
uview-ui:
|
||||
specifier: 1.8.8
|
||||
version: 1.8.8
|
||||
vue-i18n:
|
||||
specifier: '9'
|
||||
version: 9.14.5(vue@3.5.22)
|
||||
devDependencies:
|
||||
sass:
|
||||
specifier: ^1.57.1
|
||||
@@ -33,9 +36,38 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
'@babel/helper-string-parser@7.27.1':
|
||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5':
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@climblee/uv-ui@1.1.20':
|
||||
resolution: {integrity: sha512-jkyesHJsPJkF4Nap9ZmG1/ibKlxXA5M8+ntqKXwwloIsYSYL5SOKb0gyPj17aBOU1PkJpmeiZ8PwnTolhK2/HA==}
|
||||
|
||||
'@intlify/core-base@9.14.5':
|
||||
resolution: {integrity: sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@9.14.5':
|
||||
resolution: {integrity: sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@9.14.5':
|
||||
resolution: {integrity: sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.8':
|
||||
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@@ -54,6 +86,9 @@ packages:
|
||||
'@jridgewell/sourcemap-codec@1.5.0':
|
||||
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
@@ -160,6 +195,38 @@ packages:
|
||||
'@types/node@24.0.4':
|
||||
resolution: {integrity: sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==}
|
||||
|
||||
'@vue/compiler-core@3.5.22':
|
||||
resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==}
|
||||
|
||||
'@vue/compiler-dom@3.5.22':
|
||||
resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.22':
|
||||
resolution: {integrity: sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.22':
|
||||
resolution: {integrity: sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==}
|
||||
|
||||
'@vue/devtools-api@6.6.4':
|
||||
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||
|
||||
'@vue/reactivity@3.5.22':
|
||||
resolution: {integrity: sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==}
|
||||
|
||||
'@vue/runtime-core@3.5.22':
|
||||
resolution: {integrity: sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==}
|
||||
|
||||
'@vue/runtime-dom@3.5.22':
|
||||
resolution: {integrity: sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==}
|
||||
|
||||
'@vue/server-renderer@3.5.22':
|
||||
resolution: {integrity: sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==}
|
||||
peerDependencies:
|
||||
vue: 3.5.22
|
||||
|
||||
'@vue/shared@3.5.22':
|
||||
resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==}
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
|
||||
|
||||
@@ -279,6 +346,9 @@ packages:
|
||||
commander@2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
|
||||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
debug@3.1.0:
|
||||
resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
|
||||
peerDependencies:
|
||||
@@ -307,6 +377,10 @@ packages:
|
||||
resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
es-define-property@1.0.1:
|
||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -346,6 +420,9 @@ packages:
|
||||
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
events@3.3.0:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
@@ -443,6 +520,9 @@ packages:
|
||||
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
|
||||
engines: {node: '>=6.11.5'}
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
math-intrinsics@1.1.0:
|
||||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -465,6 +545,11 @@ packages:
|
||||
ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
neo-async@2.6.2:
|
||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||
|
||||
@@ -481,6 +566,10 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
@@ -590,6 +679,20 @@ packages:
|
||||
uview-ui@1.8.8:
|
||||
resolution: {integrity: sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==}
|
||||
|
||||
vue-i18n@9.14.5:
|
||||
resolution: {integrity: sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
vue@3.5.22:
|
||||
resolution: {integrity: sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
watchpack@2.4.4:
|
||||
resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -610,8 +713,33 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@babel/helper-string-parser@7.27.1': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@climblee/uv-ui@1.1.20': {}
|
||||
|
||||
'@intlify/core-base@9.14.5':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 9.14.5
|
||||
'@intlify/shared': 9.14.5
|
||||
|
||||
'@intlify/message-compiler@9.14.5':
|
||||
dependencies:
|
||||
'@intlify/shared': 9.14.5
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@9.14.5': {}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.8':
|
||||
dependencies:
|
||||
'@jridgewell/set-array': 1.2.1
|
||||
@@ -629,6 +757,8 @@ snapshots:
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.0': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
@@ -713,6 +843,62 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 7.8.0
|
||||
|
||||
'@vue/compiler-core@3.5.22':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/shared': 3.5.22
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-dom@3.5.22':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
'@vue/compiler-sfc@3.5.22':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/compiler-core': 3.5.22
|
||||
'@vue/compiler-dom': 3.5.22
|
||||
'@vue/compiler-ssr': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.21
|
||||
postcss: 8.5.6
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-ssr@3.5.22':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
'@vue/devtools-api@6.6.4': {}
|
||||
|
||||
'@vue/reactivity@3.5.22':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
'@vue/runtime-core@3.5.22':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
'@vue/runtime-dom@3.5.22':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.22
|
||||
'@vue/runtime-core': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
csstype: 3.1.3
|
||||
|
||||
'@vue/server-renderer@3.5.22(vue@3.5.22)':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
vue: 3.5.22
|
||||
|
||||
'@vue/shared@3.5.22': {}
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
dependencies:
|
||||
'@webassemblyjs/helper-numbers': 1.13.2
|
||||
@@ -866,6 +1052,8 @@ snapshots:
|
||||
|
||||
commander@2.20.3: {}
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
debug@3.1.0:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
@@ -888,6 +1076,8 @@ snapshots:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.2
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
es-define-property@1.0.1: {}
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
@@ -920,6 +1110,8 @@ snapshots:
|
||||
|
||||
estraverse@5.3.0: {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
@@ -1010,6 +1202,10 @@ snapshots:
|
||||
|
||||
loader-runner@4.3.0: {}
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
math-intrinsics@1.1.0: {}
|
||||
|
||||
merge-stream@2.0.0: {}
|
||||
@@ -1028,6 +1224,8 @@ snapshots:
|
||||
|
||||
ms@2.0.0: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
neo-async@2.6.2: {}
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
@@ -1040,6 +1238,12 @@ snapshots:
|
||||
picomatch@2.3.1:
|
||||
optional: true
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
@@ -1128,6 +1332,21 @@ snapshots:
|
||||
|
||||
uview-ui@1.8.8: {}
|
||||
|
||||
vue-i18n@9.14.5(vue@3.5.22):
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.14.5
|
||||
'@intlify/shared': 9.14.5
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.22
|
||||
|
||||
vue@3.5.22:
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.22
|
||||
'@vue/compiler-sfc': 3.5.22
|
||||
'@vue/runtime-dom': 3.5.22
|
||||
'@vue/server-renderer': 3.5.22(vue@3.5.22)
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
watchpack@2.4.4:
|
||||
dependencies:
|
||||
glob-to-regexp: 0.4.1
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// i18n工具函数 - 用于在 Vue 3 setup 中安全获取 $t
|
||||
import { getCurrentInstance } from 'vue'
|
||||
|
||||
/**
|
||||
* 在 setup 中使用 i18n
|
||||
* @returns {{ t: Function, locale: string, i18n: object }}
|
||||
*/
|
||||
export function useI18n() {
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
if (!instance || !instance.proxy) {
|
||||
return {
|
||||
t: (key) => key,
|
||||
locale: 'zh-CN',
|
||||
i18n: null
|
||||
}
|
||||
}
|
||||
|
||||
const proxy = instance.proxy
|
||||
|
||||
// 返回一个函数,每次调用时动态获取 $t(确保 $t 已经注入)
|
||||
return {
|
||||
t: (key, ...args) => {
|
||||
if (proxy.$t && typeof proxy.$t === 'function') {
|
||||
return proxy.$t(key, ...args)
|
||||
}
|
||||
return key
|
||||
},
|
||||
locale: proxy.$i18n?.locale || 'zh-CN',
|
||||
i18n: proxy.$i18n
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user