2 Commits

Author SHA1 Message Date
DaxPay
33f0228655 fix vant组件夜间模式切换有不生效 2024-10-12 17:22:11 +08:00
DaxPay
1e503b80b9 ref 分包调整 2024-10-08 17:41:01 +08:00
19 changed files with 21 additions and 656 deletions

View File

@@ -5,7 +5,7 @@ VITE_PORT=9100
VITE_PUBLIC_PATH=/h5
# 跨域代理,可以配置多个,请注意不要换行
VITE_PROXY=[["/server","http://localhost:10880"]]
VITE_PROXY=[["/server","http://localhost:9999"]]
# API 接口地址
VITE_GLOB_API_URL=

View File

@@ -1,5 +1,5 @@
<template>
<vanConfigProvider :theme="getDarkMode" :theme-vars="getThemeVars()">
<vanConfigProvider :theme="darkMode" :theme-vars="getThemeVars()">
<routerView v-slot="{ Component }">
<div class="absolute bottom-0 top-0 w-full overflow-hidden">
<transition :name="getTransitionName" mode="out-in" appear>
@@ -18,8 +18,10 @@ import { useRouteStore } from '@/store/modules/route'
import { useDesignSetting } from '@/hooks/setting/useDesignSetting'
const routeStore = useRouteStore()
const { getDarkMode, getAppTheme, getIsPageAnimate, getPageAnimateType } = useDesignSetting()
const { getAppTheme, getIsPageAnimate, getPageAnimateType } = useDesignSetting()
// 读取是否为夜间模式
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
const darkMode = mediaQuery.matches ? 'dark' : 'light'
// 需要缓存的路由组件
const keepAliveComponents = computed(() => routeStore.keepAliveComponents)

View File

