fix:修复bug
This commit is contained in:
@@ -379,7 +379,7 @@ const handleSearch = () => {
|
||||
|
||||
const handleService = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/help/index'
|
||||
url: '/subPackages/service/help/index'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ const handleSearch = () => {
|
||||
|
||||
const handleJoinTap = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/join/index'
|
||||
url: '/subPackages/business/join/index'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ const request = (option) => {
|
||||
const query = current && current.options ? Object.keys(current.options).map(k => `${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
|
||||
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({ url: `/pages/login/index?redirect=${redirect}` })
|
||||
uni.reLaunch({ url: `/subPackages/user/login/index?redirect=${redirect}` })
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
||||
// export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||
export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
||||
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||
// export const URL = "http://192.168.5.123:8080" //本地调试
|
||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||
|
||||
|
||||
+8
-2
@@ -55,7 +55,12 @@ export default {
|
||||
pull: 'Pull to refresh',
|
||||
release: 'Release to refresh',
|
||||
noMore: 'No more',
|
||||
functionDeveloping: 'Function under development'
|
||||
functionDeveloping: 'Function under development',
|
||||
saveImage: 'Save to Phone',
|
||||
saveSuccess: 'Saved successfully',
|
||||
saving: 'Saving...',
|
||||
saveFailed: 'Save failed',
|
||||
downloadFailed: 'Download failed'
|
||||
},
|
||||
|
||||
nav: {
|
||||
@@ -272,7 +277,8 @@ export default {
|
||||
deviceNoEjectSuccess: 'Feedback received, will be handled within 5 minutes',
|
||||
deviceNoEjectFailed: 'Feedback submission failed, please try again',
|
||||
returnProblemTip: 'After returning, if the order is still active, please go to ',
|
||||
contactStaff: ' to contact staff.'
|
||||
contactStaff: ' to contact staff.',
|
||||
returnLocationMap: 'Return Location Map',
|
||||
},
|
||||
|
||||
user: {
|
||||
|
||||
+8
-2
@@ -55,7 +55,12 @@ export default {
|
||||
pull: 'Tarik untuk muat ulang',
|
||||
release: 'Lepas untuk muat ulang',
|
||||
noMore: 'Tidak ada lagi',
|
||||
functionDeveloping: 'Fungsi sedang dikembangkan'
|
||||
functionDeveloping: 'Fungsi sedang dikembangkan',
|
||||
saveImage: 'Simpan ke Ponsel',
|
||||
saveSuccess: 'Berhasil disimpan',
|
||||
saving: 'Menyimpan...',
|
||||
saveFailed: 'Gagal menyimpan',
|
||||
downloadFailed: 'Gagal mengunduh'
|
||||
},
|
||||
|
||||
nav: {
|
||||
@@ -272,7 +277,8 @@ export default {
|
||||
deviceNoEjectSuccess: 'Umpan balik telah diterima, akan diproses dalam 5 menit',
|
||||
deviceNoEjectFailed: 'Pengiriman umpan balik gagal, harap coba lagi nanti',
|
||||
returnProblemTip: 'Setelah produk dikembalikan ke gudang, pesanan masih belum berakhir, harap pergi ke',
|
||||
contactStaff: 'Hubungi staf.'
|
||||
contactStaff: 'Hubungi staf.',
|
||||
returnLocationMap: 'Peta Lokasi Pengembalian',
|
||||
},
|
||||
|
||||
user: {
|
||||
|
||||
+20
-15
@@ -55,7 +55,11 @@ export default {
|
||||
pull: '下拉刷新',
|
||||
release: '释放刷新',
|
||||
noMore: '没有更多了',
|
||||
functionDeveloping: '功能开发中'
|
||||
functionDeveloping: '功能开发中',
|
||||
saveImage:'保存到手机',
|
||||
saveSuccess:'保存成功',
|
||||
saving:'保存中...',
|
||||
saveFailed:'保存失败'
|
||||
},
|
||||
|
||||
nav: {
|
||||
@@ -157,7 +161,7 @@ export default {
|
||||
|
||||
order: {
|
||||
myOrders: '我的订单',
|
||||
myDeviceOrders:'我的定制',
|
||||
myDeviceOrders: '我的定制',
|
||||
noOrderRecord: '暂无订单记录',
|
||||
getOrderListFailed: '获取订单列表失败',
|
||||
confirmCancelContent: '确定要取消此订单吗?',
|
||||
@@ -176,11 +180,11 @@ export default {
|
||||
payAmount: '支付金额',
|
||||
deposit: '押金',
|
||||
rentFee: '租金',
|
||||
myCards:'会员卡优惠',
|
||||
myCoupons:'优惠券优惠',
|
||||
myCards: '会员卡优惠',
|
||||
myCoupons: '优惠券优惠',
|
||||
payNow: '立即支付',
|
||||
cancelOrder: '取消订单',
|
||||
quickReturn: '快速归还',
|
||||
quickReturn: '附近可归还',
|
||||
returnDevice: '归还设备',
|
||||
viewDetails: '查看详情',
|
||||
orderCompleted: '订单已完成',
|
||||
@@ -261,7 +265,7 @@ export default {
|
||||
convertToOwnSuccess: '已成功转为自用',
|
||||
convertToOwnFailed: '操作失败,请稍后重试',
|
||||
convertToOwnConfirmBtn: '买断自用',
|
||||
convertToOwnCancelBtn: '继续租借',
|
||||
convertToOwnCancelBtn: '继续租借',
|
||||
convertToOwnWithMaxFee: '不想还了?转为自用',
|
||||
convertToOwnWithMaxFeeTitle: '买断带回家!',
|
||||
convertToOwnWithMaxFeeConfirm: '既然用得顺手,直接买断带回家!仅需99元,设备永久归你,无需归还~\n✅支持Type-C充电,居家使用超方便~\n✅买断后无任何使用限制,随心用!',
|
||||
@@ -272,7 +276,8 @@ export default {
|
||||
deviceNoEjectSuccess: '反馈已受理,将在5分钟内处理',
|
||||
deviceNoEjectFailed: '反馈提交失败,请稍后重试',
|
||||
returnProblemTip: '产品归还入仓后,订单仍未结束,请前往',
|
||||
contactStaff: '联系工作人员。'
|
||||
contactStaff: '联系工作人员。',
|
||||
returnLocationMap:'归还点地图',
|
||||
},
|
||||
|
||||
user: {
|
||||
@@ -578,23 +583,23 @@ export default {
|
||||
applicableToService: '适用于"风电者"共享风扇租借服务',
|
||||
footerNotice: '如对本协议有疑问,请前往"我的-客服"咨询',
|
||||
footerNoticePolicy: '如对本政策有疑问,请前往"我的-客服"咨询',
|
||||
|
||||
|
||||
// 条款与细则内容
|
||||
applicableLaw: '适用法律',
|
||||
applicableLawContent: '本服务条款受中华人民共和国法律管辖。用户使用本服务即表示同意接受中国法律的约束。任何因本服务引起的争议,应首先通过友好协商解决;协商不成的,任何一方均可向服务提供方所在地有管辖权的人民法院提起诉讼。',
|
||||
|
||||
|
||||
paymentMethods: '支付方式',
|
||||
paymentMethodsContent: '我们支持多种支付方式,包括但不限于:微信支付、支付宝、微信支付分免押金等。用户在使用服务前需完成支付流程。支付成功后,系统将自动开启设备供用户使用。所有支付交易均通过安全加密通道进行,确保用户资金安全。',
|
||||
|
||||
|
||||
refundPolicy: '退款介绍',
|
||||
refundPolicyContent: '1. 押金退款:归还设备后,押金将在扣除相应租金后自动退还至原支付账户,预计0-7个工作日到账。\n2. 订单取消:未使用的订单可在开始使用前取消,押金将全额退还。\n3. 异常退款:如遇设备故障等特殊情况,用户可申请退款,我们将在核实后3-5个工作日内处理。\n4. 会员卡/优惠券:已购买的会员卡和优惠券一般不支持退款,特殊情况请联系客服处理。',
|
||||
|
||||
|
||||
serviceTerms: '服务条款',
|
||||
serviceTermsContent: '用户在使用本服务时,应遵守以下规定:1) 妥善保管租借的设备,不得故意损坏或私自占有;2) 按时归还设备,避免产生额外费用;3) 不得将设备用于非法用途;4) 如发现设备故障,应及时联系客服处理。违反上述规定的,我们有权终止服务并追究相应责任。',
|
||||
|
||||
|
||||
liabilityLimitation: '责任限制',
|
||||
liabilityLimitationContent: '在法律允许的最大范围内,我们对因使用或无法使用本服务而导致的任何间接、偶然、特殊或后果性损害不承担责任。我们的总责任不超过用户为使用本服务所支付的费用。对于因不可抗力、网络故障、第三方原因等导致的服务中断或延迟,我们不承担责任。',
|
||||
|
||||
|
||||
disputeResolution: '争议解决',
|
||||
disputeResolutionContent: '如用户对服务有任何疑问或争议,请首先通过客服渠道联系我们,我们将在收到反馈后24小时内响应,并尽快协商解决。如协商不成,双方同意将争议提交至服务提供方所在地有管辖权的人民法院通过诉讼方式解决。在争议解决期间,双方应继续履行本协议中无争议的条款。'
|
||||
},
|
||||
@@ -809,7 +814,7 @@ export default {
|
||||
useNow: '去使用',
|
||||
usedStatus: '已使用',
|
||||
expiredStatus: '已过期',
|
||||
refundedStatus:'已退款',
|
||||
refundedStatus: '已退款',
|
||||
noAvailableCoupons: '暂无可用优惠券',
|
||||
noUsedCoupons: '暂无已使用优惠券',
|
||||
noExpiredCoupons: '暂无已过期优惠券',
|
||||
@@ -821,7 +826,7 @@ export default {
|
||||
|
||||
goods: {
|
||||
title: '商品详情',
|
||||
goodsTitle:'定制详情',
|
||||
goodsTitle: '定制详情',
|
||||
productName: '风电者共享风扇 + 充电宝 + 暖手宝系列-樱花粉',
|
||||
perUnit: '/个',
|
||||
buyNow: '立即购买',
|
||||
|
||||
+299
-258
@@ -5,7 +5,8 @@
|
||||
"^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
|
||||
}
|
||||
},
|
||||
"pages": [{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
@@ -15,6 +16,12 @@
|
||||
"enableShareTimeline": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/serve/bagCheck/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/scan/index",
|
||||
"style": {
|
||||
@@ -23,168 +30,6 @@
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#C8F4D9",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/phone",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#C8F4D9",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/agreement-zh",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/agreement-en",
|
||||
"style": {
|
||||
"navigationBarTitleText": "User Agreement",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/privacy-zh",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/privacy-en",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Privacy Policy",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/legal/terms",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userProfile/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/setting/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/deposit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/device/orderList",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/device/orderDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "定制详情",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/payment",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/expressReturn/addExpressReturn",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/feedback/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/feedback/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/feedback/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/help/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/device/detail",
|
||||
"style": {
|
||||
@@ -193,37 +38,6 @@
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/serve/bagCheck/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/return/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/return-success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/detail",
|
||||
"style": {
|
||||
@@ -232,21 +46,6 @@
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/expressReturn/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/expressReturn/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/search/index",
|
||||
"style": {
|
||||
@@ -255,22 +54,6 @@
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/position/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/join/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/waiting/index",
|
||||
"style": {
|
||||
@@ -278,47 +61,305 @@
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "subPackages/user",
|
||||
"pages": [
|
||||
{
|
||||
"path": "login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#C8F4D9",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "login/phone",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#C8F4D9",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "userProfile/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "setting/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "user/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "pages/webview/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
"root": "subPackages/order",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "payment",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "return-success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "pages/purchase/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "优惠专区",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
"root": "subPackages/service",
|
||||
"pages": [
|
||||
{
|
||||
"path": "feedback/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "feedback/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "feedback/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "help/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "expressReturn/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "expressReturn/addExpressReturn",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "expressReturn/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "return/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "pages/my/card",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
"root": "subPackages/business",
|
||||
"pages": [
|
||||
{
|
||||
"path": "purchase/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "优惠专区",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my-card",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my-coupon",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "position/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#D1FFE1",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "device-goods",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "device-orderList",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "device-orderDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "定制详情",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "pages/my/coupon",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/device/goods",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
"root": "subPackages/other",
|
||||
"pages": [
|
||||
{
|
||||
"path": "legal/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/agreement-zh",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/agreement-en",
|
||||
"style": {
|
||||
"navigationBarTitleText": "User Agreement",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/privacy-zh",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/privacy-en",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Privacy Policy",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "legal/terms",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "join/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "webview/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "serve/bagCheck/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "deposit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
+25
-7
@@ -81,11 +81,12 @@
|
||||
|
||||
<!-- 底部操作区 -->
|
||||
<view class="footer">
|
||||
<button class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||||
@click="handleRent('wx-pay')">
|
||||
<text>{{ hasActiveOrder ? $t('order.returnDevice') : $t('device.rentDepositFree') }}</text>
|
||||
</button>
|
||||
<view class="wechat-credit">
|
||||
<view class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||||
@click="handleRent(isWechatMiniProgram ? 'wx-score-pay' : 'wx-pay')">
|
||||
<text>{{ hasActiveOrder ? $t('order.returnDevice') : getRentButtonText() }}</text>
|
||||
</view>
|
||||
<!-- 微信支付分标识仅在微信小程序环境显示 -->
|
||||
<view class="wechat-credit" v-if="isWechatMiniProgram">
|
||||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="wx-icon"></image>
|
||||
<text class="credit-text">{{ $t('device.wxPayScoreDesc') }}</text>
|
||||
</view>
|
||||
@@ -162,6 +163,7 @@
|
||||
const isLoggedIn = ref(true)
|
||||
const phoneNumber = ref('')
|
||||
const showPhoneAuthPopup = ref(false)
|
||||
const isWechatMiniProgram = ref(false)
|
||||
|
||||
// 生命周期 onLoad 钩子
|
||||
onLoad(async (options) => {
|
||||
@@ -179,6 +181,13 @@
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('device.deviceInfo')
|
||||
})
|
||||
// 检测当前运行环境
|
||||
// #ifdef MP-WEIXIN
|
||||
isWechatMiniProgram.value = true
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
isWechatMiniProgram.value = false
|
||||
// #endif
|
||||
await checkUserPhone()
|
||||
await fetchDeviceInfo()
|
||||
})
|
||||
@@ -368,7 +377,7 @@
|
||||
const goToPurchase = () => {
|
||||
const positionId = positionInfo.value?.positionId || positionInfo.value?.id
|
||||
uni.navigateTo({
|
||||
url: `/pages/purchase/index?positionId=${positionId}`
|
||||
url: `/subPackages/business/purchase/index?positionId=${positionId}`
|
||||
})
|
||||
}
|
||||
|
||||
@@ -381,7 +390,7 @@
|
||||
const order = inUseRes.data
|
||||
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/return?deviceId=${deviceId.value}`
|
||||
url: `/subPackages/service/return/index?deviceId=${deviceId.value}`
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -499,6 +508,15 @@
|
||||
return `不足${unitMinutes}分钟按${unitMinutes}分钟计费,封顶${depositAmount}元,持续计费至${depositAmount}元视为买断`
|
||||
}
|
||||
|
||||
// 获取租借按钮文本
|
||||
const getRentButtonText = () => {
|
||||
if (isWechatMiniProgram.value) {
|
||||
return t('device.rentDepositFree')
|
||||
} else {
|
||||
return '立即租借'
|
||||
}
|
||||
}
|
||||
|
||||
// 提交租借订单
|
||||
const submitRentOrder = async (payWay) => {
|
||||
try {
|
||||
|
||||
+10
-10
@@ -287,11 +287,11 @@
|
||||
`${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
|
||||
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
|
||||
uni.reLaunch({
|
||||
url: `/pages/login/index?redirect=${redirect}`
|
||||
url: `/subPackages/user/login/index?redirect=${redirect}`
|
||||
})
|
||||
} catch (e) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
url: '/subPackages/user/login/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -407,7 +407,7 @@
|
||||
} else if (config.linkType === 'external' && config.linkUrl) {
|
||||
// 跳转到外部链接(H5页面)
|
||||
uni.navigateTo({
|
||||
url: `/pages/webview/index?url=${encodeURIComponent(config.linkUrl)}`
|
||||
url: `/subPackages/other/webview/index?url=${encodeURIComponent(config.linkUrl)}`
|
||||
})
|
||||
} else if (config.linkType === 'internal' && config.linkUrl) {
|
||||
// 跳转到内部页面
|
||||
@@ -875,7 +875,7 @@
|
||||
|
||||
const goMy = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/index'
|
||||
url: '/subPackages/user/my/index'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -906,13 +906,13 @@
|
||||
|
||||
// 跳转到商品详情页面,传递商品ID
|
||||
uni.navigateTo({
|
||||
url: `/pages/device/goods?productId=${productId}`
|
||||
url: `/subPackages/business/device-goods?productId=${productId}`
|
||||
})
|
||||
} else {
|
||||
console.warn('没有查询到商品数据')
|
||||
// 如果没有商品数据,仍然跳转到商品页面(显示空状态)
|
||||
uni.navigateTo({
|
||||
url: '/pages/device/goods'
|
||||
url: '/subPackages/business/device-goods'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -921,7 +921,7 @@
|
||||
|
||||
// 即使查询失败,也跳转到商品页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/device/goods'
|
||||
url: '/subPackages/business/device-goods'
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1061,14 +1061,14 @@
|
||||
success: () => {
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||
url: `/subPackages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||
url: `/subPackages/order/payment?orderId=${unpaidOrder.orderId}`
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -1171,7 +1171,7 @@
|
||||
// 使用指南弹窗控制
|
||||
const openPopup = () => {
|
||||
uni.navigateTo({
|
||||
url:'/pages/device/goods'
|
||||
url:'/subPackages/business/device-goods'
|
||||
})
|
||||
// try {
|
||||
// showGuidePopup.value = true
|
||||
|
||||
+246
-34
@@ -48,9 +48,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="fee-rule">
|
||||
{{ feeRuleText }}
|
||||
</view> -->
|
||||
<!-- 计费规则图片 -->
|
||||
<view class="fee-rule-image">
|
||||
<image :src="getFeeRuleImageUrl()" mode="widthFix" class="rule-image"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 租借信息卡片 -->
|
||||
@@ -209,6 +210,27 @@
|
||||
</view>
|
||||
</view>
|
||||
</uv-popup>
|
||||
|
||||
<!-- 归还地图弹窗 -->
|
||||
<view class="return-map-popup" v-if="showReturnMapPopup" @click.self="closeReturnMapPopup">
|
||||
<view class="popup-mask"></view>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">{{ $t('order.returnLocationMap') }}</text>
|
||||
<view class="close-btn" @click="closeReturnMapPopup">
|
||||
<text class="close-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<image :src="returnMapImageUrl" mode="widthFix" class="map-image"></image>
|
||||
</view>
|
||||
<view class="popup-footer">
|
||||
<view class="save-btn" @click="saveReturnMapImage">
|
||||
{{ $t('common.saveImage') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -288,7 +310,8 @@
|
||||
userPurchaseId: '',
|
||||
discountTypeName: '',
|
||||
originalFee:'',
|
||||
discountAmount:''
|
||||
discountAmount:'',
|
||||
returnMapImage: ''
|
||||
})
|
||||
const timer = ref(null)
|
||||
const statusCheckTimer = ref(null)
|
||||
@@ -303,6 +326,8 @@
|
||||
const countdownTimer = ref(null)
|
||||
const feeRuleText = ref('')
|
||||
const convertToOwnPopup = ref(null)
|
||||
const showReturnMapPopup = ref(false)
|
||||
const returnMapImageUrl = ref('')
|
||||
|
||||
// 计算属性:是否显示优惠券/会员卡可用提示
|
||||
const canUsePromotionTag = computed(() => {
|
||||
@@ -400,14 +425,86 @@
|
||||
// 联系客服
|
||||
const contactService = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/help/index'
|
||||
url: '/subPackages/service/help/index'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取计费规则图片URL
|
||||
const getFeeRuleImageUrl = () => {
|
||||
const locale = instance?.proxy?.$i18n?.locale || 'en_US'
|
||||
// 如果是中文环境,显示中文图片,否则显示英文图片
|
||||
if (locale === 'zh_CN' || locale === 'zh-CN' || locale === 'zh') {
|
||||
return 'https://static.fdzpower.com/order_notice/notice_CN.png'
|
||||
}
|
||||
return 'https://static.fdzpower.com/order_notice/notice_EN.png'
|
||||
}
|
||||
|
||||
// 快速归还
|
||||
const quickReturn = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/search/index'
|
||||
// 检查是否有 returnMapImage 字段
|
||||
console.log(orderInfo.value.returnMapImage);
|
||||
|
||||
if (orderInfo.value.returnMapImage) {
|
||||
// 有值则弹窗显示图片
|
||||
returnMapImageUrl.value = orderInfo.value.returnMapImage
|
||||
showReturnMapPopup.value = true
|
||||
} else {
|
||||
// 没有值则继续执行跳转流程
|
||||
uni.navigateTo({
|
||||
url: '/pages/search/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭归还地图弹窗
|
||||
const closeReturnMapPopup = () => {
|
||||
showReturnMapPopup.value = false
|
||||
}
|
||||
|
||||
// 保存归还地图图片
|
||||
const saveReturnMapImage = () => {
|
||||
uni.showLoading({
|
||||
title: t('common.saving')
|
||||
})
|
||||
|
||||
uni.downloadFile({
|
||||
url: returnMapImageUrl.value,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: t('common.saveSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading()
|
||||
console.error('保存图片失败:', err)
|
||||
uni.showToast({
|
||||
title: t('common.saveFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: t('common.downloadFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading()
|
||||
console.error('下载图片失败:', err)
|
||||
uni.showToast({
|
||||
title: t('common.downloadFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -781,6 +878,7 @@
|
||||
orderInfo.value.userPurchaseId = orderData.userPurchaseId || ''
|
||||
orderInfo.value.discountTypeName = orderData.discountTypeName || ''
|
||||
orderInfo.value.originalFee = orderData.originalFee||''
|
||||
orderInfo.value.returnMapImage = orderData.returnMapImage||''
|
||||
|
||||
// 保存快递归还开始时间(小时为单位)
|
||||
orderInfo.value.expressReturnStart = orderData.expressReturnStart || null
|
||||
@@ -997,37 +1095,40 @@
|
||||
|
||||
// 申请退款
|
||||
const handleWithdraw = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: t('common.processing')
|
||||
})
|
||||
uni.navigateTo({
|
||||
url:'/subPackages/service/feedback/index'
|
||||
})
|
||||
// try {
|
||||
// uni.showLoading({
|
||||
// title: t('common.processing')
|
||||
// })
|
||||
|
||||
const res = await withdrawDeposit(orderInfo.value.orderNo)
|
||||
// const res = await withdrawDeposit(orderInfo.value.orderNo)
|
||||
|
||||
if (res && res.code === 200) {
|
||||
uni.showToast({
|
||||
title: t('order.refundSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
// if (res && res.code === 200) {
|
||||
// uni.showToast({
|
||||
// title: t('order.refundSuccess'),
|
||||
// icon: 'success'
|
||||
// })
|
||||
|
||||
orderInfo.value.withdrawStatus = 'processing'
|
||||
orderInfo.value.isWithdrawn = true
|
||||
// orderInfo.value.withdrawStatus = 'processing'
|
||||
// orderInfo.value.isWithdrawn = true
|
||||
|
||||
setTimeout(() => {
|
||||
getOrderDetails()
|
||||
}, 1500)
|
||||
} else {
|
||||
throw new Error(res?.msg || t('order.refundFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('退款申请失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || t('order.refundFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
// setTimeout(() => {
|
||||
// getOrderDetails()
|
||||
// }, 1500)
|
||||
// } else {
|
||||
// throw new Error(res?.msg || t('order.refundFailed'))
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('退款申请失败:', error)
|
||||
// uni.showToast({
|
||||
// title: error.message || t('order.refundFailed'),
|
||||
// icon: 'none'
|
||||
// })
|
||||
// } finally {
|
||||
// uni.hideLoading()
|
||||
// }
|
||||
}
|
||||
|
||||
// 返回首页
|
||||
@@ -1381,6 +1482,18 @@
|
||||
color: #4CAF50;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.fee-rule-image {
|
||||
margin-top: 20rpx;
|
||||
width: 100%;
|
||||
|
||||
.rule-image {
|
||||
// height: 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转为自用提示
|
||||
@@ -1655,4 +1768,103 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 归还地图弹窗样式 */
|
||||
.return-map-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.popup-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 600rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
z-index: 10000;
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: #f5f5f5;
|
||||
|
||||
.close-icon {
|
||||
font-size: 40rpx;
|
||||
color: #666;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: 30rpx;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.map-image {
|
||||
width: 100%;
|
||||
display: block;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
padding: 20rpx 30rpx 30rpx;
|
||||
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: linear-gradient(135deg, #07c160, #10d673);
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -303,7 +303,7 @@ const init = async () => {
|
||||
return
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/position/detail?positionId=${position.positionId}`
|
||||
url: `/subPackages/business/position/detail?positionId=${position.positionId}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
<script>
|
||||
import {
|
||||
wxLogin,
|
||||
} from '../../../util/index'
|
||||
} from '@/util/index'
|
||||
|
||||
import {
|
||||
getMyIndexInfo
|
||||
} from "../../../config/api/user.js";
|
||||
} from "@/config/api/user.js";
|
||||
import {
|
||||
queryHasOrder,
|
||||
checkOrdersByStatus
|
||||
} from "../../../config/api/order.js";
|
||||
} from "@/config/api/order.js";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -56,7 +56,7 @@
|
||||
// 如果是使用中的订单,跳转到归还页面
|
||||
console.log('检测到使用中订单,跳转归还页:', latestOrder.orderId);
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/return?orderId=${latestOrder.orderId}`
|
||||
url: `/subPackages/service/return/index?orderId=${latestOrder.orderId}`
|
||||
});
|
||||
} else if (latestOrder.orderStatus === 'waiting_for_payment') {
|
||||
// 如果是待支付订单,跳转到支付页面,并传递必要信息
|
||||
@@ -81,13 +81,13 @@
|
||||
const totalAmount = (parseFloat(depositAmount) + parseFloat(packagePrice)).toFixed(2);
|
||||
|
||||
uni.redirectTo({
|
||||
url: `/pages/order/payment?orderId=${latestOrder.orderId}&packageTimeHours=${packageTimeHours}&packagePrice=${packagePrice}&hourlyRate=${hourlyRate}&totalAmount=${totalAmount}&depositAmount=${depositAmount}`
|
||||
url: `/subPackages/order/payment?orderId=${latestOrder.orderId}&packageTimeHours=${packageTimeHours}&packagePrice=${packagePrice}&hourlyRate=${hourlyRate}&totalAmount=${totalAmount}&depositAmount=${depositAmount}`
|
||||
});
|
||||
} else {
|
||||
// 其他状态(理论上不应该到这里,除非statusesToCheck配置错误),默认到详情页
|
||||
console.log('检测到其他状态订单,跳转详情页:', latestOrder.orderId);
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/detail?deviceNo=${deviceNo}`
|
||||
url: `/pages/order/detail?deviceNo=${deviceNo}`
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 26 KiB |
@@ -763,7 +763,7 @@
|
||||
|
||||
const GotoList = ()=>{
|
||||
uni.navigateTo({
|
||||
url:'/pages/device/orderList'
|
||||
url:'/subPackages/business/device-orderList'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -825,7 +825,7 @@
|
||||
// 跳转到订单页面
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/order/index'
|
||||
url: '/subPackages/business/device-orderList'
|
||||
})
|
||||
}, 2000)
|
||||
},
|
||||
@@ -599,7 +599,7 @@
|
||||
const onReorder = (order) => {
|
||||
if(order){
|
||||
uni.navigateTo({
|
||||
url: `/pages/device/goods?productId=${order}`
|
||||
url: `/subPackages/business/device-goods?productId=${order}`
|
||||
});
|
||||
}
|
||||
// console.log(order);
|
||||
@@ -466,7 +466,7 @@
|
||||
// 跳转到设备订单详情页
|
||||
const navigateToDeviceOrderDetail = (order) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/device/orderDetail?orderId=${order.orderId || order.orderNo}`
|
||||
url: `/subPackages/business/device-orderDetail?orderId=${order.orderId || order.orderNo}`
|
||||
});
|
||||
};
|
||||
|
||||
@@ -71,8 +71,8 @@ import {
|
||||
import {
|
||||
getNearbyDevices,
|
||||
transformDeviceData
|
||||
} from '../../config/api/device.js'
|
||||
import { useI18n } from '../../utils/i18n.js'
|
||||
} from '@/config/api/device.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -391,7 +391,7 @@ const handleBuy = async () => {
|
||||
// 支付成功后,跳转到我的会员卡页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/card'
|
||||
url: '/subPackages/business/my-card'
|
||||
})
|
||||
}, 1500)
|
||||
},
|
||||
@@ -463,7 +463,7 @@ const handleBuy = async () => {
|
||||
// 支付成功后,跳转到我的优惠券页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/coupon'
|
||||
url: '/subPackages/business/my-coupon'
|
||||
})
|
||||
}, 1500)
|
||||
},
|
||||
@@ -514,11 +514,11 @@ const handleBuy = async () => {
|
||||
const goToMyProducts = () => {
|
||||
if (currentTab.value === 'card') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/card'
|
||||
url: '/subPackages/business/my-card'
|
||||
})
|
||||
} else if (currentTab.value === 'coupon') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/coupon'
|
||||
url: '/subPackages/business/my-coupon'
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,399 @@
|
||||
<template>
|
||||
<view class="success-container">
|
||||
<!-- 支付成功状态和订单信息 -->
|
||||
<view class="status-order-card">
|
||||
<!-- 支付成功状态 -->
|
||||
<view class="status-section">
|
||||
<view class="status-icon success"></view>
|
||||
<view class="status-text">{{ $t('success.paymentSuccess') }}</view>
|
||||
<view class="status-desc">{{ $t('success.paymentSuccessDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<view class="section-divider"></view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-section">
|
||||
<view class="card-title">{{ $t('success.orderInfo') }}</view>
|
||||
<view class="info-item">
|
||||
<text class="label">{{ $t('order.orderNo') }}</text>
|
||||
<text class="value">{{ orderInfo.orderNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">{{ $t('order.deviceNo') }}</text>
|
||||
<text class="value">{{ orderInfo.deviceNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">{{ $t('success.paymentAmount') }}</text>
|
||||
<text class="value">¥{{ orderInfo.amount || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">{{ $t('success.paymentTime') }}</text>
|
||||
<text class="value">{{ orderInfo.payTime || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 设备状态 -->
|
||||
<view class="device-status">
|
||||
<view class="status-message">{{ deviceMessage }}</view>
|
||||
<view class="loading-animation" v-if="isLoading">
|
||||
<view class="loading-circle"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="button-group">
|
||||
<view class="secondary-btn" @click="goToHome">{{ $t('success.backToHome') }}</view>
|
||||
<view class="primary-btn" @click="goToOrderList">{{ $t('success.viewOrder') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
getCurrentInstance
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
queryById,
|
||||
getOrderByOrderNo
|
||||
} from '@/config/api/order.js'
|
||||
|
||||
// 获取当前实例以访问 $t 方法
|
||||
const {
|
||||
proxy
|
||||
} = getCurrentInstance()
|
||||
|
||||
// 响应式数据
|
||||
const orderId = ref('')
|
||||
const orderInfo = ref({})
|
||||
const isLoading = ref(true)
|
||||
const deviceMessage = ref('')
|
||||
const hasTriggeredDevice = ref(false)
|
||||
|
||||
// 页面加载
|
||||
onLoad((options) => {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: proxy.$t('success.paymentSuccess')
|
||||
})
|
||||
|
||||
deviceMessage.value = proxy.$t('success.preparingDevice')
|
||||
|
||||
// #ifdef H5
|
||||
if (uni.getStorageSync('pendingPaymentNo')) {
|
||||
orderId.value = options.orderId
|
||||
loadOrderInfo()
|
||||
|
||||
// 添加页面显示监听,防止页面切换后重复触发弹出
|
||||
uni.$once('orderSuccess:' + orderId.value, () => {
|
||||
console.log('已经触发过弹出逻辑,不再重复触发')
|
||||
hasTriggeredDevice.value = true
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: proxy.$t('order.orderNotExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
goToHome()
|
||||
}, 1500)
|
||||
}
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
if (options && options.orderId) {
|
||||
orderId.value = options.orderId
|
||||
loadOrderInfo()
|
||||
|
||||
// 添加页面显示监听,防止页面切换后重复触发弹出
|
||||
uni.$once('orderSuccess:' + orderId.value, () => {
|
||||
console.log('已经触发过弹出逻辑,不再重复触发')
|
||||
hasTriggeredDevice.value = true
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: proxy.$t('order.orderNotExist'),
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
goToHome()
|
||||
}, 1500)
|
||||
}
|
||||
// #endif
|
||||
})
|
||||
|
||||
// 加载订单信息
|
||||
const loadOrderInfo = async () => {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: proxy.$t('common.loading')
|
||||
})
|
||||
|
||||
const res = await queryById(orderId.value)
|
||||
if (res.code === 200 && res.data) {
|
||||
const orderData = res.data
|
||||
orderInfo.value = {
|
||||
orderNo: orderData.orderNo || orderData.orderId,
|
||||
deviceNo: orderData.deviceNo,
|
||||
amount: orderData.payAmount || orderData.amount,
|
||||
payTime: orderData.payTime || formatTime(new Date())
|
||||
}
|
||||
|
||||
// 检查订单状态
|
||||
if (orderData.orderStatus === 'IN_USED') {
|
||||
// 如果已经是使用中状态,可能说明开锁已经完成
|
||||
deviceMessage.value = '设备已弹出,请取走您的风扇'
|
||||
isLoading.value = false
|
||||
|
||||
// 如果是第一次加载页面且设备已弹出,记录状态,避免重复弹出
|
||||
if (!hasTriggeredDevice.value) {
|
||||
uni.$emit('orderSuccess:' + orderId.value)
|
||||
hasTriggeredDevice.value = true
|
||||
}
|
||||
} else {
|
||||
// 在此页面不再触发设备弹出操作,仅更新展示文案和加载状态
|
||||
deviceMessage.value = proxy.$t('success.paymentSuccessDesc')
|
||||
isLoading.value = false
|
||||
}
|
||||
} else {
|
||||
throw new Error('获取订单信息失败')
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: error.message || proxy.$t('order.getOrderFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
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')
|
||||
const second = date.getSeconds().toString().padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
||||
}
|
||||
|
||||
// 返回首页
|
||||
const goToHome = () => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
|
||||
// 查看订单列表
|
||||
const goToOrderList = () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/order/index'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.success-container {
|
||||
padding: 20px;
|
||||
padding-bottom: 180rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.status-order-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
|
||||
.status-section {
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
|
||||
.status-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 0 auto 16px;
|
||||
background-color: #07c160;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
border: 3px solid #fff;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
transform-origin: center;
|
||||
transform: translate(-50%, -70%) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #07c160;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.status-desc {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
height: 1px;
|
||||
background-color: #f0f0f0;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.order-section {
|
||||
padding: 20px;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
padding-left: 12px;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #07c160;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.device-status {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
|
||||
.status-message {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.loading-animation {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
|
||||
.loading-circle {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #f0f0f0;
|
||||
border-top-color: #07c160;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.primary-btn {
|
||||
background-color: #07c160;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 32rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 24rpx;
|
||||
height: 64rpx;
|
||||
line-height: 64rpx;
|
||||
white-space: nowrap;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-btn {
|
||||
background-color: #fff;
|
||||
color: #07c160;
|
||||
border: 2rpx solid #07c160;
|
||||
border-radius: 32rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 24rpx;
|
||||
height: 64rpx;
|
||||
line-height: 64rpx;
|
||||
white-space: nowrap;
|
||||
|
||||
&:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,323 +1,323 @@
|
||||
<template>
|
||||
<view class="deposit-container">
|
||||
<!-- 押金金额卡片 -->
|
||||
<view class="deposit-card">
|
||||
<view class="title">{{ $t('deposit.depositBalance') }}</view>
|
||||
<view class="amount">¥{{ depositAmount }}</view>
|
||||
<button class="withdraw-btn" @click="handleWithdraw" :disabled="depositAmount <= 0">{{ $t('deposit.withdraw') }}</button>
|
||||
</view>
|
||||
|
||||
<!-- 提现说明 -->
|
||||
<view class="notice-card">
|
||||
<view class="notice-title">
|
||||
<view class="dot"></view>
|
||||
<text>{{ $t('deposit.withdrawNotice') }}</text>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<view class="notice-item">1. {{ $t('deposit.withdrawNotice1') }}</view>
|
||||
<view class="notice-item">2. {{ $t('deposit.withdrawNotice2') }}</view>
|
||||
<view class="notice-item">3. {{ $t('deposit.withdrawNotice3') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 押金记录 -->
|
||||
<view class="record-card" v-if="records.length > 0">
|
||||
<view class="record-title">{{ $t('deposit.depositRecord') }}</view>
|
||||
<view class="record-list">
|
||||
<view class="record-item" v-for="(item, index) in records" :key="index">
|
||||
<view class="record-info">
|
||||
<text class="record-type">{{ item.typeText }}</text>
|
||||
<text class="record-time">{{ item.time }}</text>
|
||||
</view>
|
||||
<text class="record-amount" :class="item.type === 'refund' ? 'refund' : ''">
|
||||
{{ item.type === 'refund' ? '+' : '-' }}¥{{ item.amount }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getUserInfo } from '../../util/index.js'
|
||||
import { withdrawDeposit } from '../../config/api/user.js'
|
||||
import { queryById } from '../../config/api/order.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const depositAmount = ref('0.00')
|
||||
const orderNo = ref('')
|
||||
const orderId = ref('')
|
||||
const records = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('deposit.title')
|
||||
})
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
loadUserInfo()
|
||||
})
|
||||
|
||||
const loadUserInfo = async () => {
|
||||
try {
|
||||
const res = await getUserInfo()
|
||||
if (res.code === 200) {
|
||||
depositAmount.value = res.data.balanceAmount || '0.00'
|
||||
orderNo.value = res.data.latestOrderNo || ''
|
||||
orderId.value = res.data.latestOrderId || ''
|
||||
|
||||
// 如果存在余额,获取押金记录
|
||||
if (parseFloat(depositAmount.value) > 0 && orderNo.value) {
|
||||
records.value = [
|
||||
{
|
||||
type: 'pay',
|
||||
typeText: t('deposit.payRecord'),
|
||||
time: formatDate(new Date()),
|
||||
amount: depositAmount.value
|
||||
}
|
||||
]
|
||||
} else {
|
||||
records.value = []
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: t('user.getUserInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleWithdraw = async () => {
|
||||
if (parseFloat(depositAmount.value) <= 0) {
|
||||
uni.showToast({
|
||||
title: t('deposit.noBalance'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: t('deposit.confirmWithdraw'),
|
||||
content: t('deposit.withdrawDesc'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({
|
||||
title: t('deposit.withdrawing')
|
||||
})
|
||||
|
||||
try {
|
||||
const result = await withdrawDeposit(orderNo.value)
|
||||
|
||||
if (result.code === 200) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: t('deposit.withdrawSubmitted'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 更新记录
|
||||
records.value.push({
|
||||
type: 'refund',
|
||||
typeText: t('deposit.refundRecord'),
|
||||
time: formatDate(new Date()),
|
||||
amount: depositAmount.value
|
||||
})
|
||||
// 更新余额为0
|
||||
depositAmount.value = '0.00'
|
||||
|
||||
// 重新加载用户信息
|
||||
setTimeout(() => {
|
||||
loadUserInfo()
|
||||
}, 1500)
|
||||
} else {
|
||||
throw new Error(result.msg || t('deposit.withdrawFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
|
||||
// 更详细的错误处理
|
||||
let errorMessage = t('deposit.withdrawFailed');
|
||||
|
||||
if (error.message) {
|
||||
if (error.message.includes('尚未归还')) {
|
||||
errorMessage = t('deposit.orderNotReturned');
|
||||
} else if (error.message.includes('已退还')) {
|
||||
errorMessage = t('deposit.alreadyRefunded');
|
||||
} else if (error.message.includes('处理中')) {
|
||||
errorMessage = t('deposit.refundProcessing');
|
||||
} else if (error.message.includes('余额为0')) {
|
||||
errorMessage = t('deposit.noBalance');
|
||||
} else {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: t('deposit.withdrawFailed'),
|
||||
content: errorMessage,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear()
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = date.getDate().toString().padStart(2, '0')
|
||||
const hours = date.getHours().toString().padStart(2, '0')
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0')
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.deposit-container {
|
||||
min-height: 100vh;
|
||||
background: #f8f8f8;
|
||||
padding: 30rpx;
|
||||
|
||||
.deposit-card {
|
||||
background: linear-gradient(135deg, #1976D2, #64B5F6);
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
box-shadow: 0 4rpx 20rpx rgba(25,118,210,0.2);
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 72rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.withdraw-btn {
|
||||
background: #fff;
|
||||
color: #1976D2;
|
||||
width: 80%;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin: 0 auto;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
background: rgba(255,255,255,0.6);
|
||||
color: rgba(25,118,210,0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
margin-top: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.notice-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background: #1976D2;
|
||||
border-radius: 50%;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
.notice-item {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
padding-left: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.record-card {
|
||||
margin-top: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.record-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
border-left: 8rpx solid #1976D2;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.record-list {
|
||||
.record-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.record-info {
|
||||
.record-type {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 6rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.record-amount {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&.refund {
|
||||
color: #4CAF50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view class="deposit-container">
|
||||
<!-- 押金金额卡片 -->
|
||||
<view class="deposit-card">
|
||||
<view class="title">{{ $t('deposit.depositBalance') }}</view>
|
||||
<view class="amount">¥{{ depositAmount }}</view>
|
||||
<button class="withdraw-btn" @click="handleWithdraw" :disabled="depositAmount <= 0">{{ $t('deposit.withdraw') }}</button>
|
||||
</view>
|
||||
|
||||
<!-- 提现说明 -->
|
||||
<view class="notice-card">
|
||||
<view class="notice-title">
|
||||
<view class="dot"></view>
|
||||
<text>{{ $t('deposit.withdrawNotice') }}</text>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<view class="notice-item">1. {{ $t('deposit.withdrawNotice1') }}</view>
|
||||
<view class="notice-item">2. {{ $t('deposit.withdrawNotice2') }}</view>
|
||||
<view class="notice-item">3. {{ $t('deposit.withdrawNotice3') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 押金记录 -->
|
||||
<view class="record-card" v-if="records.length > 0">
|
||||
<view class="record-title">{{ $t('deposit.depositRecord') }}</view>
|
||||
<view class="record-list">
|
||||
<view class="record-item" v-for="(item, index) in records" :key="index">
|
||||
<view class="record-info">
|
||||
<text class="record-type">{{ item.typeText }}</text>
|
||||
<text class="record-time">{{ item.time }}</text>
|
||||
</view>
|
||||
<text class="record-amount" :class="item.type === 'refund' ? 'refund' : ''">
|
||||
{{ item.type === 'refund' ? '+' : '-' }}¥{{ item.amount }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getUserInfo } from '@/util/index.js'
|
||||
import { withdrawDeposit } from '@/config/api/user.js'
|
||||
import { queryById } from '@/config/api/order.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const depositAmount = ref('0.00')
|
||||
const orderNo = ref('')
|
||||
const orderId = ref('')
|
||||
const records = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('deposit.title')
|
||||
})
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
loadUserInfo()
|
||||
})
|
||||
|
||||
const loadUserInfo = async () => {
|
||||
try {
|
||||
const res = await getUserInfo()
|
||||
if (res.code === 200) {
|
||||
depositAmount.value = res.data.balanceAmount || '0.00'
|
||||
orderNo.value = res.data.latestOrderNo || ''
|
||||
orderId.value = res.data.latestOrderId || ''
|
||||
|
||||
// 如果存在余额,获取押金记录
|
||||
if (parseFloat(depositAmount.value) > 0 && orderNo.value) {
|
||||
records.value = [
|
||||
{
|
||||
type: 'pay',
|
||||
typeText: t('deposit.payRecord'),
|
||||
time: formatDate(new Date()),
|
||||
amount: depositAmount.value
|
||||
}
|
||||
]
|
||||
} else {
|
||||
records.value = []
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: t('user.getUserInfoFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleWithdraw = async () => {
|
||||
if (parseFloat(depositAmount.value) <= 0) {
|
||||
uni.showToast({
|
||||
title: t('deposit.noBalance'),
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: t('deposit.confirmWithdraw'),
|
||||
content: t('deposit.withdrawDesc'),
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({
|
||||
title: t('deposit.withdrawing')
|
||||
})
|
||||
|
||||
try {
|
||||
const result = await withdrawDeposit(orderNo.value)
|
||||
|
||||
if (result.code === 200) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: t('deposit.withdrawSubmitted'),
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 更新记录
|
||||
records.value.push({
|
||||
type: 'refund',
|
||||
typeText: t('deposit.refundRecord'),
|
||||
time: formatDate(new Date()),
|
||||
amount: depositAmount.value
|
||||
})
|
||||
// 更新余额为0
|
||||
depositAmount.value = '0.00'
|
||||
|
||||
// 重新加载用户信息
|
||||
setTimeout(() => {
|
||||
loadUserInfo()
|
||||
}, 1500)
|
||||
} else {
|
||||
throw new Error(result.msg || t('deposit.withdrawFailed'))
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
|
||||
// 更详细的错误处理
|
||||
let errorMessage = t('deposit.withdrawFailed');
|
||||
|
||||
if (error.message) {
|
||||
if (error.message.includes('尚未归还')) {
|
||||
errorMessage = t('deposit.orderNotReturned');
|
||||
} else if (error.message.includes('已退还')) {
|
||||
errorMessage = t('deposit.alreadyRefunded');
|
||||
} else if (error.message.includes('处理中')) {
|
||||
errorMessage = t('deposit.refundProcessing');
|
||||
} else if (error.message.includes('余额为0')) {
|
||||
errorMessage = t('deposit.noBalance');
|
||||
} else {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: t('deposit.withdrawFailed'),
|
||||
content: errorMessage,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear()
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = date.getDate().toString().padStart(2, '0')
|
||||
const hours = date.getHours().toString().padStart(2, '0')
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0')
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.deposit-container {
|
||||
min-height: 100vh;
|
||||
background: #f8f8f8;
|
||||
padding: 30rpx;
|
||||
|
||||
.deposit-card {
|
||||
background: linear-gradient(135deg, #1976D2, #64B5F6);
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
box-shadow: 0 4rpx 20rpx rgba(25,118,210,0.2);
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 72rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.withdraw-btn {
|
||||
background: #fff;
|
||||
color: #1976D2;
|
||||
width: 80%;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin: 0 auto;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
background: rgba(255,255,255,0.6);
|
||||
color: rgba(25,118,210,0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
margin-top: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.notice-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background: #1976D2;
|
||||
border-radius: 50%;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
.notice-item {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
padding-left: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.record-card {
|
||||
margin-top: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.record-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
border-left: 8rpx solid #1976D2;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.record-list {
|
||||
.record-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.record-info {
|
||||
.record-type {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 6rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.record-amount {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&.refund {
|
||||
color: #4CAF50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
wxLogin,
|
||||
} from '@/util/index'
|
||||
|
||||
import {
|
||||
getMyIndexInfo
|
||||
} from "@/config/api/user.js";
|
||||
import {
|
||||
queryHasOrder,
|
||||
checkOrdersByStatus
|
||||
} from "@/config/api/order.js";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
async onLoad(option) {
|
||||
console.log('bagCheck onLoad option:', option);
|
||||
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('device.checking')
|
||||
})
|
||||
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.processing'),
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 检查是否传入设备编号
|
||||
if (!option || !option.deviceNo) {
|
||||
throw new Error(this.$t('device.deviceNoNotRecognized'));
|
||||
}
|
||||
|
||||
const deviceNo = option.deviceNo;
|
||||
|
||||
// 检查用户是否有进行中(in_used)或待支付(waiting_for_payment)的订单
|
||||
const statusesToCheck = ['in_used', 'waiting_for_payment'];
|
||||
const res = await checkOrdersByStatus(deviceNo, statusesToCheck);
|
||||
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
// 找到相关订单,取最新的一条
|
||||
const latestOrder = res.data[0]; // 假设返回结果按时间倒序
|
||||
|
||||
if (latestOrder.orderStatus === 'in_used') {
|
||||
// 如果是使用中的订单,跳转到归还页面
|
||||
console.log('检测到使用中订单,跳转归还页:', latestOrder.orderId);
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/return?orderId=${latestOrder.orderId}`
|
||||
});
|
||||
} else if (latestOrder.orderStatus === 'waiting_for_payment') {
|
||||
// 如果是待支付订单,跳转到支付页面,并传递必要信息
|
||||
console.log('检测到待支付订单,跳转支付页:', latestOrder.orderId);
|
||||
|
||||
// 获取套餐时间(分钟)
|
||||
const packageTimeMinutes = latestOrder.packageTime || 60;
|
||||
|
||||
// 套餐小时数
|
||||
const packageTimeHours = (packageTimeMinutes / 60).toFixed(1);
|
||||
|
||||
// 套餐价格
|
||||
const packagePrice = latestOrder.packagePrice || '0.00';
|
||||
|
||||
// 计算每小时费率
|
||||
const hourlyRate = (parseFloat(packagePrice) / (packageTimeMinutes / 60)).toFixed(2);
|
||||
|
||||
// 押金金额
|
||||
const depositAmount = latestOrder.depositAmount || '99.00';
|
||||
|
||||
// 计算总金额(套餐+押金)
|
||||
const totalAmount = (parseFloat(depositAmount) + parseFloat(packagePrice)).toFixed(2);
|
||||
|
||||
uni.redirectTo({
|
||||
url: `/pages/order/payment?orderId=${latestOrder.orderId}&packageTimeHours=${packageTimeHours}&packagePrice=${packagePrice}&hourlyRate=${hourlyRate}&totalAmount=${totalAmount}&depositAmount=${depositAmount}`
|
||||
});
|
||||
} else {
|
||||
// 其他状态(理论上不应该到这里,除非statusesToCheck配置错误),默认到详情页
|
||||
console.log('检测到其他状态订单,跳转详情页:', latestOrder.orderId);
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/detail?deviceNo=${deviceNo}`
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 没有找到相关状态的订单,跳转到设备详情页进行租借
|
||||
console.log('未检测到相关订单,跳转详情页');
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/detail?deviceNo=${deviceNo}`
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// 只处理真正的错误,不是"没有订单"的情况
|
||||
if (error.message && (
|
||||
error.message.includes('未识别到设备编号') ||
|
||||
error.message.includes('网络请求失败') ||
|
||||
error.message.includes('服务器错误')
|
||||
) ) {
|
||||
console.error('扫码检查订单失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || this.$t('device.processFailed'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
} else {
|
||||
// 对于其他错误,包括"没有找到订单",直接跳转到详情页,不显示错误消息
|
||||
console.log('没有找到符合条件的订单或发生其他错误,直接跳转详情页');
|
||||
}
|
||||
|
||||
// 无论什么情况,都跳转到一个可用页面
|
||||
setTimeout(() => {
|
||||
if (option && option.deviceNo) {
|
||||
uni.redirectTo({
|
||||
url: `/pages/device/detail?deviceNo=${option.deviceNo}`
|
||||
});
|
||||
} else {
|
||||
// uni.switchTab({
|
||||
// url:'/pages/index/index'
|
||||
// })
|
||||
// 如果连deviceNo都没有,则返回首页
|
||||
uni.reLaunch({ url: '/pages/index/index' });
|
||||
}
|
||||
}, 2000);
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -92,7 +92,7 @@
|
||||
getFeedbackDetail,
|
||||
getFeedbackMessages,
|
||||
sendFeedbackMessage
|
||||
} from '../../config/api/feedback.js';
|
||||
} from '@/config/api/feedback.js';
|
||||
import {
|
||||
useI18n
|
||||
} from '@/utils/i18n.js'
|
||||
@@ -72,10 +72,10 @@
|
||||
} from "@dcloudio/uni-app"
|
||||
import {
|
||||
addUserFeedback
|
||||
} from '../../config/api/feedback'
|
||||
} from '@/config/api/feedback'
|
||||
import {
|
||||
uploadOssResource
|
||||
} from '../../config/api/user'
|
||||
} from '@/config/api/user'
|
||||
import {
|
||||
useI18n
|
||||
} from '@/utils/i18n.js'
|
||||
@@ -72,7 +72,7 @@
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
getFeedbackList
|
||||
} from '../../config/api/feedback.js';
|
||||
} from '@/config/api/feedback.js';
|
||||
import {
|
||||
useI18n
|
||||
} from '@/utils/i18n.js'
|
||||
@@ -1,143 +1,143 @@
|
||||
<template>
|
||||
<view class="help-container">
|
||||
<!-- 常见问题 -->
|
||||
<view class="faq-section">
|
||||
<uv-collapse :border="false">
|
||||
<uv-collapse-item
|
||||
v-for="(item, index) in faqList"
|
||||
:key="index"
|
||||
:title="$t(item.question)"
|
||||
:name="index"
|
||||
>
|
||||
<view class="answer-content">
|
||||
<text class="answer-text">{{ $t(item.answer) }}</text>
|
||||
</view>
|
||||
</uv-collapse-item>
|
||||
</uv-collapse>
|
||||
</view>
|
||||
|
||||
<!-- 联系客服 -->
|
||||
<view class="contact-card">
|
||||
<view class="contact-title">{{ $t('help.contactUs') }}</view>
|
||||
<view class="contact-content">
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ $t('help.phone') }}</text>
|
||||
<text class="value" @click="makePhoneCall">{{ customerPhone }}</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ $t('help.workingHours') }}</text>
|
||||
<text class="value">{{ $t('help.workingHoursValue') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { HELP_CONTENT } from '@/constants/help'
|
||||
import { getCustomerPhone } from '@/util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const faqList = ref(HELP_CONTENT.FAQ_LIST)
|
||||
const customerPhone = ref(HELP_CONTENT.CONTACT.PHONE.VALUE)
|
||||
|
||||
onLoad(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('help.title')
|
||||
})
|
||||
customerPhone.value = getCustomerPhone()
|
||||
})
|
||||
|
||||
const makePhoneCall = () => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: customerPhone.value
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.help-container {
|
||||
min-height: 100vh;
|
||||
background: #f8f8f8;
|
||||
padding: 30rpx;
|
||||
|
||||
.faq-section {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
overflow: hidden;
|
||||
|
||||
.answer-content {
|
||||
padding: 20rpx 30rpx 30rpx;
|
||||
background: #f9f9f9;
|
||||
|
||||
.answer-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.contact-title {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
display: inline-block;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 8rpx;
|
||||
width: fit-content;
|
||||
|
||||
&::after {
|
||||
z-index: -1;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 8rpx;
|
||||
width: 88%;
|
||||
height: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #07C160;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-content {
|
||||
.contact-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view class="help-container">
|
||||
<!-- 常见问题 -->
|
||||
<view class="faq-section">
|
||||
<uv-collapse :border="false">
|
||||
<uv-collapse-item
|
||||
v-for="(item, index) in faqList"
|
||||
:key="index"
|
||||
:title="$t(item.question)"
|
||||
:name="index"
|
||||
>
|
||||
<view class="answer-content">
|
||||
<text class="answer-text">{{ $t(item.answer) }}</text>
|
||||
</view>
|
||||
</uv-collapse-item>
|
||||
</uv-collapse>
|
||||
</view>
|
||||
|
||||
<!-- 联系客服 -->
|
||||
<view class="contact-card">
|
||||
<view class="contact-title">{{ $t('help.contactUs') }}</view>
|
||||
<view class="contact-content">
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ $t('help.phone') }}</text>
|
||||
<text class="value" @click="makePhoneCall">{{ customerPhone }}</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="label">{{ $t('help.workingHours') }}</text>
|
||||
<text class="value">{{ $t('help.workingHoursValue') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { HELP_CONTENT } from '@/constants/help'
|
||||
import { getCustomerPhone } from '@/util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const faqList = ref(HELP_CONTENT.FAQ_LIST)
|
||||
const customerPhone = ref(HELP_CONTENT.CONTACT.PHONE.VALUE)
|
||||
|
||||
onLoad(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('help.title')
|
||||
})
|
||||
customerPhone.value = getCustomerPhone()
|
||||
})
|
||||
|
||||
const makePhoneCall = () => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: customerPhone.value
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.help-container {
|
||||
min-height: 100vh;
|
||||
background: #f8f8f8;
|
||||
padding: 30rpx;
|
||||
|
||||
.faq-section {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
overflow: hidden;
|
||||
|
||||
.answer-content {
|
||||
padding: 20rpx 30rpx 30rpx;
|
||||
background: #f9f9f9;
|
||||
|
||||
.answer-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
|
||||
.contact-title {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
display: inline-block;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 8rpx;
|
||||
width: fit-content;
|
||||
|
||||
&::after {
|
||||
z-index: -1;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 8rpx;
|
||||
width: 88%;
|
||||
height: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #07C160;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-content {
|
||||
.contact-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -27,9 +27,9 @@
|
||||
<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>
|
||||
<text class="link" @tap.stop="go('/subPackages/other/legal/agreement')">{{ $t('user.userAgreement') }}</text>
|
||||
{{ $t('common.and') }}
|
||||
<text class="link" @tap.stop="go('/pages/legal/privacy')">{{ $t('user.privacyPolicy') }}</text>
|
||||
<text class="link" @tap.stop="go('/subPackages/other/legal/privacy')">{{ $t('user.privacyPolicy') }}</text>
|
||||
</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
@@ -40,7 +40,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
||||
import { wxLogin, getUserPhoneNumber, getUserInfo } from '@/util/index.js'
|
||||
import { useI18n } from '@/utils/i18n.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -166,7 +166,7 @@
|
||||
|
||||
// 跳转到手机号登录页面
|
||||
const goToPhoneLogin = () => {
|
||||
uni.navigateTo({ url: '/pages/login/phone' })
|
||||
uni.navigateTo({ url: '/subPackages/user/login/phone' })
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
<template>
|
||||
<view class="my-card-page">
|
||||
<!-- 会员卡列表 -->
|
||||
<view class="card-list" v-if="cardList.length > 0">
|
||||
<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: 240rpx;'">
|
||||
<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">
|
||||
<text class="card-name">{{ card.name }}</text>
|
||||
<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: 20rpx; padding: 6rpx 20rpx;"
|
||||
@click.stop="handleUseCard(card)">
|
||||
<text class="status-text" style="color: #A16300;">{{ $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>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 使用情况和操作按钮 -->
|
||||
<view style="position: absolute; bottom: -20rpx; left: 0; right: 0; padding: 20rpx;z-index:1;">
|
||||
<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 v-else class="card-usage-info">
|
||||
<text class="usage-text">每日限用次数:{{card.dailyLimitCount}}次</text>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<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>
|
||||
|
||||
</view>
|
||||
<view v-else class="renew-btn">
|
||||
<text class="renew-text">单次限时:{{card.singleLimitMinutes}}分钟</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else>
|
||||
<image class="empty-icon" src="/static/empty-card.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">{{ $t('myCard.noCards') }}</text>
|
||||
<view class="buy-btn" @click="goToBuy">
|
||||
<text class="buy-text">{{ $t('myCard.buyNow') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import {
|
||||
useI18n
|
||||
} from '@/utils/i18n.js'
|
||||
import {
|
||||
getMemberCardsByStatus
|
||||
} from '@/config/api/member.js'
|
||||
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 getCardList = async () => {
|
||||
try {
|
||||
const response = await getMemberCardsByStatus()
|
||||
// 处理API返回的数据,转换为模板需要的格式
|
||||
if (response.code === 200 && response.data) {
|
||||
cardList.value = response.data.map(item => ({
|
||||
id: item.id,
|
||||
name: item.cardName,
|
||||
cardType: item.cardType, // TIME 或 COUNT
|
||||
// 次卡相关
|
||||
totalCount: item.totalCount,
|
||||
remainingCount: item.remainingCount,
|
||||
singleLimitMinutesForCount: item.singleLimitMinutesForCount,
|
||||
// 时长卡相关
|
||||
cycleDays: item.cycleDays,
|
||||
dailyLimitCount: item.dailyLimitCount,
|
||||
singleLimitMinutes: item.singleLimitMinutes,
|
||||
currentCycleStartTime: item.currentCycleStartTime,
|
||||
currentCycleUsedCount: item.currentCycleUsedCount,
|
||||
// 通用信息
|
||||
status: item.status,
|
||||
startDate: item.startTime?.split(' ')[0] || item.startTime,
|
||||
endDate: item.endTime?.split(' ')[0] || item.endTime,
|
||||
positionId: item.positionId,
|
||||
positionName: item.positionName,
|
||||
purchasePrice: item.purchasePrice,
|
||||
remark: item.remark
|
||||
}))
|
||||
} else {
|
||||
cardList.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取会员卡列表失败:', error)
|
||||
uni.showToast({
|
||||
title: t('myCard.getListFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 计算进度条宽度
|
||||
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 = {
|
||||
'unused': 'active',
|
||||
'expired': 'expired',
|
||||
'used': 'used',
|
||||
'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) => {
|
||||
// TODO: 跳转到卡详情页面
|
||||
// uni.showToast({
|
||||
// title: t('common.functionDeveloping'),
|
||||
// icon: 'none'
|
||||
// })
|
||||
}
|
||||
|
||||
// 续卡
|
||||
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({
|
||||
url: '/pages/purchase/index'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('user.myCards')
|
||||
})
|
||||
getCardList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-card-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
// background-color: #ffffff;
|
||||
border-radius: 25rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
|
||||
}
|
||||
|
||||
// 卡片头部
|
||||
.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;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
padding-top: 50rpx;
|
||||
position: absolute;
|
||||
background: rgba(255, 244, 227, 1);
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 0 0 25rpx 25rpx;
|
||||
|
||||
/* text-align: 30rpx ; */
|
||||
}
|
||||
|
||||
.card-usage-info {
|
||||
flex: 1;
|
||||
|
||||
.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;
|
||||
// background-color: #FFF9F0;
|
||||
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 {
|
||||
// background-color: #FFF9F0;
|
||||
|
||||
.status-text {
|
||||
color: #D4A574;
|
||||
}
|
||||
}
|
||||
|
||||
&.expired {
|
||||
// background-color: #F5F5F5;
|
||||
|
||||
.status-text {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
&.used {
|
||||
// background-color: #F5F5F5;
|
||||
|
||||
.status-text {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.buy-btn {
|
||||
padding: 20rpx 60rpx;
|
||||
background-color: #B8741A;
|
||||
border-radius: 48rpx;
|
||||
|
||||
.buy-text {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,542 @@
|
||||
<template>
|
||||
<view class="my-coupon-page">
|
||||
<!-- Tab 切换 -->
|
||||
<!-- <view class="tab-container">
|
||||
<view class="tab-item" :class="{ active: currentTab === 'available' }" @click="switchTab('available')">
|
||||
<text class="tab-text">{{ $t('myCoupon.available') }}</text>
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: currentTab === 'used' }" @click="switchTab('used')">
|
||||
<text class="tab-text">{{ $t('myCoupon.used') }}</text>
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: currentTab === 'expired' }" @click="switchTab('expired')">
|
||||
<text class="tab-text">{{ $t('myCoupon.expired') }}</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 优惠券列表 -->
|
||||
<view class="coupon-list" v-if="filteredCoupons.length > 0">
|
||||
<view v-for="coupon in filteredCoupons" :key="coupon.id" class="coupon-item-wrapper">
|
||||
<view class="coupon-item" :class="getCouponClass(coupon.status)">
|
||||
|
||||
<!-- 虚线上下圆形缺口 -->
|
||||
<view class="coupon-circle-top"></view>
|
||||
<view class="coupon-circle-bottom"></view>
|
||||
|
||||
<view class="coupon-left">
|
||||
<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-validity-left">{{ coupon.validity }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="coupon-divider"></view>
|
||||
<view class="coupon-right">
|
||||
<!-- <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 == 'unused'" @click="useCoupon(coupon)">
|
||||
<text class="use-text">{{ $t('myCoupon.useNow') }}</text>
|
||||
</view>
|
||||
<text class="coupon-status" v-else>{{ getStatusText(coupon.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else>
|
||||
<image class="empty-icon" src="/static/empty-coupon.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">{{ getEmptyText() }}</text>
|
||||
<view class="buy-btn" @click="goToBuy" v-if="currentTab === 'available'">
|
||||
<text class="buy-text">{{ $t('myCoupon.buyNow') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useI18n } from '@/utils/i18n.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 } = useI18n()
|
||||
|
||||
// 当前选中的 Tab
|
||||
const currentTab = ref('available')
|
||||
|
||||
// // Tab 与 API 状态的映射
|
||||
// const tabToStatusMap = {
|
||||
// available: 'unused',
|
||||
// used: 'used',
|
||||
// expired: 'expired'
|
||||
// }
|
||||
|
||||
// 优惠券列表
|
||||
const couponList = ref([])
|
||||
|
||||
// 过滤后的优惠券
|
||||
const filteredCoupons = computed(() => {
|
||||
return couponList.value;
|
||||
})
|
||||
|
||||
// 获取优惠券列表
|
||||
const getCouponList = async () => {
|
||||
try {
|
||||
// const apiStatus = tabToStatusMap[currentTab.value]
|
||||
const res = await getUserCoupons('')
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
// 将后端数据转换为前端需要的格式
|
||||
couponList.value = (res.data || []).map(item => {
|
||||
// 判断优惠券类型:discount_coupon 折扣券,deduction_coupon 抵扣券
|
||||
const isCashCoupon = item.couponType === 'deduction_coupon'
|
||||
|
||||
// 格式化使用条件
|
||||
let condition = '无门槛'
|
||||
if (item.usableCondition && item.usableCondition > 0) {
|
||||
condition = `满${item.usableCondition}可用`
|
||||
}
|
||||
|
||||
// 格式化有效期
|
||||
let validity = ''
|
||||
if (currentTab.value === 'used') {
|
||||
// 已使用显示使用时间
|
||||
validity = item.couponStartTime ? `使用时间 ${item.couponStartTime.split(' ')[0]}` : ''
|
||||
} else if (item.couponEndTime) {
|
||||
validity = `于 ${item.couponEndTime.split(' ')[0]} 过期`
|
||||
}
|
||||
console.log(item.status);
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.couponName || '优惠券',
|
||||
type: isCashCoupon ? 'cash' : 'discount',
|
||||
value: item.deductAmount ? parseFloat(item.deductAmount) : 0,
|
||||
discount: item.discountRate ? parseFloat(item.discountRate) * 10 : null,
|
||||
condition: condition,
|
||||
validity: validity,
|
||||
status: item.status,
|
||||
positionName: item.positionName
|
||||
}
|
||||
})
|
||||
} else {
|
||||
couponList.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取优惠券列表失败:', error)
|
||||
couponList.value = []
|
||||
uni.showToast({
|
||||
title: t('myCoupon.getListFailed'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 切换 Tab
|
||||
const switchTab = (tab) => {
|
||||
currentTab.value = tab
|
||||
getCouponList()
|
||||
}
|
||||
|
||||
// 获取优惠券样式类名
|
||||
const getCouponClass = (status) => {
|
||||
return status === 'unused' ? '' : 'disabled'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'used': t('myCoupon.usedStatus'),
|
||||
'expired': t('myCoupon.expiredStatus'),
|
||||
'refunded':t('myCoupon.refundedStatus')
|
||||
}
|
||||
console.log("获取状态文本:"+statusMap[status]);
|
||||
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'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 去购买
|
||||
const goToBuy = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/purchase/index?tab=coupon'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('user.myCoupons')
|
||||
})
|
||||
getCouponList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 优惠券样式变量封装
|
||||
$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;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* Tab 切换 */
|
||||
.tab-container {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
display: flex;
|
||||
background-color: #ffffff;
|
||||
z-index: 999;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
position: relative;
|
||||
|
||||
.tab-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.tab-text {
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background-color: #FFA928;
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-list {
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.coupon-item-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.coupon-item {
|
||||
background: #FFF4E3;
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
min-height: 180rpx;
|
||||
box-sizing: border-box;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.selected {
|
||||
border-color: $coupon-divider-color;
|
||||
box-shadow: 0 4rpx 20rpx rgba(184, 116, 26, 0.2);
|
||||
|
||||
.coupon-circle-top,
|
||||
.coupon-circle-bottom {
|
||||
background-color: $coupon-active-bg-start;
|
||||
border: 2rpx solid $coupon-divider-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
|
||||
opacity: 0.6;
|
||||
|
||||
.coupon-value,
|
||||
.coupon-condition,
|
||||
.coupon-name {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.coupon-circle-top,
|
||||
.coupon-circle-bottom {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 虚线顶部圆形缺口 */
|
||||
.coupon-circle-top {
|
||||
position: absolute;
|
||||
left: $coupon-divider-left+4%;
|
||||
top: -$coupon-circle-radius;
|
||||
transform: translateX(-50%);
|
||||
width: $coupon-circle-radius * 2;
|
||||
height: $coupon-circle-radius * 2;
|
||||
border-radius: 50%;
|
||||
background-color: $coupon-bg-faded;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* 虚线底部圆形缺口 */
|
||||
.coupon-circle-bottom {
|
||||
position: absolute;
|
||||
left: $coupon-divider-left+4%;
|
||||
bottom: -$coupon-circle-radius;
|
||||
transform: translateX(-50%);
|
||||
width: $coupon-circle-radius * 2;
|
||||
height: $coupon-circle-radius * 2;
|
||||
border-radius: 50%;
|
||||
background-color: $coupon-bg-faded;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.coupon-left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.coupon-value {
|
||||
display: flex;
|
||||
align-items: flex-end; // 单位在脚
|
||||
color: $coupon-theme-color;
|
||||
line-height: 1;
|
||||
width:120rpx;
|
||||
}
|
||||
|
||||
.coupon-amount {
|
||||
font-size: 56rpx; // 值要大
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.coupon-unit {
|
||||
font-size: 24rpx; // 单位小
|
||||
font-weight: 500;
|
||||
margin-bottom: 6rpx; // 微调单位垂直位置,使其更贴合“脚”
|
||||
margin-left: 4rpx;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.coupon-condition {
|
||||
font-size: 24rpx;
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.coupon-validity-left {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.coupon-divider {
|
||||
width: 2rpx;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: $coupon-divider-left;
|
||||
transform: translateX(-50%);
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
align-self: stretch;
|
||||
background: repeating-linear-gradient(to bottom,
|
||||
$coupon-divider-color 0rpx,
|
||||
$coupon-divider-color 8rpx,
|
||||
transparent 8rpx,
|
||||
transparent 16rpx);
|
||||
margin: 0 30rpx;
|
||||
}
|
||||
|
||||
.coupon-right {
|
||||
// flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
align-items: center;
|
||||
margin: auto 0;
|
||||
width: 160rpx;
|
||||
// align-content: center;
|
||||
// transform: translateY(50%);
|
||||
}
|
||||
|
||||
.coupon-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.coupon-validity {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.use-btn {
|
||||
// margin-top: 10rpx;
|
||||
// padding: 12rpx 28rpx;
|
||||
// background-color: #B8741A;
|
||||
// border-radius: 40rpx;
|
||||
|
||||
.use-text {
|
||||
font-size: 28rpx;
|
||||
color: #A16300;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-status {
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.buy-btn {
|
||||
padding: 20rpx 60rpx;
|
||||
background-color: #B8741A;
|
||||
border-radius: 48rpx;
|
||||
|
||||
.buy-text {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,15 +10,15 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="group">
|
||||
<view class="item" @click="navigateTo('/pages/legal/agreement')">
|
||||
<view class="item" @click="navigateTo('/subPackages/other/legal/agreement')">
|
||||
<text class="label">{{ $t('user.userAgreement') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="item" @click="navigateTo('/pages/legal/privacy')">
|
||||
<view class="item" @click="navigateTo('/subPackages/other/legal/privacy')">
|
||||
<text class="label">{{ $t('user.privacyPolicy') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
<view class="item" @click="navigateTo('/pages/legal/terms')">
|
||||
<view class="item" @click="navigateTo('/subPackages/other/legal/terms')">
|
||||
<text class="label">{{ $t('legal.termsAndConditions') }}</text>
|
||||
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
|
||||
</view>
|
||||
@@ -123,7 +123,7 @@ const handleLogout = async () => {
|
||||
setTimeout(() => {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
uni.reLaunch({ url: '/subPackages/user/login/index' })
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
@@ -1,240 +1,240 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card">
|
||||
<view class="avatar">
|
||||
<image :src="userInfo.avatar || '/static/images/default-avatar.png'" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="nickname">{{ userInfo.nickName || $t('user.notLoggedIn') }}</text>
|
||||
<text class="phone">{{ userInfo.phone || $t('user.phoneNotBound') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 余额卡片 -->
|
||||
<view class="balance-card">
|
||||
<view class="balance-title">{{ $t('userProfile.balance') }}</view>
|
||||
<view class="balance-amount">¥{{ userInfo.balanceAmount || '0.00' }}</view>
|
||||
<view class="balance-desc">{{ $t('user.balanceDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-list">
|
||||
<view class="menu-item" @click="navigateTo('/pages/order/index')">
|
||||
<text class="menu-icon">📋</text>
|
||||
<text class="menu-text">{{ $t('user.myOrders') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/feedback/index')">
|
||||
<text class="menu-icon">💬</text>
|
||||
<text class="menu-text">{{ $t('user.feedback') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/help/index')">
|
||||
<text class="menu-icon">ℹ️</text>
|
||||
<text class="menu-text">{{ $t('help.title') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-btn" @click="handleLogout" v-if="isLogin">
|
||||
<text>{{ $t('user.logout') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUserInfo } from '@/api/user'
|
||||
import { URL } from '@/config/url'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
userInfo: {},
|
||||
isLogin: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('user.personalCenter')
|
||||
})
|
||||
},
|
||||
onShow() {
|
||||
this.loadUserInfo()
|
||||
},
|
||||
methods: {
|
||||
async loadUserInfo() {
|
||||
try {
|
||||
const res = await getUserInfo()
|
||||
if (res.code === 401 || res.code === 40101) {
|
||||
// 无提示跳转至登录
|
||||
try {
|
||||
const pages = getCurrentPages()
|
||||
const current = pages && pages.length ? pages[pages.length - 1] : null
|
||||
const route = current && current.route ? ('/' + current.route) : '/pages/index/index'
|
||||
const query = current && current.options ? Object.keys(current.options).map(k => `${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
|
||||
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
|
||||
uni.reLaunch({ url: `/pages/login/index?redirect=${redirect}` })
|
||||
} catch (e) {
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
}
|
||||
} else if (res.code === 200) {
|
||||
this.userInfo = res.data
|
||||
this.isLogin = true
|
||||
} else {
|
||||
this.isLogin = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户信息失败:', error)
|
||||
this.isLogin = false
|
||||
}
|
||||
},
|
||||
navigateTo(url) {
|
||||
uni.navigateTo({ url })
|
||||
},
|
||||
handleLogout() {
|
||||
uni.showModal({
|
||||
title: this.$t('common.tips'),
|
||||
content: this.$t('user.confirmLogout'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
this.isLogin = false
|
||||
uni.showToast({
|
||||
title: this.$t('user.logoutSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.avatar image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.phone {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.balance-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.balance-title {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.balance-amount {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.balance-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin-top: 40rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
color: #ff4d4f;
|
||||
font-size: 28rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card">
|
||||
<view class="avatar">
|
||||
<image :src="userInfo.avatar || '/static/images/default-avatar.png'" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="nickname">{{ userInfo.nickName || $t('user.notLoggedIn') }}</text>
|
||||
<text class="phone">{{ userInfo.phone || $t('user.phoneNotBound') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 余额卡片 -->
|
||||
<view class="balance-card">
|
||||
<view class="balance-title">{{ $t('userProfile.balance') }}</view>
|
||||
<view class="balance-amount">¥{{ userInfo.balanceAmount || '0.00' }}</view>
|
||||
<view class="balance-desc">{{ $t('user.balanceDesc') }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-list">
|
||||
<view class="menu-item" @click="navigateTo('/pages/order/index')">
|
||||
<text class="menu-icon">📋</text>
|
||||
<text class="menu-text">{{ $t('user.myOrders') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/feedback/index')">
|
||||
<text class="menu-icon">💬</text>
|
||||
<text class="menu-text">{{ $t('user.feedback') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="navigateTo('/pages/help/index')">
|
||||
<text class="menu-icon">ℹ️</text>
|
||||
<text class="menu-text">{{ $t('help.title') }}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-btn" @click="handleLogout" v-if="isLogin">
|
||||
<text>{{ $t('user.logout') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUserInfo } from '@/util/index.js'
|
||||
import { URL } from '@/config/url'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
userInfo: {},
|
||||
isLogin: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$t('user.personalCenter')
|
||||
})
|
||||
},
|
||||
onShow() {
|
||||
this.loadUserInfo()
|
||||
},
|
||||
methods: {
|
||||
async loadUserInfo() {
|
||||
try {
|
||||
const res = await getUserInfo()
|
||||
if (res.code === 401 || res.code === 40101) {
|
||||
// 无提示跳转至登录
|
||||
try {
|
||||
const pages = getCurrentPages()
|
||||
const current = pages && pages.length ? pages[pages.length - 1] : null
|
||||
const route = current && current.route ? ('/' + current.route) : '/pages/index/index'
|
||||
const query = current && current.options ? Object.keys(current.options).map(k => `${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
|
||||
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
|
||||
uni.reLaunch({ url: `/pages/login/index?redirect=${redirect}` })
|
||||
} catch (e) {
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
}
|
||||
} else if (res.code === 200) {
|
||||
this.userInfo = res.data
|
||||
this.isLogin = true
|
||||
} else {
|
||||
this.isLogin = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户信息失败:', error)
|
||||
this.isLogin = false
|
||||
}
|
||||
},
|
||||
navigateTo(url) {
|
||||
uni.navigateTo({ url })
|
||||
},
|
||||
handleLogout() {
|
||||
uni.showModal({
|
||||
title: this.$t('common.tips'),
|
||||
content: this.$t('user.confirmLogout'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
this.isLogin = false
|
||||
uni.showToast({
|
||||
title: this.$t('user.logoutSuccess'),
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.avatar image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.phone {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.balance-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.balance-title {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.balance-amount {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.balance-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin-top: 40rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
color: #ff4d4f;
|
||||
font-size: 28rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
</style>
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<script setup>
|
||||
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'
|
||||
|
||||
const { t } = useI18n()
|
||||
Reference in New Issue
Block a user