feat 组合支付收银台

This commit is contained in:
xxm
2022-12-08 22:59:38 +08:00
parent cc92b65ba9
commit c55fc4e223
6 changed files with 236 additions and 228 deletions

View File

@@ -23,6 +23,16 @@ export function createAggregatePay(obj) {
})
}
/**
* 组合支付
*/
export function combinationPay (obj) {
return defHttp.post({
url: '/cashier/combinationPay',
data: obj
})
}
/**
* 根据业务ID获取支付状态
*/

View File

@@ -0,0 +1,161 @@
<template>
<a-card :bordered="false">
<a-spin :spinning="loading">
<div>
<a-form ref="formRef" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="异步支付方式" name="payChannel">
<a-radio-group v-model:value="form.payChannel" :default-value="1" button-style="solid">
<a-radio-button v-for="o in payChannel" :value="o.code" :key="o.code"> {{ o.label }} </a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="订单编号" name="businessId">
<a-input v-model:value="form.businessId" @search="genOrderNo">
<template #addonAfter>
<a-button type="link" size="small" @click="genOrderNo"> 生成订单号 </a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="订单名称" name="title">
<a-input v-model:value="form.title" />
</a-form-item>
<a-form-item label="异步支付金额" name="asyncAmount">
<a-input-number :precision="2" v-model:value="form.asyncAmount" />
</a-form-item>
<a-form-item label="钱包支付" name="walletAmount">
<a-input-number :precision="2" v-model:value="form.walletAmount" />
<template #help>
<span>钱包余额{{ wallet.balance }}</span>
</template>
</a-form-item>
<a-form-item label="现金支付" name="cashAmount">
<a-input-number :precision="2" v-model:value="form.cashAmount" />
</a-form-item>
</a-form>
</div>
<div style="display: flex; justify-content: center">
<a-button type="primary" @click="pay"> 发起支付 </a-button>
</div>
</a-spin>
<!-- 扫码弹出窗口 -->
<cashier-qr-code ref="cashierQrCode" @cancel="handleCancel" />
</a-card>
</template>
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import { combinationPay, findStatusByBusinessId, findWalletByUser } from '/@/views/demo/payment/cashier/Cashier.api'
import { Voucher } from '/@/views/modules/payment/voucher/Voucher.api'
import { useMessage } from '/@/hooks/web/useMessage'
import { FormInstance } from 'ant-design-vue/lib/form'
import { useIntervalFn } from '@vueuse/core'
import { onMounted } from 'vue'
import CashierQrCode from './CashierQrCode.vue'
const { createMessage } = useMessage()
const formRef = $ref<FormInstance>()
const cashierQrCode = $ref<any>()
const labelCol = {
sm: { span: 7 },
}
const wrapperCol = {
sm: { span: 13 },
}
const payChannel = [
{ code: 1, label: '支付宝' },
{ code: 2, label: '微信' },
]
let loading = $ref(false)
let visible = $ref(false)
let wallet = $ref({ balance: 0 })
let voucher = $ref<Voucher>({})
let form = $ref({
payChannel: 1,
payWay: 4,
businessId: '',
title: '测试支付订单',
asyncAmount: null,
walletAmount: null,
cashAmount: null,
})
const rules = {
payChannel: [{ required: true, message: '不可为空' }],
businessId: [{ required: true, message: '不可为空' }],
title: [{ required: true, message: '不可为空' }],
payWay: [{ required: true, message: '不可为空' }],
}
// 检查支付状态
const { pause, resume } = useIntervalFn(
() => {
findStatusByBusinessId(form.businessId).then((res) => {
// 成功
if (res.data === 1) {
createMessage.success('支付成功')
handleCancel()
}
if ([2, 3].includes(res.data)) {
createMessage.error('支付失败')
handleCancel()
}
})
},
1000 * 3,
{ immediate: false },
)
onMounted(() => {
init()
})
function init() {
findWalletByUser().then(({ data }) => {
wallet = data
})
genOrderNo()
}
// 生成订单号
function genOrderNo() {
form.businessId = 'P' + new Date().getTime()
}
function pay() {
formRef?.validate().then(async () => {
loading = true
// 组装支付参数
const payModeList = [
{ payChannel: form.payChannel, payWay: form.payWay, amount: form.asyncAmount },
{ payChannel: 4, amount: form.cashAmount },
{ payChannel: 5, amount: form.walletAmount },
]
// 异步
const { data } = await combinationPay({
title: form.title,
businessId: form.businessId,
payModeList: payModeList,
}).finally(() => (loading = false))
// 同步还是异步支付
if (data.asyncPayMode) {
if (data.payChannel === 1) {
cashierQrCode.init(data.asyncPayInfo.payBody, '请使用支付宝"扫一扫"扫码支付')
} else {
cashierQrCode.init(data.asyncPayInfo.payBody, '请使用微信"扫一扫"扫码支付')
}
loading = false
resume()
} else {
createMessage.success('支付成功')
}
})
}
function handleCancel() {
cashierQrCode.handleClose()
loading = false
genOrderNo()
pause()
}
</script>
<style scoped></style>