@@ -4,8 +4,6 @@ import { useDesignSettingStore } from '@/store/modules/designSetting'
export function useDesignSetting() {
const designStore = useDesignSettingStore()
const getDarkMode = computed(() => designStore.darkMode)
const getAppTheme = computed(() => designStore.appTheme)
const getAppThemeList = computed(() => designStore.appThemeList)
@@ -15,7 +13,6 @@ export function useDesignSetting() {
const getPageAnimateType = computed(() => designStore.pageAnimateType)
return {
getDarkMode,
getAppTheme,
getAppThemeList,
getIsPageAnimate,

View File

@@ -13,7 +13,7 @@ export const DaxPayRoute: RouteRecordRaw = {
{
path: '/alipay/auth/:appId/:channel/:queryCode/:aliAppId',
name: 'AlipayAuth',
component: () => import('@/views/daxpay/channel/alipay/auth/AlipayAuth.vue'),
component: () => import('@/views/daxpay/auth/alipay/AlipayAuth.vue'),
meta: {
title: '支付宝信息获取',
},
@@ -21,7 +21,7 @@ export const DaxPayRoute: RouteRecordRaw = {
{
path: '/wechat/auth/:appId/:channel/:queryCode',
name: 'WechatAuth',
component: () => import('@/views/daxpay/channel/wechat/auth/WechatAuth.vue'),
component: () => import('@/views/daxpay/auth/wechat/WechatAuth.vue'),
meta: {
title: '微信信息获取',
},
@@ -29,7 +29,7 @@ export const DaxPayRoute: RouteRecordRaw = {
{
path: '/channel/cashier/:appId',
name: 'ChannelCashier',
component: () => import('@/views/daxpay/channel/ChannelCashier.vue'),
component: () => import('@/views/daxpay/cashier/ChannelCashier.vue'),
meta: {
title: '收银台',
},
@@ -37,7 +37,7 @@ export const DaxPayRoute: RouteRecordRaw = {
{
path: '/alipay/cashier/:appId',
name: 'AlipayCashier',
component: () => import('@/views/daxpay/channel/alipay/cashier/AlipayCashier.vue'),
component: () => import('@/views/daxpay/cashier/alipay/AlipayCashier.vue'),
meta: {
title: '支付宝收银台',
},
@@ -45,7 +45,7 @@ export const DaxPayRoute: RouteRecordRaw = {
{
path: '/wechat/cashier/:appId',
name: 'WechatCashier',
component: () => import('@/views/daxpay/channel/wechat/cashier/WechatCashier.vue'),
component: () => import('@/views/daxpay/cashier/wechat/WechatCashier.vue'),
meta: {
title: '微信收银台',
},

View File

@@ -1,8 +1,6 @@
// app theme preset color
export interface DesignSettingState {
// 系统主题
darkMode: 'light' | 'dark'
// 系统风格
appTheme: string
// 系统内置风格
@@ -36,8 +34,6 @@ export const appThemeList: string[] = [
]
const setting: DesignSettingState = {
// 深色主题
darkMode: 'dark',
// 系统主题色
appTheme: '#5d9dfe',
// 系统内置主题色列表

View File

@@ -3,21 +3,17 @@ import { store } from '@/store'
import designSetting from '@/settings/designSetting'
import type { DesignSettingState } from '@/settings/designSetting'
const { darkMode, appTheme, appThemeList, isPageAnimate, pageAnimateType } = designSetting
const { appTheme, appThemeList, isPageAnimate, pageAnimateType } = designSetting
export const useDesignSettingStore = defineStore({
id: 'app-design-setting',
state: (): DesignSettingState => ({
darkMode,
appTheme,
appThemeList,
isPageAnimate,
pageAnimateType,
}),
getters: {
getDarkMode(): 'light' | 'dark' {
return this.darkMode
},
getAppTheme(): string {
return this.appTheme
},
@@ -32,9 +28,6 @@ export const useDesignSettingStore = defineStore({
},
},
actions: {
setDarkMode(mode: 'light' | 'dark'): void {
this.darkMode = mode
},
setPageAnimateType(type: string): void {
this.pageAnimateType = type
},

View File

@@ -12,8 +12,8 @@
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { showDialog } from 'vant'
import type { AuthCodeParam } from '@/views/daxpay/channel/ChannelAuth.api'
import { authAndSet } from '@/views/daxpay/channel/ChannelAuth.api'
import type { AuthCodeParam } from '@/views/daxpay/auth/ChannelAuth.api'
import { authAndSet } from '@/views/daxpay/auth/ChannelAuth.api'
const script = document.createElement('script')
script.setAttribute(

View File

@@ -12,8 +12,8 @@
import { useRoute } from 'vue-router'
import { onMounted, ref } from 'vue'
import { showDialog } from 'vant'
import type { AuthCodeParam } from '@/views/daxpay/channel/ChannelAuth.api'
import { authAndSet } from '@/views/daxpay/channel/ChannelAuth.api'
import type { AuthCodeParam } from '@/views/daxpay/auth/ChannelAuth.api'
import { authAndSet } from '@/views/daxpay/auth/ChannelAuth.api'
const route = useRoute()
const { appId, channel, queryCode } = route.params

View File

@@ -1,4 +1,4 @@
import type { AuthResult } from './ChannelAuth.api'
import type { AuthResult } from '../auth/ChannelAuth.api'
import { http } from '@/utils/http/axios'
import type { Result } from '#/axios'

View File

@@ -66,11 +66,11 @@ import { showNotify } from 'vant'
import type {
CashierPayParam,
ChannelCashierConfigResult,
} from '@/views/daxpay/channel/ChannelCashier.api'
} from '@/views/daxpay/cashier/ChannelCashier.api'
import {
cashierPay,
getCashierInfo,
} from '@/views/daxpay/channel/ChannelCashier.api'
} from '@/views/daxpay/cashier/ChannelCashier.api'
import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router'

View File

@@ -68,13 +68,13 @@ import type {
CashierPayParam,
ChannelCashierConfigResult,
WxJsapiSignResult,
} from '@/views/daxpay/channel/ChannelCashier.api'
} from '@/views/daxpay/cashier/ChannelCashier.api'
import {
auth
, cashierPay,
generateAuthUrl,
getCashierInfo,
} from '@/views/daxpay/channel/ChannelCashier.api'
} from '@/views/daxpay/cashier/ChannelCashier.api'
import { CashierTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router'

View File

@@ -1,63 +0,0 @@
import { http } from '@/utils/http/axios'
import type { Result } from '#/axios'
/**
* 获取支付信息
*/
export function getInfo(code): Promise<Result<AggregatePayInfo>> {
return http.request({
url: '/demo/aggregate/getInfo',
method: 'get',
params: { code },
})
}
/**
* 支付宝h5支付
*/
export function aliH5Pay(code): Promise<Result<PayOrderResult>> {
return http.request({
url: '/demo/aggregate/aliH5Pay',
method: 'post',
params: { code },
})
}
/**
* 获取微信H5预支付签名信息
*/
export function getWxJsapiPay(aggregateCode, openId): Promise<Result<WxJsapiSignResult>> {
return http.request({
url: '/demo/aggregate/getWxJsapiPay',
method: 'post',
params: { aggregateCode, openId },
})
}
/**
*支付信息
*/
export interface AggregatePayInfo {
title?: string
bizOrderNo?: string
amount: number
}
/**
* 发起支付后响应对象
*/
export interface PayOrderResult {
payBody: string
}
/**
* 微信Jsapi预支付签名返回信息
*/
export interface WxJsapiSignResult {
appId?: string
timeStamp?: string
nonceStr?: string
signType?: string
paySign?: string
package?: string
}

View File

@@ -1,95 +0,0 @@
<template>
<div class="page-container flex flex-col justify-center">
<van-overlay lock-scroll :show="loading">
<Loading text="调起支付中..." />
</van-overlay>
<div class="text-center">
<h1>金额: {{ info.amount / 100.0 }} </h1>
<h1>标题: {{ info.title }}</h1>
<h1>业务号: {{ info.businessNo }}</h1>
</div>
<div class="text-center">
<van-button type="primary" @click="pay">
去支付
</van-button>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, unref } from 'vue'
import { useRouter } from 'vue-router'
import type { AggregatePayInfo } from './Aggregate.api'
import { aliH5Pay, getInfo } from './Aggregate.api'
import router from '@/router'
import Loading from '@/components/Loading.vue'
onMounted(() => {
init()
})
const { currentRoute } = useRouter()
const { query } = unref(currentRoute)
const loading = ref<boolean>(false)
const code = ref<string>(query.code as string)
const info = ref<AggregatePayInfo>({ amount: 0 })
/**
* 根据code获取支付信息
*/
async function init() {
loading.value = true
await getInfo(code.value)
.then(({ data }) => {
info.value = data
loading.value = false
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
// 调起支付
pay()
}
/**
* 发起支付
*/
function pay() {
loading.value = true
aliH5Pay(code.value)
.then(({ data }) => {
loading.value = false
// 跳转到H5支付页面
window.location.href = data.payBody
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
}
</script>
<style lang="less" scoped>
.page-container {
width: 100%;
border-radius: 4px;
padding: 50px 0;
height: 100vh;
.text-center {
h1 {
color: #666;
padding: 2vh 0;
font-size: x-large;
}
}
}
</style>

View File

@@ -1,118 +0,0 @@
<template>
<div class="page-container flex flex-col justify-center">
<van-overlay lock-scroll :show="loading">
<Loading text="调起支付中..." />
</van-overlay>
<div class="text-center">
<h1>金额: {{ info.amount / 100.0 }} </h1>
<h1>标题: {{ info.title }}</h1>
<h1>订单号: {{ info.bizOrderNo }}</h1>
</div>
<div class="text-center">
<van-button type="primary" @click="pay">
去支付
</van-button>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, unref } from 'vue'
import { useRouter } from 'vue-router'
import type { AggregatePayInfo, WxJsapiSignResult } from './Aggregate.api'
import { getInfo, getWxJsapiPay } from './Aggregate.api'
import router from '@/router'
import Loading from '@/components/Loading.vue'
const { currentRoute } = useRouter()
const { query } = unref(currentRoute)
const aggregateCode = ref<string>(query.aggregateCode as string)
const openId = ref<string>(query.openId as string)
const info = ref<AggregatePayInfo>({ amount: 0 })
const loading = ref<boolean>(false)
onMounted(() => {
init()
})
/**
* 根据code获取支付信息
*/
async function init() {
loading.value = true
// 获取支付信息
await getInfo(aggregateCode.value)
.then(({ data }) => {
loading.value = false
info.value = data
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
// 调起支付
pay()
}
/**
* 发起支付
*/
function pay() {
loading.value = true
getWxJsapiPay(aggregateCode.value, openId.value)
.then(({ data }) => {
loading.value = false
doPay(data)
})
.catch(() => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: '支付失败' },
})
})
}
/**
* 拉起支付
*/
function doPay(data: WxJsapiSignResult) {
const form = {
appId: data.appId, // 公众号ID由商户传入
timeStamp: data.timeStamp, // 时间戳自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package, // 预支付ID
signType: data.signType, // 微信签名方式:
paySign: data.paySign, // 微信签名
}
// 使用微信JsSdk拉起支付
WeixinJSBridge.invoke('getBrandWCPayRequest', form, (res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
setTimeout(() => {
WeixinJSBridge.call('closeWindow')
}, 0)
}
})
}
</script>
<style lang="less" scoped>
.page-container {
width: 100%;
border-radius: 4px;
padding: 50px 0;
height: 100vh;
.text-center {
h1 {
color: #666;
padding: 2vh 0;
font-size: x-large;
}
}
}
</style>

View File

@@ -1,41 +0,0 @@
import { http } from '@/utils/http/axios'
import type { Result } from '#/axios'
/**
* 获取当前可用支付的环境
*/
export function getPayEnv(): Promise<Result<string>> {
return http.request({
url: '/demo/cashier/getPayEnv',
method: 'get',
})
}
/**
* 获取微信授权请求页URL
*/
export function getWxAuthUrl(): Promise<Result<string>> {
return http.request({
url: '/demo/cashier/getWxAuthUrl',
method: 'get',
})
}
/**
* 单独支付
*/
export function simplePayCashier(obj): Promise<Result<PayOrderResult>> {
return http.request({
url: '/demo/cashier/simplePayCashier',
method: 'post',
data: obj,
})
}
/**
* 发起支付后响应对象
*/
export interface PayOrderResult {
// 支付参数体(通常用于发起异步支付的参数)
payBody: string
}

View File

@@ -1,295 +0,0 @@
<template>
<div v-show="pageShow">
<div class="h-screen flex justify-center pt-8">
<van-overlay lock-scroll :show="loading">
<Loading text="调起支付中..." />
</van-overlay>
<div class="w-full flex flex-col">
<div class="flex flex-col items-center justify-center">
<div class="logo enter-y my-35px">
<SvgIcon class="!h-150px !w-150px" name="logo" />
</div>
<div class="text-darkBlue dark:text-garyWhite enter-y mb-80px text-45px font-black">
手机收银台
</div>
<van-form ref="formRef">
<van-cell-group inset>
<van-field
v-model="amount"
type="number"
required
label="金额"
:rules="[
{ required: true, message: '请输入要支付的金额' },
{ pattern: /^\d+(\.\d{2})?$/, message: '金额最为多两位小数' },
{
validator: validatorAmount,
message: '请输入0.01-100之间的金额',
},
]"
/>
<van-field name="switch" label="过滤支付方式">
<template #input>
<van-switch v-model="filterChannelFlag" size="24px" @change="initChannelList" />
</template>
</van-field>
</van-cell-group>
</van-form>
<van-action-sheet
v-model:show="channelShow"
safe-area-inset-bottom
:actions="channelList"
@select="pay"
/>
<van-action-bar safe-area-inset-bottom>
<van-action-bar-button type="danger" text="支付" @click="paySelect" />
</van-action-bar>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, unref } from 'vue'
import type { ActionSheetAction } from 'vant'
import { useRouter } from 'vue-router'
import { getPayEnv, getWxAuthUrl, simplePayCashier } from '@/views/demo/cashier/Cashier.api'
import router from '@/router'
import { payChannelEnum } from '@/enums/payment/payChannelEnum'
import { payMethodEnum } from '@/enums/payment/payMethodEnum'
import type { WxJsapiSignResult } from '@/views/demo/aggregate/Aggregate.api'
import Loading from '@/components/Loading.vue'
const pageShow = ref<boolean>(false)
const loading = ref<boolean>(false)
const channelShow = ref<boolean>(false)
const filterChannelFlag = ref<boolean>(true)
const amount = ref<number>(0.01)
const formRef = ref<any>()
// 当前环境
const currentEnv = ref<string>('all')
const openId = ref<string>('')
const channelList = ref<ActionSheetAction[]>([])
const { currentRoute } = useRouter()
const { query } = unref(currentRoute)
onMounted(() => {
init()
})
/**
* 初始化
*/
async function init() {
await getPayEnv().then(({ data }) => {
currentEnv.value = data
})
// 是否在微信环境中. 在的话获取微信授权
if (currentEnv.value === payChannelEnum.WECHAT) {
const source = query.source as string
// 重定向则获取OpenId
if (source === 'redirect') {
openId.value = query.openId as string
}
else {
// 跳转到微信授权地址
const { data: url } = await getWxAuthUrl()
location.replace(url)
return
}
}
initChannelList()
pageShow.value = true
}
/**
* 初始化通道列表
*/
function initChannelList() {
channelList.value = [
{
name: '支付宝',
disabled: channelFilter(payChannelEnum.ALI),
},
{
name: '微信',
disabled: channelFilter(payChannelEnum.WECHAT),
},
]
}
/**
* 过滤当前的状态是否可以使用
*/
function channelFilter(channel: string): boolean {
// 未开启过滤
if (!filterChannelFlag.value) {
return false
}
// 返回为all
if (currentEnv.value === 'all') {
return false
}
// 如果返回通道, 只有当前符合环境的可以用
return currentEnv.value !== channel
}
/**
* 校验支付金额
*/
function validatorAmount(input: string) {
if (Number.parseFloat(input) >= 0.01 && Number.parseFloat(input) <= 100) {
return Promise.resolve(true)
}
else {
return Promise.resolve(false)
}
}
/**
* 调起支付选择
*/
function paySelect() {
// 校验表单
formRef.value.validate().then(() => {
// 拉起选择弹窗
channelShow.value = true
})
}
/**
* 发起支付
*/
function pay(action: ActionSheetAction) {
if (action.name === '微信') {
wechatPay()
}
else {
aliPay()
}
}
/**
* 发起微信支付
* 1. 微信中使用jsapi
* 2. 外部浏览器使用wap支付
*/
function wechatPay() {
if (currentEnv.value === 'wechat_pay') {
wechatJsapiPay()
}
else {
wechatH5Pay()
}
}
/**
* 微信jsapi方式支付
*/
function wechatJsapiPay() {
loading.value = true
const from = {
bizOrderNo: `M${new Date().getTime()}`,
title: '测试H5支付',
amount: amount.value,
channel: payChannelEnum.WECHAT,
method: payMethodEnum.JSAPI,
openId: openId.value,
}
simplePayCashier(from)
.then(({ data }) => {
loading.value = false
// 拉起jsapi支付
const json = JSON.parse(data.payBody)
doJsapiPay(json)
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
}
/**
* 拉起Jsapi支付窗口
*/
function doJsapiPay(data: WxJsapiSignResult) {
const form = {
appId: data.appId, // 公众号ID由商户传入
timeStamp: data.timeStamp, // 时间戳自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package, // 预支付ID
signType: data.signType, // 微信签名方式:
paySign: data.paySign, // 微信签名
}
// 使用微信JsSdk拉起支付
WeixinJSBridge.invoke('getBrandWCPayRequest', form, (res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
setTimeout(() => {
WeixinJSBridge.call('closeWindow')
}, 0)
}
})
}
/**
* 微信h5支付
*/
function wechatH5Pay() {
loading.value = true
const from = {
bizOrderNo: new Date().getTime(),
title: '测试H5支付',
amount: amount.value,
channel: payChannelEnum.WECHAT,
method: payMethodEnum.WAP,
}
simplePayCashier(from)
.then(({ data }) => {
loading.value = false
// 跳转到H5支付页面
location.replace(data.payBody)
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
}
/**
* 支付宝支付, 使用h5支付
*/
function aliPay() {
loading.value = true
const from = {
bizOrderNo: new Date().getTime(),
title: '测试H5支付',
amount: amount.value,
channel: payChannelEnum.ALI,
method: payMethodEnum.WAP,
}
simplePayCashier(from)
.then(({ data }) => {
loading.value = false
// 跳转到H5支付页面
window.location.href = data.payBody
})
.catch((err) => {
// 跳转到错误页
router.push({
name: 'PayErrorResult',
query: { msg: err.message },
})
})
}
</script>
<style scoped lang="less"></style>

View File

@@ -1,11 +0,0 @@
<template>
支付超时
</template>
<script setup lang="ts">
</script>
<style scoped lang="less">
</style>