feat: 小程序跳转H5+支付

This commit is contained in:
zc 2025-11-08 20:34:56 +08:00
parent 4b4e5a73bd
commit 347403df42
10 changed files with 150 additions and 21 deletions

5
components.d.ts vendored
View File

@ -11,16 +11,21 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
VanArea: typeof import('vant/es')['Area'] VanArea: typeof import('vant/es')['Area']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell'] VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup'] VanCellGroup: typeof import('vant/es')['CellGroup']
VanField: typeof import('vant/es')['Field'] VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form'] VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon'] VanIcon: typeof import('vant/es')['Icon']
VanNoticeBar: typeof import('vant/es')['NoticeBar'] VanNoticeBar: typeof import('vant/es')['NoticeBar']
VanPopover: typeof import('vant/es')['Popover']
VanPopup: typeof import('vant/es')['Popup'] VanPopup: typeof import('vant/es')['Popup']
VanSearch: typeof import('vant/es')['Search']
VanStepper: typeof import('vant/es')['Stepper'] VanStepper: typeof import('vant/es')['Stepper']
VanSwipe: typeof import('vant/es')['Swipe'] VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem'] VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanSwitch: typeof import('vant/es')['Switch'] VanSwitch: typeof import('vant/es')['Switch']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
} }
} }

View File

@ -30,6 +30,7 @@
"vant": "^4.9.21", "vant": "^4.9.21",
"vconsole": "^3.15.1", "vconsole": "^3.15.1",
"vue": "^3.5.18", "vue": "^3.5.18",
"vue-cookie": "^1.1.4",
"vue-router": "^4.5.1", "vue-router": "^4.5.1",
"weixin-js-sdk": "^1.6.5" "weixin-js-sdk": "^1.6.5"
}, },

View File

@ -10,6 +10,7 @@ import VConsole from 'vconsole'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import GetUserInfo from './utils/getUserInfo'
const app = createApp(App) const app = createApp(App)
@ -19,3 +20,5 @@ app.use(router)
app.mount('#app') app.mount('#app')
!location.host.startsWith('app') && new VConsole() !location.host.startsWith('app') && new VConsole()
GetUserInfo.getInstance()

View File

