| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795 |
- <template>
- <view class="normal-login-container">
-
-
- <view class="logo-content align-center justify-center flex">
- <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
- </image>
- <text class="title">哎呀电子小说2</text>
- </view>
-
- <view class="login-form-content">
- <!-- 用户名密码登录 -->
- <view class="input-item flex align-center">
- <view class="iconfont icon-user icon"></view>
- <input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
- </view>
- <view class="input-item flex align-center">
- <view class="iconfont icon-password icon"></view>
- <input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
- </view>
- <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
- <view class="iconfont icon-code icon"></view>
- <input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
- <view class="login-code">
- <image :src="codeUrl" @click="getCode" class="login-code-img"></image>
- </view>
- </view>
-
- <view class="action-btn">
- <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">账号登录</button>
- </view>
-
- <!-- 微信一键登录 -->
- <view class="wechat-login-section">
- <button class="wechat-login-btn" @click="handleWechatLogin">
- <image src="/static/icons/wechat.png" class="wechat-icon"></image>
- <text>微信一键登录</text>
- </button>
- </view>
-
- <view class="reg text-center" v-if="register">
- <text class="text-grey1">没有账号?</text>
- <text @click="handleUserRegister" class="text-blue">立即注册</text>
- </view>
- <view class="xieyi text-center">
- <text class="text-grey1">登录即代表同意</text>
- <text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
- <text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
- </view>
-
- <!-- 备案信息 - 只在H5环境中显示 -->
- <!-- #ifdef H5 -->
- <view class="beian-info">
- <view class="beian-links">
- <a href="https://beian.miit.gov.cn" target="_blank" class="beian-link">陕ICP备2024057340号-2</a>
- <!-- <a href="http://www.beian.gov.cn" target="_blank" class="beian-link">
- <img src="/static/icons/police-beian.png" class="police-icon" />
- 京公网安备 11010502034567号
- </a> -->
- </view>
- <view class="copyright">
- © 2025 哎呀电子小说 * 哎呀电子 版权所有
- </view>
- </view>
- <!-- #endif -->
- </view>
- <!-- 广告组件保持不变 -->
- <!-- <ad-interstitial adpid="1433929280" :loadnext="true" v-slot:default="{loading, error}" @load="onadload" @close="onadclose" @error="onaderror">
- <button :disabled="loading" :loading="loading">点击广告获取奖励</button>
- <view v-if="error">{{error}}</view>
- </ad-interstitial>
- <view class="ad-view">
- <ad adpid="1325240772" @load="onload" @close="onclose" @error="onerror"></ad>
- </view>
- <view class="ad-view">
- <ad adpid="1695714925" @load="onload1" @close="onclose1" @error="onerror1"></ad>
- </view> -->
- </view>
- </template>
-
- <script>
- import { getCodeImg } from '@/api/login'
- import { getToken, setToken, removeToken } from '@/utils/auth'
- export default {
- data() {
- return {
- codeUrl: "",
- captchaEnabled: true,
- // 用户注册开关
- register: true,
- wxCode: "", // 添加这个变量来保存微信code
- globalConfig: {
- appInfo: {
- logo: '/static/logo.png',
- agreements: []
- }
- },
- loginForm: {
- username: "",
- password: "",
- code: "",
- uuid: ''
- }
- }
- },
- created() {
- this.safeInitConfig()
- this.getCode()
- },
- methods: {
- // 安全初始化配置
- safeInitConfig() {
- try {
- const app = getApp()
- if (app && app.globalData && app.globalData.config) {
- this.globalConfig = app.globalData.config
- } else {
- this.globalConfig = {
- appInfo: {
- logo: '/static/logo.png',
- name: '恋爱圈',
- agreements: [
- { title: '隐私协议', url: 'https://www.aiyadianzi.cn/privacy' },
- { title: '用户协议', url: 'https://www.aiyadianzi.cn/agreement' }
- ]
- }
- }
- }
- } catch (error) {
- console.warn('获取全局配置失败:', error)
- this.globalConfig = {
- appInfo: {
- logo: '/static/logo.png',
- name: '哎呀电子',
- agreements: []
- }
- }
- }
- },
-
- // 广告相关方法
- onadload(e) { console.log('广告数据加载成功') },
- onadclose(e) { console.log("onadclose",e) },
- onaderror(e) { console.log("onaderror: ", e.detail) },
- onload(e) { console.log("onload") },
- onclose(e) { console.log("onclose: " + e.detail) },
- onerror(e) { console.log("onerror: " + e.detail.errCode + " message:: " + e.detail.errMsg) },
- onload1(e) { console.log("onload") },
- onclose1(e) { console.log("onclose: " + e.detail) },
- onerror1(e) { console.log("onerror: " + e.detail.errCode + " message:: " + e.detail.errMsg) },
-
- // 微信登录 - 修复版
- async handleWechatLogin() {
- console.log('开始微信登录流程')
-
- try {
-
- // 1. 先检查网络状态
- const networkState = await this.checkNetworkState()
- if (!networkState) {
- uni.showToast({
- title: '网络连接不可用,请检查网络',
- icon: 'none'
- })
- return
- }
-
- // 2. 先获取微信code
- const loginRes = await this.getWxLoginCode()
- console.log('微信login结果:', loginRes)
-
- if (loginRes.errMsg !== 'login:ok' || !loginRes.code) {
- uni.showToast({
- title: '获取微信登录凭证失败',
- icon: 'none'
- })
- return
- }
-
- // 保存code,用于后续请求
- this.wxCode = loginRes.code
-
- // 3. 显示确认授权弹窗,然后获取用户信息
- uni.showModal({
- title: '授权确认',
- content: '需要获取您的用户信息以完成登录',
- confirmText: '允许',
- cancelText: '拒绝',
- success: async (res) => {
- if (res.confirm) {
- // 用户确认授权,获取用户信息
- await this.getUserInfoAndLogin()
- } else {
- uni.showToast({
- title: '授权已取消',
- icon: 'none'
- })
- }
- }
- })
-
- } catch (error) {
- console.error('微信登录流程失败:', error)
-
- let errorMsg = '登录失败,请重试'
- if (error.errMsg) {
- errorMsg = error.errMsg
- } else if (error.message) {
- errorMsg = error.message
- }
-
- uni.showToast({
- title: errorMsg,
- icon: 'none',
- duration: 3000
- })
- }
- },
-
- // 获取用户信息并登录
- async getUserInfoAndLogin() {
- try {
- uni.showLoading({
- title: '获取用户信息...',
- mask: true
- })
-
- // 直接调用getUserProfile,确保在用户交互中
- const userProfileRes = await new Promise((resolve, reject) => {
- uni.getUserProfile({
- desc: '用于完善会员资料',
- success: resolve,
- fail: reject
- })
- })
-
- console.log('用户信息获取结果:', userProfileRes)
-
- if (userProfileRes.errMsg !== 'getUserProfile:ok') {
- uni.hideLoading()
- uni.showToast({
- title: '获取用户信息失败',
- icon: 'none'
- })
- return
- }
-
- const userInfo = userProfileRes.userInfo
- uni.hideLoading()
-
- // 调用后端登录接口
- await this.sendLoginRequest(this.wxCode, userInfo)
-
- } catch (error) {
- uni.hideLoading()
- console.error('获取用户信息失败:', error)
-
- let errorMsg = '获取用户信息失败'
- if (error.errMsg) {
- if (error.errMsg.includes('getUserProfile:fail')) {
- errorMsg = '用户拒绝授权'
- } else {
- errorMsg = error.errMsg
- }
- }
-
- uni.showToast({
- title: errorMsg,
- icon: 'none',
- duration: 3000
- })
- }
- },
-
- // 发送登录请求到后端 - 修复版
- async sendLoginRequest(code, userInfo) {
- uni.showLoading({
- title: '登录中...',
- mask: true
- })
- try {
- const loginData = {
- code: code,
- userInfo: {
- nickName: userInfo.nickName,
- avatarUrl: userInfo.avatarUrl,
- gender: userInfo.gender,
- country: userInfo.country,
- province: userInfo.province,
- city: userInfo.city
- }
- }
-
- console.log('发送登录数据:', loginData)
-
- // 使用配置中的baseUrl
- const baseUrl = this.getBaseUrl()
- const requestUrl = `${baseUrl}/wxLogin`
-
- console.log('请求URL:', requestUrl)
-
- const res = await new Promise((resolve, reject) => {
- uni.request({
- url: requestUrl,
- method: 'POST',
- data: loginData,
- header: {
- 'content-type': 'application/json',
- },
- success: (res) => {
- console.log('请求成功,状态码:', res.statusCode)
- console.log('响应数据:', res.data)
- resolve(res.data)
- },
- fail: (err) => {
- console.error('请求失败:', err)
- reject(err)
- }
- })
- })
-
- uni.hideLoading()
- console.log('后端登录响应:', res)
-
- if (res.code === 200) {
- // 修复:使用正确的 token 存储方式
- const token = res.data.token
- const user = res.data.user
-
- console.log('解析出的token:', token)
- console.log('解析出的user:', user)
-
- if (!token) {
- throw new Error('后端返回的token为空')
- }
-
- // 修复:使用 auth.js 中的方法存储 token
- try {
- // 使用 setToken 方法存储 token(key 为 'App-Token')
- setToken(token)
-
- // 存储用户信息到本地存储
- uni.setStorageSync('userInfo', user)
-
- // 验证存储是否成功
- const storedToken = getToken() // 使用 getToken 方法获取
- const storedUserInfo = uni.getStorageSync('userInfo')
-
- console.log('存储验证 - token:', storedToken ? '成功' : '失败')
- console.log('存储验证 - userInfo:', storedUserInfo ? '成功' : '失败')
-
- if (!storedToken) {
- throw new Error('token存储失败')
- }
-
- // 尝试更新 Vuex 状态(如果存在)
- if (this.$store) {
- try {
- // 使用 user.js 中的 mutation 更新状态
- if (this.$store._mutations && this.$store._mutations['user/SET_TOKEN']) {
- this.$store.commit('user/SET_TOKEN', token)
- }
-
- if (user && this.$store._mutations && this.$store._mutations['user/SET_NAME']) {
- const userName = user.nickName || user.userName
- this.$store.commit('user/SET_NAME', userName)
- }
-
- if (user && user.avatar && this.$store._mutations && this.$store._mutations['user/SET_AVATAR']) {
- this.$store.commit('user/SET_AVATAR', user.avatar)
- }
- } catch (error) {
- console.warn('Vuex状态更新失败,但不影响登录:', error)
- }
- }
-
- } catch (storageError) {
- console.error('存储数据失败:', storageError)
- throw new Error('登录状态保存失败')
- }
-
- // 触发全局用户信息更新事件
- uni.$emit('userInfoUpdate', user)
- uni.$emit('loginStatusUpdate', {
- isLoggedIn: true,
- userInfo: user
- })
-
- uni.showToast({
- title: '登录成功',
- icon: 'success'
- })
-
- // 立即跳转页面
- setTimeout(() => {
- this.loginSuccess()
- }, 500)
-
- } else {
- uni.showToast({
- title: res.msg || '登录失败,请重试',
- icon: 'none',
- duration: 3000
- })
- }
-
- } catch (error) {
- uni.hideLoading()
- console.error('登录请求失败:', error)
-
- let errorMsg = '登录失败,请重试'
- if (error.message) {
- errorMsg = error.message
- }
-
- uni.showToast({
- title: errorMsg,
- icon: 'none',
- duration: 3000
- })
- }
- },
-
- // 获取微信登录code
- getWxLoginCode() {
- return new Promise((resolve, reject) => {
- uni.login({
- provider: 'weixin',
- success: resolve,
- fail: reject
- })
- })
- },
-
- // 检查网络状态
- checkNetworkState() {
- return new Promise((resolve) => {
- uni.getNetworkType({
- success: (res) => {
- if (res.networkType === 'none') {
- resolve(false)
- } else {
- resolve(true)
- }
- },
- fail: () => {
- resolve(true) // 如果获取网络状态失败,默认继续执行
- }
- })
- })
- },
-
- // 获取基础URL - 使用你的配置
- getBaseUrl() {
- // 直接从配置中获取baseUrl
- try {
- // 方式1: 从全局配置获取
- const app = getApp()
- if (app && app.globalData && app.globalData.config && app.globalData.config.baseUrl) {
- return app.globalData.config.baseUrl
- }
-
- // 方式2: 从Vue原型获取
- if (this.$config && this.$config.baseUrl) {
- return this.$config.baseUrl
- }
-
- // 方式3: 使用你的配置中的默认值
- return 'https://love.aiyadianzi.cn/prod-api' // 使用你配置的生产环境地址
- } catch (error) {
- console.warn('获取baseUrl失败,使用默认值:', error)
- return 'https://love.aiyadianzi.cn/prod-api'
- }
- },
-
- // 原有方法保持不变
- handleUserRegister() {
- this.$tab.redirectTo(`/pages/register/index`)
- },
- // 隐私协议
- handlePrivacy() {
- const site = this.globalConfig.appInfo.agreements[0] || { title: '隐私协议', url: '' }
- this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
- },
- // 用户协议
- handleUserAgrement() {
- const site = this.globalConfig.appInfo.agreements[1] || { title: '用户协议', url: '' }
- this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
- },
- // 获取图形验证码
- getCode() {
- getCodeImg().then(res => {
- this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
- if (this.captchaEnabled) {
- this.codeUrl = 'data:image/gif;base64,' + res.img
- this.loginForm.uuid = res.uuid
- }
- }).catch(error => {
- console.error('获取验证码失败:', error)
- // 如果API调用失败,使用默认验证码
- this.captchaEnabled = false
- })
- },
- // 登录方法 - 使用原有的若依登录逻辑
- async handleLogin() {
- if (!this.loginForm.username) {
- this.$modal.msgError("请输入您的账号")
- return
- }
- if (!this.loginForm.password) {
- this.$modal.msgError("请输入您的密码")
- return
- }
- if (this.captchaEnabled && !this.loginForm.code) {
- this.$modal.msgError("请输入验证码")
- return
- }
-
- this.$modal.loading("登录中,请耐心等待...")
-
- try {
- // 使用原有的Login action
- await this.$store.dispatch('Login', this.loginForm)
-
- // 获取用户信息 - 添加详细的错误处理
- try {
- await this.$store.dispatch('GetInfo')
-
- // 确保用户信息正确存储
- const userInfo = this.$store.state.user
- console.log('Vuex用户信息:', userInfo)
-
- // 手动存储用户信息到本地存储,确保一致性
- if (userInfo && userInfo.name) {
- uni.setStorageSync('userInfo', {
- userName: userInfo.name,
- nickName: userInfo.name,
- avatar: userInfo.avatar
- })
- }
-
- this.$modal.msgSuccess("登录成功")
-
- // 立即触发全局状态更新
- uni.$emit('userInfoUpdate', userInfo)
- uni.$emit('loginStatusUpdate', {
- isLoggedIn: true,
- userInfo: userInfo
- })
-
- // 登录成功处理 - 使用延时确保状态更新完成
- setTimeout(() => {
- this.loginSuccess()
- }, 1000)
-
- } catch (infoError) {
- console.error('获取用户信息失败:', infoError)
- // 即使获取用户信息失败,只要登录成功就继续
- this.$modal.msgSuccess("登录成功")
- setTimeout(() => {
- this.loginSuccess()
- }, 1000)
- }
-
- } catch (error) {
- this.$modal.closeLoading()
- console.error('登录失败:', error)
-
- let errorMsg = '登录失败'
- if (error.message) {
- errorMsg = error.message
- } else if (error.msg) {
- errorMsg = error.msg
- }
-
- this.$modal.msgError(errorMsg)
-
- if (this.captchaEnabled) {
- this.getCode()
- }
- }
- },
-
- // 登录成功处理 - 增强版
- loginSuccess() {
- console.log('执行登录成功跳转')
-
- // 多重验证登录状态
- const token = getToken()
- const vuexUser = this.$store.state.user
- const storedUserInfo = uni.getStorageSync('userInfo')
-
- console.log('跳转前状态检查:')
- console.log('- token:', token ? '存在' : '不存在')
- console.log('- vuex用户:', vuexUser)
- console.log('- 存储用户:', storedUserInfo)
-
- if (token) {
- console.log('Token存在,允许跳转')
-
- // 即使没有完整的用户信息,只要token存在就允许访问
- uni.switchTab({
- url: '/pages/user/index',
- success: () => {
- console.log('跳转个人中心成功')
- // 强制刷新页面数据
- setTimeout(() => {
- uni.$emit('forceRefreshUserInfo')
- }, 500)
- },
- fail: (err) => {
- console.error('跳转失败:', err)
- // 备用跳转方案
- uni.switchTab({
- url: '/pages/index/index'
- })
- }
- })
- } else {
- console.error('跳转时Token不存在')
- uni.showToast({
- title: '登录状态异常,请重新登录',
- icon: 'none',
- duration: 3000
- })
- }
- }
- }
- }
- </script>
-
- <style lang="scss">
- page {
- background-color: #ffffff;
- }
-
- .normal-login-container {
- width: 100%;
- min-height: 100vh;
- padding: 40rpx;
-
- .logo-content {
- width: 100%;
- font-size: 21px;
- text-align: center;
- padding-top: 15%;
- flex-direction: column;
-
- image {
- border-radius: 4px;
- }
-
- .title {
- margin: 10px 0;
- font-size: 24px;
- color: #e94f87;
- }
-
- .subtitle {
- font-size: 14px;
- color: #999;
- }
- }
-
- .login-form-content {
- text-align: center;
- margin: 20px auto;
- margin-top: 10%;
- width: 100%;
-
- .input-item {
- margin: 20px auto;
- background-color: #f5f6f7;
- height: 45px;
- border-radius: 20px;
-
- .icon {
- font-size: 38rpx;
- margin-left: 10px;
- color: #999;
- }
-
- .input {
- width: 100%;
- font-size: 14px;
- line-height: 20px;
- text-align: left;
- padding-left: 15px;
- }
- }
-
- .login-btn {
- margin-top: 40px;
- height: 45px;
- background: #e94f87 !important;
- color: #fff;
- border-radius: 25px;
- font-size: 16px;
- }
-
- .wechat-login-section {
- margin: 20px 0;
- }
-
- .wechat-login-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- background: #07c160;
- color: #fff;
- border: none;
- border-radius: 25px;
- padding: 12px;
- font-size: 16px;
- width: 100%;
-
- .wechat-icon {
- width: 20px;
- height: 20px;
- margin-right: 10px;
- }
- }
-
- .reg {
- margin-top: 15px;
- font-size: 14px;
- }
-
- .xieyi {
- color: #333;
- margin-top: 20px;
- font-size: 12px;
- }
-
- .login-code {
- height: 38px;
- position: absolute;
- right: 10px;
-
- .login-code-img {
- height: 38px;
- width: 100px;
- }
- }
-
- /* 备案信息样式 - 只在H5环境中生效 */
- /* #ifdef H5 */
- .beian-info {
- margin-top: 40px;
- padding-top: 20px;
- border-top: 1px solid #f0f0f0;
- text-align: center;
- color: #999;
- font-size: 12px;
-
- .beian-links {
- display: flex;
- justify-content: center;
- align-items: center;
- flex-wrap: wrap;
- gap: 15px;
- margin-bottom: 8px;
-
- .beian-link {
- color: #999;
- text-decoration: none;
- display: flex;
- align-items: center;
- transition: color 0.3s;
-
- &:hover {
- color: #e94f87;
- }
-
- .police-icon {
- width: 14px;
- height: 14px;
- margin-right: 4px;
- }
- }
- }
-
- .copyright {
- color: #999;
- }
- }
- /* #endif */
- }
- }
-
- .ad-view {
- background-color: #FFFFFF;
- margin-bottom: 20px;
- }
- </style>
|