feat: 登录添加验证码
This commit is contained in:
@@ -6,6 +6,8 @@ const WECHAT_MINIAPP_AUTH_BASE_URL = "/api/v1/wechat/miniapp/auth";
|
|||||||
export interface LoginData {
|
export interface LoginData {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
captchaId?: string;
|
||||||
|
captchaCode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
@@ -18,6 +20,11 @@ export interface LoginResult {
|
|||||||
openid?: string;
|
openid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CaptchaVO {
|
||||||
|
captchaId: string;
|
||||||
|
captchaBase64: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SmsLoginData {
|
export interface SmsLoginData {
|
||||||
mobile: string;
|
mobile: string;
|
||||||
code: string;
|
code: string;
|
||||||
@@ -45,6 +52,16 @@ export interface WechatMiniappBindMobileData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AuthAPI = {
|
const AuthAPI = {
|
||||||
|
/**
|
||||||
|
* 获取图形验证码
|
||||||
|
*/
|
||||||
|
getCaptcha(): Promise<CaptchaVO> {
|
||||||
|
return publicRequest<CaptchaVO>({
|
||||||
|
url: `${AUTH_BASE_URL}/captcha`,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号密码登录
|
* 账号密码登录
|
||||||
*/
|
*/
|
||||||
@@ -58,7 +75,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送短信验证码
|
* 发送短信验证码
|
||||||
*
|
*
|
||||||
* 演示环境说明:短信服务未配置,验证码固定为 123456
|
* 演示环境说明:短信服务未配置,验证码固定为 123456
|
||||||
*/
|
*/
|
||||||
sendSmsLoginCode(mobile: string): Promise<void> {
|
sendSmsLoginCode(mobile: string): Promise<void> {
|
||||||
@@ -83,7 +100,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信小程序静默登录
|
* 微信小程序静默登录
|
||||||
*
|
*
|
||||||
* 适用场景:个人小程序
|
* 适用场景:个人小程序
|
||||||
* - 已绑定手机号的用户:直接返回 token,登录成功
|
* - 已绑定手机号的用户:直接返回 token,登录成功
|
||||||
* - 未绑定手机号的用户:返回 openid,需调用绑定手机号接口
|
* - 未绑定手机号的用户:返回 openid,需调用绑定手机号接口
|
||||||
@@ -97,7 +114,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信小程序手机号快捷登录
|
* 微信小程序手机号快捷登录
|
||||||
*
|
*
|
||||||
* 适用场景:企业认证小程序(已开通手机号快捷登录权限)
|
* 适用场景:企业认证小程序(已开通手机号快捷登录权限)
|
||||||
* 一步完成登录,无需绑定流程,自动创建新用户
|
* 一步完成登录,无需绑定流程,自动创建新用户
|
||||||
*/
|
*/
|
||||||
@@ -112,7 +129,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信小程序绑定手机号
|
* 微信小程序绑定手机号
|
||||||
*
|
*
|
||||||
* 演示环境说明:短信服务未配置,验证码固定为 123456
|
* 演示环境说明:短信服务未配置,验证码固定为 123456
|
||||||
*/
|
*/
|
||||||
wechatMiniappBindMobile(data: WechatMiniappBindMobileData): Promise<LoginResult> {
|
wechatMiniappBindMobile(data: WechatMiniappBindMobileData): Promise<LoginResult> {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "login",
|
"name": "login",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationBarTitleText": "登录"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<view class="login-logo">
|
<view class="login-logo">
|
||||||
<image class="logo-image" src="/static/logo.png" mode="aspectFit" />
|
<image class="logo-image" src="/static/logo.png" mode="aspectFit" />
|
||||||
<text class="logo-text">YouLai Admin</text>
|
<text class="logo-text">youlai-app</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 登录卡片 -->
|
<!-- 登录卡片 -->
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
class="input-field"
|
class="input-field"
|
||||||
:password="!showPassword"
|
:password="!showPassword"
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
maxlength="50"
|
:maxlength="50"
|
||||||
@confirm="handleLogin"
|
@confirm="handleLogin"
|
||||||
/>
|
/>
|
||||||
<view class="input-suffix" @click="showPassword = !showPassword">
|
<view class="input-suffix" @click="showPassword = !showPassword">
|
||||||
@@ -51,6 +51,25 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 图形验证码(密码登录时显示) -->
|
||||||
|
<view v-if="loginMode === 'PASSWORD'" class="input-box">
|
||||||
|
<wd-icon name="shield" size="20" color="#9ca3af" />
|
||||||
|
<input
|
||||||
|
v-model="formData.captchaCode"
|
||||||
|
class="input-field"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
:maxlength="6"
|
||||||
|
@confirm="handleLogin"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-if="captchaBase64"
|
||||||
|
class="captcha-img"
|
||||||
|
:src="captchaBase64"
|
||||||
|
mode="aspectFit"
|
||||||
|
@click="fetchCaptcha"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 验证码 -->
|
<!-- 验证码 -->
|
||||||
<view v-else class="input-box">
|
<view v-else class="input-box">
|
||||||
<wd-icon name="shield" size="20" color="#9ca3af" />
|
<wd-icon name="shield" size="20" color="#9ca3af" />
|
||||||
@@ -59,7 +78,7 @@
|
|||||||
class="input-field"
|
class="input-field"
|
||||||
placeholder="请输入验证码"
|
placeholder="请输入验证码"
|
||||||
type="number"
|
type="number"
|
||||||
maxlength="6"
|
:maxlength="6"
|
||||||
@confirm="handleLogin"
|
@confirm="handleLogin"
|
||||||
/>
|
/>
|
||||||
<view
|
<view
|
||||||
@@ -77,7 +96,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 登录按钮 -->
|
<!-- 登录按钮 -->
|
||||||
<button class="btn-primary" :disabled="loading || !canSubmit" @click="handleLogin">
|
<button class="btn-primary" :disabled="loading" @click="handleLogin">
|
||||||
{{ loading ? "登录中..." : "登 录" }}
|
{{ loading ? "登录中..." : "登 录" }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -130,13 +149,11 @@
|
|||||||
@click="loginMode = 'WECHAT'"
|
@click="loginMode = 'WECHAT'"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- 协议 -->
|
|
||||||
<view class="agreement">
|
<view class="agreement">
|
||||||
<wd-checkbox v-model="isAgreePolicy" shape="square" size="16px">
|
<wd-checkbox v-model="isAgreePolicy" shape="square" size="16px">
|
||||||
<text class="agreement-text">
|
<text class="agreement-text">
|
||||||
登录即代表同意
|
我已阅读并同意
|
||||||
<text class="agreement-link" @click.stop="navigateToAgreement('user')">
|
<text class="agreement-link" @click.stop="navigateToAgreement('user')">
|
||||||
《用户协议》
|
《用户协议》
|
||||||
</text>
|
</text>
|
||||||
@@ -147,6 +164,7 @@
|
|||||||
</text>
|
</text>
|
||||||
</wd-checkbox>
|
</wd-checkbox>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -169,7 +187,7 @@
|
|||||||
class="input-field"
|
class="input-field"
|
||||||
placeholder="请输入手机号"
|
placeholder="请输入手机号"
|
||||||
type="number"
|
type="number"
|
||||||
maxlength="11"
|
:maxlength="11"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -180,7 +198,7 @@
|
|||||||
class="input-field"
|
class="input-field"
|
||||||
placeholder="请输入验证码"
|
placeholder="请输入验证码"
|
||||||
type="number"
|
type="number"
|
||||||
maxlength="6"
|
:maxlength="6"
|
||||||
/>
|
/>
|
||||||
<view
|
<view
|
||||||
class="sms-btn"
|
class="sms-btn"
|
||||||
@@ -203,6 +221,15 @@
|
|||||||
</view>
|
</view>
|
||||||
</wd-popup>
|
</wd-popup>
|
||||||
|
|
||||||
|
<!-- 协议确认弹窗 -->
|
||||||
|
<wd-message-box selector="policy-box">
|
||||||
|
<view class="text-center text-sm text-gray-500 leading-relaxed">
|
||||||
|
请阅读并同意有来技术
|
||||||
|
<text class="text-blue-500" @click.stop="navigateToAgreement('user')">《用户协议》</text>
|
||||||
|
<text class="text-blue-500" @click.stop="navigateToAgreement('privacy')">《隐私政策》</text>
|
||||||
|
</view>
|
||||||
|
</wd-message-box>
|
||||||
|
|
||||||
<wd-toast />
|
<wd-toast />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -210,17 +237,18 @@
|
|||||||
<route lang="json">
|
<route lang="json">
|
||||||
{
|
{
|
||||||
"name": "login",
|
"name": "login",
|
||||||
"style": { "navigationStyle": "custom" }
|
"style": { "navigationBarTitleText": "登录" }
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
||||||
import { useToast } from "wot-design-uni";
|
import { useToast, useMessage } from "wot-design-uni";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import AuthAPI from "@/api/auth";
|
import AuthAPI from "@/api/auth";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const message = useMessage("policy-box");
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
@@ -235,8 +263,13 @@ const formData = ref({
|
|||||||
username: "admin",
|
username: "admin",
|
||||||
password: "123456",
|
password: "123456",
|
||||||
code: "123456",
|
code: "123456",
|
||||||
|
captchaCode: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 图形验证码
|
||||||
|
const captchaId = ref("");
|
||||||
|
const captchaBase64 = ref("");
|
||||||
|
|
||||||
const redirect = ref("/pages/index/index");
|
const redirect = ref("/pages/index/index");
|
||||||
|
|
||||||
// 绑定手机号相关
|
// 绑定手机号相关
|
||||||
@@ -251,6 +284,20 @@ const bindMobileForm = ref({
|
|||||||
code: "",
|
code: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pendingLoginAction = ref<"FORM" | "WECHAT_PHONE" | null>(null);
|
||||||
|
const pendingWechatPhoneCode = ref<string>("");
|
||||||
|
|
||||||
|
// 获取图形验证码
|
||||||
|
const fetchCaptcha = async () => {
|
||||||
|
try {
|
||||||
|
const res = await AuthAPI.getCaptcha();
|
||||||
|
captchaId.value = res.captchaId;
|
||||||
|
captchaBase64.value = res.captchaBase64;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("获取验证码失败", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const loginModeDesc = computed(() => {
|
const loginModeDesc = computed(() => {
|
||||||
const modeMap = {
|
const modeMap = {
|
||||||
@@ -264,7 +311,6 @@ const loginModeDesc = computed(() => {
|
|||||||
const isValidMobile = (mobile: string) => /^1\d{10}$/.test((mobile || "").trim());
|
const isValidMobile = (mobile: string) => /^1\d{10}$/.test((mobile || "").trim());
|
||||||
|
|
||||||
const canSubmit = computed(() => {
|
const canSubmit = computed(() => {
|
||||||
if (!isAgreePolicy.value) return false;
|
|
||||||
if (loginMode.value === "PASSWORD") {
|
if (loginMode.value === "PASSWORD") {
|
||||||
return (formData.value.username || "").trim() && (formData.value.password || "").trim();
|
return (formData.value.username || "").trim() && (formData.value.password || "").trim();
|
||||||
}
|
}
|
||||||
@@ -286,6 +332,8 @@ onLoad((options: any) => {
|
|||||||
loginMode.value = "PASSWORD";
|
loginMode.value = "PASSWORD";
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
// 获取图形验证码
|
||||||
|
fetchCaptcha();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnload(() => {
|
onUnload(() => {
|
||||||
@@ -305,13 +353,43 @@ const toggleLoginMode = () => {
|
|||||||
formData.value.code = "";
|
formData.value.code = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const openPolicyDialog = (action: "FORM" | "WECHAT_PHONE", phoneCode: string = "") => {
|
||||||
if (loading.value || !canSubmit.value) return;
|
pendingLoginAction.value = action;
|
||||||
if (!isAgreePolicy.value) {
|
pendingWechatPhoneCode.value = phoneCode;
|
||||||
toast.error("请先同意用户协议");
|
|
||||||
|
message
|
||||||
|
.confirm({ title: "提示" })
|
||||||
|
.then(async () => {
|
||||||
|
isAgreePolicy.value = true;
|
||||||
|
const act = pendingLoginAction.value;
|
||||||
|
const code = pendingWechatPhoneCode.value;
|
||||||
|
pendingLoginAction.value = null;
|
||||||
|
pendingWechatPhoneCode.value = "";
|
||||||
|
|
||||||
|
if (act === "WECHAT_PHONE") {
|
||||||
|
await doWechatPhoneLogin(code);
|
||||||
|
} else if (act === "FORM") {
|
||||||
|
await doFormLogin();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
pendingLoginAction.value = null;
|
||||||
|
pendingWechatPhoneCode.value = "";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async function doFormLogin() {
|
||||||
|
if (!canSubmit.value) {
|
||||||
|
if (loginMode.value === "PASSWORD") {
|
||||||
|
toast.error("请输入用户名和密码");
|
||||||
|
} else if (loginMode.value === "SMS") {
|
||||||
|
toast.error("请输入正确的手机号和验证码");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loading.value) return;
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -319,6 +397,8 @@ const handleLogin = async () => {
|
|||||||
await userStore.login({
|
await userStore.login({
|
||||||
username: formData.value.username,
|
username: formData.value.username,
|
||||||
password: formData.value.password,
|
password: formData.value.password,
|
||||||
|
captchaId: captchaId.value,
|
||||||
|
captchaCode: formData.value.captchaCode,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await userStore.loginBySms({
|
await userStore.loginBySms({
|
||||||
@@ -332,9 +412,21 @@ const handleLogin = async () => {
|
|||||||
setTimeout(() => uni.reLaunch({ url: redirect.value }), 800);
|
setTimeout(() => uni.reLaunch({ url: redirect.value }), 800);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast.error(error?.message || "登录失败");
|
toast.error(error?.message || "登录失败");
|
||||||
|
// 登录失败刷新验证码
|
||||||
|
if (loginMode.value === "PASSWORD") {
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLogin = async () => {
|
||||||
|
if (!isAgreePolicy.value) {
|
||||||
|
openPolicyDialog("FORM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await doFormLogin();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendCode = async () => {
|
const handleSendCode = async () => {
|
||||||
@@ -378,17 +470,24 @@ const startSmsCountdown = (
|
|||||||
|
|
||||||
// 微信登录
|
// 微信登录
|
||||||
const handleWechatPhoneLogin = async (e: any) => {
|
const handleWechatPhoneLogin = async (e: any) => {
|
||||||
|
const phoneCode = e.detail.code;
|
||||||
if (!isAgreePolicy.value) {
|
if (!isAgreePolicy.value) {
|
||||||
toast.error("请先同意用户协议");
|
openPolicyDialog("WECHAT_PHONE", phoneCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const phoneCode = e.detail.code;
|
|
||||||
if (!phoneCode) {
|
if (!phoneCode) {
|
||||||
// 用户拒绝授权,尝试个人小程序登录
|
// 用户拒绝授权,尝试个人小程序登录
|
||||||
await handleWechatSilentLogin();
|
await handleWechatSilentLogin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await doWechatPhoneLogin(phoneCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function doWechatPhoneLogin(phoneCode: string) {
|
||||||
|
if (!phoneCode) {
|
||||||
|
await handleWechatSilentLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
@@ -398,14 +497,13 @@ const handleWechatPhoneLogin = async (e: any) => {
|
|||||||
await userStore.getInfo();
|
await userStore.getInfo();
|
||||||
toast.success("登录成功");
|
toast.success("登录成功");
|
||||||
setTimeout(() => uni.reLaunch({ url: redirect.value }), 800);
|
setTimeout(() => uni.reLaunch({ url: redirect.value }), 800);
|
||||||
} catch (error: any) {
|
} catch {
|
||||||
// 企业登录失败,尝试个人小程序登录
|
|
||||||
toast.info("正在尝试其他登录方式...");
|
toast.info("正在尝试其他登录方式...");
|
||||||
await handleWechatSilentLogin();
|
await handleWechatSilentLogin();
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleWechatSilentLogin = async () => {
|
const handleWechatSilentLogin = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@@ -472,7 +570,7 @@ const handleBindMobile = async () => {
|
|||||||
await userStore.bindMobileForWechatMiniapp({
|
await userStore.bindMobileForWechatMiniapp({
|
||||||
openid: wechatOpenid.value,
|
openid: wechatOpenid.value,
|
||||||
mobile,
|
mobile,
|
||||||
code,
|
smsCode: code,
|
||||||
});
|
});
|
||||||
await userStore.getInfo();
|
await userStore.getInfo();
|
||||||
showBindMobilePopup.value = false;
|
showBindMobilePopup.value = false;
|
||||||
@@ -542,7 +640,7 @@ const navigateToAgreement = (type: string) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 160px 48px 0;
|
padding: 24px 48px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logo
|
// Logo
|
||||||
@@ -613,8 +711,11 @@ const navigateToAgreement = (type: string) => {
|
|||||||
|
|
||||||
// 表单区域
|
// 表单区域
|
||||||
.form-area {
|
.form-area {
|
||||||
& > view + view {
|
> view,
|
||||||
margin-top: 16px;
|
> button {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +846,12 @@ const navigateToAgreement = (type: string) => {
|
|||||||
background-color: #e5e7eb;
|
background-color: #e5e7eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.captcha-img {
|
||||||
|
width: 100px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
:global(.dark) .sms-btn-active {
|
:global(.dark) .sms-btn-active {
|
||||||
background-color: rgba(30, 58, 138, 0.3);
|
background-color: rgba(30, 58, 138, 0.3);
|
||||||
}
|
}
|
||||||
@@ -822,37 +929,25 @@ const navigateToAgreement = (type: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 协议
|
|
||||||
.agreement {
|
.agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
border-top: 1px solid #f3f4f6;
|
border-top: 1px solid #f3f4f6;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .agreement {
|
|
||||||
border-top-color: #374151;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agreement-text {
|
.agreement-text {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .agreement-text {
|
|
||||||
color: #9ca3af;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agreement-link {
|
.agreement-link {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .agreement-link {
|
|
||||||
color: #60a5fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定手机号弹窗
|
// 绑定手机号弹窗
|
||||||
.bind-popup {
|
.bind-popup {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="section-card">
|
<view v-if="isLogin" class="section-card">
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<view class="section-title">
|
<view class="section-title">
|
||||||
<wd-icon name="user" size="18" :color="currentThemeColor" />
|
<wd-icon name="user" size="18" :color="currentThemeColor" />
|
||||||
|
|||||||
Reference in New Issue
Block a user