提交 5452e724 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 添加帮助中心和联系我们页面,优化页面布局和样式

上级 d32120dc
...@@ -89,6 +89,7 @@ export function LearningLayout() { ...@@ -89,6 +89,7 @@ export function LearningLayout() {
<Layout.Footer className='learning-layout__footer'> <Layout.Footer className='learning-layout__footer'>
<nav className='learning-layout__footer-links' aria-label='页脚导航'> <nav className='learning-layout__footer-links' aria-label='页脚导航'>
<Link to='/about'>关于我们</Link> <Link to='/about'>关于我们</Link>
<Link to='/help'>帮助中心</Link>
<a <a
href='https://webapp-pub.ezijing.com/book-app/agreement/ser_agreement.html?v=3' href='https://webapp-pub.ezijing.com/book-app/agreement/ser_agreement.html?v=3'
target='_blank' target='_blank'
...@@ -103,7 +104,7 @@ export function LearningLayout() { ...@@ -103,7 +104,7 @@ export function LearningLayout() {
> >
隐私政策 隐私政策
</a> </a>
<span>联系我们</span> <Link to='/contact'>联系我们</Link>
</nav> </nav>
</Layout.Footer> </Layout.Footer>
<MobileDownloadModal /> <MobileDownloadModal />
......
import type { ReactNode } from 'react'
import { RedbudBranch, RedbudFlower } from './Redbud'
interface PageHeroProps {
title: string
intro?: ReactNode
/** 眉题,默认「✿ 清控紫荆数智学堂」 */
eyebrow?: ReactNode
}
const brandEyebrow = (
<>
<RedbudFlower size={13} color='#ffdce6' centerColor='#b5284e' />
清控紫荆数智学堂
</>
)
/** 关于我们 / 帮助中心 / 联系我们 共用的页头:深紫荆红底 + 宋体标题 + 紫荆枝纹样 */
export function PageHero({ title, intro, eyebrow = brandEyebrow }: PageHeroProps) {
return (
<header className='info-hero'>
<div className='info-hero__text'>
<p className='info-hero__eyebrow'>{eyebrow}</p>
<h1 className='info-hero__title'>{title}</h1>
{intro ? <p className='info-hero__intro'>{intro}</p> : null}
</div>
<RedbudBranch className='info-hero__mark' />
</header>
)
}
import type { CSSProperties } from 'react'
/** 五瓣紫荆花 —— 品牌的视觉签名,用于列表标记、卡片图标与页头装饰 */
const PETAL_ANGLES = [0, 72, 144, 216, 288]
interface RedbudFlowerProps {
size?: number
/** 花瓣颜色 */
color?: string
/** 花蕊颜色 */
centerColor?: string
className?: string
style?: CSSProperties
}
export function RedbudFlower({
size = 16,
color = '#aa1941',
centerColor = '#ffffff',
className,
style,
}: RedbudFlowerProps) {
return (
<svg
className={className}
style={style}
width={size}
height={size}
viewBox='0 0 40 40'
aria-hidden='true'
focusable='false'
>
{PETAL_ANGLES.map((angle) => (
<ellipse
key={angle}
cx='20'
cy='8.4'
rx='5.4'
ry='7.6'
fill={color}
transform={`rotate(${angle} 20 20)`}
/>
))}
<circle cx='20' cy='20' r='4.4' fill={centerColor} />
</svg>
)
}
interface FlowerShapeProps {
offsetX: number
offsetY: number
petal: string
}
function FlowerShape({ offsetX, offsetY, petal }: FlowerShapeProps) {
return (
<g transform={`translate(${offsetX} ${offsetY})`}>
{PETAL_ANGLES.map((angle) => (
<ellipse key={angle} cx='0' cy='-6' rx='4' ry='5.6' fill={petal} transform={`rotate(${angle})`} />
))}
<circle r='3.2' fill='#c2456a' />
</g>
)
}
/** 花团(紫荆花成簇生于枝干,三朵一组) */
function FlowerCluster({ x, y, scale }: { x: number; y: number; scale: number }) {
return (
<g transform={`translate(${x} ${y}) scale(${scale})`}>
<FlowerShape offsetX={-14} offsetY={-8} petal='#ffdce6' />
<FlowerShape offsetX={0} offsetY={0} petal='#ffffff' />
<FlowerShape offsetX={12} offsetY={-6} petal='#ffdce6' />
</g>
)
}
const CLUSTERS = [
{ x: 34, y: 92, scale: 1 },
{ x: 96, y: 60, scale: 0.8 },
{ x: 168, y: 42, scale: 0.95 },
{ x: 222, y: 54, scale: 0.65 },
]
interface RedbudBranchProps {
className?: string
style?: CSSProperties
}
/** 一枝紫荆 —— 页头 hero 的装饰纹样(浅色线稿,用于深紫荆红底) */
export function RedbudBranch({ className, style }: RedbudBranchProps) {
return (
<svg
className={className}
style={style}
viewBox='0 0 260 130'
fill='none'
aria-hidden='true'
focusable='false'
>
<path
d='M10 118 C 66 112, 128 84, 186 60 C 216 48, 238 42, 252 40'
stroke='#ffc9d6'
strokeWidth='3'
strokeLinecap='round'
/>
<path d='M96 60 C 88 44, 84 34, 90 22' stroke='#ffc9d6' strokeWidth='2.4' strokeLinecap='round' />
{CLUSTERS.map((cluster, index) => (
<FlowerCluster key={index} x={cluster.x} y={cluster.y} scale={cluster.scale} />
))}
{/* 心形叶(紫荆的叶形,尖顶心形) */}
<path
d='M212 6 C 221 2, 230 8, 230 17 C 230 27, 222 34, 212 30 C 202 34, 194 27, 194 17 C 194 8, 203 2, 212 6 Z'
fill='#ffdce6'
opacity='0.85'
/>
</svg>
)
}
import { Card, Divider, Space, Typography } from 'antd' import { PageHero } from '../components/PageHero'
import { RedbudFlower } from '../components/Redbud'
import './info-pages.css'
const agreementBaseUrl = 'https://webapp-pub.ezijing.com/book-app/agreement' const agreementBaseUrl = 'https://webapp-pub.ezijing.com/book-app/agreement'
const NUMERALS = ['一', '二', '三', '四', '五']
const teachingLoop = [
{ title: '编写', desc: '多形态工具与 AI 大模型结合的数字教材编辑器' },
{ title: '出版', desc: '高品质专业出版服务' },
{ title: '学习', desc: '富媒体、交互式数字教材' },
{ title: '测验', desc: '基于大数据、多模态 AI 的学习测评' },
{ title: '评价', desc: '教学评价与全流程数字化管理' },
]
const highlights = [
{
title: 'AI 数字教材编辑器',
desc: '多形态工具与 AI 大模型结合,打通学校端、出版端、教学端、学生端的完整流程',
},
{
title: '富媒体交互式教材',
desc: '支持富媒体、交互式数字教材,满足全流程数字化教学及管理要求',
},
{
title: '专业出版服务',
desc: '配套高品质专业出版服务,实现教育资源的优化配置与高效利用',
},
]
export function AboutView() { export function AboutView() {
return ( return (
<main> <main className='info-page'>
<Typography.Title level={1}>关于我们</Typography.Title> <PageHero
<Card> title='关于我们'
<Space direction='vertical' size='middle' style={{ width: '100%', textAlign: 'center' }}> intro='清控紫荆教育深耕高等教育多年,以数字教材为核心,贯通「编写 — 出版 — 学习 — 测验 — 评价」的教学闭环。'
<Typography.Title level={2} style={{ margin: 0 }}> />
清控紫荆数智学堂
</Typography.Title> <section className='info-section'>
<Typography.Text type='secondary'>清控紫荆(北京)教育科技股份有限公司</Typography.Text> <h2 className='info-section__title'>教学闭环</h2>
<Divider style={{ margin: 0 }} /> <p className='info-section__lede'>
<Space split={<Divider type='vertical' />}> 数字教材的重要性并不局限于教材的编写与出版——它更应服务于教学的后续环节,构建起以数字教材为核心的完整教学闭环。
</p>
<div className='info-flow'>
<ol className='info-flow__steps'>
{teachingLoop.map((step, index) => (
<li className='info-flow__step' key={step.title}>
<span className='info-flow__num' aria-hidden='true'>
{NUMERALS[index]}
</span>
<span className='info-flow__name'>{step.title}</span>
<span className='info-flow__desc'>{step.desc}</span>
{index < teachingLoop.length - 1 ? (
<span className='info-flow__arrow' aria-hidden='true'>
→
</span>
) : null}
</li>
))}
</ol>
<svg
className='info-flow__loop'
viewBox='0 0 800 46'
preserveAspectRatio='none'
aria-hidden='true'
>
<defs>
<marker
id='info-loop-arrow'
viewBox='0 0 10 10'
refX='9'
refY='5'
markerWidth='7'
markerHeight='7'
orient='auto'
>
<path d='M0 0 L10 5 L0 10 z' fill='#aa1941' />
</marker>
</defs>
<path
d='M720 14 C 560 46, 240 46, 80 14'
fill='none'
stroke='#aa1941'
strokeWidth='2'
strokeDasharray='0.5 8'
strokeLinecap='round'
markerEnd='url(#info-loop-arrow)'
/>
</svg>
<p className='info-flow__caption'>循环往复,构筑教育新质生产力</p>
</div>
</section>
<section className='info-section'>
<h2 className='info-section__title'>平台能力</h2>
<p className='info-section__lede'>
平台打通「学校端 — 出版端 — 教学端 — 学生端」的完整流程,基于大数据、多模态的 AI 辅助教学,配套高品质专业出版服务。
</p>
<div className='info-highlights'>
{highlights.map((item) => (
<article className='info-highlight' key={item.title}>
<span className='info-highlight__icon'>
<RedbudFlower size={22} />
</span>
<h3 className='info-highlight__title'>{item.title}</h3>
<p className='info-highlight__desc'>{item.desc}</p>
</article>
))}
</div>
</section>
<section className='info-card info-meta' aria-label='公司信息'>
<dl className='info-meta__rows'>
<div className='info-meta__row'>
<dt>公司名称</dt>
<dd>清控紫荆(北京)教育科技股份有限公司</dd>
</div>
<div className='info-meta__row'>
<dt>地址</dt>
<dd>北京市海淀区北四环西路52号方正国际大厦5层501</dd>
</div>
<div className='info-meta__row'>
<dt>联系电话</dt>
<dd>
<a href='tel:010-62793909'>010-62793909</a>
</dd>
</div>
<div className='info-meta__row'>
<dt>邮箱</dt>
<dd>
<a href='mailto:service@ezijing.com'>service@ezijing.com</a>
</dd>
</div>
<div className='info-meta__row'>
<dt>相关协议</dt>
<dd>
<a href={`${agreementBaseUrl}/ser_agreement.html?v=3`} target='_blank' rel='noreferrer'> <a href={`${agreementBaseUrl}/ser_agreement.html?v=3`} target='_blank' rel='noreferrer'>
《用户协议》 《用户协议》
</a> </a>
<a href={`${agreementBaseUrl}/pri_agreement.html?v=3`} target='_blank' rel='noreferrer'> <a href={`${agreementBaseUrl}/pri_agreement.html?v=3`} target='_blank' rel='noreferrer'>
《隐私政策》 《隐私政策》
</a> </a>
</Space> </dd>
<Typography.Text type='secondary'> </div>
</dl>
<p className='info-meta__copyright'>
Copyright © 2026 Zijing Education. All rights reserved. Copyright © 2026 Zijing Education. All rights reserved.
<br /> <br />
京ICP证150431号 京ICP证150431号
</Typography.Text> </p>
</Space> </section>
</Card>
</main> </main>
) )
} }
import { EnvironmentOutlined, MailOutlined, PhoneOutlined } from '@ant-design/icons'
import { PageHero } from '../components/PageHero'
import './info-pages.css'
const contactChannels = [
{
key: 'address',
icon: EnvironmentOutlined,
label: '公司地址',
value: '北京市海淀区北四环西路52号方正国际大厦5层501',
},
{ key: 'phone', icon: PhoneOutlined, label: '联系电话', value: '010-62793909', href: 'tel:010-62793909' },
{
key: 'email',
icon: MailOutlined,
label: '电子邮箱',
value: 'service@ezijing.com',
href: 'mailto:service@ezijing.com',
},
]
export function ContactView() {
return (
<main className='info-page'>
<PageHero
title='联系我们'
intro='清控紫荆(北京)教育科技股份有限公司。使用平台时遇到任何问题,均可通过以下方式与我们联系。'
/>
<section className='contact-cards' aria-label='联系方式'>
{contactChannels.map(({ key, icon: Icon, label, value, href }) => (
<article className='contact-card' key={key}>
<span className='contact-card__icon'>
<Icon />
</span>
<p className='contact-card__label'>{label}</p>
<p className='contact-card__value'>{href ? <a href={href}>{value}</a> : value}</p>
</article>
))}
</section>
</main>
)
}
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { Alert, Button, Card, Skeleton, Typography } from 'antd' import { Alert, Button, Card, Skeleton } from 'antd'
import { useParams } from 'react-router' import { Link, useParams } from 'react-router'
import { helpArticleOptions } from '../query' import { helpArticleOptions } from '../query'
import { PageHero } from '../components/PageHero'
import './info-pages.css'
const ARTICLE_BASE_STYLES =
'body{margin:0;padding:24px;color:#262626;font:16px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;word-break:break-word}img,video,table,pre,code{max-width:100%;box-sizing:border-box}pre{white-space:pre-wrap}table,td,th{border:1px solid #d9d9d9;border-collapse:collapse;padding:6px}'
export function HelpDetailView() { export function HelpDetailView() {
const { id = '' } = useParams() const { id = '' } = useParams()
const articleQuery = useQuery(helpArticleOptions(id)) const articleQuery = useQuery(helpArticleOptions(id))
if (articleQuery.isPending) return <Skeleton active paragraph={{ rows: 12 }} />
if (articleQuery.isPending)
return (
<main className='info-page'>
<section className='info-card'>
<Skeleton active paragraph={{ rows: 10 }} style={{ padding: '16px 0' }} />
</section>
</main>
)
if (articleQuery.isError) if (articleQuery.isError)
return ( return (
<main className='info-page'>
<PageHero title='帮助详情' intro='文章加载失败,请稍后重试。' />
<section className='info-card'>
<Alert <Alert
style={{ margin: '16px 0' }}
type='error' type='error'
showIcon showIcon
message='帮助详情加载失败' message='帮助详情加载失败'
description={articleQuery.error.message} description={articleQuery.error.message}
action={<Button onClick={() => void articleQuery.refetch()}>重试</Button>} action={<Button onClick={() => void articleQuery.refetch()}>重试</Button>}
/> />
</section>
</main>
) )
const article = articleQuery.data const article = articleQuery.data
if (!article) return null if (!article) return null
return ( return (
<main> <main className='info-page'>
<Typography.Title level={1}>{article.title || '帮助详情'}</Typography.Title> <PageHero
<Card bodyStyle={{ padding: 0 }}> title={article.title || '帮助详情'}
intro={
<>
使用指南与常见问题。如未找到所需内容,可前往
<Link to='/contact'>联系我们</Link>获取帮助。
</>
}
eyebrow={<Link to='/help'>← 返回帮助中心</Link>}
/>
<Card className='info-doc' styles={{ body: { padding: 0 } }}>
<iframe <iframe
className='info-doc__frame'
title={article.title || '帮助详情'} title={article.title || '帮助详情'}
sandbox='' sandbox=''
srcDoc={`<!doctype html><html lang="zh-CN"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><style>body{margin:0;padding:24px;color:#262626;font:16px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;word-break:break-word}img,video,table,pre,code{max-width:100%;box-sizing:border-box}pre{white-space:pre-wrap}table,td,th{border:1px solid #d9d9d9;border-collapse:collapse;padding:6px}</style></head><body>${article.content}</body></html>`} srcDoc={`<!doctype html><html lang="zh-CN"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><style>${ARTICLE_BASE_STYLES}</style></head><body>${article.content}</body></html>`}
style={{ width: '100%', minHeight: 480, border: 0, display: 'block' }}
/> />
</Card> </Card>
</main> </main>
......
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { Alert, Button, Empty, List, Skeleton, Typography } from 'antd' import { RightOutlined } from '@ant-design/icons'
import { Alert, Button, Empty, Skeleton } from 'antd'
import { Link } from 'react-router' import { Link } from 'react-router'
import { helpArticlesOptions } from '../query' import { helpArticlesOptions } from '../query'
import { PageHero } from '../components/PageHero'
import { RedbudFlower } from '../components/Redbud'
import './info-pages.css'
export function HelpListView() { export function HelpListView() {
const articlesQuery = useQuery(helpArticlesOptions()) const articlesQuery = useQuery(helpArticlesOptions())
const articles = articlesQuery.data ?? [] const articles = articlesQuery.data ?? []
return ( return (
<main> <main className='info-page'>
<Typography.Title level={1}>帮助中心</Typography.Title> <PageHero title='帮助中心' intro='常见问题与使用指南,助你更快上手数智学堂。' />
{articlesQuery.isPending ? <Skeleton active paragraph={{ rows: 10 }} /> : null} <section className='info-card' aria-label='帮助文章列表'>
{articlesQuery.isPending ? (
<Skeleton active paragraph={{ rows: 8 }} style={{ padding: '16px 0' }} />
) : null}
{articlesQuery.isError ? ( {articlesQuery.isError ? (
<Alert <Alert
style={{ margin: '16px 0' }}
type='error' type='error'
showIcon showIcon
message='帮助内容加载失败' message='帮助内容加载失败'
...@@ -19,20 +27,29 @@ export function HelpListView() { ...@@ -19,20 +27,29 @@ export function HelpListView() {
action={<Button onClick={() => void articlesQuery.refetch()}>重试</Button>} action={<Button onClick={() => void articlesQuery.refetch()}>重试</Button>}
/> />
) : null} ) : null}
{articlesQuery.data && articles.length === 0 ? <Empty description='暂无帮助内容' /> : null} {articlesQuery.data && articles.length === 0 ? (
<Empty description='暂无帮助内容' style={{ padding: '32px 0' }} />
) : null}
{articles.length ? ( {articles.length ? (
<List <ul className='info-list'>
bordered {articles.map((article, index) => (
dataSource={articles} <li
renderItem={(article, index) => ( className='info-list__item'
<List.Item> key={article.id}
<Link to={`/my/help/${encodeURIComponent(article.id)}`}> style={{ animationDelay: `${index * 36}ms` }}
{index + 1}. {article.title} >
<Link className='info-list__link' to={`/help/${encodeURIComponent(article.id)}`}>
<span className='info-list__flower'>
<RedbudFlower size={15} />
</span>
<span className='info-list__title'>{article.title}</span>
<RightOutlined className='info-list__chevron' />
</Link> </Link>
</List.Item> </li>
)} ))}
/> </ul>
) : null} ) : null}
</section>
</main> </main>
) )
} }
/* 关于我们 / 帮助中心 / 联系我们 ——「紫荆印象」页面家族样式 */
.info-page {
display: grid;
gap: 28px;
--info-crimson: #aa1941;
--info-blush: #fff1f4;
--info-line: #e9ebef;
--info-ink: #252b36;
--info-muted: #6b7280;
--info-faint: #9ca3af;
--info-serif: 'Songti SC', 'STSong', 'Noto Serif CJK SC', 'SimSun', serif;
}
/* ---------- 页头 hero ---------- */
.info-hero {
position: relative;
display: flex;
min-height: 224px;
padding: 52px 56px;
overflow: hidden;
align-items: center;
color: #fff;
background:
radial-gradient(130% 180% at 90% -30%, rgb(255 255 255 / 12%), transparent 52%),
linear-gradient(128deg, #7b1230 0%, #aa1941 56%, #b5284e 100%);
border-radius: 20px;
}
.info-hero__text {
position: relative;
z-index: 1;
max-width: 600px;
}
.info-hero__eyebrow {
display: inline-flex;
gap: 8px;
margin: 0 0 18px;
align-items: center;
color: rgb(255 255 255 / 74%);
font-size: 13px;
letter-spacing: 0.32em;
}
.info-hero__eyebrow a {
color: rgb(255 255 255 / 88%);
letter-spacing: normal;
text-decoration: none;
}
.info-hero__eyebrow a:hover {
color: #fff;
text-decoration: underline;
text-underline-offset: 4px;
}
.info-hero__title {
margin: 0;
font-family: var(--info-serif);
font-size: clamp(30px, 3.6vw, 42px);
font-weight: 700;
letter-spacing: 0.08em;
line-height: 1.3;
}
.info-hero__intro {
max-width: 480px;
margin: 14px 0 0;
color: rgb(255 255 255 / 84%);
font-size: 15px;
line-height: 1.85;
}
.info-hero__intro a {
color: #fff;
text-decoration: underline;
text-underline-offset: 4px;
}
.info-hero__mark {
position: absolute;
right: 20px;
bottom: -6px;
width: min(320px, 40%);
opacity: 0.92;
animation: info-drift 9s ease-in-out infinite alternate;
}
@keyframes info-drift {
from {
transform: translateY(0) rotate(0deg);
}
to {
transform: translateY(-7px) rotate(-1.4deg);
}
}
/* ---------- 通用卡片与章节 ---------- */
.info-section {
display: grid;
gap: 18px;
}
.info-section__title {
margin: 0;
color: var(--info-ink);
font-family: var(--info-serif);
font-size: 22px;
font-weight: 700;
letter-spacing: 0.06em;
}
.info-section__lede {
max-width: 680px;
margin: -6px 0 0;
color: var(--info-muted);
font-size: 14px;
line-height: 1.9;
}
.info-card {
padding: 8px 28px;
background: #fff;
border: 1px solid var(--info-line);
border-radius: 16px;
}
/* ---------- 关于我们:教学闭环 ---------- */
.info-flow {
display: grid;
gap: 10px;
}
.info-flow__steps {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 28px;
margin: 0;
padding: 0;
list-style: none;
}
.info-flow__step {
position: relative;
display: grid;
gap: 8px;
padding: 24px 20px;
justify-items: start;
background: #fff;
border: 1px solid var(--info-line);
border-radius: 14px;
}
.info-flow__arrow {
position: absolute;
top: 50%;
right: -22px;
z-index: 1;
color: var(--info-crimson);
font-size: 15px;
line-height: 1;
transform: translateY(-50%);
}
.info-flow__num {
color: var(--info-crimson);
font-family: var(--info-serif);
font-size: 20px;
font-weight: 700;
}
.info-flow__name {
color: var(--info-ink);
font-size: 15px;
font-weight: 600;
}
.info-flow__desc {
margin: 0;
color: var(--info-muted);
font-size: 13px;
line-height: 1.7;
}
.info-flow__loop {
display: block;
width: 100%;
height: 46px;
}
.info-flow__caption {
margin: 0;
color: var(--info-faint);
font-size: 12px;
letter-spacing: 0.3em;
text-align: center;
}
/* ---------- 关于我们:平台能力 ---------- */
.info-highlights {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.info-highlight {
display: grid;
gap: 12px;
padding: 26px 24px;
background: #fff;
border: 1px solid var(--info-line);
border-radius: 14px;
transition:
border-color 180ms ease-out,
box-shadow 180ms ease-out,
transform 180ms ease-out;
}
.info-highlight:hover {
border-color: #efc3cf;
box-shadow: var(--learning-shadow);
transform: translateY(-2px);
}
.info-highlight__icon {
display: grid;
width: 42px;
height: 42px;
place-items: center;
background: var(--info-blush);
border-radius: 12px;
}
.info-highlight__title {
margin: 0;
color: var(--info-ink);
font-size: 15px;
font-weight: 600;
}
.info-highlight__desc {
margin: 0;
color: var(--info-muted);
font-size: 13px;
line-height: 1.75;
}
/* ---------- 关于我们:公司信息 ---------- */
.info-meta {
display: grid;
gap: 4px;
padding: 28px;
}
.info-meta__rows {
display: grid;
gap: 12px;
margin: 0;
}
.info-meta__row {
display: flex;
gap: 8px 28px;
align-items: baseline;
flex-wrap: wrap;
color: #4b5563;
font-size: 14px;
line-height: 1.7;
}
.info-meta__row dt {
flex: 0 0 76px;
color: var(--info-faint);
font-size: 13px;
}
.info-meta__row dd {
margin: 0;
}
.info-meta__row a {
color: var(--info-crimson);
text-decoration: none;
}
.info-meta__row a:hover {
text-decoration: underline;
text-underline-offset: 3px;
}
.info-meta__row a + a {
margin-left: 20px;
}
.info-meta__copyright {
margin: 8px 0 0;
padding-top: 18px;
color: var(--info-faint);
font-size: 12px;
line-height: 1.9;
text-align: center;
border-top: 1px solid #f1f2f5;
}
/* ---------- 帮助中心:文章列表 ---------- */
.info-list {
margin: 0;
padding: 0;
list-style: none;
}
.info-list__item {
border-bottom: 1px solid #f1f2f5;
animation: info-rise 360ms ease-out both;
}
.info-list__item:last-child {
border-bottom: 0;
}
.info-list__link {
display: flex;
gap: 14px;
padding: 18px 4px;
align-items: center;
color: var(--info-ink);
text-decoration: none;
transition: color 160ms ease-out;
}
.info-list__link:hover {
color: var(--info-crimson);
}
.info-list__flower {
display: inline-flex;
flex: 0 0 auto;
transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.info-list__link:hover .info-list__flower {
transform: rotate(26deg) scale(1.1);
}
.info-list__title {
flex: 1;
min-width: 0;
overflow: hidden;
font-size: 15px;
text-overflow: ellipsis;
white-space: nowrap;
}
.info-list__chevron {
flex: 0 0 auto;
color: #c3c7ce;
font-size: 12px;
transition:
color 160ms ease-out,
transform 160ms ease-out;
}
.info-list__link:hover .info-list__chevron {
color: var(--info-crimson);
transform: translateX(3px);
}
@keyframes info-rise {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
/* ---------- 联系我们:联系方式卡片 ---------- */
.contact-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.contact-card {
display: grid;
gap: 14px;
padding: 30px 26px;
justify-items: start;
background: #fff;
border: 1px solid var(--info-line);
border-radius: 14px;
transition:
border-color 180ms ease-out,
box-shadow 180ms ease-out;
}
.contact-card:hover {
border-color: #efc3cf;
box-shadow: var(--learning-shadow);
}
.contact-card__icon {
display: grid;
width: 46px;
height: 46px;
place-items: center;
color: var(--info-crimson);
font-size: 19px;
background: var(--info-blush);
border-radius: 50%;
}
.contact-card__label {
margin: 0;
color: var(--info-faint);
font-size: 12px;
letter-spacing: 0.22em;
}
.contact-card__value {
margin: 0;
color: var(--info-ink);
font-size: 15px;
font-weight: 600;
line-height: 1.7;
}
.contact-card__value a {
color: inherit;
text-decoration: none;
}
.contact-card__value a:hover {
color: var(--info-crimson);
text-decoration: underline;
text-underline-offset: 3px;
}
/* ---------- 帮助详情:文档容器 ---------- */
.info-doc.ant-card {
overflow: hidden;
border-color: var(--info-line);
border-radius: 16px;
}
.info-doc__frame {
display: block;
width: 100%;
min-height: clamp(380px, 58vh, 780px);
border: 0;
}
/* ---------- 响应式 ---------- */
@media (max-width: 960px) {
.info-highlights,
.contact-cards {
grid-template-columns: 1fr;
}
.info-flow__steps {
grid-template-columns: 1fr;
gap: 30px;
}
.info-flow__arrow {
top: auto;
right: auto;
bottom: -24px;
left: 50%;
transform: translateX(-50%) rotate(90deg);
}
.info-flow__loop {
display: none;
}
}
@media (max-width: 640px) {
.info-hero {
min-height: 196px;
padding: 36px 24px;
}
.info-hero__mark {
right: -40px;
width: 220px;
opacity: 0.6;
}
.info-card {
padding: 8px 18px;
}
.info-meta {
padding: 22px 18px;
}
.info-meta__row dt {
flex-basis: auto;
min-width: 70px;
}
}
@media (prefers-reduced-motion: reduce) {
.info-hero__mark {
animation: none;
}
.info-list__item {
animation: none;
}
}
...@@ -42,10 +42,7 @@ export const myMenuGroups: MyMenuGroup[] = [ ...@@ -42,10 +42,7 @@ export const myMenuGroups: MyMenuGroup[] = [
{ {
key: 'help-feedback', key: 'help-feedback',
label: '帮助与反馈', label: '帮助与反馈',
items: [ items: [{ path: '/my/feedback', label: '意见反馈' }],
{ path: '/my/help', label: '帮助中心' },
{ path: '/my/feedback', label: '意见反馈' },
],
}, },
] ]
......
...@@ -6,7 +6,6 @@ import { routes as couponRoutes } from './coupons/routes' ...@@ -6,7 +6,6 @@ import { routes as couponRoutes } from './coupons/routes'
import { MyDiscussionsView } from './discussions/views/MyDiscussionsView' import { MyDiscussionsView } from './discussions/views/MyDiscussionsView'
import { routes as feedbackRoutes } from './feedback/routes' import { routes as feedbackRoutes } from './feedback/routes'
import { MyFavoritesView } from './favorites/views/MyFavoritesView' import { MyFavoritesView } from './favorites/views/MyFavoritesView'
import { routes as helpRoutes } from './help/routes'
import { MyHistoryView } from './history/views/MyHistoryView' import { MyHistoryView } from './history/views/MyHistoryView'
import { MyLayout } from './layout/MyLayout' import { MyLayout } from './layout/MyLayout'
import { routes as messageRoutes } from './messages/routes' import { routes as messageRoutes } from './messages/routes'
...@@ -44,7 +43,6 @@ export const routes: RouteObject[] = [ ...@@ -44,7 +43,6 @@ export const routes: RouteObject[] = [
...securityRoutes, ...securityRoutes,
...messageRoutes, ...messageRoutes,
...feedbackRoutes, ...feedbackRoutes,
...helpRoutes,
], ],
}, },
] ]
...@@ -6,10 +6,14 @@ import { routes as libraryRoutes } from '@/modules/library/routes' ...@@ -6,10 +6,14 @@ import { routes as libraryRoutes } from '@/modules/library/routes'
import { routes as myRoutes } from '@/modules/my/routes' import { routes as myRoutes } from '@/modules/my/routes'
import { routes as readerRoutes } from '@/modules/reader/routes' import { routes as readerRoutes } from '@/modules/reader/routes'
import { AboutView } from '@/modules/my/help/views/AboutView' import { AboutView } from '@/modules/my/help/views/AboutView'
import { ContactView } from '@/modules/my/help/views/ContactView'
import { routes as helpRoutes } from '@/modules/my/help/routes'
export const appChildRoutes: RouteObject[] = [ export const appChildRoutes: RouteObject[] = [
{ index: true, element: <Navigate to='/library' replace /> }, { index: true, element: <Navigate to='/library' replace /> },
{ path: 'about', element: <AboutView /> }, { path: 'about', element: <AboutView /> },
{ path: 'contact', element: <ContactView /> },
...helpRoutes,
...libraryRoutes, ...libraryRoutes,
...bookRoutes, ...bookRoutes,
...myRoutes, ...myRoutes,
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论