用户协议默认不勾选
This commit is contained in:
@@ -2,6 +2,7 @@ import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import AuthGate from './components/AuthGate';
|
||||
import TabLayout from './layouts/TabLayout';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import LegalPage from './pages/LegalPage';
|
||||
import SelectStorePage from './pages/SelectStorePage';
|
||||
import HomePage from './pages/HomePage';
|
||||
import RedeemConfirmPage from './pages/RedeemConfirmPage';
|
||||
@@ -17,6 +18,8 @@ export default function App() {
|
||||
<AuthGate>
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/legal/user-agreement" element={<LegalPage docId="user-agreement" />} />
|
||||
<Route path="/legal/privacy-policy" element={<LegalPage docId="privacy-policy" />} />
|
||||
<Route path="/select-store" element={<SelectStorePage />} />
|
||||
<Route path="/staff" element={<StaffPage />} />
|
||||
<Route path="/redeem" element={<RedeemConfirmPage />} />
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Navigate, useLocation } from 'react-router-dom';
|
||||
import { getStoreProfile, hasShopWxSession } from '../lib/api';
|
||||
import { useStoreSession } from '../contexts/StoreSessionContext';
|
||||
|
||||
const PUBLIC_PATHS = new Set(['/login']);
|
||||
const PUBLIC_PATHS = new Set(['/login', '/legal/user-agreement', '/legal/privacy-policy']);
|
||||
const SELECT_STORE_PATH = '/select-store';
|
||||
|
||||
export default function AuthGate({ children }: { children: React.ReactNode }) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getRouterBasename } from '@dukang/weixin-sdk';
|
||||
import { StoreSessionProvider } from './contexts/StoreSessionContext';
|
||||
import App from './App';
|
||||
import './styles.css';
|
||||
import './styles/legal.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getLegalDocument, type LegalDocument } from '@dukang/shared-types';
|
||||
|
||||
type LegalPageProps = {
|
||||
docId: LegalDocument['id'];
|
||||
/** 返回登录页的路径,如 /login */
|
||||
backTo?: string;
|
||||
};
|
||||
|
||||
/** H5 各端共用的协议/隐私正文页 */
|
||||
export default function LegalPage({ docId, backTo = '/login' }: LegalPageProps) {
|
||||
const doc = getLegalDocument(docId);
|
||||
|
||||
return (
|
||||
<div className="legal-h5-page">
|
||||
<header className="legal-h5-header">
|
||||
<Link to={backTo} className="legal-h5-back" aria-label="返回">
|
||||
‹
|
||||
</Link>
|
||||
<h1 className="legal-h5-title">{doc.title}</h1>
|
||||
</header>
|
||||
<main className="legal-h5-body">
|
||||
<p className="legal-h5-updated">更新日期:{doc.updatedAt}</p>
|
||||
<p className="legal-h5-intro">{doc.intro}</p>
|
||||
{doc.sections.map((section) => (
|
||||
<section key={section.heading} className="legal-h5-section">
|
||||
<h2>{section.heading}</h2>
|
||||
{section.paragraphs.map((p, i) => (
|
||||
<p key={`${section.heading}-${i}`}>{p}</p>
|
||||
))}
|
||||
</section>
|
||||
))}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ export default function LoginPage() {
|
||||
const savedProfile = getStoreProfile();
|
||||
const [phone, setPhone] = useState(getLastPhone());
|
||||
const [code, setCode] = useState('');
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [wxLoading, setWxLoading] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
@@ -309,9 +309,13 @@ export default function LoginPage() {
|
||||
/>
|
||||
<span>
|
||||
我已阅读并同意
|
||||
<a href="#user-agreement">《用户协议》</a>
|
||||
<Link to="/legal/user-agreement" onClick={(e) => e.stopPropagation()}>
|
||||
《用户协议》
|
||||
</Link>
|
||||
与
|
||||
<a href="#privacy">《隐私政策》</a>
|
||||
<Link to="/legal/privacy-policy" onClick={(e) => e.stopPropagation()}>
|
||||
《隐私政策》
|
||||
</Link>
|
||||
</span>
|
||||
</label>
|
||||
</main>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
.legal-h5-page {
|
||||
min-height: 100vh;
|
||||
background: #faf9f7;
|
||||
color: #1f1a17;
|
||||
}
|
||||
|
||||
.legal-h5-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 52px;
|
||||
padding: 0 16px;
|
||||
background: #faf9f7;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.legal-h5-back {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
color: #1f1a17;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.legal-h5-title {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.legal-h5-body {
|
||||
padding: 16px 20px 40px;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.legal-h5-updated {
|
||||
margin: 0 0 12px;
|
||||
font-size: 12px;
|
||||
color: #8d706e;
|
||||
}
|
||||
|
||||
.legal-h5-intro {
|
||||
margin: 0 0 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.legal-h5-section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.legal-h5-section h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.legal-h5-section p {
|
||||
margin: 0 0 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: #5c504c;
|
||||
}
|
||||
Reference in New Issue
Block a user