568 lines
13 KiB
Vue
568 lines
13 KiB
Vue
<template>
|
||
<view class="login-container">
|
||
<!-- 用户名 -->
|
||
<!-- <view class="form-item">
|
||
<input v-model="loginForm.username" placeholder="请输入用户名" class="input" placeholder-class="placeholder" />
|
||
</view> -->
|
||
<view class="form-item">
|
||
<input v-model="loginForm.phoneNumber" placeholder="请输入手机号" class="input" placeholder-class="placeholder" />
|
||
</view>
|
||
<!-- 密码 -->
|
||
<view class="form-item">
|
||
<view class="password-item">
|
||
<input v-model="loginForm.password" :password="!showPassword" placeholder="请输入密码"
|
||
class="input password-input" placeholder-class="placeholder" />
|
||
<u-icon class="toggle-eye" :name="showPassword ? 'eye' : 'eye-off'" size="28" color="#999"
|
||
@tap="togglePassword"></u-icon>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 记住密码 -->
|
||
<label class="remember">
|
||
<checkbox :checked="loginForm.rememberMe" @tap="toggleRemember" />
|
||
<text>记住密码</text>
|
||
</label>
|
||
|
||
<!-- 登录按钮 -->
|
||
<!-- <button :loading="loading" :disabled="loading" class="login-btn" @tap="handleLogin">
|
||
{{ loading ? '登录中...' : '立即登录' }}
|
||
</button> -->
|
||
<checkbox-group @change="onPrivacyChange">
|
||
<label class="remember" style="white-space: nowrap;">
|
||
<checkbox value="agree" :checked="agreedPrivacy" />
|
||
<text>我已阅读并同意</text>
|
||
<text class="register-link-txt" @tap="goToPrivacyPage">
|
||
《隐私协议》
|
||
</text>
|
||
</label>
|
||
</checkbox-group>
|
||
<!-- 微信登录按钮 -->
|
||
<button @tap="getUserProfileLogin" class="login-btn" :loading="loading" :disabled="!agreedPrivacy || loading">
|
||
{{ loading ? '登录中...' : '微信一键登录' }}
|
||
</button>
|
||
<!-- 查看隐私协议(样式与注册入口一致,居中显示) -->
|
||
<view class="register-link" @tap="goToPrivacyPage">
|
||
<text>查看隐私协议</text>
|
||
</view>
|
||
<!-- 注册入口 -->
|
||
<!-- <view class="register-link" @tap="goToRegister">
|
||
<text>没有账号?立即注册</text>
|
||
</view> -->
|
||
|
||
<!-- 操作流程说明 -->
|
||
<view class="guide-text">
|
||
<text>若您未注册,请点击上方立即注册按钮进行账户注册。注册成功后请到后台(http://erp.buzhiyushu.cn)申请入驻。申请入驻审核通过后即可通过后台注册使用的手机号进行小程序登录操作!</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
wxLoginRequest
|
||
} from '../../service/login'
|
||
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
loginForm: {
|
||
tenantId: '000000',
|
||
userName: '',
|
||
password: '',
|
||
appid: 'wx703b8fb6c3da692a',
|
||
phoneNumber: '',
|
||
rememberMe: true,
|
||
clientId: '1400a724f627ddc73d8f4dd344f80a5e',
|
||
grantType: 'xcx',
|
||
code: '',
|
||
userId: '',
|
||
|
||
},
|
||
agreedPrivacy: false, // 用户是否勾选了隐私协议
|
||
// 是否显示明文密码
|
||
showPassword: false,
|
||
tenantList: [], // 租户列表
|
||
tenantIndex: -1,
|
||
codeUrl: '', // 验证码图片
|
||
loading: false, // 加载状态
|
||
captchaEnabled: false, // 是否启用验证码
|
||
|
||
appIds: [
|
||
'wx703b8fb6c3da692a', // 示例 AppID 1
|
||
],
|
||
results: []
|
||
|
||
|
||
}
|
||
},
|
||
computed: {
|
||
// 当前选中的租户
|
||
selectedTenant() {
|
||
return this.tenantList[this.tenantIndex] || {}
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.checkPrivacyAuth(); // ← 新增:进入页面时检查隐私协议
|
||
this.initData()
|
||
// this.getTenantList()
|
||
},
|
||
methods: {
|
||
/**
|
||
* 隐私勾选变更:根据checkbox-group返回值设置agreedPrivacy
|
||
*/
|
||
onPrivacyChange(e) {
|
||
const values = Array.isArray(e.detail?.value) ? e.detail.value : []
|
||
this.agreedPrivacy = values.includes('agree')
|
||
if (this.agreedPrivacy) {
|
||
uni.setStorageSync('agreedPrivacy', true)
|
||
} else {
|
||
uni.removeStorageSync('agreedPrivacy')
|
||
}
|
||
},
|
||
/**
|
||
* 打开微信隐私协议弹窗或fallback
|
||
*/
|
||
goToPrivacyPage() {
|
||
if (typeof wx !== 'undefined' && wx.openPrivacyContract) {
|
||
wx.openPrivacyContract({
|
||
success: () => {},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '隐私弹窗打开失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: '当前环境不支持隐私弹窗',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
toggleAgreed(e) {
|
||
this.agreedPrivacy = e.detail.value.length > 0;
|
||
},
|
||
// 检查隐私授权
|
||
checkPrivacyAuth() {
|
||
if (!wx.getPrivacySetting) return; // 老版本不支持
|
||
|
||
wx.getPrivacySetting({
|
||
success: (res) => {
|
||
// 微信检测需要用户授权隐私协议
|
||
if (res.needAuthorization) {
|
||
this.showPrivacyContract();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
// 调起微信官方隐私协议弹窗
|
||
showPrivacyContract() {
|
||
wx.openPrivacyContract({
|
||
success: () => {
|
||
console.log("用户查看并同意隐私协议");
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: "您必须阅读并同意隐私协议才能继续使用服务",
|
||
icon: "none"
|
||
});
|
||
}
|
||
});
|
||
},
|
||
/**
|
||
* 切换密码显示/隐藏
|
||
* 通过切换 showPassword 控制输入框是否密文显示
|
||
*/
|
||
togglePassword() {
|
||
this.showPassword = !this.showPassword
|
||
},
|
||
// 初始化记住的手机号和密码
|
||
initData() {
|
||
const phoneNumber = uni.getStorageSync('rememberedPhoneNumber')
|
||
const password = uni.getStorageSync('rememberedPassword')
|
||
const rememberMe = uni.getStorageSync('rememberMe')
|
||
if (phoneNumber && password && rememberMe) {
|
||
this.loginForm.phoneNumber = phoneNumber
|
||
this.loginForm.password = password
|
||
this.loginForm.rememberMe = true
|
||
console.log('已自动填充保存的账号密码')
|
||
}
|
||
|
||
const storedAgreedPrivacy = uni.getStorageSync('agreedPrivacy')
|
||
this.agreedPrivacy = !!storedAgreedPrivacy
|
||
},
|
||
getUserProfileLogin() {
|
||
if (!this.agreedPrivacy) {
|
||
uni.showToast({
|
||
title: '请先阅读并同意隐私协议',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
wx.getUserProfile({
|
||
desc: '用于完善用户信息',
|
||
success: (res) => {
|
||
console.log("获取用户信息成功", res)
|
||
this.wxLogin(res) // 把用户信息传到 wxLogin
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '您取消了授权',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
// 租户选择变化
|
||
onTenantChange(e) {
|
||
this.tenantIndex = e.detail.value
|
||
this.loginForm.tenantId = this.tenantList[this.tenantIndex].tenantId
|
||
},
|
||
|
||
// 切换记住手机号和密码
|
||
toggleRemember() {
|
||
this.loginForm.rememberMe = !this.loginForm.rememberMe
|
||
if (this.loginForm.rememberMe && this.loginForm.phoneNumber && this.loginForm.password) {
|
||
// 保存账号密码到本地存储
|
||
uni.setStorageSync('rememberedPhoneNumber', this.loginForm.phoneNumber)
|
||
uni.setStorageSync('rememberedPassword', this.loginForm.password)
|
||
uni.setStorageSync('rememberMe', true)
|
||
console.log('已保存账号密码')
|
||
} else {
|
||
// 清除本地存储的账号密码
|
||
uni.removeStorageSync('rememberedPhoneNumber')
|
||
uni.removeStorageSync('rememberedPassword')
|
||
uni.removeStorageSync('rememberMe')
|
||
console.log('已清除保存的账号密码')
|
||
}
|
||
},
|
||
|
||
// 表单验证
|
||
validateForm() {
|
||
if (!this.loginForm.phoneNumber.trim()) {
|
||
uni.showToast({
|
||
title: '请输入用户名',
|
||
icon: 'none',
|
||
duration: 2500
|
||
})
|
||
return false
|
||
}
|
||
if (!this.loginForm.password) {
|
||
uni.showToast({
|
||
title: '请输入密码',
|
||
icon: 'none',
|
||
duration: 2500
|
||
})
|
||
return false
|
||
}
|
||
if (this.captchaEnabled && !this.loginForm.code) {
|
||
uni.showToast({
|
||
title: '请输入验证码',
|
||
icon: 'none',
|
||
duration: 2500
|
||
})
|
||
return false
|
||
}
|
||
return true
|
||
},
|
||
|
||
// 执行微信登录 + 后台登录
|
||
async wxLogin(userProfile) {
|
||
this.loading = true;
|
||
|
||
try {
|
||
console.log('正在调用 wx.login ...');
|
||
|
||
const loginRes = await new Promise((resolve, reject) => {
|
||
wx.login({
|
||
success: resolve,
|
||
fail: reject
|
||
});
|
||
});
|
||
|
||
console.log('wx.login 返回:', loginRes);
|
||
|
||
// 存入 code
|
||
this.loginForm.code = loginRes.code;
|
||
|
||
// 调用你自己的后台登录接口
|
||
const response = await wxLoginRequest(this.loginForm);
|
||
console.log("后台登录成功:", response);
|
||
|
||
// 后台返回的用户数据
|
||
const userId = response.data.userId || '';
|
||
const openId = response.data.openid || '';
|
||
|
||
// 存储
|
||
uni.setStorageSync("userInfo", userProfile);
|
||
uni.setStorageSync("openId", openId);
|
||
uni.setStorageSync("userId", userId);
|
||
uni.setStorageSync("phoneNumber", this.loginForm.phoneNumber);
|
||
const currentTime = Date.now();
|
||
uni.setStorageSync('lastSubmitTime', currentTime);
|
||
// 记住账号/密码
|
||
const phoneNumber = this.loginForm.phoneNumber;
|
||
const password = this.loginForm.password;
|
||
|
||
if (this.loginForm.rememberMe && phoneNumber && password) {
|
||
uni.setStorageSync('rememberedPhoneNumber', phoneNumber);
|
||
uni.setStorageSync('rememberedPassword', password);
|
||
uni.setStorageSync('rememberMe', true);
|
||
}
|
||
|
||
// Vuex 更新
|
||
this.$store.commit('auth/SET_USER_INFO', userProfile);
|
||
this.$store.commit('auth/SET_LOGIN_STATUS', true);
|
||
|
||
// 最后调用你的 addMember 接口
|
||
this.addMember(userId);
|
||
|
||
// 跳转
|
||
uni.navigateTo({
|
||
url: '/pages/entry/index'
|
||
});
|
||
|
||
} catch (err) {
|
||
console.error("wxLogin 错误:", err);
|
||
|
||
uni.showToast({
|
||
title: err?.msg || '登录失败',
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
// 单独封装 addMember 避免 wxLogin 过长
|
||
async addMember(userId) {
|
||
try {
|
||
const res = await uni.request({
|
||
url: 'https://go.order.service.buzhiyushu.cn/api/user/insertRecbusinessByUserId',
|
||
method: 'GET',
|
||
data: {
|
||
userId: userId,
|
||
sort: 1,
|
||
},
|
||
header: {
|
||
'Content-Type': 'application/x-www-form-urlencoded'
|
||
}
|
||
});
|
||
|
||
console.log("addMember 返回:", res);
|
||
|
||
if (res[1].statusCode !== 200) {
|
||
console.warn("addMember 调用失败");
|
||
}
|
||
} catch (err) {
|
||
console.error("addMember 出错:", err);
|
||
}
|
||
}
|
||
},
|
||
|
||
|
||
// 跳转到注册页面
|
||
// goToRegister() {
|
||
// uni.navigateTo({
|
||
// url: '/pages/register/index'
|
||
// })
|
||
// },
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.login-container {
|
||
padding: 40rpx;
|
||
min-height: 100vh;
|
||
background: #f8f8f8;
|
||
|
||
.form-item {
|
||
margin-bottom: 30rpx;
|
||
background: #fff;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.picker {
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.input {
|
||
height: 80rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.password-item {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.password-input {
|
||
flex: 1;
|
||
}
|
||
|
||
.toggle-eye {
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
&.code-item {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.code-input {
|
||
flex: 1;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.code-image {
|
||
width: 200rpx;
|
||
height: 80rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.remember {
|
||
display: flex;
|
||
align-items: center;
|
||
margin: 30rpx 0;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.privacy-link {
|
||
display: block;
|
||
margin-top: 8rpx;
|
||
color: #007aff;
|
||
}
|
||
|
||
.login-btn {
|
||
margin-top: 60rpx;
|
||
background: #007aff;
|
||
color: #fff;
|
||
border-radius: 50rpx;
|
||
font-size: 34rpx;
|
||
}
|
||
|
||
.wechat-login-btn {
|
||
margin-top: 30rpx;
|
||
background: #07C160;
|
||
color: #fff;
|
||
border-radius: 50rpx;
|
||
font-size: 34rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.wechat-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.placeholder {
|
||
color: #999;
|
||
}
|
||
|
||
.register-link {
|
||
margin-top: 30rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #007aff;
|
||
}
|
||
|
||
.register-link-txt {
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #007aff;
|
||
}
|
||
|
||
.guide-text {
|
||
margin-top: 20rpx;
|
||
text-align: center;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
padding: 0 30rpx;
|
||
line-height: 1.5;
|
||
}
|
||
}
|
||
|
||
view,
|
||
text,
|
||
image,
|
||
input {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.content {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 100vh;
|
||
padding: 160rpx 40rpx 0;
|
||
|
||
image {
|
||
width: 275rpx;
|
||
height: 104rpx;
|
||
}
|
||
|
||
.title {
|
||
width: 100%;
|
||
margin-top: 80rpx;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
text-align: left;
|
||
}
|
||
|
||
.msg {
|
||
display: block;
|
||
width: 100%;
|
||
margin-top: 16rpx;
|
||
font-size: 28rpx;
|
||
color: rgba(0, 0, 0, 0.65);
|
||
text-align: left;
|
||
}
|
||
|
||
.btn {
|
||
position: absolute;
|
||
bottom: 160rpx;
|
||
width: 670rpx;
|
||
height: 96rpx;
|
||
background: #00B391;
|
||
border-radius: 8rpx;
|
||
font-size: 34rpx;
|
||
font-weight: 400;
|
||
color: #FFFFFF;
|
||
line-height: 96rpx;
|
||
}
|
||
|
||
::v-deep .filter-section.data-v-57280228 {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
//筛选按钮
|
||
::v-deep .u-button.data-v-2bf0e569 {
|
||
height: 70rpx;
|
||
width: 200rpx;
|
||
font-size: 18rpx;
|
||
}
|
||
|
||
.uni-fab__button {
|
||
background-color: #ff5a5f !important;
|
||
/* 主按钮背景色 */
|
||
width: 60px !important;
|
||
height: 60px !important;
|
||
}
|
||
|
||
|
||
}
|
||
</style> |