feat 收银台调试

This commit is contained in:
DaxPay
2024-09-30 17:52:51 +08:00
parent cf671f175b
commit a96441949a
8 changed files with 104 additions and 102 deletions

2
components.d.ts vendored
View File

@@ -10,10 +10,12 @@ 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'] VanDialog: typeof import('vant/es')['Dialog']
VanField: typeof import('vant/es')['Field'] VanField: typeof import('vant/es')['Field']
VanLoading: typeof import('vant/es')['Loading'] VanLoading: typeof import('vant/es')['Loading']
VanNumberKeyboard: typeof import('vant/es')['NumberKeyboard'] VanNumberKeyboard: typeof import('vant/es')['NumberKeyboard']
VanTextEllipsis: typeof import('vant/es')['TextEllipsis']
} }
} }

View File

@@ -27,7 +27,7 @@ export const DaxPayRoute: RouteRecordRaw = {
}, },
}, },
{ {
path: '/channel/cashier/:appId/:channel', path: '/channel/cashier/:mchNo/:appId',
name: 'ChannelCashier', name: 'ChannelCashier',
component: () => import('@/views/daxpay/channel/ChannelCashier.vue'), component: () => import('@/views/daxpay/channel/ChannelCashier.vue'),
meta: { meta: {

View File

@@ -91,34 +91,12 @@ const transform: AxiosTransform = {
return result return result
} }
// 接口请求错误,统一提示错误信息 这里逻辑可以根据项目进行修改 // 接口请求错误,统一提示错误信息 这里逻辑可以根据项目进行修改
let errorMsg = msg const errorMsg = msg
switch (code) { // 请求失败
// 请求失败 console.log(code)
case ResultEnum.ERROR: if (code) {
showFailToast(errorMsg) showFailToast(errorMsg)
break
// token 过期
case ResultEnum.TOKEN_EXPIRED:
const LoginName = PageEnum.BASE_LOGIN_NAME
const LoginPath = PageEnum.BASE_LOGIN
if (router.currentRoute.value?.name === LoginName) {
return
}
// 到登录页
errorMsg = '登录超时,请重新登录!'
showDialog({
title: '提示',
message: '登录身份已失效,请重新登录!',
})
.then(() => {
storage.clear()
window.location.href = LoginPath
})
.catch(() => {
// on cancel
})
break
} }
throw new Error(errorMsg) throw new Error(errorMsg)
}, },

View File

@@ -13,7 +13,6 @@ export function authAndSet(param: AuthCodeParam) {
}) })
} }
/** /**
* 通道认证参数 * 通道认证参数
*/ */
@@ -27,3 +26,17 @@ export interface AuthCodeParam {
// 应用号 // 应用号
appId?: string appId?: string
} }
/**
* AuthResult
*/
export interface AuthResult {
// OpenId
openId?: string
// 用户ID
userId?: string
// AccessToken
accessToken?: string
// 状态
status?: string
}

View File

