feat: 登录拦截功能完善

This commit is contained in:
duanshuwen
2025-09-13 22:01:50 +08:00
parent 11141ae436
commit 261fb16bd6
11 changed files with 139 additions and 119 deletions

View File

@@ -38,6 +38,12 @@ body,
// 重置按钮样式
.reset-btn {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1000;
background: none;
border: none;
outline: none;

View File

@@ -0,0 +1,18 @@
<template>
<button
v-if="!hasToken"
class="reset-btn"
open-type="getPhoneNumber"
@getphonenumber="onLogin"
/>
</template>
<script setup>
import { computed, defineEmits } from "vue";
import { useAppStore } from "@/store";
import { onLogin } from "@/hooks/useGoLogin";
const emits = defineEmits(["click"]);
const hasToken = computed(() => useAppStore().hasToken);
</script>

View File

@@ -22,9 +22,6 @@ export const onLogin = (e) => {
// 绑定手机号
bindPhone(params);
// 通知刷新
uni.$emit("TOKEN_CHANGE");
});
};

View File

@@ -1,14 +1,24 @@
export const getWeChatAuthCode = () => {
return new Promise((resolve, reject) => {
// 条件编译微信小程序、抖音小程序
let provider = "";
// #ifdef MP-WEIXIN
provider = "weixin";
// #endif
// #ifdef MP-TOUTIAO
provider = "toutiao";
// #endif
uni.login({
provider: 'weixin',
onlyAuthorize: true,
provider,
success: (res) => {
console.log("微信登录成功", res);
resolve(res.code);
},
fail: (err) => {
reject(err);
}
},
});
});
}
};

View File

