feat: 更新登录弹窗组件路径,新增实时信息页面的登录弹窗实现

This commit is contained in:
傅光孟 2026-02-24 15:26:54 +08:00
parent 032b7a1dab
commit a90946ef89
10 changed files with 334 additions and 58 deletions

View File

@ -184,7 +184,7 @@ import {
onShareTimeline,
} from "@dcloudio/uni-app";
import articleMock from "@/mock/article.js";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import { Session } from "@/utils/storage";
import zhaiyaoImg from "../../assets/zixun/zhaiyao_icon.png";
import { useUserStore } from "@/stores/user";

View File

@ -1,57 +1,32 @@
<template>
<u-popup
class="loginPopup"
:show="props.show"
closeable
:mode="props.mode"
round="12"
:closeOnClickOverlay="false"
@close="handlePopupClose"
>
<!-- <view class="loginPopup"> -->
<u-popup class="loginPopup" :show="props.show" closeable :mode="props.mode" round="12" :closeOnClickOverlay="false"
@close="handlePopupClose">
<view class="loginPopupContent">
<view class="loginTitle">登录后掌握更多优质财经内容</view>
<!-- 登录表单 -->
<view class="loginForm">
<u--form :model="state.loginForm" ref="uForm">
<u-form-item
style="padding: 0"
class="loginFormItem"
prop="userInfo.name"
borderBottom
ref="item1"
>
<u--input
class="loginFormInput"
placeholder="请输入您的手机号"
v-model="state.loginForm.phone"
border="none"
></u--input>
<u-form-item style="padding: 0" class="loginFormItem" prop="userInfo.name" borderBottom ref="item1">
<u--input class="loginFormInput" placeholder="请输入您的手机号" v-model="state.loginForm.phone"
border="none"></u--input>
</u-form-item>
<u-form-item
class="loginFormItem"
prop="userInfo.name"
borderBottom
ref="item1"
>
<u--input
class="loginFormInput"
placeholder="请输入短信验证码"
v-model="state.loginForm.code"
border="none"
></u--input>
<u-form-item class="loginFormItem" prop="userInfo.name" borderBottom ref="item1">
<u--input class="loginFormInput" placeholder="请输入短信验证码" v-model="state.loginForm.code"
border="none"></u--input>
<view class="getCode" @click="captcha">{{ codeText }}</view>
</u-form-item>
</u--form>
<u-button class="loginFormBtn" text="登录" @click="Login"></u-button>
</view>
<!-- 用户协议 -->
<view class="tips"
>登录即代表已经阅读并同意
<view class="tips">登录即代表已经阅读并同意
<view class="userAgreement">用户协议</view>
</view>
</view>
</u-popup>
<!-- </view> -->
</template>
<script setup lang="ts">
@ -59,22 +34,23 @@ import { reactive, ref } from "vue";
import { getCaptcha, login } from "@/api";
import { validatePhoneNumber } from "@/utils/util";
import { Session } from "@/utils/storage";
import { useUserStore } from "@/stores/user";
const emit = defineEmits([
"handlePopupClose",
"handlePopupSuccessCallback",
"handlePopupErrorCallback",
]);
const emit = defineEmits(["onSuccess", "onError", "onCancel"]);
const props = defineProps({
//
show: {
type: Boolean,
default: () => false,
},
mode: {
type: String,
default: () => "bottom",
},
});
const userStore = useUserStore();
const codeText = ref("获取验证码");
const isDisabled = ref(false);
const state = reactive({
@ -84,7 +60,6 @@ const state = reactive({
},
});
//
const captcha = async () => {
if (!validatePhoneNumber(state.loginForm.phone)) {
return uni.showToast({
@ -121,13 +96,14 @@ const captcha = async () => {
};
//
const callbackSuccess = () => {
emit("onSuccess");
const handlePopupSuccessCallback = () => {
emit("handlePopupSuccessCallback");
};
//
const callBackError = () => {
emit("onError");
const handlePopupErrorCallback = () => {
emit("handlePopupErrorCallback");
};
const { aplus_queue } = window;
//
const Login = async () => {
@ -142,17 +118,50 @@ const Login = async () => {
icon: "none",
});
}
const result = await userStore.onLogin({ ...state.loginForm });
if (result.code === 200) {
callbackSuccess();
uni.showLoading({
title: "登录中",
mask: true,
});
const { code, data, msg } = await login({
phone: state.loginForm.phone,
smsCode: state.loginForm.code,
});
console.log(code, "<=== code");
if (code === 200) {
aplus_queue.push({
action: 'aplus.record',
arguments: ['login', 'CLK', {
phone: data.phone,
}]
});
uni.hideLoading();
Session.set("token", data.token);
Session.set("userPhone", data.phone);
uni.showToast({
title: "登录成功",
icon: "success",
});
handlePopupSuccessCallback();
} else {
callBackError();
console.log(msg, "<=== msg");
handlePopupErrorCallback();
uni.hideLoading();
uni.showToast({
title: msg,
icon: "error",
});
}
emit("handlePopupClose");
};
//
const handlePopupClose = () => {
emit("onCancel");
emit("handlePopupClose");
};
</script>

View File

@ -31,7 +31,7 @@
<script setup lang="ts">
import { useUserStore } from "@/stores/user";
import { computed, onMounted, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import CustomView from "./components/CustomView.vue";
import List from "./components/List.vue";
import { getMyTags, updateMyTags } from "@/api";

View File

@ -101,7 +101,7 @@
import { getForeignList } from "@/api";
import { useUserStore } from "@/stores/user";
import { computed, onMounted, reactive, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import { onReachBottom } from "@dcloudio/uni-app";
//

View File

@ -31,7 +31,7 @@
<script setup lang="ts">
import { useUserStore } from "@/stores/user";
import { computed, onMounted, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import CustomView from "./components/CustomView.vue";
import List from "./components/List.vue";
import { getMyIndustries, updateMyIndustries } from "@/api";

View File

@ -66,7 +66,7 @@
import { getMacroList } from "@/api";
import { useUserStore } from "@/stores/user";
import { computed, onMounted, reactive, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import { onReachBottom } from "@dcloudio/uni-app";
//
const handleBack = () => {

View File

@ -0,0 +1,267 @@
<template>
<u-popup
class="loginPopup"
:show="props.show"
closeable
:mode="props.mode"
round="12"
:closeOnClickOverlay="false"
@close="handlePopupClose"
>
<view class="loginPopupContent">
<view class="loginTitle">登录后掌握更多优质财经内容</view>
<!-- 登录表单 -->
<view class="loginForm">
<u--form :model="state.loginForm" ref="uForm">
<u-form-item
style="padding: 0"
class="loginFormItem"
prop="userInfo.name"
borderBottom
ref="item1"
>
<u--input
class="loginFormInput"
placeholder="请输入您的手机号"
v-model="state.loginForm.phone"
border="none"
></u--input>
</u-form-item>
<u-form-item
class="loginFormItem"
prop="userInfo.name"
borderBottom
ref="item1"
>
<u--input
class="loginFormInput"
placeholder="请输入短信验证码"
v-model="state.loginForm.code"
border="none"
></u--input>
<view class="getCode" @click="captcha">{{ codeText }}</view>
</u-form-item>
</u--form>
<u-button class="loginFormBtn" text="登录" @click="Login"></u-button>
</view>
<!-- 用户协议 -->
<view class="tips"
>登录即代表已经阅读并同意
<view class="userAgreement">用户协议</view>
</view>
</view>
</u-popup>
</template>
<script setup lang="ts">
import { reactive, ref } from "vue";
import { getCaptcha, login } from "@/api";
import { validatePhoneNumber } from "@/utils/util";
import { Session } from "@/utils/storage";
import { useUserStore } from "@/stores/user";
const emit = defineEmits(["onSuccess", "onError", "onCancel"]);
const props = defineProps({
//
show: {
type: Boolean,
default: () => false,
},
mode: {
type: String,
default: () => "bottom",
},
});
const userStore = useUserStore();
const codeText = ref("获取验证码");
const isDisabled = ref(false);
const state = reactive({
loginForm: {
phone: "",
code: "",
},
});
//
const captcha = async () => {
if (!validatePhoneNumber(state.loginForm.phone)) {
return uni.showToast({
title: "请输入正确的手机号",
icon: "none",
});
} else {
const res = await getCaptcha({
phone: state.loginForm.phone,
});
if (res.code == 200) {
let countdown = 60;
if (!isDisabled.value) {
isDisabled.value = true;
codeText.value = `${countdown}秒后重新获取`;
const intervalId = setInterval(() => {
countdown--;
codeText.value = `${countdown}秒后重新获取`;
if (countdown <= 0) {
clearInterval(intervalId);
isDisabled.value = false;
codeText.value = "获取验证码";
}
}, 1000);
} else {
uni.showToast({
title: "请等待 60s 后重试",
icon: "error",
});
}
}
}
};
//
const callbackSuccess = () => {
emit("onSuccess");
};
//
const callBackError = () => {
emit("onError");
};
//
const Login = async () => {
if (!validatePhoneNumber(state.loginForm.phone)) {
return uni.showToast({
title: "请输入正确的手机号",
icon: "none",
});
} else if (state.loginForm.code.length !== 6) {
return uni.showToast({
title: "请输入正确的验证码",
icon: "none",
});
}
const result = await userStore.onLogin({ ...state.loginForm });
if (result.code === 200) {
callbackSuccess();
} else {
callBackError();
}
};
//
const handlePopupClose = () => {
emit("onCancel");
};
</script>
<style lang="scss" scoped>
.loginPopup {
::v-deep {
.u-slide-up-enter-active {
width: 100%;
height: 786rpx;
}
.u-popup__content__close {
margin-top: 30rpx;
}
}
.loginPopupContent {
box-sizing: border-box;
padding: 30rpx;
position: relative;
.loginTitle {
// font-size: 32rpx;
font-size: var(--h1-font-size);
font-weight: bold;
text-align: center;
box-sizing: border-box;
padding-top: 30rpx;
}
.loginForm {
width: 600rpx;
// border: 1px solid;
margin: 60rpx auto;
.loginFormItem {
width: 600rpx;
height: 100rpx;
border-radius: 20rpx;
background-color: #fff;
border: 2rpx solid #b9b9b9;
// padding: 0 !important;
&:nth-child(2) {
margin: 32rpx 0;
}
::v-deep {
.u-form-item__body {
padding: 0;
}
}
.loginFormInput {
width: 100%;
height: 100rpx !important;
box-sizing: border-box;
padding: 0 20px !important;
}
.getCode {
height: 100rpx;
box-sizing: border-box;
padding: 20px;
display: flex;
align-items: center;
font-size: var(--h1-font-size);
color: rgba(51, 51, 51, 0.6);
position: relative;
&::before {
content: "";
display: block;
width: 2rpx;
height: 52rpx;
background-color: rgba(51, 51, 51, 0.1);
position: absolute;
left: 0;
}
}
}
.loginFormBtn {
width: 600rpx;
height: 100rpx;
border-radius: 20rpx;
border: none;
background-color: #e7303f;
color: #fff;
::v-deep {
.u-button__text {
font-size: var(--h1-font-size) !important;
}
}
}
}
.tips {
// font-size: 24rpx;
font-size: var(--h4-font-size);
display: flex;
justify-content: center;
color: #717171;
.userAgreement {
color: #333;
}
}
}
}
</style>

View File

@ -49,7 +49,7 @@ import IndustryNewsView from "./components/IndustryNewsView/index.vue";
import ConceptNewsView from "./components/ConceptNewsView/index.vue";
import TodayNewsView from "./components/TodayNewsView/index.vue";
import FooterView from "./components/FooterView/index.vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();

View File

@ -139,7 +139,7 @@
import { getRecommendList } from "@/api";
import { useUserStore } from "@/stores/user";
import { computed, onMounted, reactive, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
import { onReachBottom } from "@dcloudio/uni-app";
//
const handleBack = () => {

View File

@ -130,7 +130,7 @@ import { getTopNews } from "@/api/newsInfo";
import dayjs from "dayjs";
import { useUserStore } from "@/stores/user";
import RadarChat from "@/components/charts/Radar.vue";
import LoginDialog from "@/components/loginPopup/index.vue";
import LoginDialog from "@/pages/realtimeInfo/LoginPopup/index.vue";
const userStore = useUserStore(); //
const LoginShow = ref(false);