wechar支付兼容
CI/CD / build (push) Successful in 7m43s Details

This commit is contained in:
13121765685 2026-01-16 13:08:08 +08:00
parent 6fe9e04030
commit 91824a1368
17 changed files with 242 additions and 57 deletions

View File

@ -8,6 +8,7 @@ import { useAuthStore } from '@/stores/auth';
import footerCom from './components/footerBeiAn/index.vue';
import {isWeChatBrowser} from '@deotaland/utils';
const authStore = useAuthStore();
console.log('更新西悉尼');
authStore.updateUserInfo()
const route = useRoute()
//

View File

@ -78,20 +78,20 @@ const emit = defineEmits(['close', 'acknowledge'])
const handleOverlayClick = () => onClose();
const onClose = () => emit('close');
const handleAcknowledge = () => {
if(isWeChatBrowser()){
WechatBus.BusWechartForNavigate('/pages/pay/pay',{
method:'pay',
payData:JSON.stringify({
orderId: 1,
series:1,
name:{
D1:'定制模型',
E1:'定制模型',
},
})
})
return
}
// if(isWeChatBrowser()){
// WechatBus.BusWechartForNavigate('/pages/pay/pay',{
// method:'pay',
// payData:JSON.stringify({
// orderId: 1,
// series:1,
// name:{
// D1:'',
// E1:'',
// },
// })
// })
// return
// }
emit('acknowledge', props.modelData)
onClose()
}

View File

