Files
cashier_admin_app/pagesOrder/pay-order/pay-order.vue

867 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="bg-gray min-page u-p-30 u-font-28">
<view class="u-p-t-60 u-p-b-60 u-text-center">
<template v-if="order.amount!=payPrice">
<view class="u-font-32 ">
<text class="price-fuhao"></text>
<!-- <text class="font-bold price">{{discount.currentPrice?discount.currentPrice:order.amount}}</text> -->
<text class="font-bold price">{{payPrice}}</text>
</view>
<view class="u-m-t-10 color-999 old-price">
<text class=""></text>
<text class=" ">{{order.amount}}</text>
</view>
<view class="u-m-t-10 u-flex u-row-center color-main">
<view @click="discountShow">修改</view>
</view>
</template>
<template v-else>
<view class="u-font-32 ">
<text class="price-fuhao"></text>
<text class="font-bold price">{{order.amount}}</text>
</view>
<view class="u-m-t-10 u-flex u-row-center color-main">
<view @click="discountShow">修改</view>
</view>
</template>
</view>
<view class="content bg-fff border-r-12">
<view class=" u-p-t-30 u-p-l-26 u-p-r-26 card top u-m-t-30">
<view class="border-bottom-dashed u-p-b-30">
<view class="u-flex u-p-l-24 u-p-r-24 u-row-between " @click="toQuan">
<view>优惠券</view>
<view class="color-999 u-flex u-col-center">
<text>选择优惠券</text>
<view class="u-flex u-col-center">
<uni-icons type="right" color="#999"></uni-icons>
</view>
</view>
</view>
<view class="u-m-t-24" v-if="pays.quan.length>0">
<view class="u-flex u-p-l-24 u-p-r-24 u-m-t-24 u-row-between "
v-for="(item,index) in pays.quan" :key="index">
<view class="u-flex">
<view class="hui"></view>
<view class="u-m-l-18">{{item.name}}</view>
<view class="u-m-l-18 color-999">x{{item.num}}</view>
</view>
<view class="u-flex">
<view class="color-red">
-{{item.discountAmount}}
</view>
<view class="u-m-l-12" @click="delQuan(index)">
<up-icon :size="16" name="minus-circle-fill" color="rgb(255, 0, 0)"></up-icon>
</view>
</view>
</view>
</view>
</view>
<view class="border-bottom u-p-b-30" v-if="(discount.price&&discount.currentPrice!=order.amount)||accountPoints.sel">
<view class="u-flex u-p-l-24 u-p-r-24 u-row-between u-p-t-30 "
v-if="discount.price&&discount.currentPrice!=order.amount">
<view>服务员改价</view>
<view class=" u-flex u-col-center">
<text style="color: rgb(255, 95, 46);">-{{to2(order.amount- discount.currentPrice)}}</text>
</view>
</view>
<view class="u-flex u-p-l-24 u-p-r-24 u-row-between u-p-t-30 "
v-if="accountPoints.price&&accountPoints.sel">
<view>积分抵扣</view>
<view class=" u-flex u-col-center">
<text style="color: rgb(255, 95, 46);">-{{to2(accountPoints.price)}}</text>
</view>
</view>
</view>
</view>
<view class="bg-fff border-r-12 ">
<view class="u-p-t-30 u-p-l-50 u-p-r-50 card bottom">
<my-tabs :list="pays.list" v-model="pays.selIndex"></my-tabs>
<template v-if="pays.selIndex==0">
<view class="list">
<view class="item" @click="changePayType(index,item)" :class="{disabled:item.disabled}"
v-for="(item,index) in pays.payTypes.list" :key="index">
<view class="u-flex u-row-between u-p-t-30 u-p-b-30 border-bottom">
<view class="u-flex">
<image class="icon" :src="item.icon" mode=""></image>
<text class="u-m-l-10 no-wrap">{{item.payName}}</text>
</view>
<view class="u-flex color-999 u-font-24">
<view class="u-m-r-20" v-if="item.payType=='vipPay'&&user.id">
<view>
<text>会员</text>
<text class="u-m-r-4">{{user.telephone||user.nickName}}</text>
</view>
<view>
<text>余额</text>
<text>{{user.amount||'0'}}</text>
</view>
<!-- <view>
<text>积分</text>
<text>{{user.accountPoints||'0'}}</text>
</view> -->
</view>
<view :class="{op3:item.disabled}">
<my-radio @click="changePayType(index,item)"
:modelValue="index==pays.payTypes.selIndex">
</my-radio>
</view>
</view>
</view>
</view>
</view>
<view class="border-bottom-dashed "></view>
<view class="u-flex u-row-between u-p-t-24" v-if="user.id" @click="changeAccountPoints">
<view class="u-flex ">
<view class="">积分抵扣</view>
<view class="color-999 u-m-l-10">
<text>(</text>
<text>{{user.accountPoints||'0'}}</text>
<text>)</text>
</view>
<!-- <view><text class="color-red font-bold">{{accountPoints.price}}</text></view> -->
</view>
<view class="u-flex">
<view class="u-flex">
<view><text>{{accountPoints.num}}</text></view>
<view v-if="accountPoints.calcRes.usable" @click.stop="refPointsOpen">
<up-icon name="edit-pen" size="16" color="#999"></up-icon>
</view>
</view>
<view class="u-m-l-32 u-relative" v-if="accountPoints.calcRes.usable">
<view class="u-absolute position-all"></view>
<my-radio :modelValue="accountPoints.sel">
</my-radio>
</view>
</view>
</view>
<view class="color-999 u-font-24 u-m-t-16">
<view class="" v-if="accountPoints.calcRes.unusableReason">
<text class="color-red">*</text>
<text>{{accountPoints.calcRes.unusableReason}}</text>
</view>
<view class="" v-if="accountPoints.calcRes.usable">
<text class="color-red">*</text>
<text class=""
v-if="accountPoints.calcRes.equivalentPoints">100积分等于{{to2(accountPoints.calcRes.equivalentPoints*100)}},</text>
<text>
最大抵扣积分{{accountPoints.calcRes.maxUsablePoints}}
</text>
<text>,
最小抵扣积分0
</text>
</view>
</view>
<view class="u-m-t-60 u-p-b-30">
<my-button @click="payOrderClick">确认付款</my-button>
</view>
</template>
<template v-if="pays.selIndex==1">
<view class="u-font-32 u-m-t-40 u-text-center">请让顾客使用微信/支付宝扫码</view>
<view class="u-flex u-row-center u-m-t-40">
<up-qrcode cid="code" :size="140" :val="payCodeUrl"></up-qrcode>
</view>
</template>
</view>
<!-- 二维码支付扫码 -->
<template v-if="pays.selIndex==1">
<view class="card border-bottom top u-m-t-32">
</view>
<view class="bg-fff card bottom border-r-12 u-p-32">
<view class="font-bold u-font-32 u-text-center">
{{payPrice}}</view>
<view class="u-flex u-row-center u-m-t-24">
<template v-if="order.status=='unpaid'">
<up-loading-icon size="14" text="等待支付"></up-loading-icon>
</template>
<template v-if="order.status=='closed'">
<view class="u-flex pay-success">
<up-icon color="#5CBB6F" name="checkmark-circle-fill"></up-icon>
<view class="u-m-l-6">支付成功</view>
</view>
</template>
</view>
</view>
</template>
</view>
</view>
<edit-discount @confirm="editDiscountConfirm" title="优惠金额" :ref="setModel" name="editMoney"
:price="order.amount"></edit-discount>
<up-modal :title="modal.title" :content="modal.content" :show="modal.show" :confirmText="modal.confirmText"
:cancelText="modal.cancelText" showCancelButton closeOnClickOverlay @confirm="confirmModelConfirm"
@cancel="confirmModelCancel" @close="confirmModelCancel" width="300px" />
<edit-accountPoints @confirm="pointsConfirm" :price="accountPoints.num" :accountPoints="accountPoints"
ref="refPoints"></edit-accountPoints>
</view>
</template>
<script setup>
import {
reactive,
onMounted,
watch,
ref,
onBeforeUnmount,
computed
} from 'vue';
import {
onLoad,
onBackPress,
onShow
} from '@dcloudio/uni-app'
import go from '@/commons/utils/go.js'
import * as Api from '@/http/yskApi/Instead.js'
import {
queryAllShopUser
} from '@/http/yskApi/shop-user.js'
import {
hasPermission
} from '@/commons/utils/hasPermission.js'
import * as orderApi from '@/http/yskApi/order.js'
import infoBox from '@/commons/utils/infoBox.js'
import editDiscount from '@/components/my-components/edit-discount.vue'
import editAccountPoints from './components/edit-accountPoints.vue'
import {
returnGoodsPayPriceMap,
returnProCoupStartIndex,
returnProductCoupAllPrice,
returnProductCanUseNum
} from '../quan_util.js'
const modal = reactive({
title: '提示',
cancelText: '取消',
confirmText: '确认',
content: '',
key: 'cash',
show: false,
data: ''
})
function confirmModelCancel() {
modal.show=false
modal.key=''
modal.data=''
}
function cashConfirmShow() {
modal.content = '是否确认已现金收款' + payPrice.value
modal.key='cash'
modal.show=true
}
async function confirmModelConfirm() {
if (modal.key == 'cash') {
await pay()
setModalShow('cash', false)
}
}
//商品数量从0到n每一个对应的价格
let $goodsPayPriceMap = {}
const refPoints = ref(null)
function delQuan(i) {
pays.quan.splice(i, 1)
}
function refPointsOpen() {
if (!accountPoints.calcRes.usable && accountPoints.sel) {
return
}
refPoints.value.open()
}
const accountPoints = reactive({
sel: false,
num: 0,
calcRes: {
usable: false,
unusableReason: '',
minDeductionPoints: 0,
maxUsablePoints: 0
},
price: 0
})
function pointsConfirm(e) {
accountPoints.num = e
}
async function calcUsablePoints() {
if (!order.memberId) {
return
}
const res = await Api.$calcUsablePoints({
memberId: order.memberId,
orderAmount: pointCanDicountPrice.value
})
accountPoints.calcRes = res
accountPoints.num = res.maxUsablePoints
return res;
}
watch(() => accountPoints.sel, (newval) => {
if (newval) {
calcUsablePoints()
}
})
async function calcDeDuctionPoints() {
const res = await Api.$calcDeDuctionPoints({
memberId: order.memberId,
orderAmount: order.amount,
points: accountPoints.num
})
accountPoints.price = res
return res
}
watch(() => accountPoints.num, (newval) => {
if (!newval) {
accountPoints.price = 0
return
}
calcDeDuctionPoints()
})
function changeAccountPoints() {
if (!accountPoints.calcRes.usable) {
return
}
accountPoints.sel = !accountPoints.sel
if (!accountPoints.sel) {
accountPoints.num = 0
}
}
function toQuan() {
console.log(order);
if (!order.memberId) {
return infoBox.showToast('请先选择会员', 0.5).then(() => {
chooseUser()
})
}
go.to('PAGES_ORDER_QUAN', {
orderId: order.id,
memberId: order.memberId,
orderPrice: payPrice.value * 1 + coupAllPrice.value * 1
})
}
async function discountShow() {
const bol = await hasPermission('yun_xu_da_zhe')
if (bol) {
showModel('editMoney', true)
}
}
let option = {
isNowPay: false
}
let payFinish = ref(false)
onBackPress(() => {
uni.$emit('orderDetail:update')
console.log('onBackPress');
// uni.$emit('update:createOrderIndex')
// if (option.isNowPay&&!payFinish.value) {
// infoBox.showToast('先付费模式,请先结算订单')
// return true
// }
// return false
})
let timer = null
let user = ref({
amount: 0
});
function clear() {
clearInterval(timer)
timer = null
}
function to2(n) {
if (!n) {
return ''
}
return n.toFixed(2)
}
const pays = reactive({
list: ['扫码收款', '二维码收款'],
selIndex: 0,
payTypes: {
list: [],
selIndex: 0
},
quan: []
})
function chooseUser() {
go.to('PAGES_CHOOSE_USER')
}
//更新选择用户
function setUser(par) {
console.log(option);
const submitPar = {
tableId: order.tableId,
orderId: order.id,
masterId: order.masterId,
vipUserId: user.value.id ? user.value.id : '',
type: user.value.id ? 0 : 1 //0 设置 1 取消
}
Object.assign(submitPar, par)
return Api.$setUser(submitPar)
}
function watchChooseuser() {
uni.$off('choose-user')
uni.$on('choose-user', (data) => {
console.log(data);
setUser({
vipUserId: data.id ? data.id : '',
type: data.id ? 0 : 1 //0 设置 1 取消
}).then(res => {
user.value = data
order.memberId = data.id
init()
})
})
}
function watchChooseQuan() {
uni.$off('choose-quan')
uni.$on('choose-quan', (arr) => {
console.log(arr);
const manjianCoup = arr.filter(v => v.type == 1 && v.num >= 1)
let productCoup = arr.filter(v => v.type == 2)
console.log(productCoup);
//商品券分组
let coupMap = {}
for (let i in productCoup) {
const coup = productCoup[i]
if (coupMap.hasOwnProperty(coup.proId)) {
coupMap[coup.proId].push(coup)
} else {
coupMap[coup.proId] = [coup]
}
}
console.log(coupMap);
for (let key in coupMap) {
const arr = coupMap[key]
for (let i in arr) {
const coup = arr[i]
const proCoupStartIndex = returnProCoupStartIndex(arr, i)
console.log(proCoupStartIndex);
const coupUseNum = returnProductCanUseNum($goodsPayPriceMap[coup.proId], proCoupStartIndex,
coup.num)
const num = Math.min($goodsPayPriceMap[coup.proId].length, coupUseNum)
coup.num = num
coup.discountAmount = returnProductCoupAllPrice($goodsPayPriceMap[coup.proId],
proCoupStartIndex, num).toFixed(2)
}
}
productCoup = productCoup.filter(v => v.num >= 1)
console.log(productCoup);
pays.quan = [...manjianCoup, ...productCoup]
})
}
onShow(() => {
watchChooseuser()
watchChooseQuan()
})
watch(() => pays.selIndex, (newval) => {
clearInterval(timer)
if (newval) {
timer = setInterval(() => {
orderApi.tbOrderInfoDetail(order.orderId).then(res => {
order.status = res.status
if (res.status == 'closed') {
paySuccess()
}
})
}, 2000)
} else {
}
})
const models = new Map();
function setModel(el) {
if (el && el.$attrs['name']) {
models.set(el.$attrs['name'], el);
}
}
function showModel(key) {
const model = models.get(key)
model && model.open()
}
//打折相关数据
const discount = reactive({
discount: 100
})
function editDiscountConfirm(form) {
console.log(form);
Object.assign(discount, form)
getPayUrl()
}
async function getPayType() {
const payTypeList = await Api.$getPayType()
pays.payTypes.list = payTypeList.map(v => {
return {
...v,
disabled: false
}
})
}
function changePayType(i, item) {
if (item.disabled) {
return infoBox.showToast(item.payName + '不可用')
}
pays.payTypes.selIndex = i
if (item.payType == 'vipPay') {
chooseUser()
}
}
let payStatus = '';
//支付成功回调
function paySuccess() {
infoBox.showToast('支付成功')
payStatus = 'success'
setTimeout(() => {
// uni.$emit('orderDetail:update')
payFinish.value = true
uni.$emit('get:table')
uni.$emit('update:orderDetail')
uni.navigateBack({
delta: 1
})
}, 500)
}
function payOrderClick() {
const payType = pays.payTypes.list[pays.payTypes.selIndex].payType
console.log(payType);
if (payType == 'scanCode' || payType == 'deposit') {
return saomaPay()
}
if (payType == 'cash' && payPrice.value * 1 > 0) {
return cashConfirmShow()
}
payOrder()
}
const tipsMap = {
paying: '支付中',
success: '已支付成功'
}
async function payOrder() {
const payType = pays.payTypes.list[pays.payTypes.selIndex].payType
if (payType == 'vipPay' && user.value.amount * 1 < order.amount * 1) {
infoBox.showToast('余额不足')
return
}
if (payStatus) {
return infoBox.showToast(tipsMap[payStatus])
}
try {
payStatus = 'paying'
await Api.$payOrder({
tableId: order.tableId,
masterId: order.masterId,
orderId: order.id || order.orderId,
payType,
vipUserId: order.memberId,
discount: discount.discount / 100,
code: '',
pointsNum: accountPoints.sel ? accountPoints.num : 0,
userCouponInfos: pays.quan.map(v => {
return {
userCouponId: v.id,
num: v.num
}
})
})
paySuccess()
} catch (e) {
//TODO handle the exception
payStatus = ''
}
}
async function pay(par) {
const payType = pays.payTypes.list[pays.payTypes.selIndex].payType
payStatus = 'paying'
await Api.$payOrder({
tableId: order.tableId,
masterId: order.masterId,
orderId: order.id || order.orderId,
payType,
vipUserId: order.memberId,
discount: discount.discount / 100,
code: '',
pointsNum: accountPoints.sel ? accountPoints.num : 0,
userCouponInfos: pays.quan.map(v => {
return {
userCouponId: v.id,
num: v.num
}
}),
...par
})
paySuccess()
}
const order = reactive({
amount: 0
})
function saomaPay() {
const item = pays.payTypes.list[pays.payTypes.selIndex]
uni.scanCode({
onlyFromCamera: true,
success: function(res) {
console.log('条码类型:' + res.scanType);
console.log('条码内容:' + res.result);
Api.$payOrder({
orderId: order.id || order.orderId,
payType: item.payType, //
discount: discount.discount / 100,
code: res.result,
tableId: order.tableId,
masterId: order.masterId,
vipUserId: order.memberId,
pointsNum: accountPoints.sel ? accountPoints.num : 0,
userCouponInfos: pays.quan.map(v => {
return {
userCouponId: v.id,
num: v.num
}
})
}).then(res => {
console.log(res);
paySuccess()
})
}
});
}
watch(() => pays.payTypes.selIndex, (newval) => {
// const item = pays.payTypes.list[newval]
// if (item.payType == "vipPay") {
// return
// }
// if (item.payType == "deposit") {
// //储值卡支付
// return saomaPay('deposit')
// }
// if (item.payType == "scanCode") {
// //扫码支付
// return saomaPay('scanCode')
// }
})
let payCodeUrl = ref('')
async function init() {
const orderRes = await orderApi.tbOrderInfoDetail(order.orderId)
Object.assign(order, orderRes)
$goodsPayPriceMap = returnGoodsPayPriceMap(order.detailList)
console.log($goodsPayPriceMap);
if (orderRes.memberId) {
calcUsablePoints()
queryAllShopUser({
id: orderRes.memberId
}).then(res => {
if (res.content[0]) {
user.value = res.content[0]
}
})
}
}
function getPayUrl() {
orderApi.$getOrderPayUrl({
orderId: order.id,
payAmount: payPrice.value
}).then(res => {
payCodeUrl.value = res
})
}
const coupAllPrice = computed(() => {
return pays.quan.reduce((prve, cur) => {
return prve + cur.discountAmount * 1
}, 0)
})
const payPrice = computed(() => {
const discountPrice = discount.currentPrice ? discount.currentPrice : order.amount
const calcPrice = discountPrice - coupAllPrice.value - accountPoints.price * (accountPoints.sel ? 1 : 0)
return (calcPrice <= 0 ? 0 : calcPrice).toFixed(2)
})
watch(() => payPrice.value, (newval) => {
getPayUrl()
if (newval <= 0) {
const arr = ['cash', 'vipPay']
pays.payTypes.list.map(v => {
if (arr.includes(v.payType)) {
v.disabled = false
} else {
v.disabled = true
}
})
const index = pays.payTypes.list.findIndex(v => !v.disabled)
pays.payTypes.selIndex = index
} else {
pays.payTypes.list.map(v => {
v.disabled = false
})
}
})
const pointCanDicountPrice = computed(() => {
const discountPrice = discount.currentPrice ? discount.currentPrice : order.amount
const calcPrice = discountPrice - coupAllPrice.value
return (calcPrice <= 0 ? 0 : calcPrice).toFixed(2)
})
watch(() => pointCanDicountPrice.value, (newval) => {
calcUsablePoints()
})
onLoad(async (opt) => {
console.log(opt);
option = opt
Object.assign(order, opt)
getPayType()
init()
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount');
clear()
})
</script>
<style lang="scss" scoped>
$quan-color: #318AFE;
.op3 {
opacity: .3;
}
.hui {
// background-color: $quan-color;
background-image: linear-gradient(to right bottom, rgb(254, 103, 4), rgb(241, 50, 42));
padding: 4rpx 10rpx;
border-radius: 10rpx;
font-size: 24rpx;
color: #fff;
}
.box-shadow {
box-shadow: 0 0 5px #E5E5E5;
}
.pay-success {
color: #5CBB6F;
}
.icon {
width: 40rpx;
height: 40rpx;
}
.border-bottom-dashed {
border-bottom: 1px dashed #bbb;
}
.border-bottom {
border-color: rgb(240, 240, 240);
}
.list {
.item {
&.disabled {
color: #999;
}
}
.item:last-child {
.border-bottom {
border-bottom: none;
}
}
}
.old-price {
text-decoration: line-through;
}
.price-fuhao {
font-size: 24px;
}
.price {
font-size: 32px;
}
$dotSize: 20rpx;
$position: calc($dotSize / (-2));
.card {
position: relative;
&::after,
&:before {
content: '';
display: block;
position: absolute;
background-color: #F9F9F9;
width: $dotSize;
height: $dotSize;
border-radius: 50%;
}
&.top {
&::after {
right: $position;
bottom: $position;
}
&:before {
left: $position;
bottom: $position;
}
}
&.bottom {
&::after {
right: $position;
top: $position;
}
&:before {
left: $position;
top: $position;
}
}
}
</style>