fix:修复bug
This commit is contained in:
@@ -40,7 +40,7 @@
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: { type: Boolean, default: false },
|
show: { type: Boolean, default: false },
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="map-container" :class="{ 'full-width': props.fullWidth }" :style="{ '--map-height': props.customHeight || '78vh' }">
|
<view class="map-container" :class="{ 'full-width': props.fullWidth }" :style="{ '--map-height': props.customHeight || '72vh' }">
|
||||||
<!-- 地图容器 -->
|
<!-- 地图容器 -->
|
||||||
<view class="map-wrapper">
|
<view class="map-wrapper">
|
||||||
<!-- 使用小程序原生地图组件 -->
|
<!-- 使用小程序原生地图组件 -->
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
import { useI18n } from '../utils/i18n.js'
|
import { useI18n } from '../utils/i18n.js'
|
||||||
|
|
||||||
// 获取 i18n 实例
|
// 获取 i18n 实例
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 引用折叠面板组件的ref
|
// 引用折叠面板组件的ref
|
||||||
const collapseRef = ref(null)
|
const collapseRef = ref(null)
|
||||||
@@ -272,13 +272,19 @@
|
|||||||
const onMapRegionChange = (e) => {
|
const onMapRegionChange = (e) => {
|
||||||
|
|
||||||
// 只处理结束事件
|
// 只处理结束事件
|
||||||
if (!e || e.type !== 'end') {
|
if (!e || (e.type !== 'end' && e.type !== 'regionchange')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const causedBy = e.causedBy || e.detail?.causedBy
|
const causedBy = e.causedBy || e.detail?.causedBy
|
||||||
|
|
||||||
if (causedBy === 'gesture' || causedBy === 'scale' || causedBy === 'drag'||causedBy==='update') {
|
// H5 环境下可能没有 causedBy,只要是 end 事件就处理
|
||||||
|
const isH5 = false;
|
||||||
|
// #ifdef H5
|
||||||
|
const h5Status = true;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if (causedBy === 'gesture' || causedBy === 'scale' || causedBy === 'drag' || causedBy === 'update' || (typeof h5Status !== 'undefined' && e.type === 'end')) {
|
||||||
// 清除之前的定时器
|
// 清除之前的定时器
|
||||||
if (regionChangeTimer) {
|
if (regionChangeTimer) {
|
||||||
clearTimeout(regionChangeTimer)
|
clearTimeout(regionChangeTimer)
|
||||||
@@ -481,22 +487,26 @@ const handleSearch = () => {
|
|||||||
/* 地图容器 */
|
/* 地图容器 */
|
||||||
.map-container {
|
.map-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
// position: fixed;
|
// position: fixed;
|
||||||
// top: 0;
|
// top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 94vw;
|
width: 94vw;
|
||||||
height: calc(100% - 20rpx); /* 减少高度,避免覆盖底部按钮 */
|
height: var(--map-height, calc(100% - 20rpx)); /* 使用变量或默认高度 */
|
||||||
margin: 20rpx;
|
margin: 20rpx;
|
||||||
margin-bottom: 0; /* 底部不需要边距 */
|
margin-bottom: 0; /* 底部不需要边距 */
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
&.full-width {
|
&.full-width {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-wrapper {
|
.map-wrapper {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
order: { type: Object, required: true },
|
order: { type: Object, required: true },
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
const isFinished = computed(() => normalizedStatus.value === 'used_done');
|
const isFinished = computed(() => normalizedStatus.value === 'used_done');
|
||||||
const isCancelled = computed(() => normalizedStatus.value === 'order_cancelled');
|
const isCancelled = computed(() => normalizedStatus.value === 'order_cancelled');
|
||||||
|
|
||||||
const titleText = computed(() => $t('order.rentFan'));
|
const titleText = computed(() => t('order.rentFan'));
|
||||||
|
|
||||||
// 显示金额(优先后端给定字段)
|
// 显示金额(优先后端给定字段)
|
||||||
const displayAmount = computed(() => props.order.amount || props.order.payAmount || props.order.actualDeviceAmount || props.order.currentFee || '0.00');
|
const displayAmount = computed(() => props.order.amount || props.order.payAmount || props.order.actualDeviceAmount || props.order.currentFee || '0.00');
|
||||||
@@ -158,8 +158,8 @@
|
|||||||
const minutes = Math.floor(diffMs / 60000);
|
const minutes = Math.floor(diffMs / 60000);
|
||||||
const hours = Math.floor(minutes / 60);
|
const hours = Math.floor(minutes / 60);
|
||||||
const mins = minutes % 60;
|
const mins = minutes % 60;
|
||||||
if (hours > 0) return `${hours}${$t('time.hour')}${mins}${$t('time.minute')}`;
|
if (hours > 0) return `${hours}${t('time.hour')}${mins}${t('time.minute')}`;
|
||||||
return `${mins}${$t('time.minute')}`;
|
return `${mins}${t('time.minute')}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
function parseDate(str) {
|
function parseDate(str) {
|
||||||
|
|||||||
@@ -79,3 +79,15 @@ export const forcefOpenEmptyGrid = (deviceNo) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送租借指令
|
||||||
|
export const sendRentCommand = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/app/device/sendRentCommand',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,38 @@ export const closeWithMaxFee = (orderNo) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建微信支付订单
|
||||||
|
export const createWxPayment = (orderNo) => {
|
||||||
|
return request({
|
||||||
|
url: `/app/wx-payment/create/${orderNo}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取正在使用中的订单
|
||||||
|
export const getInUseOrder = () => {
|
||||||
|
return request({
|
||||||
|
url: '/app/order/inUse',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取待支付订单
|
||||||
|
export const getUnpaidOrder = () => {
|
||||||
|
return request({
|
||||||
|
url: '/app/order/unpaid',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询微信支付状态
|
||||||
|
export const getWxPaymentStatus = (orderNo) => {
|
||||||
|
return request({
|
||||||
|
url: `/app/wx-payment/status/${orderNo}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 通过订单号获取支付分订单信息
|
// 通过订单号获取支付分订单信息
|
||||||
export const getOrderByOrderNoScore = (orderNo) => {
|
export const getOrderByOrderNoScore = (orderNo) => {
|
||||||
console.log('通过订单号获取支付分订单信息', orderNo);
|
console.log('通过订单号获取支付分订单信息', orderNo);
|
||||||
|
|||||||
+30
-4
@@ -27,12 +27,38 @@ export const getCommonByBrand = (brandName) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询激活的且临近关闭时间最近的活动
|
// 获取当前协议内容
|
||||||
export const getActiveActivity = () => {
|
export const getCurrentAgreement = (data) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/device/activity/agent/list',
|
url: '/device/agreementConfig/current',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
hideLoading: true
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前广告内容
|
||||||
|
export const getCurrentAdvertisement = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/device/advertisementConfig/current',
|
||||||
|
method: 'get',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前公告内容
|
||||||
|
export const getCurrentAnnouncement = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/device/announcementConfig/current',
|
||||||
|
method: 'get',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getActiveActivity = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/device/activeActivity/current',
|
||||||
|
method: 'get',
|
||||||
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
-2
@@ -10,6 +10,24 @@ export const login = (data) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
export const sendVerifyCode = (phonenumber) => {
|
||||||
|
return request({
|
||||||
|
url: '/app/user/sms/code',
|
||||||
|
method: 'get',
|
||||||
|
data: { phonenumber }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手机号+验证码登录
|
||||||
|
export const loginWithCode = (phonenumber, smsCode) => {
|
||||||
|
return request({
|
||||||
|
url: '/app/user/sms/login',
|
||||||
|
method: 'post',
|
||||||
|
data: { phonenumber, smsCode }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 用户退出登录
|
// 用户退出登录
|
||||||
export const userLogout = (data) => {
|
export const userLogout = (data) => {
|
||||||
return request({
|
return request({
|
||||||
@@ -56,7 +74,8 @@ export const uploadUserAvatar = (filePath) => {
|
|||||||
header: {
|
header: {
|
||||||
'appid': appid,
|
'appid': appid,
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
'Clientid': uni.getStorageSync('client_id'),
|
||||||
|
'Content-Language': (uni.getStorageSync('language') || 'zh-CN').replace(/-/g, '_')
|
||||||
},
|
},
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
try {
|
try {
|
||||||
@@ -83,7 +102,8 @@ export const uploadOssResource = (filePath) => {
|
|||||||
header: {
|
header: {
|
||||||
'appid': appid,
|
'appid': appid,
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
'Clientid': uni.getStorageSync('client_id'),
|
||||||
|
'Content-Language': (uni.getStorageSync('language') || 'zh-CN').replace(/-/g, '_')
|
||||||
},
|
},
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
try {
|
try {
|
||||||
@@ -115,3 +135,12 @@ export const withdrawDeposit = (orderNo) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取微信用户手机号
|
||||||
|
export const getWxUserPhoneNumber = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/app/user/getPhoneNumber',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -33,7 +33,8 @@ const request = (option) => {
|
|||||||
...option.headers,
|
...option.headers,
|
||||||
'appid': appid,
|
'appid': appid,
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
'Clientid': uni.getStorageSync('client_id'),
|
||||||
|
'Content-Language': (uni.getStorageSync('language') || 'zh-CN').replace(/-/g, '_')
|
||||||
},
|
},
|
||||||
success(res) {
|
success(res) {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
||||||
// export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
// export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
||||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||||
// export const URL = "http://192.168.5.52:8080" //本地调试
|
// export const URL = "http://192.168.5.123:8080" //本地调试
|
||||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||||
|
|
||||||
export const appid = "wx2165f0be356ae7a9" //微信小程序appid
|
export const appid = "wx2165f0be356ae7a9" //微信小程序appid
|
||||||
|
|||||||
+55
-7
@@ -49,6 +49,8 @@ export default {
|
|||||||
loginRequired: 'Please login first',
|
loginRequired: 'Please login first',
|
||||||
operationSuccess: 'Operation successful',
|
operationSuccess: 'Operation successful',
|
||||||
operationFailed: 'Operation failed',
|
operationFailed: 'Operation failed',
|
||||||
|
sending: 'Sending...',
|
||||||
|
loggingIn: 'Logging in...',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
pull: 'Pull to refresh',
|
pull: 'Pull to refresh',
|
||||||
release: 'Release to refresh',
|
release: 'Release to refresh',
|
||||||
@@ -114,7 +116,8 @@ export default {
|
|||||||
businessHours: 'Business Hours: ',
|
businessHours: 'Business Hours: ',
|
||||||
navigateHere: 'Navigate Here',
|
navigateHere: 'Navigate Here',
|
||||||
coordinateError: 'Invalid location coordinates',
|
coordinateError: 'Invalid location coordinates',
|
||||||
notExist: 'Location does not exist'
|
notExist: 'Location does not exist',
|
||||||
|
supportCouponOrMember: 'Coupons & Cards Available'
|
||||||
},
|
},
|
||||||
|
|
||||||
device: {
|
device: {
|
||||||
@@ -172,6 +175,8 @@ export default {
|
|||||||
deposit: 'Deposit',
|
deposit: 'Deposit',
|
||||||
rentFee: 'Rent Fee',
|
rentFee: 'Rent Fee',
|
||||||
payNow: 'Pay Now',
|
payNow: 'Pay Now',
|
||||||
|
myCoupons:'Coupons',
|
||||||
|
myCards:'Member Cards',
|
||||||
cancelOrder: 'Cancel Order',
|
cancelOrder: 'Cancel Order',
|
||||||
quickReturn: 'Quick Return',
|
quickReturn: 'Quick Return',
|
||||||
returnDevice: 'Return Device',
|
returnDevice: 'Return Device',
|
||||||
@@ -246,6 +251,8 @@ export default {
|
|||||||
perHalfHour: 'per half hour',
|
perHalfHour: 'per half hour',
|
||||||
deviceNoEject: 'Not Ejected',
|
deviceNoEject: 'Not Ejected',
|
||||||
returnReminder: 'Return Reminder',
|
returnReminder: 'Return Reminder',
|
||||||
|
canUsePromotion: 'Coupons & Cards Available',
|
||||||
|
usedPromotion: 'Promotion Applied',
|
||||||
convertToOwn: 'Don\'t want to return? Convert to own',
|
convertToOwn: 'Don\'t want to return? Convert to own',
|
||||||
convertToOwnTitle: 'Convert to Own',
|
convertToOwnTitle: 'Convert to Own',
|
||||||
convertToOwnConfirm: 'Only ¥99 to convert to own. The power bank will be yours. Confirm?',
|
convertToOwnConfirm: 'Only ¥99 to convert to own. The power bank will be yours. Confirm?',
|
||||||
@@ -261,7 +268,9 @@ export default {
|
|||||||
deviceNoEjectTitle: 'Device Not Ejected',
|
deviceNoEjectTitle: 'Device Not Ejected',
|
||||||
deviceNoEjectConfirm: 'Your power bank didn\'t eject? We will handle it immediately, expected to resolve within 5 minutes.',
|
deviceNoEjectConfirm: 'Your power bank didn\'t eject? We will handle it immediately, expected to resolve within 5 minutes.',
|
||||||
deviceNoEjectSuccess: 'Feedback received, will be handled within 5 minutes',
|
deviceNoEjectSuccess: 'Feedback received, will be handled within 5 minutes',
|
||||||
deviceNoEjectFailed: 'Feedback submission failed, please try again'
|
deviceNoEjectFailed: 'Feedback submission failed, please try again',
|
||||||
|
returnProblemTip: 'After returning, if the order is still active, please go to ',
|
||||||
|
contactStaff: ' to contact staff.'
|
||||||
},
|
},
|
||||||
|
|
||||||
user: {
|
user: {
|
||||||
@@ -327,7 +336,22 @@ export default {
|
|||||||
phoneSuccess: 'Success',
|
phoneSuccess: 'Success',
|
||||||
phoneError: 'Error',
|
phoneError: 'Error',
|
||||||
phoneGetFailed: 'Failed',
|
phoneGetFailed: 'Failed',
|
||||||
authCodeFailed: 'Auth failed'
|
authCodeFailed: 'Auth failed',
|
||||||
|
phoneLogin: 'Phone Login',
|
||||||
|
phonePlaceholder: 'Enter phone number',
|
||||||
|
codePlaceholder: 'Enter verification code',
|
||||||
|
getCode: 'Get Code',
|
||||||
|
resend: 'Resend',
|
||||||
|
loginBtn: 'Login',
|
||||||
|
phoneRequired: 'Phone required',
|
||||||
|
phoneInvalid: 'Invalid phone number',
|
||||||
|
codeRequired: 'Verification code required',
|
||||||
|
codeSent: 'Code sent',
|
||||||
|
sendCodeFailed: 'Send code failed',
|
||||||
|
regionNotSupported: 'Non-mainland China, Hong Kong, Macau users please login via platform phone authorization',
|
||||||
|
onlyMainlandSupported: 'Currently only Mainland China is supported',
|
||||||
|
getServicePhoneFailed: 'Failed to get service phone',
|
||||||
|
noAuthToken: 'Login successful but no credentials obtained'
|
||||||
},
|
},
|
||||||
|
|
||||||
permission: {
|
permission: {
|
||||||
@@ -361,7 +385,9 @@ export default {
|
|||||||
package: 'Package',
|
package: 'Package',
|
||||||
total: 'Total',
|
total: 'Total',
|
||||||
paymentFailedRetry: 'Payment failed, retry?',
|
paymentFailedRetry: 'Payment failed, retry?',
|
||||||
createPayOrderFailed: 'Failed'
|
createPayOrderFailed: 'Failed',
|
||||||
|
subscriptionSuccess: 'Subscription successful',
|
||||||
|
subscriptionFailed: 'Subscription failed, please try again'
|
||||||
},
|
},
|
||||||
|
|
||||||
feedback: {
|
feedback: {
|
||||||
@@ -421,6 +447,7 @@ export default {
|
|||||||
phone: 'Phone',
|
phone: 'Phone',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
workingHours: 'Working Hours',
|
workingHours: 'Working Hours',
|
||||||
|
workingHoursValue: 'Mon-Sun 09:00-22:00',
|
||||||
functionDeveloping: 'Feature in development',
|
functionDeveloping: 'Feature in development',
|
||||||
faq1Question: 'How to rent a fan?',
|
faq1Question: 'How to rent a fan?',
|
||||||
faq1Answer: 'Click "Scan to Rent" on the homepage, scan the QR code on the device with WeChat, and complete payment as prompted.',
|
faq1Answer: 'Click "Scan to Rent" on the homepage, scan the QR code on the device with WeChat, and complete payment as prompted.',
|
||||||
@@ -440,6 +467,7 @@ export default {
|
|||||||
languageSetting: 'Language Setting',
|
languageSetting: 'Language Setting',
|
||||||
chinese: '简体中文',
|
chinese: '简体中文',
|
||||||
english: 'English',
|
english: 'English',
|
||||||
|
languageSwitched: 'Language switched, refreshing...',
|
||||||
notification: 'Notification',
|
notification: 'Notification',
|
||||||
privacy: 'Privacy',
|
privacy: 'Privacy',
|
||||||
about: 'About',
|
about: 'About',
|
||||||
@@ -664,6 +692,8 @@ export default {
|
|||||||
withdrawNotice2: 'Withdrawal expected to arrive within 0-7 business days',
|
withdrawNotice2: 'Withdrawal expected to arrive within 0-7 business days',
|
||||||
withdrawNotice3: 'If delayed, please contact customer service',
|
withdrawNotice3: 'If delayed, please contact customer service',
|
||||||
depositRecord: 'Deposit Record',
|
depositRecord: 'Deposit Record',
|
||||||
|
payRecord: 'Payment Record',
|
||||||
|
refundRecord: 'Refund Record',
|
||||||
orderNotReturned: 'Current order not returned, please return before withdraw',
|
orderNotReturned: 'Current order not returned, please return before withdraw',
|
||||||
alreadyRefunded: 'Deposit already refunded',
|
alreadyRefunded: 'Deposit already refunded',
|
||||||
refundProcessing: 'Refund processing, please wait'
|
refundProcessing: 'Refund processing, please wait'
|
||||||
@@ -719,7 +749,7 @@ export default {
|
|||||||
type: 'Type',
|
type: 'Type',
|
||||||
timesCard: 'Times Card',
|
timesCard: 'Times Card',
|
||||||
durationCard: 'Duration Card',
|
durationCard: 'Duration Card',
|
||||||
remainingTimes: 'Remaining Times',
|
remainingTimes: 'Remaining: ',
|
||||||
remainingDuration: 'Remaining Duration',
|
remainingDuration: 'Remaining Duration',
|
||||||
hours: 'Hours',
|
hours: 'Hours',
|
||||||
validPeriod: 'Valid Period',
|
validPeriod: 'Valid Period',
|
||||||
@@ -730,7 +760,23 @@ export default {
|
|||||||
price: 'Purchase Price',
|
price: 'Purchase Price',
|
||||||
noCards: 'No cards',
|
noCards: 'No cards',
|
||||||
buyNow: 'Buy Now',
|
buyNow: 'Buy Now',
|
||||||
getListFailed: 'Failed to get card list'
|
getListFailed: 'Failed to get card list',
|
||||||
|
dailyLimit: 'Daily Limit',
|
||||||
|
singleTimeLimit: 'Single Use Limit',
|
||||||
|
unlimited: 'Unlimited',
|
||||||
|
times: 'Times',
|
||||||
|
minutes: 'Minutes',
|
||||||
|
validWithinDays: 'days valid',
|
||||||
|
validFromPurchase: 'Valid from purchase',
|
||||||
|
daysValid: 'days',
|
||||||
|
currentCycleUsed: 'Current Cycle Used',
|
||||||
|
totalCount: 'Total Count',
|
||||||
|
expire: 'Expire',
|
||||||
|
expiredOn: 'Expired on ',
|
||||||
|
renew: 'Renew',
|
||||||
|
toUse: 'Use Now',
|
||||||
|
onlyForRegionBefore: 'Only for ',
|
||||||
|
onlyForRegionAfter: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
myCoupon: {
|
myCoupon: {
|
||||||
@@ -744,7 +790,9 @@ export default {
|
|||||||
noUsedCoupons: 'No used coupons',
|
noUsedCoupons: 'No used coupons',
|
||||||
noExpiredCoupons: 'No expired coupons',
|
noExpiredCoupons: 'No expired coupons',
|
||||||
buyNow: 'Buy Now',
|
buyNow: 'Buy Now',
|
||||||
getListFailed: 'Failed to get coupon list'
|
getListFailed: 'Failed to get coupon list',
|
||||||
|
onlyForRegionBefore: 'Only for ',
|
||||||
|
onlyForRegionAfter: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
-9
@@ -49,6 +49,8 @@ export default {
|
|||||||
loginRequired: '请先登录',
|
loginRequired: '请先登录',
|
||||||
operationSuccess: '操作成功',
|
operationSuccess: '操作成功',
|
||||||
operationFailed: '操作失败',
|
operationFailed: '操作失败',
|
||||||
|
sending: '发送中...',
|
||||||
|
loggingIn: '登录中...',
|
||||||
refresh: '刷新',
|
refresh: '刷新',
|
||||||
pull: '下拉刷新',
|
pull: '下拉刷新',
|
||||||
release: '释放刷新',
|
release: '释放刷新',
|
||||||
@@ -114,7 +116,8 @@ export default {
|
|||||||
businessHours: '营业时间:',
|
businessHours: '营业时间:',
|
||||||
navigateHere: '导航去这',
|
navigateHere: '导航去这',
|
||||||
coordinateError: '该场地坐标信息异常',
|
coordinateError: '该场地坐标信息异常',
|
||||||
notExist: '场地不存在'
|
notExist: '场地不存在',
|
||||||
|
supportCouponOrMember: '可使用优惠券、会员卡'
|
||||||
},
|
},
|
||||||
|
|
||||||
device: {
|
device: {
|
||||||
@@ -171,6 +174,8 @@ export default {
|
|||||||
payAmount: '支付金额',
|
payAmount: '支付金额',
|
||||||
deposit: '押金',
|
deposit: '押金',
|
||||||
rentFee: '租金',
|
rentFee: '租金',
|
||||||
|
myCards:'会员卡优惠',
|
||||||
|
myCoupons:'优惠券优惠',
|
||||||
payNow: '立即支付',
|
payNow: '立即支付',
|
||||||
cancelOrder: '取消订单',
|
cancelOrder: '取消订单',
|
||||||
quickReturn: '快速归还',
|
quickReturn: '快速归还',
|
||||||
@@ -246,6 +251,8 @@ export default {
|
|||||||
perHalfHour: '每半小时',
|
perHalfHour: '每半小时',
|
||||||
deviceNoEject: '宝未弹出',
|
deviceNoEject: '宝未弹出',
|
||||||
returnReminder: '归还提醒',
|
returnReminder: '归还提醒',
|
||||||
|
canUsePromotion: '可使用优惠券、会员卡',
|
||||||
|
usedPromotion: '已享受优惠',
|
||||||
convertToOwn: '不想还了?点击转为自用',
|
convertToOwn: '不想还了?点击转为自用',
|
||||||
convertToOwnTitle: '转为自用',
|
convertToOwnTitle: '转为自用',
|
||||||
convertToOwnConfirm: '仅需花费99元,即可转为自用,充电宝将归您所有,确认操作吗?',
|
convertToOwnConfirm: '仅需花费99元,即可转为自用,充电宝将归您所有,确认操作吗?',
|
||||||
@@ -261,7 +268,9 @@ export default {
|
|||||||
deviceNoEjectTitle: '充电宝未弹出',
|
deviceNoEjectTitle: '充电宝未弹出',
|
||||||
deviceNoEjectConfirm: '您的充电宝未弹出吗?我们将立即为您处理,预计5分钟内解决问题。',
|
deviceNoEjectConfirm: '您的充电宝未弹出吗?我们将立即为您处理,预计5分钟内解决问题。',
|
||||||
deviceNoEjectSuccess: '反馈已受理,将在5分钟内处理',
|
deviceNoEjectSuccess: '反馈已受理,将在5分钟内处理',
|
||||||
deviceNoEjectFailed: '反馈提交失败,请稍后重试'
|
deviceNoEjectFailed: '反馈提交失败,请稍后重试',
|
||||||
|
returnProblemTip: '产品归还入仓后,订单仍未结束,请前往',
|
||||||
|
contactStaff: '联系工作人员。'
|
||||||
},
|
},
|
||||||
|
|
||||||
user: {
|
user: {
|
||||||
@@ -327,7 +336,22 @@ export default {
|
|||||||
phoneSuccess: '手机号获取成功',
|
phoneSuccess: '手机号获取成功',
|
||||||
phoneError: '获取手机号异常',
|
phoneError: '获取手机号异常',
|
||||||
phoneGetFailed: '获取手机号失败',
|
phoneGetFailed: '获取手机号失败',
|
||||||
authCodeFailed: '获取授权码失败'
|
authCodeFailed: '获取授权码失败',
|
||||||
|
phoneLogin: '手机号登录',
|
||||||
|
phonePlaceholder: '请输入手机号码',
|
||||||
|
codePlaceholder: '请输入验证码',
|
||||||
|
getCode: '获取验证码',
|
||||||
|
resend: '重新发送',
|
||||||
|
loginBtn: '立即登录',
|
||||||
|
phoneRequired: '请输入手机号',
|
||||||
|
phoneInvalid: '请输入正确的手机号',
|
||||||
|
codeRequired: '请输入验证码',
|
||||||
|
codeSent: '验证码已发送',
|
||||||
|
sendCodeFailed: '发送验证码失败',
|
||||||
|
regionNotSupported: '非大陆、香港、澳门用户请通过平台手机号授权登录',
|
||||||
|
onlyMainlandSupported: '当前仅支持中国大陆地区',
|
||||||
|
getServicePhoneFailed: '获取客服电话失败',
|
||||||
|
noAuthToken: '登录成功但未获取到授权凭证'
|
||||||
},
|
},
|
||||||
|
|
||||||
permission: {
|
permission: {
|
||||||
@@ -361,7 +385,9 @@ export default {
|
|||||||
package: '套餐',
|
package: '套餐',
|
||||||
total: '合计',
|
total: '合计',
|
||||||
paymentFailedRetry: '支付失败,请重试',
|
paymentFailedRetry: '支付失败,请重试',
|
||||||
createPayOrderFailed: '创建支付订单失败'
|
createPayOrderFailed: '创建支付订单失败',
|
||||||
|
subscriptionSuccess: '订阅成功',
|
||||||
|
subscriptionFailed: '订阅失败,请稍后重试'
|
||||||
},
|
},
|
||||||
|
|
||||||
feedback: {
|
feedback: {
|
||||||
@@ -421,6 +447,7 @@ export default {
|
|||||||
phone: '电话',
|
phone: '电话',
|
||||||
email: '邮箱',
|
email: '邮箱',
|
||||||
workingHours: '工作时间',
|
workingHours: '工作时间',
|
||||||
|
workingHoursValue: '周一至周日 09:00-22:00',
|
||||||
functionDeveloping: '功能开发中',
|
functionDeveloping: '功能开发中',
|
||||||
faq1Question: '如何租借风扇?',
|
faq1Question: '如何租借风扇?',
|
||||||
faq1Answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。',
|
faq1Answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。',
|
||||||
@@ -440,6 +467,7 @@ export default {
|
|||||||
languageSetting: '语言设置',
|
languageSetting: '语言设置',
|
||||||
chinese: '简体中文',
|
chinese: '简体中文',
|
||||||
english: 'English',
|
english: 'English',
|
||||||
|
languageSwitched: '语言已切换,正在刷新...',
|
||||||
notification: '通知',
|
notification: '通知',
|
||||||
privacy: '隐私',
|
privacy: '隐私',
|
||||||
about: '关于',
|
about: '关于',
|
||||||
@@ -664,6 +692,8 @@ export default {
|
|||||||
withdrawNotice2: '提现申请提交后预计0-7个工作日到账',
|
withdrawNotice2: '提现申请提交后预计0-7个工作日到账',
|
||||||
withdrawNotice3: '如超时未收到,请联系客服处理',
|
withdrawNotice3: '如超时未收到,请联系客服处理',
|
||||||
depositRecord: '押金记录',
|
depositRecord: '押金记录',
|
||||||
|
payRecord: '支付记录',
|
||||||
|
refundRecord: '退还记录',
|
||||||
orderNotReturned: '当前订单尚未归还,请归还后再提现',
|
orderNotReturned: '当前订单尚未归还,请归还后再提现',
|
||||||
alreadyRefunded: '押金已退还,无需重复提现',
|
alreadyRefunded: '押金已退还,无需重复提现',
|
||||||
refundProcessing: '押金退还处理中,请耐心等待'
|
refundProcessing: '押金退还处理中,请耐心等待'
|
||||||
@@ -719,32 +749,50 @@ export default {
|
|||||||
type: '类型',
|
type: '类型',
|
||||||
timesCard: '次卡',
|
timesCard: '次卡',
|
||||||
durationCard: '时长卡',
|
durationCard: '时长卡',
|
||||||
remainingTimes: '剩余次数',
|
remainingTimes: '剩余次数:',
|
||||||
remainingDuration: '剩余时长',
|
remainingDuration: '剩余时长',
|
||||||
hours: '小时',
|
hours: '小时',
|
||||||
validPeriod: '有效期',
|
validPeriod: '有效期',
|
||||||
active: '使用中',
|
active: '使用中',
|
||||||
expired: '已过期',
|
expired: '已失效',
|
||||||
used: '已用完',
|
used: '已用完',
|
||||||
position: '使用地点',
|
position: '使用地点',
|
||||||
price: '购买价格',
|
price: '购买价格',
|
||||||
noCards: '暂无会员卡',
|
noCards: '暂无会员卡',
|
||||||
buyNow: '立即购买',
|
buyNow: '立即购买',
|
||||||
getListFailed: '获取会员卡列表失败'
|
getListFailed: '获取会员卡列表失败',
|
||||||
|
dailyLimit: '每日限用',
|
||||||
|
singleTimeLimit: '单次限时',
|
||||||
|
unlimited: '不限',
|
||||||
|
times: '次',
|
||||||
|
minutes: '分钟',
|
||||||
|
validWithinDays: '天内有效',
|
||||||
|
validFromPurchase: '从购买时间起',
|
||||||
|
daysValid: '天有效',
|
||||||
|
currentCycleUsed: '本周期已使用',
|
||||||
|
totalCount: '总次数',
|
||||||
|
expire: '到期',
|
||||||
|
expiredOn: '失效于',
|
||||||
|
renew: '续卡',
|
||||||
|
toUse: '去使用',
|
||||||
|
onlyForRegionBefore: '仅限',
|
||||||
|
onlyForRegionAfter: '使用'
|
||||||
},
|
},
|
||||||
|
|
||||||
myCoupon: {
|
myCoupon: {
|
||||||
available: '可使用',
|
available: '可使用',
|
||||||
used: '已使用',
|
used: '已使用',
|
||||||
expired: '已过期',
|
expired: '已过期',
|
||||||
useNow: '立即使用',
|
useNow: '去使用',
|
||||||
usedStatus: '已使用',
|
usedStatus: '已使用',
|
||||||
expiredStatus: '已过期',
|
expiredStatus: '已过期',
|
||||||
noAvailableCoupons: '暂无可用优惠券',
|
noAvailableCoupons: '暂无可用优惠券',
|
||||||
noUsedCoupons: '暂无已使用优惠券',
|
noUsedCoupons: '暂无已使用优惠券',
|
||||||
noExpiredCoupons: '暂无已过期优惠券',
|
noExpiredCoupons: '暂无已过期优惠券',
|
||||||
buyNow: '立即购买',
|
buyNow: '立即购买',
|
||||||
getListFailed: '获取优惠券列表失败'
|
getListFailed: '获取优惠券列表失败',
|
||||||
|
onlyForRegionBefore: '仅限',
|
||||||
|
onlyForRegionAfter: '使用'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,19 @@
|
|||||||
"mp-toutiao" : {
|
"mp-toutiao" : {
|
||||||
"usingComponents" : true
|
"usingComponents" : true
|
||||||
},
|
},
|
||||||
|
"h5" : {
|
||||||
|
"sdkConfigs" : {
|
||||||
|
"maps" : {
|
||||||
|
"qqmap" : {
|
||||||
|
"key" : "DJQBZ-WB53Q-WPS5B-4S6J7-53RMS-X4FJ2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"router" : {
|
||||||
|
"mode" : "hash",
|
||||||
|
"base" : "./"
|
||||||
|
}
|
||||||
|
},
|
||||||
"uniStatistics" : {
|
"uniStatistics" : {
|
||||||
"enable" : false
|
"enable" : false
|
||||||
},
|
},
|
||||||
|
|||||||
+9
-1
@@ -19,7 +19,15 @@
|
|||||||
"path": "pages/login/index",
|
"path": "pages/login/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "",
|
"navigationBarTitleText": "",
|
||||||
"navigationBarBackgroundColor": "#ffffff",
|
"navigationBarBackgroundColor": "#C8F4D9",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/login/phone",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "",
|
||||||
|
"navigationBarBackgroundColor": "#C8F4D9",
|
||||||
"navigationBarTextStyle": "black"
|
"navigationBarTextStyle": "black"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+63
-81
@@ -26,11 +26,11 @@
|
|||||||
<view class="record-list">
|
<view class="record-list">
|
||||||
<view class="record-item" v-for="(item, index) in records" :key="index">
|
<view class="record-item" v-for="(item, index) in records" :key="index">
|
||||||
<view class="record-info">
|
<view class="record-info">
|
||||||
<text class="record-type">{{ item.type }}</text>
|
<text class="record-type">{{ item.typeText }}</text>
|
||||||
<text class="record-time">{{ item.time }}</text>
|
<text class="record-time">{{ item.time }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="record-amount" :class="item.type === '退还' ? 'refund' : ''">
|
<text class="record-amount" :class="item.type === 'refund' ? 'refund' : ''">
|
||||||
{{ item.type === '退还' ? '+' : '-' }}¥{{ item.amount }}
|
{{ item.type === 'refund' ? '+' : '-' }}¥{{ item.amount }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -38,145 +38,128 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
import { getUserInfo } from '../../util/index.js'
|
import { getUserInfo } from '../../util/index.js'
|
||||||
import { withdrawDeposit } from '../../config/api/user.js'
|
import { withdrawDeposit } from '../../config/api/user.js'
|
||||||
import { queryById } from '../../config/api/order.js'
|
import { queryById } from '../../config/api/order.js'
|
||||||
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
export default {
|
const { t } = useI18n()
|
||||||
data() {
|
|
||||||
return {
|
const depositAmount = ref('0.00')
|
||||||
depositAmount: '0.00',
|
const orderNo = ref('')
|
||||||
orderNo: '',
|
const orderId = ref('')
|
||||||
records: [],
|
const records = ref([])
|
||||||
orderId:''
|
|
||||||
}
|
onMounted(() => {
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
// 设置页面标题
|
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: this.$t('deposit.title')
|
title: t('deposit.title')
|
||||||
})
|
})
|
||||||
// this.loadUserInfo()
|
})
|
||||||
},
|
|
||||||
onShow() {
|
onShow(() => {
|
||||||
this.loadUserInfo()
|
loadUserInfo()
|
||||||
},
|
})
|
||||||
methods: {
|
|
||||||
async loadUserInfo() {
|
const loadUserInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getUserInfo()
|
const res = await getUserInfo()
|
||||||
console.log('loadUserInfo',res);
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.depositAmount = res.data.balanceAmount || '0.00'
|
depositAmount.value = res.data.balanceAmount || '0.00'
|
||||||
this.orderNo = res.data.latestOrderNo || ''
|
orderNo.value = res.data.latestOrderNo || ''
|
||||||
this.orderId = res.data.latestOrderId||''
|
orderId.value = res.data.latestOrderId || ''
|
||||||
|
|
||||||
// 如果存在余额,获取押金记录
|
// 如果存在余额,获取押金记录
|
||||||
if (parseFloat(this.depositAmount) > 0 && this.orderNo) {
|
if (parseFloat(depositAmount.value) > 0 && orderNo.value) {
|
||||||
this.records = [
|
records.value = [
|
||||||
{
|
{
|
||||||
type: '支付',
|
type: 'pay',
|
||||||
time: this.formatDate(new Date()),
|
typeText: t('deposit.payRecord'),
|
||||||
amount: this.depositAmount
|
time: formatDate(new Date()),
|
||||||
|
amount: depositAmount.value
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
this.records = []
|
records.value = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取用户信息失败:', error)
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('user.getUserInfoFailed'),
|
title: t('user.getUserInfoFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
async handleWithdraw() {
|
|
||||||
if (parseFloat(this.depositAmount) <= 0) {
|
const handleWithdraw = async () => {
|
||||||
|
if (parseFloat(depositAmount.value) <= 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('deposit.noBalance'),
|
title: t('deposit.noBalance'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(this.orderId.length!=0||this.orderNo.length!=0){
|
|
||||||
const res = await queryById(Number(this.orderId))
|
|
||||||
console.log(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if(this.orderNo.length!=0){
|
|
||||||
// uni.showToast({
|
|
||||||
// title:'当前存在进行中的订单',
|
|
||||||
// icon:'none'
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: this.$t('deposit.confirmWithdraw'),
|
title: t('deposit.confirmWithdraw'),
|
||||||
content: this.$t('deposit.withdrawDesc'),
|
content: t('deposit.withdrawDesc'),
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: this.$t('deposit.withdrawing')
|
title: t('deposit.withdrawing')
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('发起提现请求,订单号:', this.orderNo)
|
const result = await withdrawDeposit(orderNo.value)
|
||||||
const result = await withdrawDeposit(this.orderNo)
|
|
||||||
console.log('提现响应:', result)
|
|
||||||
|
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('deposit.withdrawSubmitted'),
|
title: t('deposit.withdrawSubmitted'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新余额为0
|
// 更新记录
|
||||||
this.depositAmount = '0.00'
|
records.value.push({
|
||||||
this.records.push({
|
type: 'refund',
|
||||||
type: '退还',
|
typeText: t('deposit.refundRecord'),
|
||||||
time: this.formatDate(new Date()),
|
time: formatDate(new Date()),
|
||||||
amount: this.depositAmount
|
amount: depositAmount.value
|
||||||
})
|
})
|
||||||
|
// 更新余额为0
|
||||||
|
depositAmount.value = '0.00'
|
||||||
|
|
||||||
// 重新加载用户信息
|
// 重新加载用户信息
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.loadUserInfo()
|
loadUserInfo()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.msg || this.$t('deposit.withdrawFailed'))
|
throw new Error(result.msg || t('deposit.withdrawFailed'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('提现失败:', error)
|
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
||||||
// 更详细的错误处理
|
// 更详细的错误处理
|
||||||
let errorMessage = this.$t('deposit.withdrawFailed');
|
let errorMessage = t('deposit.withdrawFailed');
|
||||||
|
|
||||||
// 如果有具体错误信息,使用它
|
|
||||||
if (error.message) {
|
if (error.message) {
|
||||||
// 常见错误消息处理
|
|
||||||
if (error.message.includes('尚未归还')) {
|
if (error.message.includes('尚未归还')) {
|
||||||
errorMessage = this.$t('deposit.orderNotReturned');
|
errorMessage = t('deposit.orderNotReturned');
|
||||||
} else if (error.message.includes('已退还')) {
|
} else if (error.message.includes('已退还')) {
|
||||||
errorMessage = this.$t('deposit.alreadyRefunded');
|
errorMessage = t('deposit.alreadyRefunded');
|
||||||
} else if (error.message.includes('处理中')) {
|
} else if (error.message.includes('处理中')) {
|
||||||
errorMessage = this.$t('deposit.refundProcessing');
|
errorMessage = t('deposit.refundProcessing');
|
||||||
} else if (error.message.includes('余额为0')) {
|
} else if (error.message.includes('余额为0')) {
|
||||||
errorMessage = this.$t('deposit.noBalance');
|
errorMessage = t('deposit.noBalance');
|
||||||
} else {
|
} else {
|
||||||
// 使用后端返回的具体错误消息
|
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示错误提示
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: this.$t('deposit.withdrawFailed'),
|
title: t('deposit.withdrawFailed'),
|
||||||
content: errorMessage,
|
content: errorMessage,
|
||||||
showCancel: false
|
showCancel: false
|
||||||
})
|
})
|
||||||
@@ -184,8 +167,9 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
formatDate(date) {
|
|
||||||
|
const formatDate = (date) => {
|
||||||
const year = date.getFullYear()
|
const year = date.getFullYear()
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||||
const day = date.getDate().toString().padStart(2, '0')
|
const day = date.getDate().toString().padStart(2, '0')
|
||||||
@@ -193,8 +177,6 @@ export default {
|
|||||||
const minutes = date.getMinutes().toString().padStart(2, '0')
|
const minutes = date.getMinutes().toString().padStart(2, '0')
|
||||||
|
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+46
-42
@@ -131,7 +131,9 @@
|
|||||||
import {
|
import {
|
||||||
getOrderByOrderNoScore,
|
getOrderByOrderNoScore,
|
||||||
getOrderByOrderNo,
|
getOrderByOrderNo,
|
||||||
cancelOrder
|
cancelOrder,
|
||||||
|
getInUseOrder,
|
||||||
|
getUnpaidOrder
|
||||||
} from '@/config/api/order.js'
|
} from '@/config/api/order.js'
|
||||||
import {
|
import {
|
||||||
initiateWeChatScorePayment,
|
initiateWeChatScorePayment,
|
||||||
@@ -143,7 +145,7 @@
|
|||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
@@ -154,7 +156,7 @@
|
|||||||
const deviceLocation = ref('一号教学楼大厅')
|
const deviceLocation = ref('一号教学楼大厅')
|
||||||
const hasActiveOrder = ref(false)
|
const hasActiveOrder = ref(false)
|
||||||
const deviceStatus = reactive({
|
const deviceStatus = reactive({
|
||||||
text: $t('device.available'),
|
text: t('device.available'),
|
||||||
class: 'available'
|
class: 'available'
|
||||||
})
|
})
|
||||||
const isLoggedIn = ref(true)
|
const isLoggedIn = ref(true)
|
||||||
@@ -175,7 +177,7 @@
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('device.deviceInfo')
|
title: t('device.deviceInfo')
|
||||||
})
|
})
|
||||||
await checkUserPhone()
|
await checkUserPhone()
|
||||||
await fetchDeviceInfo()
|
await fetchDeviceInfo()
|
||||||
@@ -219,7 +221,7 @@
|
|||||||
// 用户拒绝授权的情况
|
// 用户拒绝授权的情况
|
||||||
if (e.detail.errMsg && e.detail.errMsg.includes('deny')) {
|
if (e.detail.errMsg && e.detail.errMsg.includes('deny')) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.phoneRequired'),
|
title: t('auth.phoneRequired'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -228,7 +230,7 @@
|
|||||||
// 获取到授权code
|
// 获取到授权code
|
||||||
if (e.detail.code) {
|
if (e.detail.code) {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('auth.getting')
|
title: t('auth.getting')
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('获取到的授权code:', e.detail.code)
|
console.log('获取到的授权code:', e.detail.code)
|
||||||
@@ -260,15 +262,15 @@
|
|||||||
showPhoneAuthPopup.value = false
|
showPhoneAuthPopup.value = false
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.phoneSuccess'),
|
title: t('auth.phoneSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 记录详细信息,不抛出错误
|
// 记录详细信息,不抛出错误
|
||||||
console.warn('获取手机号响应异常:', res.msg || '未知错误')
|
console.warn('获取手机号响应异常:', res.msg || '未知错误')
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('auth.phoneError'),
|
title: t('auth.phoneError'),
|
||||||
content: `${$t('common.statusCode')}: ${res.code}, ${$t('common.message')}: ${res.msg || $t('common.none')}`,
|
content: `${t('common.statusCode')}: ${res.code}, ${t('common.message')}: ${res.msg || t('common.none')}`,
|
||||||
showCancel: false
|
showCancel: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -280,8 +282,8 @@
|
|||||||
// 显示更详细的错误信息
|
// 显示更详细的错误信息
|
||||||
let errMsg = err.message || err.toString()
|
let errMsg = err.message || err.toString()
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('auth.phoneGetFailed'),
|
title: t('auth.phoneGetFailed'),
|
||||||
content: $t('common.errorInfo') + ': ' + errMsg,
|
content: t('common.errorInfo') + ': ' + errMsg,
|
||||||
showCancel: false
|
showCancel: false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -289,14 +291,14 @@
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
console.error('获取手机号外部错误:', outerError)
|
console.error('获取手机号外部错误:', outerError)
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('common.unexpectedError'),
|
title: t('common.unexpectedError'),
|
||||||
content: $t('common.processException') + ': ' + (outerError.message || outerError),
|
content: t('common.processException') + ': ' + (outerError.message || outerError),
|
||||||
showCancel: false
|
showCancel: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.authCodeFailed'),
|
title: t('auth.authCodeFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -325,10 +327,10 @@
|
|||||||
// 更新设备状态
|
// 更新设备状态
|
||||||
if (deviceInfo.value.status) {
|
if (deviceInfo.value.status) {
|
||||||
if (deviceInfo.value.status === 'online') {
|
if (deviceInfo.value.status === 'online') {
|
||||||
deviceStatus.text = $t('device.available')
|
deviceStatus.text = t('device.available')
|
||||||
deviceStatus.class = 'available'
|
deviceStatus.class = 'available'
|
||||||
} else if (deviceInfo.value.status === 'offline') {
|
} else if (deviceInfo.value.status === 'offline') {
|
||||||
deviceStatus.text = $t('device.offline')
|
deviceStatus.text = t('device.offline')
|
||||||
deviceStatus.class = 'offline'
|
deviceStatus.class = 'offline'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,9 +351,9 @@
|
|||||||
// 显示登录提示
|
// 显示登录提示
|
||||||
const showLoginTip = () => {
|
const showLoginTip = () => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('common.tips'),
|
title: t('common.tips'),
|
||||||
content: $t('common.loginRequired'),
|
content: t('common.loginRequired'),
|
||||||
confirmText: $t('auth.goToLogin'),
|
confirmText: t('auth.goToLogin'),
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
@@ -374,27 +376,29 @@
|
|||||||
const checkOrderStatus = async () => {
|
const checkOrderStatus = async () => {
|
||||||
try {
|
try {
|
||||||
// 调用接口检查是否有进行中的订单
|
// 调用接口检查是否有进行中的订单
|
||||||
const result = await uni.$api.checkActiveOrder()
|
const inUseRes = await getInUseOrder()
|
||||||
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
if (result.hasOrder) {
|
const order = inUseRes.data
|
||||||
const order = result.order // 假设后端返回 order 对象
|
|
||||||
|
|
||||||
// 检查订单状态
|
|
||||||
if (order.status === 'waiting_for_payment') {
|
|
||||||
// 跳转支付页面,带上订单ID
|
|
||||||
uni.redirectTo({
|
|
||||||
url: `/pages/order/payment?orderId=${order.orderId}&deviceId=${deviceId.value}`
|
|
||||||
})
|
|
||||||
} else if (order.status === 'in_used') {
|
|
||||||
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
|
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/device/return?deviceId=${deviceId.value}`
|
url: `/pages/device/return?deviceId=${deviceId.value}`
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否有待支付的订单
|
||||||
|
const unpaidRes = await getUnpaidOrder()
|
||||||
|
if (unpaidRes && unpaidRes.code === 200 && unpaidRes.data) {
|
||||||
|
const order = unpaidRes.data
|
||||||
|
// 跳转支付页面,带上订单ID
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/order/payment?orderId=${order.orderId}&deviceId=${deviceId.value}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('检查订单状态失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.getOrderStatusFailed'),
|
title: t('order.getOrderStatusFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -427,7 +431,7 @@
|
|||||||
return '30分钟'
|
return '30分钟'
|
||||||
}
|
}
|
||||||
// 按小时计费(默认)
|
// 按小时计费(默认)
|
||||||
return $t('time.hour')
|
return t('time.hour')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算计费单位时间(分钟)
|
// 计算计费单位时间(分钟)
|
||||||
@@ -499,7 +503,7 @@
|
|||||||
const submitRentOrder = async (payWay) => {
|
const submitRentOrder = async (payWay) => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
})
|
})
|
||||||
// --- 第一步:先请求订阅消息(必须在用户点击的同步上下文中)---
|
// --- 第一步:先请求订阅消息(必须在用户点击的同步上下文中)---
|
||||||
if (payWay === 'wx-score-pay') {
|
if (payWay === 'wx-score-pay') {
|
||||||
@@ -532,7 +536,7 @@
|
|||||||
// 调用设备租借接口
|
// 调用设备租借接口
|
||||||
const rentResult = await rentPowerBank(deviceId.value, phoneNumber.value)
|
const rentResult = await rentPowerBank(deviceId.value, phoneNumber.value)
|
||||||
if (rentResult.code !== 200) {
|
if (rentResult.code !== 200) {
|
||||||
throw new Error(rentResult.msg || $t('device.rentFailed'))
|
throw new Error(rentResult.msg || t('device.rentFailed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取后端返回的订单信息
|
// 获取后端返回的订单信息
|
||||||
@@ -587,7 +591,7 @@
|
|||||||
// 用户取消授权,需要取消订单
|
// 用户取消授权,需要取消订单
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('order.cancelling')
|
title: t('order.cancelling')
|
||||||
});
|
});
|
||||||
const cancelRes = await cancelOrder({
|
const cancelRes = await cancelOrder({
|
||||||
orderId: order.orderNo
|
orderId: order.orderNo
|
||||||
@@ -596,7 +600,7 @@
|
|||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.orderCancelled'),
|
title: t('order.orderCancelled'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
});
|
});
|
||||||
@@ -611,7 +615,7 @@
|
|||||||
console.error('取消订单失败:', cancelError);
|
console.error('取消订单失败:', cancelError);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.cancelFailedContactService'),
|
title: t('order.cancelFailedContactService'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -622,7 +626,7 @@
|
|||||||
// 支付分调用异常,也需要取消订单
|
// 支付分调用异常,也需要取消订单
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('order.cancelling')
|
title: t('order.cancelling')
|
||||||
});
|
});
|
||||||
const cancelRes = await cancelOrder({
|
const cancelRes = await cancelOrder({
|
||||||
orderId: order.orderNo
|
orderId: order.orderNo
|
||||||
@@ -635,7 +639,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('device.payScoreFailedCancelled'),
|
title: t('device.payScoreFailedCancelled'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -647,7 +651,7 @@
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res?.msg || $t('device.getPayParamsFailed'),
|
title: res?.msg || t('device.getPayParamsFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -655,7 +659,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('device.rentFailedRetry'),
|
title: error.message || t('device.rentFailedRetry'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,11 @@
|
|||||||
} from '@/config/api/expressReturn.js'
|
} from '@/config/api/expressReturn.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('express.fillExpress')
|
title: t('express.fillExpress')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
|
|
||||||
if (!orderId.value) {
|
if (!orderId.value) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('express.orderNoMissing'),
|
title: t('express.orderNoMissing'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
const loadOrder = async () => {
|
const loadOrder = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.loading')
|
title: t('common.loading')
|
||||||
})
|
})
|
||||||
const res = await queryById(orderId.value)
|
const res = await queryById(orderId.value)
|
||||||
if (res?.code === 200 && res.data) {
|
if (res?.code === 200 && res.data) {
|
||||||
@@ -121,11 +121,11 @@
|
|||||||
// 默认联系电话可回填订单上的手机号(若有)
|
// 默认联系电话可回填订单上的手机号(若有)
|
||||||
if (res.data.phone && !phone.value) phone.value = res.data.phone
|
if (res.data.phone && !phone.value) phone.value = res.data.phone
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res?.msg || $t('order.getOrderFailed'))
|
throw new Error(res?.msg || t('order.getOrderFailed'))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: e.message || $t('express.loadFailed'),
|
title: e.message || t('express.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
const loadRecordAndOrderByRecord = async () => {
|
const loadRecordAndOrderByRecord = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.loading')
|
title: t('common.loading')
|
||||||
})
|
})
|
||||||
const res = await getExpressReturnDetail(recordId.value)
|
const res = await getExpressReturnDetail(recordId.value)
|
||||||
if (res?.code === 200 && res.data) {
|
if (res?.code === 200 && res.data) {
|
||||||
@@ -146,11 +146,11 @@
|
|||||||
}
|
}
|
||||||
if (res.data.userPhone && !phone.value) phone.value = res.data.userPhone
|
if (res.data.userPhone && !phone.value) phone.value = res.data.userPhone
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res?.msg || $t('express.getRecordFailed'))
|
throw new Error(res?.msg || t('express.getRecordFailed'))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: e.message || $t('express.loadFailed'),
|
title: e.message || t('express.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -166,10 +166,10 @@
|
|||||||
if (rec.status === 0) {
|
if (rec.status === 0) {
|
||||||
recordId.value = rec.id
|
recordId.value = rec.id
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('common.tips'),
|
title: t('common.tips'),
|
||||||
content: $t('express.existingReturnNotice'),
|
content: t('express.existingReturnNotice'),
|
||||||
confirmText: $t('express.goToFill'),
|
confirmText: t('express.goToFill'),
|
||||||
cancelText: $t('common.cancel'),
|
cancelText: t('common.cancel'),
|
||||||
success: (r) => {
|
success: (r) => {
|
||||||
if (r.confirm) {
|
if (r.confirm) {
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('express.alreadyHasRecord'),
|
title: t('express.alreadyHasRecord'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -201,14 +201,14 @@
|
|||||||
const digits = (phone.value || '').replace(/\D/g, '')
|
const digits = (phone.value || '').replace(/\D/g, '')
|
||||||
if (!digits || digits.length < 5) {
|
if (!digits || digits.length < 5) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('express.pleaseEnterValidPhone'),
|
title: t('express.pleaseEnterValidPhone'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (isFillMode.value && !trackingNumber.value) {
|
if (isFillMode.value && !trackingNumber.value) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('express.pleaseEnterTrackingNo'),
|
title: t('express.pleaseEnterTrackingNo'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@@ -221,7 +221,7 @@
|
|||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: isFillMode.value ? $t('common.filling') : $t('common.submitting')
|
title: isFillMode.value ? t('common.filling') : t('common.submitting')
|
||||||
})
|
})
|
||||||
let res
|
let res
|
||||||
if (isFillMode.value) {
|
if (isFillMode.value) {
|
||||||
@@ -238,18 +238,18 @@
|
|||||||
}
|
}
|
||||||
if (res && res.code === 200) {
|
if (res && res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: isFillMode.value ? '补填成功' : '提交成功',
|
title: isFillMode.value ? t('express.fillSuccess') : t('express.submitSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
}, 800)
|
}, 800)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res?.msg || (isFillMode.value ? '补填失败' : '提交失败'))
|
throw new Error(res?.msg || (isFillMode.value ? t('express.fillFailed') : t('express.submitFailed')))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: e.message || (isFillMode.value ? '补填失败' : '提交失败'),
|
title: e.message || (isFillMode.value ? t('express.fillFailed') : t('express.submitFailed')),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ import { getExpressReturnDetail } from '@/config/api/expressReturn.js'
|
|||||||
import { getCustomerPhone } from '@/util/index.js'
|
import { getCustomerPhone } from '@/util/index.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 详情数据
|
// 详情数据
|
||||||
const detailData = ref({
|
const detailData = ref({
|
||||||
@@ -131,21 +131,21 @@ const getStatusIcon = (status) => {
|
|||||||
// 获取状态文本
|
// 获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const textMap = {
|
const textMap = {
|
||||||
'completed': $t('express.returnCompleted'),
|
'completed': t('express.returnCompleted'),
|
||||||
'processing': $t('express.processing'),
|
'processing': t('express.processing'),
|
||||||
'pending': $t('express.pending')
|
'pending': t('express.pending')
|
||||||
}
|
}
|
||||||
return textMap[status] || $t('express.pending')
|
return textMap[status] || t('express.pending')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取状态描述
|
// 获取状态描述
|
||||||
const getStatusDesc = (status) => {
|
const getStatusDesc = (status) => {
|
||||||
const descMap = {
|
const descMap = {
|
||||||
'completed': $t('express.returnCompletedDesc'),
|
'completed': t('express.returnCompletedDesc'),
|
||||||
'processing': $t('express.processingDesc'),
|
'processing': t('express.processingDesc'),
|
||||||
'pending': $t('express.pendingDesc')
|
'pending': t('express.pendingDesc')
|
||||||
}
|
}
|
||||||
return descMap[status] || $t('express.pendingDesc')
|
return descMap[status] || t('express.pendingDesc')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制运单号
|
// 复制运单号
|
||||||
@@ -154,7 +154,7 @@ const handleCopyTracking = () => {
|
|||||||
data: detailData.value.trackingNumber,
|
data: detailData.value.trackingNumber,
|
||||||
success: () => {
|
success: () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('express.trackingNoCopied'),
|
title: t('express.trackingNoCopied'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -165,10 +165,10 @@ const handleCopyTracking = () => {
|
|||||||
const handleContactService = () => {
|
const handleContactService = () => {
|
||||||
const customerPhone = getCustomerPhone()
|
const customerPhone = getCustomerPhone()
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('user.customerService'),
|
title: t('user.customerService'),
|
||||||
content: `${$t('help.phone')}:${customerPhone}\n${$t('help.workingHours')}:${$t('express.workingHours')}`,
|
content: `${t('help.phone')}:${customerPhone}\n${t('help.workingHours')}:${t('express.workingHours')}`,
|
||||||
confirmText: $t('express.call'),
|
confirmText: t('express.call'),
|
||||||
cancelText: $t('common.cancel'),
|
cancelText: t('common.cancel'),
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
uni.makePhoneCall({
|
uni.makePhoneCall({
|
||||||
@@ -182,7 +182,7 @@ const handleContactService = () => {
|
|||||||
// 页面加载时获取详情数据
|
// 页面加载时获取详情数据
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('express.returnDetail')
|
title: t('express.returnDetail')
|
||||||
})
|
})
|
||||||
|
|
||||||
const pages = getCurrentPages()
|
const pages = getCurrentPages()
|
||||||
@@ -190,7 +190,7 @@ onMounted(async () => {
|
|||||||
const options = currentPage.options || {}
|
const options = currentPage.options || {}
|
||||||
if (!options.id) return
|
if (!options.id) return
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: $t('common.loading') })
|
uni.showLoading({ title: t('common.loading') })
|
||||||
const res = await getExpressReturnDetail(options.id)
|
const res = await getExpressReturnDetail(options.id)
|
||||||
if (res && res.code === 200 && res.data) {
|
if (res && res.code === 200 && res.data) {
|
||||||
const r = res.data
|
const r = res.data
|
||||||
@@ -208,10 +208,10 @@ onMounted(async () => {
|
|||||||
remark: r.remark || ''
|
remark: r.remark || ''
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res?.msg || $t('express.getDetailFailed'))
|
throw new Error(res?.msg || t('express.getDetailFailed'))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({ title: e.message || $t('express.loadFailed'), icon: 'none' })
|
uni.showToast({ title: e.message || t('express.loadFailed'), icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import { ref, onMounted } from 'vue'
|
|||||||
import { getExpressReturnList } from '@/config/api/expressReturn.js'
|
import { getExpressReturnList } from '@/config/api/expressReturn.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const returnList = ref([])
|
const returnList = ref([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -62,7 +62,7 @@ const query = ref({ pageNum: 1, pageSize: 20 })
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('express.returnRecord')
|
title: t('express.returnRecord')
|
||||||
})
|
})
|
||||||
loadList()
|
loadList()
|
||||||
})
|
})
|
||||||
@@ -80,12 +80,12 @@ const loadList = async () => {
|
|||||||
const rows = (res.data && (res.data.rows || res.data)) || []
|
const rows = (res.data && (res.data.rows || res.data)) || []
|
||||||
returnList.value = rows.map(r => ({
|
returnList.value = rows.map(r => ({
|
||||||
id: r.id,
|
id: r.id,
|
||||||
expressCompany: r.expressCompany || r.company || '待填写',
|
expressCompany: r.expressCompany || r.company || t('express.toFill'),
|
||||||
trackingNumber: r.logisticsTrackingNumber || r.trackingNumber || '待填写',
|
trackingNumber: r.logisticsTrackingNumber || r.trackingNumber || t('express.toFill'),
|
||||||
returnAddress: r.returnAddress || r.address || '待填写',
|
returnAddress: r.returnAddress || r.address || t('express.toFill'),
|
||||||
returnTime: r.expressFillTime || r.createTime || r.returnTime || '待填写',
|
returnTime: r.expressFillTime || r.createTime || r.returnTime || t('express.toFill'),
|
||||||
packageType: r.packageType || '待填写',
|
packageType: r.packageType || t('express.toFill'),
|
||||||
weight: r.weight || '待填写',
|
weight: r.weight || t('express.toFill'),
|
||||||
status: mapStatus(r.status),
|
status: mapStatus(r.status),
|
||||||
rawStatus: r.status,
|
rawStatus: r.status,
|
||||||
userPhone: r.userPhone,
|
userPhone: r.userPhone,
|
||||||
@@ -93,10 +93,10 @@ const loadList = async () => {
|
|||||||
remark: r.remark
|
remark: r.remark
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res?.msg || $t('express.getListFailed'))
|
throw new Error(res?.msg || t('express.getListFailed'))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uni.showToast({ title: e.message || $t('express.loadFailed'), icon: 'none' })
|
uni.showToast({ title: e.message || t('express.loadFailed'), icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -118,34 +118,33 @@ const getStatusClass = (status) => ({
|
|||||||
}[status] || 'status-pending')
|
}[status] || 'status-pending')
|
||||||
|
|
||||||
const getStatusText = (status) => ({
|
const getStatusText = (status) => ({
|
||||||
'completed': $t('express.billingPaused'),
|
'completed': t('express.billingPaused'),
|
||||||
'processing': $t('express.billingPaused'),
|
'processing': t('express.billingPaused'),
|
||||||
'pending': $t('express.billingPaused')
|
'pending': t('express.billingPaused')
|
||||||
}[status] || $t('express.billingPaused'))
|
}[status] || t('express.billingPaused'))
|
||||||
|
|
||||||
const getStatusBadge = (status) => ({
|
const getStatusBadge = (status) => ({
|
||||||
'completed': $t('express.completed'),
|
'completed': t('express.completed'),
|
||||||
'processing': $t('express.processing'),
|
'processing': t('express.processing'),
|
||||||
'pending': $t('express.pending')
|
'pending': t('express.pending')
|
||||||
}[status] || $t('express.pending'))
|
}[status] || t('express.pending'))
|
||||||
|
|
||||||
// 一键复制全部信息
|
// 一键复制全部信息
|
||||||
const copyAllInfo = () => {
|
const copyAllInfo = () => {
|
||||||
const allInfo = `${$t('express.recipient')}:${recipientName}\n${$t('express.recipientAddressLabel')}:${recipientAddress}`
|
const allInfo = `${t('express.recipient')}:${recipientName}\n${t('express.recipientAddressLabel')}:${recipientAddress}`
|
||||||
uni.setClipboardData({
|
uni.setClipboardData({
|
||||||
data: allInfo,
|
data: allInfo,
|
||||||
success: () => {
|
success: () => {
|
||||||
uni.showToast({ title: $t('express.copySuccess'), icon: 'success' })
|
uni.showToast({ title: t('express.copySuccess'), icon: 'success' })
|
||||||
},
|
},
|
||||||
fail: () => {
|
fail: () => {
|
||||||
uni.showToast({ title: $t('express.copyFailed'), icon: 'none' })
|
uni.showToast({ title: t('express.copyFailed'), icon: 'none' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击列表项
|
// 点击列表项
|
||||||
const handleItemClick = (item) => {
|
const handleItemClick = (item) => {
|
||||||
console.log('点击了归还记录:', item)
|
|
||||||
// 未填写(status=0 -> mapped 'pending')时跳转到补填页,其它跳详情
|
// 未填写(status=0 -> mapped 'pending')时跳转到补填页,其它跳详情
|
||||||
if (item && item.rawStatus === 0) {
|
if (item && item.rawStatus === 0) {
|
||||||
uni.navigateTo({ url: `/pages/expressReturn/addExpressReturn?id=${item.id}` })
|
uni.navigateTo({ url: `/pages/expressReturn/addExpressReturn?id=${item.id}` })
|
||||||
|
|||||||
+17
-17
@@ -98,13 +98,13 @@
|
|||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('feedback.detail')
|
title: t('feedback.detail')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
await loadDetail();
|
await loadDetail();
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.idRequired'),
|
title: t('feedback.idRequired'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
try {
|
try {
|
||||||
if (shouldShowLoading) {
|
if (shouldShowLoading) {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.loading')
|
title: t('common.loading')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
await loadMessages(res.data.messages);
|
await loadMessages(res.data.messages);
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || $t('feedback.getDetailFailed'),
|
title: res.msg || t('feedback.getDetailFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -190,7 +190,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取投诉详情失败:', error);
|
console.error('获取投诉详情失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.getDetailFailed'),
|
title: t('feedback.getDetailFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
const submitReply = async () => {
|
const submitReply = async () => {
|
||||||
if (!replyContent.value.trim()) {
|
if (!replyContent.value.trim()) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.pleaseEnterReply'),
|
title: t('feedback.pleaseEnterReply'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.submitting')
|
title: t('common.submitting')
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await sendFeedbackMessage(feedbackId.value, {
|
const res = await sendFeedbackMessage(feedbackId.value, {
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.replySuccess'),
|
title: t('feedback.replySuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
replyContent.value = '';
|
replyContent.value = '';
|
||||||
@@ -234,14 +234,14 @@
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || $t('feedback.replyFailed'),
|
title: res.msg || t('feedback.replyFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('提交回复失败:', error);
|
console.error('提交回复失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.replyFailed'),
|
title: t('feedback.replyFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -252,11 +252,11 @@
|
|||||||
// 获取状态文本
|
// 获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'pending': $t('feedback.pending'),
|
'pending': t('feedback.pending'),
|
||||||
'in_progress': $t('feedback.processing'),
|
'in_progress': t('feedback.processing'),
|
||||||
'resolved': $t('feedback.completed')
|
'resolved': t('feedback.completed')
|
||||||
};
|
};
|
||||||
return statusMap[status] || $t('feedback.pending');
|
return statusMap[status] || t('feedback.pending');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取状态样式类
|
// 获取状态样式类
|
||||||
@@ -272,8 +272,8 @@
|
|||||||
// 获取类型文本
|
// 获取类型文本
|
||||||
const getTypeText = (type) => {
|
const getTypeText = (type) => {
|
||||||
const typeMap = {
|
const typeMap = {
|
||||||
'complain': $t('feedback.complain'),
|
'complain': t('feedback.complain'),
|
||||||
'suggestion': $t('feedback.suggestion')
|
'suggestion': t('feedback.suggestion')
|
||||||
};
|
};
|
||||||
return typeMap[type] || type || '-';
|
return typeMap[type] || type || '-';
|
||||||
};
|
};
|
||||||
|
|||||||
+10
-10
@@ -80,7 +80,7 @@
|
|||||||
useI18n
|
useI18n
|
||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 跳转到投诉记录列表
|
// 跳转到投诉记录列表
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('feedback.title')
|
title: t('feedback.title')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
const submitFeedback = async () => {
|
const submitFeedback = async () => {
|
||||||
if (selectedType.value === -1) {
|
if (selectedType.value === -1) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.pleaseSelectType'),
|
title: t('feedback.pleaseSelectType'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
|
|
||||||
if (!description.value.trim()) {
|
if (!description.value.trim()) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.pleaseDescribe'),
|
title: t('feedback.pleaseDescribe'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
if (!contact.value) {
|
if (!contact.value) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.pleaseContact'),
|
title: t('feedback.pleaseContact'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
try {
|
try {
|
||||||
// 显示上传进度
|
// 显示上传进度
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('feedback.uploading') || '上传中...',
|
title: t('feedback.uploading') || '上传中...',
|
||||||
mask: true
|
mask: true
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
console.error(`文件 ${i + 1} 上传失败:`, err)
|
console.error(`文件 ${i + 1} 上传失败:`, err)
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.imageUploadFailed'),
|
title: t('feedback.imageUploadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
// 处理响应
|
// 处理响应
|
||||||
if (res && (res.code === 200 || res === true || res?.success === true)) {
|
if (res && (res.code === 200 || res === true || res?.success === true)) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.submitSuccess'),
|
title: t('feedback.submitSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: (res && (res.msg || res.message)) || $t('feedback.submitFailed'),
|
title: (res && (res.msg || res.message)) || t('feedback.submitFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
console.error('feedback submit failed:', err)
|
console.error('feedback submit failed:', err)
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('error.networkError') || '网络错误,请重试',
|
title: t('error.networkError') || '网络错误,请重试',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -78,13 +78,13 @@
|
|||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('feedback.recordList')
|
title: t('feedback.recordList')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -100,25 +100,25 @@
|
|||||||
// 状态标签
|
// 状态标签
|
||||||
const statusTabs = reactive([{
|
const statusTabs = reactive([{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('common.all')
|
return t('common.all')
|
||||||
},
|
},
|
||||||
status: ''
|
status: ''
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('feedback.pending')
|
return t('feedback.pending')
|
||||||
},
|
},
|
||||||
status: 'pending'
|
status: 'pending'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('feedback.processing')
|
return t('feedback.processing')
|
||||||
},
|
},
|
||||||
status: 'in_progress'
|
status: 'in_progress'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('feedback.completed')
|
return t('feedback.completed')
|
||||||
},
|
},
|
||||||
status: 'resolved'
|
status: 'resolved'
|
||||||
}
|
}
|
||||||
@@ -176,14 +176,14 @@
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || $t('feedback.getListFailed'),
|
title: res.msg || t('feedback.getListFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取投诉列表失败:', error);
|
console.error('获取投诉列表失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('feedback.getListFailed'),
|
title: t('feedback.getListFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -211,11 +211,11 @@
|
|||||||
// 获取状态文本
|
// 获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'pending': $t('feedback.pending'),
|
'pending': t('feedback.pending'),
|
||||||
'in_progress': $t('feedback.processing'),
|
'in_progress': t('feedback.processing'),
|
||||||
'resolved': $t('feedback.completed')
|
'resolved': t('feedback.completed')
|
||||||
};
|
};
|
||||||
return statusMap[status] || $t('feedback.pending');
|
return statusMap[status] || t('feedback.pending');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取状态样式类
|
// 获取状态样式类
|
||||||
@@ -231,8 +231,8 @@
|
|||||||
// 获取类型文本
|
// 获取类型文本
|
||||||
const getTypeText = (type) => {
|
const getTypeText = (type) => {
|
||||||
const typeMap = {
|
const typeMap = {
|
||||||
'complain': $t('feedback.complain'),
|
'complain': t('feedback.complain'),
|
||||||
'suggestion': $t('feedback.suggestion')
|
'suggestion': t('feedback.suggestion')
|
||||||
};
|
};
|
||||||
return typeMap[type] || type || '-';
|
return typeMap[type] || type || '-';
|
||||||
};
|
};
|
||||||
|
|||||||
+17
-21
@@ -26,40 +26,36 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="contact-item">
|
<view class="contact-item">
|
||||||
<text class="label">{{ $t('help.workingHours') }}</text>
|
<text class="label">{{ $t('help.workingHours') }}</text>
|
||||||
<text class="value">{{ HELP_CONTENT.CONTACT.SERVICE_TIME.VALUE }}</text>
|
<text class="value">{{ $t('help.workingHoursValue') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { HELP_CONTENT } from '@/constants/help'
|
import { HELP_CONTENT } from '@/constants/help'
|
||||||
import { getCustomerPhone } from '@/util/index.js'
|
import { getCustomerPhone } from '@/util/index.js'
|
||||||
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
export default {
|
const { t } = useI18n()
|
||||||
data() {
|
|
||||||
return {
|
const faqList = ref(HELP_CONTENT.FAQ_LIST)
|
||||||
HELP_CONTENT,
|
const customerPhone = ref(HELP_CONTENT.CONTACT.PHONE.VALUE)
|
||||||
faqList: HELP_CONTENT.FAQ_LIST,
|
|
||||||
customerPhone: HELP_CONTENT.CONTACT.PHONE.VALUE // 默认客服电话
|
onLoad(() => {
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
// 设置页面标题
|
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: this.$t('help.title')
|
title: t('help.title')
|
||||||
})
|
})
|
||||||
// 从缓存读取客服电话
|
customerPhone.value = getCustomerPhone()
|
||||||
this.customerPhone = getCustomerPhone()
|
})
|
||||||
},
|
|
||||||
methods: {
|
const makePhoneCall = () => {
|
||||||
makePhoneCall() {
|
|
||||||
uni.makePhoneCall({
|
uni.makePhoneCall({
|
||||||
phoneNumber: this.customerPhone
|
phoneNumber: customerPhone.value
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+41
-83
@@ -198,10 +198,13 @@
|
|||||||
transformDeviceData
|
transformDeviceData
|
||||||
} from '../../config/api/device.js'
|
} from '../../config/api/device.js'
|
||||||
import {
|
import {
|
||||||
getPotionsDetail
|
getInUseOrder,
|
||||||
|
getUnpaidOrder
|
||||||
} from '../../config/api/order.js'
|
} from '../../config/api/order.js'
|
||||||
import {
|
import {
|
||||||
getActiveActivity
|
getActiveActivity,
|
||||||
|
getCurrentAnnouncement,
|
||||||
|
getCurrentAdvertisement
|
||||||
} from '../../config/api/system.js'
|
} from '../../config/api/system.js'
|
||||||
// 导入地图工具函数
|
// 导入地图工具函数
|
||||||
import {
|
import {
|
||||||
@@ -227,7 +230,7 @@
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
@@ -294,39 +297,21 @@
|
|||||||
const bannerImages = ref([]) // 首页广告图片列表
|
const bannerImages = ref([]) // 首页广告图片列表
|
||||||
const bannerImageList = ref([]) // 完整的广告配置列表(包含链接信息)
|
const bannerImageList = ref([]) // 完整的广告配置列表(包含链接信息)
|
||||||
|
|
||||||
// 将语言代码转换为后端接受的格式
|
|
||||||
const convertLanguageCode = (lang) => {
|
|
||||||
// zh-CN -> zh_CN (转换下划线)
|
|
||||||
// en-US -> en_US (转换下划线)
|
|
||||||
return lang.replace(/-/g, '_')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取公告内容(支持多语言)
|
// 获取公告内容(支持多语言)
|
||||||
const getNoticeText = async () => {
|
const getNoticeText = async () => {
|
||||||
try {
|
try {
|
||||||
// 获取当前语言设置
|
console.log('加载公告')
|
||||||
const currentLang = uni.getStorageSync('language') || 'zh-CN'
|
|
||||||
const languageCode = convertLanguageCode(currentLang)
|
|
||||||
|
|
||||||
console.log('加载公告,语言:', currentLang, '转换后:', languageCode)
|
|
||||||
|
|
||||||
// 调用接口获取公告内容
|
// 调用接口获取公告内容
|
||||||
const res = await uni.request({
|
const res = await getCurrentAnnouncement({
|
||||||
url: `${URL}/device/announcementConfig/current`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Language': languageCode
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: 'wx_user_type' // 微信小程序用户端
|
type: 'wx_user_type' // 微信小程序用户端
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('公告响应:', res)
|
console.log('公告响应:', res)
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
if (res && res.code === 200 && res.data) {
|
||||||
// 使用后端自动解析的 announcement 字段
|
// 使用后端自动解析的 announcement 字段
|
||||||
const announcement = res.data.data.announcement || ''
|
const announcement = res.data.announcement || ''
|
||||||
noticeText.value = announcement
|
noticeText.value = announcement
|
||||||
|
|
||||||
// 设置通知栏高度
|
// 设置通知栏高度
|
||||||
@@ -342,7 +327,7 @@
|
|||||||
console.warn('缓存通知内容失败:', e)
|
console.warn('缓存通知内容失败:', e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('获取公告失败:', res.data?.msg || '未知错误')
|
console.warn('获取公告失败:', res?.msg || '未知错误')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取公告失败:', error)
|
console.error('获取公告失败:', error)
|
||||||
@@ -352,31 +337,20 @@
|
|||||||
// 获取首页广告图片(支持多语言)
|
// 获取首页广告图片(支持多语言)
|
||||||
const getBannerImages = async () => {
|
const getBannerImages = async () => {
|
||||||
try {
|
try {
|
||||||
// 获取当前语言设置
|
console.log('加载首页广告')
|
||||||
const currentLang = uni.getStorageSync('language') || 'zh-CN'
|
|
||||||
const languageCode = convertLanguageCode(currentLang)
|
|
||||||
|
|
||||||
console.log('加载首页广告,语言:', currentLang, '转换后:', languageCode)
|
|
||||||
|
|
||||||
// 调用接口获取广告内容
|
// 调用接口获取广告内容
|
||||||
const res = await uni.request({
|
const res = await getCurrentAdvertisement({
|
||||||
url: `${URL}/device/advertisementConfig/current`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Language': languageCode
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
appPlatform: 'wechat', // 微信平台
|
appPlatform: 'wechat', // 微信平台
|
||||||
appType: 'user' ,// 用户端
|
appType: 'user' ,// 用户端
|
||||||
pictureLocation:'home_banner'
|
pictureLocation:'home_banner'
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('首页广告响应:', res)
|
console.log('首页广告响应:', res)
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
if (res && res.code === 200 && res.data) {
|
||||||
// 使用 imageList 字段(包含图片和链接信息)
|
// 使用 imageList 字段(包含图片和链接信息)
|
||||||
const imageList = res.data.data.imageList || []
|
const imageList = res.data.imageList || []
|
||||||
if (imageList.length > 0) {
|
if (imageList.length > 0) {
|
||||||
bannerImageList.value = imageList
|
bannerImageList.value = imageList
|
||||||
// 提取图片URL用于展示
|
// 提取图片URL用于展示
|
||||||
@@ -385,7 +359,7 @@
|
|||||||
console.warn('未获取到广告图片')
|
console.warn('未获取到广告图片')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('获取首页广告失败:', res.data?.msg || '未知错误')
|
console.warn('获取首页广告失败:', res?.msg || '未知错误')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取首页广告失败:', error)
|
console.error('获取首页广告失败:', error)
|
||||||
@@ -415,7 +389,7 @@
|
|||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
console.error('跳转小程序失败:', err)
|
console.error('跳转小程序失败:', err)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '跳转失败',
|
title: t('common.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -423,7 +397,7 @@
|
|||||||
// #endif
|
// #endif
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '请在微信小程序中使用',
|
title: t('auth.pleaseUseInWechat'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
@@ -568,10 +542,10 @@
|
|||||||
console.warn('清理旧缓存失败:', e);
|
console.warn('清理旧缓存失败:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开发环境测试距离计算
|
// // 开发环境测试距离计算
|
||||||
if (process.env.NODE_ENV === 'development') {
|
// if (process.env.NODE_ENV === 'development') {
|
||||||
testDistanceCalculation()
|
// testDistanceCalculation()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 并行加载公告和广告(不依赖定位)
|
// 并行加载公告和广告(不依赖定位)
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@@ -586,12 +560,12 @@
|
|||||||
await loadPositions()
|
await loadPositions()
|
||||||
|
|
||||||
// 3. 查询活动并显示弹窗
|
// 3. 查询活动并显示弹窗
|
||||||
await checkActiveActivity()
|
// await checkActiveActivity()
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('初始化失败:', error)
|
console.error('初始化失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('home.getLocationFailed'),
|
title: t('home.getLocationFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -787,12 +761,16 @@
|
|||||||
isRelocating.value = true
|
isRelocating.value = true
|
||||||
|
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('home.relocating'),
|
title: t('home.relocating'),
|
||||||
mask: true
|
mask: true
|
||||||
})
|
})
|
||||||
|
|
||||||
// 重新获取用户真实位置(不使用缓存)
|
// 重新获取用户真实位置
|
||||||
const loc = await getUserLocation()
|
const loc = await getUserLocation()
|
||||||
|
if (!loc || !loc.longitude || !loc.latitude) {
|
||||||
|
throw new Error('location failed')
|
||||||
|
}
|
||||||
|
|
||||||
const newLocation = {
|
const newLocation = {
|
||||||
longitude: Number(loc.longitude),
|
longitude: Number(loc.longitude),
|
||||||
latitude: Number(loc.latitude)
|
latitude: Number(loc.latitude)
|
||||||
@@ -827,7 +805,7 @@
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('home.locateSuccess'),
|
title: t('home.locateSuccess'),
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
duration: 1500
|
duration: 1500
|
||||||
})
|
})
|
||||||
@@ -836,7 +814,7 @@
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: e.errMsg || $t('home.locateFailed'),
|
title: e.errMsg || t('home.locateFailed'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -868,7 +846,7 @@
|
|||||||
|
|
||||||
const selectPosition = (position) => {
|
const selectPosition = (position) => {
|
||||||
uni.showActionSheet({
|
uni.showActionSheet({
|
||||||
itemList: ['扫码使用', '导航前往'],
|
itemList: [t('home.scanToUse'), t('home.navigate')],
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
switch (res.tapIndex) {
|
switch (res.tapIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -948,27 +926,17 @@
|
|||||||
|
|
||||||
if (!deviceNo) {
|
if (!deviceNo) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('home.invalidQRCode'),
|
title: t('home.invalidQRCode'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有使用中的订单
|
// 检查是否有使用中的订单
|
||||||
const inUseRes = await uni.request({
|
const inUseRes = await getInUseOrder()
|
||||||
url: `${URL}/app/order/inUse`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (inUseRes.statusCode === 401 || inUseRes.data?.code === 401 || inUseRes.data?.code === 40101) {
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
redirectToLogin()
|
const inUseOrder = inUseRes.data
|
||||||
return
|
|
||||||
} else if (inUseRes.statusCode == 200 && inUseRes.data.code == 200 && inUseRes.data.data) {
|
|
||||||
const inUseOrder = inUseRes.data.data
|
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
|
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
|
||||||
})
|
})
|
||||||
@@ -976,20 +944,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有待支付订单
|
// 检查是否有待支付订单
|
||||||
const orderRes = await uni.request({
|
const orderRes = await getUnpaidOrder()
|
||||||
url: `${URL}/app/order/unpaid`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (orderRes.statusCode === 401 || orderRes.data?.code === 401 || orderRes.data?.code === 40101) {
|
if (orderRes && orderRes.code === 200 && orderRes.data) {
|
||||||
redirectToLogin()
|
const unpaidOrder = orderRes.data
|
||||||
return
|
|
||||||
} else if (orderRes.statusCode == 200 && orderRes.data.code == 200 && orderRes.data.data) {
|
|
||||||
const unpaidOrder = orderRes.data.data
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||||
})
|
})
|
||||||
@@ -1018,7 +976,7 @@
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '获取设备信息失败',
|
title: t('device.getDeviceInfoFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 外部网页地址
|
// 外部网页地址
|
||||||
const webUrl = ref('https://joininvestment.gxfs123.com/')
|
const webUrl = ref('https://joininvestment.gxfs123.com/')
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
const handleError = (e) => {
|
const handleError = (e) => {
|
||||||
console.error('web-view 加载错误:', e)
|
console.error('web-view 加载错误:', e)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('join.pageLoadFailed'),
|
title: t('join.pageLoadFailed'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('join.title')
|
title: t('join.title')
|
||||||
})
|
})
|
||||||
console.log('招商页面加载,外部网址:', webUrl.value)
|
console.log('招商页面加载,外部网址:', webUrl.value)
|
||||||
})
|
})
|
||||||
|
|||||||
+10
-30
@@ -36,9 +36,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
import { URL } from '@/config/url.js'
|
import { getCurrentAgreement } from '@/config/api/system.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
@@ -50,13 +50,6 @@
|
|||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// 将语言代码转换为后端接受的格式
|
|
||||||
const convertLanguageCode = (lang) => {
|
|
||||||
// zh-CN -> zh-CN (保持不变)
|
|
||||||
// en-US -> en_US (转换下划线)
|
|
||||||
return lang.replace(/-/g, '_')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载协议内容
|
// 加载协议内容
|
||||||
const loadAgreement = async () => {
|
const loadAgreement = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -64,35 +57,22 @@
|
|||||||
errorMessage.value = ''
|
errorMessage.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取当前语言设置
|
console.log('加载用户协议')
|
||||||
const currentLang = uni.getStorageSync('language') || 'zh-CN'
|
|
||||||
const languageCode = convertLanguageCode(currentLang)
|
|
||||||
|
|
||||||
console.log('加载用户协议,语言:', currentLang, '转换后:', languageCode)
|
|
||||||
|
|
||||||
// 调用接口获取协议内容
|
// 调用接口获取协议内容
|
||||||
const res = await uni.request({
|
const res = await getCurrentAgreement({
|
||||||
url: `${URL}/device/agreementConfig/current`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Language': languageCode,
|
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
agreementCode: 'USER_AGREEMENT',
|
agreementCode: 'USER_AGREEMENT',
|
||||||
appPlatform: 'wechat',
|
appPlatform: 'wechat',
|
||||||
appType: 'user'
|
appType: 'user'
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('用户协议响应:', res)
|
console.log('用户协议响应:', res)
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
if (res && res.code === 200 && res.data) {
|
||||||
agreementData.value = {
|
agreementData.value = {
|
||||||
title: res.data.data.title || $t('legal.agreement'),
|
title: res.data.title || t('legal.agreement'),
|
||||||
content: res.data.data.content || '',
|
content: res.data.content || '',
|
||||||
remark: res.data.data.remark || ''
|
remark: res.data.remark || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
@@ -100,12 +80,12 @@
|
|||||||
title: agreementData.value.title
|
title: agreementData.value.title
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.msg || $t('common.loadFailed'))
|
throw new Error(res?.msg || t('common.loadFailed'))
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载用户协议失败:', err)
|
console.error('加载用户协议失败:', err)
|
||||||
error.value = true
|
error.value = true
|
||||||
errorMessage.value = err.message || $t('common.loadFailed')
|
errorMessage.value = err.message || t('common.loadFailed')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-30
@@ -36,9 +36,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
import { URL } from '@/config/url.js'
|
import { getCurrentAgreement } from '@/config/api/system.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
@@ -50,13 +50,6 @@
|
|||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// 将语言代码转换为后端接受的格式
|
|
||||||
const convertLanguageCode = (lang) => {
|
|
||||||
// zh-CN -> zh-CN (保持不变)
|
|
||||||
// en-US -> en_US (转换下划线)
|
|
||||||
return lang.replace(/-/g, '_')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载协议内容
|
// 加载协议内容
|
||||||
const loadAgreement = async () => {
|
const loadAgreement = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -64,35 +57,22 @@
|
|||||||
errorMessage.value = ''
|
errorMessage.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取当前语言设置
|
console.log('加载隐私政策')
|
||||||
const currentLang = uni.getStorageSync('language') || 'zh-CN'
|
|
||||||
const languageCode = convertLanguageCode(currentLang)
|
|
||||||
|
|
||||||
console.log('加载隐私政策,语言:', currentLang, '转换后:', languageCode)
|
|
||||||
|
|
||||||
// 调用接口获取协议内容
|
// 调用接口获取协议内容
|
||||||
const res = await uni.request({
|
const res = await getCurrentAgreement({
|
||||||
url: `${URL}/device/agreementConfig/current`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Language': languageCode,
|
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
agreementCode: 'PRIVACY_POLICY',
|
agreementCode: 'PRIVACY_POLICY',
|
||||||
appPlatform: 'wechat',
|
appPlatform: 'wechat',
|
||||||
appType: 'user'
|
appType: 'user'
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('隐私政策响应:', res)
|
console.log('隐私政策响应:', res)
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
if (res && res.code === 200 && res.data) {
|
||||||
agreementData.value = {
|
agreementData.value = {
|
||||||
title: res.data.data.title || $t('legal.privacy'),
|
title: res.data.title || t('legal.privacy'),
|
||||||
content: res.data.data.content || '',
|
content: res.data.content || '',
|
||||||
remark: res.data.data.remark || ''
|
remark: res.data.remark || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
@@ -100,12 +80,12 @@
|
|||||||
title: agreementData.value.title
|
title: agreementData.value.title
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.msg || $t('common.loadFailed'))
|
throw new Error(res?.msg || t('common.loadFailed'))
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载隐私政策失败:', err)
|
console.error('加载隐私政策失败:', err)
|
||||||
error.value = true
|
error.value = true
|
||||||
errorMessage.value = err.message || $t('common.loadFailed')
|
errorMessage.value = err.message || t('common.loadFailed')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-17
@@ -16,8 +16,10 @@
|
|||||||
{{ $t('auth.getPhoneNumber') }}
|
{{ $t('auth.getPhoneNumber') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- 仅微信登录(不授权手机号时使用) -->
|
<!-- 手机号验证码登录 -->
|
||||||
<!-- <button class="btn outline" @click="onWeChatLogin">仅微信登录</button> -->
|
<button class="btn outline" @click="goToPhoneLogin" v-if="isHTML5">
|
||||||
|
{{ $t('auth.phoneLogin') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
<view class="agreement-box">
|
<view class="agreement-box">
|
||||||
<checkbox-group @change="onAgreementChange">
|
<checkbox-group @change="onAgreementChange">
|
||||||
@@ -41,22 +43,23 @@
|
|||||||
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('auth.loginTitle')
|
title: t('auth.loginTitle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isHTML5 = ref(false) // 是否是HTML5模式
|
||||||
|
|
||||||
const redirect = ref('/pages/index/index')
|
const redirect = ref('/pages/index/index')
|
||||||
const isAgreed = ref(false) // 是否同意协议
|
const isAgreed = ref(false) // 是否同意协议
|
||||||
|
|
||||||
// 勾选协议变化
|
// 勾选协议变化
|
||||||
const onAgreementChange = (e) => {
|
const onAgreementChange = (e) => {
|
||||||
isAgreed.value = e.detail.value.includes('agreed')
|
isAgreed.value = e.detail.value.includes('agreed')
|
||||||
console.log('协议勾选状态:', isAgreed.value, e.detail.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未勾选协议时点击登录按钮
|
// 未勾选协议时点击登录按钮
|
||||||
@@ -79,10 +82,10 @@
|
|||||||
|
|
||||||
// 未勾选,弹窗提示
|
// 未勾选,弹窗提示
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('common.tips'),
|
title: t('common.tips'),
|
||||||
content: $t('auth.pleaseAgreeToTerms'),
|
content: t('auth.pleaseAgreeToTerms'),
|
||||||
confirmText: $t('common.confirm'),
|
confirmText: t('common.confirm'),
|
||||||
cancelText: $t('common.cancel'),
|
cancelText: t('common.cancel'),
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// 用户点击同意,自动勾选
|
// 用户点击同意,自动勾选
|
||||||
@@ -90,7 +93,7 @@
|
|||||||
resolve()
|
resolve()
|
||||||
} else {
|
} else {
|
||||||
// 用户点击取消
|
// 用户点击取消
|
||||||
reject(new Error('需要同意协议才能登录'))
|
reject(new Error(t('auth.pleaseAgreeToTerms')))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -119,18 +122,18 @@
|
|||||||
await checkAgreement()
|
await checkAgreement()
|
||||||
|
|
||||||
await wxLogin()
|
await wxLogin()
|
||||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
uni.showToast({ title: t('auth.loginSuccess'), icon: 'success' })
|
||||||
await navigateAfterLogin()
|
await navigateAfterLogin()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.message !== '需要同意协议才能登录') {
|
if (error.message !== t('auth.pleaseAgreeToTerms')) {
|
||||||
uni.showToast({ title: error.message || '登录失败', icon: 'none' })
|
uni.showToast({ title: error.message || t('auth.loginFailed'), icon: 'none' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onGetPhoneNumber = async (e) => {
|
const onGetPhoneNumber = async (e) => {
|
||||||
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
|
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||||
uni.showToast({ title: $t('auth.phoneCancelled'), icon: 'none' })
|
uni.showToast({ title: t('auth.phoneCancelled'), icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,10 +142,10 @@
|
|||||||
await wxLogin()
|
await wxLogin()
|
||||||
// 再用微信返回的临时 code 换取手机号
|
// 再用微信返回的临时 code 换取手机号
|
||||||
await getUserPhoneNumber(e.detail.code)
|
await getUserPhoneNumber(e.detail.code)
|
||||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
uni.showToast({ title: t('auth.loginSuccess'), icon: 'success' })
|
||||||
await navigateAfterLogin()
|
await navigateAfterLogin()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.showToast({ title: error.message || $t('auth.loginFailed'), icon: 'none' })
|
uni.showToast({ title: error.message || t('auth.loginFailed'), icon: 'none' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,17 +155,25 @@
|
|||||||
redirect.value = decodeURIComponent(opts.redirect)
|
redirect.value = decodeURIComponent(opts.redirect)
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
// #ifdef H5
|
||||||
|
isHTML5.value = true
|
||||||
|
// #endif
|
||||||
})
|
})
|
||||||
|
|
||||||
const go = (url) => {
|
const go = (url) => {
|
||||||
uni.navigateTo({ url })
|
uni.navigateTo({ url })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 跳转到手机号登录页面
|
||||||
|
const goToPhoneLogin = () => {
|
||||||
|
uni.navigateTo({ url: '/pages/login/phone' })
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login-container {
|
.login-container {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f8f8f8;
|
background: linear-gradient(180deg, #C8F4D9 0%, #FFFFFF 100%);
|
||||||
padding: 80rpx 40rpx 40rpx;
|
padding: 80rpx 40rpx 40rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -0,0 +1,394 @@
|
|||||||
|
<template>
|
||||||
|
<view class="login-container">
|
||||||
|
<view class="header">
|
||||||
|
<view class="title">Hello,</view>
|
||||||
|
<view class="subtitle">{{ $t('app.welcome') }}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 国家区号选择器 -->
|
||||||
|
<view class="form-group">
|
||||||
|
<view class="phone-input-wrapper">
|
||||||
|
<view class="country-code" @click="showCountryPicker">
|
||||||
|
<text>{{ countryCode }}</text>
|
||||||
|
<text class="arrow">▼</text>
|
||||||
|
</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
<input
|
||||||
|
class="phone-input"
|
||||||
|
v-model="phone"
|
||||||
|
type="number"
|
||||||
|
maxlength="11"
|
||||||
|
:placeholder="$t('auth.phonePlaceholder')"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 验证码输入 -->
|
||||||
|
<view class="form-group">
|
||||||
|
<view class="code-input-wrapper">
|
||||||
|
<input
|
||||||
|
class="code-input"
|
||||||
|
v-model="verifyCode"
|
||||||
|
type="number"
|
||||||
|
maxlength="6"
|
||||||
|
:placeholder="$t('auth.codePlaceholder')"
|
||||||
|
/>
|
||||||
|
<view class="code-btn" @click="handleSendCode" :class="{ disabled: countdown > 0 }">
|
||||||
|
<text class="code-btn-text">{{ countdown > 0 ? `${countdown}s` : $t('auth.getCode') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 区域提示 -->
|
||||||
|
<view class="region-notice">
|
||||||
|
<text>{{ $t('auth.regionNotSupported') }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 登录按钮 -->
|
||||||
|
<view class="login-btn" @click="handleLogin">
|
||||||
|
<text class="login-btn-text">{{ $t('auth.loginBtn') }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 协议勾选 -->
|
||||||
|
<view class="agreement-box">
|
||||||
|
<checkbox-group @change="onAgreementChange">
|
||||||
|
<label class="agreement-label">
|
||||||
|
<checkbox value="agreed" :checked="isAgreed" color="#07c160" class="agreement-checkbox" />
|
||||||
|
<text class="agreement-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>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { sendVerifyCode, loginWithCode } from '@/config/api/user.js'
|
||||||
|
import { fetchAndCacheCustomerPhone } from '@/util/index.js'
|
||||||
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 设置页面标题
|
||||||
|
onMounted(() => {
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: t('auth.phoneLogin')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const redirect = ref('/pages/index/index')
|
||||||
|
const isAgreed = ref(false) // 是否同意协议
|
||||||
|
const phone = ref('') // 手机号
|
||||||
|
const verifyCode = ref('') // 验证码
|
||||||
|
const countryCode = ref('+86') // 国家区号
|
||||||
|
const countdown = ref(0) // 验证码倒计时
|
||||||
|
let timer = null // 计时器
|
||||||
|
|
||||||
|
// 勾选协议变化
|
||||||
|
const onAgreementChange = (e) => {
|
||||||
|
isAgreed.value = e.detail.value.includes('agreed')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示国家区号选择器(暂时仅支持+86)
|
||||||
|
const showCountryPicker = () => {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('auth.onlyMainlandSupported'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证手机号格式
|
||||||
|
const validatePhone = () => {
|
||||||
|
if (!phone.value) {
|
||||||
|
uni.showToast({ title: t('auth.phoneRequired'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const phoneReg = /^1[3-9]\d{9}$/
|
||||||
|
if (!phoneReg.test(phone.value)) {
|
||||||
|
uni.showToast({ title: t('auth.phoneInvalid'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
const handleSendCode = async () => {
|
||||||
|
if (countdown.value > 0) return
|
||||||
|
|
||||||
|
if (!validatePhone()) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: t('common.sending') })
|
||||||
|
await sendVerifyCode(phone.value)
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: t('auth.codeSent'), icon: 'success' })
|
||||||
|
|
||||||
|
// 启动60秒倒计时
|
||||||
|
countdown.value = 60
|
||||||
|
timer = setInterval(() => {
|
||||||
|
countdown.value--
|
||||||
|
if (countdown.value <= 0) {
|
||||||
|
clearInterval(timer)
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('auth.sendCodeFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
const handleLogin = async () => {
|
||||||
|
if (!validatePhone()) return
|
||||||
|
|
||||||
|
if (!verifyCode.value) {
|
||||||
|
uni.showToast({ title: t('auth.codeRequired'), icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAgreed.value) {
|
||||||
|
uni.showToast({ title: t('auth.pleaseAgreeToTerms'), icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: t('common.loggingIn') })
|
||||||
|
const res = await loginWithCode(phone.value, verifyCode.value)
|
||||||
|
|
||||||
|
// 保存token和client_id
|
||||||
|
// 兼容多种返回格式:res.data.token, res.token, res.data.access_token
|
||||||
|
const token = res.token || (res.data && (res.data.token || res.data.access_token))
|
||||||
|
const clientId = res.client_id || (res.data && (res.data.client_id || res.data.clientId))
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
uni.setStorageSync('token', token)
|
||||||
|
if (clientId) {
|
||||||
|
uni.setStorageSync('client_id', clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录成功后获取并缓存客服电话
|
||||||
|
fetchAndCacheCustomerPhone().catch(err => {
|
||||||
|
console.error(t('auth.getServicePhoneFailed'), err)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(t('auth.noAuthToken'))
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: t('auth.loginSuccess'), icon: 'success' })
|
||||||
|
|
||||||
|
// 跳转到首页
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.reLaunch({ url: redirect.value })
|
||||||
|
}, 1500)
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('auth.loginFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载
|
||||||
|
onLoad((opts) => {
|
||||||
|
if (opts && opts.redirect) {
|
||||||
|
try {
|
||||||
|
redirect.value = decodeURIComponent(opts.redirect)
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const go = (url) => {
|
||||||
|
uni.navigateTo({ url })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理定时器
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer)
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: linear-gradient(180deg, #C8F4D9 0%, #FFFFFF 100%);
|
||||||
|
padding: 0 48rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding-top: 120rpx;
|
||||||
|
margin-bottom: 80rpx;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 64rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 64rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
|
||||||
|
.phone-input-wrapper {
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-radius: 48rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.country-code {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
padding-right: 16rpx;
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: 8rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 2rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
background: #E5E5E5;
|
||||||
|
margin: 0 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-input-wrapper {
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-radius: 48rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.code-input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-btn {
|
||||||
|
padding-left: 24rpx;
|
||||||
|
border-left: 2rpx solid #E5E5E5;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-btn-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #07c160;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-notice {
|
||||||
|
margin-bottom: 48rpx;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666666;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
background: #07c160;
|
||||||
|
border-radius: 60rpx;
|
||||||
|
height: 112rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
|
||||||
|
margin-bottom: 48rpx;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn-text {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-box {
|
||||||
|
position: absolute;
|
||||||
|
left: 48rpx;
|
||||||
|
right: 48rpx;
|
||||||
|
bottom: 60rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.agreement-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.agreement-checkbox {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transform: scale(0.75);
|
||||||
|
margin-right: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.8;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: #07c160;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+344
-110
@@ -2,30 +2,63 @@
|
|||||||
<view class="my-card-page">
|
<view class="my-card-page">
|
||||||
<!-- 会员卡列表 -->
|
<!-- 会员卡列表 -->
|
||||||
<view class="card-list" v-if="cardList.length > 0">
|
<view class="card-list" v-if="cardList.length > 0">
|
||||||
<view v-for="card in cardList" :key="card.id" class="card-item" @click="viewCardDetail(card)">
|
<view v-for="card in cardList" :key="card.id" style="position: relative;background-color: #f5f5f5;"
|
||||||
|
@click="viewCardDetail(card)" :style="card.cardType==='COUNT'?'height: 240rpx;':'height: 200rpx;'">
|
||||||
|
<view
|
||||||
|
style="height: 120rpx;background-color: #ffffff;z-index: 999;border-radius: 25rpx;padding: 32rpx;position: absolute;top: 0;left: 0;right: 0;">
|
||||||
|
<!-- 卡片头部:标题和日期 -->
|
||||||
<view class="card-header">
|
<view class="card-header">
|
||||||
<text class="card-name">{{ card.name }}</text>
|
<text class="card-name">{{ card.name }}</text>
|
||||||
<view class="card-status" :class="getStatusClass(card.status)">
|
<view class="card-date">
|
||||||
|
<text class="date-text" v-if="card.status !== 'expired'">{{ card.endDate }}{{
|
||||||
|
$t('myCard.expire') }}</text>
|
||||||
|
<text class="date-text expired" v-else>{{ $t('myCard.expiredOn') }}{{ card.endDate }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 地区信息 -->
|
||||||
|
<view class="card-region">
|
||||||
|
<text
|
||||||
|
class="region-text">{{ $t('myCard.onlyForRegionBefore') }}{{ card.positionName }}{{ $t('myCard.onlyForRegionAfter') }}</text>
|
||||||
|
<!-- 状态标签 / 去使用按钮 -->
|
||||||
|
<view v-if="card.status !== 'expired'" class="status-tag active"
|
||||||
|
style="display: flex; align-items: center; gap: 4rpx; background-color: #FFE2B8; border-radius: 26rpx; padding: 6rpx 20rpx;"
|
||||||
|
@click.stop="handleUseCard(card)">
|
||||||
|
<text class="status-text" style="color: #D4A574;">{{ $t('myCard.toUse') }}</text>
|
||||||
|
<!-- <uv-icon name="scan" size="12" color="#D4A574"></uv-icon> -->
|
||||||
|
</view>
|
||||||
|
<view v-else class="status-tag" :class="getStatusClass(card.status)">
|
||||||
<text class="status-text">{{ getStatusText(card.status) }}</text>
|
<text class="status-text">{{ getStatusText(card.status) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info">
|
|
||||||
<text class="info-label">{{ $t('myCard.type') }}:</text>
|
|
||||||
<text class="info-value">{{ card.cardType === 'COUNT' ? $t('myCard.timesCard') :
|
|
||||||
$t('myCard.durationCard') }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info" v-if="card.type === 'times'">
|
<!-- 使用情况和操作按钮 -->
|
||||||
<text class="info-label">{{ $t('myCard.remainingTimes') }}:</text>
|
<view style="position: absolute; bottom: -10rpx; left: 0; right: 0; padding: 20rpx;z-index:1;"
|
||||||
<text class="info-value highlight">{{ card.remainingTimes }}/{{ card.totalTimes }}</text>
|
v-if="card.cardType==='COUNT'">
|
||||||
|
<view class="card-footer">
|
||||||
|
<!-- 次卡信息 -->
|
||||||
|
<view v-if="card.cardType === 'COUNT'" class="card-usage-info">
|
||||||
|
<text class="usage-text">{{ $t('myCard.remainingTimes') }}{{ card.remainingCount }}{{
|
||||||
|
$t('myCard.times') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info" v-if="card.type === 'duration'">
|
<!-- 时长卡信息 -->
|
||||||
<text class="info-label">{{ $t('myCard.remainingDuration') }}:</text>
|
<view v-if="card.cardType === 'TIME'" class="card-usage-info">
|
||||||
<text class="info-value highlight">{{ card.remainingDuration }}{{ $t('myCard.hours') }}</text>
|
<text class="usage-text">{{ $t('myCard.durationCard') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info">
|
|
||||||
<text class="info-label">{{ $t('myCard.validPeriod') }}:</text>
|
<!-- 操作按钮 -->
|
||||||
<text class="info-value">{{ card.startDate }} - {{ card.endDate }}</text>
|
<view class="card-actions">
|
||||||
|
<!-- 续卡按钮(仅次卡显示) -->
|
||||||
|
<view v-if="card.cardType === 'COUNT'" class="renew-btn" @click.stop="renewCard(card)">
|
||||||
|
<text class="renew-text">{{ $t('myCard.renew') }}</text>
|
||||||
|
<uv-icon name="arrow-right" size="14" color="#D4A574"></uv-icon>
|
||||||
|
<!-- <text class="arrow">{{ '>' }}</text> -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -41,18 +74,35 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import {
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
ref,
|
||||||
import {
|
onMounted
|
||||||
|
} from 'vue'
|
||||||
|
import {
|
||||||
|
useI18n
|
||||||
|
} from '@/utils/i18n.js'
|
||||||
|
import {
|
||||||
getMemberCardsByStatus
|
getMemberCardsByStatus
|
||||||
} from '@/config/api/member.js'
|
} from '@/config/api/member.js'
|
||||||
const { t: $t } = useI18n()
|
import {
|
||||||
|
getQueryString
|
||||||
|
} from '@/util/index.js'
|
||||||
|
import {
|
||||||
|
getDeviceInfo
|
||||||
|
} from '@/config/api/device.js'
|
||||||
|
import {
|
||||||
|
getInUseOrder,
|
||||||
|
getUnpaidOrder
|
||||||
|
} from '@/config/api/order.js'
|
||||||
|
const {
|
||||||
|
t
|
||||||
|
} = useI18n()
|
||||||
|
|
||||||
// 会员卡列表
|
// 会员卡列表
|
||||||
const cardList = ref([])
|
const cardList = ref([])
|
||||||
|
|
||||||
// 获取会员卡列表
|
// 获取会员卡列表
|
||||||
const getCardList = async () => {
|
const getCardList = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await getMemberCardsByStatus()
|
const response = await getMemberCardsByStatus()
|
||||||
// 处理API返回的数据,转换为模板需要的格式
|
// 处理API返回的数据,转换为模板需要的格式
|
||||||
@@ -60,17 +110,25 @@ const getCardList = async () => {
|
|||||||
cardList.value = response.data.map(item => ({
|
cardList.value = response.data.map(item => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.cardName,
|
name: item.cardName,
|
||||||
cardType: item.cardType, // TIME -> time
|
cardType: item.cardType, // TIME 或 COUNT
|
||||||
totalTimes: item.totalCount,
|
// 次卡相关
|
||||||
remainingTimes: item.remainingCount,
|
totalCount: item.totalCount,
|
||||||
remainingDuration: item.singleLimitMinutes,
|
remainingCount: item.remainingCount,
|
||||||
|
singleLimitMinutesForCount: item.singleLimitMinutesForCount,
|
||||||
|
// 时长卡相关
|
||||||
|
cycleDays: item.cycleDays,
|
||||||
|
dailyLimitCount: item.dailyLimitCount,
|
||||||
|
singleLimitMinutes: item.singleLimitMinutes,
|
||||||
|
currentCycleStartTime: item.currentCycleStartTime,
|
||||||
|
currentCycleUsedCount: item.currentCycleUsedCount,
|
||||||
|
// 通用信息
|
||||||
status: item.status,
|
status: item.status,
|
||||||
startDate: item.startTime,
|
startDate: item.startTime?.split(' ')[0] || item.startTime,
|
||||||
endDate: item.endTime,
|
endDate: item.endTime?.split(' ')[0] || item.endTime,
|
||||||
|
positionId: item.positionId,
|
||||||
positionName: item.positionName,
|
positionName: item.positionName,
|
||||||
purchasePrice: item.purchasePrice,
|
purchasePrice: item.purchasePrice,
|
||||||
// 添加可能的其他字段
|
remark: item.remark
|
||||||
...item
|
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
cardList.value = []
|
cardList.value = []
|
||||||
@@ -78,14 +136,21 @@ const getCardList = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取会员卡列表失败:', error)
|
console.error('获取会员卡列表失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('myCard.getListFailed'),
|
title: t('myCard.getListFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取状态类名
|
// 计算进度条宽度
|
||||||
const getStatusClass = (status) => {
|
const getProgressWidth = (used, total) => {
|
||||||
|
if (!total || total === 0) return '0%'
|
||||||
|
const percentage = (used / total) * 100
|
||||||
|
return `${Math.min(percentage, 100)}%`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取状态类名
|
||||||
|
const getStatusClass = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'unused': 'active',
|
'unused': 'active',
|
||||||
'expired': 'expired',
|
'expired': 'expired',
|
||||||
@@ -93,121 +158,290 @@ const getStatusClass = (status) => {
|
|||||||
'active': 'active' // 兼容原始状态
|
'active': 'active' // 兼容原始状态
|
||||||
}
|
}
|
||||||
return statusMap[status] || 'active' // 默认为active
|
return statusMap[status] || 'active' // 默认为active
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
|
||||||
const getStatusText = (status) => {
|
|
||||||
const statusMap = {
|
|
||||||
'unused': $t('myCard.active'), // unused表示未使用,即活跃状态
|
|
||||||
'expired': $t('myCard.expired'),
|
|
||||||
'used': $t('myCard.used'),
|
|
||||||
'active': $t('myCard.active') // 兼容原始状态
|
|
||||||
}
|
}
|
||||||
return statusMap[status] || $t('myCard.active') // 默认为active
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看卡详情
|
// 获取状态文本
|
||||||
const viewCardDetail = (card) => {
|
const getStatusText = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'unused': t('myCard.active'), // unused表示未使用,即活跃状态
|
||||||
|
'expired': t('myCard.expired'),
|
||||||
|
'used': t('myCard.used'),
|
||||||
|
'active': t('myCard.active') // 兼容原始状态
|
||||||
|
}
|
||||||
|
return statusMap[status] || t('myCard.active') // 默认为active
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看卡详情
|
||||||
|
const viewCardDetail = (card) => {
|
||||||
// TODO: 跳转到卡详情页面
|
// TODO: 跳转到卡详情页面
|
||||||
// uni.showToast({
|
// uni.showToast({
|
||||||
// title: $t('common.functionDeveloping'),
|
// title: t('common.functionDeveloping'),
|
||||||
// icon: 'none'
|
// icon: 'none'
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去购买
|
// 续卡
|
||||||
const goToBuy = () => {
|
const renewCard = (card) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/purchase/index?positionId=${card.positionId}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去使用会员卡
|
||||||
|
const handleUseCard = async (card) => {
|
||||||
|
try {
|
||||||
|
const scanResult = await new Promise((resolve, reject) => {
|
||||||
|
uni.scanCode({
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('扫码结果:', scanResult);
|
||||||
|
let deviceNo;
|
||||||
|
// 兼容不同平台的扫码结果
|
||||||
|
if (scanResult.scanType === 'QR_CODE' || scanResult.scanType === 'qrCode') {
|
||||||
|
deviceNo = getQueryString(scanResult.result, 'deviceNo')
|
||||||
|
} else if (scanResult.path) {
|
||||||
|
deviceNo = getQueryString(scanResult.path, 'deviceNo')
|
||||||
|
} else {
|
||||||
|
deviceNo = scanResult.result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceNo) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('home.invalidQRCode'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({
|
||||||
|
title: t('common.getting')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查是否有使用中的订单
|
||||||
|
const inUseRes = await getInUseOrder()
|
||||||
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const inUseOrder = inUseRes.data
|
||||||
|
uni.reLaunch({
|
||||||
|
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有待支付订单
|
||||||
|
const orderRes = await getUnpaidOrder()
|
||||||
|
if (orderRes && orderRes.code === 200 && orderRes.data) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const unpaidOrder = orderRes.data
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备信息并跳转详情
|
||||||
|
const deviceInfoRes = await getDeviceInfo(deviceNo)
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (deviceInfoRes.code === 200 && deviceInfoRes.data && deviceInfoRes.data.device) {
|
||||||
|
const deviceInfo = deviceInfoRes.data.device
|
||||||
|
let url = `/pages/device/detail?deviceNo=${deviceNo}`
|
||||||
|
if (deviceInfo.feeConfig) {
|
||||||
|
url += `&feeConfig=${encodeURIComponent(deviceInfo.feeConfig)}`
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/device/detail?deviceNo=${deviceNo}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('扫码处理失败:', error)
|
||||||
|
if (error && error.errMsg !== 'scanCode:fail cancel') {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('home.scanFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去购买
|
||||||
|
const goToBuy = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/purchase/index'
|
url: '/pages/purchase/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('user.myCards')
|
title: t('user.myCards')
|
||||||
})
|
})
|
||||||
getCardList()
|
getCardList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.my-card-page {
|
.my-card-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
padding: 20rpx;
|
padding: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-list {
|
.card-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20rpx;
|
gap: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-item {
|
.card-item {
|
||||||
background-color: #ffffff;
|
// background-color: #ffffff;
|
||||||
border-radius: 20rpx;
|
border-radius: 25rpx;
|
||||||
padding: 30rpx;
|
padding: 32rpx;
|
||||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
|
||||||
.card-header {
|
}
|
||||||
|
|
||||||
|
// 卡片头部
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-name {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333333;
|
||||||
|
line-height: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-date {
|
||||||
|
.date-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
line-height: 34rpx;
|
||||||
|
|
||||||
|
&.expired {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地区信息
|
||||||
|
.card-region {
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
|
||||||
|
.region-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666666;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片底部
|
||||||
|
.card-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20rpx;
|
/* padding-top: 24rpx ; */
|
||||||
padding-bottom: 20rpx;
|
position: absolute;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
background: rgba(255, 244, 227, 1);
|
||||||
}
|
z-index: 1;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
border-radius: 0 0 25rpx 25rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
/* text-align: 30rpx ; */
|
||||||
|
}
|
||||||
|
|
||||||
.card-name {
|
.card-usage-info {
|
||||||
font-size: 32rpx;
|
flex: 1;
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-status {
|
.usage-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #D4A574;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续卡按钮
|
||||||
|
.renew-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4rpx;
|
||||||
padding: 8rpx 16rpx;
|
padding: 8rpx 16rpx;
|
||||||
border-radius: 20rpx;
|
// background-color: #FFF9F0;
|
||||||
font-size: 22rpx;
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.renew-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #D4A574;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #D4A574;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态标签
|
||||||
|
.status-tag {
|
||||||
|
padding: 8rpx 20rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: #e8f5e8;
|
// background-color: #FFF9F0;
|
||||||
color: #4caf50;
|
|
||||||
|
.status-text {
|
||||||
|
color: #D4A574;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.expired {
|
&.expired {
|
||||||
background-color: #ffeaea;
|
// background-color: #F5F5F5;
|
||||||
color: #f44336;
|
|
||||||
|
.status-text {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.used {
|
&.used {
|
||||||
background-color: #f0f0f0;
|
// background-color: #F5F5F5;
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-info {
|
.status-text {
|
||||||
display: flex;
|
color: #999999;
|
||||||
align-items: center;
|
}
|
||||||
margin-bottom: 12rpx;
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #333;
|
|
||||||
|
|
||||||
&.highlight {
|
|
||||||
color: #FF6B00;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -238,5 +472,5 @@ onMounted(() => {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
+275
-156
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="my-coupon-page">
|
<view class="my-coupon-page">
|
||||||
<!-- Tab 切换 -->
|
<!-- Tab 切换 -->
|
||||||
<view class="tab-container">
|
<!-- <view class="tab-container">
|
||||||
<view class="tab-item" :class="{ active: currentTab === 'available' }" @click="switchTab('available')">
|
<view class="tab-item" :class="{ active: currentTab === 'available' }" @click="switchTab('available')">
|
||||||
<text class="tab-text">{{ $t('myCoupon.available') }}</text>
|
<text class="tab-text">{{ $t('myCoupon.available') }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -11,25 +11,35 @@
|
|||||||
<view class="tab-item" :class="{ active: currentTab === 'expired' }" @click="switchTab('expired')">
|
<view class="tab-item" :class="{ active: currentTab === 'expired' }" @click="switchTab('expired')">
|
||||||
<text class="tab-text">{{ $t('myCoupon.expired') }}</text>
|
<text class="tab-text">{{ $t('myCoupon.expired') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view> -->
|
||||||
|
|
||||||
<!-- 优惠券列表 -->
|
<!-- 优惠券列表 -->
|
||||||
<view class="coupon-list" v-if="filteredCoupons.length > 0">
|
<view class="coupon-list" v-if="filteredCoupons.length > 0">
|
||||||
<view v-for="coupon in filteredCoupons" :key="coupon.id" class="coupon-item-wrapper">
|
<view v-for="coupon in filteredCoupons" :key="coupon.id" class="coupon-item-wrapper">
|
||||||
<view class="coupon-item" :class="getCouponClass(coupon.status)">
|
<view class="coupon-item" :class="getCouponClass(coupon.status)">
|
||||||
<!-- 左侧圆形缺口 -->
|
|
||||||
<view class="coupon-circle-left"></view>
|
<!-- 虚线上下圆形缺口 -->
|
||||||
<!-- 右侧圆形缺口 -->
|
<view class="coupon-circle-top"></view>
|
||||||
<view class="coupon-circle-right"></view>
|
<view class="coupon-circle-bottom"></view>
|
||||||
|
|
||||||
<view class="coupon-left">
|
<view class="coupon-left">
|
||||||
<text class="coupon-value">{{ coupon.type === 'discount' ? coupon.discount + '折' : '¥' + coupon.value }}</text>
|
<view class="coupon-value">
|
||||||
|
<text v-if="coupon.type === 'cash'" class="coupon-unit">¥</text>
|
||||||
|
<text class="coupon-amount">{{ coupon.type === 'discount' ? coupon.discount : coupon.value }}</text>
|
||||||
|
<text v-if="coupon.type === 'discount'" class="coupon-unit">折</text>
|
||||||
|
</view>
|
||||||
|
<view style="display: flex;flex-direction: column;">
|
||||||
<text class="coupon-condition">{{ coupon.condition }}</text>
|
<text class="coupon-condition">{{ coupon.condition }}</text>
|
||||||
<text class="coupon-validity-left">{{ coupon.validity }}</text>
|
<text class="coupon-validity-left">{{ coupon.validity }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<view class="coupon-divider"></view>
|
<view class="coupon-divider"></view>
|
||||||
<view class="coupon-right">
|
<view class="coupon-right">
|
||||||
<text class="coupon-name">{{ coupon.name }}</text>
|
<!-- <text class="coupon-name">{{ coupon.name }}</text> -->
|
||||||
|
<!-- <text class="coupon-region" v-if="coupon.positionName"
|
||||||
|
style="font-size: 22rpx; color: #999; margin-top: 4rpx;">
|
||||||
|
{{ $t('myCoupon.onlyForRegionBefore') }}{{ coupon.positionName }}{{ $t('myCoupon.onlyForRegionAfter') }}
|
||||||
|
</text> -->
|
||||||
<view class="use-btn" v-if="coupon.status === 'available'" @click="useCoupon(coupon)">
|
<view class="use-btn" v-if="coupon.status === 'available'" @click="useCoupon(coupon)">
|
||||||
<text class="use-text">{{ $t('myCoupon.useNow') }}</text>
|
<text class="use-text">{{ $t('myCoupon.useNow') }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -51,35 +61,38 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
import { getUserCoupons } from '@/config/api/coupon.js'
|
import { getUserCoupons } from '@/config/api/coupon.js'
|
||||||
|
import { getQueryString } from '@/util/index.js'
|
||||||
|
import { getDeviceInfo } from '@/config/api/device.js'
|
||||||
|
import { getInUseOrder, getUnpaidOrder } from '@/config/api/order.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 当前选中的 Tab
|
// 当前选中的 Tab
|
||||||
const currentTab = ref('available')
|
const currentTab = ref('available')
|
||||||
|
|
||||||
// Tab 与 API 状态的映射
|
// // Tab 与 API 状态的映射
|
||||||
const tabToStatusMap = {
|
// const tabToStatusMap = {
|
||||||
available: 'unused',
|
// available: 'unused',
|
||||||
used: 'used',
|
// used: 'used',
|
||||||
expired: 'expired'
|
// expired: 'expired'
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 优惠券列表
|
// 优惠券列表
|
||||||
const couponList = ref([])
|
const couponList = ref([])
|
||||||
|
|
||||||
// 过滤后的优惠券
|
// 过滤后的优惠券
|
||||||
const filteredCoupons = computed(() => {
|
const filteredCoupons = computed(() => {
|
||||||
return couponList.value.filter(coupon => coupon.status === currentTab.value)
|
return couponList.value.filter(coupon => coupon.status === currentTab.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取优惠券列表
|
// 获取优惠券列表
|
||||||
const getCouponList = async () => {
|
const getCouponList = async () => {
|
||||||
try {
|
try {
|
||||||
const apiStatus = tabToStatusMap[currentTab.value]
|
// const apiStatus = tabToStatusMap[currentTab.value]
|
||||||
const res = await getUserCoupons(apiStatus)
|
const res = await getUserCoupons('')
|
||||||
|
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
// 将后端数据转换为前端需要的格式
|
// 将后端数据转换为前端需要的格式
|
||||||
@@ -96,10 +109,10 @@
|
|||||||
// 格式化有效期
|
// 格式化有效期
|
||||||
let validity = ''
|
let validity = ''
|
||||||
if (currentTab.value === 'used') {
|
if (currentTab.value === 'used') {
|
||||||
// 已使用显示使用时间(这里暂用开始时间,如后端有使用时间字段可替换)
|
// 已使用显示使用时间
|
||||||
validity = item.couponStartTime ? `使用时间 ${item.couponStartTime}` : ''
|
validity = item.couponStartTime ? `使用时间 ${item.couponStartTime.split(' ')[0]}` : ''
|
||||||
} else if (item.couponEndTime) {
|
} else if (item.couponEndTime) {
|
||||||
validity = `有效期至 ${item.couponEndTime}`
|
validity = `于 ${item.couponEndTime.split(' ')[0]} 过期`
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -110,7 +123,8 @@
|
|||||||
discount: item.discountRate ? parseFloat(item.discountRate) * 10 : null,
|
discount: item.discountRate ? parseFloat(item.discountRate) * 10 : null,
|
||||||
condition: condition,
|
condition: condition,
|
||||||
validity: validity,
|
validity: validity,
|
||||||
status: currentTab.value
|
status: currentTab.value,
|
||||||
|
positionName: item.positionName
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -120,82 +134,167 @@
|
|||||||
console.error('获取优惠券列表失败:', error)
|
console.error('获取优惠券列表失败:', error)
|
||||||
couponList.value = []
|
couponList.value = []
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('myCoupon.getListFailed'),
|
title: t('myCoupon.getListFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换 Tab
|
||||||
|
const switchTab = (tab) => {
|
||||||
|
currentTab.value = tab
|
||||||
|
getCouponList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取优惠券样式类名
|
||||||
|
const getCouponClass = (status) => {
|
||||||
|
return status === 'available' ? '' : 'disabled'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
const getStatusText = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'used': t('myCoupon.usedStatus'),
|
||||||
|
'expired': t('myCoupon.expiredStatus')
|
||||||
|
}
|
||||||
|
return statusMap[status] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取空状态文本
|
||||||
|
const getEmptyText = () => {
|
||||||
|
const textMap = {
|
||||||
|
'available': t('myCoupon.noAvailableCoupons'),
|
||||||
|
'used': t('myCoupon.noUsedCoupons'),
|
||||||
|
'expired': t('myCoupon.noExpiredCoupons')
|
||||||
|
}
|
||||||
|
return textMap[currentTab.value] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用优惠券
|
||||||
|
const useCoupon = async (coupon) => {
|
||||||
|
try {
|
||||||
|
const scanResult = await new Promise((resolve, reject) => {
|
||||||
|
uni.scanCode({
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('扫码结果:', scanResult);
|
||||||
|
let deviceNo;
|
||||||
|
// 兼容不同平台的扫码结果
|
||||||
|
if (scanResult.scanType === 'QR_CODE' || scanResult.scanType === 'qrCode') {
|
||||||
|
deviceNo = getQueryString(scanResult.result, 'deviceNo')
|
||||||
|
} else if (scanResult.path) {
|
||||||
|
deviceNo = getQueryString(scanResult.path, 'deviceNo')
|
||||||
|
} else {
|
||||||
|
deviceNo = scanResult.result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceNo) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('home.invalidQRCode'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({
|
||||||
|
title: t('common.getting')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查是否有使用中的订单
|
||||||
|
const inUseRes = await getInUseOrder()
|
||||||
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const inUseOrder = inUseRes.data
|
||||||
|
uni.reLaunch({
|
||||||
|
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有待支付订单
|
||||||
|
const orderRes = await getUnpaidOrder()
|
||||||
|
if (orderRes && orderRes.code === 200 && orderRes.data) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const unpaidOrder = orderRes.data
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备信息并跳转详情
|
||||||
|
const deviceInfoRes = await getDeviceInfo(deviceNo)
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (deviceInfoRes.code === 200 && deviceInfoRes.data && deviceInfoRes.data.device) {
|
||||||
|
const deviceInfo = deviceInfoRes.data.device
|
||||||
|
let url = `/pages/device/detail?deviceNo=${deviceNo}`
|
||||||
|
if (deviceInfo.feeConfig) {
|
||||||
|
url += `&feeConfig=${encodeURIComponent(deviceInfo.feeConfig)}`
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/device/detail?deviceNo=${deviceNo}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('扫码处理失败:', error)
|
||||||
|
if (error && error.errMsg !== 'scanCode:fail cancel') {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('home.scanFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 切换 Tab
|
// 去购买
|
||||||
const switchTab = (tab) => {
|
const goToBuy = () => {
|
||||||
currentTab.value = tab
|
|
||||||
getCouponList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取优惠券样式类名
|
|
||||||
const getCouponClass = (status) => {
|
|
||||||
return status === 'available' ? '' : 'disabled'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
|
||||||
const getStatusText = (status) => {
|
|
||||||
const statusMap = {
|
|
||||||
'used': $t('myCoupon.usedStatus'),
|
|
||||||
'expired': $t('myCoupon.expiredStatus')
|
|
||||||
}
|
|
||||||
return statusMap[status] || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取空状态文本
|
|
||||||
const getEmptyText = () => {
|
|
||||||
const textMap = {
|
|
||||||
'available': $t('myCoupon.noAvailableCoupons'),
|
|
||||||
'used': $t('myCoupon.noUsedCoupons'),
|
|
||||||
'expired': $t('myCoupon.noExpiredCoupons')
|
|
||||||
}
|
|
||||||
return textMap[currentTab.value] || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用优惠券
|
|
||||||
const useCoupon = (coupon) => {
|
|
||||||
// TODO: 使用优惠券逻辑
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages/index/index'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去购买
|
|
||||||
const goToBuy = () => {
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/purchase/index?tab=coupon'
|
url: '/pages/purchase/index?tab=coupon'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('user.myCoupons')
|
title: t('user.myCoupons')
|
||||||
})
|
})
|
||||||
getCouponList()
|
getCouponList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.my-coupon-page {
|
// 优惠券样式变量封装
|
||||||
|
$coupon-theme-color: #A16300;
|
||||||
|
$coupon-divider-color: #B8741A;
|
||||||
|
$coupon-bg-faded: #f5f5f5;
|
||||||
|
$coupon-active-bg-start: #FFF4E6;
|
||||||
|
$coupon-active-bg-end: #FFE8CC;
|
||||||
|
$coupon-divider-left: 65%;
|
||||||
|
$coupon-circle-radius: 16rpx;
|
||||||
|
|
||||||
|
.my-coupon-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tab 切换 */
|
/* Tab 切换 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
padding: 20rpx 0;
|
padding: 20rpx 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20rpx 0;
|
padding: 20rpx 0;
|
||||||
@@ -225,21 +324,21 @@
|
|||||||
border-radius: 3rpx;
|
border-radius: 3rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-list {
|
.coupon-list {
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20rpx;
|
gap: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-item-wrapper {
|
.coupon-item-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-item {
|
.coupon-item {
|
||||||
background: linear-gradient(135deg, #FFF4E6 0%, #FFE8CC 100%);
|
background: #FFF4E3;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
padding: 40rpx 30rpx;
|
padding: 40rpx 30rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -252,13 +351,13 @@
|
|||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
border-color: #B8741A;
|
border-color: $coupon-divider-color;
|
||||||
box-shadow: 0 4rpx 20rpx rgba(184, 116, 26, 0.2);
|
box-shadow: 0 4rpx 20rpx rgba(184, 116, 26, 0.2);
|
||||||
|
|
||||||
.coupon-circle-left,
|
.coupon-circle-top,
|
||||||
.coupon-circle-right {
|
.coupon-circle-bottom {
|
||||||
background-color: #FFF4E6;
|
background-color: $coupon-active-bg-start;
|
||||||
border: 2rpx solid #B8741A;
|
border: 2rpx solid $coupon-divider-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,120 +371,140 @@
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-circle-left,
|
.coupon-circle-top,
|
||||||
.coupon-circle-right {
|
.coupon-circle-bottom {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 左侧圆形缺口 */
|
/* 虚线顶部圆形缺口 */
|
||||||
.coupon-circle-left {
|
.coupon-circle-top {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -16rpx;
|
left: $coupon-divider-left+4%;
|
||||||
top: 50%;
|
top: -$coupon-circle-radius;
|
||||||
transform: translateY(-50%);
|
transform: translateX(-50%);
|
||||||
width: 32rpx;
|
width: $coupon-circle-radius * 2;
|
||||||
height: 32rpx;
|
height: $coupon-circle-radius * 2;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #f5f5f5;
|
background-color: $coupon-bg-faded;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 右侧圆形缺口 */
|
/* 虚线底部圆形缺口 */
|
||||||
.coupon-circle-right {
|
.coupon-circle-bottom {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -16rpx;
|
left: $coupon-divider-left+4%;
|
||||||
top: 50%;
|
bottom: -$coupon-circle-radius;
|
||||||
transform: translateY(-50%);
|
transform: translateX(-50%);
|
||||||
width: 32rpx;
|
width: $coupon-circle-radius * 2;
|
||||||
height: 32rpx;
|
height: $coupon-circle-radius * 2;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #f5f5f5;
|
background-color: $coupon-bg-faded;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-left {
|
.coupon-left {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
gap: 8rpx;
|
gap: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-value {
|
.coupon-value {
|
||||||
font-size: 48rpx;
|
display: flex;
|
||||||
|
align-items: flex-end; // 单位在脚
|
||||||
|
color: $coupon-theme-color;
|
||||||
|
line-height: 1;
|
||||||
|
width:120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-amount {
|
||||||
|
font-size: 56rpx; // 值要大
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #B8741A;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.coupon-condition {
|
.coupon-unit {
|
||||||
|
font-size: 24rpx; // 单位小
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 6rpx; // 微调单位垂直位置,使其更贴合“脚”
|
||||||
|
margin-left: 4rpx;
|
||||||
|
margin-right: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-condition {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #666;
|
color: #000;
|
||||||
}
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-validity-left {
|
.coupon-validity-left {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-top: 8rpx;
|
margin-top: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-divider {
|
.coupon-divider {
|
||||||
width: 2rpx;
|
width: 2rpx;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 65%;
|
left: $coupon-divider-left;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
// min-height: 160rpx;
|
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
background: repeating-linear-gradient(to bottom,
|
background: repeating-linear-gradient(to bottom,
|
||||||
#B8741A 0rpx,
|
$coupon-divider-color 0rpx,
|
||||||
#B8741A 8rpx,
|
$coupon-divider-color 8rpx,
|
||||||
transparent 8rpx,
|
transparent 8rpx,
|
||||||
transparent 16rpx);
|
transparent 16rpx);
|
||||||
margin: 0 30rpx;
|
margin: 0 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-right {
|
.coupon-right {
|
||||||
flex: 1;
|
// flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8rpx;
|
gap: 8rpx;
|
||||||
align-items: flex-end;
|
align-items: center;
|
||||||
}
|
margin: auto 0;
|
||||||
|
width: 160rpx;
|
||||||
|
// align-content: center;
|
||||||
|
// transform: translateY(50%);
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-name {
|
.coupon-name {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-validity {
|
.coupon-validity {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.use-btn {
|
.use-btn {
|
||||||
margin-top: 10rpx;
|
// margin-top: 10rpx;
|
||||||
padding: 12rpx 28rpx;
|
// padding: 12rpx 28rpx;
|
||||||
background-color: #B8741A;
|
// background-color: #B8741A;
|
||||||
border-radius: 40rpx;
|
// border-radius: 40rpx;
|
||||||
|
|
||||||
.use-text {
|
.use-text {
|
||||||
font-size: 24rpx;
|
font-size: 28rpx;
|
||||||
color: #ffffff;
|
color: #A16300;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-status {
|
.coupon-status {
|
||||||
margin-top: 10rpx;
|
margin-top: 10rpx;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -416,5 +535,5 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+33
-82
@@ -155,13 +155,12 @@
|
|||||||
import {
|
import {
|
||||||
uploadUserAvatar
|
uploadUserAvatar
|
||||||
} from '../../config/api/user.js'
|
} from '../../config/api/user.js'
|
||||||
import {
|
import { getCurrentAdvertisement } from '@/config/api/system.js'
|
||||||
URL
|
import { getInUseOrder } from '@/config/api/order.js'
|
||||||
} from '../../config/url.js'
|
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
// 设置页执行退出登录,此页不再直接调用
|
// 设置页执行退出登录,此页不再直接调用
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
const userInfo = ref({});
|
const userInfo = ref({});
|
||||||
@@ -175,48 +174,25 @@ import {
|
|||||||
const bannerImages = ref([]) // 广告图片列表
|
const bannerImages = ref([]) // 广告图片列表
|
||||||
const bannerImageList = ref([]) // 完整的广告配置列表(包含链接信息)
|
const bannerImageList = ref([]) // 完整的广告配置列表(包含链接信息)
|
||||||
|
|
||||||
// 将语言代码转换为后端接受的格式
|
|
||||||
const convertLanguageCode = (lang) => {
|
|
||||||
// zh-CN -> zh_CN (转换下划线)
|
|
||||||
// en-US -> en_US (转换下划线)
|
|
||||||
return lang.replace(/-/g, '_')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取广告图片
|
// 获取广告图片
|
||||||
const getBannerImages = async () => {
|
const getBannerImages = async () => {
|
||||||
try {
|
try {
|
||||||
// 获取当前语言设置
|
|
||||||
const currentLang = uni.getStorageSync('language') || 'zh-CN'
|
|
||||||
const languageCode = convertLanguageCode(currentLang)
|
|
||||||
|
|
||||||
console.log('加载个人中心广告,语言:', currentLang, '转换后:', languageCode)
|
|
||||||
|
|
||||||
// 调用接口获取广告内容
|
// 调用接口获取广告内容
|
||||||
const res = await uni.request({
|
const res = await getCurrentAdvertisement({
|
||||||
url: `${URL}/device/advertisementConfig/current`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Language': languageCode
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
appPlatform: 'wechat', // 微信平台
|
appPlatform: 'wechat', // 微信平台
|
||||||
appType: 'user' // 用户端
|
appType: 'user' // 用户端
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('个人中心广告响应:', res)
|
if (res && res.code === 200 && res.data) {
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
|
||||||
// 使用 imageList 字段(包含图片和链接信息)
|
// 使用 imageList 字段(包含图片和链接信息)
|
||||||
const imageList = res.data.data.imageList || []
|
const imageList = res.data.imageList || []
|
||||||
if (imageList.length > 0) {
|
if (imageList.length > 0) {
|
||||||
bannerImageList.value = imageList
|
bannerImageList.value = imageList
|
||||||
// 提取图片URL用于展示
|
// 提取图片URL用于展示
|
||||||
bannerImages.value = imageList.map(item => item.imageUrl)
|
bannerImages.value = imageList.map(item => item.imageUrl)
|
||||||
console.log('个人中心广告加载成功,图片数量:', imageList.length)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('获取个人中心广告失败:', res.data?.msg || '未知错误')
|
console.warn('获取个人中心广告失败:', res?.msg || '未知错误')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取个人中心广告失败:', error)
|
console.error('获取个人中心广告失败:', error)
|
||||||
@@ -226,12 +202,10 @@ import {
|
|||||||
// 处理广告点击
|
// 处理广告点击
|
||||||
const handleBannerClick = (index) => {
|
const handleBannerClick = (index) => {
|
||||||
if (!bannerImageList.value || !bannerImageList.value[index]) {
|
if (!bannerImageList.value || !bannerImageList.value[index]) {
|
||||||
console.warn('未找到对应的广告配置')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = bannerImageList.value[index]
|
const config = bannerImageList.value[index]
|
||||||
console.log('点击广告:', index, config)
|
|
||||||
|
|
||||||
// 根据链接类型进行跳转
|
// 根据链接类型进行跳转
|
||||||
if (config.linkType === 'miniapp' && config.appId) {
|
if (config.linkType === 'miniapp' && config.appId) {
|
||||||
@@ -241,12 +215,11 @@ import {
|
|||||||
appId: config.appId,
|
appId: config.appId,
|
||||||
path: config.linkUrl || '',
|
path: config.linkUrl || '',
|
||||||
success: () => {
|
success: () => {
|
||||||
console.log('跳转小程序成功')
|
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
console.error('跳转小程序失败:', err)
|
console.error('跳转小程序失败:', err)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '跳转失败',
|
title: t('common.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -254,7 +227,7 @@ import {
|
|||||||
// #endif
|
// #endif
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '请在微信小程序中使用',
|
title: t('auth.pleaseUseInWechat'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
@@ -268,15 +241,13 @@ import {
|
|||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: config.linkUrl
|
url: config.linkUrl
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
console.log('无有效的跳转配置')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面加载时初始化
|
// 页面加载时初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('user.personalCenter')
|
title: t('user.personalCenter')
|
||||||
})
|
})
|
||||||
getInfo();
|
getInfo();
|
||||||
initVersion();
|
initVersion();
|
||||||
@@ -293,7 +264,6 @@ import {
|
|||||||
const getInfo = async () => {
|
const getInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getUserInfo();
|
const res = await getUserInfo();
|
||||||
console.log('User info response:', res);
|
|
||||||
|
|
||||||
if (res.code == 401 || res.code == 40101) {
|
if (res.code == 401 || res.code == 40101) {
|
||||||
redirectToLogin()
|
redirectToLogin()
|
||||||
@@ -317,9 +287,8 @@ import {
|
|||||||
deposit.value = res.data.balanceAmount || '0.00';
|
deposit.value = res.data.balanceAmount || '0.00';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取用户信息失败:', error);
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.getUserInfoFailed'),
|
title: t('user.getUserInfoFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -374,43 +343,29 @@ import {
|
|||||||
const handleQuickReturn = async () => {
|
const handleQuickReturn = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.loading')
|
title: t('common.loading')
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取使用中的订单
|
// 获取使用中的订单
|
||||||
const res = await uni.request({
|
const res = await getInUseOrder();
|
||||||
url: `${URL}/app/order/inUse`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|
||||||
if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
if (res && res.code === 200 && res.data) {
|
||||||
redirectToLogin();
|
const inUseOrder = res.data;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
|
|
||||||
const inUseOrder = res.data.data;
|
|
||||||
// 跳转到统一订单详情页面
|
// 跳转到统一订单详情页面
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${inUseOrder.deviceNo}`
|
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${inUseOrder.deviceNo}`
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.noOrder'),
|
title: t('order.noOrder'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading();
|
|
||||||
console.error('获取使用中订单失败:', error);
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.getOrderFailed'),
|
title: t('order.getOrderFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -433,7 +388,7 @@ import {
|
|||||||
// #endif
|
// #endif
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.pleaseUseInWechat'),
|
title: t('auth.pleaseUseInWechat'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
@@ -450,13 +405,13 @@ import {
|
|||||||
const avatarLocalPath = e?.detail?.avatarUrl
|
const avatarLocalPath = e?.detail?.avatarUrl
|
||||||
if (!avatarLocalPath) {
|
if (!avatarLocalPath) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '未选择头像',
|
title: t('user.noAvatar'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.uploading'),
|
title: t('common.uploading'),
|
||||||
mask: true
|
mask: true
|
||||||
})
|
})
|
||||||
const uploadRes = await uploadUserAvatar(avatarLocalPath)
|
const uploadRes = await uploadUserAvatar(avatarLocalPath)
|
||||||
@@ -469,14 +424,13 @@ import {
|
|||||||
uni.setStorageSync('userInfo', userInfo.value)
|
uni.setStorageSync('userInfo', userInfo.value)
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '头像已更新',
|
title: t('user.avatarUpdated'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
await getInfo()
|
await getInfo()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('选择/上传头像失败:', err)
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '头像更新失败',
|
title: t('user.avatarUploadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -494,14 +448,12 @@ import {
|
|||||||
|
|
||||||
// 弹窗打开事件处理
|
// 弹窗打开事件处理
|
||||||
const onPopupOpen = () => {
|
const onPopupOpen = () => {
|
||||||
console.log('授权弹窗已打开');
|
|
||||||
isPopupVisible.value = true;
|
isPopupVisible.value = true;
|
||||||
// 这里可以添加弹窗打开后的逻辑
|
// 这里可以添加弹窗打开后的逻辑
|
||||||
};
|
};
|
||||||
|
|
||||||
// 弹窗关闭事件处理
|
// 弹窗关闭事件处理
|
||||||
const onPopupClose = () => {
|
const onPopupClose = () => {
|
||||||
console.log('授权弹窗已关闭');
|
|
||||||
isPopupVisible.value = false;
|
isPopupVisible.value = false;
|
||||||
// 这里可以添加弹窗关闭后的逻辑
|
// 这里可以添加弹窗关闭后的逻辑
|
||||||
};
|
};
|
||||||
@@ -510,7 +462,7 @@ import {
|
|||||||
const getUserProfile = () => {
|
const getUserProfile = () => {
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.getting'),
|
title: t('common.getting'),
|
||||||
mask: true
|
mask: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -524,7 +476,7 @@ import {
|
|||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
console.error('获取用户信息失败:', err);
|
console.error('获取用户信息失败:', err);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '获取用户信息失败',
|
title: t('user.getUserInfoFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -537,7 +489,7 @@ import {
|
|||||||
|
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.pleaseUseInWechat'),
|
title: t('auth.pleaseUseInWechat'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
closeAuthPopup();
|
closeAuthPopup();
|
||||||
@@ -566,7 +518,7 @@ import {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.updateSuccess'),
|
title: t('user.updateSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -575,7 +527,7 @@ import {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新用户信息失败:', error);
|
console.error('更新用户信息失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.updateFailed'),
|
title: t('user.updateFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -587,7 +539,7 @@ import {
|
|||||||
const avatarUrl = wxUserInfo?.avatarUrl
|
const avatarUrl = wxUserInfo?.avatarUrl
|
||||||
if (!avatarUrl) {
|
if (!avatarUrl) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '未获取到头像地址',
|
title: t('user.noAvatarUrl'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -601,7 +553,7 @@ import {
|
|||||||
resolve(res.tempFilePath)
|
resolve(res.tempFilePath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reject(new Error('头像下载失败'))
|
reject(new Error(t('user.avatarDownloadFailed')))
|
||||||
},
|
},
|
||||||
fail: reject
|
fail: reject
|
||||||
})
|
})
|
||||||
@@ -618,14 +570,13 @@ import {
|
|||||||
uni.setStorageSync('userInfo', userInfo.value)
|
uni.setStorageSync('userInfo', userInfo.value)
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '头像已更新',
|
title: t('user.avatarUpdated'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
await getInfo()
|
await getInfo()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('头像上传失败:', error)
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '头像上传失败',
|
title: t('user.avatarUploadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -644,7 +595,7 @@ import {
|
|||||||
// 关于我们
|
// 关于我们
|
||||||
const handleAboutUs = () => {
|
const handleAboutUs = () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('help.functionDeveloping'),
|
title: t('help.functionDeveloping'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -652,7 +603,7 @@ import {
|
|||||||
// 隐私政策
|
// 隐私政策
|
||||||
const handlePrivacyPolicy = () => {
|
const handlePrivacyPolicy = () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('help.functionDeveloping'),
|
title: t('help.functionDeveloping'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+154
-87
@@ -4,7 +4,13 @@
|
|||||||
<view class="page-header">
|
<view class="page-header">
|
||||||
<view class="header-top">
|
<view class="header-top">
|
||||||
<view class="header-left">
|
<view class="header-left">
|
||||||
<view class="header-title">{{ getOrderStatusText() }}</view>
|
<view class="header-title-row">
|
||||||
|
<text class="header-title">{{ getOrderStatusText() }}</text>
|
||||||
|
<!-- 优惠券/会员卡可用提示标签 -->
|
||||||
|
<view v-if="orderInfo.orderStatus === 'in_used' && canUsePromotionTag" class="promotion-tag">
|
||||||
|
{{ $t('order.canUsePromotion') }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="header-desc">{{ getStatusDesc() }}</view>
|
<view class="header-desc">{{ getStatusDesc() }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="header-right" v-if="orderInfo.orderStatus === 'in_used'">
|
<view class="header-right" v-if="orderInfo.orderStatus === 'in_used'">
|
||||||
@@ -78,6 +84,14 @@
|
|||||||
<view class="rent-label">{{ $t('order.paymentMethod') }}</view>
|
<view class="rent-label">{{ $t('order.paymentMethod') }}</view>
|
||||||
<view class="rent-value">{{ getPayWayText() }}</view>
|
<view class="rent-value">{{ getPayWayText() }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 优惠信息显示 - 订单完成且使用了优惠 -->
|
||||||
|
<view class="rent-item" v-if="isOrderCompleted() && orderInfo.discountTypeName">
|
||||||
|
<view class="rent-label">{{ $t('order.usedPromotion') }}</view>
|
||||||
|
<view class="rent-value promotion-value">
|
||||||
|
<image src="/static/promotion-icon.png" class="promotion-icon" mode="aspectFit"></image>
|
||||||
|
{{ orderInfo.discountTypeName }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="rent-item" v-if="isOrderCompleted() && orderInfo.endTime">
|
<view class="rent-item" v-if="isOrderCompleted() && orderInfo.endTime">
|
||||||
<view class="rent-label">{{ $t('order.returnTime') }}</view>
|
<view class="rent-label">{{ $t('order.returnTime') }}</view>
|
||||||
<view class="rent-value">{{ orderInfo.endTime }}</view>
|
<view class="rent-value">{{ orderInfo.endTime }}</view>
|
||||||
@@ -94,7 +108,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="">
|
<view class="">
|
||||||
<view class="" style="font-size: 24rpx;text-align: center;">
|
<view class="" style="font-size: 24rpx;text-align: center;">
|
||||||
产品归还入仓后,订单仍未结束,请前往<text @click="contactService" style="color:#07c160 ;">客服中心</text>联系工作人员。
|
{{ $t('order.returnProblemTip') }}<text @click="contactService" style="color:#07c160 ;">{{ $t('user.customerService') }}</text>{{ $t('order.contactStaff') }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -209,8 +223,12 @@
|
|||||||
cancelOrder,
|
cancelOrder,
|
||||||
reportDeviceNoEject,
|
reportDeviceNoEject,
|
||||||
convertToOwned,
|
convertToOwned,
|
||||||
closeWithMaxFee
|
closeWithMaxFee,
|
||||||
|
getInUseOrder
|
||||||
} from '@/config/api/order.js'
|
} from '@/config/api/order.js'
|
||||||
|
import {
|
||||||
|
withdrawDeposit
|
||||||
|
} from '@/config/api/user.js'
|
||||||
import {
|
import {
|
||||||
addUserFeedback
|
addUserFeedback
|
||||||
} from '@/config/api/feedback.js'
|
} from '@/config/api/feedback.js'
|
||||||
@@ -222,7 +240,7 @@
|
|||||||
} from "@/config/url.js"
|
} from "@/config/url.js"
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
const $orderMonitor = instance?.proxy?.$orderMonitor || null
|
const $orderMonitor = instance?.proxy?.$orderMonitor || null
|
||||||
|
|
||||||
@@ -251,7 +269,12 @@
|
|||||||
isSupportExpressReturn: 'yes',
|
isSupportExpressReturn: 'yes',
|
||||||
freeRentTime: '',
|
freeRentTime: '',
|
||||||
unitPrice: '',
|
unitPrice: '',
|
||||||
orderType: ''
|
orderType: '',
|
||||||
|
canUseMember: false,
|
||||||
|
canUseCoupon: false,
|
||||||
|
userMemberCardId: '',
|
||||||
|
userPurchaseId: '',
|
||||||
|
discountTypeName: ''
|
||||||
})
|
})
|
||||||
const timer = ref(null)
|
const timer = ref(null)
|
||||||
const statusCheckTimer = ref(null)
|
const statusCheckTimer = ref(null)
|
||||||
@@ -264,8 +287,28 @@
|
|||||||
const countdownRemaining = ref(0)
|
const countdownRemaining = ref(0)
|
||||||
const showExpressAction = ref(false)
|
const showExpressAction = ref(false)
|
||||||
const countdownTimer = ref(null)
|
const countdownTimer = ref(null)
|
||||||
const feeRuleText = ref('5.0元/60分钟 前15分钟内归还免费 不足60分钟按60分钟计费 封顶99元 持续计费至99元视为买断')
|
const feeRuleText = ref('')
|
||||||
const convertToOwnPopup = ref(null)
|
const convertToOwnPopup = ref(null)
|
||||||
|
|
||||||
|
// 计算属性:是否显示优惠券/会员卡可用提示
|
||||||
|
const canUsePromotionTag = computed(() => {
|
||||||
|
return orderInfo.value.canUseMember === true || orderInfo.value.canUseCoupon === true
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算属性:是否使用了优惠
|
||||||
|
const hasUsedPromotion = computed(() => {
|
||||||
|
return !!(orderInfo.value.userMemberCardId || orderInfo.value.userPurchaseId)
|
||||||
|
})
|
||||||
|
// 获取已使用优惠的文本
|
||||||
|
const getUsedPromotionText = () => {
|
||||||
|
if (orderInfo.value.userMemberCardId) {
|
||||||
|
return t('user.myCards')
|
||||||
|
} else if (orderInfo.value.userPurchaseId) {
|
||||||
|
return t('user.myCoupons')
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
// 判断订单是否已完成
|
// 判断订单是否已完成
|
||||||
const isOrderCompleted = () => {
|
const isOrderCompleted = () => {
|
||||||
return orderInfo.value.orderStatus === 'used_done' ||
|
return orderInfo.value.orderStatus === 'used_done' ||
|
||||||
@@ -275,27 +318,27 @@
|
|||||||
// 获取订单状态文字
|
// 获取订单状态文字
|
||||||
const getOrderStatusText = () => {
|
const getOrderStatusText = () => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'waiting_for_payment': $t('order.waitingForPayment'),
|
'waiting_for_payment': t('order.waitingForPayment'),
|
||||||
'payment_in_progress': $t('order.paymentInProgress'),
|
'payment_in_progress': t('order.paymentInProgress'),
|
||||||
'payment_successful': $t('order.paymentSuccess'),
|
'payment_successful': t('order.paymentSuccess'),
|
||||||
'in_used': $t('order.inUse'),
|
'in_used': t('order.inUse'),
|
||||||
'payment_failed': $t('order.paymentFailed'),
|
'payment_failed': t('order.paymentFailed'),
|
||||||
'order_cancelled': $t('order.cancelled'),
|
'order_cancelled': t('order.cancelled'),
|
||||||
'used_done': $t('order.finished'),
|
'used_done': t('order.finished'),
|
||||||
'used_down': $t('order.finished')
|
'used_down': t('order.finished')
|
||||||
}
|
}
|
||||||
return statusMap[orderInfo.value.orderStatus] || $t('order.orderDetail')
|
return statusMap[orderInfo.value.orderStatus] || t('order.orderDetail')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取状态描述
|
// 获取状态描述
|
||||||
const getStatusDesc = () => {
|
const getStatusDesc = () => {
|
||||||
const descMap = {
|
const descMap = {
|
||||||
'waiting_for_payment': $t('order.pleasePaySoon'),
|
'waiting_for_payment': t('order.pleasePaySoon'),
|
||||||
'in_used': $t('order.pleaseReturnInTime'),
|
'in_used': t('order.pleaseReturnInTime'),
|
||||||
'used_done': $t('order.returnedThankYou'),
|
'used_done': t('order.returnedThankYou'),
|
||||||
'used_down': $t('order.returnedThankYou'),
|
'used_down': t('order.returnedThankYou'),
|
||||||
'order_cancelled': $t('order.orderCancelled'),
|
'order_cancelled': t('order.orderCancelled'),
|
||||||
'payment_failed': $t('order.paymentFailedRetry')
|
'payment_failed': t('order.paymentFailedRetry')
|
||||||
}
|
}
|
||||||
return descMap[orderInfo.value.orderStatus] || ''
|
return descMap[orderInfo.value.orderStatus] || ''
|
||||||
}
|
}
|
||||||
@@ -303,11 +346,11 @@
|
|||||||
// 获取支付方式文本
|
// 获取支付方式文本
|
||||||
const getPayWayText = () => {
|
const getPayWayText = () => {
|
||||||
const payWayMap = {
|
const payWayMap = {
|
||||||
'wx_score_pay': $t('order.depositFree'),
|
'wx_score_pay': t('order.depositFree'),
|
||||||
'wx_member_pay': $t('order.memberOrder'),
|
'wx_member_pay': t('order.memberOrder'),
|
||||||
'wx_pay': $t('order.depositPay')
|
'wx_pay': t('order.depositPay')
|
||||||
}
|
}
|
||||||
return payWayMap[orderInfo.value.payWay] || $t('order.depositFree')
|
return payWayMap[orderInfo.value.payWay] || t('order.depositFree')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取免费时长显示
|
// 获取免费时长显示
|
||||||
@@ -321,13 +364,13 @@
|
|||||||
if (!orderInfo.value.unitPrice || !orderInfo.value.orderType) return '-'
|
if (!orderInfo.value.unitPrice || !orderInfo.value.orderType) return '-'
|
||||||
|
|
||||||
const orderTypeMap = {
|
const orderTypeMap = {
|
||||||
'hours': $t('time.hours'),
|
'hours': t('time.hours'),
|
||||||
'minutes': $t('time.minutes'),
|
'minutes': t('time.minutes'),
|
||||||
'halfhours': $t('time.halfHours')
|
'halfhours': t('time.halfHours')
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderTypeText = orderTypeMap[orderInfo.value.orderType] || orderInfo.value.orderType
|
const orderTypeText = orderTypeMap[orderInfo.value.orderType] || orderInfo.value.orderType
|
||||||
return `${orderInfo.value.unitPrice}${$t('unit.yuan')}/${orderTypeText}`
|
return `${orderInfo.value.unitPrice}${t('unit.yuan')}/${orderTypeText}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化倒计时(显示为 HH:MM:SS 格式)
|
// 格式化倒计时(显示为 HH:MM:SS 格式)
|
||||||
@@ -378,21 +421,21 @@
|
|||||||
if (totalMinutes >= 60) {
|
if (totalMinutes >= 60) {
|
||||||
const hours = Math.floor(totalMinutes / 60)
|
const hours = Math.floor(totalMinutes / 60)
|
||||||
const minutes = totalMinutes % 60
|
const minutes = totalMinutes % 60
|
||||||
usedTime = minutes > 0 ? `${hours}小时${minutes}分钟` : `${hours}小时`
|
usedTime = minutes > 0 ? `${hours}${t('time.hour')}${minutes}${t('time.minute')}` : `${hours}${t('time.hour')}`
|
||||||
} else {
|
} else {
|
||||||
usedTime = `${totalMinutes}分钟`
|
usedTime = `${totalMinutes}${t('time.minute')}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果还是没有值,使用默认值
|
// 如果还是没有值,使用默认值
|
||||||
if (!usedTime) {
|
if (!usedTime) {
|
||||||
usedTime = '0分钟'
|
usedTime = `0${t('time.minute')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析时长字符串,例如 "1小时5分钟" 或 "5分钟"
|
// 解析时长字符串,例如 "1小时5分钟" 或 "5分钟"
|
||||||
const hourMatch = usedTime.match(/(\d+)小时/)
|
const hourMatch = usedTime.match(new RegExp(`(\\d+)${t('time.hour')}`))
|
||||||
const minuteMatch = usedTime.match(/(\d+)分钟/)
|
const minuteMatch = usedTime.match(new RegExp(`(\\d+)${t('time.minute')}`))
|
||||||
|
|
||||||
let displayNumber = ''
|
let displayNumber = ''
|
||||||
let displayUnit = ''
|
let displayUnit = ''
|
||||||
@@ -400,19 +443,19 @@
|
|||||||
if (hourMatch && minuteMatch) {
|
if (hourMatch && minuteMatch) {
|
||||||
// 有小时也有分钟,如 "1小时5分钟"
|
// 有小时也有分钟,如 "1小时5分钟"
|
||||||
displayNumber = `${hourMatch[1]}`
|
displayNumber = `${hourMatch[1]}`
|
||||||
displayUnit = `小时${minuteMatch[1]}分钟`
|
displayUnit = `${t('time.hour')}${minuteMatch[1]}${t('time.minute')}`
|
||||||
} else if (hourMatch) {
|
} else if (hourMatch) {
|
||||||
// 只有小时,如 "1小时"
|
// 只有小时,如 "1小时"
|
||||||
displayNumber = hourMatch[1]
|
displayNumber = hourMatch[1]
|
||||||
displayUnit = '小时'
|
displayUnit = t('time.hour')
|
||||||
} else if (minuteMatch) {
|
} else if (minuteMatch) {
|
||||||
// 只有分钟,如 "5分钟"
|
// 只有分钟,如 "5分钟"
|
||||||
displayNumber = minuteMatch[1]
|
displayNumber = minuteMatch[1]
|
||||||
displayUnit = '分钟'
|
displayUnit = t('time.minute')
|
||||||
} else {
|
} else {
|
||||||
// 默认情况
|
// 默认情况
|
||||||
displayNumber = '0'
|
displayNumber = '0'
|
||||||
displayUnit = '分钟'
|
displayUnit = t('time.minute')
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -424,7 +467,7 @@
|
|||||||
// 获取使用时长标签文本
|
// 获取使用时长标签文本
|
||||||
const getUsedTimeLabel = () => {
|
const getUsedTimeLabel = () => {
|
||||||
// 使用中状态显示"已使用",已完成状态显示"使用时长"
|
// 使用中状态显示"已使用",已完成状态显示"使用时长"
|
||||||
return orderInfo.value.orderStatus === 'in_used' ? $t('order.used') : $t('order.duration')
|
return orderInfo.value.orderStatus === 'in_used' ? t('order.used') : t('order.duration')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取订单费用(不含单位)
|
// 获取订单费用(不含单位)
|
||||||
@@ -663,7 +706,7 @@
|
|||||||
if (currentStatusChecks.value >= maxStatusChecks.value) {
|
if (currentStatusChecks.value >= maxStatusChecks.value) {
|
||||||
clearStatusCheckTimer()
|
clearStatusCheckTimer()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.pleaseRefreshManually'),
|
title: t('order.pleaseRefreshManually'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 3000
|
duration: 3000
|
||||||
})
|
})
|
||||||
@@ -709,6 +752,13 @@
|
|||||||
orderInfo.value.unitPrice = orderData.unitPrice || ''
|
orderInfo.value.unitPrice = orderData.unitPrice || ''
|
||||||
orderInfo.value.orderType = orderData.orderType || ''
|
orderInfo.value.orderType = orderData.orderType || ''
|
||||||
|
|
||||||
|
// 保存优惠券/会员卡相关信息
|
||||||
|
orderInfo.value.canUseMember = orderData.canUseMember === true
|
||||||
|
orderInfo.value.canUseCoupon = orderData.canUseCoupon === true
|
||||||
|
orderInfo.value.userMemberCardId = orderData.userMemberCardId || ''
|
||||||
|
orderInfo.value.userPurchaseId = orderData.userPurchaseId || ''
|
||||||
|
orderInfo.value.discountTypeName = orderData.discountTypeName || ''
|
||||||
|
|
||||||
// 保存快递归还开始时间(小时为单位)
|
// 保存快递归还开始时间(小时为单位)
|
||||||
orderInfo.value.expressReturnStart = orderData.expressReturnStart || null
|
orderInfo.value.expressReturnStart = orderData.expressReturnStart || null
|
||||||
|
|
||||||
@@ -741,7 +791,7 @@
|
|||||||
// 显示订单完成提示
|
// 显示订单完成提示
|
||||||
if (orderInfo.value.orderStatus === 'used_done' || orderInfo.value.orderStatus === 'used_down') {
|
if (orderInfo.value.orderStatus === 'used_done' || orderInfo.value.orderStatus === 'used_down') {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.orderCompleted'),
|
title: t('order.orderCompleted'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -763,7 +813,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (!orderInfo.value.orderId) {
|
if (!orderInfo.value.orderId) {
|
||||||
throw new Error($t('order.orderIdRequired'))
|
throw new Error(t('order.orderIdRequired'))
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoadingOrder.value = true
|
isLoadingOrder.value = true
|
||||||
@@ -813,12 +863,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.msg || $t('order.getOrderFailed'))
|
throw new Error(result.msg || t('order.getOrderFailed'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取订单详情错误:', error)
|
console.error('获取订单详情错误:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.getOrderFailed'),
|
title: error.message || t('order.getOrderFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -834,22 +884,15 @@
|
|||||||
const getOrderByDevice = async () => {
|
const getOrderByDevice = async () => {
|
||||||
try {
|
try {
|
||||||
if (!deviceId.value) {
|
if (!deviceId.value) {
|
||||||
throw new Error($t('device.deviceNoRequired'))
|
throw new Error(t('device.deviceNoRequired'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const inUseRes = await uni.request({
|
const inUseRes = await getInUseOrder()
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/order/inUse`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('通过设备号查询订单结果:', JSON.stringify(inUseRes))
|
console.log('通过设备号查询订单结果:', JSON.stringify(inUseRes))
|
||||||
|
|
||||||
if (inUseRes.statusCode === 200 && inUseRes.data.code === 200 && inUseRes.data.data) {
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
const inUseOrder = inUseRes.data.data
|
const inUseOrder = inUseRes.data
|
||||||
console.log('使用中的订单:', inUseOrder)
|
console.log('使用中的订单:', inUseOrder)
|
||||||
|
|
||||||
orderInfo.value.orderId = inUseOrder.orderId
|
orderInfo.value.orderId = inUseOrder.orderId
|
||||||
@@ -859,12 +902,12 @@
|
|||||||
|
|
||||||
getOrderDetails()
|
getOrderDetails()
|
||||||
} else {
|
} else {
|
||||||
throw new Error($t('order.noOrderInUse'))
|
throw new Error(t('order.noOrderInUse'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('通过设备号查询订单失败:', error)
|
console.error('通过设备号查询订单失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.getOrderFailed'),
|
title: error.message || t('order.getOrderFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -885,13 +928,13 @@
|
|||||||
// 取消订单
|
// 取消订单
|
||||||
const handleCancelOrder = () => {
|
const handleCancelOrder = () => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('order.confirmCancel'),
|
title: t('order.confirmCancel'),
|
||||||
content: $t('order.confirmCancelContent'),
|
content: t('order.confirmCancelContent'),
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
})
|
})
|
||||||
const result = await cancelOrder({
|
const result = await cancelOrder({
|
||||||
orderId: orderInfo.value.orderId
|
orderId: orderInfo.value.orderId
|
||||||
@@ -899,17 +942,17 @@
|
|||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.cancelSuccess'),
|
title: t('order.cancelSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
await getOrderDetails()
|
await getOrderDetails()
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.msg || $t('order.cancelFailed'))
|
throw new Error(result.msg || t('order.cancelFailed'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.cancelFailed'),
|
title: error.message || t('order.cancelFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -929,22 +972,14 @@
|
|||||||
const handleWithdraw = async () => {
|
const handleWithdraw = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = await uni.request({
|
const res = await withdrawDeposit(orderInfo.value.orderNo)
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/withdraw/add/${orderInfo.value.orderNo}`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
if (res && res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.refundSuccess'),
|
title: t('order.refundSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -955,12 +990,12 @@
|
|||||||
getOrderDetails()
|
getOrderDetails()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.msg || $t('order.refundFailed'))
|
throw new Error(res?.msg || t('order.refundFailed'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('退款申请错误:', error)
|
console.error('退款申请失败:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.refundFailed'),
|
title: error.message || t('order.refundFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1002,14 +1037,14 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '订阅成功',
|
title: t('payment.subscriptionSuccess'),
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('订阅消息异常', error)
|
console.log('订阅消息异常', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '订阅失败,请稍后重试',
|
title: t('payment.subscriptionFailed'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -1040,7 +1075,7 @@
|
|||||||
try {
|
try {
|
||||||
closeConvertToOwnPopup()
|
closeConvertToOwnPopup()
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await closeWithMaxFee(orderInfo.value.orderNo)
|
const result = await closeWithMaxFee(orderInfo.value.orderNo)
|
||||||
@@ -1048,7 +1083,7 @@
|
|||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.convertToOwnWithMaxFeeSuccess'),
|
title: t('order.convertToOwnWithMaxFeeSuccess'),
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -1058,12 +1093,12 @@
|
|||||||
getOrderDetails()
|
getOrderDetails()
|
||||||
}, 2000)
|
}, 2000)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.msg || $t('order.convertToOwnWithMaxFeeFailed'))
|
throw new Error(result.msg || t('order.convertToOwnWithMaxFeeFailed'))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.convertToOwnWithMaxFeeFailed'),
|
title: error.message || t('order.convertToOwnWithMaxFeeFailed'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -1076,7 +1111,7 @@
|
|||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('order.orderDetail')
|
title: t('order.orderDetail')
|
||||||
})
|
})
|
||||||
|
|
||||||
isPageActive.value = true
|
isPageActive.value = true
|
||||||
@@ -1101,7 +1136,7 @@
|
|||||||
getOrderDetails()
|
getOrderDetails()
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.orderInfoMissing'),
|
title: t('order.orderInfoMissing'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -1162,11 +1197,17 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-desc {
|
.header-desc {
|
||||||
@@ -1211,6 +1252,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.promotion-tag {
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
background: linear-gradient(135deg, #FFF4E6 0%, #FFE9CC 100%);
|
||||||
|
border-radius: 10rpx;
|
||||||
|
border: 1rpx solid #FFB84D;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #FF8C00;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 订单信息卡片
|
// 订单信息卡片
|
||||||
.info-card {
|
.info-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
@@ -1355,6 +1408,20 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
max-width: 400rpx;
|
max-width: 400rpx;
|
||||||
|
|
||||||
|
&.promotion-value {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: #FF8C00;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.promotion-icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-41
@@ -46,7 +46,8 @@
|
|||||||
getOrderList,
|
getOrderList,
|
||||||
queryById,
|
queryById,
|
||||||
getOrderByOrderNoScorePayStatus,
|
getOrderByOrderNoScorePayStatus,
|
||||||
cancelOrder
|
cancelOrder,
|
||||||
|
createWxPayment
|
||||||
} from '../../config/api/order.js';
|
} from '../../config/api/order.js';
|
||||||
import {
|
import {
|
||||||
confirmPaymentAndRent
|
confirmPaymentAndRent
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
} from '../../config/url.js';
|
} from '../../config/url.js';
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
const currentTab = ref(0);
|
const currentTab = ref(0);
|
||||||
@@ -68,62 +69,62 @@
|
|||||||
// 订单状态映射
|
// 订单状态映射
|
||||||
const orderStatusMap = reactive({
|
const orderStatusMap = reactive({
|
||||||
'0': {
|
'0': {
|
||||||
get text() { return $t('order.waitingForPayment') },
|
get text() { return t('order.waitingForPayment') },
|
||||||
class: 'status-waiting'
|
class: 'status-waiting'
|
||||||
},
|
},
|
||||||
'1': {
|
'1': {
|
||||||
get text() { return $t('order.inUse') },
|
get text() { return t('order.inUse') },
|
||||||
class: 'status-using'
|
class: 'status-using'
|
||||||
},
|
},
|
||||||
'2': {
|
'2': {
|
||||||
get text() { return $t('order.finished') },
|
get text() { return t('order.finished') },
|
||||||
class: 'status-finished'
|
class: 'status-finished'
|
||||||
},
|
},
|
||||||
'3': {
|
'3': {
|
||||||
get text() { return $t('order.cancelled') },
|
get text() { return t('order.cancelled') },
|
||||||
class: 'status-cancelled'
|
class: 'status-cancelled'
|
||||||
},
|
},
|
||||||
'waiting_for_payment': {
|
'waiting_for_payment': {
|
||||||
get text() { return $t('order.waitingForPayment') },
|
get text() { return t('order.waitingForPayment') },
|
||||||
class: 'status-waiting'
|
class: 'status-waiting'
|
||||||
},
|
},
|
||||||
'in_used': {
|
'in_used': {
|
||||||
get text() { return $t('order.inUse') },
|
get text() { return t('order.inUse') },
|
||||||
class: 'status-using'
|
class: 'status-using'
|
||||||
},
|
},
|
||||||
'used_done': {
|
'used_done': {
|
||||||
get text() { return $t('order.finished') },
|
get text() { return t('order.finished') },
|
||||||
class: 'status-finished'
|
class: 'status-finished'
|
||||||
},
|
},
|
||||||
'order_cancelled': {
|
'order_cancelled': {
|
||||||
get text() { return $t('order.cancelled') },
|
get text() { return t('order.cancelled') },
|
||||||
class: 'status-cancelled'
|
class: 'status-cancelled'
|
||||||
},
|
},
|
||||||
'express_return': {
|
'express_return': {
|
||||||
get text() { return $t('express.title') },
|
get text() { return t('express.title') },
|
||||||
class: 'status-express-return'
|
class: 'status-express-return'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 订单状态标签
|
// 订单状态标签
|
||||||
const orderStatusTabs = reactive([{
|
const orderStatusTabs = reactive([{
|
||||||
get text() { return $t('common.all') },
|
get text() { return t('common.all') },
|
||||||
status: []
|
status: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() { return $t('order.waitingForPayment') },
|
get text() { return t('order.waitingForPayment') },
|
||||||
status: ['waiting_for_payment']
|
status: ['waiting_for_payment']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() { return $t('order.inUse') },
|
get text() { return t('order.inUse') },
|
||||||
status: ['in_used']
|
status: ['in_used']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() { return $t('order.finished') },
|
get text() { return t('order.finished') },
|
||||||
status: ['used_done']
|
status: ['used_done']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() { return $t('order.cancelled') },
|
get text() { return t('order.cancelled') },
|
||||||
status: ['order_cancelled']
|
status: ['order_cancelled']
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -216,7 +217,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取订单列表失败:', error);
|
console.error('获取订单列表失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.getOrderListFailed'),
|
title: t('order.getOrderListFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -233,7 +234,7 @@
|
|||||||
// 设置页面标题并监听订单完成事件
|
// 设置页面标题并监听订单完成事件
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('order.myOrders')
|
title: t('order.myOrders')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听订单完成事件
|
// 监听订单完成事件
|
||||||
@@ -251,14 +252,14 @@
|
|||||||
const res = await getOrderByOrderNoScorePayStatus(order.orderNo);
|
const res = await getOrderByOrderNoScorePayStatus(order.orderNo);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.syncSuccess'),
|
title: t('order.syncSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
await loadOrderList(orderStatusTabs[currentTab.value].status);
|
await loadOrderList(orderStatusTabs[currentTab.value].status);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.syncFailed'),
|
title: t('order.syncFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -285,28 +286,21 @@
|
|||||||
const handlePayment = async (order) => {
|
const handlePayment = async (order) => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
});
|
});
|
||||||
|
|
||||||
// 调用后端创建微信支付订单接口
|
// 调用后端创建微信支付订单接口
|
||||||
const res = await uni.request({
|
const res = await createWxPayment(order.orderNo);
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/create/${order.orderNo}`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
if (res && res.code === 200) {
|
||||||
const payParams = res.data.data;
|
const payParams = res.data;
|
||||||
|
|
||||||
// 调用微信支付
|
// 调用微信支付
|
||||||
await uni.requestPayment({
|
await uni.requestPayment({
|
||||||
...payParams,
|
...payParams,
|
||||||
success: async () => {
|
success: async () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('payment.paymentSuccess'),
|
title: t('payment.paymentSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -322,18 +316,18 @@
|
|||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
console.error('支付失败:', err);
|
console.error('支付失败:', err);
|
||||||
throw new Error($t('payment.paymentFailedRetry'));
|
throw new Error(t('payment.paymentFailedRetry'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.msg || '创建支付订单失败');
|
throw new Error(res?.msg || '创建支付订单失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('payment.paymentFailed'),
|
title: error.message || t('payment.paymentFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -343,12 +337,12 @@
|
|||||||
const handleCancelOrder = async (order) => {
|
const handleCancelOrder = async (order) => {
|
||||||
try {
|
try {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('order.confirmCancel'),
|
title: t('order.confirmCancel'),
|
||||||
content: $t('order.confirmCancelContent'),
|
content: t('order.confirmCancelContent'),
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: t('common.processing')
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await cancelOrder({
|
const result = await cancelOrder({
|
||||||
@@ -358,14 +352,14 @@
|
|||||||
if (result) {
|
if (result) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('order.cancelSuccess'),
|
title: t('order.cancelSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
// 刷新订单列表
|
// 刷新订单列表
|
||||||
await loadOrderList();
|
await loadOrderList();
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.msg || $t('order.cancelFailed'));
|
throw new Error(result.msg || t('order.cancelFailed'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,7 +367,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('order.cancelFailed'),
|
title: error.message || t('order.cancelFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+171
-297
@@ -59,96 +59,210 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { queryById, updateOrderPackage } from '@/config/api/order.js'
|
import { ref, computed, reactive } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { queryById, createWxPayment } from '@/config/api/order.js'
|
||||||
import { getDeviceInfo } from '@/config/api/device.js'
|
import { getDeviceInfo } from '@/config/api/device.js'
|
||||||
import { updateUserBalance } from '@/config/api/user.js'
|
import { updateUserBalance } from '@/config/api/user.js'
|
||||||
import {
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
URL
|
|
||||||
}from"@/config/url.js"
|
|
||||||
|
|
||||||
export default {
|
const { t } = useI18n()
|
||||||
data() {
|
|
||||||
return {
|
const orderId = ref(null)
|
||||||
orderId: null,
|
const deviceNo = ref(null)
|
||||||
deviceNo: null,
|
const orderInfo = ref({})
|
||||||
orderInfo: {},
|
const packageInfo = ref({
|
||||||
packageInfo: {
|
|
||||||
time: '',
|
time: '',
|
||||||
price: '0.00'
|
price: '0.00'
|
||||||
},
|
})
|
||||||
deviceInfo: null,
|
const deviceInfo = ref(null)
|
||||||
passedTotalAmount: null,
|
const passedTotalAmount = ref(null)
|
||||||
passedDepositAmount: null,
|
const passedDepositAmount = ref(null)
|
||||||
orderStatus: {
|
|
||||||
get text() { return this.$t('payment.waitingForPayment') },
|
const orderStatus = reactive({
|
||||||
get desc() { return this.$t('payment.pleasePayIn15Min') },
|
get text() { return t('payment.waitingForPayment') },
|
||||||
|
get desc() { return t('payment.pleasePayIn15Min') },
|
||||||
class: 'waiting'
|
class: 'waiting'
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalAmount = computed(() => {
|
||||||
|
if (passedTotalAmount.value !== null) {
|
||||||
|
return parseFloat(passedTotalAmount.value).toFixed(2);
|
||||||
}
|
}
|
||||||
}
|
const deposit = parseFloat(orderInfo.value.deposit || passedDepositAmount.value || 99)
|
||||||
},
|
const packagePrice = parseFloat(packageInfo.value.price || 0)
|
||||||
computed: {
|
|
||||||
totalAmount() {
|
|
||||||
if (this.passedTotalAmount !== null) {
|
|
||||||
return parseFloat(this.passedTotalAmount).toFixed(2);
|
|
||||||
}
|
|
||||||
const deposit = parseFloat(this.orderInfo.deposit || this.passedDepositAmount || 99)
|
|
||||||
const packagePrice = parseFloat(this.packageInfo.price || 0)
|
|
||||||
return (deposit + packagePrice).toFixed(2)
|
return (deposit + packagePrice).toFixed(2)
|
||||||
},
|
})
|
||||||
// 计算每小时的价格
|
|
||||||
hourlyRate() {
|
|
||||||
const price = parseFloat(this.packageInfo.price || 0);
|
|
||||||
let time = parseFloat(this.packageInfo.time || 1);
|
|
||||||
|
|
||||||
// 如果时间单位不是小时(例如分钟),需要转换
|
// 加载订单信息
|
||||||
if (this.packageInfo.time && this.packageInfo.time.includes('分钟')) {
|
const loadOrderInfo = async () => {
|
||||||
time = time / 60; // 将分钟转换为小时
|
try {
|
||||||
} else if (this.packageInfo.time && this.packageInfo.time.includes('次')) {
|
uni.showLoading({
|
||||||
// 按次计费时,暂时显示单次价格
|
title: t('common.loading')
|
||||||
return price.toFixed(2);
|
})
|
||||||
|
|
||||||
|
const res = await queryById(orderId.value)
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
const orderData = res.data
|
||||||
|
|
||||||
|
// 处理创建时间
|
||||||
|
let formattedTime;
|
||||||
|
try {
|
||||||
|
if (orderData.createTime) {
|
||||||
|
formattedTime = formatTime(new Date(orderData.createTime));
|
||||||
|
} else {
|
||||||
|
formattedTime = formatTime(new Date());
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('时间格式化错误:', e);
|
||||||
|
formattedTime = formatTime(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 避免除以零
|
orderInfo.value = {
|
||||||
if (time <= 0) time = 1;
|
orderNo: orderData.orderNo || orderData.orderId,
|
||||||
|
deviceNo: orderData.deviceNo,
|
||||||
// 计算每小时价格
|
createTime: formattedTime,
|
||||||
return (price / time).toFixed(2);
|
phone: orderData.phone,
|
||||||
|
deposit: passedDepositAmount.value || orderData.depositAmount || '99.00',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (orderData.packageTime && orderData.packagePrice) {
|
||||||
|
const timeInHours = (parseFloat(orderData.packageTime) / 60).toFixed(1);
|
||||||
|
packageInfo.value = {
|
||||||
|
time: timeInHours.toString(),
|
||||||
|
price: orderData.packagePrice.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceNo.value = orderData.deviceNo;
|
||||||
|
await loadDeviceInfo();
|
||||||
|
} else {
|
||||||
|
throw new Error(t('order.getOrderFailed'))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取订单信息失败:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('order.getOrderFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载设备信息
|
||||||
|
const loadDeviceInfo = async () => {
|
||||||
|
if (!deviceNo.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await getDeviceInfo(deviceNo.value);
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
deviceInfo.value = res.data.device;
|
||||||
|
|
||||||
|
if (deviceInfo.value && deviceInfo.value.depositAmount) {
|
||||||
|
orderInfo.value.deposit = deviceInfo.value.depositAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设备信息失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理支付
|
||||||
|
const handlePayment = async () => {
|
||||||
|
try {
|
||||||
|
uni.showLoading({
|
||||||
|
title: t('common.processing')
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await createWxPayment(orderInfo.value.orderNo)
|
||||||
|
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
const payParams = res.data
|
||||||
|
|
||||||
|
await uni.requestPayment({
|
||||||
|
...payParams,
|
||||||
|
success: async () => {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('payment.paymentSuccess'),
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateUserBalance(orderId.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('更新用户余额失败:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/order/index?orderId=${orderId.value}`
|
||||||
|
});
|
||||||
|
}, 1500);
|
||||||
},
|
},
|
||||||
onLoad(options) {
|
fail: (err) => {
|
||||||
// 设置页面标题
|
console.error('支付失败:', err)
|
||||||
|
uni.showToast({
|
||||||
|
title: t('payment.paymentFailedRetry'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(res?.msg || t('payment.createPayOrderFailed'))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('支付失败:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('payment.paymentFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化时间
|
||||||
|
const formatTime = (date) => {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||||
|
const day = date.getDate().toString().padStart(2, '0')
|
||||||
|
const hour = date.getHours().toString().padStart(2, '0')
|
||||||
|
const minute = date.getMinutes().toString().padStart(2, '0')
|
||||||
|
|
||||||
|
return `${year}-${month}-${day} ${hour}:${minute}`
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: this.$t('payment.orderPayment')
|
title: t('payment.orderPayment')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (options && options.orderId) {
|
if (options && options.orderId) {
|
||||||
this.orderId = options.orderId
|
orderId.value = options.orderId
|
||||||
|
|
||||||
if (options.totalAmount) {
|
if (options.totalAmount) {
|
||||||
this.passedTotalAmount = options.depositAmount;
|
passedTotalAmount.value = options.totalAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.depositAmount) {
|
if (options.depositAmount) {
|
||||||
this.passedDepositAmount = options.depositAmount;
|
passedDepositAmount.value = options.depositAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果URL中包含了feeConfig参数,保存它
|
|
||||||
if (options.feeConfig) {
|
if (options.feeConfig) {
|
||||||
try {
|
try {
|
||||||
console.log('从URL获取到feeConfig:', options.feeConfig)
|
|
||||||
const feeConfigStr = decodeURIComponent(options.feeConfig)
|
const feeConfigStr = decodeURIComponent(options.feeConfig)
|
||||||
// 创建一个临时的deviceInfo对象保存feeConfig
|
deviceInfo.value = { feeConfig: feeConfigStr }
|
||||||
this.deviceInfo = { feeConfig: feeConfigStr }
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析URL中的feeConfig失败:', e)
|
console.error('解析URL中的feeConfig失败:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadOrderInfo()
|
loadOrderInfo()
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('order.orderNotExist'),
|
title: t('order.orderNotExist'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -157,247 +271,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}, 1500)
|
}, 1500)
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
methods: {
|
|
||||||
// 加载订单信息
|
|
||||||
async loadOrderInfo() {
|
|
||||||
try {
|
|
||||||
uni.showLoading({
|
|
||||||
title: this.$t('common.loading')
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await queryById(this.orderId)
|
|
||||||
if (res.code === 200 && res.data) {
|
|
||||||
const orderData = res.data
|
|
||||||
|
|
||||||
// 处理创建时间,确保显示的是格式化后的时间
|
|
||||||
let formattedTime;
|
|
||||||
try {
|
|
||||||
// 如果orderData.createTime存在并且是有效的日期字符串/时间戳,则格式化它
|
|
||||||
if (orderData.createTime) {
|
|
||||||
formattedTime = this.formatTime(new Date(orderData.createTime));
|
|
||||||
} else {
|
|
||||||
// 如果createTime不存在,使用当前时间作为创建时间
|
|
||||||
formattedTime = this.formatTime(new Date());
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('时间格式化错误:', e);
|
|
||||||
formattedTime = this.formatTime(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.orderInfo = {
|
|
||||||
orderNo: orderData.orderNo || orderData.orderId,
|
|
||||||
deviceNo: orderData.deviceNo,
|
|
||||||
createTime: formattedTime,
|
|
||||||
phone: orderData.phone,
|
|
||||||
deposit: this.passedDepositAmount || orderData.depositAmount || '99.00',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 直接从订单数据中获取套餐信息
|
|
||||||
if (orderData.packageTime && orderData.packagePrice) {
|
|
||||||
// 将分钟转换为小时
|
|
||||||
const timeInHours = (parseFloat(orderData.packageTime) / 60).toFixed(1);
|
|
||||||
this.packageInfo = {
|
|
||||||
time: timeInHours.toString(),
|
|
||||||
price: orderData.packagePrice.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取设备信息(但不再用于设置套餐信息)
|
|
||||||
this.deviceNo = orderData.deviceNo;
|
|
||||||
await this.loadDeviceInfo();
|
|
||||||
} else {
|
|
||||||
throw new Error('获取订单信息失败')
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
} catch (error) {
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: error.message || '获取订单信息失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 加载设备信息
|
|
||||||
async loadDeviceInfo() {
|
|
||||||
if (!this.deviceNo) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await getDeviceInfo(this.deviceNo);
|
|
||||||
if (res.code === 200 && res.data) {
|
|
||||||
this.deviceInfo = res.data.device;
|
|
||||||
|
|
||||||
// 设置存款金额
|
|
||||||
if (this.deviceInfo && this.deviceInfo.depositAmount) {
|
|
||||||
this.orderInfo.deposit = this.deviceInfo.depositAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取设备信息失败:', error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 处理支付
|
|
||||||
async handlePayment() {
|
|
||||||
try {
|
|
||||||
uni.showLoading({
|
|
||||||
title: this.$t('common.processing')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 调用后端创建微信支付订单接口
|
|
||||||
const res = await uni.request({
|
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/create/${this.orderInfo.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: async () => {
|
|
||||||
uni.showToast({
|
|
||||||
title: this.$t('payment.paymentSuccess'),
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新用户余额
|
|
||||||
try {
|
|
||||||
await updateUserBalance(this.orderId);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('更新用户余额失败:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 支付成功后直接跳转到订单页面,不再轮询
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({
|
|
||||||
url: `/pages/order/index?orderId=${this.orderId}`
|
|
||||||
});
|
|
||||||
}, 1500);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('支付失败:', err)
|
|
||||||
throw new Error(this.$t('payment.paymentFailedRetry'))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
throw new Error(res.data.msg || '创建支付订单失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: error.message || '支付失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 发送租借指令
|
|
||||||
async sendRentCommand() {
|
|
||||||
try {
|
|
||||||
uni.showLoading({
|
|
||||||
title: this.$t('common.processing')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 调用发送租借指令的接口
|
|
||||||
const res = await this.sendRentRequest()
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: this.$t('device.rentSuccess'),
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 跳转到订单列表页面
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({
|
|
||||||
url: `/pages/order/index?orderId=${this.orderId}`
|
|
||||||
})
|
|
||||||
}, 1500)
|
|
||||||
} else {
|
|
||||||
throw new Error(res.msg || this.$t('device.rentFailed'))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: error.message || this.$t('device.rentFailed'),
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 发送租借请求
|
|
||||||
sendRentRequest() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
uni.request({
|
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/device/sendRentCommand`,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
orderId: this.orderId
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
},
|
|
||||||
success(res) {
|
|
||||||
if (res.statusCode === 200) {
|
|
||||||
resolve(res.data)
|
|
||||||
} else {
|
|
||||||
reject(new Error('请求失败'))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail(err) {
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 格式化时间
|
|
||||||
formatTime(date) {
|
|
||||||
const year = date.getFullYear()
|
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
||||||
const day = date.getDate().toString().padStart(2, '0')
|
|
||||||
const hour = date.getHours().toString().padStart(2, '0')
|
|
||||||
const minute = date.getMinutes().toString().padStart(2, '0')
|
|
||||||
|
|
||||||
return `${year}-${month}-${day} ${hour}:${minute}`
|
|
||||||
},
|
|
||||||
|
|
||||||
// 检查订单状态(单次查询,不轮询)
|
|
||||||
async checkOrderStatus() {
|
|
||||||
try {
|
|
||||||
const res = await uni.request({
|
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/status/${this.orderInfo.orderNo}`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
|
||||||
return res.data.data;
|
|
||||||
} else {
|
|
||||||
throw new Error('查询订单状态失败');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('查询订单状态错误:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { queryById } from '@/config/api/order.js'
|
import { queryById } from '@/config/api/order.js'
|
||||||
|
import { withdrawDeposit } from '@/config/api/user.js'
|
||||||
import {
|
import {
|
||||||
URL
|
URL
|
||||||
}from"@/config/url.js"
|
}from"@/config/url.js"
|
||||||
@@ -234,17 +235,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
uni.showLoading({ title: this.$t('common.processing') });
|
uni.showLoading({ title: this.$t('common.processing') });
|
||||||
|
|
||||||
const res = await uni.request({
|
const res = await withdrawDeposit(this.orderInfo.orderNo)
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/withdraw/add/${this.orderInfo.orderNo}`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
if (res && res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('order.refundSuccess'),
|
title: this.$t('order.refundSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
@@ -259,7 +252,7 @@ export default {
|
|||||||
this.loadOrderInfo();
|
this.loadOrderInfo();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.msg || this.$t('order.refundFailed'));
|
throw new Error(res?.msg || this.$t('order.refundFailed'));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('退款申请错误:', error);
|
console.error('退款申请错误:', error);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ import {
|
|||||||
} from '../../config/api/device.js'
|
} from '../../config/api/device.js'
|
||||||
import { useI18n } from '../../utils/i18n.js'
|
import { useI18n } from '../../utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const positionInfo = ref({})
|
const positionInfo = ref({})
|
||||||
const positionId = ref('')
|
const positionId = ref('')
|
||||||
@@ -112,7 +112,7 @@ const { t: $t } = useI18n()
|
|||||||
const loadPositionDetail = async () => {
|
const loadPositionDetail = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.loading')
|
title: t('common.loading')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取用户位置用于查询附近设备
|
// 获取用户位置用于查询附近设备
|
||||||
@@ -147,7 +147,7 @@ const { t: $t } = useI18n()
|
|||||||
positionInfo.value = position
|
positionInfo.value = position
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('location.notExist'),
|
title: t('location.notExist'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ const { t: $t } = useI18n()
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载设备详情失败:', e)
|
console.error('加载设备详情失败:', e)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('common.loadFailed'),
|
title: t('common.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -166,7 +166,7 @@ const { t: $t } = useI18n()
|
|||||||
const navigateToPosition = () => {
|
const navigateToPosition = () => {
|
||||||
if (!positionInfo.value.latitude || !positionInfo.value.longitude) {
|
if (!positionInfo.value.latitude || !positionInfo.value.longitude) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('location.coordinateError'),
|
title: t('location.coordinateError'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -181,7 +181,7 @@ const { t: $t } = useI18n()
|
|||||||
longitude < -180 || longitude > 180 ||
|
longitude < -180 || longitude > 180 ||
|
||||||
(latitude === 0 && longitude === 0)) {
|
(latitude === 0 && longitude === 0)) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('location.coordinateError'),
|
title: t('location.coordinateError'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
+374
-165
@@ -19,12 +19,60 @@
|
|||||||
:class="{ selected: selectedProduct?.id === item.id }" @click="selectProduct(item)">
|
:class="{ selected: selectedProduct?.id === item.id }" @click="selectProduct(item)">
|
||||||
<view class="card-content">
|
<view class="card-content">
|
||||||
<view class="card-left">
|
<view class="card-left">
|
||||||
|
<view class="card-title-row">
|
||||||
<text class="card-name">{{ item.name }}</text>
|
<text class="card-name">{{ item.name }}</text>
|
||||||
|
<view class="card-type-tag" :class="{ 'type-time': item.type === 'TIME', 'type-count': item.type === 'COUNT' }">
|
||||||
|
<text class="card-type-text">{{ item.type === 'TIME' ? $t('myCard.durationCard') : $t('myCard.timesCard') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<text class="card-desc">{{ item.description }}</text>
|
<text class="card-desc">{{ item.description }}</text>
|
||||||
|
|
||||||
|
<!-- 使用限制信息 -->
|
||||||
|
<view class="card-limits">
|
||||||
|
<!-- 时长卡:展示每日限用次数和单次限时 -->
|
||||||
|
<view v-if="item.type === 'TIME'" class="limit-tags">
|
||||||
|
<view class="limit-tag" v-if="item.dailyLimitCount > 0">
|
||||||
|
<text class="limit-label">{{ $t('myCard.dailyLimit') }}:</text>
|
||||||
|
<text class="limit-value">{{ item.dailyLimitCount }}{{ $t('myCard.times') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="limit-tag">
|
||||||
|
<text class="limit-label">{{ $t('myCard.singleTimeLimit') }}:</text>
|
||||||
|
<text class="limit-value" :class="{ unlimited: item.singleLimitMinutes === 0 }">
|
||||||
|
{{ item.singleLimitMinutes > 0 ? item.singleLimitMinutes + $t('myCard.minutes') : $t('myCard.unlimited') }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="limit-tag validity-tag" v-if="item.cycleDays">
|
||||||
|
<text class="limit-value">{{ item.cycleDays }}{{ $t('myCard.daysValid') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 次卡:展示总次数和单次限时 -->
|
||||||
|
<view v-if="item.type === 'COUNT'" class="limit-tags">
|
||||||
|
<view class="limit-tag count-tag" v-if="item.totalCount > 0">
|
||||||
|
<text class="limit-label">{{ $t('myCard.totalCount') }}:</text>
|
||||||
|
<text class="limit-value">{{ item.totalCount }}{{ $t('myCard.times') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="limit-tag">
|
||||||
|
<text class="limit-label">{{ $t('myCard.singleTimeLimit') }}:</text>
|
||||||
|
<text class="limit-value" :class="{ unlimited: item.singleLimitMinutesForCount === 0 }">
|
||||||
|
{{ item.singleLimitMinutesForCount > 0 ? item.singleLimitMinutesForCount + $t('myCard.minutes') : $t('myCard.unlimited') }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="limit-tag validity-tag" v-if="item.validDays">
|
||||||
|
<text class="limit-value">{{ item.validDays }}{{ $t('myCard.daysValid') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-right">
|
<view class="card-right">
|
||||||
<text class="card-price">¥{{ item.price }}</text>
|
<view class="card-price">
|
||||||
<text class="card-original-price" v-if="item.originalPrice">¥{{ item.originalPrice }}</text>
|
<text class="price-currency">¥</text>
|
||||||
|
<text class="price-value">{{ item.price }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-original-price" v-if="item.originalPrice">
|
||||||
|
<text class="original-currency">¥</text>
|
||||||
|
<text class="original-value">{{ item.originalPrice }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -36,19 +84,24 @@
|
|||||||
<!-- 优惠券列表 -->
|
<!-- 优惠券列表 -->
|
||||||
<view v-if="currentTab === 'coupon'" class="product-list">
|
<view v-if="currentTab === 'coupon'" class="product-list">
|
||||||
<view v-for="item in coupons" :key="item.id" class="coupon-card-wrapper">
|
<view v-for="item in coupons" :key="item.id" class="coupon-card-wrapper">
|
||||||
<view class="coupon-card"
|
<view class="coupon-card" :class="{ selected: selectedProduct?.id === item.id }"
|
||||||
:class="{ selected: selectedProduct?.id === item.id }" @click="selectProduct(item)">
|
@click="selectProduct(item)">
|
||||||
<!-- 左侧圆形缺口 -->
|
<!-- 左侧圆形缺口 -->
|
||||||
<view class="coupon-circle-left"></view>
|
<view class="coupon-circle-left"></view>
|
||||||
<!-- 右侧圆形缺口 -->
|
<!-- 右侧圆形缺口 -->
|
||||||
<view class="coupon-circle-right"></view>
|
<view class="coupon-circle-right"></view>
|
||||||
|
|
||||||
<view class="coupon-left">
|
<view class="coupon-left">
|
||||||
<text class="coupon-value">{{ item.type === 'discount' ? item.discount + '折' : '¥' + item.value
|
<view class="coupon-value-wrapper">
|
||||||
|
<text class="coupon-value-num">{{ item.type === 'discount' ? item.discount : item.value
|
||||||
}}</text>
|
}}</text>
|
||||||
|
<text class="coupon-value-unit">{{ item.type === 'discount' ? '折' : '¥' }}</text>
|
||||||
|
</view>
|
||||||
|
<view style="display: flex;flex-direction: column;">
|
||||||
<text class="coupon-condition">{{ item.condition }}</text>
|
<text class="coupon-condition">{{ item.condition }}</text>
|
||||||
<text class="coupon-validity">{{ item.validity }}</text>
|
<text class="coupon-validity">{{ item.validity }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<view class="coupon-divider"></view>
|
<view class="coupon-divider"></view>
|
||||||
<view class="coupon-right">
|
<view class="coupon-right">
|
||||||
<view class="coupon-price">
|
<view class="coupon-price">
|
||||||
@@ -79,8 +132,8 @@
|
|||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<view class="bottom-bar">
|
<view class="bottom-bar">
|
||||||
<view class="my-products-wrapper" @click="goToMyProducts">
|
<view class="my-products-wrapper" @click="goToMyProducts">
|
||||||
<view class="" style="display: flex;" >
|
<view class="" style="display: flex;">
|
||||||
<view class="my-products" >
|
<view class="my-products">
|
||||||
<image class="my-products-icon" src="/static/couponList.png" mode="aspectFit">
|
<image class="my-products-icon" src="/static/couponList.png" mode="aspectFit">
|
||||||
</image>
|
</image>
|
||||||
<text class="my-products-text">{{ currentTab === 'card' ? $t('purchase.myCards') :
|
<text class="my-products-text">{{ currentTab === 'card' ? $t('purchase.myCards') :
|
||||||
@@ -107,95 +160,95 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
computed,
|
computed,
|
||||||
onMounted
|
onMounted
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import {
|
import {
|
||||||
onLoad
|
onLoad
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
import {
|
import {
|
||||||
useI18n
|
useI18n
|
||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
import {
|
import {
|
||||||
getCouponsByPosition,
|
getCouponsByPosition,
|
||||||
createCouponPayment,
|
createCouponPayment,
|
||||||
cancelCouponPayment
|
cancelCouponPayment
|
||||||
} from '@/config/api/coupon.js'
|
} from '@/config/api/coupon.js'
|
||||||
// import {
|
// import {
|
||||||
// cancelMemberCardPayment
|
// cancelMemberCardPayment
|
||||||
// } from '@/config/api/member.js'
|
// } from '@/config/api/member.js'
|
||||||
import {
|
import {
|
||||||
createMemberCardPayment,
|
createMemberCardPayment,
|
||||||
getMemberCardsByPosition,
|
getMemberCardsByPosition,
|
||||||
cancelMemberCardPayment
|
cancelMemberCardPayment
|
||||||
} from '@/config/api/member.js'
|
} from '@/config/api/member.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
// 当前选中的 Tab
|
// 当前选中的 Tab
|
||||||
const currentTab = ref('card') // 'card' 或 'coupon'
|
const currentTab = ref('card') // 'card' 或 'coupon'
|
||||||
|
|
||||||
// 选中的商品
|
// 选中的商品
|
||||||
const selectedProduct = ref(null)
|
const selectedProduct = ref(null)
|
||||||
|
|
||||||
// 当前场地ID(从路由参数获取)
|
// 当前场地ID(从路由参数获取)
|
||||||
const positionId = ref(null)
|
const positionId = ref(null)
|
||||||
|
|
||||||
// 生命周期 onLoad 钩子 - 获取路由参数
|
// 生命周期 onLoad 钩子 - 获取路由参数
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
if (options.positionId) {
|
if (options.positionId) {
|
||||||
positionId.value = options.positionId
|
positionId.value = options.positionId
|
||||||
console.log('获取到场地ID:', positionId.value)
|
console.log('获取到场地ID:', positionId.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 会员卡列表(从后端加载)
|
// 会员卡列表(从后端加载)
|
||||||
const memberCards = ref([])
|
const memberCards = ref([])
|
||||||
|
|
||||||
// 优惠券列表(从后端加载)
|
// 优惠券列表(从后端加载)
|
||||||
const coupons = ref([])
|
const coupons = ref([])
|
||||||
|
|
||||||
// 说明内容
|
// 说明内容
|
||||||
const descriptions = computed(() => {
|
const descriptions = computed(() => {
|
||||||
if (currentTab.value === 'card') {
|
if (currentTab.value === 'card') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: $t('purchase.cardUseInstruction'),
|
title: t('purchase.cardUseInstruction'),
|
||||||
content: $t('purchase.cardUseDescription')
|
content: t('purchase.cardUseDescription')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: $t('purchase.cardValidityPeriod'),
|
title: t('purchase.cardValidityPeriod'),
|
||||||
content: $t('purchase.cardValidityDescription')
|
content: t('purchase.cardValidityDescription')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: $t('purchase.cardRefundPolicy'),
|
title: t('purchase.cardRefundPolicy'),
|
||||||
content: $t('purchase.cardRefundDescription')
|
content: t('purchase.cardRefundDescription')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: $t('purchase.couponUseInstruction'),
|
title: t('purchase.couponUseInstruction'),
|
||||||
content: $t('purchase.couponUseDescription')
|
content: t('purchase.couponUseDescription')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: $t('purchase.couponValidityPeriod'),
|
title: t('purchase.couponValidityPeriod'),
|
||||||
content: $t('purchase.couponValidityDescription')
|
content: t('purchase.couponValidityDescription')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: $t('purchase.couponUsageScope'),
|
title: t('purchase.couponUsageScope'),
|
||||||
content: $t('purchase.couponUsageDescription')
|
content: t('purchase.couponUsageDescription')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 加载会员卡列表
|
// 加载会员卡列表
|
||||||
const loadMemberCards = async () => {
|
const loadMemberCards = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: '加载中...'
|
title: '加载中...'
|
||||||
@@ -215,8 +268,9 @@
|
|||||||
originalPrice: null,
|
originalPrice: null,
|
||||||
availablePositions: item.positionName,
|
availablePositions: item.positionName,
|
||||||
cycleDays: item.cycleDays,
|
cycleDays: item.cycleDays,
|
||||||
dailyLimitCount: item.dailyLimitCount,
|
dailyLimitCount: item.dailyLimitCount || 0,
|
||||||
singleLimitMinutes: item.singleLimitMinutes,
|
singleLimitMinutes: item.singleLimitMinutes || 0,
|
||||||
|
singleLimitMinutesForCount: item.singleLimitMinutesForCount || 0,
|
||||||
validDays: item.validDays,
|
validDays: item.validDays,
|
||||||
totalCount: item.totalCount,
|
totalCount: item.totalCount,
|
||||||
purchaseQuantity: item.purchaseQuantity
|
purchaseQuantity: item.purchaseQuantity
|
||||||
@@ -230,11 +284,11 @@
|
|||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 加载优惠券列表
|
// 加载优惠券列表
|
||||||
const loadCoupons = async () => {
|
const loadCoupons = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: '加载中...'
|
title: '加载中...'
|
||||||
@@ -249,7 +303,7 @@
|
|||||||
id: item.couponId,
|
id: item.couponId,
|
||||||
couponId: item.couponId,
|
couponId: item.couponId,
|
||||||
name: item.couponName,
|
name: item.couponName,
|
||||||
type: item.couponType === '1' ? 'discount' : 'cash',
|
type: item.couponType === 'discount_coupon' ? 'discount' : 'cash',
|
||||||
discount: item.discountRate ? (item.discountRate * 10).toFixed(0) : null,
|
discount: item.discountRate ? (item.discountRate * 10).toFixed(0) : null,
|
||||||
value: item.deductAmount ? item.deductAmount.toString() : null,
|
value: item.deductAmount ? item.deductAmount.toString() : null,
|
||||||
condition: item.usableCondition > 0 ? `满${item.usableCondition}元可用` : '无门槛',
|
condition: item.usableCondition > 0 ? `满${item.usableCondition}元可用` : '无门槛',
|
||||||
@@ -268,10 +322,10 @@
|
|||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 加载会员卡列表
|
// 加载会员卡列表
|
||||||
if (positionId.value) {
|
if (positionId.value) {
|
||||||
await loadMemberCards()
|
await loadMemberCards()
|
||||||
@@ -286,24 +340,24 @@
|
|||||||
if (memberCards.value.length > 0) {
|
if (memberCards.value.length > 0) {
|
||||||
selectedProduct.value = memberCards.value[0]
|
selectedProduct.value = memberCards.value[0]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const switchTab = (tab) => {
|
const switchTab = (tab) => {
|
||||||
currentTab.value = tab
|
currentTab.value = tab
|
||||||
selectedProduct.value = null
|
selectedProduct.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选择商品
|
// 选择商品
|
||||||
const selectProduct = (product) => {
|
const selectProduct = (product) => {
|
||||||
selectedProduct.value = product
|
selectedProduct.value = product
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderNo = ref('')
|
const orderNo = ref('')
|
||||||
|
|
||||||
// 处理购买
|
// 处理购买
|
||||||
const handleBuy = async () => {
|
const handleBuy = async () => {
|
||||||
if (!selectedProduct.value) {
|
if (!selectedProduct.value) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('purchase.pleaseSelect'),
|
title: t('purchase.pleaseSelect'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -454,10 +508,10 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看我的商品
|
// 查看我的商品
|
||||||
const goToMyProducts = () => {
|
const goToMyProducts = () => {
|
||||||
if (currentTab.value === 'card') {
|
if (currentTab.value === 'card') {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/my/card'
|
url: '/pages/my/card'
|
||||||
@@ -467,76 +521,85 @@
|
|||||||
url: '/pages/my/coupon'
|
url: '/pages/my/coupon'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.purchase-page {
|
.purchase-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
padding-bottom: 180rpx;
|
padding-bottom: 180rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tab 切换 */
|
/* Tab 切换 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
top: 0;
|
top: 20rpx;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
|
width: 500rpx;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
padding: 20rpx 0;
|
padding: 5rpx 0;
|
||||||
}
|
margin: 0 auto;
|
||||||
|
border-radius: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20rpx 0;
|
padding: 10rpx 30rpx;
|
||||||
|
margin: 0 10rpx;
|
||||||
|
width: 120rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.tab-text {
|
.tab-text {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #A6A6A6;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
background:#FFE2B8;
|
||||||
|
border-radius: 26rpx;
|
||||||
|
|
||||||
|
|
||||||
.tab-text {
|
.tab-text {
|
||||||
color: #333;
|
color: #A16300;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
// &::after {
|
||||||
content: '';
|
// content: '';
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
bottom: 0;
|
// bottom: 0;
|
||||||
left: 50%;
|
// left: 50%;
|
||||||
transform: translateX(-50%);
|
// transform: translateX(-50%);
|
||||||
width: 60rpx;
|
// width: 60rpx;
|
||||||
height: 6rpx;
|
// height: 6rpx;
|
||||||
background-color: #FFA928;
|
// background-color: #FFA928;
|
||||||
border-radius: 3rpx;
|
// border-radius: 3rpx;
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 内容区域 */
|
/* 内容区域 */
|
||||||
.content-area {
|
.content-area {
|
||||||
height: calc(100vh - 180rpx);
|
height: calc(100vh - 180rpx);
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
padding-top: 120rpx;
|
padding-top: 80rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 商品列表 */
|
/* 商品列表 */
|
||||||
.product-list {
|
.product-list {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 会员卡卡片 */
|
/* 会员卡卡片 */
|
||||||
.product-card {
|
.product-card {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
padding: 30rpx;
|
padding: 30rpx;
|
||||||
@@ -567,18 +630,118 @@
|
|||||||
gap: 10rpx;
|
gap: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.card-name {
|
.card-name {
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-type-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.type-time {
|
||||||
|
background-color: #E6F7FF;
|
||||||
|
border: 1rpx solid #91D5FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-count {
|
||||||
|
background-color: #FFF1F0;
|
||||||
|
border: 1rpx solid #FFCCC7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-type-text {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-time .card-type-text {
|
||||||
|
color: #1890FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-count .card-type-text {
|
||||||
|
color: #FF4D4F;
|
||||||
|
}
|
||||||
|
|
||||||
.card-desc {
|
.card-desc {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 会员卡限制信息样式 */
|
||||||
|
.card-limits {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.limit-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8rpx;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.limit-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4rpx;
|
||||||
|
padding: 6rpx 12rpx;
|
||||||
|
background-color: #FFF4E6;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
border: 1rpx solid #FFE8CC;
|
||||||
|
|
||||||
|
.limit-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #B8741A;
|
||||||
|
// font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.limit-value {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #FF6B00;
|
||||||
|
// font-weight: 600;
|
||||||
|
|
||||||
|
&.unlimited {
|
||||||
|
color: #07c160;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 有效期标签特殊样式 */
|
||||||
|
&.validity-tag {
|
||||||
|
background-color: #F0F5FF;
|
||||||
|
border: 1rpx solid #D6E4FF;
|
||||||
|
|
||||||
|
.limit-value {
|
||||||
|
color: #1890FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 总次数标签特殊样式 */
|
||||||
|
&.count-tag {
|
||||||
|
background-color: #FFF1F0;
|
||||||
|
border: 1rpx solid #FFCCC7;
|
||||||
|
|
||||||
|
.limit-label {
|
||||||
|
color: #CF1322;
|
||||||
|
}
|
||||||
|
|
||||||
|
.limit-value {
|
||||||
|
color: #FF4D4F;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.card-right {
|
.card-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -587,29 +750,54 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-price {
|
.card-price {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 2rpx;
|
||||||
|
|
||||||
|
.price-currency {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #FF6B00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-value {
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #FF6B00;
|
color: #FF6B00;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.card-original-price {
|
.card-original-price {
|
||||||
font-size: 24rpx;
|
display: flex;
|
||||||
color: #999;
|
align-items: baseline;
|
||||||
|
gap: 2rpx;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
|
||||||
|
.original-currency {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 优惠券卡片 */
|
.original-value {
|
||||||
.coupon-card-wrapper {
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优惠券卡片 */
|
||||||
|
.coupon-card-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-card {
|
.coupon-card {
|
||||||
background: linear-gradient(135deg, #FFF4E6 0%, #FFE8CC 100%);
|
background: linear-gradient(135deg, #FFF4E6 0%, #FFE8CC 100%);
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
padding: 40rpx 30rpx;
|
padding: 40rpx 30rpx;
|
||||||
@@ -632,10 +820,10 @@
|
|||||||
border: 2rpx solid #B8741A;
|
border: 2rpx solid #B8741A;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 左侧圆形缺口 */
|
/* 左侧圆形缺口 */
|
||||||
.coupon-circle-left {
|
.coupon-circle-left {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -16rpx;
|
left: -16rpx;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -647,10 +835,10 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 右侧圆形缺口 */
|
/* 右侧圆形缺口 */
|
||||||
.coupon-circle-right {
|
.coupon-circle-right {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -16rpx;
|
right: -16rpx;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -662,32 +850,53 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-left {
|
.coupon-left {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
gap: 8rpx;
|
gap: 8rpx;
|
||||||
}
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-value {
|
/* 优惠券金额显示包裹器 */
|
||||||
|
.coupon-value-wrapper {
|
||||||
|
width: 180rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优惠券实际值(数字) */
|
||||||
|
.coupon-value-num {
|
||||||
|
font-size: 52rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #B8741A;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优惠券单位(折/¥) */
|
||||||
|
.coupon-value-unit {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #B8741A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-value {
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #B8741A;
|
color: #B8741A;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-condition {
|
.coupon-condition {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-validity {
|
.coupon-validity {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-divider {
|
.coupon-divider {
|
||||||
width: 2rpx;
|
width: 2rpx;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -703,9 +912,9 @@
|
|||||||
transparent 8rpx,
|
transparent 8rpx,
|
||||||
transparent 16rpx);
|
transparent 16rpx);
|
||||||
margin: 0 30rpx;
|
margin: 0 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-right {
|
.coupon-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -727,51 +936,51 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 说明部分 */
|
/* 说明部分 */
|
||||||
.description-section {
|
.description-section {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
padding: 30rpx;
|
padding: 30rpx;
|
||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-title {
|
.description-title {
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-content {
|
.description-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20rpx;
|
gap: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-item {
|
.description-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10rpx;
|
gap: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-subtitle {
|
.description-subtitle {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-text {
|
.description-text {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底部操作栏 */
|
/* 底部操作栏 */
|
||||||
.bottom-bar {
|
.bottom-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -783,9 +992,9 @@
|
|||||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.my-products-wrapper {
|
.my-products-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -793,9 +1002,9 @@
|
|||||||
border-radius: 40rpx;
|
border-radius: 40rpx;
|
||||||
padding: 16rpx 32rpx;
|
padding: 16rpx 32rpx;
|
||||||
border-radius: 40rpx 40rpx 0 0;
|
border-radius: 40rpx 40rpx 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-wrapper {
|
.action-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -803,9 +1012,9 @@
|
|||||||
margin-left: 20rpx;
|
margin-left: 20rpx;
|
||||||
margin-right: 20rpx;
|
margin-right: 20rpx;
|
||||||
padding-top: 20rpx;
|
padding-top: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.my-products {
|
.my-products {
|
||||||
display: flex;
|
display: flex;
|
||||||
// flex-direction: column;
|
// flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -834,30 +1043,30 @@
|
|||||||
color: #A16300;
|
color: #A16300;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-info {
|
.price-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
// align-items: flex-end;
|
// align-items: flex-end;
|
||||||
gap: 4rpx;
|
gap: 4rpx;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin: 0 20rpx;
|
margin: 0 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-price {
|
.current-price {
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #FF6B00;
|
color: #FF6B00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.original-price {
|
.original-price {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buy-button {
|
.buy-button {
|
||||||
padding: 24rpx 60rpx;
|
padding: 24rpx 60rpx;
|
||||||
background-color: #B8741A;
|
background-color: #B8741A;
|
||||||
border-radius: 48rpx;
|
border-radius: 48rpx;
|
||||||
@@ -873,5 +1082,5 @@
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
+5
-11
@@ -143,7 +143,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
queryById,
|
queryById,
|
||||||
cancelOrder
|
cancelOrder,
|
||||||
|
getInUseOrder
|
||||||
} from '@/config/api/order.js'
|
} from '@/config/api/order.js'
|
||||||
import {
|
import {
|
||||||
getSystemConfig
|
getSystemConfig
|
||||||
@@ -710,19 +711,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 这里调用API查询该设备的使用中订单
|
// 这里调用API查询该设备的使用中订单
|
||||||
const inUseRes = await uni.request({
|
const inUseRes = await getInUseOrder()
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/order/inUse`,
|
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('通过设备号查询订单结果:', JSON.stringify(inUseRes))
|
console.log('通过设备号查询订单结果:', JSON.stringify(inUseRes))
|
||||||
|
|
||||||
if (inUseRes.statusCode === 200 && inUseRes.data.code === 200 && inUseRes.data.data) {
|
if (inUseRes && inUseRes.code === 200 && inUseRes.data) {
|
||||||
const inUseOrder = inUseRes.data.data
|
const inUseOrder = inUseRes.data
|
||||||
console.log('使用中的订单:', inUseOrder)
|
console.log('使用中的订单:', inUseOrder)
|
||||||
|
|
||||||
// 更新订单ID
|
// 更新订单ID
|
||||||
|
|||||||
+51
-40
@@ -22,15 +22,19 @@
|
|||||||
:class="{ available: isRentable(item), invalid: !isValidCoordinate(item.latitude, item.longitude) }"
|
:class="{ available: isRentable(item), invalid: !isValidCoordinate(item.latitude, item.longitude) }"
|
||||||
v-for="(item, index) in filteredPositions" :key="item.positionId || index"
|
v-for="(item, index) in filteredPositions" :key="item.positionId || index"
|
||||||
@click="goToPositionDetail(item)">
|
@click="goToPositionDetail(item)">
|
||||||
|
<!-- 第一行:三列布局 -->
|
||||||
|
<view class="card-row-first">
|
||||||
|
<!-- 第一列:缩略图 -->
|
||||||
<view class="thumb">
|
<view class="thumb">
|
||||||
<image v-if="item.deviceImg" :src="item.deviceImg" class="thumb-img" mode="aspectFill">
|
<image v-if="item.deviceImg" :src="item.deviceImg" class="thumb-img" mode="aspectFill">
|
||||||
</image>
|
</image>
|
||||||
<image v-else src="/static/device-info.png" class="thumb-img" mode="aspectFit"></image>
|
<image v-else src="/static/device-info.png" class="thumb-img" mode="aspectFit"></image>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 第二列:信息 -->
|
||||||
<view class="info">
|
<view class="info">
|
||||||
<view class="row top">
|
<view class="row top">
|
||||||
<view class="name">{{ item.name }}</view>
|
<view class="name">{{ item.name }}</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view class="row sub" v-if="item.location">
|
<view class="row sub" v-if="item.location">
|
||||||
<text class="addr">{{ item.location }}</text>
|
<text class="addr">{{ item.location }}</text>
|
||||||
@@ -41,32 +45,28 @@
|
|||||||
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
||||||
<text class="time" style="color: #ff6b6b;">{{ $t('location.coordinateError') }}</text>
|
<text class="time" style="color: #ff6b6b;">{{ $t('location.coordinateError') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="row meta"
|
|
||||||
v-if="item.availablePowerBankCount !== undefined && item.availablePowerBankCount !== null">
|
|
||||||
<text class="time">可租借:{{ item.availablePowerBankCount }} 台</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="row meta"
|
|
||||||
v-if="item.availableEmptyGridCount !== undefined && item.availableEmptyGridCount !== null">
|
|
||||||
<text class="time">可归还:{{ item.availableEmptyGridCount }} 个空位</text>
|
|
||||||
</view>
|
|
||||||
<view class="row meta remark-info" v-if="item.remark">
|
|
||||||
<text class="time">💰 {{ item.remark }}</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 class="tag" v-if="isCoupon(item)">{{CouponOrmember(item)}}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="actions">
|
|
||||||
|
|
||||||
|
<!-- 第三列:操作 -->
|
||||||
|
<view class="actions">
|
||||||
<view class="nav" :class="{ disabled: !isValidCoordinate(item.latitude, item.longitude) }"
|
<view class="nav" :class="{ disabled: !isValidCoordinate(item.latitude, item.longitude) }"
|
||||||
@click.stop="navigateToPosition(item)">
|
@click.stop="navigateToPosition(item)">
|
||||||
<image src="/static/luxian.png" class="action-icon" mode="aspectFit"></image>
|
<image src="/static/luxian.png" class="action-icon" mode="aspectFit"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="distance"
|
<view class="distance"
|
||||||
v-if="item.distance && isValidCoordinate(item.latitude, item.longitude)">
|
v-if="item.distance && isValidCoordinate(item.latitude, item.longitude)">
|
||||||
{{ item.distance }}</view>
|
{{ item.distance }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 第二行:标签 -->
|
||||||
|
<view class="card-row-second">
|
||||||
|
<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 class="tag coupon" v-if="item.supportCouponOrMember">{{ $t('location.supportCouponOrMember') }}</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -101,13 +101,13 @@
|
|||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
t: $t
|
t
|
||||||
} = useI18n()
|
} = useI18n()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('search.title')
|
title: t('search.title')
|
||||||
})
|
})
|
||||||
// uni.showLoading({
|
// uni.showLoading({
|
||||||
// title:'11111',
|
// title:'11111',
|
||||||
@@ -133,11 +133,6 @@
|
|||||||
return String(item?.status || '').toLowerCase() === 'online'
|
return String(item?.status || '').toLowerCase() === 'online'
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCoupon = (item)=>{
|
|
||||||
if(typeof item.canCoupon!=='undefined')return !!item.canCoupon
|
|
||||||
return String(item?.canCoupon||'').toLowerCase()==='true';
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatDistance = (meters) => {
|
const formatDistance = (meters) => {
|
||||||
if (meters < 1000) return `${Math.round(meters)}m`
|
if (meters < 1000) return `${Math.round(meters)}m`
|
||||||
return `${(meters / 1000).toFixed(1)}km`
|
return `${(meters / 1000).toFixed(1)}km`
|
||||||
@@ -193,11 +188,6 @@
|
|||||||
applyFilter()
|
applyFilter()
|
||||||
}
|
}
|
||||||
|
|
||||||
const CouponOrmember= async(item)=>{
|
|
||||||
|
|
||||||
return "可使用优惠券、会员卡"
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadPositions = async (center) => {
|
const loadPositions = async (center) => {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
@@ -227,8 +217,8 @@
|
|||||||
return {
|
return {
|
||||||
...transformed,
|
...transformed,
|
||||||
canRent: activeTab.value === 'rent' ? true : (device.availablePowerBankCount > 0),
|
canRent: activeTab.value === 'rent' ? true : (device.availablePowerBankCount > 0),
|
||||||
canReturn: activeTab.value === 'return' ? true : (device.availableEmptyGridCount >
|
canReturn: activeTab.value === 'return' ? true : (device.availableEmptyGridCount > 0),
|
||||||
0)
|
supportCouponOrMember: device.supportCouponOrMember || false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -267,7 +257,7 @@ const init = async () => {
|
|||||||
positionList.value = []
|
positionList.value = []
|
||||||
filteredPositions.value = []
|
filteredPositions.value = []
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('home.getLocationFailed'),
|
title: t('home.getLocationFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -289,7 +279,7 @@ const init = async () => {
|
|||||||
const navigateToPosition = (position) => {
|
const navigateToPosition = (position) => {
|
||||||
if (!isValidCoordinate(position.latitude, position.longitude)) {
|
if (!isValidCoordinate(position.latitude, position.longitude)) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('search.invalidCoordinate'),
|
title: t('search.invalidCoordinate'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -307,7 +297,7 @@ const init = async () => {
|
|||||||
const goToPositionDetail = (position) => {
|
const goToPositionDetail = (position) => {
|
||||||
if (!position.positionId) {
|
if (!position.positionId) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('search.positionInfoError'),
|
title: t('search.positionInfoError'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -403,9 +393,8 @@ const init = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 120rpx 1fr 72rpx;
|
flex-direction: column;
|
||||||
align-items: center;
|
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
@@ -424,6 +413,21 @@ const init = async () => {
|
|||||||
background: #FFF9F9;
|
background: #FFF9F9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 第一行:三列布局
|
||||||
|
.card-row-first {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 120rpx 1fr 72rpx;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二行:标签
|
||||||
|
.card-row-second {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 8rpx;
|
||||||
|
// border-top: 1rpx solid #F0F0F0;
|
||||||
|
}
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
width: 120rpx;
|
width: 120rpx;
|
||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
@@ -453,7 +457,7 @@ const init = async () => {
|
|||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #2A2A2A;
|
color: #2A2A2A;
|
||||||
max-width: 70%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -485,9 +489,11 @@ const init = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 10rpx;
|
gap: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,6 +513,10 @@ const init = async () => {
|
|||||||
background: #E8F2FF;
|
background: #E8F2FF;
|
||||||
color: #3578e5;
|
color: #3578e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag.coupon {
|
||||||
|
background: #FFF9F0;
|
||||||
|
color: #D4A574;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@@ -514,6 +524,7 @@ const init = async () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
|
|||||||
+9
-33
@@ -33,7 +33,7 @@ import { ref, computed, onMounted, getCurrentInstance } from 'vue'
|
|||||||
import { userLogout } from '@/config/api/user.js'
|
import { userLogout } from '@/config/api/user.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 获取全局 i18n 实例
|
// 获取全局 i18n 实例
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
@@ -42,7 +42,7 @@ const globalI18n = instance?.appContext?.config?.globalProperties?.$i18n
|
|||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('settings.title')
|
title: t('settings.title')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ const currentLanguage = ref(uni.getStorageSync('language') || 'zh-CN')
|
|||||||
|
|
||||||
// 当前语言文本显示
|
// 当前语言文本显示
|
||||||
const currentLanguageText = computed(() => {
|
const currentLanguageText = computed(() => {
|
||||||
return currentLanguage.value === 'zh-CN' ? '简体中文' : 'English'
|
return currentLanguage.value === 'zh-CN' ? t('settings.chinese') : t('settings.english')
|
||||||
})
|
})
|
||||||
|
|
||||||
const navigateTo = (url) => {
|
const navigateTo = (url) => {
|
||||||
@@ -61,57 +61,33 @@ const navigateTo = (url) => {
|
|||||||
// 显示语言选择器
|
// 显示语言选择器
|
||||||
const showLanguageSelector = () => {
|
const showLanguageSelector = () => {
|
||||||
uni.showActionSheet({
|
uni.showActionSheet({
|
||||||
itemList: ['简体中文', 'English'],
|
itemList: [t('settings.chinese'), t('settings.english')],
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const lang = res.tapIndex === 0 ? 'zh-CN' : 'en-US'
|
const lang = res.tapIndex === 0 ? 'zh-CN' : 'en-US'
|
||||||
if (lang !== currentLanguage.value) {
|
if (lang !== currentLanguage.value) {
|
||||||
console.log('========================================')
|
|
||||||
console.log('=== 用户选择切换语言 ===')
|
|
||||||
console.log('旧语言:', currentLanguage.value)
|
|
||||||
console.log('新语言:', lang)
|
|
||||||
|
|
||||||
// 1. 保存到缓存
|
// 1. 保存到缓存
|
||||||
uni.setStorageSync('language', lang)
|
uni.setStorageSync('language', lang)
|
||||||
console.log('✓ 语言已保存到缓存')
|
|
||||||
|
|
||||||
// 2. 立即更新 i18n 实例(重要!)
|
// 2. 立即更新 i18n 实例(重要!)
|
||||||
if (globalI18n) {
|
if (globalI18n) {
|
||||||
console.log('✓ 正在更新 globalI18n.locale...')
|
|
||||||
console.log(' 更新前:', globalI18n.locale)
|
|
||||||
globalI18n.locale = lang
|
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. 更新当前语言状态
|
// 3. 更新当前语言状态
|
||||||
currentLanguage.value = lang
|
currentLanguage.value = lang
|
||||||
|
|
||||||
console.log('========================================')
|
|
||||||
|
|
||||||
// 4. 提示用户
|
// 4. 提示用户
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: lang === 'zh-CN' ? '语言已切换,正在刷新...' : 'Language switched, refreshing...',
|
title: t('settings.languageSwitched'),
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 800
|
duration: 800
|
||||||
})
|
})
|
||||||
|
|
||||||
// 5. 延迟后重新加载应用(确保 i18n 更新已生效)
|
// 5. 延迟后重新加载应用(确保 i18n 更新已生效)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('=== 准备 reLaunch 到首页 ===')
|
|
||||||
// 使用 reLaunch 完全重启应用
|
// 使用 reLaunch 完全重启应用
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: '/pages/index/index',
|
url: '/pages/index/index'
|
||||||
success: () => {
|
|
||||||
console.log('✓ 页面已重新加载')
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('✗ 页面重载失败:', err)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}, 800)
|
}, 800)
|
||||||
}
|
}
|
||||||
@@ -121,13 +97,13 @@ const showLanguageSelector = () => {
|
|||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: $t('common.tips'),
|
title: t('common.tips'),
|
||||||
content: $t('user.confirmLogout'),
|
content: t('user.confirmLogout'),
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
const response = await userLogout();
|
const response = await userLogout();
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
uni.showToast({ title: $t('user.logoutSuccess'), icon: 'none' })
|
uni.showToast({ title: t('user.logoutSuccess'), icon: 'none' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.removeStorageSync('token')
|
uni.removeStorageSync('token')
|
||||||
uni.removeStorageSync('userInfo')
|
uni.removeStorageSync('userInfo')
|
||||||
|
|||||||
+12
-12
@@ -59,7 +59,7 @@ import { ref, reactive, onMounted } from 'vue';
|
|||||||
import { getMyIndexInfo, uploadUserAvatar, updateUserInfo } from '../../config/api/user.js';
|
import { getMyIndexInfo, uploadUserAvatar, updateUserInfo } from '../../config/api/user.js';
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
const userInfo = ref({
|
const userInfo = ref({
|
||||||
@@ -75,7 +75,7 @@ const isEditingNickname = ref(false);
|
|||||||
// 页面加载时初始化
|
// 页面加载时初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('userProfile.title')
|
title: t('userProfile.title')
|
||||||
})
|
})
|
||||||
loadUserInfo();
|
loadUserInfo();
|
||||||
});
|
});
|
||||||
@@ -102,7 +102,7 @@ const loadUserInfo = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取用户信息失败:', error);
|
console.error('获取用户信息失败:', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.getUserInfoFailed'),
|
title: t('user.getUserInfoFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -138,13 +138,13 @@ const onChooseAvatar = async (e) => {
|
|||||||
const avatarLocalPath = e?.detail?.avatarUrl;
|
const avatarLocalPath = e?.detail?.avatarUrl;
|
||||||
if (!avatarLocalPath) {
|
if (!avatarLocalPath) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.noAvatar'),
|
title: t('user.noAvatar'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('userProfile.uploading'),
|
title: t('userProfile.uploading'),
|
||||||
mask: true
|
mask: true
|
||||||
});
|
});
|
||||||
const uploadRes = await uploadUserAvatar(avatarLocalPath);
|
const uploadRes = await uploadUserAvatar(avatarLocalPath);
|
||||||
@@ -157,14 +157,14 @@ const onChooseAvatar = async (e) => {
|
|||||||
uni.setStorageSync('userInfo', userInfo.value);
|
uni.setStorageSync('userInfo', userInfo.value);
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.avatarUpdated'),
|
title: t('user.avatarUpdated'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
await loadUserInfo();
|
await loadUserInfo();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('选择/上传头像失败:', err);
|
console.error('选择/上传头像失败:', err);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.avatarUploadFailed'),
|
title: t('user.avatarUploadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -188,7 +188,7 @@ const cancelEditNickname = () => {
|
|||||||
const saveNickname = async () => {
|
const saveNickname = async () => {
|
||||||
if (!newNickname.value || !newNickname.value.trim()) {
|
if (!newNickname.value || !newNickname.value.trim()) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('userProfile.nicknameRequired'),
|
title: t('userProfile.nicknameRequired'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -196,7 +196,7 @@ const saveNickname = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('userProfile.saving'),
|
title: t('userProfile.saving'),
|
||||||
mask: true
|
mask: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -228,19 +228,19 @@ const saveNickname = async () => {
|
|||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('userProfile.nicknameUpdated'),
|
title: t('userProfile.nicknameUpdated'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
isEditingNickname.value = false;
|
isEditingNickname.value = false;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.message || $t('userProfile.updateFailed'));
|
throw new Error(res.message || t('userProfile.updateFailed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('修改昵称失败:', error);
|
console.error('修改昵称失败:', error);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.message || $t('userProfile.updateFailed'),
|
title: error.message || t('userProfile.updateFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
import { getOrderByOrderNoScorePayStatus, cancelOrder } from '@/config/api/order.js'
|
import { getOrderByOrderNoScorePayStatus, cancelOrder } from '@/config/api/order.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const progress = ref(0)
|
const progress = ref(0)
|
||||||
const leftRotateDeg = ref(0)
|
const leftRotateDeg = ref(0)
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
await cancelOrder({ orderId: orderNo.value })
|
await cancelOrder({ orderId: orderNo.value })
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
uni.showToast({ title: $t('waiting.rentFailed'), icon: 'none' })
|
uni.showToast({ title: t('waiting.rentFailed'), icon: 'none' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.reLaunch({ url: '/pages/index/index' })
|
uni.reLaunch({ url: '/pages/index/index' })
|
||||||
}, 800)
|
}, 800)
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
// 超时保护:例如 60 秒
|
// 超时保护:例如 60 秒
|
||||||
timeoutTimer = setTimeout(() => {
|
timeoutTimer = setTimeout(() => {
|
||||||
stopAllTimers()
|
stopAllTimers()
|
||||||
uni.showToast({ title: $t('waiting.timeout'), icon: 'none' })
|
uni.showToast({ title: t('waiting.timeout'), icon: 'none' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.reLaunch({ url: '/pages/index/index' })
|
uni.reLaunch({ url: '/pages/index/index' })
|
||||||
}, 800)
|
}, 800)
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
|
|
||||||
onLoad((query) => {
|
onLoad((query) => {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({
|
||||||
title: $t('waiting.title')
|
title: t('waiting.title')
|
||||||
})
|
})
|
||||||
if (query) {
|
if (query) {
|
||||||
if (query.orderNo) {
|
if (query.orderNo) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 网页链接
|
// 网页链接
|
||||||
const webUrl = ref('')
|
const webUrl = ref('')
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
console.log('加载外部链接:', webUrl.value)
|
console.log('加载外部链接:', webUrl.value)
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('common.invalidUrl') || '无效的链接',
|
title: t('common.invalidUrl') || '无效的链接',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
const handleError = (e) => {
|
const handleError = (e) => {
|
||||||
console.error('网页加载错误:', e)
|
console.error('网页加载错误:', e)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('common.loadFailed') || '加载失败',
|
title: t('common.loadFailed') || '加载失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-42
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
login,
|
login,
|
||||||
getMyIndexInfo
|
getMyIndexInfo,
|
||||||
|
getWxUserPhoneNumber
|
||||||
} from "../config/api/user"
|
} from "../config/api/user"
|
||||||
import {
|
import {
|
||||||
URL,
|
URL,
|
||||||
@@ -84,52 +85,20 @@ export const getUserInfo = () => {
|
|||||||
export const getUserPhoneNumber = (code) => {
|
export const getUserPhoneNumber = (code) => {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
// 获取登录态信息
|
console.log('开始请求获取手机号,code=', code)
|
||||||
const token = uni.getStorageSync('token')
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
reject(new Error('用户未登录'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('开始请求获取手机号,code=', code, '请求地址=', URL + '/app/user/getPhoneNumber')
|
|
||||||
|
|
||||||
// 发送请求到后端获取手机号
|
// 发送请求到后端获取手机号
|
||||||
uni.request({
|
const res = await getWxUserPhoneNumber({
|
||||||
url: URL + '/app/user/getPhoneNumber',
|
|
||||||
method: 'POST',
|
|
||||||
header: {
|
|
||||||
'Authorization': 'Bearer ' + token,
|
|
||||||
'clientId': uni.getStorageSync('client_id'),
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
code: code, // 微信获取手机号授权后的临时code
|
code: code, // 微信获取手机号授权后的临时code
|
||||||
appid: appid
|
appid: appid
|
||||||
},
|
|
||||||
success: (res) => {
|
|
||||||
console.log('请求获取手机号接口成功,原始响应:', JSON.stringify(res))
|
|
||||||
|
|
||||||
// 检查HTTP状态码
|
|
||||||
if (res.statusCode !== 200) {
|
|
||||||
reject(new Error(`HTTP错误: ${res.statusCode}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保响应体存在
|
|
||||||
if (!res.data) {
|
|
||||||
reject(new Error('服务器返回空数据'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正常返回响应数据,不做额外判断,由调用方处理业务状态码
|
|
||||||
resolve(res.data)
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('请求获取手机号接口网络错误:', err)
|
|
||||||
reject(new Error('请求获取手机号接口失败: ' + (err.errMsg || JSON.stringify(err))))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
console.log('请求获取手机号接口成功:', JSON.stringify(res))
|
||||||
|
resolve(res)
|
||||||
|
} else {
|
||||||
|
reject(new Error('服务器返回空数据'))
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取手机号过程中出现异常:', error)
|
console.error('获取手机号过程中出现异常:', error)
|
||||||
reject(new Error('获取手机号异常: ' + (error.message || JSON.stringify(error))))
|
reject(new Error('获取手机号异常: ' + (error.message || JSON.stringify(error))))
|
||||||
|
|||||||
+318
-12
@@ -4,16 +4,16 @@ const DEFAULT_LOCALE = 'zh-CN'
|
|||||||
const permissionTexts = {
|
const permissionTexts = {
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
locationTitle: '位置信息授权',
|
locationTitle: '位置信息授权',
|
||||||
locationNeed: '需要获取您的位置信息以展示附近设备,请在“设置-权限管理”中开启定位权限。',
|
locationNeed: '需要获取您的位置信息以展示附近设备,请在"设置-权限管理"中开启定位权限。',
|
||||||
locationDenied: '未授权定位,将无法展示附近设备。您可以稍后在“设置-权限管理”中重新开启定位权限。',
|
locationDenied: '未授权定位,将无法展示附近设备。您可以稍后在"设置-权限管理"中重新开启定位权限。',
|
||||||
goToSettings: '去设置',
|
goToSettings: '去设置',
|
||||||
later: '暂不',
|
later: '暂不',
|
||||||
gotIt: '知道了'
|
gotIt: '知道了'
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
locationTitle: 'Location Permission',
|
locationTitle: 'Location Permission',
|
||||||
locationNeed: 'We need your location to show nearby devices. Please enable location in “Settings > Permissions”.',
|
locationNeed: 'We need your location to show nearby devices. Please enable location in "Settings > Permissions".',
|
||||||
locationDenied: 'Location access is disabled. You can re-enable it later in “Settings > Permissions”.',
|
locationDenied: 'Location access is disabled. You can re-enable it later in "Settings > Permissions".',
|
||||||
goToSettings: 'Set',
|
goToSettings: 'Set',
|
||||||
later: 'Skip',
|
later: 'Skip',
|
||||||
gotIt: 'OK'
|
gotIt: 'OK'
|
||||||
@@ -37,7 +37,14 @@ const getPermissionText = (key) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 腾讯地图Key
|
// 腾讯地图Key
|
||||||
const QQMAP_KEY = 'RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35';
|
const QQMAP_KEY =
|
||||||
|
// #ifdef H5
|
||||||
|
'DJQBZ-WB53Q-WPS5B-4S6J7-53RMS-X4FJ2'
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
'RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35'
|
||||||
|
// #endif
|
||||||
|
;
|
||||||
|
|
||||||
// 内联腾讯地图SDK核心代码
|
// 内联腾讯地图SDK核心代码
|
||||||
const QQMapWX = (function() {
|
const QQMapWX = (function() {
|
||||||
@@ -118,7 +125,7 @@ const QQMapWX = (function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!param.location) {
|
if (!param.location) {
|
||||||
wx.getLocation({
|
uni.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: locationsuccess,
|
success: locationsuccess,
|
||||||
fail: locationfail,
|
fail: locationfail,
|
||||||
@@ -280,10 +287,16 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.location = result.latitude + ',' + result.longitude;
|
requestParam.location = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// #ifdef H5
|
||||||
|
// H5环境使用JSONP方式
|
||||||
|
that._requestJsonp(URL_GET_GEOCODER, requestParam, options, 'reverseGeocoder');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
url: URL_GET_GEOCODER,
|
url: URL_GET_GEOCODER,
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'reverseGeocoder'));
|
}, 'reverseGeocoder'));
|
||||||
|
// #endif
|
||||||
};
|
};
|
||||||
Utils.locationProcess(options, locationsuccess);
|
Utils.locationProcess(options, locationsuccess);
|
||||||
}
|
}
|
||||||
@@ -323,10 +336,16 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")";
|
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")";
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// #ifdef H5
|
||||||
|
// H5环境使用JSONP方式
|
||||||
|
that._requestJsonp(URL_SEARCH, requestParam, options, 'search');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
url: URL_SEARCH,
|
url: URL_SEARCH,
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'search'));
|
}, 'search'));
|
||||||
|
// #endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.locationProcess(options, locationsuccess);
|
Utils.locationProcess(options, locationsuccess);
|
||||||
@@ -368,17 +387,27 @@ const QQMapWX = (function() {
|
|||||||
if (options.location) {
|
if (options.location) {
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.location = result.latitude + ',' + result.longitude;
|
requestParam.location = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// #ifdef H5
|
||||||
|
that._requestJsonp(URL_SUGGESTION, requestParam, options, "suggest");
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
url: URL_SUGGESTION,
|
url: URL_SUGGESTION,
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, "suggest"));
|
}, "suggest"));
|
||||||
|
// #endif
|
||||||
};
|
};
|
||||||
Utils.locationProcess(options, locationsuccess);
|
Utils.locationProcess(options, locationsuccess);
|
||||||
} else {
|
} else {
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// #ifdef H5
|
||||||
|
that._requestJsonp(URL_SUGGESTION, requestParam, options, "suggest");
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
url: URL_SUGGESTION,
|
url: URL_SUGGESTION,
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, "suggest"));
|
}, "suggest"));
|
||||||
|
// #endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,14 +437,64 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.from = result.latitude + ',' + result.longitude;
|
requestParam.from = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// #ifdef H5
|
||||||
|
that._requestJsonp(URL_DISTANCE, requestParam, options, 'calculateDistance');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
url: URL_DISTANCE,
|
url: URL_DISTANCE,
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'calculateDistance'));
|
}, 'calculateDistance'));
|
||||||
|
// #endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.locationProcess(options, locationsuccess);
|
Utils.locationProcess(options, locationsuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// H5环境JSONP请求方法
|
||||||
|
_requestJsonp(url, params, options, feature) {
|
||||||
|
const callbackName = `qqmap_callback_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
// 构建URL参数
|
||||||
|
const queryString = Object.keys(params)
|
||||||
|
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
const fullUrl = `${url}?${queryString}&output=jsonp&callback=${callbackName}`;
|
||||||
|
|
||||||
|
// 创建全局回调函数
|
||||||
|
window[callbackName] = (data) => {
|
||||||
|
// 清理回调函数和script标签
|
||||||
|
delete window[callbackName];
|
||||||
|
const script = document.getElementById(callbackName);
|
||||||
|
if (script && script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 0) {
|
||||||
|
Utils.handleData(options, data, feature);
|
||||||
|
} else {
|
||||||
|
options.fail(data);
|
||||||
|
}
|
||||||
|
options.complete(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建script标签进行JSONP请求
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = callbackName;
|
||||||
|
script.src = fullUrl;
|
||||||
|
script.onerror = () => {
|
||||||
|
delete window[callbackName];
|
||||||
|
const scriptEl = document.getElementById(callbackName);
|
||||||
|
if (scriptEl && scriptEl.parentNode) {
|
||||||
|
scriptEl.parentNode.removeChild(scriptEl);
|
||||||
|
}
|
||||||
|
const error = { status: 600, message: '请求失败' };
|
||||||
|
options.fail(error);
|
||||||
|
options.complete(error);
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QQMapWX;
|
return QQMapWX;
|
||||||
@@ -550,8 +629,9 @@ function getUserLocation() {
|
|||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// 非微信小程序平台:使用 uni.getLocation 做一个尽量兼容的兜底
|
// 非微信小程序平台:根据平台使用不同的定位方式
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
|
// 统一使用 uni.getLocation,框架会根据环境自动选择最佳定位方式
|
||||||
uni.getLocation({
|
uni.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
@@ -565,6 +645,16 @@ function getUserLocation() {
|
|||||||
},
|
},
|
||||||
fail: (error) => {
|
fail: (error) => {
|
||||||
console.error('获取位置失败:', error);
|
console.error('获取位置失败:', error);
|
||||||
|
// H5 环境下的特殊错误提示
|
||||||
|
// #ifdef H5
|
||||||
|
if (error.errMsg && error.errMsg.indexOf('permission denied') !== -1) {
|
||||||
|
uni.showModal({
|
||||||
|
title: getPermissionText('locationTitle'),
|
||||||
|
content: getPermissionText('locationNeed'),
|
||||||
|
showCancel: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -575,6 +665,57 @@ function getUserLocation() {
|
|||||||
// 逆地理编码 - 根据经纬度获取地址信息
|
// 逆地理编码 - 根据经纬度获取地址信息
|
||||||
function getRegeo(longitude, latitude) {
|
function getRegeo(longitude, latitude) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
// H5环境:使用JSONP方式调用腾讯地图API,避免跨域问题
|
||||||
|
const callbackName = `qqmap_geocoder_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
// 创建全局回调函数
|
||||||
|
window[callbackName] = (data) => {
|
||||||
|
// 清理回调函数和script标签
|
||||||
|
delete window[callbackName];
|
||||||
|
const script = document.getElementById(callbackName);
|
||||||
|
if (script && script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 0) {
|
||||||
|
const result = data.result;
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
formatted_address: result.address,
|
||||||
|
addressComponent: {
|
||||||
|
city: result.address_component.city,
|
||||||
|
district: result.address_component.district,
|
||||||
|
province: result.address_component.province,
|
||||||
|
street: result.address_component.street,
|
||||||
|
street_number: result.address_component.street_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('H5逆地理编码失败:', data);
|
||||||
|
reject({ success: false, message: data.message || '逆地理编码失败' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建script标签进行JSONP请求
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = callbackName;
|
||||||
|
script.src = `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=${QQMAP_KEY}&output=jsonp&callback=${callbackName}`;
|
||||||
|
script.onerror = () => {
|
||||||
|
delete window[callbackName];
|
||||||
|
const scriptEl = document.getElementById(callbackName);
|
||||||
|
if (scriptEl && scriptEl.parentNode) {
|
||||||
|
scriptEl.parentNode.removeChild(scriptEl);
|
||||||
|
}
|
||||||
|
reject({ success: false, message: '逆地理编码请求失败' });
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// 小程序环境:使用 QQMapWX SDK
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -608,12 +749,68 @@ function getRegeo(longitude, latitude) {
|
|||||||
reject({ success: false, message: error.message || '逆地理编码失败' });
|
reject({ success: false, message: error.message || '逆地理编码失败' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索周边POI
|
// 搜索周边POI
|
||||||
function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
// H5环境:使用JSONP方式调用腾讯地图API
|
||||||
|
const callbackName = `qqmap_search_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
// 创建全局回调函数
|
||||||
|
window[callbackName] = (data) => {
|
||||||
|
// 清理回调函数和script标签
|
||||||
|
delete window[callbackName];
|
||||||
|
const script = document.getElementById(callbackName);
|
||||||
|
if (script && script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 0) {
|
||||||
|
const searchSimplify = data.data.map(item => ({
|
||||||
|
id: item.id || null,
|
||||||
|
title: item.title || null,
|
||||||
|
latitude: item.location && item.location.lat || null,
|
||||||
|
longitude: item.location && item.location.lng || null,
|
||||||
|
address: item.address || null,
|
||||||
|
category: item.category || null,
|
||||||
|
tel: item.tel || null,
|
||||||
|
adcode: item.ad_info && item.ad_info.adcode || null,
|
||||||
|
city: item.ad_info && item.ad_info.city || null,
|
||||||
|
district: item.ad_info && item.ad_info.district || null,
|
||||||
|
province: item.ad_info && item.ad_info.province || null
|
||||||
|
}));
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: searchSimplify
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('H5搜索POI失败:', data);
|
||||||
|
reject({ success: false, message: data.message || '搜索POI失败' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建script标签进行JSONP请求
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = callbackName;
|
||||||
|
script.src = `https://apis.map.qq.com/ws/place/v1/search?boundary=nearby(${latitude},${longitude},${radius})&keyword=${encodeURIComponent(keyword)}&orderby=_distance&page_size=10&page_index=1&key=${QQMAP_KEY}&output=jsonp&callback=${callbackName}`;
|
||||||
|
script.onerror = () => {
|
||||||
|
delete window[callbackName];
|
||||||
|
const scriptEl = document.getElementById(callbackName);
|
||||||
|
if (scriptEl && scriptEl.parentNode) {
|
||||||
|
scriptEl.parentNode.removeChild(scriptEl);
|
||||||
|
}
|
||||||
|
reject({ success: false, message: '搜索POI请求失败' });
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// 小程序环境:使用 QQMapWX SDK
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -639,12 +836,64 @@ function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
|||||||
reject({ success: false, message: error.message || '搜索POI失败' });
|
reject({ success: false, message: error.message || '搜索POI失败' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算距离(异步)
|
// 计算距离(异步)
|
||||||
function calculateDistance(from, to) {
|
function calculateDistance(from, to) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
// H5环境:使用JSONP方式调用腾讯地图API
|
||||||
|
const callbackName = `qqmap_distance_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
// 创建全局回调函数
|
||||||
|
window[callbackName] = (data) => {
|
||||||
|
// 清理回调函数和script标签
|
||||||
|
delete window[callbackName];
|
||||||
|
const script = document.getElementById(callbackName);
|
||||||
|
if (script && script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 0) {
|
||||||
|
const distances = data.result.elements.map(element => element.distance);
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: distances
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('H5计算距离失败:', data);
|
||||||
|
reject({ success: false, message: data.message || '计算距离失败' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建script标签进行JSONP请求
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = callbackName;
|
||||||
|
// 构建to参数
|
||||||
|
let toStr = '';
|
||||||
|
if (Array.isArray(to)) {
|
||||||
|
toStr = to.map(p => `${p.latitude},${p.longitude}`).join(';');
|
||||||
|
} else {
|
||||||
|
toStr = `${to.latitude},${to.longitude}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromStr = `${from.latitude},${from.longitude}`;
|
||||||
|
script.src = `https://apis.map.qq.com/ws/distance/v1/?mode=walking&from=${fromStr}&to=${toStr}&key=${QQMAP_KEY}&output=jsonp&callback=${callbackName}`;
|
||||||
|
script.onerror = () => {
|
||||||
|
delete window[callbackName];
|
||||||
|
const scriptEl = document.getElementById(callbackName);
|
||||||
|
if (scriptEl && scriptEl.parentNode) {
|
||||||
|
scriptEl.parentNode.removeChild(scriptEl);
|
||||||
|
}
|
||||||
|
reject({ success: false, message: '计算距离请求失败' });
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// 小程序环境:使用 QQMapWX SDK
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -667,6 +916,7 @@ function calculateDistance(from, to) {
|
|||||||
reject({ success: false, message: error.message || '计算距离失败' });
|
reject({ success: false, message: error.message || '计算距离失败' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,6 +935,61 @@ function calculateDistanceSync(lat1, lng1, lat2, lng2) {
|
|||||||
// 关键词提示
|
// 关键词提示
|
||||||
function getSuggestion(keyword, region = '全国') {
|
function getSuggestion(keyword, region = '全国') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
// H5环境:使用JSONP方式调用腾讯地图API
|
||||||
|
const callbackName = `qqmap_suggestion_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
// 创建全局回调函数
|
||||||
|
window[callbackName] = (data) => {
|
||||||
|
// 清理回调函数和script标签
|
||||||
|
delete window[callbackName];
|
||||||
|
const script = document.getElementById(callbackName);
|
||||||
|
if (script && script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 0) {
|
||||||
|
const suggestSimplify = data.data.map(item => ({
|
||||||
|
adcode: item.adcode || null,
|
||||||
|
address: item.address || null,
|
||||||
|
category: item.category || null,
|
||||||
|
city: item.city || null,
|
||||||
|
district: item.district || null,
|
||||||
|
id: item.id || null,
|
||||||
|
latitude: item.location && item.location.lat || null,
|
||||||
|
longitude: item.location && item.location.lng || null,
|
||||||
|
province: item.province || null,
|
||||||
|
title: item.title || null,
|
||||||
|
type: item.type || null
|
||||||
|
}));
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: suggestSimplify
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('H5关键词提示失败:', data);
|
||||||
|
reject({ success: false, message: data.message || '关键词提示失败' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建script标签进行JSONP请求
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.id = callbackName;
|
||||||
|
script.src = `https://apis.map.qq.com/ws/place/v1/suggestion?keyword=${encodeURIComponent(keyword)}®ion=${encodeURIComponent(region)}&page_size=10&page_index=1&key=${QQMAP_KEY}&output=jsonp&callback=${callbackName}`;
|
||||||
|
script.onerror = () => {
|
||||||
|
delete window[callbackName];
|
||||||
|
const scriptEl = document.getElementById(callbackName);
|
||||||
|
if (scriptEl && scriptEl.parentNode) {
|
||||||
|
scriptEl.parentNode.removeChild(scriptEl);
|
||||||
|
}
|
||||||
|
reject({ success: false, message: '关键词提示请求失败' });
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// 小程序环境:使用 QQMapWX SDK
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -706,6 +1011,7 @@ function getSuggestion(keyword, region = '全国') {
|
|||||||
reject({ success: false, message: error.message || '关键词提示失败' });
|
reject({ success: false, message: error.message || '关键词提示失败' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
-2
@@ -249,7 +249,9 @@ class OrderMonitor {
|
|||||||
export const orderMonitor = new OrderMonitor()
|
export const orderMonitor = new OrderMonitor()
|
||||||
|
|
||||||
// 监听页面切换事件
|
// 监听页面切换事件
|
||||||
uni.onAppRoute((route) => {
|
// #ifdef MP-WEIXIN || APP-PLUS
|
||||||
|
if (typeof uni.onAppRoute === 'function') {
|
||||||
|
uni.onAppRoute((route) => {
|
||||||
const pagePath = route.path || ''
|
const pagePath = route.path || ''
|
||||||
const pageSegments = pagePath.split('/')
|
const pageSegments = pagePath.split('/')
|
||||||
const pageName = pageSegments[pageSegments.length - 1]
|
const pageName = pageSegments[pageSegments.length - 1]
|
||||||
@@ -258,7 +260,34 @@ uni.onAppRoute((route) => {
|
|||||||
orderMonitor.setActivePage(pageName || null)
|
orderMonitor.setActivePage(pageName || null)
|
||||||
|
|
||||||
console.log('页面切换:', pagePath, '当前活跃页面:', pageName)
|
console.log('页面切换:', pagePath, '当前活跃页面:', pageName)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
// H5环境下通过路由监听实现页面切换检测
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const updateActivePageForH5 = () => {
|
||||||
|
const pagePath = window.location.pathname || window.location.hash
|
||||||
|
const pageSegments = pagePath.split('/')
|
||||||
|
const pageName = pageSegments[pageSegments.length - 1].replace(/[?#].*$/, '')
|
||||||
|
|
||||||
|
if (pageName) {
|
||||||
|
orderMonitor.setActivePage(pageName)
|
||||||
|
console.log('页面切换(H5):', pagePath, '当前活跃页面:', pageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听 popstate 事件(浏览器前进后退)
|
||||||
|
window.addEventListener('popstate', updateActivePageForH5)
|
||||||
|
|
||||||
|
// 监听 hashchange 事件(hash 模式路由)
|
||||||
|
window.addEventListener('hashchange', updateActivePageForH5)
|
||||||
|
|
||||||
|
// 初始化时执行一次
|
||||||
|
updateActivePageForH5()
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
// 页面加载时自动恢复监控上次的活跃订单(如果有)
|
// 页面加载时自动恢复监控上次的活跃订单(如果有)
|
||||||
const initOrderMonitor = () => {
|
const initOrderMonitor = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user