@ -113,7 +113,7 @@
</div>
<!-- 联系信息和配送信息并排布局 -->
<div class="info-row">
<div class="info-row" v-if="!isWeChatBrowser()">
<!-- 联系信息 -->
<div class="info-column">
<h2 class="block-title">
@ -141,7 +141,7 @@
</div>
<!-- 配送信息 -->
<div class="info-column">
<div class="info-column" v-if="!isWeChatBrowser()">
<h2 class="block-title">
{{ $t('checkout.shipping') }}
</h2>
@ -206,7 +206,8 @@
<!-- Action Buttons -->
<div class="action-area">
<button class="buy-btn" :disabled="isPayButtonDisabled" @click="goShopify">{{ $t('checkout.buy') }}</button>
<button class="buy-btn" v-if="!isWeChatBrowser()" :disabled="isPayButtonDisabled" @click="goShopify">{{ $t('checkout.buy') }}</button>
<button class="buy-btn" v-else @click="goShopify">{{ $t('checkout.buy') }}</button>
</div>
<!-- Stripe Payment Overlay -->
@ -235,9 +236,10 @@ import { CloseBold, Search } from '@element-plus/icons-vue'
import StripePaymentForm from '@/components/StripePaymentForm.vue'
import { Country, State } from 'country-state-city'
import { useI18n } from 'vue-i18n'
import { PayServer } from '@deotaland/utils'
import { PayServer,isWeChatBrowser } from '@deotaland/utils'
import { requestUtils,clientApi,environmentUtils } from '@deotaland/utils'
import { PurchaseModal as PurchaseModalClass } from './index.js'
import { WechatBus } from '@deotaland/utils'
const payserver = new PayServer();
const purchaseModal = new PurchaseModalClass();
const props = defineProps({
@ -279,7 +281,7 @@ const loadingShops = ref(false)
//
const isPayButtonDisabled = computed(() => {
return !(
return (!(
shipping.value.firstName.trim() &&
shipping.value.lastName.trim() &&
shipping.value.state.trim() &&
@ -287,7 +289,7 @@ const isPayButtonDisabled = computed(() => {
shipping.value.address1.trim() &&
shipping.value.phone.trim() &&
ipName.value.trim()
)
))
})
const unt = ref('');
const price = ref(0);
@ -404,7 +406,7 @@ const goShopify = () => {//用户点击购买
}
let params ={
quantity:qty.value,
project_id:props.modelData.projectId,
project_id:props.modelData.project_id,
project_details:project_details,
order_info:order_info,
}
@ -426,6 +428,17 @@ const goShopify = () => {//用户点击购买
saveLocal()
//
params.product_id = seriesId.value
params.amount = (amountCents.value).toFixed(2)
if(isWeChatBrowser()){
const token = window.localStorage.getItem('token')
console.log(params,'params');
WechatBus.BusWechartForNavigate('/pages/pay/pay',{
method:'pay',
payData:JSON.stringify({...params,token:token})
})
return
}
payserver.createPayorOrder(params);
}
const saveLocal = () => {

View File

@ -162,6 +162,21 @@
</label>
</div>
<!-- 微信一键登录登录和注册时显示重置密码时不显示 -->
<button
v-if="isWeChatBrowser()"
type="button"
class="wechat-login-button"
:disabled="loading"
@click="handleWechatLogin"
>
<svg class="wechat-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path fill="#07C160" d="M666.24 495.36c-8.96 0-17.92 0.96-26.88 2.88 27.52-47.36 43.52-102.4 43.52-161.28 0-170.24-158.72-308.48-354.56-308.48-195.84 0-354.56 138.24-354.56 308.48 0 88.32 43.52 168.96 115.2 225.28-6.4 19.84-16.96 52.48-19.84 60.8-4.48 13.44 6.4 26.88 20.48 21.76 9.6-3.84 52.48-20.48 77.44-30.08 52.48 23.04 112 36.48 175.36 36.48 8.96 0 17.92-0.96 26.88-1.92-4.48-20.48-6.4-41.6-6.4-63.36 0-154.24 140.8-279.68 313.6-279.68 8.96 0 17.92 0 26.88 0.96 0-3.84 0-7.68 0-11.52z"/>
<path fill="#07C160" d="M958.72 643.84c0-134.4-128-243.2-285.44-243.2-157.44 0-285.44 108.8-285.44 243.2 0 134.4 128 243.2 285.44 243.2 32 0 63.36-4.48 92.8-12.16 20.48 8.32 57.6 22.4 65.28 25.28 11.52 4.48 20.48-6.4 16.96-17.92-2.88-6.4-11.52-33.28-16.96-49.92 51.2-44.8 82.56-105.6 82.56-172.8z"/>
</svg>
<span class="button-text">{{ t('login.wechat_login_button') }}</span>
</button>
<!-- 登录/注册按钮 -->
<button
type="submit"
@ -198,10 +213,10 @@ import { useRouter } from 'vue-router'
import { WarningFilled, View, Hide } from '@element-plus/icons-vue'
import { useVuelidate } from '@vuelidate/core'
import { required, minLength } from '@vuelidate/validators'
import { isWeChatBrowser,WechatBus } from '@deotaland/utils';
const { t } = useI18n()
const router = useRouter()
const emit = defineEmits(['login', 'codeLogin', 'register', 'resetPassword', 'resetSuccess', 'sendCode'])
const emit = defineEmits(['login', 'codeLogin', 'register', 'resetPassword', 'resetSuccess', 'sendCode', 'wechatLogin'])
const props = defineProps({
loading: {
type: Boolean,
@ -420,12 +435,15 @@ const toggleLoginMode = (mode, method = 'password') => {
//
agreementChecked.value = false
}
//
const handleWechatLogin = () => {
WechatBus.BusWechartForNavigate('/pages/login/index',{
},'2')
}
//
const goToAgreement = (type) => {
router.push(`/agreement/${type}`)
}
//
defineExpose({
toggleLoginMode
@ -785,6 +803,59 @@ defineExpose({
color: #5B21B6;
}
/* 微信登录按钮 */
.wechat-login-button {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
height: 48px;
background: white;
border: 2px solid #07C160;
border-radius: 12px;
color: #07C160;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
box-shadow: 0 2px 4px rgba(7, 193, 96, 0.1);
}
.wechat-login-button:hover:not(:disabled) {
background: #F0FDF4;
border-color: #06A84D;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(7, 193, 96, 0.2);
}
.wechat-login-button:active:not(:disabled) {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(7, 193, 96, 0.15);
}
.wechat-login-button:disabled {
background: #F9FAFB;
border-color: #D1D5DB;
color: #9CA3AF;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.wechat-login-button .wechat-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
}
.wechat-login-button .button-text {
font-weight: 600;
letter-spacing: 0.025em;
}
/* 响应式设计 */
@media (max-width: 768px) {
.form-input {
@ -797,6 +868,11 @@ defineExpose({
font-size: 15px;
}
.wechat-login-button {
height: 44px;
font-size: 15px;
}
.send-code-button {
height: 44px;
font-size: 13px;

View File

@ -292,7 +292,7 @@ export default {
case 'logout':
try {
await authStore.logout(()=>{
router.push('/login')
// router.push('/login')
})
} catch (error) {
console.error('登出失败:', error)

View File

@ -747,6 +747,7 @@ export default {
privacy_policy: '《隐私政策》',
agreement_and: '和',
agreement_required: '请先阅读并同意用户协议和隐私政策',
wechat_login_button: '微信授权登录',
},
payment: {
methods: '支付方式',
@ -2447,6 +2448,7 @@ export default {
privacy_policy: 'Privacy Policy',
agreement_and: 'and',
agreement_required: 'Please read and agree to the User Agreement and Privacy Policy first',
wechat_login_button: 'WeChat Authorization Login',
},
payment: {
methods: 'Payment Methods',

View File

@ -24,13 +24,27 @@ import {ElMessage} from 'element-plus'
import dtUI from '@deotaland/ui'
import '@deotaland/ui/style.css'
import { environmentUtils,WechatBus,isWeChatBrowser } from '@deotaland/utils';
const app = createApp(App)
window.setElMessage = (options={})=>{
ElMessage[options.type || 'info'](options.message || '请求失败')
}
if(isWeChatBrowser()){
new WechatBus()
const getHashParam = (name) => {
const hash = window.location.hash
const queryStart = hash.indexOf('?')
if (queryStart === -1) return null
const queryString = hash.substring(queryStart + 1)
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
const r = queryString.match(reg)
if (r != null) return decodeURIComponent(r[2])
return null
}
const accessToken = getHashParam('accessToken')
if (accessToken) {
window.localStorage.setItem('token', accessToken)
}
}
const app = createApp(App)
// environmentUtils.detectEnvironment().then((env)=>{
// console.log('当前环境:', env)
// })
@ -52,9 +66,8 @@ app.use(pinia)
const i18n = createI18n(i18nConfig)
app.use(i18n)
// Router & UI
app.use(router)
app.use(ElementPlus)
app.use(router)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}

View File

@ -1,6 +1,7 @@
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { nextTick } from 'vue'
import {WechatBus} from '@deotaland/utils';
import NProgress from 'nprogress'
const ModernHome = () => import('../views/ModernHome/ModernHome.vue')
const List = () => import('../views/List.vue')
@ -210,6 +211,18 @@ const router = createRouter({
history: createWebHashHistory(),
routes,
})
window.Redirectlogin = () => {
localStorage.removeItem('token')
localStorage.removeItem('auth')
removeDynamicRoutes()
if(isWeChatBrowser()){//如果是微信浏览器,跳转到现代首页
WechatBus.BusWechartForNavigate('/pages/loginout/index',{
},'2')
return
}
// 恢复默认路由
router.push('/login')
}
// 路由守卫
router.beforeEach(async (to, from, next) => {
NProgress.start()
@ -236,6 +249,13 @@ router.beforeEach(async (to, from, next) => {
const token = localStorage.getItem('token')
// 如果没有 token跳转到登录页
if (!token) {
if(isWeChatBrowser()){//如果是微信浏览器,跳转到现代首页
setTimeout(() => {
WechatBus.BusWechartForNavigate('/pages/loginout/index',{
},'2')
}, 200);
return
}
next('/login')
return
}
@ -293,12 +313,7 @@ function isDynamicRoute(path) {
return regex.test(path)
})
}
window.Redirectlogin = () => {
localStorage.removeItem('token')
// 恢复默认路由
removeDynamicRoutes()
router.push('/login')
}
router.afterEach(() => {
NProgress.done()
})

View File

@ -49,6 +49,10 @@ export const useAuthStore = defineStore('auth', () => {
}
//返回用户信息
const updateUserInfo = async () => {
let tokenWindow = window.localStorage.getItem('token')
if(tokenWindow){
token.value = tokenWindow
}
if(!token.value){
return
}

View File

@ -152,9 +152,14 @@ const goToPhoneLogin = () => {
//
//
onMounted(() => {
const token = window.localStorage.getItem('token')
if(token){
router.replace('/czhome')
return
}
// detectEnvironment()
// isWeChatBrowser()&&goToPhoneLogin()
goToPhoneLogin()
isWeChatBrowser()&&goToPhoneLogin()
// goToPhoneLogin()
})
</script>

View File

@ -78,7 +78,7 @@ import { ElMessageBox, ElMessage } from 'element-plus'
import OrderCard from '@/components/OrderCard.vue'
import { useOrderStore } from '@/stores/orders'
import {OrderManagement} from './OrderManagement'
import {orderStatus} from '@deotaland/utils'
import {orderStatus,isWeChatBrowser,WechatBus} from '@deotaland/utils'
const orderPlug = new OrderManagement()
const { t } = useI18n()
const router = useRouter()
@ -93,7 +93,26 @@ const viewOrderDetails = (orderData) => {
console.log(orderData);
router.push({ name: 'order-detail', params: { orderId:orderData.id } })
}
const handlePayOrder = (orderData) => {
const handlePayOrder = (orderData) => {//
console.log(orderData);
if(isWeChatBrowser()){
const order_info = orderData.order_info
if(!order_info.pay_params){
ElMessage.error('当前订单不属于小程序订单')
return
}
const token = window.localStorage.getItem('token')
WechatBus.BusWechartForNavigate('/pages/pay/pay',{
method:'pay',
payData:JSON.stringify({
...orderData.order_info,
token:token,
amount:orderData.order_info.amount,
order_no:orderData.order_no,
})
})
return
}
window.location.href = orderData.stripe_url
}
//

View File

@ -84,6 +84,7 @@ import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import LanguageToggle from '@/components/ui/LanguageToggle.vue'
import { PointsRecharge } from './index.js'
import { WechatBus,isWeChatBrowser } from '@deotaland/utils'
const pointsRecharge = new PointsRecharge()
const { t } = useI18n()
const router = useRouter()
@ -109,9 +110,22 @@ const selectPlan = (planId) => {
}
const purchasePlan = (pkg) => {
console.log(pkg,'pkgpkg');
let parmas = {
package_id: pkg.id,
}
if(isWeChatBrowser()){
const token = localStorage.getItem('token') || ''
WechatBus.BusWechartForNavigate('/pages/pay/payPoint',{
method:'pay',
payData:JSON.stringify({
package_id: pkg.id,
credits:pkg.credits,
amount:pkg.amount,
token:token})
},'1')
return
}
pointsRecharge.confirmPay(parmas)
}

View File

@ -1,12 +1,12 @@
<template>
<div class="agreement-page">
<div class="page-header">
<button class="back-button" @click="goBack">
<!-- <div class="page-header"> -->
<!-- <button class="back-button" @click="goBack">
<el-icon class="back-icon"><ArrowLeft /></el-icon>
<span class="back-text">{{ t('common.back') }}</span>
</button>
</button> -->
<!-- <h1 class="page-title">{{ pageTitle }}</h1> -->
</div>
<!-- </div> -->
<div class="content-container">
<div v-if="loading" class="loading-container">

View File

@ -3,6 +3,7 @@ const pay = {
createCheckoutSession:{url:'/createCheckoutSession',method:'POST'},// 创建会话支付(购物车)
createPayorOrder:{url:'/api-core/front/stripe/create-and-checkout',method:'POST'},//根据产品ID创建订单并跳转支付
getProductList:{url:'/api-core/front/stripe/product/list',method:'POST'},//获取产品列表
calculateUnitAmount:{url:'/api-core/front/stripe/calculate-unit-amount',method:'POST'}//刷新支付金额
calculateUnitAmount:{url:'/api-core/front/stripe/calculate-unit-amount',method:'POST'},//刷新支付金额
createWechatPay:{url:'/api-core/front/wechat/create',method:'POST'}//微信小程序支付
}
export default pay;

View File

@ -1,6 +1,7 @@
// import { loadStripe } from '@stripe/stripe-js';
import { request as requestUtils } from '../utils/request.js'
import * as clientApi from '../api/frontend/index.js'
import { WechatBus } from '../utils/wechaBus.js'
//获取Stripe公钥
export function getStripePublishableKey() {
if (typeof window !== 'undefined') {
@ -189,9 +190,19 @@ export class PayServer {
1: clientApi.default.createPayorOrder,
2: clientApi.default.CREATE_RECHARGE_ORDER,
}[type]
// if(type==1&&WechatBus.isWeChatBrowser()){
// requestUrl = clientApi.default.createWechatPay
// }
let res = await requestUtils.common(requestUrl, pamras);
if (res.code == 0) {
let data = res.data
// if(WechatBus.isWeChatBrowser()){
// WechatBus.BusWechartForNavigate('/pages/pay/pay',{
// method:'pay',
// payData:JSON.stringify(data)
// })
// return
// }
// return
const loadUrl = data.url || data.payment_url
if(type==1){

View File

@ -17,7 +17,7 @@ const getEnvBaseURL = () => {
// }
var baseURL = '';
const hostname = window.location.hostname;
if(hostname=='localhost'){
if(hostname=='localhost'||hostname=='192.168.0.146'){
baseURL = '/api'
}else if(hostname.indexOf('deotaland.ai')>-1||hostname.indexOf('deota.cn')>-1){
baseURL = 'https://api.deotaland.ai'
@ -40,23 +40,24 @@ service.interceptors.request.use(
// 从localStorage中获取token如果存在
// console.log(config,'请求配置');
let token = localStorage.getItem('token');
if(config.url=='/api-core/front/s3/get-presigned-post'){
token = '123'
}
// if(config.url=='/api-core/front/s3/get-presigned-post'){
// token = '123'
// }
if (token) {
// 将token添加到请求头
config.headers['Authorization'] = `Bearer ${token}`;
const lang = localStorage.getItem('lang');
if (lang =='zh') {
config.headers['accept-language'] = 'zh-CN';
} else if (lang == 'en') {
config.headers['accept-language'] = 'en-US';
}
// config.headers['token'] = `${token}`;
// config.headers['Authorization'] = `123`;
// config.headers['token'] = `123`;
// config.headers['accept-language'] = 'en';
}
const lang = localStorage.getItem('lang');
if (lang =='zh') {
config.headers['accept-language'] = 'zh-CN';
} else if (lang == 'en') {
config.headers['accept-language'] = 'en-US';
}
return config;
},
error => {
@ -78,6 +79,7 @@ service.interceptors.response.use(
if(res.code&&res.code==200){
return res;
}
console.log(res,'resres');
if(res.code==1124){//重定向登录
window?.Redirectlogin()
}

View File

@ -28,6 +28,11 @@ export class WechatBus {
document.head.appendChild(script)
})
}
// 判断是否在微信浏览器中
static isWeChatBrowser() {
const ua = navigator.userAgent.toLowerCase()
return ua.indexOf('micromessenger') !== -1
}
static objectToUrlParams(obj, prefix = '') {
const params = []
for (const key in obj) {
@ -57,7 +62,7 @@ export class WechatBus {
return params
}
// 导航到微信小程序页面并且携带通信参数
static BusWechartForNavigate(url, data = {}) {
static BusWechartForNavigate(url, data = {},goType='1') {
let finalUrl = url
if (data && typeof data === 'object' && Object.keys(data).length > 0) {
const params = WechatBus.objectToUrlParams(data)
@ -66,7 +71,11 @@ export class WechatBus {
finalUrl = url + separator + params.join('&')
}
}
WechatBus.wx.miniProgram.navigateTo({
const type = {
1:'navigateTo',
2:'redirectTo',
}[goType]
WechatBus.wx.miniProgram[type]({
url: finalUrl
})
}