View File

@@ -4,7 +4,7 @@
<div>
<a-form ref="formRef" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="支付方式" name="payChannel">
<a-radio-group v-model:value="form.payChannel" :default-value="1" button-style="solid">
<a-radio-group v-model:value="form.payChannel" button-style="solid">
<a-radio-button v-for="o in payChannel" :value="o.code" :key="o.code"> {{ o.name }} </a-radio-button>
</a-radio-group>
</a-form-item>
@@ -82,16 +82,14 @@
// 二维码支付方式
amount: 0.01,
})
const rules = computed(() => {
return {
payChannel: [{ required: true, message: '不可为空' }],
businessId: [{ required: true, message: '不可为空' }],
title: [{ required: true, message: '不可为空' }],
payWay: [{ required: true, message: '不可为空' }],
amount: [{ required: true, message: '不可为空' }],
voucherNo: [{ required: true, message: '不可为空' }],
}
})
const rules = {
payChannel: [{ required: true, message: '不可为空' }],
businessId: [{ required: true, message: '不可为空' }],
title: [{ required: true, message: '不可为空' }],
payWay: [{ required: true, message: '不可为空' }],
amount: [{ required: true, message: '不可为空' }],
voucherNo: [{ required: true, message: '不可为空' }],
}
// 检查支付状态
const { pause, resume } = useIntervalFn(
@@ -168,7 +166,4 @@
</script>
<style scoped>
.cashier {
display: flex;
}
</style>

View File

@@ -1,197 +0,0 @@
<template>
<!-- <a-card :bordered="false">-->
<!-- <a-spin :spinning="loading">-->
<!-- <div>-->
<!-- <div>-->
<!-- <a-form-model-->
<!-- ref="form"-->
<!-- :model="form"-->
<!-- :rules="rules"-->
<!-- :label-col="labelCol"-->
<!-- :wrapper-col="wrapperCol"-->
<!-- >-->
<!-- <a-form-model-item label="异步支付方式" prop="payChannel">-->
<!-- <a-radio-group v-model="form.payChannel" :default-value="1" button-style="solid">-->
<!-- <a-radio-button v-for="o in payChannel" :value="o.code" :key="o.code"> {{ o.name }} </a-radio-button>-->
<!-- </a-radio-group>-->
<!-- </a-form-model-item>-->
<!-- <a-form-model-item label="订单编号" prop="businessId">-->
<!-- <a-input-search v-model="form.businessId" @search="genOrderNo">-->
<!-- <template #enterButton>-->
<!-- <a-button>-->
<!-- 生成订单号-->
<!-- </a-button>-->
<!-- </template>-->
<!-- </a-input-search>-->
<!-- </a-form-model-item>-->
<!-- <a-form-model-item label="订单名称" prop="title">-->
<!-- <a-input v-model="form.title" />-->
<!-- </a-form-model-item>-->
<!-- <a-form-model-item label="异步支付金额" prop="asyncAmount">-->
<!-- <a-input-number :precision="2" v-model="form.asyncAmount" />-->
<!-- </a-form-model-item>-->
<!-- <a-form-model-item label="钱包支付" prop="walletAmount">-->
<!-- <a-input-number :precision="2" v-model="form.walletAmount" />-->
<!-- <span slot="help">钱包余额{{ wallet.balance }}</span>-->
<!-- </a-form-model-item>-->
<!-- <a-form-model-item label="现金支付" prop="cashAmount">-->
<!-- <a-input-number :precision="2" v-model="form.cashAmount" />-->
<!-- </a-form-model-item>-->
<!-- </a-form-model>-->
<!-- </div>-->
<!-- <div style="display: flex;justify-content: center">-->
<!-- <a-button type="primary" @click="pay">-->
<!-- 发起支付-->
<!-- </a-button>-->
<!-- </div>-->
<!-- </div>-->
<!-- </a-spin>-->
<!-- <a-modal-->
<!-- title="扫码支付"-->
<!-- :footer="null"-->
<!-- :width="300"-->
<!-- :visible="visible"-->
<!-- :maskClosable="false"-->
<!-- @cancel="handleCancel"-->
<!-- >-->
<!-- <a-spin :spinning="qrLoading">-->
<!-- <vue-qr-->
<!-- :size="250"-->
<!-- :margin="0"-->
<!-- :auto-color="true"-->
<!-- :dot-scale="1"-->
<!-- :text="payUrl" />-->
<!-- </a-spin>-->
<!-- </a-modal>-->
<!-- </a-card>-->
</template>
<!--<script>-->
<!--import VueQr from 'vue-qr'-->
<!--import { combinationPay } from '@/api/payment/cashier'-->
<!--import { findStatusByBusinessId } from '@/api/payment/payment'-->
<!--import { findByUser } from '@/api/payment/wallet'-->
<!--export default {-->
<!-- name: 'CombinationCashier',-->
<!-- components: {-->
<!-- VueQr-->
<!-- },-->
<!-- data () {-->
<!-- return {-->
<!-- labelCol: {-->
<!-- sm: { span: 7 }-->
<!-- },-->
<!-- payChannel: [-->
<!-- { code: 1, name: '支付宝' },-->
<!-- { code: 2, name: '微信' }-->
<!-- // { code: 3, name: '云闪付' }-->
<!-- ],-->
<!-- wrapperCol: {-->
<!-- sm: { span: 13 }-->
<!-- },-->
<!-- loading: false,-->
<!-- qrLoading: false,-->
<!-- visible: false,-->
<!-- title: '扫码支付',-->
<!-- wallet: {},-->
<!-- form: {-->
<!-- payChannel: 1,-->
<!-- payWay: 4,-->
<!-- businessId: '',-->
<!-- title: '测试支付订单',-->
<!-- asyncAmount: null,-->
<!-- walletAmount: null,-->
<!-- cashAmount: null-->
<!-- },-->
<!-- rules: {-->
<!-- payChannel: [{ required: true, message: '不可为空' }],-->
<!-- businessId: [{ required: true, message: '不可为空' }],-->
<!-- title: [{ required: true, message: '不可为空' }],-->
<!-- payWay: [{ required: true, message: '不可为空' }]-->
<!-- },-->
<!-- payUrl: '',-->
<!-- // 定时查询支付状态定时器-->
<!-- interval: null-->
<!-- }-->
<!-- },-->
<!-- methods: {-->
<!-- // 初始化-->
<!-- init () {-->
<!-- this.genOrderNo()-->
<!-- findByUser().then(res => {-->
<!-- this.wallet = res.data-->
<!-- })-->
<!-- },-->
<!-- // 生成订单号-->
<!-- genOrderNo () {-->
<!-- this.form.businessId = 'P' + new Date().getTime()-->
<!-- },-->
<!-- pay () {-->
<!-- this.$refs.form.validate(async valid => {-->
<!-- if (valid) {-->
<!-- this.loading = true-->
<!-- // 组装支付参数-->
<!-- const payModeList = []-->
<!-- // 异步-->
<!-- payModeList.push({ payChannel: this.form.payChannel, payWay: this.form.payWay, amount: this.form.asyncAmount })-->
<!-- payModeList.push({ payChannel: 4, amount: this.form.cashAmount })-->
<!-- payModeList.push({ payChannel: 5, amount: this.form.walletAmount })-->
<!-- const form = {-->
<!-- title: this.form.title,-->
<!-- businessId: this.form.businessId,-->
<!-- payModeList: payModeList-->
<!-- }-->
<!-- const { data } = await combinationPay(form)-->
<!-- // 同步还是异步支付-->
<!-- if (data.asyncPayMode) {-->
<!-- this.payUrl = data.asyncPayInfo.payBody-->
<!-- this.visible = true-->
<!-- this.loading = false-->
<!-- this.checkPayStatus()-->
<!-- } else {-->
<!-- this.$message.success('支付成功')-->
<!-- this.handleCancel()-->
<!-- }-->
<!-- } else {-->
<!-- return false-->
<!-- }-->
<!-- })-->
<!-- },-->
<!-- handleCancel () {-->
<!-- this.visible = false-->
<!-- this.loading = false-->
<!-- this.init()-->
<!-- this.payUrl = ''-->
<!-- clearInterval(this.interval)-->
<!-- this.interval = null-->
<!-- },-->
<!-- checkPayStatus () {-->
<!-- this.interval = setInterval(() => {-->
<!-- findStatusByBusinessId(this.form.businessId).then(res => {-->
<!-- // 成功-->
<!-- if (res.data === 1) {-->
<!-- this.$message.success('支付成功')-->
<!-- this.handleCancel()-->
<!-- }-->
<!-- if ([2, 3].includes(res.data)) {-->
<!-- this.$message.error('支付失败')-->
<!-- this.handleCancel()-->
<!-- }-->
<!-- })-->
<!-- }, 1000 * 3)-->
<!-- }-->
<!-- },-->
<!-- created () {-->
<!-- this.init()-->
<!-- },-->
<!-- destroyed () {-->
<!-- this.handleCancel()-->
<!-- }-->
<!--}-->
<!--</script>-->
<!--<style scoped>-->
<!--</style>-->

View File

@@ -27,31 +27,31 @@ export const get = (id) => {
*/
export interface OperateLog extends BaseEntity {
// 操作模块
title: string
title?: string
// 操作人员id
operateId: number
operateId?: number
// 操作人员账号
username: string
username?: string
// 业务类型
businessType: string
businessType?: string
// 请求方法
method: string
method?: string
// 请求方式
requestMethod: string
requestMethod?: string
// 请求url
operateUrl: string
operateUrl?: string
// 操作ip
operateIp: string
operateIp?: string
// 操作地点
operateLocation: string
operateLocation?: string
// 请求参数
operateParam: string
operateParam?: string
// 返回参数
operateReturn: string
operateReturn?: string
// 是否成功
success: boolean
success?: boolean
// 错误提示
errorMsg: string
errorMsg?: string
// 操作时间
operateTime: string
operateTime?: string
}

View File

@@ -1,8 +1,47 @@
<template>
<basic-modal v-bind="$attrs" :loading="confirmLoading" width="50%" title="查看" :visible="visible" @cancel="visible = false">
<description :column="2" :data="data" :schema="schema" />
<a-descriptions title="" :column="{ md: 2, sm: 1, xs: 1 }">
<a-descriptions-item label="操作人员账号">
{{ data.username }}
</a-descriptions-item>
<a-descriptions-item label="操作模块">
{{ data.title }}
</a-descriptions-item>
<a-descriptions-item label="业务类型">
{{ dictConvert('LogBusinessType', data.businessType) }}
</a-descriptions-item>
<a-descriptions-item label="请求方式">
{{ data.requestMethod }}
</a-descriptions-item>
<a-descriptions-item label="请求url">
{{ data.operateUrl }}
</a-descriptions-item>
<a-descriptions-item label="操作方法">
{{ data.method }}
</a-descriptions-item>
<a-descriptions-item label="操作ip">
{{ data.operateIp }}
</a-descriptions-item>
<a-descriptions-item label="操作状态">
{{ data.success ? '成功' : '失败' }}
</a-descriptions-item>
<a-descriptions-item label="提示消息">
{{ data.errorMsg }}
</a-descriptions-item>
<a-descriptions-item label="请求参数">
{{ data.operateParam }}
</a-descriptions-item>
<a-descriptions-item label="响应参数">
{{ data.operateReturn }}
</a-descriptions-item>
<a-descriptions-item label="操作时间">
{{ data.operateTime }}
</a-descriptions-item>
</a-descriptions>
<template #footer>
<a-button key="cancel" @click="visible = false">取消</a-button>
<a-space>
<a-button key="cancel" @click="visible=false">取消</a-button>
</a-space>
</template>
</basic-modal>
</template>
@@ -17,7 +56,7 @@
const { dictConvert } = useDict()
let data = $ref<OperateLog>()
let data = $ref<OperateLog>({})
let visible = $ref(false)
let confirmLoading = $ref(false)
let schema = [