Quick login required agreement without a checkbox; move the consent row above CTAs across partner/shop/user/mini login pages so it stays visible on short screens. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState, type RefObject } from 'react';
|
||||||
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import { isWxAuthorizeEnabled } from '@dukang/shared-types';
|
import { isWxAuthorizeEnabled } from '@dukang/shared-types';
|
||||||
import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk';
|
import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk';
|
||||||
@@ -24,6 +24,32 @@ import { isWechatEnv } from '../lib/weixin';
|
|||||||
const REMEMBER_PHONE_KEY = 'partner_remember_phone';
|
const REMEMBER_PHONE_KEY = 'partner_remember_phone';
|
||||||
const REMEMBER_FLAG_KEY = 'partner_remember_account';
|
const REMEMBER_FLAG_KEY = 'partner_remember_account';
|
||||||
|
|
||||||
|
function AgreementCheckbox({
|
||||||
|
agreed,
|
||||||
|
onChange,
|
||||||
|
inputRef,
|
||||||
|
}: {
|
||||||
|
agreed: boolean;
|
||||||
|
onChange: (next: boolean) => void;
|
||||||
|
inputRef?: RefObject<HTMLLabelElement | null>;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<label className="partner-checkbox-row partner-checkbox-row--agreement" ref={inputRef}>
|
||||||
|
<input type="checkbox" checked={agreed} onChange={(e) => onChange(e.target.checked)} />
|
||||||
|
<span>
|
||||||
|
我已阅读并同意{' '}
|
||||||
|
<Link to="/legal/user-agreement" className="text-primary" style={{ fontWeight: 600 }} onClick={(e) => e.stopPropagation()}>
|
||||||
|
《用户协议》
|
||||||
|
</Link>{' '}
|
||||||
|
与{' '}
|
||||||
|
<Link to="/legal/privacy-policy" className="text-primary" style={{ fontWeight: 600 }} onClick={(e) => e.stopPropagation()}>
|
||||||
|
《隐私政策》
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function maskPhone(phone: string) {
|
function maskPhone(phone: string) {
|
||||||
if (phone.length < 7) return phone;
|
if (phone.length < 7) return phone;
|
||||||
return `${phone.slice(0, 3)} **** ${phone.slice(-4)}`;
|
return `${phone.slice(0, 3)} **** ${phone.slice(-4)}`;
|
||||||
@@ -74,6 +100,7 @@ export default function LoginPage() {
|
|||||||
const [msg, setMsg] = useState('');
|
const [msg, setMsg] = useState('');
|
||||||
const [codeCooldown, setCodeCooldown] = useState(0);
|
const [codeCooldown, setCodeCooldown] = useState(0);
|
||||||
const [wxAuthorize, setWxAuthorize] = useState(false);
|
const [wxAuthorize, setWxAuthorize] = useState(false);
|
||||||
|
const agreementRef = useRef<HTMLLabelElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchClientConfig()
|
fetchClientConfig()
|
||||||
@@ -88,6 +115,7 @@ export default function LoginPage() {
|
|||||||
function ensureAgreed() {
|
function ensureAgreed() {
|
||||||
if (!agreed) {
|
if (!agreed) {
|
||||||
setMsg('请先勾选并同意用户协议');
|
setMsg('请先勾选并同意用户协议');
|
||||||
|
agreementRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -230,10 +258,16 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
<nav style={{ width: '100%', maxWidth: 384, marginTop: 16 }}>
|
<nav style={{ width: '100%', maxWidth: 384, marginTop: 16 }}>
|
||||||
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center', marginBottom: 12 }}>{msg}</p>}
|
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center', marginBottom: 12 }}>{msg}</p>}
|
||||||
|
<AgreementCheckbox
|
||||||
|
agreed={agreed}
|
||||||
|
onChange={setAgreed}
|
||||||
|
inputRef={agreementRef}
|
||||||
|
/>
|
||||||
{canWechatQuick ? (
|
{canWechatQuick ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="partner-btn-primary"
|
className="partner-btn-primary"
|
||||||
|
style={{ marginTop: 16 }}
|
||||||
disabled={wxLoading}
|
disabled={wxLoading}
|
||||||
onClick={() => void wechatLogin()}
|
onClick={() => void wechatLogin()}
|
||||||
>
|
>
|
||||||
@@ -241,7 +275,7 @@ export default function LoginPage() {
|
|||||||
<span>{wxLoading ? '登录中...' : '微信一键登录'}</span>
|
<span>{wxLoading ? '登录中...' : '微信一键登录'}</span>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<p className="partner-auth-msg" style={{ textAlign: 'center', marginBottom: 12 }}>
|
<p className="partner-auth-msg" style={{ textAlign: 'center', marginTop: 12, marginBottom: 12 }}>
|
||||||
{wxAuthorize && !isWechatEnv()
|
{wxAuthorize && !isWechatEnv()
|
||||||
? '请在微信内打开以使用一键登录'
|
? '请在微信内打开以使用一键登录'
|
||||||
: '请使用验证码登录并绑定微信后,即可 7 天内免登录'}
|
: '请使用验证码登录并绑定微信后,即可 7 天内免登录'}
|
||||||
@@ -321,6 +355,12 @@ export default function LoginPage() {
|
|||||||
<span>记住账号</span>
|
<span>记住账号</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<AgreementCheckbox
|
||||||
|
agreed={agreed}
|
||||||
|
onChange={setAgreed}
|
||||||
|
inputRef={agreementRef}
|
||||||
|
/>
|
||||||
|
|
||||||
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center' }}>{msg}</p>}
|
{msg && <p className="partner-auth-msg" style={{ color: 'var(--color-error, #d33)', fontSize: 13, textAlign: 'center' }}>{msg}</p>}
|
||||||
|
|
||||||
<button type="button" className="partner-btn-primary" onClick={() => void login()} disabled={loading}>
|
<button type="button" className="partner-btn-primary" onClick={() => void login()} disabled={loading}>
|
||||||
@@ -339,20 +379,6 @@ export default function LoginPage() {
|
|||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<label className="partner-checkbox-row">
|
|
||||||
<input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />
|
|
||||||
<span>
|
|
||||||
我已阅读并同意{' '}
|
|
||||||
<Link to="/legal/user-agreement" className="text-primary" style={{ fontWeight: 600 }} onClick={(e) => e.stopPropagation()}>
|
|
||||||
《用户协议》
|
|
||||||
</Link>{' '}
|
|
||||||
与{' '}
|
|
||||||
<Link to="/legal/privacy-policy" className="text-primary" style={{ fontWeight: 600 }} onClick={(e) => e.stopPropagation()}>
|
|
||||||
《隐私政策》
|
|
||||||
</Link>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,23 @@ html {
|
|||||||
/* ── Partner auth ── */
|
/* ── Partner auth ── */
|
||||||
.partner-auth-page {
|
.partner-auth-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
min-height: 100dvh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: flex-start;
|
||||||
padding: 48px var(--space-page) var(--space-page);
|
padding: 48px var(--space-page) calc(24px + env(safe-area-inset-bottom, 0px));
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
background-image: url("https://www.transparenttextures.com/patterns/natural-paper.png");
|
background-image: url("https://www.transparenttextures.com/patterns/natural-paper.png");
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-height: 720px) {
|
||||||
|
.partner-auth-page {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.partner-auth-page--quick {
|
.partner-auth-page--quick {
|
||||||
@@ -166,14 +176,27 @@ html {
|
|||||||
|
|
||||||
.partner-checkbox-row {
|
.partner-checkbox-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
margin-top: var(--space-md);
|
margin-top: var(--space-md);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
color: var(--color-on-surface-variant);
|
color: var(--color-on-surface-variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
.partner-checkbox-row input { margin-top: 0; accent-color: var(--color-heritage-red); }
|
.partner-checkbox-row input {
|
||||||
|
margin-top: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
accent-color: var(--color-heritage-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-checkbox-row--agreement {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.partner-auth-footer {
|
.partner-auth-footer {
|
||||||
margin-top: var(--space-lg);
|
margin-top: var(--space-lg);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState, type RefObject } from 'react';
|
||||||
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import AppImage from '@dukang/shared-ui/AppImage';
|
import AppImage from '@dukang/shared-ui/AppImage';
|
||||||
import { isWxAuthorizeEnabled } from '@dukang/shared-types';
|
import { isWxAuthorizeEnabled } from '@dukang/shared-types';
|
||||||
@@ -28,6 +28,36 @@ function formatWechatError(e: unknown): string {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ShopAgreementCheckbox({
|
||||||
|
agreed,
|
||||||
|
onChange,
|
||||||
|
labelRef,
|
||||||
|
}: {
|
||||||
|
agreed: boolean;
|
||||||
|
onChange: (next: boolean) => void;
|
||||||
|
labelRef?: RefObject<HTMLLabelElement | null>;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<label className="shop-login-agreement" ref={labelRef}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={agreed}
|
||||||
|
onChange={(e) => onChange(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
我已阅读并同意
|
||||||
|
<Link to="/legal/user-agreement" onClick={(e) => e.stopPropagation()}>
|
||||||
|
《用户协议》
|
||||||
|
</Link>
|
||||||
|
与
|
||||||
|
<Link to="/legal/privacy-policy" onClick={(e) => e.stopPropagation()}>
|
||||||
|
《隐私政策》
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { applySession } = useStoreSession();
|
const { applySession } = useStoreSession();
|
||||||
@@ -42,6 +72,7 @@ export default function LoginPage() {
|
|||||||
const [msg, setMsg] = useState('');
|
const [msg, setMsg] = useState('');
|
||||||
const [codeCooldown, setCodeCooldown] = useState(0);
|
const [codeCooldown, setCodeCooldown] = useState(0);
|
||||||
const [wxAuthorize, setWxAuthorize] = useState(false);
|
const [wxAuthorize, setWxAuthorize] = useState(false);
|
||||||
|
const agreementRef = useRef<HTMLLabelElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchClientConfig()
|
fetchClientConfig()
|
||||||
@@ -71,6 +102,7 @@ export default function LoginPage() {
|
|||||||
function ensureAgreed() {
|
function ensureAgreed() {
|
||||||
if (!agreed) {
|
if (!agreed) {
|
||||||
setMsg('请先阅读并同意用户协议');
|
setMsg('请先阅读并同意用户协议');
|
||||||
|
agreementRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -180,6 +212,11 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
<div className="shop-quick-actions">
|
<div className="shop-quick-actions">
|
||||||
{msg && <p className="shop-login-msg">{msg}</p>}
|
{msg && <p className="shop-login-msg">{msg}</p>}
|
||||||
|
<ShopAgreementCheckbox
|
||||||
|
agreed={agreed}
|
||||||
|
onChange={setAgreed}
|
||||||
|
labelRef={agreementRef}
|
||||||
|
/>
|
||||||
{canWechatQuick ? (
|
{canWechatQuick ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -270,6 +307,12 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
{msg && <p className="shop-login-msg">{msg}</p>}
|
{msg && <p className="shop-login-msg">{msg}</p>}
|
||||||
|
|
||||||
|
<ShopAgreementCheckbox
|
||||||
|
agreed={agreed}
|
||||||
|
onChange={setAgreed}
|
||||||
|
labelRef={agreementRef}
|
||||||
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="shop-login-submit"
|
className="shop-login-submit"
|
||||||
@@ -300,24 +343,6 @@ export default function LoginPage() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label className="shop-login-agreement">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={agreed}
|
|
||||||
onChange={(e) => setAgreed(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
我已阅读并同意
|
|
||||||
<Link to="/legal/user-agreement" onClick={(e) => e.stopPropagation()}>
|
|
||||||
《用户协议》
|
|
||||||
</Link>
|
|
||||||
与
|
|
||||||
<Link to="/legal/privacy-policy" onClick={(e) => e.stopPropagation()}>
|
|
||||||
《隐私政策》
|
|
||||||
</Link>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer className="shop-login-footer">
|
<footer className="shop-login-footer">
|
||||||
|
|||||||
@@ -188,7 +188,7 @@
|
|||||||
|
|
||||||
.shop-login-submit {
|
.shop-login-submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 32px;
|
margin-top: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
@@ -248,14 +248,18 @@
|
|||||||
|
|
||||||
.shop-login-agreement {
|
.shop-login-agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
max-width: 280px;
|
max-width: 100%;
|
||||||
margin: 32px auto 0;
|
margin: 16px 0 0;
|
||||||
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shop-login-agreement input {
|
.shop-login-agreement input {
|
||||||
margin-top: 0;
|
margin-top: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
accent-color: var(--color-heritage-red);
|
accent-color: var(--color-heritage-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,6 +459,15 @@
|
|||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shop-quick-actions .shop-login-agreement {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shop-quick-actions .shop-quick-login-btn {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.shop-quick-login-btn {
|
.shop-quick-login-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||||
import AppImage from '@dukang/shared-ui/AppImage';
|
import AppImage from '@dukang/shared-ui/AppImage';
|
||||||
import type { WechatLoginResult } from '@dukang/shared-types';
|
import type { WechatLoginResult } from '@dukang/shared-types';
|
||||||
@@ -31,6 +31,7 @@ export default function LoginPage() {
|
|||||||
const [wxSessionKey, setWxSessionKey] = useState<string | null>(null);
|
const [wxSessionKey, setWxSessionKey] = useState<string | null>(null);
|
||||||
const [bindMode, setBindMode] = useState(false);
|
const [bindMode, setBindMode] = useState(false);
|
||||||
const [wxAuthorize, setWxAuthorize] = useState(false);
|
const [wxAuthorize, setWxAuthorize] = useState(false);
|
||||||
|
const agreementRef = useRef<HTMLLabelElement>(null);
|
||||||
const { sendCode, sending, codeCooldown, sentHint, error: smsError, setError: setSmsError, clearMessages } =
|
const { sendCode, sending, codeCooldown, sentHint, error: smsError, setError: setSmsError, clearMessages } =
|
||||||
useSmsCode();
|
useSmsCode();
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ export default function LoginPage() {
|
|||||||
function ensureAgreed() {
|
function ensureAgreed() {
|
||||||
if (!agreed) {
|
if (!agreed) {
|
||||||
setMsg('请先勾选并同意用户协议');
|
setMsg('请先勾选并同意用户协议');
|
||||||
|
agreementRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -194,6 +196,23 @@ export default function LoginPage() {
|
|||||||
{displayMsg || sentHint}
|
{displayMsg || sentHint}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
<label className="login-agreement" ref={agreementRef}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={agreed}
|
||||||
|
onChange={(e) => setAgreed(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
我已阅读并同意
|
||||||
|
<Link to="/legal/user-agreement" onClick={(e) => e.stopPropagation()}>
|
||||||
|
《用户协议》
|
||||||
|
</Link>
|
||||||
|
和
|
||||||
|
<Link to="/legal/privacy-policy" onClick={(e) => e.stopPropagation()}>
|
||||||
|
《隐私政策》
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="login-sms-btn"
|
className="login-sms-btn"
|
||||||
@@ -219,26 +238,6 @@ export default function LoginPage() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer className="login-footer">
|
|
||||||
<label className="login-agreement">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={agreed}
|
|
||||||
onChange={(e) => setAgreed(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
我已阅读并同意
|
|
||||||
<Link to="/legal/user-agreement" onClick={(e) => e.stopPropagation()}>
|
|
||||||
《用户协议》
|
|
||||||
</Link>
|
|
||||||
和
|
|
||||||
<Link to="/legal/privacy-policy" onClick={(e) => e.stopPropagation()}>
|
|
||||||
《隐私政策》
|
|
||||||
</Link>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1558,8 +1558,9 @@
|
|||||||
|
|
||||||
.login-agreement {
|
.login-agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
margin: 12px 0 16px;
|
||||||
font-family: var(--font-label);
|
font-family: var(--font-label);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -1571,8 +1572,8 @@
|
|||||||
|
|
||||||
.login-agreement input {
|
.login-agreement input {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
width: 16px;
|
width: 18px;
|
||||||
height: 16px;
|
height: 18px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
accent-color: var(--color-heritage-red);
|
accent-color: var(--color-heritage-red);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,6 +177,11 @@
|
|||||||
color: var(--hq-muted);
|
color: var(--hq-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-agreement {
|
||||||
|
margin: 8px 0 12px;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.login-remember {
|
.login-remember {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
|
|||||||
@@ -212,24 +212,6 @@ export default function LoginPage() {
|
|||||||
<Text>记住账号</Text>
|
<Text>记住账号</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Button className="hq-btn hq-btn--primary hq-btn--block login-submit" loading={loading} onClick={smsLogin}>
|
|
||||||
登录
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{msg ? <Text className="login-msg">{msg}</Text> : null}
|
|
||||||
|
|
||||||
<View className="login-divider">
|
|
||||||
<Text>其他登录方式</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View
|
|
||||||
className={`login-wechat-btn${wxLoading ? ' is-disabled' : ''}`}
|
|
||||||
onClick={wxLoading ? undefined : wechatLogin}
|
|
||||||
>
|
|
||||||
<WechatIcon />
|
|
||||||
<Text>{wxLoading ? '登录中...' : '微信一键授权'}</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View className="login-agreement" onClick={() => setAgreed((v) => !v)}>
|
<View className="login-agreement" onClick={() => setAgreed((v) => !v)}>
|
||||||
<View className={`login-checkbox${agreed ? ' is-checked' : ''}`} />
|
<View className={`login-checkbox${agreed ? ' is-checked' : ''}`} />
|
||||||
<Text className="login-agreement-text">
|
<Text className="login-agreement-text">
|
||||||
@@ -255,6 +237,24 @@ export default function LoginPage() {
|
|||||||
</Text>
|
</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{msg ? <Text className="login-msg">{msg}</Text> : null}
|
||||||
|
|
||||||
|
<Button className="hq-btn hq-btn--primary hq-btn--block login-submit" loading={loading} onClick={smsLogin}>
|
||||||
|
登录
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<View className="login-divider">
|
||||||
|
<Text>其他登录方式</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View
|
||||||
|
className={`login-wechat-btn${wxLoading ? ' is-disabled' : ''}`}
|
||||||
|
onClick={wxLoading ? undefined : wechatLogin}
|
||||||
|
>
|
||||||
|
<WechatIcon />
|
||||||
|
<Text>{wxLoading ? '登录中...' : '微信一键授权'}</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className="login-footer">
|
<View className="login-footer">
|
||||||
|
|||||||
@@ -329,6 +329,33 @@ export default function LoginPage() {
|
|||||||
<Text className="login-msg login-msg--hint" style={{ marginBottom: 16 }}>
|
<Text className="login-msg login-msg--hint" style={{ marginBottom: 16 }}>
|
||||||
使用微信支付前需授权微信账号
|
使用微信支付前需授权微信账号
|
||||||
</Text>
|
</Text>
|
||||||
|
<View className="login-agreement" onClick={() => setAgreed((v) => !v)}>
|
||||||
|
<View className={`login-agreement-check${agreed ? ' login-agreement-check--on' : ''}`}>
|
||||||
|
{agreed ? <Text>✓</Text> : null}
|
||||||
|
</View>
|
||||||
|
<Text className="login-agreement-text">
|
||||||
|
我已阅读并同意
|
||||||
|
<Text
|
||||||
|
className="login-agreement-link"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Taro.navigateTo({ url: '/pages/user-agreement/index' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
《用户协议》
|
||||||
|
</Text>
|
||||||
|
和
|
||||||
|
<Text
|
||||||
|
className="login-agreement-link"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Taro.navigateTo({ url: '/pages/privacy-policy/index' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
《隐私政策》
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
{showWechatLogin ? (
|
{showWechatLogin ? (
|
||||||
<WechatLoginButton loading={wxLoading} onClick={() => void wechatLogin()} />
|
<WechatLoginButton loading={wxLoading} onClick={() => void wechatLogin()} />
|
||||||
) : null}
|
) : null}
|
||||||
@@ -376,6 +403,34 @@ export default function LoginPage() {
|
|||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
<View className="login-agreement" onClick={() => setAgreed((v) => !v)}>
|
||||||
|
<View className={`login-agreement-check${agreed ? ' login-agreement-check--on' : ''}`}>
|
||||||
|
{agreed ? <Text>✓</Text> : null}
|
||||||
|
</View>
|
||||||
|
<Text className="login-agreement-text">
|
||||||
|
我已阅读并同意
|
||||||
|
<Text
|
||||||
|
className="login-agreement-link"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Taro.navigateTo({ url: '/pages/user-agreement/index' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
《用户协议》
|
||||||
|
</Text>
|
||||||
|
和
|
||||||
|
<Text
|
||||||
|
className="login-agreement-link"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Taro.navigateTo({ url: '/pages/privacy-policy/index' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
《隐私政策》
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
className={`login-sms-btn${loading ? ' login-sms-btn--disabled' : ''}`}
|
className={`login-sms-btn${loading ? ' login-sms-btn--disabled' : ''}`}
|
||||||
onClick={loading ? undefined : () => void login()}
|
onClick={loading ? undefined : () => void login()}
|
||||||
@@ -415,36 +470,6 @@ export default function LoginPage() {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className="login-footer">
|
|
||||||
<View className="login-agreement" onClick={() => setAgreed((v) => !v)}>
|
|
||||||
<View className={`login-agreement-check${agreed ? ' login-agreement-check--on' : ''}`}>
|
|
||||||
{agreed ? <Text>✓</Text> : null}
|
|
||||||
</View>
|
|
||||||
<Text className="login-agreement-text">
|
|
||||||
我已阅读并同意
|
|
||||||
<Text
|
|
||||||
className="login-agreement-link"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
Taro.navigateTo({ url: '/pages/user-agreement/index' });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
《用户协议》
|
|
||||||
</Text>
|
|
||||||
和
|
|
||||||
<Text
|
|
||||||
className="login-agreement-link"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
Taro.navigateTo({ url: '/pages/privacy-policy/index' });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
《隐私政策》
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</PageShell>
|
</PageShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,8 +306,9 @@
|
|||||||
|
|
||||||
.login-agreement {
|
.login-agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
margin: 12px 0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-agreement-check {
|
.login-agreement-check {
|
||||||
|
|||||||
Reference in New Issue
Block a user