mirror of
https://gitee.com/bootx/dax-pay-h5.git
synced 2025-10-15 14:40:27 +00:00
feat 收银台开发
This commit is contained in:
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -10,8 +10,10 @@ declare module 'vue' {
|
|||||||
Loading: typeof import('./src/components/Loading.vue')['default']
|
Loading: typeof import('./src/components/Loading.vue')['default']
|
||||||
Logo: typeof import('./src/components/Logo.vue')['default']
|
Logo: typeof import('./src/components/Logo.vue')['default']
|
||||||
SvgIcon: typeof import('./src/components/SvgIcon.vue')['default']
|
SvgIcon: typeof import('./src/components/SvgIcon.vue')['default']
|
||||||
VanButton: typeof import('vant/es')['Button']
|
|
||||||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||||
|
VanDialog: typeof import('vant/es')['Dialog']
|
||||||
|
VanField: typeof import('vant/es')['Field']
|
||||||
VanLoading: typeof import('vant/es')['Loading']
|
VanLoading: typeof import('vant/es')['Loading']
|
||||||
|
VanNumberKeyboard: typeof import('vant/es')['NumberKeyboard']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/enums/daxpay/DaxPayEnum.ts
Normal file
28
src/enums/daxpay/DaxPayEnum.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 支付通道
|
||||||
|
*/
|
||||||
|
export enum ChannelEnum {
|
||||||
|
ALI = 'ali_pay',
|
||||||
|
WECHAT = 'wechat_pay',
|
||||||
|
UNION_PAY = 'union_pay',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付方式
|
||||||
|
*/
|
||||||
|
export enum payMethodEnum {
|
||||||
|
WAP = 'wap',
|
||||||
|
APP = 'app',
|
||||||
|
WEB = 'web',
|
||||||
|
QRCODE = 'qrcode',
|
||||||
|
BARCODE = 'barcode',
|
||||||
|
JSAPI = 'jsapi',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收银台类型
|
||||||
|
*/
|
||||||
|
export enum CashierTypeEnum {
|
||||||
|
WECHAT_PAY = 'wechat_pay',
|
||||||
|
ALIPAY = 'alipay',
|
||||||
|
}
|
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* 支付通道
|
|
||||||
*/
|
|
||||||
export enum payChannelEnum {
|
|
||||||
ALI = 'ali_pay',
|
|
||||||
WECHAT = 'wechat_pay',
|
|
||||||
UNION_PAY = 'union_pay',
|
|
||||||
CASH = 'cash_pay',
|
|
||||||
WALLET = 'wallet_pay',
|
|
||||||
VOUCHER = 'voucher_pay',
|
|
||||||
CREDIT_CARD = 'credit_pay',
|
|
||||||
AGGREGATION = 'aggregation_pay',
|
|
||||||
}
|
|
@@ -1,12 +0,0 @@
|
|||||||
/**
|
|
||||||
* 支付通道
|
|
||||||
*/
|
|
||||||
export enum payMethodEnum {
|
|
||||||
NORMAL = 'normal',
|
|
||||||
WAP = 'wap',
|
|
||||||
APP = 'app',
|
|
||||||
WEB = 'web',
|
|
||||||
QRCODE = 'qrcode',
|
|
||||||
BARCODE = 'barcode',
|
|
||||||
JSAPI = 'jsapi',
|
|
||||||
}
|
|
@@ -25,7 +25,7 @@ export const BusinessRoute: RouteRecordRaw = {
|
|||||||
name: 'SuccessResult',
|
name: 'SuccessResult',
|
||||||
component: () => import('@/views/result/SuccessResult.vue'),
|
component: () => import('@/views/result/SuccessResult.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '支付成功',
|
title: '操作成功',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -1,14 +1,54 @@
|
|||||||
import { http } from '@/utils/http/axios'
|
import { http } from '@/utils/http/axios'
|
||||||
import type { Result } from '#/axios'
|
import type { Result } from '#/axios'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商户名称
|
||||||
|
*/
|
||||||
|
export function getMchName(mchNo: string) {
|
||||||
|
return http.request<Result<string>>({
|
||||||
|
url: '/unipay/ext/channel/cashier/getMchName',
|
||||||
|
method: 'GET',
|
||||||
|
params: { mchNo },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取收银台信息
|
||||||
|
*/
|
||||||
|
export function getCashierInfo(cashierType: string, appId: string) {
|
||||||
|
return http.request<Result<ChannelCashierConfigResult>>({
|
||||||
|
url: '/unipay/ext/channel/cashier/getCashierType',
|
||||||
|
method: 'GET',
|
||||||
|
params: { cashierType, appId },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取收银台所需授权链接, 用于获取OpenId一类的信息
|
||||||
|
*/
|
||||||
|
export function generateAuthUrl(param: CashierAuthCodeParam) {
|
||||||
|
return http.request<Result<string>>({
|
||||||
|
url: '/unipay/ext/channel/cashier/authCode',
|
||||||
|
method: 'POST',
|
||||||
|
data: param,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起支付
|
||||||
|
*/
|
||||||
|
export function cashierPay(param: CashierPayParam) {
|
||||||
|
return http.request<Result<PayResult>>({
|
||||||
|
url: '/unipay/ext/channel/cashier/pay',
|
||||||
|
method: 'POST',
|
||||||
|
data: param,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通道认证参数
|
* 通道认证参数
|
||||||
*/
|
*/
|
||||||
export interface CashierAuthCodeParam {
|
export interface CashierAuthCodeParam {
|
||||||
// 标识码
|
|
||||||
authCode?: string
|
|
||||||
// 查询Code
|
|
||||||
queryCode?: string
|
|
||||||
// 商户号
|
// 商户号
|
||||||
mchNo?: string
|
mchNo?: string
|
||||||
// 应用号
|
// 应用号
|
||||||
@@ -16,3 +56,77 @@ export interface CashierAuthCodeParam {
|
|||||||
// 收银台类型
|
// 收银台类型
|
||||||
cashierType?: string
|
cashierType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通道收银支付参数
|
||||||
|
*/
|
||||||
|
export interface CashierPayParam {
|
||||||
|
|
||||||
|
// 商户号
|
||||||
|
mchNo?: string
|
||||||
|
// 应用号
|
||||||
|
appId?: string
|
||||||
|
// 收银台类型
|
||||||
|
cashierType?: string
|
||||||
|
// 支付金额
|
||||||
|
amount?: number
|
||||||
|
// 标识码
|
||||||
|
authCode?: string
|
||||||
|
// 支付描述
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付结果
|
||||||
|
*/
|
||||||
|
export interface PayResult {
|
||||||
|
|
||||||
|
// 支付状态
|
||||||
|
status: string
|
||||||
|
// 支付参数体
|
||||||
|
payBody: string
|
||||||
|
// 商户订单号
|
||||||
|
bizOrderNo: string
|
||||||
|
// 订单号
|
||||||
|
orderNo: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信Jsapi预支付签名返回信息
|
||||||
|
*/
|
||||||
|
export interface WxJsapiSignResult {
|
||||||
|
// 公众号ID,由商户传入
|
||||||
|
appId?: string
|
||||||
|
// 时间戳,自1970年以来的秒数
|
||||||
|
timeStamp?: string
|
||||||
|
// 随机串
|
||||||
|
nonceStr?: string
|
||||||
|
// 预支付ID
|
||||||
|
package?: string
|
||||||
|
// 微信签名方式:
|
||||||
|
signType?: string
|
||||||
|
// 微信签名
|
||||||
|
paySign?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收银台配置信息
|
||||||
|
*/
|
||||||
|
export interface ChannelCashierConfigResult {
|
||||||
|
// 商户号
|
||||||
|
mchNo?: string
|
||||||
|
// 应用号
|
||||||
|
appId?: string
|
||||||
|
// 收银台类型
|
||||||
|
cashierType?: string
|
||||||
|
// 收银台名称
|
||||||
|
cashierName?: string
|
||||||
|
// 支付通道
|
||||||
|
channel?: string
|
||||||
|
// 支付方式
|
||||||
|
payMethod?: string
|
||||||
|
// 是否开启分账
|
||||||
|
allocation?: boolean
|
||||||
|
// 自动分账
|
||||||
|
autoAllocation?: boolean
|
||||||
|
}
|
||||||
|
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
@@ -1,9 +1,201 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="container">
|
||||||
|
<div style="font-size: 28px;margin-top: 10px;">
|
||||||
|
{{ cashierInfo.cashierName || '支付宝收银台' }}
|
||||||
|
</div>
|
||||||
|
<div class="amount-display">
|
||||||
|
<p style="font-size: 20px">
|
||||||
|
付款给{{ mchName }}
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 32px;">
|
||||||
|
¥ {{ amount }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<van-dialog
|
||||||
|
v-model:show="show"
|
||||||
|
title="支付备注"
|
||||||
|
confirm-button-text="保存"
|
||||||
|
cancel-button-text="清除"
|
||||||
|
confirm-button-color="#108ee9"
|
||||||
|
cancel-button-color="red"
|
||||||
|
show-cancel-button
|
||||||
|
@cancel="description = ''"
|
||||||
|
>
|
||||||
|
<van-field
|
||||||
|
v-model="description"
|
||||||
|
rows="2"
|
||||||
|
autosize
|
||||||
|
label=""
|
||||||
|
type="textarea"
|
||||||
|
:maxlength="50"
|
||||||
|
placeholder="请输入支付备注内容"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</van-dialog>
|
||||||
|
<van-number-keyboard
|
||||||
|
:show="true"
|
||||||
|
theme="custom"
|
||||||
|
extra-key="."
|
||||||
|
close-button-text="付款"
|
||||||
|
@close="pay"
|
||||||
|
@input="input"
|
||||||
|
@delete="del"
|
||||||
|
>
|
||||||
|
<template #title-left>
|
||||||
|
<div style="width: 100vw;display: flex; justify-content: center">
|
||||||
|
<div class="remark" @click="show = true">
|
||||||
|
添加备注
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-number-keyboard>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import type {
|
||||||
|
CashierPayParam,
|
||||||
|
ChannelCashierConfigResult,
|
||||||
|
} from '@/views/daxpay/channel/ChannelCashier.api'
|
||||||
|
import {
|
||||||
|
cashierPay,
|
||||||
|
getCashierInfo,
|
||||||
|
getMchName,
|
||||||
|
} from '@/views/daxpay/channel/ChannelCashier.api'
|
||||||
|
|
||||||
|
import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const { mchNo, appId } = route.params
|
||||||
|
|
||||||
|
const show = ref<boolean>(false)
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const cashierInfo = ref<ChannelCashierConfigResult>({})
|
||||||
|
const amount = ref<string>('0')
|
||||||
|
const description = ref<string>('')
|
||||||
|
const mchName = ref<string>('')
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initData()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据
|
||||||
|
*/
|
||||||
|
function initData() {
|
||||||
|
getCashierInfo(CashierTypeEnum.ALIPAY, appId as string).then(({ data }) => {
|
||||||
|
cashierInfo.value = data
|
||||||
|
})
|
||||||
|
getMchName(mchNo as string).then(({ data }) => {
|
||||||
|
mchName.value = data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入
|
||||||
|
*/
|
||||||
|
function input(value: string) {
|
||||||
|
const amountStr = amount.value
|
||||||
|
if (amountStr === '0') {
|
||||||
|
if (value === '.') {
|
||||||
|
amount.value = '0.'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
amount.value = String(value)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 只允许有一个小数点
|
||||||
|
if (value === '.' && amountStr.includes('.')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 小数最多两位
|
||||||
|
if (amountStr.includes('.') && amountStr.length - amountStr.indexOf('.') > 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 金额最高100万
|
||||||
|
if (amountStr.split('.')[0].length > 7 && value !== '.') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
amount.value = amountStr.concat(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
function del() {
|
||||||
|
if (amount.value.length > 1) {
|
||||||
|
amount.value = amount.value.substring(0, amount.value.length - 1)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
amount.value = '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付
|
||||||
|
*/
|
||||||
|
function pay() {
|
||||||
|
// 金额不可为0
|
||||||
|
if (amount.value === '0') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
const from = {
|
||||||
|
amount: Number(amount.value),
|
||||||
|
appId,
|
||||||
|
cashierType: CashierTypeEnum.ALIPAY,
|
||||||
|
description: description.value,
|
||||||
|
mchNo,
|
||||||
|
} as CashierPayParam
|
||||||
|
cashierPay(from)
|
||||||
|
.then(({ data }) => {
|
||||||
|
loading.value = false
|
||||||
|
// 跳转到H5/付款码支付页面
|
||||||
|
location.replace(data.payBody)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// 跳转到错误页
|
||||||
|
router.push({
|
||||||
|
name: 'ErrorResult',
|
||||||
|
query: { msg: err.message },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
@color: #108ee9;
|
||||||
|
|
||||||
|
:deep(.van-key--blue) {
|
||||||
|
background: @color;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: @color;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
.amount-display {
|
||||||
|
background-color: white;
|
||||||
|
color: @color;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.amount-display p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.remark {
|
||||||
|
color: @color;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,11 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="container">
|
||||||
|
<h2>收银台</h2>
|
||||||
|
<div class="amount-display">
|
||||||
|
<p>付款给骏易</p>
|
||||||
|
<p class="amount">¥ 0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import type { WxJsapiSignResult } from '@/views/demo/aggregate/Aggregate.api'
|
import type {
|
||||||
import type { CashierAuthCodeParam } from '@/views/daxpay/channel/ChannelCashier.api'
|
CashierAuthCodeParam,
|
||||||
|
CashierPayParam,
|
||||||
|
WxJsapiSignResult,
|
||||||
|
} from '@/views/daxpay/channel/ChannelCashier.api'
|
||||||
|
import {
|
||||||
|
cashierPay,
|
||||||
|
generateAuthUrl,
|
||||||
|
} from '@/views/daxpay/channel/ChannelCashier.api'
|
||||||
|
|
||||||
|
import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { mchNo, appId } = route.params
|
const { mchNo, appId } = route.params
|
||||||
@@ -18,8 +37,7 @@ const amount = ref<number>(0.0)
|
|||||||
const authParam = ref<CashierAuthCodeParam>({
|
const authParam = ref<CashierAuthCodeParam>({
|
||||||
mchNo: mchNo as string,
|
mchNo: mchNo as string,
|
||||||
appId: appId as string,
|
appId: appId as string,
|
||||||
authCode: code as string,
|
cashierType: CashierTypeEnum.WECHAT_PAY,
|
||||||
cashierType: 'wechat_pay',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -32,17 +50,15 @@ onMounted(() => {
|
|||||||
function init() {
|
function init() {
|
||||||
// 如果不是重定向跳转过来, 跳转到到重定向地址
|
// 如果不是重定向跳转过来, 跳转到到重定向地址
|
||||||
if (!code) {
|
if (!code) {
|
||||||
// 跳转到微信授权地址
|
// 重定向跳转到微信授权地址
|
||||||
const url = ''
|
generateAuthUrl(authParam.value).then((res) => {
|
||||||
|
const url = res.data
|
||||||
location.replace(url)
|
location.replace(url)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 获取并设置OpenId
|
|
||||||
|
|
||||||
// 发起收银台支付
|
// 发起收银台支付
|
||||||
|
wechatPay()
|
||||||
// 获取jsapi调用方式
|
|
||||||
doJsapiPay()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,14 +68,13 @@ function init() {
|
|||||||
function wechatPay() {
|
function wechatPay() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const from = {
|
const from = {
|
||||||
bizOrderNo: `M${new Date().getTime()}`,
|
|
||||||
title: '测试H5支付',
|
|
||||||
amount: amount.value,
|
amount: amount.value,
|
||||||
channel: ChannelEnum.WECHAT,
|
appId,
|
||||||
method: MethodEnum.JSAPI,
|
authCode: code,
|
||||||
openId: openId.value,
|
cashierType: CashierTypeEnum.WECHAT_PAY,
|
||||||
}
|
mchNo,
|
||||||
simplePayCashier(from)
|
} as CashierPayParam
|
||||||
|
cashierPay(from)
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
// 拉起jsapi支付
|
// 拉起jsapi支付
|
||||||
@@ -91,9 +106,7 @@ function doJsapiPay(data: WxJsapiSignResult) {
|
|||||||
WeixinJSBridge.invoke('getBrandWCPayRequest', form, () => {
|
WeixinJSBridge.invoke('getBrandWCPayRequest', form, () => {
|
||||||
if (res.err_msg === 'get_brand_wcpay_request:ok') {
|
if (res.err_msg === 'get_brand_wcpay_request:ok') {
|
||||||
// 跳转到成功页面
|
// 跳转到成功页面
|
||||||
setTimeout(() => {
|
router.push({ name: 'SuccessResult', query: { msg: '支付成功' }, replace: true })
|
||||||
WeixinJSBridge.call('closeWindow')
|
|
||||||
}, 0)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user