用户协议默认不勾选
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import AuthGate from './components/AuthGate';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import LegalPage from './pages/LegalPage';
|
||||
import PartnerAppRoutes from './PartnerAppRoutes';
|
||||
|
||||
export default function App() {
|
||||
@@ -8,6 +9,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="/*" element={<PartnerAppRoutes />} />
|
||||
</Routes>
|
||||
</AuthGate>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getPartnerProfile, hasPartnerWxSession } from '../lib/api';
|
||||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||||
import { partnerHomePath } from '../lib/partnerAccess';
|
||||
|
||||
const PUBLIC_PATHS = new Set(['/login']);
|
||||
const PUBLIC_PATHS = new Set(['/login', '/legal/user-agreement', '/legal/privacy-policy']);
|
||||
|
||||
export default function AuthGate({ children }: { children: React.ReactNode }) {
|
||||
const { ready, authenticated, account } = usePartnerSession();
|
||||
|
||||
@@ -6,6 +6,7 @@ import App from './App';
|
||||
import { PartnerSessionProvider } from './contexts/PartnerSessionContext';
|
||||
import { PartnerToastProvider } from './contexts/PartnerToastContext';
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export default function LoginPage() {
|
||||
const [phone, setPhone] = useState(remembered.phone || getLastPhone());
|
||||
const [code, setCode] = useState('');
|
||||
const [rememberAccount, setRememberAccount] = useState(remembered.remember);
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [wxLoading, setWxLoading] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
@@ -343,7 +343,14 @@ export default function LoginPage() {
|
||||
<label className="partner-checkbox-row">
|
||||
<input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />
|
||||
<span>
|
||||
我已阅读并同意 <span className="text-primary" style={{ fontWeight: 600 }}>《用户协议》</span> 与 <span className="text-primary" style={{ fontWeight: 600 }}>《隐私政策》</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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
import TabLayout from './layouts/TabLayout';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import LegalPage from './pages/LegalPage';
|
||||
import HomePage from './pages/HomePage';
|
||||
import ProductDetailPage from './pages/ProductDetailPage';
|
||||
import OrderConfirmPage from './pages/OrderConfirmPage';
|
||||
@@ -37,6 +38,8 @@ export default function App() {
|
||||
<WechatShareBootstrap />
|
||||
<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 element={<TabLayout />}>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/stores" element={<StoreListPage />} />
|
||||
|
||||
@@ -4,6 +4,7 @@ import { BrowserRouter } from 'react-router-dom';
|
||||
import { getRouterBasename } from '@dukang/weixin-sdk';
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import AppImage from '@dukang/shared-ui/AppImage';
|
||||
import type { WechatLoginResult } from '@dukang/shared-types';
|
||||
import { SmsScene } from '@dukang/shared-types';
|
||||
@@ -26,7 +26,7 @@ export default function LoginPage() {
|
||||
const [phone, setPhone] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
const [wxSessionKey, setWxSessionKey] = useState<string | null>(null);
|
||||
const [bindMode, setBindMode] = useState(false);
|
||||
@@ -229,9 +229,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>
|
||||
</footer>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -5,6 +5,8 @@ export default defineAppConfig({
|
||||
'pages/settlement/index',
|
||||
'pages/tickets/index',
|
||||
'pages/login/index',
|
||||
'pages/user-agreement/index',
|
||||
'pages/privacy-policy/index',
|
||||
'pages/stores/detail',
|
||||
'pages/orders/index',
|
||||
'pages/orders/detail',
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function LoginPage() {
|
||||
const [phone, setPhone] = useState(remembered.phone || DEMO_PHONE);
|
||||
const [code, setCode] = useState('123456');
|
||||
const [rememberAccount, setRememberAccount] = useState(remembered.remember);
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const [cooldown, setCooldown] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [wxLoading, setWxLoading] = useState(false);
|
||||
@@ -234,9 +234,25 @@ export default function LoginPage() {
|
||||
<View className={`login-checkbox${agreed ? ' is-checked' : ''}`} />
|
||||
<Text className="login-agreement-text">
|
||||
我已阅读并同意
|
||||
<Text className="login-agreement-link">《用户协议》</Text>
|
||||
<Text
|
||||
className="login-agreement-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
Taro.navigateTo({ url: '/pages/user-agreement/index' });
|
||||
}}
|
||||
>
|
||||
《用户协议》
|
||||
</Text>
|
||||
与
|
||||
<Text className="login-agreement-link">《隐私政策》</Text>
|
||||
<Text
|
||||
className="login-agreement-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
Taro.navigateTo({ url: '/pages/privacy-policy/index' });
|
||||
}}
|
||||
>
|
||||
《隐私政策》
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '隐私政策',
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { getLegalDocument } from '@dukang/shared-types';
|
||||
import '../user-agreement/legal.css';
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
const doc = getLegalDocument('privacy-policy');
|
||||
return (
|
||||
<View className="hq-legal-page">
|
||||
<View className="hq-legal-header">
|
||||
<Text className="hq-legal-back" onClick={() => Taro.navigateBack()}>
|
||||
‹
|
||||
</Text>
|
||||
<Text className="hq-legal-title">{doc.title}</Text>
|
||||
</View>
|
||||
<ScrollView scrollY className="hq-legal-body">
|
||||
<Text className="hq-legal-updated">更新日期:{doc.updatedAt}</Text>
|
||||
<Text className="hq-legal-intro">{doc.intro}</Text>
|
||||
{doc.sections.map((section) => (
|
||||
<View key={section.heading} className="hq-legal-section">
|
||||
<Text className="hq-legal-heading">{section.heading}</Text>
|
||||
{section.paragraphs.map((p, i) => (
|
||||
<Text key={`${section.heading}-${i}`} className="hq-legal-paragraph">
|
||||
{p}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '用户协议',
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { getLegalDocument } from '@dukang/shared-types';
|
||||
import './legal.css';
|
||||
|
||||
export default function UserAgreementPage() {
|
||||
const doc = getLegalDocument('user-agreement');
|
||||
return (
|
||||
<View className="hq-legal-page">
|
||||
<View className="hq-legal-header">
|
||||
<Text className="hq-legal-back" onClick={() => Taro.navigateBack()}>
|
||||
‹
|
||||
</Text>
|
||||
<Text className="hq-legal-title">{doc.title}</Text>
|
||||
</View>
|
||||
<ScrollView scrollY className="hq-legal-body">
|
||||
<Text className="hq-legal-updated">更新日期:{doc.updatedAt}</Text>
|
||||
<Text className="hq-legal-intro">{doc.intro}</Text>
|
||||
{doc.sections.map((section) => (
|
||||
<View key={section.heading} className="hq-legal-section">
|
||||
<Text className="hq-legal-heading">{section.heading}</Text>
|
||||
{section.paragraphs.map((p, i) => (
|
||||
<Text key={`${section.heading}-${i}`} className="hq-legal-paragraph">
|
||||
{p}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
.hq-legal-page {
|
||||
min-height: 100vh;
|
||||
background: #faf9f7;
|
||||
}
|
||||
|
||||
.hq-legal-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
height: 52px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #faf9f7;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.hq-legal-back {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.hq-legal-title {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hq-legal-body {
|
||||
height: calc(100vh - 52px);
|
||||
padding: 16px 20px 40px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hq-legal-updated {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #8d706e;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.hq-legal-intro {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.hq-legal-section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.hq-legal-heading {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.hq-legal-paragraph {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: #5c504c;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@@ -18,6 +18,8 @@ export default defineAppConfig({
|
||||
'pages/redeem-code/index',
|
||||
'pages/redeem-success/index',
|
||||
'pages/login/index',
|
||||
'pages/user-agreement/index',
|
||||
'pages/privacy-policy/index',
|
||||
],
|
||||
window: {
|
||||
backgroundTextStyle: 'light',
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
@import './styles/product-detail.css';
|
||||
@import './styles/store-detail.css';
|
||||
@import './styles/login.css';
|
||||
@import './styles/legal.css';
|
||||
@import './styles/order.css';
|
||||
@import './styles/address.css';
|
||||
@import './styles/redeem.css';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { View, Text, Input, Button, Image } from '@tarojs/components';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import {
|
||||
SmsScene,
|
||||
isWxAuthorizeEnabled,
|
||||
@@ -47,7 +47,7 @@ export default function LoginPage() {
|
||||
const [wxLoading, setWxLoading] = useState(false);
|
||||
const [sending, setSending] = useState(false);
|
||||
const [cooldown, setCooldown] = useState(0);
|
||||
const [agreed, setAgreed] = useState(true);
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
const [sentHint, setSentHint] = useState('');
|
||||
const [bindMode, setBindMode] = useState(initialBindMode);
|
||||
@@ -387,9 +387,25 @@ export default function LoginPage() {
|
||||
</View>
|
||||
<Text className="login-agreement-text">
|
||||
我已阅读并同意
|
||||
<Text className="login-agreement-link">《用户协议》</Text>
|
||||
<Text
|
||||
className="login-agreement-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
Taro.navigateTo({ url: '/pages/user-agreement/index' });
|
||||
}}
|
||||
>
|
||||
《用户协议》
|
||||
</Text>
|
||||
和
|
||||
<Text className="login-agreement-link">《隐私政策》</Text>
|
||||
<Text
|
||||
className="login-agreement-link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
Taro.navigateTo({ url: '/pages/privacy-policy/index' });
|
||||
}}
|
||||
>
|
||||
《隐私政策》
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '隐私政策',
|
||||
navigationStyle: 'custom',
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import { getLegalDocument } from '@dukang/shared-types';
|
||||
import PageShell from '../../components/PageShell';
|
||||
import SubPageHeader from '../../components/SubPageHeader';
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
const doc = getLegalDocument('privacy-policy');
|
||||
return (
|
||||
<PageShell variant="sub" className="legal-page">
|
||||
<SubPageHeader title={doc.title} />
|
||||
<View className="sub-page-body inset-page">
|
||||
<ScrollView scrollY className="legal-scroll">
|
||||
<Text className="legal-updated">更新日期:{doc.updatedAt}</Text>
|
||||
<Text className="legal-intro">{doc.intro}</Text>
|
||||
{doc.sections.map((section) => (
|
||||
<View key={section.heading} className="legal-section">
|
||||
<Text className="legal-heading">{section.heading}</Text>
|
||||
{section.paragraphs.map((p, i) => (
|
||||
<Text key={`${section.heading}-${i}`} className="legal-paragraph">
|
||||
{p}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '用户协议',
|
||||
navigationStyle: 'custom',
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import { getLegalDocument } from '@dukang/shared-types';
|
||||
import PageShell from '../../components/PageShell';
|
||||
import SubPageHeader from '../../components/SubPageHeader';
|
||||
|
||||
export default function UserAgreementPage() {
|
||||
const doc = getLegalDocument('user-agreement');
|
||||
return (
|
||||
<PageShell variant="sub" className="legal-page">
|
||||
<SubPageHeader title={doc.title} />
|
||||
<View className="sub-page-body inset-page">
|
||||
<ScrollView scrollY className="legal-scroll">
|
||||
<Text className="legal-updated">更新日期:{doc.updatedAt}</Text>
|
||||
<Text className="legal-intro">{doc.intro}</Text>
|
||||
{doc.sections.map((section) => (
|
||||
<View key={section.heading} className="legal-section">
|
||||
<Text className="legal-heading">{section.heading}</Text>
|
||||
{section.paragraphs.map((p, i) => (
|
||||
<Text key={`${section.heading}-${i}`} className="legal-paragraph">
|
||||
{p}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
.legal-page .legal-scroll {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
.legal-updated {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: var(--color-on-surface-variant, #8d706e);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.legal-intro {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: var(--color-on-surface, #1f1a17);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.legal-section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.legal-heading {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--color-on-surface, #1f1a17);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.legal-paragraph {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: var(--color-on-surface-variant, #5c504c);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
Reference in New Issue
Block a user