@@ -4,6 +4,7 @@ import {
checkUserPhone,
} from "../request/api/LoginApi";
import { getWeChatAuthCode } from "./AuthManager";
import { useAppStore } from "@/store";
const loginAuth = () => {
return new Promise(async (resolve, reject) => {
@@ -20,6 +21,9 @@ const loginAuth = () => {
if (response.access_token) {
uni.setStorageSync("token", response.access_token);
const appStore = useAppStore();
appStore.setHasToken(true);
resolve();
} else {
reject(response.message || "登录失败");

View File

@@ -362,8 +362,16 @@ const initHandler = () => {
initWebSocket();
};
// 监听token变化
uni.$on("TOKEN_CHANGE", () => initHandler());
// 绑定成功,监听token变化,初始化
watch(
() => appStore.hasToken,
(newValue) => {
if (newValue) {
initHandler();
}
}
);
onMounted(() => {
try {

View File

@@ -6,26 +6,22 @@
v-for="(item, index) in itemList"
:key="index"
>
<button
class="reset-btn more-tips-item-title"
:open-type="needAuth ? 'getPhoneNumber' : ''"
@getphonenumber="handleGetPhoneNumber"
@click="handleClick(item)"
>
<view class="more-tips-item-title" @click="sendReply(item)">
<Interceptor />
{{ item }}
</button>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { defineProps, ref } from "vue";
import { onLogin, checkToken } from "@/hooks/useGoLogin";
import { defineProps } from "vue";
import { checkToken } from "@/hooks/useGoLogin";
import Interceptor from "@/components/Interceptor/index.vue";
const emits = defineEmits(["replySent"]);
const needAuth = ref(true);
let pendingText = "";
defineProps({
itemList: {
@@ -43,39 +39,8 @@ defineProps({
});
const sendReply = (text) => {
checkToken().then(() => {
emits("replySent", text); // 向父组件传递数据
});
};
// 处理点击事件
const handleClick = (text) => {
// 检查本地token
const token = uni.getStorageSync("token");
if (token) {
// 情况2token有值直接发送回复此时open-type为空字符串
needAuth.value = false;
sendReply(text);
} else {
// 情况1token没有值设置需要授权状态触发微信授权
needAuth.value = true;
pendingText = text;
// 由于open-type已经动态绑定为'getPhoneNumber',点击会自动触发授权
}
};
// 处理微信授权回调
const handleGetPhoneNumber = async (e) => {
await onLogin(e);
// 授权成功后发送之前存储的文本
if (pendingText) {
sendReply(pendingText);
pendingText = "";
}
needAuth.value = false;
// 向父组件传递数据
checkToken().then(() => emits("replySent", text));
};
</script>

View File

@@ -21,6 +21,7 @@
flex-direction: column;
flex-shrink: 0;
white-space: nowrap;
position: relative;
.more-tips-item-title {
font-weight: 500;

View File

@@ -7,7 +7,9 @@
:key="index"
>
<view class="mk-card-item" @click="sendReply(item)">
<image :src="item.coverPhoto" mode="aspectFill"></image>
<Interceptor />
<image class="card-img" :src="item.coverPhoto" mode="aspectFill" />
<view class="overlay-gradient">
<text class="overlay-text">{{ item.topic }}</text>
</view>
@@ -18,9 +20,11 @@
</template>
<script setup>
import ModuleTitle from "@/components/ModuleTitle/index.vue";
import { defineProps } from "vue";
import { RECOMMEND_POSTS_TITLE } from "@/constant/constant.js";
import { RECOMMEND_POSTS_TITLE } from "@/constant/constant";
import { checkToken } from "@/hooks/useGoLogin";
import Interceptor from "@/components/Interceptor/index.vue";
import ModuleTitle from "@/components/ModuleTitle/index.vue";
const props = defineProps({
recommendTheme: {
@@ -30,63 +34,13 @@ const props = defineProps({
});
const sendReply = (item) => {
checkToken().then(() => {
const topic = item.userInputContent || item.topic.replace(/^#/, "");
uni.$emit(RECOMMEND_POSTS_TITLE, topic);
});
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
}
.container-scroll {
display: flex;
flex-direction: row;
overflow-x: auto;
margin: 4px 0 6px;
.mk-card-item {
flex-shrink: 0; /* 关键:防止 flex 布局压缩子元素宽度 */
width: 142px;
height: 126px;
border-radius: 10px;
overflow: hidden;
margin-right: 8px;
position: relative;
image {
width: 100%;
height: 100%;
display: block;
}
/* 渐变背景层 */
.overlay-gradient {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 50px; /* 渐变层高度,可调 */
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.001) 0%,
rgba(0, 0, 0, 0.5) 100%
);
display: flex;
align-items: flex-end; /* 文字贴近底部 */
padding: 0 8px 6px; /* 内边距让文字与边缘保持距离 */
box-sizing: border-box;
}
/* 渐变层上的文字 */
.overlay-text {
color: #fff;
font-weight: 500;
font-size: 12px;
text-align: left;
width: 100%;
}
}
}
@import "./styles/RecommendPostsList.scss";
</style>

View File

@@ -0,0 +1,53 @@
.container {
width: 100%;
}
.container-scroll {
display: flex;
flex-direction: row;
overflow-x: auto;
margin: 4px 0 6px;
}
.mk-card-item {
flex-shrink: 0; /* 关键:防止 flex 布局压缩子元素宽度 */
width: 142px;
height: 126px;
border-radius: 10px;
overflow: hidden;
margin-right: 8px;
position: relative;
.card-img {
width: 100%;
height: 100%;
display: block;
}
/* 渐变背景层 */
.overlay-gradient {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 50px; /* 渐变层高度,可调 */
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.001) 0%,
rgba(0, 0, 0, 0.5) 100%
);
display: flex;
align-items: flex-end; /* 文字贴近底部 */
padding: 0 8px 6px; /* 内边距让文字与边缘保持距离 */
box-sizing: border-box;
}
/* 渐变层上的文字 */
.overlay-text {
color: #fff;
font-weight: 500;
font-size: 12px;
text-align: left;
width: 100%;
}
}

View File

@@ -5,6 +5,7 @@ export const useAppStore = defineStore("app", {
return {
title: "",
sceneId: "",
hasToken: false,
};
},
getters: {},
@@ -16,6 +17,9 @@ export const useAppStore = defineStore("app", {
setSceneId(data) {
this.sceneId = data;
},
setHasToken(data) {
this.hasToken = data;
},
},
unistorage: true,