mirror of
https://gitee.com/bootx/dax-pay-ui.git
synced 2025-09-03 19:07:02 +00:00
feat 组合支付收银台
This commit is contained in:
@@ -23,6 +23,16 @@ export function createAggregatePay(obj) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 组合支付
|
||||
*/
|
||||
export function combinationPay (obj) {
|
||||
return defHttp.post({
|
||||
url: '/cashier/combinationPay',
|
||||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务ID获取支付状态
|
||||
*/
|
||||
|
161
src/views/demo/payment/cashier/CombinationCashier.vue
Normal file
161
src/views/demo/payment/cashier/CombinationCashier.vue
Normal 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>
|
@@ -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>
|
||||
|
@@ -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>-->
|
@@ -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
|
||||
}
|
||||
|
@@ -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 = [
|
||||
|
Reference in New Issue
Block a user