You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

717 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- #ifdef H5 -->
<!-- 可选引入微信JS-SDK用于更高级的微信功能 -->
<!-- <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> -->
<!-- #endif -->
<template>
<view class="container">
<view class="header">
<div class="line">您好</div>
<div class="line">欢迎使用电梯图纸生成平台</div>
</view>
<div class="main">
<view class="form">
<uv-form
labelAlign="right"
labelWidth="50"
labelPosition="top"
:model="userInfo"
:rules="rules"
ref="form"
>
<uv-form-item prop="phone">
<div class="formLabel">
<img class="img" src="/static/imgs/phone.png" alt="" />
手机号
</div>
<uv-input
v-model="userInfo.phone"
color="#000"
border="bottom"
:placeholderStyle="{ color: '#666778' }"
placeholder="请输入用户名"
></uv-input>
</uv-form-item>
<uv-form-item prop="password">
<div class="formLabel">
<img class="img" src="/static/imgs/code.png" alt="" />
验证码
</div>
<uv-input
v-model="userInfo.password"
color="#000"
border="bottom"
:placeholderStyle="{ color: '#666778' }"
placeholder="请输入验证码"
>
<template v-slot:suffix>
<uv-code
ref="codeRef"
@change="codeChange"
seconds="20"
changeText="X秒重新获取"
></uv-code>
<text style="color: #4d82fd" @click="getCode">{{ tips }}</text>
</template>
</uv-input>
</uv-form-item>
</uv-form>
</view>
<uv-button
@click="login"
customStyle="margin-top:30px"
text="登录"
color="#3F70FF"
></uv-button>
<div class="wechatBox" v-if="showWechatLogin">
<uv-divider text="第三方登录"></uv-divider>
<uv-icon
name="weixin-circle-fill"
color="#5fc157"
size="50"
@click="wechatLogin"
></uv-icon>
</div>
</div>
<!-- 微信登录绑定手机号弹窗 -->
<uv-popup
ref="popup"
mode="center"
:closeOnClickOverlay="false"
:round="10"
>
<view class="bind-phone-modal">
<view class="modal-header">
<view class="modal-title">绑定手机号</view>
<view class="modal-subtitle">为了您的账户安全,请绑定手机号</view>
</view>
<view class="modal-form">
<uv-form
:model="bindPhoneInfo"
:rules="bindPhoneRules"
ref="bindPhoneForm"
>
<uv-form-item prop="phone">
<uv-input
v-model="bindPhoneInfo.phone"
placeholder="请输入手机号"
type="number"
maxlength="11"
border="surround"
></uv-input>
</uv-form-item>
<uv-form-item prop="code">
<uv-input
v-model="bindPhoneInfo.code"
placeholder="请输入验证码"
border="surround"
>
<template v-slot:suffix>
<uv-code
ref="bindCodeRef"
@change="bindCodeChange"
seconds="60"
changeText="X秒重新获取"
></uv-code>
<text
style="color: #4d82fd; font-size: 12px"
@click="getBindCode"
>
{{ bindCodeTips }}
</text>
</template>
</uv-input>
</uv-form-item>
</uv-form>
</view>
<view class="modal-actions">
<!-- <uv-button
type="default"
@click="closeBindPhoneModal"
customStyle="margin-right: 12px;"
>
取消
</uv-button> -->
<uv-button
type="primary"
@click="confirmBindPhone"
:loading="bindingPhone"
>
确认绑定
</uv-button>
</view>
</view>
</uv-popup>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue";
import {
HOME_PATH,
LOGIN_PATH,
isTabBarPath,
removeQueryString,
} from "@/router";
import { useAuthStore, useUserStore } from "@/store";
import { onLoad } from "@dcloudio/uni-app";
import RPC from "@/utils/request";
const authStore = useAuthStore();
const userStore = useUserStore();
// 环境判断
const showWechatLogin = ref(false);
// 微信登录绑定手机号相关
// const showBindPhoneModal = ref(false);
const popup = ref(null);
const bindingPhone = ref(false);
const bindCodeTips = ref("获取验证码");
const bindCodeRef = ref(null);
const bindPhoneForm = ref(null);
const bindPhoneInfo = ref({
phone: "",
code: "",
});
const bindPhoneRules = ref({
phone: [
{
required: true,
message: "请输入手机号",
trigger: ["blur", "change"],
},
{
pattern: /^1[3-9]\d{9}$/,
message: "请输入正确的手机号",
trigger: ["blur", "change"],
},
],
code: {
required: true,
message: "请输入验证码",
trigger: ["blur", "change"],
},
});
const tips = ref("获取验证码");
const codeChange = (text) => {
tips.value = text;
};
const codeRef = ref(null);
const getCode = () => {
if (!userInfo.phone) {
uni.showToast({
title: "请填写手机号",
icon: "none",
});
return;
}
if (codeRef.value.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: "正在获取验证码",
});
setTimeout(() => {
uni.hideLoading();
// 这里此提示会被this.start()方法中的提示覆盖
uni.showToast({
title: "验证码已发送",
icon: "none",
});
// 通知验证码组件内部开始倒计时
codeRef.value.start();
}, 2000);
} else {
uni.showToast({
title: "倒计时结束后再发送",
icon: "none",
});
}
};
const form = ref(null);
const userInfo = ref({
phone: "",
password: "",
});
const rules = ref({
phone: [
{
required: true,
message: "请输入手机号",
trigger: ["blur", "change"],
},
{
pattern: /^1[3-9]\d{9}$/,
message: "请输入正确的手机号",
trigger: ["blur", "change"],
},
],
password: {
required: true,
message: "请填写验证码",
trigger: ["blur", "change"],
},
});
let redirect = HOME_PATH;
onLoad((options) => {
if (options.redirect && removeQueryString(options.redirect) !== LOGIN_PATH) {
redirect = decodeURIComponent(options.redirect);
}
});
// 检查运行环境
const checkEnvironment = () => {
// #ifdef MP-WEIXIN
// 微信小程序环境
showWechatLogin.value = true;
// #endif
// #ifdef H5
// H5环境检查是否在微信内
const ua = navigator.userAgent.toLowerCase();
const isWechat = ua.indexOf("micromessenger") !== -1;
showWechatLogin.value = isWechat;
// #endif
// #ifdef APP-PLUS
// App环境不显示微信登录
showWechatLogin.value = false;
// #endif
};
// 微信登录
const wechatLogin = () => {
// #ifdef MP-WEIXIN
// 微信小程序登录
// uni.login({
// provider: "weixin",
// success: (loginRes) => {
// console.log("微信登录成功:", loginRes);
// // 获取用户信息
// uni.getUserProfile({
// desc: "用于完善用户资料",
// success: (userRes) => {
// console.log("获取用户信息成功:", userRes);
// // 显示绑定手机号弹窗
// showBindPhoneModal.value = true;
// },
// fail: (err) => {
// console.error("获取用户信息失败:", err);
// uni.showToast({
// title: "获取用户信息失败",
// icon: "none",
// });
// },
// });
// },
// fail: (err) => {
// console.error("微信登录失败:", err);
// uni.showToast({
// title: "微信登录失败",
// icon: "none",
// });
// },
// });
popup.value.open();
// #endif
// #ifdef H5
// H5微信登录
if (typeof WeixinJSBridge !== "undefined") {
// 在微信内使用微信JS-SDK进行授权登录
wechatH5Login();
} else {
uni.showToast({
title: "请在微信中打开",
icon: "none",
});
}
// #endif
};
// 获取绑定手机号验证码
const getBindCode = () => {
if (!bindPhoneInfo.value.phone) {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
if (!/^1[3-9]\d{9}$/.test(bindPhoneInfo.value.phone)) {
uni.showToast({
title: "请输入正确的手机号",
icon: "none",
});
return;
}
if (bindCodeRef.value.canGetCode) {
uni.showLoading({
title: "正在获取验证码",
});
// 调用发送验证码API
// RPC.post('/api/sms/send', {
// phone: bindPhoneInfo.value.phone,
// type: 'bind'
// }).then(() => {
// uni.hideLoading()
// uni.showToast({
// title: '验证码已发送',
// icon: 'success'
// })
// bindCodeRef.value.start()
// }).catch(() => {
// uni.hideLoading()
// uni.showToast({
// title: '发送失败,请重试',
// icon: 'none'
// })
// })
// 模拟发送验证码
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: "验证码已发送",
icon: "success",
});
bindCodeRef.value.start();
}, 1500);
} else {
uni.showToast({
title: "倒计时结束后再发送",
icon: "none",
});
}
};
// 绑定验证码倒计时回调
const bindCodeChange = (text) => {
bindCodeTips.value = text;
};
// H5微信登录方法
const wechatH5Login = () => {
// #ifdef H5
// 构建微信授权URL
const appId = "YOUR_WECHAT_APP_ID"; // 替换为你的微信公众号AppID
const redirectUri = encodeURIComponent(
window.location.origin + "/pages/login/login"
); // 授权回调地址
const scope = "snsapi_userinfo"; // 授权作用域
const state = "STATE" + Date.now(); // 防止CSRF攻击的随机字符串
// 检查是否已经有授权码
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
if (code) {
// 已经获得授权码,处理登录
handleWechatH5Callback(code);
} else {
// 跳转到微信授权页面
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
uni.showLoading({
title: "正在跳转微信授权...",
});
// 跳转到微信授权页面
window.location.href = authUrl;
}
// #endif
};
// 处理微信H5授权回调
const handleWechatH5Callback = async (code) => {
// #ifdef H5
try {
uni.showLoading({
title: "正在获取用户信息...",
});
// 调用后端接口通过code获取用户信息
// const result = await RPC.post('/api/wechat/h5-login', {
// code: code
// });
// 模拟获取用户信息
setTimeout(() => {
uni.hideLoading();
// 模拟获取到的用户信息
const userInfo = {
openid: "mock_openid_" + Date.now(),
nickname: "微信用户",
headimgurl: "/static/imgs/avatar.png",
};
console.log("微信H5登录成功用户信息:", userInfo);
// 显示绑定手机号弹窗
popup.value.open();
// 清除URL中的code参数
const url = new URL(window.location);
url.searchParams.delete("code");
url.searchParams.delete("state");
window.history.replaceState(
{},
document.title,
url.pathname + url.search
);
}, 1500);
} catch (error) {
uni.hideLoading();
console.error("微信H5登录失败:", error);
uni.showToast({
title: "微信登录失败,请重试",
icon: "none",
});
}
// #endif
};
// 初始化微信JS-SDK可选用于更高级的功能
const initWechatJSSDK = () => {
// #ifdef H5
// 如果需要使用微信JS-SDK的其他功能可以在这里初始化
// 需要先引入微信JS-SDKhttps://res.wx.qq.com/open/js/jweixin-1.6.0.js
// 示例配置(需要后端提供签名等信息)
// if (typeof wx !== 'undefined') {
// wx.config({
// debug: false,
// appId: 'YOUR_WECHAT_APP_ID',
// timestamp: timestamp,
// nonceStr: nonceStr,
// signature: signature,
// jsApiList: ['chooseImage', 'uploadImage', 'getLocation'] // 需要使用的JS接口列表
// });
//
// wx.ready(() => {
// console.log('微信JS-SDK初始化成功');
// });
//
// wx.error((res) => {
// console.error('微信JS-SDK初始化失败:', res);
// });
// }
// #endif
};
// 确认绑定手机号
const confirmBindPhone = async () => {
try {
await bindPhoneForm.value.validate();
bindingPhone.value = true;
// 调用绑定手机号API
// const result = await RPC.post('/api/wechat/bind-phone', {
// phone: bindPhoneInfo.value.phone,
// code: bindPhoneInfo.value.code,
// wechatCode: wechatLoginCode // 微信登录返回的code
// })
// 模拟绑定过程
setTimeout(() => {
bindingPhone.value = false;
uni.showToast({
title: "绑定成功",
icon: "success",
});
// 设置登录状态
authStore.setAccessToken("wechat_access_token");
// userStore.setUserInfo(result.userInfo)
closeBindPhoneModal();
// 跳转到首页
setTimeout(() => {
uni.$uv.route({
type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
url: redirect,
});
}, 1000);
}, 2000);
} catch (error) {
console.error("绑定手机号失败:", error);
bindingPhone.value = false;
}
};
// 关闭绑定手机号弹窗
const closeBindPhoneModal = () => {
popup.value.close();
bindPhoneInfo.value = {
phone: "",
code: "",
};
bindCodeTips.value = "获取验证码";
};
const login = async () => {
await form.value.validate();
console.log(userInfo.value);
// RPC.post('/account/login', {
// username: userInfo.value.name,
// password: userInfo.value.password,
// }, {
// custom: {
// loading: true,
// loadingText: '正在登录...'
// },
// }).then(res => {
// authStore.setAccessToken(res.token)
// userStore.setUserInfo(res)
// uni.$uv.route({
// type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
// url: redirect,
// });
// })
authStore.setAccessToken("accessToken");
setTimeout(() => {
uni.$uv.route({
type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
url: redirect,
});
}, 800);
};
onMounted(() => {
checkEnvironment();
// #ifdef H5
// 检查是否是微信授权回调
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
if (code && showWechatLogin.value) {
handleWechatH5Callback(code);
}
// 可选初始化微信JS-SDK
// initWechatJSSDK();
// #endif
});
</script>
<style lang="scss" scoped>
.container {
height: 100vh;
display: flex;
flex-direction: column;
background: linear-gradient(
124.92deg,
rgba(77, 130, 253, 1) 7.66%,
rgba(85, 184, 254, 1) 89.55%
);
.header {
height: 15vh;
color: #fff;
display: flex;
flex-direction: column;
padding-left: 7vw;
font-size: 16px;
justify-content: center;
.line {
margin: 6px 0;
}
}
.main {
flex: 1;
background-color: #fff;
border-radius: 20px 20px 0 0;
padding: 7vw;
.formLabel {
display: flex;
align-items: center;
margin-bottom: 4px;
.img {
width: 20px;
height: 20px;
margin-right: 6px;
}
}
.wechatBox {
position: fixed;
width: 100%;
left: 0;
bottom: 15vh;
display: flex;
flex-direction: column;
align-items: center;
.uv-icon {
cursor: pointer;
transition: transform 0.2s;
&:active {
transform: scale(0.95);
}
}
}
}
}
.bind-phone-modal {
width: 320px;
padding: 24px;
.modal-header {
text-align: center;
margin-bottom: 24px;
.modal-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
.modal-subtitle {
font-size: 14px;
color: #666;
}
}
.modal-form {
margin-bottom: 24px;
.uv-form-item {
margin-bottom: 16px;
}
}
.modal-actions {
display: flex;
gap: 12px;
.uv-button {
flex: 1;
}
}
}
</style>
<style lang="scss">
.wechatBox {
.uv-divider {
margin-bottom: 30px;
width: 90%;
}
}
</style>