@@ -1,3 +1,4 @@
import type { AuthResult } from './ChannelAuth.api'
import { http } from '@/utils/http/axios' import { http } from '@/utils/http/axios'
import type { Result } from '#/axios' import type { Result } from '#/axios'
@@ -26,9 +27,20 @@ export function getCashierInfo(cashierType: string, appId: string) {
/** /**
* 获取收银台所需授权链接, 用于获取OpenId一类的信息 * 获取收银台所需授权链接, 用于获取OpenId一类的信息
*/ */
export function generateAuthUrl(param: CashierAuthCodeParam) { export function generateAuthUrl(param: CashierAuthParam) {
return http.request<Result<string>>({ return http.request<Result<string>>({
url: '/unipay/ext/channel/cashier/authCode', url: '/unipay/ext/channel/cashier/generateAuthUrl',
method: 'POST',
data: param,
})
}
/**
* 获取授权信息
*/
export function auth(param: CashierPayParam) {
return http.request<Result<AuthResult>>({
url: '/unipay/ext/channel/cashier/auth',
method: 'POST', method: 'POST',
data: param, data: param,
}) })
@@ -48,13 +60,15 @@ export function cashierPay(param: CashierPayParam) {
/** /**
* 通道认证参数 * 通道认证参数
*/ */
export interface CashierAuthCodeParam { export interface CashierAuthParam {
// 商户号 // 商户号
mchNo?: string mchNo?: string
// 应用号 // 应用号
appId?: string appId?: string
// 收银台类型 // 收银台类型
cashierType?: string cashierType?: string
// 授权码
authCode?: string
} }
/** /**
@@ -70,8 +84,8 @@ export interface CashierPayParam {
cashierType?: string cashierType?: string
// 支付金额 // 支付金额
amount?: number amount?: number
// 标识 // 唯一标识
authCode?: string openId?: string
// 支付描述 // 支付描述
description?: string description?: string
} }

View File

@@ -1,34 +1,19 @@
<template> <template>
<div class="page-container flex flex-col justify-center" v-if="show">
<div class="text-center">
<img src="~@/assets/icons/exception/403.svg" alt="">
</div>
<div class="text-center">
<h1 class="text-base text-gray-500">
请使用支付宝微信等支付程序进行扫码支付
</h1>
</div>
</div>
</template> </template>
<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'
const route = useRoute() const route = useRoute()
const { mchNo, appId } = route.params const { mchNo, appId } = route.params
const { fixed, amount } = route.query
const show = ref(false)
const ua = navigator.userAgent const ua = navigator.userAgent
if (ua.includes('MicroMessenger')) { if (ua.includes('MicroMessenger')) {
router.push({ path: `/wechat/cashier/${mchNo}/${appId}`, query: { fixed, amount }, replace: true }) router.push({ path: `/wechat/cashier/${mchNo}/${appId}`, replace: true })
} }
else if (ua.includes('Alipay')) { else if (ua.includes('Alipay')) {
router.push({ path: `/alipay/cashier/${mchNo}/${appId}`, query: { fixed, amount }, replace: true }) router.push({ path: `/alipay/cashier/${mchNo}/${appId}`, replace: true })
} }
else { else {
router.push({ name: 'ErrorResult', query: { msg: '请使用支付宝、微信等支付程序进行扫码支付' }, replace: true }) router.push({ name: 'ErrorResult', query: { msg: '请使用支付宝、微信等支付程序进行扫码支付' }, replace: true })
@@ -36,23 +21,4 @@ else {
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.page-container {
width: 100%;
border-radius: 4px;
padding: 50px 0;
height: 100vh;
.text-center {
h1 {
color: #666;
padding: 5vh 0;
font-size: x-large;
}
}
img {
width: 350px;
margin: 0 auto;
}
}
</style> </style>

View File

@@ -14,7 +14,7 @@
</div> </div>
</div> </div>
<van-dialog <van-dialog
v-model:show="show" v-model:show="showRemark"
title="支付备注" title="支付备注"
confirm-button-text="保存" confirm-button-text="保存"
cancel-button-text="清除" cancel-button-text="清除"
@@ -45,8 +45,13 @@
> >
<template #title-left> <template #title-left>
<div style="width: 100vw;display: flex; justify-content: center"> <div style="width: 100vw;display: flex; justify-content: center">
<div class="remark" @click="show = true"> <div class="remark" @click="showRemark = true">
添加备注 <div v-if="!description">
添加备注
</div>
<div v-else style="max-width: 75vw;">
<van-text-ellipsis :content="`备注: ${description}`" /><div />
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -57,6 +62,7 @@
<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 { showNotify } from 'vant'
import type { import type {
CashierPayParam, CashierPayParam,
ChannelCashierConfigResult, ChannelCashierConfigResult,
@@ -74,7 +80,7 @@ import { useKeyboard } from '@/hooks/daxpay/useKeyboard'
const route = useRoute() const route = useRoute()
const { mchNo, appId } = route.params const { mchNo, appId } = route.params
const show = ref<boolean>(false) const showRemark = ref<boolean>(false)
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const cashierInfo = ref<ChannelCashierConfigResult>({}) const cashierInfo = ref<ChannelCashierConfigResult>({})
const amount = ref<string>('0') const amount = ref<string>('0')
@@ -93,9 +99,13 @@ onMounted(() => {
function initData() { function initData() {
getCashierInfo(CashierTypeEnum.ALIPAY, appId as string).then(({ data }) => { getCashierInfo(CashierTypeEnum.ALIPAY, appId as string).then(({ data }) => {
cashierInfo.value = data cashierInfo.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
}) })
getMchName(mchNo as string).then(({ data }) => { getMchName(mchNo as string).then(({ data }) => {
mchName.value = data mchName.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
}) })
} }
@@ -103,14 +113,14 @@ function initData() {
* 支付 * 支付
*/ */
function pay() { function pay() {
// 金额不可为0 const amountValue = Number(amount.value)
if (amount.value === '0') { if (amountValue === 0) {
showNotify({ type: 'warning', message: '金额不可为0' })
return return
} }
loading.value = true loading.value = true
const from = { const from = {
amount: Number(amount.value), amount: amountValue,
appId, appId,
cashierType: CashierTypeEnum.ALIPAY, cashierType: CashierTypeEnum.ALIPAY,
description: description.value, description: description.value,
@@ -122,13 +132,6 @@ function pay() {
// 跳转到H5/付款码支付页面 // 跳转到H5/付款码支付页面
location.replace(data.payBody) location.replace(data.payBody)
}) })
.catch((err) => {
// 跳转到错误页
router.push({
name: 'ErrorResult',
query: { msg: err.message },
})
})
} }
</script> </script>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div> <div v-if="show">
<div class="container"> <div class="container">
<div style="font-size: 28px;margin-top: 10px;"> <div style="font-size: 28px;margin-top: 10px;">
{{ cashierInfo.cashierName || '微信收银台' }} {{ cashierInfo.cashierName || '微信收银台' }}
@@ -14,7 +14,7 @@
</div> </div>
</div> </div>
<van-dialog <van-dialog
v-model:show="show" v-model:show="showRemark"
title="支付备注" title="支付备注"
confirm-button-text="保存" confirm-button-text="保存"
cancel-button-text="清除" cancel-button-text="清除"
@@ -45,8 +45,13 @@
> >
<template #title-left> <template #title-left>
<div style="width: 100vw;display: flex; justify-content: center"> <div style="width: 100vw;display: flex; justify-content: center">
<div class="remark" @click="show = true"> <div class="remark" @click="showRemark = true">
添加备注 <div v-if="!description">
添加备注
</div>
<div v-else style="max-width: 75vw;">
<van-text-ellipsis :content="`备注: ${description}`" /><div />
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -57,13 +62,20 @@
<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 { showNotify } from 'vant'
import type { import type {
CashierAuthCodeParam, CashierAuthParam,
CashierPayParam, CashierPayParam,
ChannelCashierConfigResult, ChannelCashierConfigResult,
WxJsapiSignResult, WxJsapiSignResult,
} from '@/views/daxpay/channel/ChannelCashier.api' } from '@/views/daxpay/channel/ChannelCashier.api'
import { cashierPay, generateAuthUrl, getCashierInfo, getMchName } from '@/views/daxpay/channel/ChannelCashier.api' import {
auth
, cashierPay,
generateAuthUrl,
getCashierInfo,
getMchName,
} from '@/views/daxpay/channel/ChannelCashier.api'
import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum' import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router' import router from '@/router'
@@ -74,14 +86,16 @@ const { mchNo, appId } = route.params
const { code } = route.query const { code } = route.query
const show = ref<boolean>(false) const show = ref<boolean>(false)
const showRemark = ref<boolean>(false)
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const cashierInfo = ref<ChannelCashierConfigResult>({}) const cashierInfo = ref<ChannelCashierConfigResult>({})
const amount = ref<string>('0') const amount = ref<string>('0')
const description = ref<string>('') const description = ref<string>('')
const mchName = ref<string>('') const mchName = ref<string>('')
const openId = ref<string>('')
// 认证参数 // 认证参数
const authParam = ref<CashierAuthCodeParam>({ const authParam = ref<CashierAuthParam>({
mchNo: mchNo as string, mchNo: mchNo as string,
appId: appId as string, appId: appId as string,
cashierType: CashierTypeEnum.WECHAT_PAY, cashierType: CashierTypeEnum.WECHAT_PAY,
@@ -103,9 +117,12 @@ function init() {
generateAuthUrl(authParam.value).then((res) => { generateAuthUrl(authParam.value).then((res) => {
const url = res.data const url = res.data
location.replace(url) location.replace(url)
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
}) })
} }
else { else {
authParam.value.authCode = code as string
// 初始化数据 // 初始化数据
initData() initData()
} }
@@ -115,11 +132,21 @@ function init() {
* 初始化数据 * 初始化数据
*/ */
function initData() { function initData() {
show.value = true
getCashierInfo(CashierTypeEnum.ALIPAY, appId as string).then(({ data }) => { getCashierInfo(CashierTypeEnum.ALIPAY, appId as string).then(({ data }) => {
cashierInfo.value = data cashierInfo.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
}) })
getMchName(mchNo as string).then(({ data }) => { getMchName(mchNo as string).then(({ data }) => {
mchName.value = data mchName.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
})
auth(authParam.value).then(({ data }) => {
openId.value = data.openId as string
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
}) })
} }
@@ -127,11 +154,17 @@ function initData() {
* 微信jsapi方式支付 * 微信jsapi方式支付
*/ */
function pay() { function pay() {
const amountValue = Number(amount.value)
if (amountValue === 0) {
showNotify({ type: 'warning', message: '金额不可为0' })
return
}
loading.value = true loading.value = true
const from = { const from = {
amount: Number(amount.value), amount: amountValue,
appId, appId,
authCode: code, openId: openId.value,
cashierType: CashierTypeEnum.WECHAT_PAY, cashierType: CashierTypeEnum.WECHAT_PAY,
description: description.value, description: description.value,
mchNo, mchNo,
@@ -143,13 +176,6 @@ function pay() {
const json = JSON.parse(data.payBody) const json = JSON.parse(data.payBody)
jsapiPay(json) jsapiPay(json)
}) })
.catch((err) => {
// 跳转到错误页
router.push({
name: 'ErrorResult',
query: { msg: err.message },
})
})
} }
/** /**
@@ -165,7 +191,7 @@ function jsapiPay(data: WxJsapiSignResult) {
paySign: data.paySign, // 微信签名 paySign: data.paySign, // 微信签名
} }
// 使用微信JsSdk拉起支付 // 使用微信JsSdk拉起支付
WeixinJSBridge.invoke('getBrandWCPayRequest', form, () => { WeixinJSBridge.invoke('getBrandWCPayRequest', form, (res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') { if (res.err_msg === 'get_brand_wcpay_request:ok') {
// 跳转到成功页面 // 跳转到成功页面
router.push({ name: 'SuccessResult', query: { msg: '支付成功' }, replace: true }) router.push({ name: 'SuccessResult', query: { msg: '支付成功' }, replace: true })