You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="pay-page" :class="{ 'wechat-browser': isWeixinBrowser }">
<view class="fixed-nav" v-if="!isWeixinBrowser">
<NavBar title="在线付款" />
</view>
<view class="pay-scroll">
<!-- 预约信息 -->
<view class="pay-section">
<view class="pay-title">预约信息</view>
<view class="pay-row"><text>预约日期</text><text>{{ item.batch && item.batch.created_at ? formatChinaDate(item.batch.created_at) : '' }}</text></view>
<view class="pay-row"><text>预约批次</text><text>{{ item.batch.name }}</text></view>
<view class="pay-row"><text>航行方向</text><text>{{ item.direction_name }}</text></view>
<view class="pay-row">
<text>预约状态</text>
<text class="pay-status">已预约</text>
</view>
</view>
<!-- 船舶信息 -->
<view class="pay-section">
<view class="pay-title">船舶信息</view>
<view class="pay-row"><text>船舶编号</text><text>{{ item.ship.ship_number }}</text></view>
<view class="pay-row"><text>总长度</text><text>{{ item.ship.total_length }}</text></view>
<view class="pay-row"><text>型宽</text><text>{{ item.ship.total_width }}</text></view>
<view class="pay-row"><text>型深</text><text>{{ item.ship.molded_depth }}</text></view>
<view class="pay-row"><text>载重</text><text>{{ item.ship.total_tonnage }}</text></view>
<view class="pay-row"><text>类型</text><text>{{ item.ship && item.ship.ship_type ? getShipTypeName(item.ship.ship_type) : '' }}</text></view>
</view>
<!-- 票价信息 -->
<view class="pay-section">
<view class="pay-title">票价信息</view>
<view class="pay-row"><text>过闸费用</text><text>{{ item.price }}</text></view>
<view class="pay-row"><text>按吨位计费</text><text>{{ item.ship.total_tonnage }}</text></view>
<view class="pay-row pay-total">
<text>总计</text>
<text class="pay-total-num">{{ item.price }}</text>
</view>
</view>
<!-- 支付方式 -->
<view class="pay-section">
<view class="pay-title">扫码支付</view>
<view class="pay-qrcode-box">
<image :src="qrcodeUrl" class="pay-qrcode-img" mode="aspectFit" @longpress="handleLongPress" />
</view>
<view class="pay-qrcode-tip">请使用微信或支付宝扫码支付</view>
</view>
</view>
<view class="pay-bottom-bar">
<view class="pay-bottom-tip">
<text class="pay-bottom-clock">🕒</text>
<text class="pay-bottom-tip-text">
请在 <text class="pay-bottom-time">14:06</text> 内完成支付
</text>
</view>
<view class="pay-bottom-btns">
<button class="pay-cancel-btn">取消订单</button>
<button class="pay-pay-btn" @click="handlePay"> 300.00</button>
</view>
</view>
</view>
</template>
<script>
import NavBar from '@/components/NavBar.vue'
import { API } from '@/config/index.js'
export default {
name: 'PayOrderPage',
components: {
NavBar
},
data() {
return {
isWeixinBrowser: false,
qrcodeUrl: 'https://xukoushuniu.115.langye.net/assets/images/fake-qrcode.png',
payType: 'wechat',
item: {},
shipTypeEnum: []
}
},
onLoad(options) {
if (options.item) {
try {
this.item = JSON.parse(decodeURIComponent(options.item));
} catch (e) {
console.error('Failed to parse item:', e);
this.item = {};
}
}
console.log(this.item);
// #ifdef H5
this.isWeixinBrowser = /MicroMessenger/i.test(navigator.userAgent)
// #endif
},
onShow() {
this.fetchShipTypeEnum().then(() => {
if (this.item.id) {
this.fetchQrcode(this.item.id);
}
});
},
methods: {
formatChinaDate(dateStr) {
if (!dateStr) return '';
// 解析 ISO 字符串为 Date 对象
const date = new Date(dateStr);
// 转为北京时间(中国标准时间,东八区)
// Date对象自动以本地时区显示前提是 dateStr 是标准ISO格式
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
},
async fetchQrcode(id) {
const token = uni.getStorageSync('token');
if (!token || !id) return;
try {
const res = await new Promise((resolve, reject) => {
uni.request({
url: `${API.GET_PAYMENT_QRCODE}?id=${id}&token=${token}`,
method: 'GET',
success: resolve,
fail: reject
});
});
if (res.data && res.data.errcode === 0) {
this.qrcodeUrl = res.data.data.qrcode;
}
} catch (e) {}
},
async fetchShipTypeEnum() {
const token = uni.getStorageSync('token');
if (!token) return;
try {
const res = await new Promise((resolve, reject) => {
uni.request({
url: `${API.SHIP_PROPERTY_ENUM}?token=${token}`,
method: 'GET',
success: resolve,
fail: reject
});
});
if (res.data && res.data.errcode === 0) {
const shipTypeRaw = res.data.data.ship_type || {};
if (Array.isArray(shipTypeRaw)) {
this.shipTypeEnum = shipTypeRaw;
} else {
this.shipTypeEnum = Object.keys(shipTypeRaw).map(label => ({
label,
value: shipTypeRaw[label]
}));
}
}
} catch (e) {
console.error('Failed to fetch ship type enum:', e);
}
},
getShipTypeName(type) {
const found = this.shipTypeEnum.find(item => item.value === type || item.value == type);
return found ? found.label : type;
},
handlePay() {
//POST调用模拟支付接口
uni.request({
url: `${API.FAKE_PAY}`,
method: 'POST',
data: {
id: this.item.id,
token: uni.getStorageSync('token')
},
success: (res) => {
console.log('模拟支付结果:', res);
},
fail: (err) => {
console.error('模拟支付失败:', err);
}
});
},
handleLongPress() {
// 获取当前图片信息
uni.getImageInfo({
src: this.qrcodeUrl,
success: (imageInfo) => {
// 使用图片路径进行扫码
uni.scanCode({
scanType: ['qrCode'],
onlyFromCamera: false,
path: imageInfo.path,
success: (res) => {
console.log('扫码结果:', res);
if (res.result) {
uni.showToast({
title: '扫码成功',
icon: 'success'
});
// 这里可以处理扫码结果,比如跳转到支付页面
// uni.navigateTo({
// url: `/pages/payment/index?url=${encodeURIComponent(res.result)}`
// });
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败',
icon: 'none'
});
}
});
},
fail: (err) => {
console.error('获取图片信息失败:', err);
uni.showToast({
title: '获取图片失败',
icon: 'none'
});
}
});
},
}
}
</script>
<style lang="scss" scoped>
.pay-page {
min-height: 100vh;
background: linear-gradient(180deg, #cbe6ff 0%, #f6faff 100%);
padding-bottom: 32rpx;
}
.wechat-browser {
padding-top: 20rpx;
}
.wechat-browser .pay-scroll {
margin-top: 0;
}
.fixed-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: linear-gradient(180deg, #cbe6ff 0%, #f6faff 100%);
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
height: 90px;
}
.pay-scroll {
padding-top: 110px;
padding-bottom: 160rpx;
}
.pay-section {
background: #fff;
border-radius: 24rpx;
margin: 0 24rpx 32rpx 24rpx;
box-shadow: 0 4rpx 16rpx rgba(59,124,255,0.08);
padding: 32rpx 24rpx 8rpx 24rpx;
}
.pay-title {
font-size: 30rpx;
font-weight: bold;
color: #222;
margin-bottom: 24rpx;
}
.pay-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
color: #222;
padding: 18rpx 0;
border-bottom: 1rpx solid #f2f4f8;
}
.pay-row:last-child {
border-bottom: none;
}
.pay-status {
background: #217aff;
color: #fff;
border-radius: 24rpx;
padding: 4rpx 24rpx;
font-size: 24rpx;
}
.pay-total {
font-weight: bold;
}
.pay-total-num {
color: #217aff;
font-size: 32rpx;
}
.pay-paytype {
gap: 16rpx;
}
.pay-label {
display: flex;
align-items: center;
}
.pay-icon {
width: 36rpx;
height: 36rpx;
margin-right: 20rpx;
}
.pay-paytype text {
margin-left: 0; /* 确保文字紧跟图标 */
}
.pay-radio-group {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.pay-bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
box-shadow: 0 -2rpx 16rpx rgba(59,124,255,0.08);
padding: 24rpx 24rpx 32rpx 24rpx;
z-index: 999;
}
.pay-bottom-tip {
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
margin-bottom: 18rpx;
}
.pay-bottom-clock-box {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #217aff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
}
.pay-bottom-clock {
color: #217aff;
font-size: 28rpx;
}
.pay-bottom-tip-text {
color: #222;
}
.pay-bottom-time {
color: #217aff;
font-weight: bold;
}
.pay-bottom-btns {
display: flex;
gap: 24rpx;
justify-content: center;
}
.pay-cancel-btn {
min-width: 240rpx;
height: 72rpx;
border-radius: 36rpx;
background: #f5f7fa;
color: #222;
font-size: 28rpx;
border: none;
outline: none;
&::after {
border: none;
}
}
.pay-pay-btn {
min-width: 320rpx;
height: 72rpx;
border-radius: 36rpx;
background: #217aff;
color: #fff;
font-size: 28rpx;
font-weight: 500;
border: none;
outline: none;
&::after {
border: none;
}
}
.pay-qrcode-box {
display: flex;
justify-content: center;
align-items: center;
margin: 32rpx 0;
}
.pay-qrcode-img {
width: 260rpx;
height: 260rpx;
background: #fff;
border-radius: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
}
.pay-qrcode-tip {
text-align: center;
color: #888;
font-size: 26rpx;
margin-top: 12rpx;
}
</style>