weipengfei 5810d2bf3f 回退
2024-06-26 14:23:07 +08:00

786 lines
23 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.

<script setup>
import { ref, watch, nextTick, computed, onMounted, onUnmounted } from "vue";
import { orderCreateApi, orderStatusApi, orderPayApi, storeOrderCheckSmsApi } from "@/api/store.js";
import { ElMessage } from "element-plus";
import { audioplay } from "@/utils/audio.js";
import mitt from "@/utils/mitt.js";
import {
storeOrderPrintApi
} from "@/api/store.js";
import { useUserStore } from "@/store/user.js";
const drawer = ref(false);
const active = ref(1);
const input = ref("");
const codeRef = ref("");
const userStore = useUserStore();
const minMoney = ref(0) //最小起购金额
const onPrint = (id) => {
storeOrderPrintApi({
id: id,
}).then(res => {
mitt.emit('letPrintReceipt', res.data);
})
}
const cancelClick = () => {
beforeClose();
};
const open = () => {
nextTick(() => {
setTimeout(() => {
loading.value = false;
input.value = "";
reLoad.value = true;
codeRef.value?.focus();
changeActive(active.value);
}, 300);
});
};
const changeActive = (e) => {
active.value = e;
if (active.value == 2) {
// 添加键盘事件监听器
window.addEventListener("keydown", keyboard);
} else {
window.removeEventListener("keydown", keyboard);
nextTick(() => {
input.value = "";
codeRef.value?.focus();
});
}
};
const form = ref({});
const cart_id = ref([]);
const uid = ref('');
const isRePay = ref(false);
const setForm = (e) => {
form.value = e.data;
cart_id.value = e.cart_id;
uid.value = e.uid;
console.log('选择了用户==', uid.value || '游客');
isRePay.value = e.isRePay || false;
};
const setRePay = (e) => {
form.value.pay_price = e.price;
order_id.value = e.order_id;
};
const emit = defineEmits(["paySuccess"]);
const reLoad = ref(false);
const numList = ref([
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"00",
".",
]);
let timecount = 0; //刷新间隔
const regexWechat = /^(10|11|12|13|14|15)\d{16}$/; //微信条码正则 10-15开头18位
const regexPay = /^(25|26|27|28|29|30)\d{14,22}$/; //支付宝条码正则 25-30开头16-24位
const order_id = ref("");
// 支付
const handleEnter = () => {
// if (form.value.pay_price < minMoney.value) return ElMessage.error(`起购金额为${minMoney.value}元`)
loading.value = true;
codeRef.value.blur();
if (isRePay.value) orderPay();
else {
let pay_type;
if (regexWechat.test(input.value)) pay_type = "9"; // 微信
else if (regexPay.test(input.value)) pay_type = "13"; // 支付宝
else {
loading.value = false;
input.value = "";
codeRef.value.focus();
console.log("=====", 22);
return ElMessage.error("请输入正确的支付码");
}
orderCreateApi({
key: form.value.key,
cart_id: cart_id.value,
pay_type: pay_type,
auth_code: input.value,
uid: uid.value
})
.then((res) => {
if (res.data.out_trade_no && res.msg == "支付成功") {
drawer.value = false;
ElMessage({
message: "支付成功",
type: "success",
});
// if(res.data.message) audioplay(res.data.message);
beforeClose(res.data);
onPrint(res.data.id);
} else {
if (res.msg == "用户支付中" && res.code == 1) {
ElMessage.warning(res.msg);
mitt.on("pay_success", (e) => {
ElMessage({
message: "支付成功",
type: "success",
});
onPrint(res.data.id);
setTimeout(() => {
mitt.off("pay_success");
}, 200);
drawer.value = false;
beforeClose(e);
});
}
}
})
.catch((err) => {
loading.value = false;
nextTick(() => {
codeRef.value?.focus();
});
});
}
};
const orderPay = () => {
let query;
let pay_type = 17;
if (active.value == 1) {
if (regexWechat.test(input.value)) pay_type = "9"; // 微信
else if (regexPay.test(input.value)) pay_type = "13"; // 支付宝
else {
loading.value = false;
input.value = "";
codeRef.value.focus();
return ElMessage.error("请输入正确的支付码");
}
}
orderPayApi({
order_id: form.value.order_id,
pay_type: pay_type,
auth_code: input.value,
uid: uid.value
}).then((res) => {
if (res.msg?.includes('成功')) {
drawer.value = false;
ElMessage({
message: "支付成功",
type: "success",
});
onPrint(res.data.id);
// if(res.data.message) audioplay(res.data.message);
beforeClose();
} else {
if (res.msg == "用户支付中" && res.code == 1) {
ElMessage.warning(res.msg);
mitt.on("pay_success", (e) => {
ElMessage({
message: "支付成功",
type: "success",
});
onPrint(res.data.id);
setTimeout(() => {
mitt.off("pay_success");
}, 200);
drawer.value = false;
beforeClose(e);
});
}
}
})
.catch((err) => {
input.value = "";
loading.value = false;
nextTick(() => {
codeRef.value?.focus();
});
});
};
const count = ref(0); // 累计请求3次, 如果3次都失败, 则只能重新支付
const getOrderStatus = (id) => {
if (!id) return;
count.value++;
timecount += 5000;
orderStatusApi({
order_sn: id,
})
.then((res) => {
if (res.data.trade_state == "SUCCESS") {
ElMessage({
message: res.message,
type: "success",
});
// if(res.data.message) audioplay(res.data.message);
beforeClose();
} else {
ElMessage({
message:
res.data.trade_state == "USERPAYING"
? "用户正在支付中"
: res.message,
type: "error",
});
input.value = "";
loading.value = false;
nextTick(() => {
codeRef.value?.focus();
});
}
})
.catch((err) => {
if (reLoad.value && count.value < 3)
setTimeout(
() => {
getOrderStatus(id);
},
15000 - timecount > 0 ? 15000 - timecount : 0
);
else {
input.value = "";
loading.value = false;
nextTick(() => {
codeRef.value?.focus();
});
}
});
};
const beforeClose = (data) => {
try {
window.removeEventListener("keydown", keyboard);
reLoad.value = false;
loading.value = false;
input.value = "";
collection.value = "";
collectionArray.value = [];
codeRef.value?.blur();
emit("paySuccess", data);
drawer.value = false;
} catch (error) {
}
};
const loading = ref(false);
defineExpose({
drawer,
setForm,
setRePay,
beforeClose,
});
const collectionArray = ref([]);
const collection = ref(""); //输入的金额
const changePrice = computed(() => {
// 找零
if (+collection.value > 0) {
return (+collection.value - form.value.pay_price).toFixed(2);
}
return -1;
});
const defaultcalc = ref(false);
//清除计算机输入的数字
const delNum = (type) => {
if (type === -1) {
collectionArray.value = [];
} else {
collectionArray.value.pop();
}
collection.value = collectionArray.value.length
? collectionArray.value.join("")
: 0;
};
//输入实际收款金额
const numTap = (item) => {
if (defaultcalc.value === false) {
collection.value = "";
defaultcalc.value = true;
}
let x = String(collection.value).indexOf(".") + 1;
let y = String(collection.value).length - x;
console.log(x, y);
if (x === 0 || y < 2) {
if (collectionArray.value.join("") <= 9999999) {
collectionArray.value.push(item);
}
collection.value =
collectionArray.value.join("") > 99999999
? 99999999
: collectionArray.value.join("");
}
};
// 现金结算
const cashBnt = () => {
// if (form.value.pay_price < minMoney.value) return ElMessage.error(`起购金额为${minMoney.value}元`)
if (
changePrice.value === "" ||
changePrice.value === null ||
changePrice.value === undefined ||
+collection.value < +form.value.pay_price
)
return ElMessage.error("收款金额应该大于等于应收金额");
if (isRePay.value) orderPay();
else
orderCreateApi({
cart_id: cart_id.value,
pay_type: "17", //现金支付 17
uid: uid.value
})
.then((res) => {
drawer.value = false;
ElMessage({
message: res.msg,
type: "success",
});
onPrint(res.data.id);
changeActive(1);
beforeClose();
})
.catch((err) => {
loading.value = false;
});
};
// 监听键盘函数
const keyboard = (event) => {
let e = event || window.event;
let key = e.keyCode;
if (key == 37) return changeActive(2);
if (key == 120) return mitt.emit("F9");
if (key == 27) return beforeClose();
event.stopPropagation(); // 阻止事件冒泡传递
event.preventDefault(); // 阻止默认事件原有功能
switch (key) {
case 96:
case 48:
numTap(0);
break;
case 97:
case 49:
numTap(1);
break;
case 98:
case 50:
numTap(2);
break;
case 99:
case 51:
numTap(3);
break;
case 100:
case 52:
numTap(4);
break;
case 101:
case 53:
numTap(5);
break;
case 102:
case 54:
numTap(6);
break;
case 103:
case 55:
numTap(7);
break;
case 104:
case 56:
numTap(8);
break;
case 105:
case 57:
numTap(9);
break;
case 110:
numTap(".");
break;
case 190:
numTap(".");
break;
case 8:
delNum();
break;
case 13:
cashBnt();
break;
}
};
const getSms = () => {
// if (form.value.pay_price < minMoney.value && active.value === 3) return ElMessage.error(`起购金额为${minMoney.value}元`)
if (!uid.value) return ElMessage.error('请先选择用户');
let type = 1; // 采购款支付
if (active.value == 4) type = 2; //礼品券兑换
storeOrderCheckSmsApi({
cart_id: cart_id.value,
uid: uid.value,
type: type
}).then(res => {
ElMessage({
message: '发送成功',
type: "success",
});
})
}
const smsCode = ref('');
// 提交验证码/支付
const handlecodeEnter = () => {
// if (form.value.pay_price < minMoney.value && active.value === 3) return ElMessage.error(`起购金额为${minMoney.value}元`)
if (!uid.value) return ElMessage.error('请先选择用户');
let pay_type = 18; // 采购款支付
if (active.value == 4) pay_type = 19; //礼品券兑换
orderCreateApi({
pay_type: pay_type,
sms_code: smsCode.value,
cart_id: cart_id.value,
uid: uid.value
}).then(res => {
drawer.value = false;
ElMessage({
message: res.msg,
type: "success",
});
onPrint(res.data.id);
changeActive(1);
beforeClose();
})
}
// 条码输入框是否聚焦
const isFocus = ref(false);
// 键盘事件
const aleft = () => {
if (!drawer.value || (isFocus.value && input.value.length > 0)) return;
if (active.value != 1) return changeActive(active.value - 1);
};
const aright = () => {
if (!drawer.value || (isFocus.value && input.value.length > 0)) return;
if (active.value != 4) return changeActive(active.value + 1);
};
onMounted(() => {
mitt.on("left", aleft);
mitt.on("right", aright);
});
onUnmounted(() => {
mitt.off("left", aleft);
mitt.off("right", aright);
});
</script>
<template>
<el-drawer size="60rem" v-model="drawer" direction="rtl" @open="open" :before-close="beforeClose">
<template #header>
<h4>选择支付方式</h4>
</template>
<template #default>
<div class="dra-body">
<div class="header">
<div class="left" :class="{ active: active == 1 }" @click="changeActive(1)">
微信/支付宝
</div>
<div class="center" :class="{ active: active == 2 }" @click="changeActive(2)">
现金收款
</div>
<div class="center" style="border-left: none;" :class="{ active: active == 3 }" @click="changeActive(3)">
采购款
</div>
<div class="right" :class="{ active: active == 4 }" @click="changeActive(4)">
礼品券兑换
</div>
</div>
<div>
<div v-if="form.activities == 1 && active != 4" style="display: inline-block;margin-right: 20px">
<div style="display: inline-block;margin-right: 20px">
<div style="color: #999;padding: 2rem 0 0.3rem 0">原价:</div>
<div style="color: #f5222d; padding-bottom: 2rem">
¥<span style="font-size: 1.6rem">{{ form.original_price }}</span>
</div>
</div>
<div style="display: inline-block;">
<div style="color: #999;padding: 2rem 0 0.3rem 0">活动折扣:
</div>
<div style="color: #f5222d; padding-bottom: 2rem">
{{ form.activity }}¥<span style="font-size: 1.6rem">{{ form.activity_price }}</span>
</div>
</div>
</div>
<div style="display: inline-block ">
<div style="color: #999; padding: 2rem 0 0.3rem 0">应收金额():</div>
<div style="color: #f5222d; padding-bottom: 2rem">
¥<span style="font-size: 1.6rem" v-if="active==2 && form.activities == 1">{{ Math.ceil(form.original_price - form.activity_price).toFixed(2) }}</span>
<span style="font-size: 1.6rem" v-else>{{ active == 4 ? form.original_price : form.pay_price }}</span>
</div>
</div>
</div>
<div v-loading="loading" element-loading-text="支付中" class="card1" v-if="active == 1">
<el-input ref="codeRef" v-model="input" autofocus class="code-input" placeholder="请点击输入框聚焦扫码或输入编码号"
@keyup.enter="handleEnter" @focus="isFocus = true" @blur="isFocus = false" />
<div class="tips"></div>
</div>
<div class="card2" v-else-if="active == 2">
<div class="drawer-body">
<div class="counter">
<div class="received">
<span v-if="collection">{{ collection }}</span>
<span v-else style="font-size: 1rem; color: #999">按下键盘输入客户支付金额</span>
</div>
<div class="balance" v-if="changePrice >= 0">
<div>
需找零()<span class="money">{{ changePrice }}</span>
</div>
<div class="tips">按回车(Enter)确认支付</div>
</div>
<div class="balance" v-else>
<div>不够找零, 请支付更多金额</div>
<div class="tips">按下小键盘输入金额</div>
</div>
<div class="keypad">
<div class="left">
<el-button v-for="item in numList" :key="item" @click="numTap(item)">{{
item
}}
</el-button>
</div>
<div class="right">
<el-button @click="delNum">
<el-icon>
<Delete />
</el-icon>
</el-button>
<el-button @click="delNum(-1)">C</el-button>
<el-button class="enter" :class="{ 'enter-disable': +collection < +form.pay_price }"
:disabled="+collection < +form.pay_price" @click="cashBnt">
确认
</el-button>
</div>
</div>
</div>
</div>
</div>
<div class="card3" v-else-if="active == 3 || active == 4">
<div class="codes">
<el-input v-model="smsCode" autofocus class="code-input" placeholder="请输入验证码"
@keyup.enter="handlecodeEnter" @focus="isFocus = true" @blur="isFocus = false" />
<el-button type="primary" @click="getSms" class="get-code-btn">获取验证码</el-button>
</div>
<el-button type="primary" @click="handlecodeEnter" class="code-pay">确认支付</el-button>
<!-- <div class="tips"></div> -->
</div>
</div>
</template>
<template #footer>
<div style="width: 100%; display: flex; justify-content: center">
<el-button class="cancel-btn" @click="cancelClick">取消收款</el-button>
</div>
</template>
</el-drawer>
</template>
<style lang="scss" scoped>
.dra-body {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
.header {
width: 30rem;
display: flex;
&>div {
flex: 1;
border: 1px solid #ccc;
text-align: center;
padding: 0.6rem 0;
cursor: pointer;
}
.left {
border-right: none;
border-radius: 5rem 0 0 5rem;
}
.right {
border-left: none;
border-radius: 0 5rem 5rem 0;
}
.active {
background-color: #1890ff;
color: #fff;
transition: 300ms;
border-color: #1890ff;
}
}
.card1 {
.code-input {
width: 100%;
height: 3rem;
font-size: 1.2rem;
}
.tips {
width: 38rem;
height: 16rem;
background: url("@/assets/pay.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
.card3 {
.codes {
width: 38rem;
display: flex;
align-items: center;
.code-input {
flex: 1;
height: 3rem;
font-size: 1.2rem;
}
.get-code-btn {
height: 3rem;
margin-left: 1rem;
}
}
.code-pay {
margin-top: 4rem;
width: 100%;
height: 3rem;
border-radius: 3rem;
}
}
}
.cancel-btn {
width: 60%;
border-color: #1890ff;
color: #1890ff;
border-radius: 5rem;
height: 3rem;
font-size: 1.2rem;
}
.drawer-body {
width: 100%;
overflow-x: hidden;
}
.counter {
padding: 1.25rem;
border-radius: 1.25rem;
background-color: #f3f9ff;
.received {
height: 3rem;
padding: 0 1.25rem;
border: 1px solid #1890ff;
box-shadow: 0 0 0.18rem #1890ff;
border-radius: 0.5rem;
background-color: #ffffff;
font-size: 1.62rem;
line-height: 3rem;
color: #333;
}
.balance {
width: 100%;
box-sizing: border-box;
padding: 1.12rem 0 1.12rem 0.625rem;
text-align: start;
font-size: 0.95rem;
color: #303133;
display: flex;
justify-content: space-between;
.money {
color: #ff4a00;
}
.tips {
font-size: 0.8rem;
color: #999;
}
}
.keypad {
display: grid;
grid-template-columns: auto auto auto auto;
grid-gap: 0.625rem;
.left {
grid-column-end: span 3;
display: grid;
grid-template-columns: auto auto auto;
grid-gap: 0.625rem;
}
.right {
display: grid;
grid-template-columns: auto;
grid-gap: 0.625rem;
}
.el-button {
height: 3.875rem;
width: 8.125rem;
margin: 0 !important;
border: 0;
border-radius: 0.5rem;
font-weight: 500;
font-size: 1.75rem !important;
line-height: 3.87rem;
color: #1890ff;
&:focus {
box-shadow: none;
}
}
.enter {
grid-row-end: span 4;
height: 8.37rem;
line-height: 8.37rem;
background-color: #1890ff;
font-weight: 500;
font-size: 1.35rem !important;
color: #ffffff;
position: relative;
}
.enter-disable {
background-color: #ccc;
}
}
}
</style>