核销未成功页面+扫码全流程

This commit is contained in:
BAKEYi 2026-05-26 13:58:25 +08:00
parent d008710130
commit 3c3159d5d8
5 changed files with 600 additions and 20 deletions

View File

@ -602,6 +602,12 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/shop/verify/verify-fail",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/shop/verify/verify-order-detail",
"style": {

View File

@ -67,19 +67,27 @@ export default {
uni.showToast({ title: '请输入6位核销码', icon: 'none' });
return;
}
request.post('/sj/poster/useOrderServerCode', {
server_code: this.code,
id: this.orderId,
order_type: this.orderType
uni.showLoading({ title: '查询订单中...', mask: true });
//
request.post('/sj/poster/getOrderByCode', {
server_code: this.code
}).then(res => {
if (res.code === 200) {
uni.showToast({ title: '核销成功' });
setTimeout(() => uni.navigateBack(), 1500);
uni.hideLoading();
if (res.code === 200 && res.data) {
// detail
const orderDataStr = encodeURIComponent(JSON.stringify(res.data));
uni.navigateTo({
url: `/pages/shop/verify/verify-order-detail?data=${orderDataStr}`
});
} else {
uni.showToast({ title: res.msg || '核销失败', icon: 'none' });
// fail
uni.navigateTo({ url: '/pages/shop/verify/verify-fail' });
}
}).catch(() => {
uni.showToast({ title: '网络异常', icon: 'none' });
uni.hideLoading();
uni.navigateTo({ url: '/pages/shop/verify/verify-fail' });
});
}
}

View File

@ -0,0 +1,105 @@
<template>
<view class="verify-fail-page">
<!-- 自定义导航栏 -->
<custom-navbar title="" :showBack="true" backgroundColor="#FFFFFF" borderBottom="none"></custom-navbar>
<view class="fail-content">
<!-- 失败图标 -->
<image class="fail-icon" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/3d7aec4c-beae-4d82-83ca-1244e9af4af7.png" mode="aspectFit"></image>
<!-- 失败文案 -->
<view class="fail-title">核销未成功</view>
<view class="fail-message">未找到订单信息请核对二维码是否正确</view>
<!-- 重新扫码按钮 -->
<view class="rescan-btn" @tap="rescan">
重新扫码验券
</view>
</view>
</view>
</template>
<script>
import CustomNavbar from "@/components/custom-navbar/custom-navbar.vue";
export default {
components: { CustomNavbar },
data() {
return {};
},
methods: {
rescan() {
// verify-order
uni.navigateBack({
delta: 1, // 退
});
}
}
};
</script>
<style lang="scss" scoped>
page {
background-color: #fff;
}
.verify-fail-page {
min-height: 100vh;
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.fail-content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
// padding: 0 60rpx;
margin-top: -250rpx;
}
.fail-icon {
width: 300rpx;
height: 257rpx;
margin-bottom: -10rpx;
}
.fail-title {
font-weight: 500;
font-size: 36rpx;
color: #333333;
line-height: 50rpx;
margin-bottom: 9rpx;
}
.fail-message {
font-weight: 400;
font-size: 26rpx;
color: #999999;
line-height: 37rpx;
text-align: center;
margin-bottom: 60rpx;
}
.rescan-btn {
width: 329rpx;
height: 98rpx;
border-radius: 49rpx;
border: 1rpx solid #FF4767;
display: flex;
align-items: center;
justify-content: center;
font-weight: 500;
font-size: 32rpx;
color: #FF4767;
transition: all 0.2s;
&:active {
transform: scale(0.98);
background: #e63e5b;
}
}
</style>

View File

@ -0,0 +1,457 @@
<template>
<view class="page">
<custom-navbar title="订单核销详情" :showBack="true" backgroundColor="#F5F5F5" :show-headle="true" borderBottom="none">
</custom-navbar>
<scroll-view class="scroll-content" scroll-y="true">
<view class="page-header">
<image class="header-icon" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/be13b4f4-c0db-4f39-b9fc-0e69c13b72ee.png" mode="aspectFit"></image>
<view class="header-text-box">
<view class="header-title">工时订单</view>
<view class="header-sub">请确认核销订单信息</view>
</view>
</view>
<view class="card">
<view class="card-title">顾客信息</view>
<view class="customer-info">
<text>{{ orderData.customerName || '--' }}</text>
<text class="ml-10">{{ orderData.customerPhone || '--' }}</text>
</view>
</view>
<view class="card">
<view class="card-title">预约信息</view>
<view class="goods-block">
<image class="goods-img" :src="orderData.goodsImg" mode="aspectFill"></image>
<view class="goods-detail">
<view class="goods-top">
<text class="goods-name">{{ orderData.goodsName || '--' }}</text>
<text class="goods-quantity">x{{ orderData.goodsNum || 1 }}</text>
</view>
<view class="goods-price"><text class="money-symbol1">¥</text>{{ formatPrice(orderData.goodsPrice) }}</view>
</view>
</view>
<view class="price-row mt-10">
<text class="label">服务售价</text>
<view class="val-box">
<text class="old-price">¥{{ formatPrice(orderData.originalPrice) }}</text>
<text class="new-price">¥{{ formatPrice(orderData.actualPrice) }}</text>
</view>
</view>
<view class="price-row mt-15">
<text class="label">用户实付</text>
<text class="new-price">¥{{ formatPrice(orderData.payPrice) }}</text>
</view>
<view class="dashed-divider"></view>
<view class="settle-row">
<text class="settle-label">商家结算基数</text>
<text class="settle-val"><text class="money-symbol2">¥</text>{{ formatPrice(orderData.settlePrice) }}</text>
</view>
</view>
<view class="bottom-placeholder"></view>
</scroll-view>
<view class="bottom-btn-wrapper">
<view class="confirm-btn" @tap="confirmVerify" :class="{ 'btn-disabled': isVerifying }">
<text class="btn-text">{{ isVerifying ? '核销中...' : '确认核销' }}</text>
</view>
</view>
</view>
</template>
<script>
import request from "@/utils/request";
export default {
data() {
return {
statusBarHeight: 44,
orderData: {
orderId: '',
customerName: '',
customerPhone: '',
goodsImg: '',
goodsName: '',
goodsNum: 1,
goodsPrice: 0,
originalPrice: 0,
actualPrice: 0,
payPrice: 0,
settlePrice: 0
},
isVerifying: false
};
},
onLoad(options) {
const sysInfo = uni.getSystemInfoSync();
if (sysInfo.statusBarHeight) {
this.statusBarHeight = sysInfo.statusBarHeight;
}
if (options.data) {
try {
const parsedData = JSON.parse(decodeURIComponent(options.data));
this.mapOrderData(parsedData);
} catch (e) {
console.error('解析订单数据失败', e);
uni.showToast({ title: '订单数据异常', icon: 'none' });
}
} else {
// uni.showToast({ title: '', icon: 'none' });
console.log('未获取到订单信息');
}
},
methods: {
// /sj/poster/getOrderByCode data
mapOrderData(data) {
this.orderData = {
orderId: data.order_id || '',
customerName: data.user_name || '--',
customerPhone: data.user_phone || '--',
goodsImg: data.order_photo || 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/default_goods.png',
goodsName: data.order_title || '--',
goodsNum: data.order_num || 1,
goodsPrice: data.cost_money || 0,
originalPrice: data.line_money || 0,
actualPrice: data.cost_money || 0,
payPrice: data.pay_money || 0,
settlePrice: data.jiesuan_jine_yiju || 0
};
},
formatPrice(price) {
if (price === null || price === undefined) return '0.00';
const num = parseFloat(price);
if (isNaN(num)) return '0.00';
return num.toFixed(2);
},
goBack() {
uni.navigateBack();
},
confirmVerify() {
if (this.isVerifying) return;
if (!this.orderData.orderId) {
uni.showToast({ title: '订单ID缺失无法核销', icon: 'none' });
return;
}
uni.showModal({
title: '确认核销',
content: '确定要将此订单标记为已核销吗?',
success: (res) => {
if (res.confirm) {
this.doVerify();
}
}
});
},
doVerify() {
this.isVerifying = true;
uni.showLoading({ title: '核销中...', mask: true });
//
request.post('/sj/poster/useOrderServerCode', {
id: this.orderData.orderId
}).then(res => {
uni.hideLoading();
if (res.code === 200) {
uni.showToast({ title: '核销成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: res.msg || '核销失败,请重试', icon: 'none' });
this.isVerifying = false;
}
}).catch(err => {
uni.hideLoading();
console.error('核销请求异常', err);
uni.showToast({ title: '网络异常,核销失败', icon: 'none' });
this.isVerifying = false;
});
}
}
};
</script>
<style lang="scss" scoped>
.page {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #F5F5F5;
position: relative;
}
/* 自定义导航栏 */
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
background-color: #ffffff;
z-index: 10;
box-sizing: border-box;
}
.back-btn {
width: 60rpx;
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
}
.back-icon {
width: 18rpx;
height: 36rpx;
}
.nav-title {
font-size: 34rpx;
font-weight: 500;
color: #333333;
}
.right-placeholder {
width: 60rpx;
}
/* 可滚动内容区域 */
.scroll-content {
padding-top: 40rpx;
flex: 1;
padding-bottom: 20rpx;
box-sizing: border-box;
}
/* 页面头部:订单类型标识 */
.page-header {
display: flex;
flex-direction: row;
align-items: center;
padding: 40rpx 30rpx 10rpx;
.header-icon {
width: 99rpx;
height: 95rpx;
margin-right: 20rpx;
}
.header-text-box {
display: flex;
flex-direction: column;
.header-title {
font-weight: 500;
font-size: 36rpx;
color: #333333;
line-height: 50rpx;
margin-bottom: 12rpx;
}
.header-sub {
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 33rpx;
}
}
}
/* 卡片通用样式 */
.card {
background-color: #ffffff;
border-radius: 20rpx;
margin: 24rpx 30rpx;
padding: 20rpx;
box-shadow: none;
.card-title {
font-weight: 500;
font-size: 30rpx;
color: #333333;
line-height: 42rpx;
margin-bottom: 24rpx;
}
}
/* 顾客信息 */
.customer-info {
font-weight: 400;
font-size: 28rpx;
color: #666666;
line-height: 40rpx;
.ml-10 {
margin-left: 6rpx;
}
}
/* 商品基础信息块 */
.goods-block {
display: flex;
flex-direction: row;
margin-bottom: 30rpx;
.goods-img {
width: 120rpx;
height: 127rpx;
border-radius: 12rpx;
background-color: #f0f0f0;
margin-right: 20rpx;
flex-shrink: 0;
}
.goods-detail {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.goods-top {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
.goods-name {
font-weight: 500;
font-size: 30rpx;
color: #333333;
line-height: 42rpx;
max-width: 380rpx;
}
.goods-quantity {
font-weight: 400;
font-size: 28rpx;
color: #666666;
line-height: 40rpx;
}
}
.goods-price {
font-weight: 500;
font-size: 36rpx;
color: #333333;
line-height: 50rpx;
}
.money-symbol1 {
font-size: 24rpx;
}
}
}
/* 价格明细行 */
.price-row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
&.mt-10 { margin-top: 20rpx; }
&.mt-15 { margin-top: 30rpx; }
.label {
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 37rpx;
}
.val-box {
display: flex;
flex-direction: row;
align-items: baseline;
.old-price {
font-weight: 400;
font-size: 26rpx;
color: #999999;
line-height: 37rpx;
text-decoration: line-through;
margin-right: 16rpx;
}
}
.new-price {
font-weight: 400;
font-size: 26rpx;
color: #333333;
line-height: 37rpx;
}
}
/* 虚线分割线 */
.dashed-divider {
width: 100%;
height: 1px;
border-bottom: 2rpx solid #f5f5f5;
margin: 30rpx 0;
}
/* 商家结算基数栏 */
.settle-row {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: baseline;
.settle-label {
font-weight: 400;
font-size: 26rpx;
color: #333333;
line-height: 37rpx;
margin-right: 12rpx;
}
.settle-val {
font-weight: 500;
font-size: 40rpx;
color: #FF4767;
line-height: 56rpx;
}
.money-symbol2 {
font-size: 26rpx;
margin-right: 5rpx;
}
}
.bottom-placeholder {
height: 160rpx;
}
/* 底部按钮容器 */
.bottom-btn-wrapper {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #f5f5f5;
padding: 20rpx 40rpx 60rpx; //
}
.confirm-btn {
background-color: #FF4767;
height: 98rpx;
border-radius: 49rpx;
display: flex;
justify-content: center;
align-items: center;
transition: opacity 0.2s;
}
.btn-text {
font-size: 32rpx;
font-weight: 500;
color: #ffffff;
}
.btn-disabled {
opacity: 0.6;
}
</style>

View File

@ -2,6 +2,7 @@
<view class="verify-page">
<barcode
ref="barcode"
class="barcode-view"
autostart="true"
flash="false"
@ -51,6 +52,13 @@ export default {
this.statusBarHeight = sysInfo.statusBarHeight;
}
},
onShow() {
// 从失败页退回来时,确保开关打开,并重新唤醒底层的扫码引擎
this.isProcessing = false;
if (this.$refs.barcode) {
this.$refs.barcode.start(); // 重新开始扫描
}
},
methods: {
goBack() {
uni.navigateBack();
@ -84,21 +92,17 @@ export default {
uni.navigateTo({
url: `/pages/shop/verify/verify-order-detail?data=${orderDataStr}`
});
// 延迟重置防抖,避免重复扫码跳转
setTimeout(() => { this.isProcessing = false; }, 1000);
} else {
// 如果无效,立即退出页面回首页
uni.showToast({ title: result.msg, icon: 'none' });
// 延迟 500ms 让用户看到 Toast然后自动退回主页
setTimeout(() => {
uni.navigateBack({ delta: 1 });
}, 500);
// 失败直接跳 fail 页
this.isProcessing = false; // 必须马上重置,保证退回该页时能继续扫
uni.navigateTo({ url: '/pages/shop/verify/verify-fail' });
}
}).catch((err) => {
uni.hideLoading();
uni.showToast({ title: '请求失败,退出重试', icon: 'none' });
setTimeout(() => {
uni.navigateBack({ delta: 1 });
}, 800);
this.isProcessing = false;
uni.navigateTo({ url: '/pages/shop/verify/verify-fail' });
});
},