Browse Source

feat(login): 添加手机号登录功能并优化登录页面样式

- 新增手机号登录功能及相关API调用
- 添加密码显示/隐藏切换功能
- 优化登录页面UI样式和布局
- 完善用户协议和隐私协议跳转逻辑
- 添加iOS系统检测以显示Apple登录按钮
master
wei 1 week ago
parent
commit
d84d0cc04e
  1. 7
      libs/request/beforeRequest.js
  2. 5
      libs/request/index.js
  3. 378
      pages/login/login.vue

7
libs/request/beforeRequest.js

@ -2,10 +2,11 @@
// const BASE_URL = "http://www.dgscdw.com/food.shop.api";// 正式服务
const BASE_URL = "https://xcx.dgscdw.com/food.shop.api";// 正式服务
// const DRIVER_URL = "https://sj.dgscdw.com";
// const UPLOAD_URL = "http://zyq.dgscdw.com/file-api";
// var baseUrl = 'http://192.168.1.200:8081/food.shop.api'//测试服务
const DRIVER_URL = "https://sj.dgscdw.com";
// let driverUrl = 'http://192.168.1.16:7301'
const UPLOAD_URL = "http://zyq.dgscdw.com/file-api";
// var baseUrl = 'http://www.seelight.top/food.shop.api' //刘盛广
/** 请求拦截 */
@ -19,7 +20,7 @@ export async function beforeRequest(config) {
config.header = {
...config.header,
session: uni.getStorageSync("session") || "",
tenant_id: uni.getStorageSync("tenantId") || "10001",
// tenant_id: uni.getStorageSync("tenantId") || "10001",
// version: "2.0",
};

5
libs/request/index.js

@ -5,7 +5,8 @@ import { beforeRequest } from "./beforeRequest";
// * _with_token {boolean} 是否挂载token,默认true
// * _return_origin{boolean} 是否返回原始数据(uni.request方法的原始值),默认false,若开启则 _service_fail 相关参数失效
// * _service_fail_toast {boolean} 是否在业务失败(响应code不为0)时自动Toast错误的msg,默认true
// * _service_fail_throw {boolean} 是否在业务失败(响应code不为0)时抛出业务失败异常,默认true。业务异常类可通过 error.is_service_fail_error 识别
// * _service_fail_throw {boolean}
// 是否在业务失败(响应code不为0)时抛出业务失败异常,默认true。业务异常类可通过 error.is_service_fail_error 识别
/**
* @typedef {object} headerType
@ -26,7 +27,7 @@ import { beforeRequest } from "./beforeRequest";
/**
* 发起请求
* @param {configType} config 基于uni.request的config参数除此之外拓展了一些参数
* @returns
* @returns {Promise<any>} 响应数据
*/
async function request(config) {
return uni.request(await beforeRequest(config)).then((response) => {

378
pages/login/login.vue

@ -1,8 +1,16 @@
<script setup>
import { onLoad, onShow } from "@dcloudio/uni-app";
import { ref } from "vue";
import navigation from "@/components/navigation/navigation.vue";
import { getmyareaApi, getUserByXcxAPPOpenIdApi, getUserTreatyApi, xcxWxLoginApi } from "@/libs/api";
import {
getmyareaApi,
getUserByXcxAPPOpenIdApi,
getUserTreatyApi,
loginApi,
xcxWxLoginApi,
} from "@/libs/api";
import { gotoBack } from "@/libs/utils";
import config from "@/libs/utils/config";
import { encryptData } from "@/libs/utils/crypto";
let appData = getApp().globalData;
/**
@ -33,15 +41,23 @@ const openid = ref("");
/**
* 手机号码
*/
const telephone = ref("");
const username = ref("");
/**
* 密码
*/
const password = ref("");
/**
* 显示密码
*/
const showPassword = ref(false);
/**
* 阅读协议
*/
const readed = ref(false);
/**
* 判断是否是ios系统
*/
const isIos = ref(false);
/**
* 授权登录
@ -55,6 +71,7 @@ function onGetUserProfile() {
success(resp) {
uni.showToast({
title: JSON.stringify(resp),
icon: "none",
});
avatarUrl.value = resp.userInfo.avatarUrl;
@ -65,6 +82,7 @@ function onGetUserProfile() {
fail(err) {
uni.showToast({
title: JSON.stringify(err),
icon: "none",
});
console.log(err);
},
@ -74,6 +92,7 @@ function onGetUserProfile() {
// #ifdef APP-PLUS||H5
uni.showToast({
title: "app login",
icon: "none",
});
// #endif
}
@ -140,6 +159,60 @@ async function getmyarea() {
});
}
/**
* 手机号登录
*/
async function onPhoneLogin() {
if (username.value === "") {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
if (password.value === "") {
uni.showToast({
title: "请输入密码",
icon: "none",
});
return;
}
if (!readed.value) {
uni.showToast({
title: "请先阅读并同意服务协议和隐私协议",
icon: "none",
});
return;
}
uni.showLoading({
title: "登录中...",
mask: true,
});
const resp = await loginApi({
username: username.value,
password: password.value,
});
// TODO: 便 code === '0',
if (resp.code === "0") {
uni.setStorageSync("session", resp.data);
const setPhone = encryptData(username.value, config.SECRET_KEY);
uni.setStorageSync("phone", setPhone);
const setPassword = encryptData(password.value, config.SECRET_KEY);
uni.setStorageSync("password", setPassword);
gotoBack();
}
else {
uni.showToast({
title: resp.message,
icon: "none",
});
}
uni.hideLoading();
}
function onWechatLogin() {}
function onRegister() {}
function onAppleLogin() {}
function updateUserInfo() {}
function onBackHome() {
@ -153,42 +226,68 @@ function onBackHome() {
*/
function onForgetPassword() { }
/**
* 打开用户协议
*/
async function onOpenUserAgreement() {
const resp = await getUserTreatyApi();
console.log(resp, 2333);
if (resp.code === "0") {
uni.navigateTo({
url: "/pages/agreement/agreement",
events: {
async getContent(callback) {
callback(resp.data.serviceAgreement);
},
},
});
}
if (resp.code !== "0")
return;
uni.navigateTo({
url: "/pages/agreement/agreement",
success(resp2) {
resp2.eventChannel.emit("serviceAgreement", {
html: resp.data.serviceAgreement,
title: "用户协议",
});
},
});
}
/**
* 打开隐私协议
*/
async function onOpenPrivacyAgreement() {
const resp = await getUserTreatyApi();
if (resp.code !== "0")
return;
uni.navigateTo({
url: "/pages/agreement/agreement",
success(resp2) {
resp2.eventChannel.emit("privacyAgreement", {
html: resp.data.privacyAgreement,
title: "隐私协议",
});
},
});
}
function onOpenPrivacyAgreement() { }
onLoad(() => {
if (uni.getUserProfile) {
canIUseGetUserProfile.value = true;
}
uni.getSystemInfo({
success(resp) {
if (resp.platform === "ios") {
isIos.value = true;
}
},
});
});
</script>
<template>
<view>
<navigation background="white">
<view class="nav">
<text class="iconfont icon-back" @click="onBackHome" />
<view>
菜大王
</view>
</view>
</navigation>
<uv-navbar
title-style="color: #fff;"
title="登录账号"
bg-color="#06CA64"
left-icon-color="#fff"
@left-click="onBackHome"
/>
<!-- #ifdef MP-WEIXIN -->
<view>
<view style="paddingTop: 44px;">
<view class="header">
<image src="/static/logo.png" />
</view>
@ -221,35 +320,96 @@ onLoad(() => {
登录账号
</view>
<view class="phone">
手机号
</view>
<input v-model="telephone" placeholder="请输入">
<view class="passowordForget">
<text class="password">
密码
</text>
<text class="forget" @click="onForgetPassword">
忘记密码?
</text>
</view>
<view class="middle">
<view class="phone">
手机号
</view>
<input v-model="username" placeholder="请输入">
<view class="passowordForget">
<text class="password">
密码
</text>
<text class="forget" @click="onForgetPassword">
忘记密码?
</text>
</view>
<input v-model="password" placeholder="请输入">
<view class="agreement">
<uv-checkbox-group>
<uv-checkbox v-model="readed" shape="circle" />
</uv-checkbox-group>
<view>
我已阅读并同意<text class="href" @click="onOpenUserAgreement">
菜大王用户服务协议
</text><text
class="href"
@click="onOpenPrivacyAgreement"
<view class="flex">
<input
v-model="password"
:type="showPassword ? '' : 'password'"
placeholder="请输入"
>
菜大王隐私协议
</text>
<uv-icon
size="35rpx"
:name="showPassword ? 'eye-off' : 'eye-fill'"
@click="showPassword = !showPassword"
/>
</view>
<!-- <input
v-model="password"
placeholder="请输入"
type="password"
:password="showPassword"
:class="[!showPassword ? 'uni-eye-active' : '']"
@click="showPassword = !showPassword"
> -->
<view class="agreement">
<uv-checkbox-group
active-color="#06CA64"
>
<uv-checkbox
v-model="readed"
shape="circle"
size="24"
icon-size="20"
@change="e => readed = e"
/>
</uv-checkbox-group>
<view>
我已阅读并同意<text class="href" @click="onOpenUserAgreement">
菜大王用户服务协议
</text><text
class="href"
@click="onOpenPrivacyAgreement"
>
菜大王隐私协议
</text>
</view>
</view>
<view class="login-box">
<button class="login-btn" @click="onPhoneLogin">
登录
</button>
<view class="no-account">
<text>
还没有账号<text class="register" @click="onRegister">
去注册
</text>
</text>
</view>
<view class="other-login">
<uv-icon
class="wechat"
name="weixin-fill"
size="35"
color="#fff"
@click="onWechatLogin"
/>
<uv-icon
v-if="isIos"
name="apple-fill"
class="apple"
size="35"
color="#fff"
@click="onAppleLogin"
/>
</view>
</view>
</view>
</view>
@ -272,9 +432,10 @@ page {
.section__title{
margin-bottom:20rpx;
}
input{
input {
border-bottom:solid 1px #f6f6f6;
width:90%;
z-index: 1;
}
.header {
margin: 90rpx 0 90rpx 0rpx;
@ -334,7 +495,6 @@ input{
display: flex;
align-items: center;
justify-content: center;
position: relative;
.icon-back {
color: black;
font-size: 50rpx;
@ -344,45 +504,91 @@ input{
}
}
.main {
padding: 60rpx 40rpx 80rpx;
padding: 44px 50rpx 0;
// font-size: 24rpx;
font-size: $text-base;
.title {
font-size: 60rpx;
font-size: $text-9xl;
// font-size: 60rpx;
padding-top: 100rpx;
padding-bottom: 40rpx;
}
.phone {
padding: 20rpx 5rpx;
}
.passowordForget {
padding: 20rpx 5rpx;
display: flex;
justify-content: space-between;
.password {}
.forget {
color:#06CA64
}
}
.agreement {
padding: 30rpx 10rpx;
display: flex;
align-items: center;
gap: 10rpx;
font-size: 28rpx;
.radio {
height: 20rpx;
width: 20rpx;
.middle {
padding: 0 10rpx;
.phone {
padding: 20rpx 0rpx;
}
input {
width: 100%;
padding: 15rpx 5rpx;
.passowordForget {
padding: 70rpx 0rpx 20rpx;
display: flex;
justify-content: space-between;
.password {
}
.forget {
color:#06CA64
}
}
.href {
color: #1b0eab;
.agreement {
padding: 30rpx 5rpx 80rpx;
display: flex;
align-items: center;
gap: 10rpx;
font-size: $text-lg;
// font-size: 28rpx;
input {
// width: 90%;
margin: 0 auto;
padding: 15rpx 5rpx;
}
.href {
color: #1b0eab;
}
}
}
}
.login-box {
margin-top: 20rpx;
display: flex;
align-items: center;
flex-direction: column;
.login-btn {
width: 100%;
z-index: 10 !important;
border-radius: 100px;
border: none;
background-color: #06CA64;
color: white;
font-size: $text-base;
}
.no-account {
font-size: $text-base;
margin-top: 20rpx;
.register {
color: #06CA64;
}
}
.other-login {
display: flex;
gap: 150rpx;
margin: 0 auto;
margin-top: 180rpx;
.apple {
height: 90rpx;
width: 90rpx;
background:black;
border-radius: 10%;
justify-content: center;
}
.wechat {
height: 90rpx;
width: 90rpx;
background:#3aa24b;
border-radius: 10%;
justify-content: center;
}
}
}
:deep(uni-input) {
width: 100%;
}
</style>
Loading…
Cancel
Save