feat 储值卡管理和结算台

This commit is contained in:
xxm1995
2023-07-07 14:54:46 +08:00
parent 068c575b6a
commit 1adc5bd35f
9 changed files with 209 additions and 32 deletions

View File

@@ -0,0 +1,43 @@
/**
* 储值卡常量
*/
export enum VoucherEnum {
/**
* 状态-正常
*/
STATUS_NORMAL = 'normal',
/**
* 状态-停用
*/
STATUS_FORBIDDEN = 'forbidden',
/**
* 储值卡日志-开通
*/
LOG_ACTIVE = 'active',
/**
* 储值卡日志-预冻结额度
*/
LOG_FREEZE_BALANCE = 'freeze',
/**
* 储值卡日志-扣减并解冻余额
*/
LOG_REDUCE_AND_UNFREEZE_BALANCE = 'reduceAndUnfreeze',
/**
* 储值卡日志-直接支付
*/
LOG_PAY = 'pay',
/**
* 储值卡日志-取消支付
*/
LOG_CLOSE_PAY = 'closePay',
/**
* 储值卡日志-退款到本卡中
*/
LOG_REFUND_SELF = 'refundSelf',
}

View File

@@ -18,15 +18,15 @@
<a-form-item label="订单名称" name="title">
<a-input v-model:value="form.title" />
</a-form-item>
<a-form-item label="异步支付金额" name="asyncAmount">
<a-form-item label="微信/支付金额" name="asyncAmount">
<a-input-number placeholder="请输入金额" :precision="2" v-model:value="form.asyncAmount" />
</a-form-item>
<!-- <a-form-item label="钱包支付" name="walletAmount">-->
<!-- <a-input-number placeholder="请输入金额" :precision="2" v-model:value="form.walletAmount" />-->
<!-- <template #help>-->
<!-- <span>钱包余额{{ wallet.balance }}</span>-->
<!-- </template>-->
<!-- </a-form-item>-->
<a-form-item label="钱包支付" name="walletAmount">
<a-input-number placeholder="请输入金额" :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 placeholder="请输入金额" :precision="2" v-model:value="form.cashAmount" />
</a-form-item>
@@ -43,18 +43,18 @@
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import { combinationPay, findStatusByBusinessId, findWalletByUser } from '/@/views/demo/payment/cashier/Cashier.api'
import { combinationPay, findStatusByBusinessId } 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'
import { Wallet } from '/src/views/modules/payment/wallet/Wallet.api'
import { payChannelEnum } from '/@/enums/payment/payChannelEnum'
import { payWayEnum } from '/@/enums/payment/payWayEnum'
import { findByParamKey } from '/@/api/common/Parameter'
import { PayStatus } from '/@/enums/payment/PayStatus'
import { findByUser as findWalletByUser, Wallet } from '/@/views/modules/payment/wallet/Wallet.api'
const { createMessage } = useMessage()
@@ -73,15 +73,15 @@
]
let loading = $ref(false)
let visible = $ref(false)
// let wallet = $ref<Wallet>({ balance: 0 })
let voucher = $ref<Voucher>({})
let wallet = $ref<Wallet>({ balance: 0 })
let form = $ref({
payChannel: payChannelEnum.ALI,
payWay: payWayEnum.QRCODE,
businessId: '',
title: '测试支付订单',
asyncAmount: null,
// walletAmount: null,
walletAmount: null,
cashAmount: null,
mchCode: '',
mchAppCode: '',
@@ -89,7 +89,7 @@
const rules = {
payChannel: [{ required: true, message: '支付通道不可为空' }],
businessId: [{ required: true, message: '业务ID不可为空' }],
title: [{ required: true, message: '标题不可为空' }],
title: [{ required: true, message: '金额不可=不可为空' }],
payWay: [{ required: true, message: '支付方式不可为空' }],
}
@@ -116,15 +116,22 @@
init()
})
/**
* 初始化钱包信息
*/
function initWallet() {
// 获取钱包
findWalletByUser().then((res) => {
wallet = res.data
})
}
/**
* 初始化数据
*/
async function init() {
// findWalletByUser().then(({ data }) => {
// wallet = data
// })
genOrderNo()
initWallet()
// 获取商户和应用编码
form.mchCode = (await findByParamKey('CashierMchCode')).data
form.mchAppCode = (await findByParamKey('CashierMchAppCode')).data
@@ -134,6 +141,9 @@
form.businessId = 'P' + new Date().getTime()
}
/**
* 支付
*/
function pay() {
formRef?.validate().then(async () => {
loading = true
@@ -141,7 +151,7 @@
const payWayList = [
{ payChannel: form.payChannel, payWay: form.payWay, amount: form.asyncAmount },
{ payChannel: payChannelEnum.CASH, payWay: payWayEnum.NORMAL, amount: form.cashAmount },
// { payChannel: 5, amount: form.walletAmount },
{ payChannel: payChannelEnum.WALLET, payWay: payWayEnum.NORMAL, amount: form.walletAmount },
]
// 异步
const { data } = await combinationPay({
@@ -161,15 +171,21 @@
loading = false
resume()
} else {
genOrderNo()
initWallet()
createMessage.success('支付成功')
}
})
}
/**
* 关闭
*/
function handleCancel() {
cashierQrCode.handleClose()
loading = false
genOrderNo()
initWallet()
pause()
}
</script>

View File

@@ -48,7 +48,7 @@
import { FormInstance } from 'ant-design-vue/lib/form'
import { useIntervalFn } from '@vueuse/core'
import { useMessage } from '/@/hooks/web/useMessage'
import { findByCardNo, Voucher } from '/@/views/modules/payment/voucher/Voucher.api'
import { getAndJudgeVoucher, Voucher } from '/@/views/modules/payment/voucher/Voucher.api'
import CashierQrCode from './CashierQrCode.vue'
import { payChannelEnum } from '/@/enums/payment/payChannelEnum'
import { findByParamKey } from '/@/api/common/Parameter'
@@ -183,7 +183,7 @@
*/
function getVoucher() {
if (form.voucherNo) {
findByCardNo(form.voucherNo).then(({ data }) => {
getAndJudgeVoucher(form.voucherNo).then(({ data }) => {
voucher = data
})
}

View File

@@ -64,9 +64,9 @@ export function del(id) {
/**
* 详情
*/
export function findByCardNo(cardNo) {
export function getAndJudgeVoucher(cardNo) {
return defHttp.get<Result<Voucher>>({
url: '/voucher/findByCardNo',
url: '/voucher/getAndJudgeVoucher',
params: { cardNo },
})
}
@@ -120,5 +120,5 @@ export interface Voucher extends BaseEntity {
// 结束时间
endTime?: string
// 状态
status?: number
status?: string
}

View File

@@ -45,8 +45,8 @@
</a-form-item>
<a-form-item label="默认状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="1">启用</a-radio>
<a-radio :value="2">停用</a-radio>
<a-radio :value="VoucherEnum.STATUS_NORMAL">启用</a-radio>
<a-radio :value="VoucherEnum.STATUS_FORBIDDEN">停用</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
@@ -65,6 +65,7 @@
import { computed, nextTick } from 'vue'
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { generationBatch } from '/@/views/modules/payment/voucher/Voucher.api'
import { VoucherEnum } from '/@/enums/payment/voucherEnum'
const { handleCancel, labelCol, wrapperCol, modalWidth, title, confirmLoading, visible, editable, showable, formEditType } = useFormEdit()
const { createMessage } = useMessage()
@@ -78,7 +79,7 @@
enduring: true,
startTime: null,
endTime: null,
status: 1,
status: VoucherEnum.STATUS_NORMAL,
})
const rules = computed<Record<string, Rule[]>>(() => {
@@ -95,8 +96,8 @@
function init() {
visible.value = true
// confirmLoading.value = true
resetForm()
confirmLoading.value = false
}
// 时间范围变动
@@ -118,6 +119,7 @@
}
await generationBatch(form)
visible.value = false
confirmLoading.value = false
emits('ok')
})
}

View File

@@ -24,6 +24,9 @@
<a-descriptions-item label="有效期">
{{ form.enduring ? '长期' : '期限' }}
</a-descriptions-item>
<a-descriptions-item label="状态">
{{ form.status === VoucherEnum.STATUS_NORMAL ? '正常' : '停用' }}
</a-descriptions-item>
<a-descriptions-item label="开始时间">
{{ form.startTime }}
</a-descriptions-item>
@@ -43,6 +46,7 @@
import { get, Voucher } from './Voucher.api'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { VoucherEnum } from "../../../../enums/payment/voucherEnum";
const { handleCancel, modalWidth, confirmLoading, visible } = useFormEdit()
// 表单
const formRef = $ref<FormInstance>()
@@ -55,7 +59,7 @@
enduring: true,
startTime: '',
endTime: '',
status: 0,
status: undefined,
})
// 入口
function init(id) {

View File

@@ -41,12 +41,12 @@
<template #overlay>
<a-menu>
<a-menu-item>
<a-link danger v-if="row.status === 1" @click="lockConfirm(row.id, true)">停用</a-link>
<a-link v-if="row.status === 2" @click="lockConfirm(row.id, false)">启用</a-link>
<a-link @click="showLogs(row.id)">日志</a-link>
</a-menu-item>
<a-menu-item>
<a-link danger v-if="row.status === 'normal'" @click="lockConfirm(row.id, true)">停用</a-link>
<a-link v-if="row.status === 'forbidden'" @click="lockConfirm(row.id, false)">启用</a-link>
</a-menu-item>
<!-- <a-menu-item>-->
<!-- <a-link>金额变动</a-link>-->
<!-- </a-menu-item>-->
</a-menu>
</template>
</a-dropdown>

View File

@@ -0,0 +1,33 @@
import { PageResult, Result } from '/#/axios'
import { defHttp } from '/@/utils/http/axios'
import { BaseEntity } from '/#/web'
/**
* 根据储值卡Id查询日志分页
*/
export function pageByVoucherId(params) {
return defHttp.get<Result<PageResult<VoucherLog>>>({
url: '/voucher/log/pageByVoucherId',
params,
})
}
/**
* 储值卡日志
*/
export interface VoucherLog extends BaseEntity {
/** 储值卡id */
voucherId: string
/** 储值卡号 */
voucherNo: string
/** 金额 */
amount: number
/** 类型 */
type: string
/** 交易记录ID */
paymentId: string
/** 业务ID */
businessId: string
/** 备注 */
remark: string
}

View File

@@ -0,0 +1,79 @@
<template>
<basic-drawer forceRender showFooter v-bind="$attrs" title="钱包日志列表" width="60%" :visible="visible" @close="visible = false">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }" />
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="type" title="类型">
<template #default="{ row }">
{{ dictConvert('WalletLogType', row.type) }}
</template>
</vxe-column>
<vxe-column field="amount" title="金额" />
<vxe-column field="operationSource" title="操作类型">
<template #default="{ row }">
{{ dictConvert('WalletLogOperation', row.operationSource) }}
</template>
</vxe-column>
<vxe-column field="createTime" title="操作时间" />
<vxe-column field="remark" title="备注" />
<template #footer>
<a-button key="cancel" @click="handleCancel">取消</a-button>
</template>
</vxe-table>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
</basic-drawer>
</template>
<script setup lang="ts">
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { useMessage } from '/@/hooks/web/useMessage'
import { useDict } from '/@/hooks/bootx/useDict'
import { QueryField } from '/@/components/Bootx/Query/Query'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { nextTick } from 'vue'
import { pageByVoucherId } from "/@/views/modules/payment/voucher/VoucherLog.api";
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
const { notification, createMessage } = useMessage()
const { dictConvert } = useDict()
// 查询条件
const fields = [] as QueryField[]
let visible = $ref(false)
let walletId = $ref<string>()
const xTable = $ref<VxeTableInstance>()
const xToolbar = $ref<VxeToolbarInstance>()
nextTick(() => {
xTable?.connect(xToolbar as VxeToolbarInstance)
})
function init(id) {
visible = true
walletId = id
queryPage()
}
// 分页查询
function queryPage() {
pageByVoucherId({
...model.queryParam,
...pages,
walletId,
}).then(({ data }) => {
pageQueryResHandel(data)
})
}
defineExpose({ init })
</script>
<style scoped lang="less"></style>