@ -4,9 +4,10 @@ import axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig, type Ax
import { showToast } from 'vant' import { showToast } from 'vant'
import { baseURL } from '@/settings' import { baseURL } from '@/settings'
import useStore from '@/stores' import useNativeStore from '@/stores/modules/native'
import { loadingData } from './page' import { loadingData } from './page'
import { getLocalData } from './common'
// 创建axios实例 // 创建axios实例
const service: AxiosInstance = axios.create({ const service: AxiosInstance = axios.create({
@ -20,9 +21,9 @@ const noConsoleWhiteList = ['bl-log/web/log/add']
// request拦截器 // request拦截器
service.interceptors.request.use( service.interceptors.request.use(
async (config: InternalAxiosRequestConfig) => { async (config: InternalAxiosRequestConfig) => {
const { userStore, appStore } = useStore() const userInfo = getLocalData('userInfo') || {}
if (!/^http/.test(config.url!)) { if (!/^http/.test(config.url!)) {
config.headers!.token = userStore.userInfo.token || '' config.headers!.token = userInfo.token || ''
} }
if (!(config.headers!['Content-Type'] as string)?.endsWith('multipart/form-data')) { if (!(config.headers!['Content-Type'] as string)?.endsWith('multipart/form-data')) {
if (config.method === 'get') { if (config.method === 'get') {
@ -32,8 +33,8 @@ service.interceptors.request.use(
loadingData.type === 'submit' && (loadingData.show = true) loadingData.type === 'submit' && (loadingData.show = true)
} }
} else { } else {
config.data.buyerId = 2 // testzc config.data.buyerId = userInfo.buyerId
config.data.buyerWeixin = '我是微信号' // testzc config.data.buyerWeixin = userInfo.buyerWeixin
config.isLoading = config.data.isLoading config.isLoading = config.data.isLoading
delete config.data.isLoading delete config.data.isLoading
config.isLoading && loadingData.type === 'submit' && (loadingData.show = true) config.isLoading && loadingData.type === 'submit' && (loadingData.show = true)
@ -51,7 +52,7 @@ service.interceptors.request.use(
// response 拦截器 // response 拦截器
service.interceptors.response.use( service.interceptors.response.use(
(response: AxiosResponse<any>) => { (response: AxiosResponse<any>) => {
const { nativeStore } = useStore() const nativeStore = useNativeStore()
if (response.config.responseType === 'blob' || response.config.third) { if (response.config.responseType === 'blob' || response.config.third) {
// 如果是文件流,直接过 // 如果是文件流,直接过
return response return response

View File

@ -4,6 +4,7 @@ import MobileDetect from 'mobile-detect'
import { getData } from 'lz-utils-lib' import { getData } from 'lz-utils-lib'
import useAppStore from '@/stores/modules/app' import useAppStore from '@/stores/modules/app'
import router from '@/router' import router from '@/router'
import VueCookie from 'vue-cookie'
// 获取手机具体型号 // 获取手机具体型号
export const getPhoneType = () => { export const getPhoneType = () => {
@ -97,3 +98,21 @@ export const handleGoPdfPage = (url: string, name: string, search: string = '')
window.location.href = window.location.origin + '/dcmb/pdfjs/web/viewer.html?file=' + encodeURIComponent(newUrl + '?' + search) window.location.href = window.location.origin + '/dcmb/pdfjs/web/viewer.html?file=' + encodeURIComponent(newUrl + '?' + search)
} }
} }
// 缓存数据存本地和cookie
export const setLocalData = (key, value) => {
const v = typeof value === 'object' ? JSON.stringify(value) : value
localStorage.setItem(key, v)
VueCookie.set(key, v)
}
// 获取缓存数据本地或cookie
export const getLocalData = (key) => {
const v = localStorage.getItem(key) || VueCookie.get(key)
try {
const data = JSON.parse(v)
return data
} catch (error) {
return v
}
}

91
src/utils/getUserInfo.ts Normal file
View File

@ -0,0 +1,91 @@
import VueCookie from 'vue-cookie'
import { setLocalData, getLocalData } from './common'
import axios from 'axios'
import { Base64 } from 'js-base64'
import { getData } from 'lz-utils-lib'
// 工厂模式:获取用户信息
export default class GetUserInfo {
static whiteSNeedtores = ['/unicom/auth/result']
static envs = { lth5: 'online', tlth5: 'test' }
static env = ''
mobile = ''
// 获取search_info
static getInstance = () => {
const host = location.host
/* if (['/unicom/login', '/unicom/ycMall/login'].includes(location.pathname) || location.search.includes('jumpData=')) {
GetUserInfo.isNeedClearCache = true
} */
let returnData = ''
const { returnData: returnDataStr } = getData.getUrlParams(location.search) || {}
returnData = JSON.parse(Base64.decode(decodeURIComponent(returnDataStr)))
const env = (GetUserInfo.env = GetUserInfo.envs[host.replace(/^([a-z]+).+/g, '$1')])
const { envParams, extendParams } = (returnData as any) || {}
GetUserInfo.logParams(env, returnData, envParams, extendParams)
returnDataStr && !import.meta.env.DEV && GetUserInfo.sendReturnData('returnData=' + returnDataStr, extendParams.mobile, location.hostname)
return new GetUserInfo(returnData, envParams, extendParams)
}
// constructor
constructor(returnData, envParams, extendParams) {
// if ((returnData || GetUserInfo.isNeedClearCache) && !GetUserInfo.whiteSNeedtores.includes(location.pathname)) {
if (returnData && !GetUserInfo.whiteSNeedtores.includes(location.pathname)) {
this.clearCache()
this.saveCache(envParams, extendParams)
} else {
this.getCache()
}
}
// 清除缓存
clearCache = () => {
const noCleanKeys = []
const noCleanKeysData = noCleanKeys.reduce((data, key) => {
data[key] = localStorage.getItem(key)
return data
}, {})
localStorage.clear()
Object.keys(noCleanKeysData).forEach((key) => {
noCleanKeysData[key] && localStorage.setItem(key, noCleanKeysData[key])
})
VueCookie.delete('userInfo')
VueCookie.delete('extendParamsData')
}
// 获取旧缓存
getCache = () => {
const userInfo = getLocalData('userInfo') || {}
this.mobile = userInfo.mobile
}
// 清除后保存缓存
saveCache = (envParams, extendParams) => {
if (extendParams) {
this.mobile = extendParams.mobile
setLocalData('userInfo', extendParams)
setLocalData('extendParamsData', extendParams)
}
const envData = Base64.encode(JSON.stringify(envParams))
setLocalData('envData', envData)
}
// 打印日志
static logParams = (env, returnData, envParams, extendParams) => {
if (env !== 'online') {
console.log('href: ', location.href)
console.log('returnData: ', JSON.stringify(returnData))
console.log('extendParams: ', JSON.stringify(extendParams))
console.log('envParams: ', JSON.stringify(envParams))
}
}
// 发送returnData
static sendReturnData = (returnData, username, hostname) => {
/* axios.post('https://bllog.yijiesudai.com/bl-log/web/app/send/returnData', {
username,
returnData: returnData,
environment: hostname,
}) */
}
}

View File

@ -6,9 +6,9 @@ import wx from 'weixin-js-sdk'
*/ */
export const openMinProgram = (type = 'index') => { export const openMinProgram = (type = 'index') => {
if (['index', 'mine'].includes(type)) { if (['index', 'mine'].includes(type)) {
window.wx.miniProgram.switchTab({ url: `/pages/${type}/index` }) wx.miniProgram.switchTab({ url: `/pages/${type}/index` })
} else { } else {
window.wx.miniProgram.redirectTo({ url: `/pages/${type}/index` }) wx.miniProgram.redirectTo({ url: `/pages/${type}/index` })
} }
} }
@ -46,10 +46,10 @@ export const h5OpenMinProgram = (type = 'index', h5Url = '') => {
* @param {string} paymentParams.paySign - * @param {string} paymentParams.paySign -
*/ */
export const requestPayment = (paymentParams) => { export const requestPayment = (paymentParams) => {
wx.miniProgram.getEnv((res) => console.log(2222, res.miniprogram))
// 向小程序发送支付请求 // 向小程序发送支付请求
if (wx && wx.miniProgram) { if (wx && wx.miniProgram) {
wx.chooseWXPay({ /* wx.chooseWXPay({
// 有公众号的情况下可以使用
// timestamp: paymentData.timestamp, // 支付签名时间戳 // timestamp: paymentData.timestamp, // 支付签名时间戳
// nonceStr: paymentData.nonceStr, // 支付签名随机串 // nonceStr: paymentData.nonceStr, // 支付签名随机串
// package: paymentData.package, // 订单详情扩展字符串 // package: paymentData.package, // 订单详情扩展字符串
@ -65,13 +65,10 @@ export const requestPayment = (paymentParams) => {
// 支付失败后的回调 // 支付失败后的回调
alert('支付失败') alert('支付失败')
}, },
}) }) */
// 微信环境 // 微信环境
wx.miniProgram.postMessage({ wx.miniProgram.navigateTo({
data: { url: `/pages/pay/index?payParams=${encodeURIComponent(JSON.stringify(paymentParams))}`,
type: 'pay',
data: paymentParams,
},
}) })
} else { } else {
console.error('不在小程序环境中') console.error('不在小程序环境中')

View File

@ -109,10 +109,10 @@ const onSubmit = async () => {
await api.shop.addCart.post(formData.value) await api.shop.addCart.post(formData.value)
showToast('加入购物车成功') showToast('加入购物车成功')
} else { } else {
// await api.shop.order.post({ buyerAddressId: 2, vvTradeOrderLineDTOList: [formData.value] }) const res = await api.shop.order.post<{ timeStamp: any; package: string; prepayId: string }>({ buyerAddressId: 2, vvTradeOrderLineDTOList: [formData.value] })
// await api.shop.getWxPayParams.post(formData.value) // testzc res.data.package = res.data.prepayId
requestPayment({ a: 1, b: 2 }) res.data.timeStamp = String(res.data.timeStamp)
showToast('下单成功') requestPayment(res.data)
} }
} }
</script> </script>

View File

@ -148,7 +148,7 @@ const handleGetCommodityDetail = (productId: number) => {
const handleGetAddressList = () => { const handleGetAddressList = () => {
api.user.getAddressList.post<any>({}).then((res) => { api.user.getAddressList.post<any>({}).then((res) => {
curAddressData.value = res.data.rows.find((item) => item.status === 'default') curAddressData.value = res.data.rows.find((item) => item.status === 'default') || {}
}) })
} }
init() init()

View File

@ -3052,6 +3052,11 @@ synckit@^0.11.7:
dependencies: dependencies:
"@pkgr/core" "^0.2.9" "@pkgr/core" "^0.2.9"
tiny-cookie@^1.0:
version "1.0.1"
resolved "https://registry.npmmirror.com/tiny-cookie/-/tiny-cookie-1.0.1.tgz#753786079c642a3c3d0b2accad600f8de119ac2a"
integrity sha512-4KJ21HYTNumxnHvCbLrtrrhSwtWXzpmaRJIUg4biBii5AiSe2izod5bauXiiQxVuf2Fta57U2DTW1Fa4/6Cmgw==
tinyexec@^1.0.1: tinyexec@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" resolved "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1"
@ -3358,6 +3363,13 @@ vscode-uri@^3.0.8:
resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
vue-cookie@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/vue-cookie/-/vue-cookie-1.1.4.tgz#b8b46d112bda9f93a2f47017c2ed5282d2064fda"
integrity sha512-lxWIzmUTCVra0H7YPbNpYx0wbTQThV+n7ueUOcqtK8dlckmfB8fcyf4OEiRuQUd7iiVub2T3IDlWiisEM5Ku0Q==
dependencies:
tiny-cookie "^1.0"
vue-eslint-parser@^10.2.0: vue-eslint-parser@^10.2.0:
version "10.2.0" version "10.2.0"
resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz#cb53f89b14c7f5bf6a95c9532e3b2961ab619d61" resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz#cb53f89b14c7f5bf6a95c9532e3b2961ab619d61"