增加登录组件
This commit is contained in:
+12
-1
@@ -1,14 +1,17 @@
|
||||
<script setup>
|
||||
// 路由转发页面无需额外组件引入
|
||||
import api from './utils/api.js';
|
||||
import { onMounted } from 'vue'
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import { WechatAuth } from '@/utils/wechat'
|
||||
import LoginModal from './components/LoginModal.vue'
|
||||
import loginService from './services/loginService'
|
||||
|
||||
// 获取当前URL参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
// const cfUid = urlParams.get('cfUid');
|
||||
const friend_account_id = urlParams.get('friend_account_id');
|
||||
const accountId = urlParams.get('accountId');
|
||||
const loginModal = ref(null) // 创建 ref
|
||||
|
||||
//微信环境
|
||||
if(WechatAuth.isWechatBrowser()){
|
||||
@@ -38,6 +41,12 @@ onMounted(() => {
|
||||
// arguments: [{ is_auto: false }]
|
||||
// })
|
||||
// }
|
||||
nextTick(() => { // 使用 nextTick 而不是 this.$nextTick
|
||||
if (loginModal.value) { // 使用 .value 访问 ref 的值
|
||||
loginService.register(loginModal.value)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -58,6 +67,8 @@ onMounted(() => {
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
<!-- 全局登录弹窗 -->
|
||||
<LoginModal ref="loginModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<!-- LoginModal.vue -->
|
||||
<template>
|
||||
<div style="--van-popup-background:transparent;--van-cell-background:transparent;">
|
||||
<van-dialog v-model:show="isVisible" :show-confirm-button="false" :closeOnClickOverlay="true">
|
||||
<div class="relative pd10">
|
||||
<div class="bg-fff ulib-rt20 inner30">
|
||||
<h3 class="text-center font-34">立即登录</h3>
|
||||
</div>
|
||||
<div class="pop-form mt5">
|
||||
<div class="bg-f2 ulib-r750 inner5 mt30">
|
||||
<van-field v-model="mobile" label="" type="tel" maxlength="11" required
|
||||
placeholder="请输入您的常用手机号码"/>
|
||||
</div>
|
||||
<div class="bg-f2 ulib-r750 inner5 mt30">
|
||||
<van-field v-model="code" label="" placeholder="验证码" maxlength="4" required type="number"
|
||||
inputmode="numeric">
|
||||
<template #button>
|
||||
<span v-if="!is_show_count" class="text-color-theme font-26" @click.stop="getSmsCode">发送验证码</span>
|
||||
<van-count-down class="color-ccc font-26" v-else :time="count_time" @finish="onCountFinish"
|
||||
format="ss 秒后重发"/>
|
||||
</template>
|
||||
</van-field>
|
||||
</div>
|
||||
<div class="mt30">
|
||||
<van-button round type="danger" class="w100" :disabled="!(mobile && code)" @click.stop="handleLogin">
|
||||
确定登录
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import api from '../utils/api.js'
|
||||
import { showToast, showDialog, Lazyload, Swipe, SwipeItem } from 'vant' // 导入Toast组件
|
||||
|
||||
// 响应式数据
|
||||
const isVisible = ref(false)
|
||||
const mobile = ref('')
|
||||
const code = ref('')
|
||||
const errorMessage = ref('')
|
||||
const callback = ref(null)
|
||||
const is_show_count = ref(false)
|
||||
const count_time = ref(60000)
|
||||
|
||||
// 显示模态框
|
||||
const showModal = (cb) => {
|
||||
callback.value = cb
|
||||
isVisible.value = true
|
||||
errorMessage.value = ''
|
||||
}
|
||||
|
||||
// 关闭模态框
|
||||
const closeModal = () => {
|
||||
isVisible.value = false
|
||||
mobile.value = ''
|
||||
code.value = ''
|
||||
errorMessage.value = ''
|
||||
}
|
||||
/**
|
||||
* 获取短信验证码
|
||||
*/
|
||||
const getSmsCode = async () => {
|
||||
// 验证手机号
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号')
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateMobile(mobile.value)) {
|
||||
showToast('请输入正确的手机号格式')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用获取验证码接口
|
||||
const result = await api.post('/auto/sms/login', { mobile: mobile.value })
|
||||
|
||||
if (result.code === 200) {
|
||||
showToast('验证码发送成功')
|
||||
// 开始倒计时
|
||||
showCount()
|
||||
} else {
|
||||
showToast(result.message || '验证码发送失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取验证码失败:', error)
|
||||
showToast('获取验证码失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
function showCount() {
|
||||
is_show_count.value = true
|
||||
count_time.value = 60000
|
||||
}
|
||||
|
||||
function onCountFinish() {
|
||||
is_show_count.value = false
|
||||
}
|
||||
|
||||
// 处理登录
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
const response = await api.post('/auto/login/mobile', {
|
||||
mobile: mobile.value,
|
||||
code: code.value,
|
||||
})
|
||||
if (response.code === 200 && response.data.Authorization) {
|
||||
localStorage.setItem('token', response.data.Authorization)
|
||||
closeModal()
|
||||
if (callback.value) {
|
||||
callback.value()
|
||||
}
|
||||
} else {
|
||||
showToast(response.message || '登录失败')
|
||||
}
|
||||
} catch (error) {
|
||||
errorMessage.value = '登录失败,请稍后再试'
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 验证手机号格式
|
||||
* @param {string} phone - 手机号
|
||||
* @returns {boolean} - 是否是有效的手机号
|
||||
*/
|
||||
const validateMobile = (phone) => {
|
||||
const reg = /^1[3-9]\d{9}$/
|
||||
return reg.test(phone)
|
||||
}
|
||||
// 暴露给父组件的方法
|
||||
defineExpose({
|
||||
showModal,
|
||||
closeModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pd10 {
|
||||
padding: 4vw;
|
||||
}
|
||||
</style>
|
||||
@@ -6,11 +6,11 @@
|
||||
<h3 class="text-center font-34">领取补贴券</h3>
|
||||
<div class="mt20">
|
||||
<CouponItem
|
||||
:price-num="coupons.price"
|
||||
:desc-left="coupons.getNun>0?'已有' + coupons.getNun + '人领取':''"
|
||||
:title="coupons.typeCn"
|
||||
:desc-right="detail.discounts2"
|
||||
:is-active="true"
|
||||
:price-num="coupons.price"
|
||||
:desc-left="coupons.getNun>0?'已有' + coupons.getNun + '人领取':''"
|
||||
:title="coupons.typeCn"
|
||||
:desc-right="detail.discounts2"
|
||||
:is-active="true"
|
||||
/>
|
||||
</div>
|
||||
<!--
|
||||
@@ -20,29 +20,34 @@
|
||||
-->
|
||||
<div class="pop-form mt5">
|
||||
<div class="bg-f2 ulib-r750 inner5 mt30">
|
||||
<van-field v-model="mobile" label="" placeholder="请输入您的常用手机号码" />
|
||||
<van-field v-model="mobile" label="" placeholder="请输入您的常用手机号码"/>
|
||||
</div>
|
||||
<div class="bg-f2 ulib-r750 inner5 mt30">
|
||||
<van-field v-model="code" label="" placeholder="验证码" maxlength="4" type="number" inputmode="numeric">
|
||||
<template #button>
|
||||
<span v-if="!is_show_count" @click.stop="getSmsCode" class="text-color-theme font-26">发送验证码</span>
|
||||
<van-count-down class="color-ccc font-26" v-else :time="count_time" format="ss 秒后重发" @finish="onCountFinish" />
|
||||
<span v-if="!is_show_count" @click.stop="getSmsCode"
|
||||
class="text-color-theme font-26">发送验证码</span>
|
||||
<van-count-down class="color-ccc font-26" v-else :time="count_time" format="ss 秒后重发"
|
||||
@finish="onCountFinish"/>
|
||||
</template>
|
||||
</van-field>
|
||||
</div>
|
||||
<div class="text-center font-24 mt30">领取即同意
|
||||
<span v-for="(item,index) in item_pop_bottom_info" :key="index" class="color-184ebb" @click="showPopContent(item)">{{ item.title }}</span></div>
|
||||
<span v-for="(item,index) in item_pop_bottom_info" :key="index" class="color-184ebb"
|
||||
@click="showPopContent(item)">{{ item.title }}</span></div>
|
||||
<div class="mt30">
|
||||
<van-button round type="danger" :disabled="!(mobile && code)" block class="w100" @click.stop="bindPostCoupon">立即领取</van-button>
|
||||
</div>
|
||||
<van-button round type="danger" :disabled="!(mobile && code)" block class="w100"
|
||||
@click.stop="bindPostCoupon">立即领取
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute right-0 top-0 mr20" :style="{'margin-top': 0/7.5+'vw'}">
|
||||
<van-icon @click="handleClose" name="close" color="#fff" size="24"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
<PopContent :content="content" :show-pop="showContentPop" @update:show-pop="showContentPop = $event" />
|
||||
<PopContent :content="content" :show-pop="showContentPop" @update:show-pop="showContentPop = $event"/>
|
||||
<van-dialog v-model:show="showConfirm" confirmButtonColor="#f84803">
|
||||
<div class="mt40 text-color-theme inner10 text-center font-26">
|
||||
<div>补贴名额有限,抓紧时间领取吧!</div>
|
||||
@@ -57,7 +62,7 @@
|
||||
</van-swipe>
|
||||
-->
|
||||
<div>
|
||||
<van-image fit="cover" style="width:150px;height:150px" :src="qrImage" />
|
||||
<van-image fit="cover" style="width:150px;height:150px" :src="qrImage"/>
|
||||
</div>
|
||||
<!--
|
||||
<vue-qrcode class="qrcode" value="https://example.com"/>
|
||||
@@ -76,11 +81,11 @@ import { ref, reactive, defineEmits, watch } from 'vue'
|
||||
import CouponItem from '@/components/CouponItem.vue' // 导入CouponItem组件
|
||||
import PopContent from '@/components/PopContent.vue' // 导入PopContent组件
|
||||
import api from '@/utils/api' // 导入API模块
|
||||
import { showToast,showDialog,Lazyload,Swipe, SwipeItem } from 'vant' // 导入Toast组件
|
||||
import { showToast, showDialog, Lazyload, Swipe, SwipeItem } from 'vant' // 导入Toast组件
|
||||
import { getBasicConfig } from '@/utils/basicSetting'
|
||||
import VueQrcode from 'vue-qrcode'; // 直接导入
|
||||
import VueQrcode from 'vue-qrcode' // 直接导入
|
||||
|
||||
const emit = defineEmits(['update:showPop','showStorePop'])
|
||||
const emit = defineEmits(['update:showPop', 'showStorePop'])
|
||||
defineOptions({
|
||||
name: 'PopGetAllowance'
|
||||
})
|
||||
@@ -89,27 +94,27 @@ const props = defineProps({
|
||||
showPop: { type: Boolean, default: false }, // 控制弹窗的显示和隐藏
|
||||
coupons: { type: Object, default: () => ({}) }, // 补贴信息
|
||||
detail: { type: Object, default: () => ({}) }, // 补贴信息
|
||||
cityInfo: { type: Object, default: () => ({})}, // 城市信息
|
||||
cityInfo: { type: Object, default: () => ({}) }, // 城市信息
|
||||
})
|
||||
// Ensure slot 'value' is called inside template/render function
|
||||
const mobile = ref('');
|
||||
const code = ref('');
|
||||
const is_show_count = ref(false);
|
||||
const count_time = ref(60000);
|
||||
const showConfirm = ref(false);
|
||||
const mobile = ref('')
|
||||
const code = ref('')
|
||||
const is_show_count = ref(false)
|
||||
const count_time = ref(60000)
|
||||
const showConfirm = ref(false)
|
||||
const qrImages = ref([
|
||||
"https://img.liche.cn/space/agent/admin/202509/p_56bb15d5873104537cd529832fb8521b.png",
|
||||
"https://img.liche.cn/space/agent/admin/202509/p_bdce5bb61375127d3dc9f51ee7519fa3.png",
|
||||
"https://img.liche.cn/space/agent/admin/202509/p_cf960a64eb62c7aa3cd25a3e81f9fe2d.png"
|
||||
'https://img.liche.cn/space/agent/admin/202509/p_56bb15d5873104537cd529832fb8521b.png',
|
||||
'https://img.liche.cn/space/agent/admin/202509/p_bdce5bb61375127d3dc9f51ee7519fa3.png',
|
||||
'https://img.liche.cn/space/agent/admin/202509/p_cf960a64eb62c7aa3cd25a3e81f9fe2d.png'
|
||||
])
|
||||
const qrImage = ref('');
|
||||
const qrImage = ref('')
|
||||
//随机取一张qrImages图片
|
||||
qrImage.value = qrImages.value[Math.floor(Math.random() * qrImages.value.length)];
|
||||
qrImage.value = qrImages.value[Math.floor(Math.random() * qrImages.value.length)]
|
||||
|
||||
watch(() => props.showPop, async(val) => {
|
||||
console.log('showPop', val);
|
||||
watch(() => props.showPop, async (val) => {
|
||||
console.log('showPop', val)
|
||||
if (val) {
|
||||
await getBottomInfoAgreeMent();
|
||||
await getBottomInfoAgreeMent()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -119,9 +124,9 @@ watch(() => props.showPop, async(val) => {
|
||||
* @returns {boolean} - 是否是有效的手机号
|
||||
*/
|
||||
const validateMobile = (phone) => {
|
||||
const reg = /^1[3-9]\d{9}$/;
|
||||
return reg.test(phone);
|
||||
};
|
||||
const reg = /^1[3-9]\d{9}$/
|
||||
return reg.test(phone)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -130,58 +135,58 @@ const validateMobile = (phone) => {
|
||||
const getSmsCode = async () => {
|
||||
// 验证手机号
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号');
|
||||
return;
|
||||
showToast('请输入手机号')
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateMobile(mobile.value)) {
|
||||
showToast('请输入正确的手机号格式');
|
||||
return;
|
||||
showToast('请输入正确的手机号格式')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用获取验证码接口
|
||||
const result = await api.post('/auto/sms', { mobile: mobile.value });
|
||||
const result = await api.post('/auto/sms', { mobile: mobile.value })
|
||||
|
||||
if (result.code === 200) {
|
||||
showToast('验证码发送成功');
|
||||
showToast('验证码发送成功')
|
||||
// 开始倒计时
|
||||
showCount();
|
||||
showCount()
|
||||
} else {
|
||||
showToast(result.message || '验证码发送失败');
|
||||
showToast(result.message || '验证码发送失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取验证码失败:', error);
|
||||
showToast('获取验证码失败,请稍后重试');
|
||||
console.error('获取验证码失败:', error)
|
||||
showToast('获取验证码失败,请稍后重试')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 防双击状态
|
||||
const isSubmitting = ref(false);
|
||||
const isSubmitting = ref(false)
|
||||
|
||||
const bindPostCoupon = async () => {
|
||||
// 防双击检查
|
||||
if (isSubmitting.value) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号');
|
||||
return;
|
||||
showToast('请输入手机号')
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateMobile(mobile.value)) {
|
||||
showToast('请输入正确的手机号格式');
|
||||
return;
|
||||
showToast('请输入正确的手机号格式')
|
||||
return
|
||||
}
|
||||
|
||||
if (!code.value) {
|
||||
showToast('请输入验证码');
|
||||
return;
|
||||
showToast('请输入验证码')
|
||||
return
|
||||
}
|
||||
|
||||
// 设置提交状态
|
||||
isSubmitting.value = true;
|
||||
isSubmitting.value = true
|
||||
|
||||
///auto/car/coupon
|
||||
try {
|
||||
@@ -190,37 +195,37 @@ const bindPostCoupon = async () => {
|
||||
code: code.value,
|
||||
couponId: props.coupons.coupon_id,
|
||||
cityId: props.cityInfo.cityId
|
||||
});
|
||||
})
|
||||
|
||||
if (result.code === 200) {
|
||||
handleSuccess();
|
||||
handleSuccess()
|
||||
} else {
|
||||
showToast(result.message || '补贴领取失败');
|
||||
showToast(result.message || '补贴领取失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('补贴领取失败:', error);
|
||||
showToast('补贴领取失败,请稍后重试');
|
||||
console.error('补贴领取失败:', error)
|
||||
showToast('补贴领取失败,请稍后重试')
|
||||
} finally {
|
||||
// 重置提交状态
|
||||
isSubmitting.value = false;
|
||||
isSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const showContentPop = ref(false);
|
||||
const showContentPop = ref(false)
|
||||
|
||||
const content = ref('');
|
||||
const content = ref('')
|
||||
const item_pop_bottom_info = ref([])
|
||||
const getBottomInfoAgreeMent = async () => {
|
||||
const getBottomInfoAgreeMent = async () => {
|
||||
item_pop_bottom_info.value = await getBasicConfig('item_bottom')
|
||||
}
|
||||
|
||||
const showPopContent = (item) => {
|
||||
content.value = item.content;
|
||||
showContentPop.value = true;
|
||||
};
|
||||
content.value = item.content
|
||||
showContentPop.value = true
|
||||
}
|
||||
|
||||
function handleSuccess(){
|
||||
function handleSuccess() {
|
||||
emit('update:showPop', false)
|
||||
emit('success', true)
|
||||
}
|
||||
@@ -229,17 +234,17 @@ function handleSuccess(){
|
||||
function handleClose() {
|
||||
// 关闭弹窗逻辑
|
||||
console.log('close')
|
||||
showConfirm.value = true;
|
||||
showConfirm.value = true
|
||||
emit('update:showPop', false)
|
||||
}
|
||||
|
||||
function showCount() {
|
||||
is_show_count.value = true;
|
||||
count_time.value = 60000;
|
||||
is_show_count.value = true
|
||||
count_time.value = 60000
|
||||
}
|
||||
|
||||
function onCountFinish() {
|
||||
is_show_count.value = false;
|
||||
is_show_count.value = false
|
||||
}
|
||||
|
||||
function handleShowStores() {
|
||||
|
||||
+27
-24
@@ -1,30 +1,32 @@
|
||||
<template>
|
||||
<div class="side-menu fixed z-index-1 bottom-0 right-0 mb50 mr30 fn-flex fn-flex-center fn-flex-column">
|
||||
<ul class="ulib-r750 bg-000-op60 text-center">
|
||||
<li class="" v-for="(item, index) in menuItems" :key="index" >
|
||||
<template v-if="name">
|
||||
<router-link :to="item.path" v-if="name === item.name">
|
||||
<div class="imgsize-80X80 fn-flex fn-flex-column fn-flex-center justify-center text-center font-24">
|
||||
<i :class="[item.icon,'color-fff']"></i>
|
||||
<span class="color-fff mt10">{{ item.name }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
<template v-else>
|
||||
<router-link :to="item.path" v-if="route.path !== item.path">
|
||||
<div class="imgsize-80X80 fn-flex fn-flex-column fn-flex-center justify-center text-center font-24">
|
||||
<i :class="[item.icon,'color-fff']"></i>
|
||||
<span class="color-fff mt10">{{ item.name }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
</li>
|
||||
<li class="" v-for="(item, index) in menuItems" :key="index">
|
||||
<template v-if="name">
|
||||
<router-link :to="item.path" v-if="name === item.name">
|
||||
<div class="imgsize-80X80 fn-flex fn-flex-column fn-flex-center justify-center text-center font-24">
|
||||
<i :class="[item.icon,'color-fff']"></i>
|
||||
<span class="color-fff mt10">{{ item.name }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
<template v-else>
|
||||
<router-link :to="item.path" v-if="route.path !== item.path">
|
||||
<div class="imgsize-80X80 fn-flex fn-flex-column fn-flex-center justify-center text-center font-24">
|
||||
<i :class="[item.icon,'color-fff']"></i>
|
||||
<span class="color-fff mt10">{{ item.name }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="route.path=='/'" class="mt20 imgsize-100X100 text-center font-24 pos-rel">
|
||||
<img src="@/assets/side-link.png" alt="">
|
||||
<wx-open-launch-weapp id="launch-btn" :appid="third_mp.appId" :username="third_mp.username" :path="third_mp.path" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
|
||||
<wx-open-launch-weapp id="launch-btn" :appid="third_mp.appId" :username="third_mp.username" :path="third_mp.path"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
|
||||
<component :is="'script'" type="text/wxtag-template">
|
||||
<div class="btn" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;opacity: 0;">打开小程序</div>
|
||||
<div class="btn" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;opacity: 0;">打开小程序
|
||||
</div>
|
||||
</component>
|
||||
</wx-open-launch-weapp>
|
||||
</div>
|
||||
@@ -33,16 +35,17 @@
|
||||
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type:String,
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
})
|
||||
const menuItems = [
|
||||
{ name: '首页', icon: 'icon-custom icon-home', path: '/' },
|
||||
{ name: '我的', icon: 'icon-custom icon-my', path: '/my' }
|
||||
{ name: '首页', icon: 'icon-custom icon-home', path: '/', needLogin: false },
|
||||
{ name: '我的', icon: 'icon-custom icon-my', path: '/my', needLogin: true }
|
||||
]
|
||||
const third_mp = {
|
||||
appId: 'wx740f441fe242082c',
|
||||
|
||||
@@ -4,11 +4,13 @@ import router from './router' // 引入路由
|
||||
import Vant from 'vant'
|
||||
import 'vant/lib/index.css'
|
||||
import App from './App.vue'
|
||||
import AuthPlugin from './plugins/auth'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(createPinia()) // 挂载Pinia
|
||||
app.use(router)
|
||||
app.use(Vant)
|
||||
app.use(AuthPlugin);
|
||||
app.mount('#app')
|
||||
import './style/pages/h5.scss'
|
||||
// import VConsole from 'vconsole'
|
||||
|
||||
+40
-6
@@ -110,13 +110,14 @@ import CouponItem from '@/components/CouponItem.vue'
|
||||
import PopGetAllowance from '@/components/PopGetAllowance.vue'
|
||||
import PopStores from '@/components/PopStores.vue'
|
||||
import SideMenu from '@/components/SideMenu.vue' // 导入SideMenu组件
|
||||
import { showDialog } from 'vant' // 导入Toast组件
|
||||
import WechatUtils,{ WechatLocation, WechatShare } from '@/utils/wechat'
|
||||
import { showDialog, showToast } from 'vant' // 导入Toast组件
|
||||
import WechatUtils,{ WechatAuth,WechatLocation, WechatShare } from '@/utils/wechat'
|
||||
import { useUserStore } from '@/stores/user';
|
||||
// 导入 cookie 工具
|
||||
import { getCookie, setCookie } from '@/utils/cookie'
|
||||
import { getCurrentInstance } from 'vue'
|
||||
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
// 获取路由参数
|
||||
const route = useRoute()
|
||||
@@ -200,11 +201,11 @@ onMounted(async () => {
|
||||
let appid = localStorage.getItem('app_id')
|
||||
if(appid) {
|
||||
const wechat = await WechatUtils.init(appid);
|
||||
// 初始化完成后获取位置信息
|
||||
await getCurrentLocation();
|
||||
// 隐藏分享
|
||||
await WechatShare.hideAllNonBaseMenuItem();
|
||||
}
|
||||
// 初始化完成后获取位置信息
|
||||
await getCurrentLocation();
|
||||
getProductDetail()
|
||||
})
|
||||
|
||||
@@ -302,7 +303,40 @@ function showEnrollPop(){
|
||||
Key_Brand: productDetail.value.brandName,
|
||||
Key_Series: productDetail.value.seriesName
|
||||
});
|
||||
showPop.value=true
|
||||
// showPop.value=true
|
||||
if(WechatAuth.isWechatBrowser()){
|
||||
showPop.value=true
|
||||
}else{
|
||||
if (proxy && proxy.$auth) {
|
||||
proxy.$auth.require(() => {
|
||||
// 登录成功后执行的代码
|
||||
getCoupon();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
const isSubmitting = ref(false)
|
||||
|
||||
const getCoupon = async () => {
|
||||
// 设置提交状态
|
||||
isSubmitting.value = true
|
||||
try {
|
||||
const result = await api.post('/auto/car/coupon', {
|
||||
couponId: productDetail.value.coupons.coupon_id,
|
||||
cityId: cityInfo.value.cityId
|
||||
})
|
||||
|
||||
if (result.code === 200) {
|
||||
handleSuccess()
|
||||
} else {
|
||||
showToast(result.message || '补贴领取失败')
|
||||
}
|
||||
} catch (error) {
|
||||
showToast('补贴领取失败,请稍后重试')
|
||||
} finally {
|
||||
// 重置提交状态
|
||||
isSubmitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="login-page">
|
||||
<!-- 登录模态框组件 -->
|
||||
<LoginModal ref="loginModalRef" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import LoginModal from '@/components/LoginModal.vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const loginModalRef = ref(null)
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(async () => {
|
||||
loginModalRef.value.showModal(() => {
|
||||
// 登录成功的回调函数
|
||||
const redirectPath = route.query.redirect || '/dashboard'
|
||||
router.push(redirectPath)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,24 @@
|
||||
// plugins/auth.js
|
||||
import loginService from '../services/loginService'
|
||||
|
||||
const AuthPlugin = {
|
||||
install(app) {
|
||||
// 正确注入全局属性
|
||||
app.config.globalProperties.$auth = {
|
||||
check() {
|
||||
return loginService.isLoggedIn();
|
||||
},
|
||||
require(callback) {
|
||||
loginService.requireLogin(callback);
|
||||
},
|
||||
// user() {
|
||||
// return loginService.getCurrentUser ? loginService.getCurrentUser() : null;
|
||||
// }
|
||||
};
|
||||
|
||||
// 同时提供一个全局变量供测试使用
|
||||
window.$auth = app.config.globalProperties.$auth;
|
||||
}
|
||||
};
|
||||
|
||||
export default AuthPlugin;
|
||||
+24
-5
@@ -1,4 +1,6 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { sendVisitLog } from '@/utils/useStatistics'
|
||||
import loginService from '../services/loginService'
|
||||
import Home from '../pages/Home.vue'
|
||||
import About from '../pages/About.vue'
|
||||
import My from '../pages/My.vue'
|
||||
@@ -8,12 +10,13 @@ import MyOrder from '../pages/MyOrder.vue'
|
||||
import MyAllowance from '../pages/MyAllowance.vue'
|
||||
import MyAllowanceForm from '../pages/MyAllowanceForm.vue'
|
||||
import MyBank from '../pages/MyBank.vue'
|
||||
import {sendVisitLog} from '@/utils/useStatistics'
|
||||
import Login from '../pages/Login.vue'
|
||||
|
||||
const routes = [
|
||||
{ path: '/login', name: 'Login', component: Login },
|
||||
{ path: '/', name: 'Home', component: Home },
|
||||
{ path: '/about', name: 'About', component: About },
|
||||
{ path: '/my', name: 'My', component: My },
|
||||
{ path: '/my', name: 'My', component: My, meta: { requiresAuth: true } },
|
||||
{ path: '/item/:id', name: 'Item', component: Item },
|
||||
{ path: '/my/coupon', name: 'MyCoupon', component: MyCoupon },
|
||||
{ path: '/my/order', name: 'MyOrder', component: MyOrder },
|
||||
@@ -23,7 +26,23 @@ const routes = [
|
||||
]
|
||||
|
||||
const router = createRouter({ history: createWebHistory(), routes })
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 检查路由是否需要认证
|
||||
if (to.meta.requiresAuth) {
|
||||
// 检查用户是否已登录
|
||||
if (loginService.isLoggedIn()) {
|
||||
next()
|
||||
} else {
|
||||
next({
|
||||
name: 'Login',
|
||||
query: { redirect: to.fullPath } // 保存原目标路径
|
||||
})
|
||||
}
|
||||
} else {
|
||||
next() // 不需要认证的路由直接放行
|
||||
}
|
||||
})
|
||||
// 路由跳转后发送PV统计
|
||||
router.afterEach(() => {
|
||||
// 检查全局的aplus_queue是否存在
|
||||
@@ -34,7 +53,7 @@ router.afterEach(() => {
|
||||
// arguments: [{ is_auto: false }] // 按文档要求传递固定格式参数
|
||||
// })
|
||||
// }
|
||||
console.log("发送PV统计");
|
||||
sendVisitLog();
|
||||
console.log('发送PV统计')
|
||||
sendVisitLog()
|
||||
})
|
||||
export default router
|
||||
@@ -0,0 +1,33 @@
|
||||
// loginService.js
|
||||
class LoginService {
|
||||
constructor() {
|
||||
this.loginComponent = null;
|
||||
}
|
||||
|
||||
// 注册登录组件实例
|
||||
register(component) {
|
||||
this.loginComponent = component;
|
||||
}
|
||||
|
||||
// 检查是否已登录
|
||||
isLoggedIn() {
|
||||
// 根据实际情况判断是否登录,例如检查token或用户信息
|
||||
return !!localStorage.getItem('token');
|
||||
}
|
||||
|
||||
// 需要登录时调用此方法
|
||||
requireLogin(callback) {
|
||||
if (this.isLoggedIn()) {
|
||||
// 已登录,直接执行回调
|
||||
if (callback) callback();
|
||||
} else {
|
||||
// 未登录,显示登录弹窗
|
||||
if (this.loginComponent) {
|
||||
this.loginComponent.showModal(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例实例
|
||||
export default new LoginService();
|
||||
@@ -0,0 +1,27 @@
|
||||
// store/index.js
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
user: null
|
||||
},
|
||||
mutations: {
|
||||
SET_USER(state, user) {
|
||||
state.user = user;
|
||||
// 同时保存到localStorage
|
||||
if (user && user.token) {
|
||||
localStorage.setItem('token', user.token);
|
||||
}
|
||||
},
|
||||
LOGOUT(state) {
|
||||
state.user = null;
|
||||
localStorage.removeItem('token');
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
isLoggedIn: state => !!state.user
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user