家谱现有接口调试50%
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"liveServer.settings.port": 5501
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
||||||
|
|
||||||
|
Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
||||||
|
|
||||||
|
1. Think Before Coding
|
||||||
|
Don't assume. Don't hide confusion. Surface tradeoffs.
|
||||||
|
|
||||||
|
Before implementing:
|
||||||
|
|
||||||
|
State your assumptions explicitly. If uncertain, ask.
|
||||||
|
If multiple interpretations exist, present them instead of picking silently.
|
||||||
|
If a simpler approach exists, say so. Push back when warranted.
|
||||||
|
If something is unclear, stop. Name what is confusing. Ask.
|
||||||
|
|
||||||
|
2. Simplicity First
|
||||||
|
Minimum code that solves the problem. Nothing speculative.
|
||||||
|
|
||||||
|
No features beyond what was asked.
|
||||||
|
No abstractions for single-use code.
|
||||||
|
No "flexibility" or "configurability" that was not requested.
|
||||||
|
No error handling for impossible scenarios.
|
||||||
|
If you write 200 lines and it could be 50, rewrite it.
|
||||||
|
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
||||||
|
|
||||||
|
3. Surgical Changes
|
||||||
|
Touch only what you must. Clean up only your own mess.
|
||||||
|
|
||||||
|
When editing existing code:
|
||||||
|
|
||||||
|
Do not "improve" adjacent code, comments, or formatting.
|
||||||
|
Do not refactor things that are not broken.
|
||||||
|
Match existing style, even if you would do it differently.
|
||||||
|
If you notice unrelated dead code, mention it instead of deleting it.
|
||||||
|
|
||||||
|
When your changes create orphans:
|
||||||
|
|
||||||
|
Remove imports, variables, functions, files, docs, and references that YOUR changes made unused.
|
||||||
|
Do not remove pre-existing dead code unless asked.
|
||||||
|
The test: Every changed line should trace directly to the user's request.
|
||||||
|
|
||||||
|
4. Contract Discipline
|
||||||
|
When a new contract lands, make it the only contract in the same change.
|
||||||
|
|
||||||
|
A contract means any source-of-truth rule that code depends on: data shape, API boundary, schema, field name, config key, prompt format, file layout, runtime entrypoint, ownership boundary, or workflow.
|
||||||
|
|
||||||
|
When introducing or changing a contract, do all three in the same round:
|
||||||
|
|
||||||
|
Specify the single owner.
|
||||||
|
|
||||||
|
Identify the one module, function, schema, document, or service that owns the contract.
|
||||||
|
Do not leave the same rule duplicated across frontend, backend, scripts, prompts, docs, or tests.
|
||||||
|
If multiple places need the value, they should consume it from the owner rather than redefine it.
|
||||||
|
|
||||||
|
Delete old fields and old entrypoints.
|
||||||
|
|
||||||
|
Remove obsolete fields, fallback reads, compatibility branches, legacy routes, stale config keys, old scripts, and old docs.
|
||||||
|
Do not keep the old path "just in case" unless the user explicitly asks for a compatibility period.
|
||||||
|
If compatibility is required, name it as temporary, define the removal condition, and keep it narrow.
|
||||||
|
|
||||||
|
Tighten validators and runtime together.
|
||||||
|
|
||||||
|
Update schemas, validators, tests, fixtures, seed data, docs, and runtime code in the same change.
|
||||||
|
Make invalid old inputs fail early and loudly.
|
||||||
|
Do not allow runtime behavior to accept shapes that validators reject, or validators to allow shapes that runtime no longer supports.
|
||||||
|
The rule: New owner, old path removed, validator and runtime tightened. If one is missing, the contract migration is not complete.
|
||||||
|
|
||||||
|
5. Goal-Driven Execution
|
||||||
|
Define success criteria. Loop until verified.
|
||||||
|
|
||||||
|
Transform tasks into verifiable goals:
|
||||||
|
|
||||||
|
"Add validation" -> "Write tests for invalid inputs, then make them pass."
|
||||||
|
"Fix the bug" -> "Write a test that reproduces it, then make it pass."
|
||||||
|
"Refactor X" -> "Ensure tests pass before and after."
|
||||||
|
"Change a contract" -> "Identify owner, remove old paths, tighten validators and runtime, then verify old inputs fail."
|
||||||
|
|
||||||
|
For multi-step tasks, state a brief plan:
|
||||||
|
|
||||||
|
1. [Step] -> verify: [check]
|
||||||
|
2. [Step] -> verify: [check]
|
||||||
|
3. [Step] -> verify: [check]
|
||||||
|
|
||||||
|
Strong success criteria let you loop independently. Weak criteria like "make it work" require clarification.
|
||||||
|
|
||||||
|
6. Verification Before Closure
|
||||||
|
A change is not finished until the relevant behavior is checked.
|
||||||
|
|
||||||
|
Before reporting completion:
|
||||||
|
|
||||||
|
Run the smallest relevant test, script, typecheck, build, or manual verification.
|
||||||
|
Prefer focused verification over broad, noisy suites when the task is narrow.
|
||||||
|
If verification cannot be run, say exactly why.
|
||||||
|
If verification is only by inspection, say that clearly.
|
||||||
|
If the task changed a contract, verify both the new valid path and the old invalid path.
|
||||||
|
Do not claim success from intent. Claim success from evidence.
|
||||||
|
|
||||||
|
7. Reporting Results
|
||||||
|
Be concise, concrete, and honest.
|
||||||
|
|
||||||
|
When summarizing work:
|
||||||
|
|
||||||
|
Say what changed.
|
||||||
|
Say how it was verified.
|
||||||
|
Mention any remaining risk or skipped verification.
|
||||||
|
Do not bury important caveats in vague language.
|
||||||
|
Do not over-explain routine edits.
|
||||||
|
|
||||||
|
Good final answer shape:
|
||||||
|
|
||||||
|
Changed: [short summary]
|
||||||
|
Verified: [command/check]
|
||||||
|
Notes: [only if needed]
|
||||||
|
|
||||||
|
These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, fewer hidden compatibility paths, clearer ownership of contracts, and clarifying questions happen before implementation rather than after mistakes.
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>关于我们 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/about.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-about">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a class="active" href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero about-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">About Us</div>
|
||||||
|
<h1>用数字化方式守护家族记忆</h1>
|
||||||
|
<p class="lead">
|
||||||
|
代代相传面向家庭、宗亲会与地方文化组织,提供家谱创建、资料管理、文化展示和亲人协作工具。
|
||||||
|
</p>
|
||||||
|
<div class="about-tags">
|
||||||
|
<span>数字家谱</span><span>亲人协作</span><span>文化传承</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card about-seal tilt-card">
|
||||||
|
<div class="seal-orb"></div>
|
||||||
|
<span>传</span>
|
||||||
|
<p>记录家族,连接亲人,传承文化。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt values-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>我们重视</h2>
|
||||||
|
<p>让家族资料真实、清晰、可协作,也能长期传下去。</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3">
|
||||||
|
<div class="card soft value-card tilt-card">
|
||||||
|
<div class="value-icon">真</div>
|
||||||
|
<h3>真实</h3>
|
||||||
|
<p>尊重家族资料来源,鼓励记录出处与修订过程。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft value-card tilt-card">
|
||||||
|
<div class="value-icon">协</div>
|
||||||
|
<h3>协作</h3>
|
||||||
|
<p>让更多亲人参与补充资料,形成长期维护机制。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft value-card tilt-card">
|
||||||
|
<div class="value-icon">承</div>
|
||||||
|
<h3>传承</h3>
|
||||||
|
<p>把家族文化整理成可持续保存的数字档案。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>应用下载 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/app.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-app" data-promotion-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a class="active" href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero app-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Mobile App</div>
|
||||||
|
<h1>手机端随时记录,电脑端清晰浏览</h1>
|
||||||
|
<p class="lead">
|
||||||
|
家族成员可以在手机端上传照片、查看家谱、发布动态;PC
|
||||||
|
端适合浏览门户内容和公开家谱。
|
||||||
|
</p>
|
||||||
|
<div class="hero-buttons">
|
||||||
|
<a class="btn primary magnetic" href="download.html">下载应用</a
|
||||||
|
><a class="btn ghost magnetic" href="help.html">查看帮助</a>
|
||||||
|
</div>
|
||||||
|
<div class="app-stats">
|
||||||
|
<span>相册上传</span><span>视频发布</span><span>家谱查看</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card app-shot-wrap tilt-card">
|
||||||
|
<div class="app-orbit"></div>
|
||||||
|
<img
|
||||||
|
class="phone-shot first"
|
||||||
|
src="public/images/app-home.png"
|
||||||
|
alt="APP首页截图"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="phone-shot second"
|
||||||
|
src="public/images/app-family-home.png"
|
||||||
|
alt="家谱主页截图"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt app-feature-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>移动端能力</h2>
|
||||||
|
<p>
|
||||||
|
承接 APP 里的主要功能,让用户理解手机端适合日常记录和共同维护。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-4">
|
||||||
|
<div class="card soft app-feature-card tilt-card">
|
||||||
|
<div class="app-icon">谱</div>
|
||||||
|
<h3>创建家谱</h3>
|
||||||
|
<p>手机上快速创建或加入家族空间。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft app-feature-card tilt-card">
|
||||||
|
<div class="app-icon">相</div>
|
||||||
|
<h3>宣传相册</h3>
|
||||||
|
<p>随手上传老照片、祖屋照片和聚会照片。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft app-feature-card tilt-card">
|
||||||
|
<div class="app-icon">影</div>
|
||||||
|
<h3>宣传视频</h3>
|
||||||
|
<p>发布家族活动与人物影像。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft app-feature-card tilt-card">
|
||||||
|
<div class="app-icon">文</div>
|
||||||
|
<h3>谱文详情</h3>
|
||||||
|
<p>阅读谱序、传记和家族文章。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 应用推广区域:内容来自 /genealogy/app/promotions 列表接口。 -->
|
||||||
|
<section class="section app-promotion-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>应用推广</h2>
|
||||||
|
<p>展示后台维护的应用推广、公告和下载引导内容。</p>
|
||||||
|
</div>
|
||||||
|
<div class="promotion-list" data-promotion-list>
|
||||||
|
<div class="api-empty">应用推广内容加载中</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a
|
||||||
|
><a href="notice-detail.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/promotion-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>为什么家谱不只是一本名册 - 文章详情 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/article-detail.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-article-detail" data-article-detail-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a class="active" href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a>
|
||||||
|
<a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero article-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Article Detail</div>
|
||||||
|
<h1 data-article-title>为什么家谱不只是一本名册</h1>
|
||||||
|
<p class="lead" data-article-summary>
|
||||||
|
家谱记录的是家族关系,也记录一个家庭如何理解自己的来处、秩序和传承。
|
||||||
|
</p>
|
||||||
|
<div class="article-meta" data-article-meta>
|
||||||
|
<span>家谱知识</span><span>2026.05</span><span>阅读 2,418</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card article-cover-detail tilt-card">
|
||||||
|
<span>谱</span>
|
||||||
|
<p>记录来处,也照见未来。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container article-layout">
|
||||||
|
<article class="article-content tilt-card" data-article-content>
|
||||||
|
<p>谱文详情加载中...</p>
|
||||||
|
</article>
|
||||||
|
<aside class="article-side tilt-card">
|
||||||
|
<h3>相关入口</h3>
|
||||||
|
<a href="genealogy.html">了解数字家谱</a>
|
||||||
|
<a href="create-genealogy.html">创建一本家谱</a>
|
||||||
|
<a href="culture.html">返回家族文化</a>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a href="article-detail.html">家谱知识</a
|
||||||
|
><a href="about.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/article-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,54 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 520" role="img" aria-label="家族祠堂插画">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="#fff8ec"/>
|
||||||
|
<stop offset=".58" stop-color="#f4e6cf"/>
|
||||||
|
<stop offset="1" stop-color="#edf4ef"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="roof" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#2e8e94"/>
|
||||||
|
<stop offset=".58" stop-color="#17606c"/>
|
||||||
|
<stop offset="1" stop-color="#133c52"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="wall" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#e85c47"/>
|
||||||
|
<stop offset="1" stop-color="#9f342e"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="gold" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="#f7d58a"/>
|
||||||
|
<stop offset="1" stop-color="#b77832"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="shadow" x="-20%" y="-20%" width="140%" height="150%">
|
||||||
|
<feDropShadow dx="0" dy="18" stdDeviation="18" flood-color="#61462e" flood-opacity=".18"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="900" height="520" rx="34" fill="url(#bg)"/>
|
||||||
|
<circle cx="734" cy="98" r="68" fill="#c49245" opacity=".12"/>
|
||||||
|
<circle cx="130" cy="388" r="96" fill="#476f63" opacity=".08"/>
|
||||||
|
<path d="M70 426c96-34 172-42 276-18 93 22 166 16 255-17 85-32 152-29 229 8" fill="none" stroke="#d9c8aa" stroke-width="3" opacity=".42"/>
|
||||||
|
|
||||||
|
<g filter="url(#shadow)" transform="translate(0 -42)">
|
||||||
|
<path d="M95 238c72-35 128-75 166-121h378c39 46 94 86 166 121-22 8-50 6-82-4l-33 33H210l-33-33c-32 10-60 12-82 4z" fill="url(#roof)"/>
|
||||||
|
<path d="M166 230h568v38H166z" fill="#f0bd64"/>
|
||||||
|
<path d="M204 264h492v174H204z" fill="url(#wall)"/>
|
||||||
|
<path d="M236 292h87v126h-87zM577 292h87v126h-87z" fill="#80312e" opacity=".8"/>
|
||||||
|
<path d="M378 286h144v152H378z" fill="#7e2f2d"/>
|
||||||
|
<path d="M404 314h92v124h-92z" fill="#bb4638"/>
|
||||||
|
<path d="M222 274h456" stroke="#f5d083" stroke-width="8" stroke-linecap="round"/>
|
||||||
|
<path d="M192 438h516v34H192z" fill="#f3d7a5"/>
|
||||||
|
<path d="M158 472h584v22H158z" fill="#d9b176"/>
|
||||||
|
<path d="M269 321h22M269 350h22M269 379h22M609 321h22M609 350h22M609 379h22" stroke="#efbf63" stroke-width="10" stroke-linecap="round"/>
|
||||||
|
<path d="M421 336h58M421 366h58M421 396h58" stroke="#f0bd64" stroke-width="10" stroke-linecap="round"/>
|
||||||
|
<rect x="378" y="248" width="144" height="46" rx="8" fill="#123a50" stroke="#e6bc69" stroke-width="5"/>
|
||||||
|
<path d="M418 271h64" stroke="#f6e4bd" stroke-width="8" stroke-linecap="round"/>
|
||||||
|
<path d="M440 92h20v28h-20z" fill="url(#gold)"/>
|
||||||
|
<path d="M420 112h60v16h-60z" fill="url(#gold)"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g opacity=".26" fill="none" stroke="#0f4150" stroke-width="2">
|
||||||
|
<path d="M160 222c138-60 432-60 580 0"/>
|
||||||
|
<path d="M210 196c122-38 352-38 480 0"/>
|
||||||
|
<path d="M280 160c97-18 242-18 340 0"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,77 @@
|
|||||||
|
(function (root, factory) {
|
||||||
|
// 全局配置同时支持浏览器页面和 Node 测试。
|
||||||
|
if (typeof module === 'object' && module.exports) {
|
||||||
|
module.exports = factory;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.GenealogyConfig = factory(root);
|
||||||
|
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var DEFAULT_ENV = 'development';
|
||||||
|
var API_BASE_URLS = {
|
||||||
|
development: 'http://test-genealogy-api.ddxcjp.cn',
|
||||||
|
production: ''
|
||||||
|
};
|
||||||
|
var TEST_API_HTTP_URL = 'http://test-genealogy-api.ddxcjp.cn';
|
||||||
|
var TEST_API_HTTPS_URL = 'https://test-genealogy-api.ddxcjp.cn';
|
||||||
|
var CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
|
||||||
|
var TENANT_ID = '000000';
|
||||||
|
var TOKEN_KEY = 'genealogy_auth_token';
|
||||||
|
var TOKEN_HEADER_NAME = 'Authorization';
|
||||||
|
var ENV_KEY = 'genealogy_env';
|
||||||
|
var BASE_URL_KEY = 'genealogy_api_base_url';
|
||||||
|
|
||||||
|
function readStorage(key) {
|
||||||
|
try {
|
||||||
|
return root.localStorage && root.localStorage.getItem(key);
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnv() {
|
||||||
|
return readStorage(ENV_KEY) || DEFAULT_ENV;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeApiBaseUrl(value) {
|
||||||
|
// 测试域名当前 HTTPS 握手失败,开发环境统一走可访问的 HTTP 地址。
|
||||||
|
var url = String(value || '').replace(/\/+$/, '');
|
||||||
|
|
||||||
|
if (url === TEST_API_HTTPS_URL) return TEST_API_HTTP_URL;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getApiBaseUrl() {
|
||||||
|
return normalizeApiBaseUrl(readStorage(BASE_URL_KEY) || API_BASE_URLS[getEnv()] || API_BASE_URLS.development);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfig() {
|
||||||
|
return {
|
||||||
|
env: getEnv(),
|
||||||
|
apiBaseUrl: getApiBaseUrl(),
|
||||||
|
clientId: CLIENT_ID,
|
||||||
|
tenantId: TENANT_ID,
|
||||||
|
tokenKey: TOKEN_KEY,
|
||||||
|
tokenHeaderName: TOKEN_HEADER_NAME
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getConfig: getConfig,
|
||||||
|
getApiBaseUrl: getApiBaseUrl,
|
||||||
|
getClientId: function () {
|
||||||
|
return CLIENT_ID;
|
||||||
|
},
|
||||||
|
getTenantId: function () {
|
||||||
|
return TENANT_ID;
|
||||||
|
},
|
||||||
|
getTokenKey: function () {
|
||||||
|
return TOKEN_KEY;
|
||||||
|
},
|
||||||
|
getTokenHeaderName: function () {
|
||||||
|
return TOKEN_HEADER_NAME;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>创建家谱 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/create-genealogy.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-create-genealogy">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic active" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero create-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Start Genealogy</div>
|
||||||
|
<h1>创建属于家族的数字空间</h1>
|
||||||
|
<p class="lead">
|
||||||
|
填写姓氏谱名、地区与简介,先建立家谱主页,再逐步邀请亲人共同完善资料。
|
||||||
|
</p>
|
||||||
|
<div class="create-tags">
|
||||||
|
<span>基础资料</span><span>成员世系</span><span>亲人共修</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card process-card tilt-card">
|
||||||
|
<div class="process-orb"></div>
|
||||||
|
<h3>创建流程</h3>
|
||||||
|
<div class="step-list">
|
||||||
|
<p><b>1</b><span>填写基础信息</span></p>
|
||||||
|
<p><b>2</b><span>添加第一批成员</span></p>
|
||||||
|
<p><b>3</b><span>邀请亲人共修</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt create-form-section">
|
||||||
|
<div class="container">
|
||||||
|
<form class="card form-card create-form tilt-card" data-genealogy-form="create" data-success-url="profile-families.html">
|
||||||
|
<div class="form-ornament"></div>
|
||||||
|
<h2>家谱信息</h2>
|
||||||
|
<p class="form-note">
|
||||||
|
先填写基本资料,后续可以继续补充成员、相册和谱文。
|
||||||
|
</p>
|
||||||
|
<div class="form-grid">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="genealogyName"
|
||||||
|
placeholder="家谱名称,如:四川武胜汤氏族谱"
|
||||||
|
/>
|
||||||
|
<input class="input" name="surname" placeholder="主要姓氏" />
|
||||||
|
<!-- 地区选择器:最终行政区编码回填到 regionCode,供创建家谱接口使用。 -->
|
||||||
|
<div class="region-picker create-region-picker" data-region-picker>
|
||||||
|
<select class="input" name="provinceCode" data-region-level="province">
|
||||||
|
<option value="">请选择省</option>
|
||||||
|
</select>
|
||||||
|
<select class="input" name="cityCode" data-region-level="city">
|
||||||
|
<option value="">请选择市</option>
|
||||||
|
</select>
|
||||||
|
<select class="input" name="districtCode" data-region-level="district">
|
||||||
|
<option value="">请选择区县</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="regionCode" data-region-code />
|
||||||
|
</div>
|
||||||
|
<input class="input" name="addressDetail" placeholder="家族所在地" />
|
||||||
|
<textarea name="intro" placeholder="家族简介"></textarea>
|
||||||
|
<button class="btn primary magnetic submit-btn" type="submit">提交创建</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/region-pages.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家族文化 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/culture.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-culture">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a class="active" href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero culture-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Family Culture</div>
|
||||||
|
<h1>让家风、族训与故事被认真保存</h1>
|
||||||
|
<p class="lead">
|
||||||
|
家族文化承接新闻、知识、公告和故事,让谱文之外的记忆也能被阅读、分享和传承。
|
||||||
|
</p>
|
||||||
|
<div class="culture-stats">
|
||||||
|
<span>家风家训</span><span>谱文故事</span><span>使用指南</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card culture-quote tilt-card">
|
||||||
|
<div class="quote-moon"></div>
|
||||||
|
<span>家风</span>
|
||||||
|
<p>
|
||||||
|
一张老照片、一段口述、一篇谱序,都可以成为后人理解家族的入口。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt article-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>精选文章</h2>
|
||||||
|
<p>用可阅读的内容入口连接家谱知识、姓氏文化和平台使用指南。</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3">
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"><span>家谱知识</span></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>为什么家谱不只是一本名册</h3>
|
||||||
|
<p>
|
||||||
|
家谱记录的是家族关系,也记录一个家庭如何理解自己的来处与传承。
|
||||||
|
</p>
|
||||||
|
<span>家谱知识 · 2026.05</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"><span>姓氏文化</span></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>字辈在家族传承中的作用</h3>
|
||||||
|
<p>字辈让不同世代的人能找到自己的位置,也让同族称谓更清晰。</p>
|
||||||
|
<span>姓氏文化 · 2026.05</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"><span>使用指南</span></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>如何邀请亲人共同完善家谱</h3>
|
||||||
|
<p>从创建家谱、生成邀请码到设置管理员,逐步建立协作流程。</p>
|
||||||
|
<span>使用指南 · 2026.05</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# 接口对接规划与进度记录
|
||||||
|
|
||||||
|
## 基本信息
|
||||||
|
|
||||||
|
- 项目路径:`C:\Users\Administrator\Desktop\job\家谱`
|
||||||
|
- 接口文档:`APP.openapi.json`
|
||||||
|
- 记录创建时间:2026-07-09 11:51:16 +08:00
|
||||||
|
- 执行范围:先做核心闭环页面接口对接,再按页面模块继续扩展。
|
||||||
|
- 当前假设:接口文档以 `/genealogy/app` 为主,PC/H5 页面先复用这些用户侧接口。
|
||||||
|
|
||||||
|
## 约束摘要
|
||||||
|
|
||||||
|
- 先规划再实现,所有执行进度需要记录年月日时间。
|
||||||
|
- 改动要小,只触碰接口对接必需文件。
|
||||||
|
- 新接口契约由共享 API 客户端统一维护,页面脚本只调用封装方法。
|
||||||
|
- 完成后做最小可验证检查;不能验证的地方要明确说明。
|
||||||
|
- 样式尽量写入 `public.css` 或页面对应 CSS 文件,通过 class 控制,不用 JS 注入样式。
|
||||||
|
- 新增 HTML、JS、CSS 注释统一使用中文。
|
||||||
|
- CSS 结构先公共后页面:`public.css` 放全站公共组件,页面 CSS 只放本页面差异样式。
|
||||||
|
- 个人中心模块页优先复用 `profile-module.css`,只有页面独有样式再新增或修改对应页面 CSS。
|
||||||
|
- 页面专用 JS 放 `public/js`,命名跟页面或模块对应;公告详情页如需 JS 使用 `public/js/notice-detail.js`。
|
||||||
|
- 业务代码不压缩,保持展开、可读;需要解释意图、边界或接口字段映射的位置使用中文注释。
|
||||||
|
- 第三方库、压缩库、已存在乱码文件不做无关重写,避免引入额外风险。
|
||||||
|
|
||||||
|
## 核心闭环范围
|
||||||
|
|
||||||
|
1. 共享接口层
|
||||||
|
- 新增统一 API 客户端,负责 `baseUrl`、`clientid`、`tenantId`、token 存取、请求头、响应解包和错误提示。
|
||||||
|
- 默认 `clientid` 使用接口文档示例:`ced7e5f0498645c6ec642dcf450b036f`。
|
||||||
|
- 默认 `tenantId` 使用接口文档示例:`000000`。
|
||||||
|
- API 基础地址从 `window.GENEALOGY_API_BASE_URL` 或 `localStorage.genealogy_api_base_url` 读取,未配置时使用同域相对路径。
|
||||||
|
- 浏览器端公共脚本放 `public/js`;`utils` 目前只适合作为纯工具类目录,不能作为页面脚本入口。
|
||||||
|
- 页面专用 JS 按页面或模块放 `public/js`,例如认证模块用 `auth-pages.js`,公告详情页如需脚本则用 `notice-detail.js`。
|
||||||
|
|
||||||
|
2. 登录注册找回
|
||||||
|
- `login.html` -> `POST /genealogy/app/auth/login`
|
||||||
|
- `register.html` -> `POST /genealogy/app/auth/register`
|
||||||
|
- `forgot-password.html` -> `POST /genealogy/app/auth/sms/code`,`PUT /genealogy/app/auth/password/reset`
|
||||||
|
- 密码按文档要求提交 32 位 MD5,复用已有 `public/js/md5.js`。
|
||||||
|
|
||||||
|
3. 家谱核心
|
||||||
|
- `create-genealogy.html` -> `POST /genealogy/app/genealogies`
|
||||||
|
- `profile-families.html` -> `GET /genealogy/app/genealogies/mine`
|
||||||
|
- `plaza.html` -> `GET /genealogy/app/genealogies/public`
|
||||||
|
- `family-detail.html` -> `GET /genealogy/app/genealogies/{genealogyId}`
|
||||||
|
|
||||||
|
4. 个人资料与反馈
|
||||||
|
- `profile.html`、`profile-data.html` -> `GET /genealogy/app/auth/profile`
|
||||||
|
- `profile-feedback.html`、`submit-ticket.html` -> `GET/POST /genealogy/app/feedback`
|
||||||
|
|
||||||
|
5. 拦截处理
|
||||||
|
- `public/js/page-effects.js` 当前会拦截登录、注册、创建家谱、个人中心页面并显示“功能待开发”。
|
||||||
|
- 对已接入接口的页面移除该拦截,保留未接入页面的提示。
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
|
||||||
|
1. 新增共享 API 客户端测试,先确认测试失败,再实现通过。
|
||||||
|
2. 检查核心页面均加载共享脚本和页面脚本。
|
||||||
|
3. 用静态结构检查确认接口路径、表单字段、脚本引用存在。
|
||||||
|
4. 运行语法检查或 Node 烟测,确保 JS 可加载、核心方法可调用。
|
||||||
|
5. 检查新增样式是否位于 CSS 文件,不通过 JS 注入。
|
||||||
|
|
||||||
|
## 进度日志
|
||||||
|
|
||||||
|
- 2026-07-09 11:47:20 +08:00:已读取 `AGENTS.md`、项目目录、`APP.openapi.json`,确认项目是静态 HTML + jQuery/Layui,接口文档主要为 `/genealogy/app`。
|
||||||
|
- 2026-07-09 11:51:16 +08:00:用户确认按核心闭环方案执行,创建本规划与进度记录。
|
||||||
|
- 2026-07-09 11:52:53 +08:00:新增 `tests/api-client.test.js`,先运行 `node tests\api-client.test.js`,确认失败原因为缺少 `public/js/api-client.js`,进入共享 API 客户端实现。
|
||||||
|
- 2026-07-09 11:54:00 +08:00:用户补充要求:尽量不用 JS 注入样式,样式写在公共或页面 CSS 中并通过 class 查找;新增 HTML/JS/CSS 注释使用中文。
|
||||||
|
- 2026-07-09 11:57:19 +08:00:复查项目结构,确认 HTML 当前统一引用 `public/js`,`utils/DateUtil.js` 未被页面引用且存在乱码/语法风险;撤回过宽的 `api-pages.js` 方案,改为共享 `api-client.js` + 按模块/页面拆分脚本。
|
||||||
|
- 2026-07-09 11:59:22 +08:00:用户补充 CSS 架构要求:抽出可复用公共样式,每个页面 CSS 只写差异样式;将 CSS 结构整理加入接口接入前置约束。
|
||||||
|
- 2026-07-09 12:06:46 +08:00:完成认证模块第一步:新增 `public/js/auth-pages.js` 和 `tests/auth-pages.test.js`;`login.html`、`register.html`、`forgot-password.html` 改为真实表单;认证页公共 CSS 抽到 `public.css`,页面 CSS 只保留差异;重写 `page-effects.js`,移除“功能待开发”拦截和 JS 注入样式。
|
||||||
|
- 2026-07-09 12:10:54 +08:00:完成家谱核心第一步:新增 `public/js/genealogy-pages.js` 和 `tests/genealogy-pages.test.js`;`create-genealogy.html` 接入创建家谱接口;`plaza.html` 接入公开家谱列表;`profile-families.html` 接入我的家谱列表。验证:`node tests\api-client.test.js`、`node tests\auth-pages.test.js`、`node tests\genealogy-pages.test.js` 均通过;`node --check` 检查新增业务 JS 均通过;新增业务 JS 未发现 `createElement("style")` 或 `style.textContent` 注入样式。
|
||||||
|
- 2026-07-09 12:13:36 +08:00:用户补充可读性要求:现有该注释的位置补中文注释,代码不要压缩。执行范围限定为业务代码和本次维护的 CSS,第三方压缩库不改。
|
||||||
|
- 2026-07-09 12:16:27 +08:00:已给本次新增/重写业务代码补中文注释,覆盖 `api-client.js`、`auth-pages.js`、`genealogy-pages.js`、`page-effects.js` 和 `public.css` 的关键逻辑/样式区块;代码保持展开可读。验证:三组 Node 测试通过,四个业务 JS `node --check` 通过,业务 JS 未发现样式注入写法。
|
||||||
|
- 2026-07-09 12:23:36 +08:00:开始下一阶段:个人资料读取展示与反馈提交/历史反馈列表。范围:`profile.html`、`profile-data.html`、`profile-feedback.html`、`submit-ticket.html`;先写测试,再实现模块脚本和页面接入。
|
||||||
|
- 2026-07-09 12:28:30 +08:00:完成个人资料与反馈阶段:新增 `public/js/profile-pages.js`、`public/js/feedback-pages.js`、`tests/profile-pages.test.js`、`tests/feedback-pages.test.js`;`profile.html`、`profile-data.html` 接入当前用户资料读取展示;`profile-feedback.html`、`submit-ticket.html` 接入反馈提交,`profile-feedback.html` 接入历史反馈列表。验证:五组 Node 测试通过,六个业务 JS `node --check` 通过,业务 JS 未发现样式注入写法。
|
||||||
|
- 2026-07-09 12:31:51 +08:00:按用户要求重新验证第一阶段和第二阶段。第一阶段 API 客户端、认证页、家谱核心页测试均重新通过;第二阶段个人资料、反馈模块测试重新通过。复验命令包括 `node tests\api-client.test.js`、`node tests\auth-pages.test.js`、`node tests\genealogy-pages.test.js`、`node tests\profile-pages.test.js`、`node tests\feedback-pages.test.js`,以及六个业务脚本的 `node --check`。同时重新检查页面脚本引用、`data-*` 挂载点、业务 JS 样式注入写法和 `TODO/TBD/待实现/压缩` 标记,未发现异常。
|
||||||
|
- 2026-07-09 12:38:13 +08:00:继续推进家谱详情与加入申请阶段。`family-detail.html` 接入 `GET /genealogy/app/genealogies/{genealogyId}`,通过 `data-family-*` 挂载标题、简介、统计和家谱信息,并把“申请加入”链接带上家谱 ID;`join-genealogy.html` 改为真实申请表单,接入 `POST /genealogy/app/genealogies/{genealogyId}/join-applies`。新增/更新 `api-client.js` 和 `genealogy-pages.js` 中的申请加入、详情渲染、表单提交逻辑,并在对应 CSS 中补中文注释和页面差异样式。验证:五组 Node 测试全部通过,六个业务 JS `node --check` 全部通过,页面脚本引用与 `data-*` 挂载点检查通过,业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记。
|
||||||
|
- 2026-07-09 12:40:15 +08:00:根据接口 schema 补充 `joinMode` 枚举中文展示映射:`0` 显示为“关闭加入”、`1` 显示为“审核加入”、`2` 显示为“邀请码加入”,避免详情页直接显示数字。重新验证五组 Node 测试、六个业务 JS 语法检查、详情页/加入页挂载点、业务 JS 样式注入检查和核心文件遗留标记检查,结果均正常。
|
||||||
|
- 2026-07-09 12:45:24 +08:00:继续推进消息中心阶段。`profile-messages.html` 接入 `GET /genealogy/app/notifications`、`POST /genealogy/app/notifications/{notificationId}/read`、`POST /genealogy/app/notifications/read-all`,新增 `public/js/notification-pages.js` 负责消息列表渲染、单条已读、全部已读和刷新;`api-client.js` 新增通知相关封装;`profile-module.css` 增加按钮型模块卡片和未读消息样式,保持样式写入 CSS。验证:六组 Node 测试全部通过,七个业务 JS `node --check` 全部通过,消息页脚本引用和 `data-*` 挂载点检查通过,业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记。
|
||||||
|
- 2026-07-09 12:59:39 +08:00:按用户要求接入 `public/tac` 滑动验证到 `login.html`、`register.html`、`forgot-password.html`。依据 `APP.openapi.json` 的 `/captcha/require`、`/captcha/challenge`、`/captcha/verify` 字段实现 `public/js/captcha-pages.js` 适配层,将接口返回的 `captchaType/challengeId/payload` 转为 TAC 需要的 `type/id/backgroundImage/templateImage`,验证成功后把 `data.validToken` 写入当前表单隐藏字段;`auth-pages.js` 在登录、注册、发送短信验证码、重置密码前先执行滑动验证;`register.html` 原可见 `validToken` 输入改为昵称输入,避免和滑动验证隐藏字段冲突。三张认证页均引入 `public/tac/css/tac.css`、`public/tac/js/tac.min.js`、`public/js/captcha-pages.js`,并增加 `data-captcha-box` 挂载容器;`public.css` 增加认证页验证码容器样式。验证:七组 Node 测试全部通过,八个业务 JS `node --check` 全部通过,三张认证页 TAC 资源、隐藏 `validToken`、`data-captcha-box` 检查通过,自有业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记;`git diff --check` 因当前目录不是 git 仓库无法执行。
|
||||||
|
- 2026-07-09 13:07:18 +08:00:按用户提醒重新以 `APP.openapi.json` 为依据梳理剩余 `/genealogy/app` 页面归属,优先推进接口和页面最匹配的帮助中心。`help.html` 接入 `GET /genealogy/app/help-articles` 帮助文章列表,并在展开条目时按需调用 `GET /genealogy/app/help-articles/{helpId}` 补充详情;新增 `public/js/help-pages.js`,`api-client.js` 新增 `helpArticles`、`helpArticleDetail` 封装;`help.css` 补帮助列表加载状态注释和样式。验证:八组 Node 测试全部通过,九个业务 JS `node --check` 全部通过,帮助页 `data-help-list`、`api-client.js`、`help-pages.js` 引用检查通过,自有业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记。
|
||||||
|
- 2026-07-09 13:13:33 +08:00:继续按 `APP.openapi.json` 推进加入申请阶段。`profile-join-review.html` 接入 `GET /genealogy/app/genealogies/{genealogyId}/join-applies/pending` 待审核申请和 `PUT /genealogy/app/genealogies/{genealogyId}/join-applies/{applyId}/audit` 审核接口;`profile-join-family.html` 接入 `GET /genealogy/app/genealogies/join-applies/mine` 我的加入申请,并支持 `DELETE /genealogy/app/genealogies/join-applies/{applyId}` 撤销申请。新增 `public/js/join-apply-pages.js`,`api-client.js` 新增 `myJoinApplies`、`pendingJoinApplies`、`auditJoinApply`、`cancelJoinApply` 封装;`profile-module.css` 补加入申请行样式。验证:九组 Node 测试全部通过,十个业务 JS `node --check` 全部通过,两张页面脚本引用与 `data-join-apply-list` 挂载点检查通过,自有业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记。
|
||||||
|
- 2026-07-09 13:19:07 +08:00:继续按 `APP.openapi.json` 推进字辈谱阶段。`profile-generation.html` 接入 `GET /genealogy/app/genealogies/{genealogyId}/generation-poems` 查询字辈谱、`POST /genealogy/app/genealogies/{genealogyId}/generation-poems` 新增字辈、`PUT /genealogy/app/genealogies/{genealogyId}/generation-poems/{poemId}` 修改字辈;新增 `public/js/generation-pages.js`,`api-client.js` 新增 `generationPoems`、`createGenerationPoem`、`updateGenerationPoem` 封装;`profile-module.css` 补字辈谱行样式。本轮暂不接批量预览/批量保存接口,避免没有页面入口时过度实现。验证:十组 Node 测试全部通过,十一个业务 JS `node --check` 全部通过,字辈页 `data-generation-list`、`data-generation-add`、`generation-pages.js` 引用检查通过,自有业务 JS 未发现样式注入写法,核心文件未发现 `TODO/TBD/待实现/压缩` 标记。
|
||||||
|
- 2026-07-09 13:21:31 +08:00:根据用户提醒停止无编号推进,新增 `docs/api-page-integration-tracker-2026-07-09.md` 作为后续唯一编号规划与状态追踪表。后续每个模块必须先在追踪表中标记“进行中”,完成并验证后再标记“已完成”。
|
||||||
|
- 2026-07-09 13:33:41 +08:00:完成 API-011 世系树与人物管理。`profile-tree.html` 接入世系树、人物分页搜索、人物详情、新增成员和父母/配偶/子女快捷关系添加;`profile-family-home.html` 接入世系树预览和家谱主页摘要;新增 `public/js/lineage-pages.js`,`api-client.js` 新增 `lineageTree`、`lineagePersons`、`lineagePersonsPage`、`lineagePersonOptions`、`lineagePersonDetail`、`createLineagePerson`、`updateLineagePerson`、`deleteLineagePerson`、`addLineageRelation` 封装;`profile-module.css` 补世系列表、搜索栏和树结构样式。验证:全部 Node 测试通过,十二个业务 JS `node --check` 通过,两张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/lineage-pages.js` 未发现 `style` 样式注入片段。
|
||||||
|
- 2026-07-09 13:40:47 +08:00:完成 API-012 成员与家族管理。`profile-family-admin.html` 接入家谱概览和成员列表,支持成员权限更新和移除;`profile-admin-permissions.html` 接入成员选项、角色保存和所有者转让;`profile-invite.html`、`profile-share.html` 使用家谱概览生成邀请码/分享链接展示,不伪造接口文档中不存在的邀请生成接口。新增 `public/js/member-admin-pages.js`,`api-client.js` 新增 `genealogyOverview`、`genealogyMembers`、`genealogyMemberOptions`、`updateGenealogyMember`、`removeGenealogyMember`、`leaveGenealogy`、`transferGenealogyOwner` 封装;`profile-module.css` 补成员操作行样式。验证:全部 Node 测试通过,十三个业务 JS `node --check` 通过,四张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/member-admin-pages.js` 未发现 `style` 样式注入片段。
|
||||||
|
- 2026-07-09 13:46:31 +08:00:完成 API-014 谱文与内容文章。`profile-article.html` 接入谱文列表;`profile-article-edit.html` 接入分类列表、谱文新增和修改;`article-detail.html` 接入谱文详情;`profile-content.html` 的最近内容先接谱文列表,其他内容类型按后续编号继续接。新增 `public/js/article-pages.js`,`api-client.js` 新增 `articleCategories`、`articles`、`articleDetail`、`createArticle`、`updateArticle` 封装;`profile-module.css` 补谱文行样式。验证:全部 Node 测试通过,十四个业务 JS `node --check` 通过,四张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/article-pages.js` 未发现 `style` 样式注入片段。
|
||||||
|
- 2026-07-09 13:52:03 +08:00:完成 API-013 家族圈动态。`profile-feed.html` 接入动态分页列表、点赞和评论;`profile-feed-edit.html` 接入动态发布和修改。新增 `public/js/feed-pages.js`,`api-client.js` 新增 `feeds`、`feedsPage`、`feedDetail`、`createFeed`、`updateFeed`、`likeFeed`、`unlikeFeed`、`feedComments`、`feedCommentsPage`、`createFeedComment`、`deleteFeedComment` 封装;`profile-module.css` 补动态行样式。验证:全部 Node 测试通过,十五个业务 JS `node --check` 通过,两张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/feed-pages.js` 未发现 `style` 样式注入片段。
|
||||||
|
- 2026-07-09 13:57:31 +08:00:完成 API-015 相册照片。`profile-album.html` 接入相册列表、新增/修改相册、照片列表和新增照片;`promo-album.html` 复用相册列表做宣传相册展示。新增 `public/js/album-pages.js`,`api-client.js` 新增 `albums`、`createAlbum`、`updateAlbum`、`albumPhotos`、`createAlbumPhoto` 封装;`profile-module.css` 补相册和照片行样式。验证:全部 Node 测试通过,十六个业务 JS `node --check` 通过,两张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/album-pages.js` 未发现 `style` 样式注入片段。
|
||||||
|
- 2026-07-09 14:04:52 +08:00:完成 API-019 文件上传公共能力。`api-client.js` 接入单文件上传、文件引用绑定/释放、分片初始化、分片上传、分片完成接口;新增 `public/js/upload-pages.js` 统一处理文件选择、上传、OSS ID 回填和上传状态展示;`profile-article-edit.html` 接入谱文封面上传,`profile-feed-edit.html` 接入动态图片上传,`profile-album.html` 接入相册封面和照片上传;`profile-module.css` 补上传控件样式。验证:全部 Node 测试通过,十七个业务 JS `node --check` 通过,上传控件挂载点检查通过,`public/js/api-client.js` 和 `public/js/upload-pages.js` 未发现样式注入片段。
|
||||||
|
- 2026-07-09 14:12:27 +08:00:完成 API-016 祭祀、献礼与功德记录。`profile-gift.html` 接入祭祀/贺礼列表、献礼列表和新增献礼;`profile-gift-edit.html` 接入贺礼创建/修改和封面上传;`profile-merit.html` 接入功德记录列表;`profile-merit-edit.html` 接入新增功德记录。新增 `public/js/ceremony-pages.js`,`api-client.js` 新增 `ceremonies`、`ceremonyDetail`、`createCeremony`、`updateCeremony`、`ceremonyGifts`、`createCeremonyGift`、`meritRecords`、`createMeritRecord` 封装;`profile-module.css` 补贺礼、献礼和功德记录行样式。验证:全部 Node 测试通过,十八个业务 JS `node --check` 通过,四张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/ceremony-pages.js` 未发现样式注入片段。
|
||||||
|
- 2026-07-09 14:18:15 +08:00:完成 API-017 成长记录。`profile-growth.html` 接入成长记录列表;`profile-growth-edit.html` 接入成长记录新增/修改和附件上传。新增 `public/js/growth-pages.js`,`api-client.js` 新增 `growthRecords`、`growthRecordDetail`、`createGrowthRecord`、`updateGrowthRecord` 封装;`profile-module.css` 补成长记录行样式。验证:全部 Node 测试通过,十九个业务 JS `node --check` 通过,两张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/growth-pages.js` 未发现样式注入片段。
|
||||||
|
- 2026-07-09 14:24:10 +08:00:完成 API-018 备忘录。`profile-memo.html` 接入备忘录列表;`profile-memo-edit.html` 接入备忘录新增/修改和附件上传。新增 `public/js/memo-pages.js`,`api-client.js` 新增 `memos`、`memoDetail`、`createMemo`、`updateMemo` 封装;`profile-module.css` 补备忘录行样式。验证:全部 Node 测试通过,二十个业务 JS `node --check` 通过,两张页面脚本引用与 `data-*` 挂载点检查通过,`public/js/api-client.js` 和 `public/js/memo-pages.js` 未发现样式注入片段。
|
||||||
|
- 2026-07-09 14:31:29 +08:00:完成 API-020 会员套餐与订单创建。`profile-services.html` 接入会员套餐列表、会员订单创建表单和会员订单列表;新增 `public/js/vip-pages.js`,`api-client.js` 新增 `vipPackages`、`vipOrders`、`createVipOrder` 封装,`profile-module.css` 补会员套餐卡片和订单行样式。验证:`node tests\vip-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、会员页挂载点/字段检查均通过;API-020 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 14:37:25 +08:00:完成 API-021 推广/公告类内容。`app.html` 接入应用推广列表,`download.html` 接入下载推广入口,`notice-detail.html` 从 `/genealogy/app/promotions` 列表按 `id` 选择公告详情,未伪造接口文档不存在的详情接口。新增 `public/js/promotion-pages.js`,`api-client.js` 新增 `promotions` 封装,`app.css` 补推广卡片样式。验证:`node tests\promotion-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、三张页面推广挂载点检查均通过;API-021 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 14:42:47 +08:00:完成 API-022 账号安全。`profile-security.html` 接入修改密码、换绑手机号、短信登录校验、退出登录和账号注销表单;新增 `public/js/security-pages.js`,`api-client.js` 新增 `changePassword`、`changePhone`、`smsLogin`、`logout`、`deactivateAccount` 封装,`profile-module.css` 补安全表单和危险操作样式。验证:`node tests\security-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、账号安全页挂载点检查均通过;API-022 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 14:49:54 +08:00:完成 API-023 地区选择公共能力。`create-genealogy.html` 接入省/市/区选择器并回填 `regionCode`,`profile-data.html` 接入个人资料省市区更新表单;新增 `public/js/region-pages.js`,`api-client.js` 新增 `regionChildren`、`regionPath`、`regionSearch`、`regionDetail` 封装,`genealogy-pages.js` 去掉 `regionCode=000000` 兜底并改为提交前校验真实地区编码,两个 CSS 文件补地区选择器样式。验证:`node tests\region-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、两张页面地区挂载点检查均通过;API-023 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 14:50:47 +08:00:复查 API-024/API-025。`surname.html`、`surname-detail.html`、`search-result.html`、`genealogy.html`、`culture.html`、`about.html`、`index.html` 未发现明确同名接口,公开家谱接口也不支持搜索参数,因此标记暂缓;`profile-video.html`、`promo-video.html`、`profile-data-reminders.html` 暂无视频/资料提醒独立接口,标记暂缓;`profile-create-family.html` 可复用创建家谱能力,单独规划为 API-026。
|
||||||
|
- 2026-07-09 14:53:50 +08:00:完成 API-026 个人中心创建家谱页。`profile-create-family.html` 改为真实创建家谱表单,接入 `api-client.js`、`region-pages.js`、`genealogy-pages.js`,复用 `/genealogy/app/genealogies` 和地区选择公共能力;`profile-module.css` 补个人中心创建表单样式,`tests/genealogy-pages.test.js` 补真实 `regionCode` 断言。验证:`node tests\genealogy-pages.test.js`、`node tests\region-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、页面挂载点检查均通过;API-026 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 15:03:27 +08:00:完成 API-027 个人资料编辑提交。`profile-data.html` 增加真实个人资料编辑表单,`profile-pages.js` 增加 `ProfileUpdateBody` 构造、表单填充和 `PUT /genealogy/app/auth/profile` 提交,`profile-module.css` 补本页表单状态样式,`tests/profile-pages.test.js` 和 `tests/api-client.test.js` 补转换与接口契约测试。验证:先观察 `node tests\profile-pages.test.js` 因缺少 `buildProfileUpdateBody` 失败;实现后 `node tests\profile-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、页面挂载点检查均通过,未发现样式注入片段和 TODO 类占位;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 15:11:37 +08:00:完成 API-028 字辈批量预览与批量保存。`profile-generation.html` 增加批量字辈表单和预览区域,`api-client.js` 增加 `previewGenerationPoems`、`saveGenerationPoemsBatch`,`generation-pages.js` 增加 `GenerationPoemBatchBody` 构造、预览渲染和保存动作,`profile-module.css` 补批量面板样式,`tests/generation-pages.test.js` 和 `tests/api-client.test.js` 补批量接口测试。验证:先观察 `node tests\generation-pages.test.js` 因缺少 `buildGenerationBatchBody` 失败、`node tests\api-client.test.js` 因缺少 `previewGenerationPoems` 失败;实现后 `node tests\generation-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、页面挂载点检查均通过,未发现样式注入片段和 TODO 类占位;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# 接口对接编号规划与状态追踪
|
||||||
|
|
||||||
|
创建时间:2026-07-09 13:21:31 +08:00
|
||||||
|
流程修正时间:2026-07-09 13:21:31 +08:00
|
||||||
|
接口依据:`APP.openapi.json`
|
||||||
|
主进度记录:`docs/api-page-integration-2026-07-09.md`
|
||||||
|
|
||||||
|
## 执行规则
|
||||||
|
|
||||||
|
1. 后续不再无编号推进,所有接口对接必须先进入本追踪表。
|
||||||
|
2. 每一项开始前,先把状态从“待开始”改为“进行中”,并记录开始时间。
|
||||||
|
3. 每一项完成后,必须记录完成时间、修改文件、接口路径、验证命令或静态检查结果。
|
||||||
|
4. 每一项验证通过后,才能把状态改为“已完成”。
|
||||||
|
5. 若接口文档没有明确对应接口,状态标记为“待确认”或“暂缓”,不强行接入。
|
||||||
|
6. 样式继续遵守公共 `public.css` + 页面 CSS 的结构,业务 JS 不注入样式。
|
||||||
|
7. 新增或修改的 HTML、JS、CSS 注释使用中文,代码保持可读、不压缩。
|
||||||
|
|
||||||
|
## 状态说明
|
||||||
|
|
||||||
|
- 已完成:已按接口文档接入,并完成对应验证。
|
||||||
|
- 进行中:当前正在推进,未完成前不能开始下一个无关模块。
|
||||||
|
- 待开始:已规划,尚未改代码。
|
||||||
|
- 待确认:页面存在,但接口归属需要进一步确认。
|
||||||
|
- 暂缓:接口或页面入口不足,暂不实现,避免过度开发。
|
||||||
|
|
||||||
|
## 已完成回填
|
||||||
|
|
||||||
|
| 编号 | 状态 | 页面范围 | 接口范围 | 完成记录 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| API-000 | 已完成 | 全项目 | `APP.openapi.json`、`AGENTS.md`、项目结构 | 2026-07-09 11:47:20 +08:00 已读取约束、接口文档和目录结构。 |
|
||||||
|
| API-001 | 已完成 | 全项目公共请求 | 共享请求客户端、认证头、租户头、Token 存取 | 2026-07-09 11:52:53 +08:00 至 12:16:27 +08:00 完成 `public/js/api-client.js` 与测试。 |
|
||||||
|
| API-002 | 已完成 | `login.html`、`register.html`、`forgot-password.html` | `/genealogy/app/auth/login`、`/genealogy/app/auth/register`、`/genealogy/app/auth/sms/code`、`/genealogy/app/auth/password/reset`、`/captcha/require`、`/captcha/challenge`、`/captcha/verify` | 2026-07-09 12:06:46 +08:00 完成认证页;2026-07-09 12:59:39 +08:00 完成 TAC 滑动验证接入。 |
|
||||||
|
| API-003 | 已完成 | `create-genealogy.html`、`plaza.html`、`profile-families.html` | `/genealogy/app/genealogies`、`/genealogy/app/genealogies/public`、`/genealogy/app/genealogies/mine` | 2026-07-09 12:10:54 +08:00 完成创建家谱、公开家谱、我的家谱列表。 |
|
||||||
|
| API-004 | 已完成 | `family-detail.html`、`join-genealogy.html` | `/genealogy/app/genealogies/{genealogyId}`、`/genealogy/app/genealogies/{genealogyId}/join-applies` | 2026-07-09 12:38:13 +08:00 完成家谱详情与申请加入;2026-07-09 12:40:15 +08:00 补 `joinMode` 展示映射。 |
|
||||||
|
| API-005 | 已完成 | `profile.html`、`profile-data.html` | `/genealogy/app/auth/profile` | 2026-07-09 12:28:30 +08:00 完成个人资料读取展示。 |
|
||||||
|
| API-006 | 已完成 | `profile-feedback.html`、`submit-ticket.html` | `/genealogy/app/feedback` | 2026-07-09 12:28:30 +08:00 完成反馈提交与历史反馈。 |
|
||||||
|
| API-007 | 已完成 | `profile-messages.html` | `/genealogy/app/notifications`、`/genealogy/app/notifications/{notificationId}/read`、`/genealogy/app/notifications/read-all` | 2026-07-09 12:45:24 +08:00 完成消息中心。 |
|
||||||
|
| API-008 | 已完成 | `help.html` | `/genealogy/app/help-articles`、`/genealogy/app/help-articles/{helpId}` | 2026-07-09 13:07:18 +08:00 完成帮助中心。 |
|
||||||
|
| API-009 | 已完成 | `profile-join-review.html`、`profile-join-family.html` | `/genealogy/app/genealogies/{genealogyId}/join-applies/pending`、`/genealogy/app/genealogies/{genealogyId}/join-applies/{applyId}/audit`、`/genealogy/app/genealogies/join-applies/mine`、`/genealogy/app/genealogies/join-applies/{applyId}` | 2026-07-09 13:13:33 +08:00 完成入谱申请审核与我的申请。 |
|
||||||
|
| API-010 | 已完成 | `profile-generation.html` | `/genealogy/app/genealogies/{genealogyId}/generation-poems`、`/genealogy/app/genealogies/{genealogyId}/generation-poems/{poemId}` | 2026-07-09 13:19:07 +08:00 完成字辈谱查询、新增、修改;批量接口因页面无入口暂缓。 |
|
||||||
|
|
||||||
|
## 后续编号规划
|
||||||
|
|
||||||
|
| 编号 | 状态 | 页面范围 | 接口范围 | 计划与验证 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| API-011 | 已完成 | `profile-tree.html`、`profile-family-home.html` | `/genealogy/app/genealogies/{genealogyId}/lineage/tree`、`/genealogy/app/genealogies/{genealogyId}/lineage/persons`、`/genealogy/app/genealogies/{genealogyId}/lineage/persons/page`、`/genealogy/app/genealogies/{genealogyId}/lineage/persons/{personId}`、`/genealogy/app/genealogies/{genealogyId}/lineage/persons/{personId}/children`、`/parents`、`/siblings`、`/spouses` | 2026-07-09 13:25:03 +08:00 开始;2026-07-09 13:33:41 +08:00 完成。新增 `public/js/lineage-pages.js`、`tests/lineage-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、`profile-tree.html`、`profile-family-home.html`、`public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-011 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-012 | 已完成 | `profile-family-admin.html`、`profile-admin-permissions.html`、`profile-invite.html`、`profile-share.html` | `/genealogy/app/genealogies/{genealogyId}/members`、`/genealogy/app/genealogies/{genealogyId}/members/{memberId}`、`/genealogy/app/genealogies/{genealogyId}/members/me`、`/genealogy/app/genealogies/{genealogyId}/members/options`、`/genealogy/app/genealogies/{genealogyId}/members/owner-transfer`、`/genealogy/app/genealogies/{genealogyId}/overview` | 2026-07-09 13:34:36 +08:00 开始;2026-07-09 13:40:47 +08:00 完成。新增 `public/js/member-admin-pages.js`、`tests/member-admin-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、四张成员/邀请页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-012 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-013 | 已完成 | `profile-feed.html`、`profile-feed-edit.html` | `/genealogy/app/genealogies/{genealogyId}/feeds`、`/genealogy/app/genealogies/{genealogyId}/feeds/page`、`/genealogy/app/genealogies/{genealogyId}/feeds/{feedId}`、`/genealogy/app/genealogies/{genealogyId}/feeds/{feedId}/likes`、评论接口 | 2026-07-09 13:47:29 +08:00 开始;2026-07-09 13:52:03 +08:00 完成。新增 `public/js/feed-pages.js`、`tests/feed-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、两张动态页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-013 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-014 | 已完成 | `profile-article.html`、`profile-article-edit.html`、`article-detail.html`、`profile-content.html` | `/genealogy/app/genealogies/{genealogyId}/article-categories`、`/genealogy/app/genealogies/{genealogyId}/articles`、`/genealogy/app/genealogies/{genealogyId}/articles/{articleId}` | 2026-07-09 13:41:44 +08:00 开始;2026-07-09 13:46:31 +08:00 完成。新增 `public/js/article-pages.js`、`tests/article-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、四张谱文/内容页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-014 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-015 | 已完成 | `profile-album.html`、`promo-album.html` | `/genealogy/app/genealogies/{genealogyId}/albums`、`/genealogy/app/genealogies/{genealogyId}/albums/{albumId}`、`/genealogy/app/genealogies/{genealogyId}/albums/{albumId}/photos` | 2026-07-09 13:52:58 +08:00 开始;2026-07-09 13:57:31 +08:00 完成。新增 `public/js/album-pages.js`、`tests/album-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、两张相册页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-015 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-016 | 已完成 | `profile-gift.html`、`profile-gift-edit.html`、`profile-merit.html`、`profile-merit-edit.html` | `/genealogy/app/genealogies/{genealogyId}/ceremonies`、`/genealogy/app/genealogies/{genealogyId}/ceremonies/{ceremonyId}`、`/genealogy/app/genealogies/{genealogyId}/ceremonies/{ceremonyId}/gifts`、`/genealogy/app/genealogies/{genealogyId}/merit-records` | 2026-07-09 14:05:57 +08:00 开始;2026-07-09 14:12:27 +08:00 完成。新增 `public/js/ceremony-pages.js`、`tests/ceremony-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、四张贺礼/功德页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-016 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-017 | 已完成 | `profile-growth.html`、`profile-growth-edit.html` | `/genealogy/app/genealogies/{genealogyId}/growth-records`、`/genealogy/app/genealogies/{genealogyId}/growth-records/{recordId}` | 2026-07-09 14:13:25 +08:00 开始;2026-07-09 14:18:15 +08:00 完成。新增 `public/js/growth-pages.js`、`tests/growth-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、两张成长记录页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-017 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-018 | 已完成 | `profile-memo.html`、`profile-memo-edit.html` | `/genealogy/app/genealogies/{genealogyId}/memos`、`/genealogy/app/genealogies/{genealogyId}/memos/{memoId}` | 2026-07-09 14:19:26 +08:00 开始;2026-07-09 14:24:10 +08:00 完成。新增 `public/js/memo-pages.js`、`tests/memo-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、两张备忘录页面和 `public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面挂载点检查通过,API-018 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-019 | 已完成 | 文章、动态、相册、成长记录等需要上传的页面 | `/genealogy/app/files/upload`、`/genealogy/app/files/reference`、`/genealogy/app/files/resumable/init`、`/genealogy/app/files/resumable/chunk`、`/genealogy/app/files/resumable/complete` | 2026-07-09 14:00:01 +08:00 开始;2026-07-09 14:04:52 +08:00 完成。新增 `public/js/upload-pages.js`、`tests/upload-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、`profile-article-edit.html`、`profile-feed-edit.html`、`profile-album.html`、`public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,上传控件挂载点检查通过,API-019 自有 JS 未发现样式注入片段。 |
|
||||||
|
| API-020 | 已完成 | `profile-services.html` | `/genealogy/app/vip/packages`、`/genealogy/app/vip/orders` | 2026-07-09 14:26:34 +08:00 开始;2026-07-09 14:31:29 +08:00 完成。新增 `public/js/vip-pages.js`、`tests/vip-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、`profile-services.html`、`public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,会员页挂载点和表单字段检查通过,API-020 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-021 | 已完成 | `app.html`、`download.html`、`notice-detail.html` | `/genealogy/app/promotions` | 2026-07-09 14:33:01 +08:00 开始;2026-07-09 14:37:25 +08:00 完成。新增 `public/js/promotion-pages.js`、`tests/promotion-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、`app.html`、`download.html`、`notice-detail.html`、`public/css/app.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,三张页面推广挂载点检查通过,API-021 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-022 | 已完成 | `profile-security.html` | `/genealogy/app/auth/password`、`/genealogy/app/auth/phone`、`/genealogy/app/auth/account/deactivate`、`/genealogy/app/auth/logout`、`/genealogy/app/auth/login/sms` | 2026-07-09 14:38:22 +08:00 开始;2026-07-09 14:42:47 +08:00 完成。新增 `public/js/security-pages.js`、`tests/security-pages.test.js`;更新 `public/js/api-client.js`、`tests/api-client.test.js`、`profile-security.html`、`public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,账号安全页表单挂载点检查通过,API-022 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-023 | 已完成 | `create-genealogy.html`、`profile-data.html`、涉及地区选择的编辑页 | `/genealogy/region/children`、`/genealogy/region/search`、`/genealogy/region/{regionCode}`、`/genealogy/region/path/{regionCode}` | 2026-07-09 14:44:43 +08:00 开始;2026-07-09 14:49:54 +08:00 完成。新增 `public/js/region-pages.js`、`tests/region-pages.test.js`;更新 `public/js/api-client.js`、`public/js/genealogy-pages.js`、`tests/api-client.test.js`、`tests/genealogy-pages.test.js`、`create-genealogy.html`、`profile-data.html`、`public/css/create-genealogy.css`、`public/css/profile-module.css`。验证:全部 Node 测试通过,业务 JS 语法检查通过,两张页面地区选择挂载点检查通过,API-023 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-024 | 暂缓 | `surname.html`、`surname-detail.html`、`search-result.html`、`genealogy.html`、`culture.html`、`about.html`、`index.html` | 当前接口文档未发现明确同名业务接口 | 2026-07-09 14:50:47 +08:00 复查。公开家谱接口不支持搜索参数,文章接口依赖 `genealogyId`,推广接口只有列表,不强行映射为姓氏百科或全站搜索。 |
|
||||||
|
| API-025 | 暂缓 | `profile-video.html`、`promo-video.html`、`profile-data-reminders.html` | 当前接口文档未发现明确视频、资料提醒独立接口 | 2026-07-09 14:50:47 +08:00 复查。视频和资料提醒没有独立接口,暂不伪造接口;`profile-create-family.html` 归入新增 API-026。 |
|
||||||
|
| API-026 | 已完成 | `profile-create-family.html` | `/genealogy/app/genealogies`、`/genealogy/region/children` | 2026-07-09 14:51:39 +08:00 开始;2026-07-09 14:53:50 +08:00 完成。更新 `profile-create-family.html`、`public/css/profile-module.css`、`tests/genealogy-pages.test.js`,复用 `public/js/api-client.js`、`public/js/region-pages.js`、`public/js/genealogy-pages.js`。验证:全部 Node 测试通过,业务 JS 语法检查通过,页面创建表单和地区选择挂载点检查通过,API-026 自有 JS 未发现样式注入片段;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-027 | 已完成 | `profile-data.html` | `/genealogy/app/auth/profile` | 2026-07-09 14:57:51 +08:00 开始;2026-07-09 15:03:27 +08:00 完成。更新 `profile-data.html`、`public/js/profile-pages.js`、`public/css/profile-module.css`、`tests/profile-pages.test.js`、`tests/api-client.test.js`。补齐个人资料编辑提交,字段对应 `ProfileUpdateBody`:`nickName`、`avatarOssId`、`sex`、`birthday`;地区字段继续沿用 API-023。验证:已观察 `node tests\profile-pages.test.js` 因缺少 `buildProfileUpdateBody` 失败;实现后 `node tests\profile-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、页面挂载点检查均通过;未发现样式注入片段和 TODO 类占位;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-028 | 已完成 | `profile-generation.html` | `/genealogy/app/genealogies/{genealogyId}/generation-poems/batch/preview`、`/genealogy/app/genealogies/{genealogyId}/generation-poems/batch/save` | 2026-07-09 15:05:58 +08:00 开始;2026-07-09 15:11:37 +08:00 完成。更新 `profile-generation.html`、`public/js/api-client.js`、`public/js/generation-pages.js`、`public/css/profile-module.css`、`tests/generation-pages.test.js`、`tests/api-client.test.js`。补齐字辈批量预览和批量保存,字段对应 `GenerationPoemBatchBody`:`content`、`stopMissingOldGeneration`。验证:已观察 `node tests\generation-pages.test.js` 因缺少 `buildGenerationBatchBody` 失败,`node tests\api-client.test.js` 因缺少 `previewGenerationPoems` 失败;实现后 `node tests\generation-pages.test.js`、`node tests\api-client.test.js`、全部 `tests/*.test.js`、业务 JS `node --check`、页面挂载点检查均通过;未发现样式注入片段和 TODO 类占位;`git diff --check` 因当前目录不是 Git 仓库无法执行。 |
|
||||||
|
| API-029 | 已中止 | `profile-services.html` | `/genealogy/app/genealogies/options` | 2026-07-09 15:13:03 +08:00 开始;2026-07-09 15:14:58 +08:00 中止。原因:用户确认此前依据的 `APP.openapi.json` 不是 PC 接口文档,PC/H5 应改用 `genealogy-pc-openapi.yaml`,且接口地址使用 `https://test-genealogy-api.ddxcjp.cn`。本项不再继续按 APP 接口推进。 |
|
||||||
|
|
||||||
|
## 下一步执行顺序
|
||||||
|
|
||||||
|
1. API-011:世系树与人物管理。
|
||||||
|
2. API-012:成员与家族管理。
|
||||||
|
3. API-014:谱文与内容文章。
|
||||||
|
4. API-013:家族圈动态。
|
||||||
|
5. API-015:相册照片。
|
||||||
|
6. API-019:上传公共能力。
|
||||||
|
7. API-016 至 API-023:按页面入口完整度继续推进。
|
||||||
|
8. API-024、API-025:只在确认接口归属后推进。
|
||||||
|
|
||||||
|
## 本次流程修正记录
|
||||||
|
|
||||||
|
- 2026-07-09 13:21:31 +08:00:收到用户提醒,停止继续无编号推进;补充本编号追踪表,并要求后续每项先标记状态再实现,完成后再标记已完成。
|
||||||
|
- 2026-07-09 14:26:34 +08:00:开始执行 API-020,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:31:29 +08:00:API-020 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:33:01 +08:00:开始执行 API-021,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:37:25 +08:00:API-021 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:38:22 +08:00:开始执行 API-022,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:42:47 +08:00:API-022 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:44:43 +08:00:开始执行 API-023,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:49:54 +08:00:API-023 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:50:47 +08:00:复查 API-024/API-025,缺少明确接口的页面标记为“暂缓”,将 `profile-create-family.html` 单独规划为 API-026。
|
||||||
|
- 2026-07-09 14:51:39 +08:00:开始执行 API-026,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:53:50 +08:00:API-026 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:57:51 +08:00:开始执行 API-027,状态标记为“进行中”;按接口文档把 `profile-data.html` 的个人资料更新归到 `/genealogy/app/auth/profile` PUT,先写测试再实现。
|
||||||
|
- 2026-07-09 15:03:27 +08:00:API-027 执行完成,状态从“进行中”改为“已完成”;完成个人资料编辑表单、提交逻辑、页面样式和测试验证。
|
||||||
|
- 2026-07-09 15:05:58 +08:00:开始执行 API-028,状态标记为“进行中”;按接口文档把 `profile-generation.html` 的批量字辈能力归到 `/generation-poems/batch/preview` 和 `/generation-poems/batch/save`。
|
||||||
|
- 2026-07-09 15:11:37 +08:00:API-028 执行完成,状态从“进行中”改为“已完成”;完成批量字辈预览、批量保存、页面入口、样式和测试验证。
|
||||||
|
- 2026-07-09 15:13:03 +08:00:开始执行 API-029,状态标记为“进行中”;把 `profile-services.html` 的家谱选择归到 `/genealogy/app/genealogies/options`。
|
||||||
|
- 2026-07-09 15:14:58 +08:00:收到用户纠正,确认旧依据 `APP.openapi.json` 不适合作为 PC 页面接口文档;中止 API-029,后续改以 `genealogy-pc-openapi.yaml` 和 `https://test-genealogy-api.ddxcjp.cn` 重新规划。
|
||||||
|
- 2026-07-09 13:25:03 +08:00:开始执行 API-011,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 13:33:41 +08:00:API-011 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 13:34:36 +08:00:开始执行 API-012,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 13:40:47 +08:00:API-012 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 13:41:44 +08:00:开始执行 API-014,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 13:46:31 +08:00:API-014 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 13:47:29 +08:00:开始执行 API-013,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 13:52:03 +08:00:API-013 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 13:52:58 +08:00:开始执行 API-015,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 13:57:31 +08:00:API-015 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:00:01 +08:00:开始执行 API-019,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:04:52 +08:00:API-019 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:05:57 +08:00:开始执行 API-016,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:12:27 +08:00:API-016 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:13:25 +08:00:开始执行 API-017,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:18:15 +08:00:API-017 执行完成,状态从“进行中”改为“已完成”。
|
||||||
|
- 2026-07-09 14:19:26 +08:00:开始执行 API-018,状态从“待开始”改为“进行中”。
|
||||||
|
- 2026-07-09 14:24:10 +08:00:API-018 执行完成,状态从“进行中”改为“已完成”。
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
# PC 接口对接重新规划与状态追踪
|
||||||
|
|
||||||
|
创建时间:2026-07-09 15:14:58 +08:00
|
||||||
|
接口依据:`genealogy-pc-openapi.yaml`
|
||||||
|
接口基础地址:`http://test-genealogy-api.ddxcjp.cn`
|
||||||
|
旧依据处理:`APP.openapi.json` 只作为历史误用记录,不再作为 PC 页面继续对接依据。
|
||||||
|
旧进度记录:`docs/api-page-integration-tracker-2026-07-09.md`
|
||||||
|
|
||||||
|
## 执行规则
|
||||||
|
|
||||||
|
1. 所有 PC 接口对接必须先进入本追踪表,再改代码。
|
||||||
|
2. 每一项开始前先标记“进行中”,记录年月日时分秒和时区。
|
||||||
|
3. 每一项完成后记录完成时间、修改文件、接口路径、验证命令和结果。
|
||||||
|
4. 只有完成验证后才能标记“已完成”。
|
||||||
|
5. `genealogy-pc-openapi.yaml` 没有明确接口的页面,标记“暂缓”或“待确认”,不继续套用 APP 路径。
|
||||||
|
6. 样式继续写入 CSS 文件,业务 JS 不注入样式。
|
||||||
|
7. 新增或修改的 HTML、JS、CSS 注释使用中文,代码保持可读、不压缩。
|
||||||
|
|
||||||
|
## PC 文档当前接口范围
|
||||||
|
|
||||||
|
- 验证中心:`/captcha/require`、`/captcha/challenge`、`/captcha/verify`、`/auth/code`
|
||||||
|
- PC 认证:`/genealogy/pc/auth/register`、`/genealogy/pc/auth/login`、`/genealogy/pc/auth/login/sms`、`/genealogy/pc/auth/sms/code`、`/genealogy/pc/auth/profile`、`/genealogy/pc/auth/password`、`/genealogy/pc/auth/password/reset`、`/genealogy/pc/auth/phone`、`/genealogy/pc/auth/account/deactivate`、`/genealogy/pc/auth/logout`
|
||||||
|
- PC 文件:`/genealogy/pc/files/upload`、`/genealogy/pc/files/resumable/init`、`/genealogy/pc/files/resumable/chunk`、`/genealogy/pc/files/resumable/complete`、`/genealogy/pc/files/reference`
|
||||||
|
- 行政区划:`/genealogy/region/children`、`/genealogy/region/path/{regionCode}`、`/genealogy/region/search`、`/genealogy/region/{regionCode}`
|
||||||
|
|
||||||
|
## 最新 PC YAML 分析记录
|
||||||
|
|
||||||
|
分析时间:2026-07-09 15:36:16 +08:00
|
||||||
|
分析文件:`genealogy-pc-openapi.yaml`
|
||||||
|
|
||||||
|
1. `paths` 中实际存在 25 个接口操作,分为验证码、PC 认证、PC 文件、行政区划四类。
|
||||||
|
2. `servers` 仍是本地地址示例,项目实际对接基础地址继续按用户指定使用 `https://test-genealogy-api.ddxcjp.cn`。
|
||||||
|
3. 登录后接口使用 `Authorization` 作为 token header,同时所有 PC 认证和文件接口都要求 header `clientid`;用户最新提供的 PC `clientid` 为 `ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`。
|
||||||
|
4. `components.tags` 和 `components.schemas/requestBodies` 中出现家谱、动态、世系、字辈等业务模型,但 `paths` 没有对应接口路径;实现时不能把这些 schema 当成可调用 PC 接口。
|
||||||
|
5. 验证码 schema 示例里仍出现 `APP_LOGIN`、`PC_LOGIN` 等文本示例;实际页面场景以后台配置为准,当前明确可用的 PC/H5 场景为 `WEB_H5_LOGIN`、`WEB_H5_REGISTER`、`WEB_H5_FORGOT_PASSWORD`。
|
||||||
|
6. `ProfileUpdate` 示例出现 `regionCode/addressDetail`,但 schema 实际字段是 `provinceCode/cityCode/districtCode`,页面资料提交时应以 schema 字段为准。
|
||||||
|
7. `SmsLoginBody` 未声明 `validToken` 字段,但短信发送 `SmsCodeBody` 必填 `validToken`;短信登录流程应先通过验证码拿票据,再发短信验证码,最后用短信码登录。
|
||||||
|
8. 文件引用 `FileReferenceBody` 必填 `bizType/bizTable/bizId/bizField`,`ossId/ossIds/usageScene/usageName` 可选;但文章、动态、相册等业务主体接口未提供,文件引用只能作为公共上传能力,不代表主业务已可提交。
|
||||||
|
|
||||||
|
## 验证码与 TAC 调用记录
|
||||||
|
|
||||||
|
- 后台验证码配置截图中,PC/H5 当前明确可用场景是 `WEB_H5_LOGIN`、`WEB_H5_REGISTER`、`WEB_H5_FORGOT_PASSWORD`,客户端 Key 为 `web_pc`,验证服务为“天爱行为验证码”,验证码类型为“滑块验证码”。
|
||||||
|
- `ADMIN_LOGIN` 是后台管理登录,类型为旋转验证码,不归当前 PC/H5 页面使用。
|
||||||
|
- `APP_LOGIN`、`APP_REGISTER`、`APP_PHONE_CHANGE`、`APP_FORGOT_PASSWORD`、`APP_SMS_CODE`、`APP_ACCOUNT_DEACTIVATE` 的客户端 Key 为 `app`,不能继续作为 PC/H5 场景默认值。
|
||||||
|
- PC/H5 登录页调用链:
|
||||||
|
1. 页面加载 `public/tac/css/tac.css`、`public/tac/js/tac.min.js`、`public/js/captcha-pages.js`。
|
||||||
|
2. 表单提供 `input[name="validToken"]` 隐藏字段和 `[data-captcha-box]` 容器。
|
||||||
|
3. `auth-pages.js` 在登录提交前调用 `CaptchaPages.ensureToken(form, { sceneCode: 'WEB_H5_LOGIN', subject: 手机号 })`。
|
||||||
|
4. `captcha-pages.js` 先请求 `GET /captcha/require?tenantId=000000&clientId=ced7e5f0498645c6ec642dcf450b036f&sceneCode=WEB_H5_LOGIN&subject=手机号`。
|
||||||
|
5. 如果返回 `required=false`,业务表单可继续提交;如果需要验证,则创建 `new CaptchaConfig(...)` 和 `new TAC(config, ...)`。
|
||||||
|
6. TAC 内部请求 `POST /captcha/challenge` 获取 `captchaType/challengeId/payload`,适配为 TAC 需要的 `data.type/data.id/backgroundImage/templateImage`。
|
||||||
|
7. 用户拖动完成后,TAC 请求 `POST /captcha/verify`,提交 `challengeId/providerCode/captchaType/payload.data.trackList`。
|
||||||
|
8. 验证成功后从返回 `data.validToken` 取票据,写回表单隐藏字段 `validToken`,再提交 PC 登录接口。
|
||||||
|
- PC/H5 注册使用 `WEB_H5_REGISTER`,找回密码和找回密码短信验证码使用 `WEB_H5_FORGOT_PASSWORD`;换绑手机、注销账号暂未看到明确 PC/H5 场景编码,仍待后端补充后再接。
|
||||||
|
|
||||||
|
## 编号计划
|
||||||
|
|
||||||
|
| 编号 | 状态 | 页面范围 | 接口范围 | 计划与验证 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| PC-000 | 已完成 | 全项目 | `genealogy-pc-openapi.yaml`、`https://test-genealogy-api.ddxcjp.cn` | 2026-07-09 15:14:58 +08:00 完成。确认旧 APP 接口依据错误,停止继续按 APP 路径推进;确认 PC YAML 当前只明确认证、文件、地区接口。 |
|
||||||
|
| PC-001 | 已完成 | 全项目配置层 | `config.js`、`https://test-genealogy-api.ddxcjp.cn` | 2026-07-09 15:57:36 +08:00 修正完成。根目录 `config.js` 作为开发/生产环境切换的唯一入口;开发环境基础地址为 `https://test-genealogy-api.ddxcjp.cn`;PC `clientid` 按用户最新截图改为 `ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`。验证:`node tests\config.test.js` 输出 `config tests passed`,`node --check config.js` 通过。 |
|
||||||
|
| PC-002 | 已完成 | `utils` 公共工具层、`public/js/api-client.js` | PC `clientid`、通用请求、token、表单、存储、PC YAML paths | 2026-07-09 15:51:34 +08:00 完成。新增 `utils/StorageUtil.js`、`utils/FormUtil.js`、`utils/RequestUtil.js`;重写 `public/js/api-client.js`,真实请求只保留 PC YAML 中的 `/captcha/*`、`/auth/code`、`/genealogy/pc/auth/*`、`/genealogy/pc/files/*`、`/genealogy/region/*`,PC YAML 未覆盖业务方法改为抛 `PC_API_NOT_AVAILABLE`,不再发旧 APP 请求。验证:`node tests\utils.test.js`、`node tests\api-client.test.js` 均通过;`Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'` 无输出;`node --check public\js\api-client.js` 通过。 |
|
||||||
|
| PC-003 | 已完成 | `login.html`、`register.html`、`forgot-password.html`、`profile-security.html`、`profile-data.html`、`profile.html` | `/genealogy/pc/auth/*`、`/captcha/*` | 2026-07-09 16:00:22 +08:00 完成。`login.html` 使用 `WEB_H5_LOGIN`;`register.html` 使用 `WEB_H5_REGISTER`;`forgot-password.html` 使用 `WEB_H5_FORGOT_PASSWORD`;认证/资料/安全页面均已补齐 `config.js`、`utils/*`、`api-client.js` 脚本顺序。资料提交字段按 PC YAML 使用 `provinceCode/cityCode/districtCode`。验证:`node tests\auth-pages.test.js`、`node tests\captcha-pages.test.js`、`node tests\profile-pages.test.js`、`node tests\security-pages.test.js` 均通过;相关 JS `node --check` 通过;旧 `PC_LOGIN/PC_REGISTER/PC_PASSWORD_RESET/APP_*` 场景扫描无输出。 |
|
||||||
|
| PC-004 | 已完成 | 文件上传相关页面 | `/genealogy/pc/files/*` | 2026-07-09 16:03:23 +08:00 完成。`api-client.js` 文件上传、分片上传、文件引用绑定均走 `/genealogy/pc/files/*`;`profile-album.html`、`profile-article-edit.html`、`profile-feed-edit.html`、`profile-growth-edit.html`、`profile-memo-edit.html`、`profile-gift-edit.html` 已补齐 `config.js`、`utils/*`、`api-client.js`、`upload-pages.js` 顺序。验证:`node tests\upload-pages.test.js`、`node tests\api-client.test.js` 通过;`Select-String -Path public\js\api-client.js,public\js\upload-pages.js -Pattern '/genealogy/app/files'` 无输出。 |
|
||||||
|
| PC-005 | 已完成 | 使用地区选择的页面 | `/genealogy/region/*` | 2026-07-09 16:05:12 +08:00 完成。`create-genealogy.html`、`profile-create-family.html`、`profile-data.html` 地区选择页面已补齐 `config.js`、`utils/*`、`api-client.js`、`region-pages.js` 顺序;地区请求只走 `/genealogy/region/children`、`/genealogy/region/path/{regionCode}`、`/genealogy/region/search`、`/genealogy/region/{regionCode}`。验证:`node tests\region-pages.test.js`、`node tests\profile-pages.test.js` 通过;`node --check public\js\region-pages.js` 通过;地区旧 APP 路径扫描无输出。 |
|
||||||
|
| PC-006 | 已修正 | 全项目页面覆盖矩阵 | PC YAML 现有接口覆盖范围与缺口 | 2026-07-09 15:34:26 +08:00 完成修正。该项只作为文档清单任务,不做业务代码。输出页面级覆盖矩阵:完整可闭环、接口存在但验证码待确认、只能保留公共能力、文件能力可切换但主业务待确认、PC YAML 未覆盖。避免把“页面里某个公共接口可用”误标为“整页已可对接”。 |
|
||||||
|
| PC-007 | 已完成 | 详细实施规划 | `genealogy-pc-openapi.yaml` 的 `paths`、`docs/superpowers/plans/2026-07-09-pc-api-replan.md` | 2026-07-09 15:41:40 +08:00 完成修正。重写详细实施计划:只以 YAML `paths` 为真实接口来源;`api-client.js` 不能保留 APP 路径 fallback;PC YAML 未覆盖页面改为受控“接口待确认/PC_API_NOT_AVAILABLE”;补充资料字段 `provinceCode/cityCode/districtCode`、TAC 登录场景 `WEB_H5_LOGIN`、文件/地区局部能力边界。 |
|
||||||
|
| PC-008 | 已完成 | PC YAML 未覆盖业务页面 | `PC_API_NOT_AVAILABLE`、旧 APP 网络路径清理 | 2026-07-09 16:06:35 +08:00 完成。`api-client.js` 中家谱主体、成员、字辈、世系、动态、文章、相册、祭祀、族务、VIP、通知、反馈、帮助、推广等 PC YAML 未覆盖业务方法保留方法名但统一抛 `PC_API_NOT_AVAILABLE`,不再发 `/genealogy/app/` 请求。验证:`Get-ChildItem -Path tests -Filter *.test.js | Sort-Object Name | ForEach-Object { node $_.FullName }` 全部通过;`Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'` 无输出。 |
|
||||||
|
| PC-009 | 已完成 | `login.html`、`register.html`、`forgot-password.html` | `/genealogy/pc/auth/login`、`/genealogy/pc/auth/login/sms`、`/genealogy/pc/auth/register`、`/genealogy/pc/auth/sms/code`、`/genealogy/pc/auth/password/reset`、`/captcha/*` | 2026-07-09 16:32:17 +08:00 开始,2026-07-09 16:40:02 +08:00 完成。专项计划见 `docs/superpowers/plans/2026-07-09-pc-auth-three-pages.md`。`login.html` 已补齐密码登录/短信登录两种模式,短信登录使用 `WEB_H5_LOGIN` 发送验证码并调用 `/genealogy/pc/auth/login/sms`;注册页继续使用 `WEB_H5_REGISTER` 和 `/genealogy/pc/auth/register`;忘记密码页继续使用 `WEB_H5_FORGOT_PASSWORD`、`/genealogy/pc/auth/sms/code`、`/genealogy/pc/auth/password/reset`。修改文件:`login.html`、`public/css/login.css`、`public/js/auth-pages.js`、`tests/auth-pages.test.js`、`tests/api-client.test.js`。验证:`node tests\auth-pages.test.js`、`node tests\api-client.test.js`、`node tests\captcha-pages.test.js` 通过;全量 `tests/*.test.js` 通过;`node --check public\js\auth-pages.js`、`node --check public\js\api-client.js`、`node --check public\js\captcha-pages.js` 通过;内联样式和旧验证码场景扫描无输出。 |
|
||||||
|
| PC-010 | 已完成 | `config.js`、`public/js/api-client.js` | 开发环境接口基础地址、`/captcha/require`、`/captcha/challenge` | 2026-07-09 16:45:35 +08:00 开始,2026-07-09 16:48:05 +08:00 完成。根因:浏览器和 `curl.exe` 复现 `https://test-genealogy-api.ddxcjp.cn` TLS 握手失败,错误为 `ERR_SSL_UNRECOGNIZED_NAME_ALERT`/`SEC_E_ILLEGAL_MESSAGE`;同一 `/captcha/require` 请求改用 `http://test-genealogy-api.ddxcjp.cn` 返回 `200 OK`。处理:开发环境基础地址改为 `http://test-genealogy-api.ddxcjp.cn`;`config.js` 对旧的 `https://test-genealogy-api.ddxcjp.cn` 本地覆盖值做归一,避免浏览器 localStorage 残留继续走坏地址;`api-client.js` fallback 默认地址同步改为 HTTP。修改文件:`config.js`、`public/js/api-client.js`、`tests/config.test.js`、`tests/api-client.test.js`。验证:`node tests\config.test.js`、`node tests\api-client.test.js`、`node --check config.js`、`node --check public\js\api-client.js` 通过。 |
|
||||||
|
| PC-011 | 已完成 | `login.html`、`register.html`、`forgot-password.html`、`public/css/public.css`、`public/js/captcha-pages.js` | `public/tac` 弹窗挂载、`/captcha/challenge`、`/captcha/verify` | 2026-07-09 16:56:22 +08:00 开始,2026-07-09 17:02:35 +08:00 完成。根因:`public/tac/css/tac.css` 中 `#tianai-captcha-parent` 是相对定位,会在绑定元素内渲染;此前把 `[data-captcha-box]` 放进表单内部,导致验证码块直接占据卡片内容区域。处理:三张认证页移除表单内部挂载点,新增页面级 `.auth-captcha-modal[data-captcha-box]`;`public/css/public.css` 增加固定遮罩、居中和移动端宽度约束;`captcha-pages.js` 优先使用页面级挂载点;未修改 `public/tac/js/tac.min.js`。修改文件:`login.html`、`register.html`、`forgot-password.html`、`public/css/public.css`、`public/js/captcha-pages.js`、`tests/auth-page-structure.test.js`、`tests/captcha-pages.test.js`。验证:`node tests\auth-page-structure.test.js`、`node tests\captcha-pages.test.js` 通过;全量 `tests/*.test.js` 通过;`node --check public\js\captcha-pages.js`、`node --check public\js\auth-pages.js` 通过;表单内部 `data-captcha-box` 扫描无输出。 |
|
||||||
|
|
||||||
|
## PC 页面覆盖矩阵草案
|
||||||
|
|
||||||
|
| 分类 | 页面/模块 | 当前判断 | 处理方式 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 完整可闭环 | `login.html` | PC YAML 有 `/genealogy/pc/auth/login`,后台验证码配置明确 `WEB_H5_LOGIN`,TAC 可完整串联。 | 可作为第一批执行页面。 |
|
||||||
|
| 接口存在但部分验证码场景待确认 | `register.html`、`forgot-password.html`、`profile-security.html` 中的换绑/注销相关动作 | PC YAML 有对应认证接口;注册场景为 `WEB_H5_REGISTER`,找回密码场景为 `WEB_H5_FORGOT_PASSWORD`,换绑和注销暂未提供 PC/H5 场景。 | 注册和找回密码可接 TAC;换绑、注销涉及验证码的提交先记录待确认,不能套用 `APP_*` 场景。 |
|
||||||
|
| 资料接口可对接 | `profile.html`、`profile-data.html` 中用户资料读取/修改 | PC YAML 有 `/genealogy/pc/auth/profile`。 | 只处理用户资料读写;页面里其他非资料业务不因此视为完成。 |
|
||||||
|
| 公共地区能力可保留 | `create-genealogy.html`、`profile-create-family.html`、`profile-data.html` 中地区选择控件 | PC YAML 有 `/genealogy/region/*`。 | 只保留和验证地区选择;创建家谱等主业务接口 PC YAML 未覆盖,仍待确认。 |
|
||||||
|
| 文件能力可切换 | 文章、动态、相册、成长、备忘、祭祀等页面里的上传控件 | PC YAML 有 `/genealogy/pc/files/*`。 | 只把上传、分片、文件引用切到 PC 文件接口;文章/动态/相册等主业务接口仍待确认。 |
|
||||||
|
| PC YAML 未覆盖 | 家谱主体、成员、字辈、世系、动态、文章、相册、祭祀、族务、VIP、通知、反馈、帮助、推广、姓氏、搜索等主业务页面 | 当前 PC YAML 没有这些业务路径。 | 不套用 APP 路径;等待补充 PC 接口后再逐页规划。 |
|
||||||
|
|
||||||
|
## 流程记录
|
||||||
|
|
||||||
|
- 2026-07-09 15:14:58 +08:00:收到用户纠正,停止 APP 接口继续推进;读取 `genealogy-pc-openapi.yaml`,确认 PC 路径前缀为 `/genealogy/pc`,基础地址改用 `https://test-genealogy-api.ddxcjp.cn`。
|
||||||
|
- 2026-07-09 15:14:58 +08:00:创建本 PC 专用追踪表,PC-001 标记为“进行中”。
|
||||||
|
- 2026-07-09 15:17:57 +08:00:收到用户补充要求,重新规划 `config.js` 环境切换和 `utils` 公共 JS 分层;停止直接执行旧 PC-001,把 PC-001 到 PC-006 重排为待执行计划。
|
||||||
|
- 2026-07-09 15:24:02 +08:00:收到用户补充验证码要求;记录 `public/tac` 调用链,确认 PC/H5 登录使用 `WEB_H5_LOGIN`,其他未配置 PC/H5 场景的认证验证码先待确认。
|
||||||
|
- 2026-07-09 15:31:14 +08:00:根据用户质疑修正 PC-006;不再把“公共地区/文件接口可用”写成“整页可对接”,改为页面覆盖矩阵和缺口清单。
|
||||||
|
- 2026-07-09 15:34:26 +08:00:同步修正详细规划文件 `docs/superpowers/plans/2026-07-09-pc-api-replan.md` 的 Task 6,并将 PC-006 标记为“已修正”。
|
||||||
|
- 2026-07-09 15:41:40 +08:00:按最新 YAML 分析结果重写 `docs/superpowers/plans/2026-07-09-pc-api-replan.md`,新增 PC-007;明确旧 APP 路径不能作为 PC fallback,缺失业务接口统一降级为接口待确认。
|
||||||
|
- 2026-07-09 15:44:18 +08:00:开始执行 PC-001/PC-002,先按 TDD 创建 `config.js` 和 `utils` 公共工具测试,再实现最小配置与工具层。
|
||||||
|
- 2026-07-09 15:47:17 +08:00:完成 PC-001 和 PC-002 的公共工具层部分;`config.js` 位于根目录,`utils` 只放跨页面公共 JS,页面业务仍留在 `public/js`。
|
||||||
|
- 2026-07-09 15:51:34 +08:00:完成 PC-002 的 `api-client.js` 切换;旧 APP 路径不再作为网络请求路径,未覆盖业务统一抛 `PC_API_NOT_AVAILABLE`。
|
||||||
|
- 2026-07-09 15:55:28 +08:00:PC-003 认证页验证码阶段完成;登录使用 `WEB_H5_LOGIN`,未确认 PC/H5 场景的注册和找回密码不调用验证中心。
|
||||||
|
- 2026-07-09 15:57:36 +08:00:收到用户补充截图,确认 PC `clientid` 为 `ced7e5f0498645c6ec642dcf450b036f`、客户端 Key 为 `web_pc`,新增注册场景 `WEB_H5_REGISTER` 和找回密码场景 `WEB_H5_FORGOT_PASSWORD`;同步修正配置、计划和认证页场景映射。
|
||||||
|
- 2026-07-09 16:00:22 +08:00:PC-003 完成;认证页、资料页、安全页的 PC auth/captcha 接入和脚本顺序已验证。
|
||||||
|
- 2026-07-09 16:03:23 +08:00:PC-004 完成;上传公共能力切换到 PC 文件接口,相关上传页已补齐公共层脚本顺序。
|
||||||
|
- 2026-07-09 16:05:12 +08:00:PC-005 完成;地区选择只保留公共行政区划能力,创建家谱等主业务仍按 PC YAML 未覆盖处理。
|
||||||
|
- 2026-07-09 16:06:35 +08:00:PC-008 完成;PC YAML 未覆盖业务不会继续发送旧 APP 请求,全量 Node 测试通过。
|
||||||
|
- 2026-07-09 16:07:42 +08:00:收尾验证完成;全量 `tests/*.test.js` 通过,`public/js` 非压缩业务脚本 `node --check` 通过,旧 `/genealogy/app/`、旧验证码场景、旧 PC clientId 扫描无输出;`git diff --check` 因当前目录不是 Git 仓库无法执行。
|
||||||
|
- 2026-07-09 16:09:55 +08:00:开始登录、注册、找回密码三页专项核对;按 PC YAML 的 `PasswordLoginBody`、`PasswordRegisterBody`、`SmsCodeBody`、`PasswordResetBody` 修正页面字段、输入类型、验证码场景声明和文案。
|
||||||
|
- 2026-07-09 16:12:10 +08:00:登录、注册、找回密码三页专项完成;三页表单已显式声明 `data-captcha-scene`,手机号输入改为 `type="tel"`、`inputmode="numeric"`、`maxlength="11"`,找回密码文案改为只支持注册手机号;`auth-pages.js` 优先读取页面 `data-captcha-scene`。验证:`node tests\auth-pages.test.js`、`node tests\captcha-pages.test.js`、`node tests\api-client.test.js` 通过;三页字段/脚本顺序扫描通过;旧邮箱文案和旧验证码场景扫描无输出。
|
||||||
|
- 2026-07-09 16:19:11 +08:00:根据用户反馈“接口文档少了很多东西”重新核对 `genealogy-pc-openapi.yaml` 的真实 `paths`;确认当前 YAML 只有验证中心、认证登录、文件上传、行政区划四类共 25 个操作,虽然声明了家谱、成员、字辈、世系、家族圈、文章、相册、祭祀、族务、VIP、消息、反馈等标签和模型,但没有对应可调用路径。结论:这些业务页面不能继续视为已对接,只能保留 `PC_API_NOT_AVAILABLE`,等待后端补充 PC 接口文档。
|
||||||
|
- 2026-07-09 16:48:05 +08:00:处理注册页滑动验证请求失败。确认失败不是注册字段问题,而是测试域名 HTTPS 握手失败;开发环境接口基础地址修正为 HTTP,并兼容清理旧 HTTPS 本地覆盖值。
|
||||||
|
- 2026-07-09 16:56:22 +08:00:处理 TAC 验证码显示位置问题。确认不是后端验证码类型问题,也不是 `tac.min.js` 被改;问题来自前端挂载点在表单中,导致 TAC 相对定位弹窗被卡片布局吞进去。
|
||||||
|
- 2026-07-09 17:02:35 +08:00:TAC 弹窗挂载修复完成。三张认证页改为页面级固定遮罩容器承载 TAC,表单内部不再放验证码挂载点;新增结构测试防止回退。
|
||||||
|
- 2026-07-09 17:04:21 +08:00:复现用户反馈的 `503 Service Unavailable`。`curl.exe` 请求 `/captcha/require` 和域名根路径 `/` 均返回 `Server: SakuraFrp`、`503 Service Unavailable`,响应页提示检查 SakuraFrp 隧道节点、隧道配置、frpc 是否运行、隧道是否在线。结论:这是测试接口域名/内网穿透服务当前不可用,不是前端字段、TAC 样式或请求参数导致。
|
||||||
|
## PC-012 认证页 layui 提示与 TAC 弹窗样式修正
|
||||||
|
|
||||||
|
- 状态:已完成
|
||||||
|
- 计划开始时间:2026-07-09 17:14:08 +08:00
|
||||||
|
- 计划文件:`docs/superpowers/plans/2026-07-09-auth-layer-message.md`
|
||||||
|
- 页面范围:`login.html`、`register.html`、`forgot-password.html`
|
||||||
|
- 接口范围:不新增接口,只修正 `/captcha/*` 流程中的前端提示方式和弹窗展示方式。
|
||||||
|
- 完成时间:2026-07-09 17:20:24 +08:00
|
||||||
|
- 修改文件:`login.html`、`register.html`、`forgot-password.html`、`utils/MessageUtil.js`、`public/js/auth-pages.js`、`public/js/captcha-pages.js`、`public/css/public.css`、`tests/auth-page-structure.test.js`、`tests/auth-message.test.js`、`docs/superpowers/plans/2026-07-09-auth-layer-message.md`
|
||||||
|
- 验证结果:
|
||||||
|
- `node tests\auth-page-structure.test.js` 通过。
|
||||||
|
- `node tests\auth-message.test.js` 通过。
|
||||||
|
- `node tests\auth-pages.test.js` 通过。
|
||||||
|
- `node tests\captcha-pages.test.js` 通过。
|
||||||
|
- `node --check public\js\auth-pages.js` 通过。
|
||||||
|
- `node --check public\js\captcha-pages.js` 通过。
|
||||||
|
- `node --check utils\MessageUtil.js` 通过。
|
||||||
|
- `Get-ChildItem -Path tests -Filter *.test.js | Sort-Object Name | ForEach-Object { node $_.FullName }` 全部通过。
|
||||||
|
- 剩余风险:测试域名当前仍可能返回 SakuraFrp `503 Service Unavailable`,这是后端/隧道可用性问题,不是本次提示和样式改动导致。
|
||||||
|
- 执行计划:
|
||||||
|
1. 已完成失败测试:`tests/auth-page-structure.test.js`、`tests/auth-message.test.js`。
|
||||||
|
2. 已完成:三页加载 layui 样式和脚本。
|
||||||
|
3. 已完成:`auth-pages.js`、`captcha-pages.js` 提示统一走 `MessageUtil`/`layui.layer.msg`,不再使用浏览器原生 `alert`。
|
||||||
|
4. 已完成:`public/css/public.css` 增加认证页 layer 提示皮肤。
|
||||||
|
5. 已完成:焦点测试、相关测试、语法检查和全量 Node 测试通过。
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# Auth Layer Message Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 让登录、注册、忘记密码三页的提示统一使用 layui `layer.msg`,不再出现浏览器原生 alert,并补好认证页提示和 TAC 弹窗样式。
|
||||||
|
|
||||||
|
**Architecture:** 页面加载 `public/layui/css/layui.css` 和 `public/layui/layui.js`;`auth-pages.js` 与 `captcha-pages.js` 只负责调用提示,不写样式;提示皮肤与 TAC 弹窗样式写入 `public/css/public.css`。
|
||||||
|
|
||||||
|
**Tech Stack:** 原生 HTML/CSS/JavaScript、layui layer、public/tac、Node 断言测试。
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- 计划开始时间:2026-07-09 17:14:08 +08:00。
|
||||||
|
- 只处理登录、注册、忘记密码三页的提示与弹窗样式问题。
|
||||||
|
- 不修改 `public/tac/js/tac.min.js`。
|
||||||
|
- 不使用 HTML 原生 `alert` 作为用户提示。
|
||||||
|
- 样式写在 CSS 文件里,JS 只切 class 或调用组件。
|
||||||
|
- 新增或修改的 HTML、CSS、JS 注释使用中文,代码保持可读。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: 补充失败测试
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `tests/auth-page-structure.test.js`
|
||||||
|
- Create: `tests/auth-message.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: 当前三页 HTML 与认证脚本。
|
||||||
|
- Produces: 能捕获缺少 layui 和原生 alert 兜底的测试。
|
||||||
|
|
||||||
|
- [x] **Step 1: 添加页面结构断言**
|
||||||
|
|
||||||
|
检查 `login.html`、`register.html`、`forgot-password.html` 必须加载 `public/layui/css/layui.css` 和 `public/layui/layui.js`,且 `layui.js` 在 `auth-pages.js` 前面。
|
||||||
|
|
||||||
|
- [x] **Step 2: 添加提示脚本断言**
|
||||||
|
|
||||||
|
检查 `public/js/auth-pages.js` 与 `public/js/captcha-pages.js` 不再包含 `root.alert`,并检查 `public/css/public.css` 提供 `.auth-layer-message`。
|
||||||
|
|
||||||
|
- [x] **Step 3: 验证红灯**
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-page-structure.test.js
|
||||||
|
node tests\auth-message.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:两个测试均失败,分别提示缺少 layui 和仍存在 `root.alert`。
|
||||||
|
|
||||||
|
### Task 2: 接入 layui 并替换原生提示
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `login.html`
|
||||||
|
- Modify: `register.html`
|
||||||
|
- Modify: `forgot-password.html`
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- Modify: `public/js/captcha-pages.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `layui.layer.msg(message, options)`。
|
||||||
|
- Produces: `showMessage(message)` 统一使用 layer,缺少 layui 时只输出控制台警告,不再弹原生 alert。
|
||||||
|
|
||||||
|
- [x] **Step 1: 三页加载 layui 样式和脚本**
|
||||||
|
|
||||||
|
在三页 `<head>` 中加入 `public/layui/css/layui.css`,在 `auth-pages.js` 前加入 `public/layui/layui.js`。
|
||||||
|
|
||||||
|
- [x] **Step 2: 修改认证脚本提示**
|
||||||
|
|
||||||
|
把 `auth-pages.js` 的 `showMessage` 改为优先调用 `layui.layer.msg(message, { skin: 'auth-layer-message' })`,没有 layui 时使用 `console.warn`。
|
||||||
|
|
||||||
|
- [x] **Step 3: 修改验证码脚本提示**
|
||||||
|
|
||||||
|
把 `captcha-pages.js` 的 `showMessage` 同步改为同样的 layer 提示策略。
|
||||||
|
|
||||||
|
### Task 3: 补齐公共样式
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/css/public.css`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: layui layer 生成的 `.auth-layer-message`。
|
||||||
|
- Produces: 认证页统一提示皮肤和移动端更稳的 TAC 弹窗尺寸。
|
||||||
|
|
||||||
|
- [x] **Step 1: 添加 layui 消息皮肤**
|
||||||
|
|
||||||
|
在公共 CSS 中添加 `.auth-layer-message`,控制圆角、背景、文字和阴影。
|
||||||
|
|
||||||
|
- [x] **Step 2: 微调 TAC 弹窗移动端尺寸**
|
||||||
|
|
||||||
|
继续使用 `.auth-captcha-modal` 页面级挂载,限制 TAC 宽度不超过视口,避免盖层内容顶到边缘。
|
||||||
|
|
||||||
|
### Task 4: 验证并记录完成
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Task 1-3 的实现结果。
|
||||||
|
- Produces: PC-012 完成记录。
|
||||||
|
|
||||||
|
- [x] **Step 1: 跑焦点测试**
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-page-structure.test.js
|
||||||
|
node tests\auth-message.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:全部通过。
|
||||||
|
|
||||||
|
- [x] **Step 2: 跑相关测试和语法检查**
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-pages.test.js
|
||||||
|
node tests\captcha-pages.test.js
|
||||||
|
node --check public\js\auth-pages.js
|
||||||
|
node --check public\js\captcha-pages.js
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:全部通过。
|
||||||
|
|
||||||
|
- [x] **Step 3: 更新追踪记录**
|
||||||
|
|
||||||
|
把 PC-012 标记为已完成,写入完成时间、修改文件、验证命令和剩余风险。
|
||||||
@@ -0,0 +1,762 @@
|
|||||||
|
# PC API Replan Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 按最新 `genealogy-pc-openapi.yaml` 重新整理 PC/H5 页面接口对接,只接入 `paths` 中真实存在的验证码、PC 认证、PC 文件和行政区划接口,并清除旧 APP 路径作为 PC 合同的风险。
|
||||||
|
|
||||||
|
**Architecture:** 根目录 `config.js` 是接口基础地址、客户端 ID、租户、token key 的唯一配置入口;`utils` 只放跨页面公共 JS;`public/js/api-client.js` 只暴露 PC YAML `paths` 中存在的接口和受控的“PC 接口未提供”错误。页面业务 JS 继续放在 `public/js`,页面只能调用 PC 已确认方法;PC YAML 未覆盖的页面保留静态/本地展示或显示接口待确认状态。
|
||||||
|
|
||||||
|
**Tech Stack:** 静态 HTML、原生 JS、jQuery/Layui、Node 测试脚本、`public/tac` 天爱验证码静态资源。
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- 接口依据只使用 `genealogy-pc-openapi.yaml` 的 `paths`。
|
||||||
|
- 开发环境接口基础地址固定为 `https://test-genealogy-api.ddxcjp.cn`。
|
||||||
|
- PC 默认 `clientid` 使用用户最新截图确认值:`ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`。
|
||||||
|
- 登录后请求使用 `Authorization` header,PC 认证和文件请求同时携带 `clientid` header。
|
||||||
|
- 样式写入 CSS 文件,不用 JS 注入样式。
|
||||||
|
- 新增或修改的 HTML、JS、CSS 注释使用中文。
|
||||||
|
- `utils` 只放跨页面公共 JS;页面业务 JS 继续放 `public/js`。
|
||||||
|
- PC YAML 没有明确接口的页面不套用 APP 路径,不把 schema/requestBodies 当成可调用接口。
|
||||||
|
- 验证码只使用后台已配置的 PC/H5 场景;当前明确场景为 `WEB_H5_LOGIN`、`WEB_H5_REGISTER`、`WEB_H5_FORGOT_PASSWORD`。
|
||||||
|
- 换绑手机、注销账号的 PC/H5 验证码场景未确认,不套用 `APP_*` 场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
- Create or Modify: `config.js`
|
||||||
|
- 唯一负责环境切换、开发接口地址、PC clientid、tenantId、token key、token header name。
|
||||||
|
- Create or Modify: `utils/StorageUtil.js`
|
||||||
|
- 负责 localStorage 安全读写。
|
||||||
|
- Create or Modify: `utils/FormUtil.js`
|
||||||
|
- 负责表单读取、空值清理、数字转换、布尔转换。
|
||||||
|
- Create or Modify: `utils/RequestUtil.js`
|
||||||
|
- 负责 URL 拼接、header 合并、FormData 判断、JSON 解包、业务错误对象。
|
||||||
|
- Modify: `public/js/api-client.js`
|
||||||
|
- 只把 PC YAML `paths` 中存在的接口作为真实请求方法;旧 APP 路径不得作为 fallback。
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- 登录使用 `WEB_H5_LOGIN`;注册使用 `WEB_H5_REGISTER`;找回密码使用 `WEB_H5_FORGOT_PASSWORD`。
|
||||||
|
- Modify: `public/js/captcha-pages.js`
|
||||||
|
- 按 `/captcha/require`、`/captcha/challenge`、`/captcha/verify` 组织 TAC 调用。
|
||||||
|
- Modify: `public/js/profile-pages.js`
|
||||||
|
- 用户资料提交字段以 `ProfileUpdateBody` schema 为准:`provinceCode/cityCode/districtCode`。
|
||||||
|
- Modify: `public/js/security-pages.js`
|
||||||
|
- 修改密码、换绑手机、注销账号只调用 PC 认证接口;涉及验证码的动作保留 PC/H5 场景待确认记录。
|
||||||
|
- Modify: `public/js/upload-pages.js`
|
||||||
|
- 上传、分片上传、文件引用只调用 `/genealogy/pc/files/*`。
|
||||||
|
- Modify: `public/js/region-pages.js`
|
||||||
|
- 地区选择只调用 `/genealogy/region/*`。
|
||||||
|
- Modify: related HTML files
|
||||||
|
- API 页面按顺序加载 `config.js`、`utils/*.js`、`public/js/api-client.js`、页面业务脚本。
|
||||||
|
- Modify: `tests/*.test.js`
|
||||||
|
- 测试只验证 PC YAML 已确认接口;旧 APP 路径测试改为“不可作为 PC 合同”。
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
|
- 每项开始/完成都回填时间、文件、接口、验证结果。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: 配置入口与公共工具合同
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create or Modify: `config.js`
|
||||||
|
- Create or Modify: `utils/StorageUtil.js`
|
||||||
|
- Create or Modify: `utils/FormUtil.js`
|
||||||
|
- Create or Modify: `utils/RequestUtil.js`
|
||||||
|
- Test: `tests/config.test.js`
|
||||||
|
- Test: `tests/utils.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `GenealogyConfig.getConfig(): { env, apiBaseUrl, clientId, tenantId, tokenKey, tokenHeaderName }`
|
||||||
|
- Produces: `GenealogyConfig.getApiBaseUrl(): string`
|
||||||
|
- Produces: `GenealogyConfig.getClientId(): string`
|
||||||
|
- Produces: `GenealogyConfig.getTenantId(): string`
|
||||||
|
- Produces: `GenealogyConfig.getTokenKey(): string`
|
||||||
|
- Produces: `StorageUtil.read(storage, key): string|null`
|
||||||
|
- Produces: `StorageUtil.write(storage, key, value): void`
|
||||||
|
- Produces: `StorageUtil.remove(storage, key): void`
|
||||||
|
- Produces: `FormUtil.trimOrUndefined(value): string|undefined`
|
||||||
|
- Produces: `FormUtil.toNumberOrUndefined(value): number|undefined`
|
||||||
|
- Produces: `FormUtil.toBoolean(value): boolean`
|
||||||
|
- Produces: `FormUtil.getFormValues(form): object`
|
||||||
|
- Produces: `RequestUtil.createRequester(options)(method, path, requestOptions): Promise<any>`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write config test**
|
||||||
|
|
||||||
|
Create or replace `tests/config.test.js` with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const assert = require('assert');
|
||||||
|
const configFactory = require('../config.js');
|
||||||
|
|
||||||
|
const store = {};
|
||||||
|
const config = configFactory({
|
||||||
|
localStorage: {
|
||||||
|
getItem: (key) => Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null,
|
||||||
|
setItem: (key, value) => { store[key] = String(value); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(config.getApiBaseUrl(), 'https://test-genealogy-api.ddxcjp.cn');
|
||||||
|
assert.strictEqual(config.getClientId(), 'ced7e5f0498645c6ec642dcf450b036f');
|
||||||
|
assert.strictEqual(config.getTenantId(), '000000');
|
||||||
|
assert.strictEqual(config.getTokenKey(), 'genealogy_auth_token');
|
||||||
|
assert.strictEqual(config.getConfig().tokenHeaderName, 'Authorization');
|
||||||
|
|
||||||
|
store.genealogy_api_base_url = 'https://custom.example.test';
|
||||||
|
assert.strictEqual(config.getApiBaseUrl(), 'https://custom.example.test');
|
||||||
|
|
||||||
|
console.log('config tests passed');
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run config test**
|
||||||
|
|
||||||
|
Run: `node tests\config.test.js`
|
||||||
|
Expected before implementation: FAIL if `config.js` is absent or lacks these methods.
|
||||||
|
Expected after implementation: PASS with `config tests passed`.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement `config.js`**
|
||||||
|
|
||||||
|
Use this implementation:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(function (root, factory) {
|
||||||
|
// 全局配置同时支持浏览器页面和 Node 测试。
|
||||||
|
if (typeof module === 'object' && module.exports) {
|
||||||
|
module.exports = factory;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.GenealogyConfig = factory(root);
|
||||||
|
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var DEFAULT_ENV = 'development';
|
||||||
|
var API_BASE_URLS = {
|
||||||
|
development: 'https://test-genealogy-api.ddxcjp.cn',
|
||||||
|
production: ''
|
||||||
|
};
|
||||||
|
var CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
|
||||||
|
var TENANT_ID = '000000';
|
||||||
|
var TOKEN_KEY = 'genealogy_auth_token';
|
||||||
|
var TOKEN_HEADER_NAME = 'Authorization';
|
||||||
|
var ENV_KEY = 'genealogy_env';
|
||||||
|
var BASE_URL_KEY = 'genealogy_api_base_url';
|
||||||
|
|
||||||
|
function readStorage(key) {
|
||||||
|
try {
|
||||||
|
return root.localStorage && root.localStorage.getItem(key);
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnv() {
|
||||||
|
return readStorage(ENV_KEY) || DEFAULT_ENV;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getApiBaseUrl() {
|
||||||
|
return readStorage(BASE_URL_KEY) || API_BASE_URLS[getEnv()] || API_BASE_URLS.development;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfig() {
|
||||||
|
return {
|
||||||
|
env: getEnv(),
|
||||||
|
apiBaseUrl: getApiBaseUrl(),
|
||||||
|
clientId: CLIENT_ID,
|
||||||
|
tenantId: TENANT_ID,
|
||||||
|
tokenKey: TOKEN_KEY,
|
||||||
|
tokenHeaderName: TOKEN_HEADER_NAME
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getConfig: getConfig,
|
||||||
|
getApiBaseUrl: getApiBaseUrl,
|
||||||
|
getClientId: function () { return CLIENT_ID; },
|
||||||
|
getTenantId: function () { return TENANT_ID; },
|
||||||
|
getTokenKey: function () { return TOKEN_KEY; },
|
||||||
|
getTokenHeaderName: function () { return TOKEN_HEADER_NAME; }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Write utilities test**
|
||||||
|
|
||||||
|
Create or replace `tests/utils.test.js` with focused utility assertions:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const assert = require('assert');
|
||||||
|
const StorageUtil = require('../utils/StorageUtil.js');
|
||||||
|
const FormUtil = require('../utils/FormUtil.js');
|
||||||
|
const RequestUtil = require('../utils/RequestUtil.js');
|
||||||
|
|
||||||
|
assert.strictEqual(FormUtil.trimOrUndefined(' 张三 '), '张三');
|
||||||
|
assert.strictEqual(FormUtil.trimOrUndefined(' '), undefined);
|
||||||
|
assert.strictEqual(FormUtil.toNumberOrUndefined('12'), 12);
|
||||||
|
assert.strictEqual(FormUtil.toNumberOrUndefined(''), undefined);
|
||||||
|
assert.strictEqual(FormUtil.toBoolean('on'), true);
|
||||||
|
assert.strictEqual(FormUtil.toBoolean('0'), false);
|
||||||
|
|
||||||
|
const store = {};
|
||||||
|
const storage = {
|
||||||
|
getItem: (key) => Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null,
|
||||||
|
setItem: (key, value) => { store[key] = String(value); },
|
||||||
|
removeItem: (key) => { delete store[key]; }
|
||||||
|
};
|
||||||
|
StorageUtil.write(storage, 'token', 'abc');
|
||||||
|
assert.strictEqual(StorageUtil.read(storage, 'token'), 'abc');
|
||||||
|
StorageUtil.remove(storage, 'token');
|
||||||
|
assert.strictEqual(StorageUtil.read(storage, 'token'), null);
|
||||||
|
|
||||||
|
const calls = [];
|
||||||
|
const requester = RequestUtil.createRequester({
|
||||||
|
baseUrl: 'https://test-genealogy-api.ddxcjp.cn',
|
||||||
|
clientId: 'pc-client',
|
||||||
|
tokenHeaderName: 'Authorization',
|
||||||
|
getToken: () => 'token-x',
|
||||||
|
fetchImpl: async (url, options) => {
|
||||||
|
calls.push({ url, options });
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: async () => ({ code: 200, data: { ok: true } })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
requester('GET', '/genealogy/pc/auth/profile', {
|
||||||
|
query: { keyword: '汤 氏' }
|
||||||
|
}).then((data) => {
|
||||||
|
assert.deepStrictEqual(data, { ok: true });
|
||||||
|
assert.strictEqual(calls[0].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile?keyword=%E6%B1%A4+%E6%B0%8F');
|
||||||
|
assert.strictEqual(calls[0].options.headers.clientid, 'pc-client');
|
||||||
|
assert.strictEqual(calls[0].options.headers.Authorization, 'Bearer token-x');
|
||||||
|
console.log('utils tests passed');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Implement utility files**
|
||||||
|
|
||||||
|
Implement the utilities with Chinese comments around storage try/catch, FormData detection, JSON response parsing and `code !== 200` error creation. `RequestUtil.createRequester` must omit `Authorization` when `requestOptions.auth === false`.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Run utility tests**
|
||||||
|
|
||||||
|
Run: `node tests\utils.test.js`
|
||||||
|
Expected: PASS with `utils tests passed`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: API 客户端收紧到 PC YAML `paths`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/api-client.js`
|
||||||
|
- Test: `tests/api-client.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `GenealogyConfig`
|
||||||
|
- Consumes: `StorageUtil`
|
||||||
|
- Consumes: `RequestUtil.createRequester`
|
||||||
|
- Produces: `GenealogyApi.createClient(options)`
|
||||||
|
- Produces: `GenealogyApi.defaultClient`
|
||||||
|
- Produces PC methods:
|
||||||
|
- `login(body)`, `register(body)`, `loginBySms(body)`, `sendSmsCode(body)`
|
||||||
|
- `getProfile()`, `updateProfile(body)`, `changePassword(body)`, `resetPassword(body)`, `changePhone(body)`, `deactivateAccount(body)`, `logout()`
|
||||||
|
- `uploadFile(formData)`, `initResumableUpload(body)`, `uploadChunk(formData)`, `completeResumableUpload(body)`, `bindFileReference(body)`, `releaseFileReference(query)`
|
||||||
|
- `getRegionChildren(parentCode)`, `getRegionPath(regionCode)`, `searchRegions(query)`, `getRegion(regionCode)`
|
||||||
|
- `captchaRequire(query)`, `captchaChallenge(body)`, `captchaVerify(body)`, `legacyCaptcha()`
|
||||||
|
- Produces unsupported method behavior: methods for PC YAML 未覆盖业务 throw `Error` with `code === 'PC_API_NOT_AVAILABLE'` and no network request.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Replace API client test**
|
||||||
|
|
||||||
|
Rewrite `tests/api-client.test.js` so it verifies only PC-confirmed paths and unsupported APP-era methods:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const assert = require('assert');
|
||||||
|
const GenealogyApi = require('../public/js/api-client.js');
|
||||||
|
|
||||||
|
const calls = [];
|
||||||
|
const client = GenealogyApi.createClient({
|
||||||
|
baseUrl: 'https://test-genealogy-api.ddxcjp.cn',
|
||||||
|
clientId: 'client-x',
|
||||||
|
tenantId: 'tenant-x',
|
||||||
|
tokenKey: 'token-key',
|
||||||
|
tokenHeaderName: 'Authorization',
|
||||||
|
storage: { getItem: () => 'abc-token' },
|
||||||
|
fetchImpl: async (url, options) => {
|
||||||
|
calls.push({ url, options });
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: async () => ({ code: 200, data: { url } })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await client.login({ tenantId: 'tenant-x', phone: '13800000000', password: 'md5' });
|
||||||
|
assert.strictEqual(calls[0].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/login');
|
||||||
|
assert.strictEqual(calls[0].options.headers.clientid, 'client-x');
|
||||||
|
assert.strictEqual(calls[0].options.headers.Authorization, undefined);
|
||||||
|
|
||||||
|
await client.getProfile();
|
||||||
|
assert.strictEqual(calls[1].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile');
|
||||||
|
assert.strictEqual(calls[1].options.headers.Authorization, 'Bearer abc-token');
|
||||||
|
|
||||||
|
await client.updateProfile({ nickName: '张三', provinceCode: '510000', cityCode: '510100', districtCode: '510104' });
|
||||||
|
assert.strictEqual(calls[2].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile');
|
||||||
|
assert.strictEqual(calls[2].options.method, 'PUT');
|
||||||
|
|
||||||
|
await client.uploadFile(new FormData());
|
||||||
|
assert.strictEqual(calls[3].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/files/upload');
|
||||||
|
|
||||||
|
await client.getRegionChildren('51');
|
||||||
|
assert.strictEqual(calls[4].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/region/children?parentCode=51');
|
||||||
|
|
||||||
|
await client.captchaRequire({ sceneCode: 'WEB_H5_LOGIN', subject: '13800000000' });
|
||||||
|
assert.strictEqual(calls[5].url, 'https://test-genealogy-api.ddxcjp.cn/captcha/require?tenantId=tenant-x&clientId=client-x&sceneCode=WEB_H5_LOGIN&subject=13800000000');
|
||||||
|
assert.strictEqual(calls[5].options.headers.Authorization, undefined);
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => client.listGenealogies(),
|
||||||
|
(error) => error.code === 'PC_API_NOT_AVAILABLE'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(calls.length, 6);
|
||||||
|
console.log('api-client tests passed');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run API client test**
|
||||||
|
|
||||||
|
Run: `node tests\api-client.test.js`
|
||||||
|
Expected before implementation: FAIL while old APP paths or old scene tests remain.
|
||||||
|
Expected after implementation: PASS with `api-client tests passed`.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement confirmed PC methods**
|
||||||
|
|
||||||
|
In `public/js/api-client.js`, remove APP auth/files paths. Map methods exactly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
login: function (body) {
|
||||||
|
return request('POST', '/genealogy/pc/auth/login', { body: body, auth: false });
|
||||||
|
},
|
||||||
|
register: function (body) {
|
||||||
|
return request('POST', '/genealogy/pc/auth/register', { body: body, auth: false });
|
||||||
|
},
|
||||||
|
sendSmsCode: function (body) {
|
||||||
|
return request('POST', '/genealogy/pc/auth/sms/code', { body: body, auth: false });
|
||||||
|
},
|
||||||
|
loginBySms: function (body) {
|
||||||
|
return request('POST', '/genealogy/pc/auth/login/sms', { body: body, auth: false });
|
||||||
|
},
|
||||||
|
getProfile: function () {
|
||||||
|
return request('GET', '/genealogy/pc/auth/profile');
|
||||||
|
},
|
||||||
|
updateProfile: function (body) {
|
||||||
|
return request('PUT', '/genealogy/pc/auth/profile', { body: body });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the remaining PC auth/files/region/captcha methods with the same direct mapping from YAML `paths`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Implement unsupported method guard**
|
||||||
|
|
||||||
|
For old business methods whose PC paths do not exist, keep the method name only if current pages call it, but route it to:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function createUnavailableMethod(name) {
|
||||||
|
return function () {
|
||||||
|
var error = new Error('PC 接口文档未提供该业务接口:' + name);
|
||||||
|
error.code = 'PC_API_NOT_AVAILABLE';
|
||||||
|
throw error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use a Chinese comment above the mapping: `// PC YAML 未提供这些业务 paths,保留方法名只用于阻止旧 APP 路径继续发请求。`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify no APP auth/files network paths remain**
|
||||||
|
|
||||||
|
Run: `Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/auth|/genealogy/app/files'`
|
||||||
|
Expected: no matches.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Run API client test again**
|
||||||
|
|
||||||
|
Run: `node tests\api-client.test.js`
|
||||||
|
Expected: PASS with `api-client tests passed`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: 登录验证码与 `public/tac` 调用
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- Modify: `public/js/captcha-pages.js`
|
||||||
|
- Modify: `login.html`
|
||||||
|
- Modify: `register.html`
|
||||||
|
- Modify: `forgot-password.html`
|
||||||
|
- Test: `tests/auth-pages.test.js`
|
||||||
|
- Test: `tests/captcha-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `public/tac/css/tac.css`
|
||||||
|
- Consumes: `public/tac/js/tac.min.js`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.captchaRequire/challenge/verify`
|
||||||
|
- Produces: `AuthPages.getCaptchaScene('login') === 'WEB_H5_LOGIN'`
|
||||||
|
- Produces: `AuthPages.getCaptchaScene('register') === 'WEB_H5_REGISTER'`
|
||||||
|
- Produces: `AuthPages.getCaptchaScene('password-reset') === 'WEB_H5_FORGOT_PASSWORD'`
|
||||||
|
- Produces: `CaptchaPages.buildChallengeBody(options, api)`
|
||||||
|
- Produces: `CaptchaPages.buildVerifyBody(options, api)`
|
||||||
|
- Produces: `CaptchaPages.ensureToken(form, options)`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Replace auth scene tests**
|
||||||
|
|
||||||
|
In `tests/auth-pages.test.js`, require these expectations:
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(AuthPages.getCaptchaScene('login'), 'WEB_H5_LOGIN');
|
||||||
|
assert.strictEqual(AuthPages.getCaptchaScene('register'), 'WEB_H5_REGISTER');
|
||||||
|
assert.strictEqual(AuthPages.getCaptchaScene('password-reset'), 'WEB_H5_FORGOT_PASSWORD');
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Replace captcha tests**
|
||||||
|
|
||||||
|
In `tests/captcha-pages.test.js`, all challenge/verify body tests must use `WEB_H5_LOGIN`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.deepStrictEqual(CaptchaPages.buildChallengeBody({
|
||||||
|
sceneCode: 'WEB_H5_LOGIN',
|
||||||
|
subject: '13800000000'
|
||||||
|
}, fakeApi), {
|
||||||
|
tenantId: 'tenant-x',
|
||||||
|
clientId: 'client-x',
|
||||||
|
sceneCode: 'WEB_H5_LOGIN',
|
||||||
|
subject: '13800000000'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Run auth and captcha tests**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-pages.test.js
|
||||||
|
node tests\captcha-pages.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected before implementation: FAIL if `PC_LOGIN` or `PC_REGISTER` remains.
|
||||||
|
Expected after implementation: PASS.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Implement scene mapping**
|
||||||
|
|
||||||
|
In `public/js/auth-pages.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function getCaptchaScene(formType) {
|
||||||
|
// PC/H5 认证场景来自后台验证码配置,客户端 Key 为 web_pc。
|
||||||
|
var map = {
|
||||||
|
login: 'WEB_H5_LOGIN',
|
||||||
|
register: 'WEB_H5_REGISTER',
|
||||||
|
'password-reset': 'WEB_H5_FORGOT_PASSWORD'
|
||||||
|
};
|
||||||
|
|
||||||
|
return map[formType] || '';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If `sceneCode` is empty, `ensureCaptcha` must return `true` without calling `/captcha/require` and must not fabricate `validToken`.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify TAC assets in auth pages**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Select-String -Path login.html,register.html,forgot-password.html -Pattern 'public/tac/css/tac.css|public/tac/js/tac.min.js|public/js/captcha-pages.js|name="validToken"|data-captcha-box'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- `login.html` has TAC CSS, TAC JS, `captcha-pages.js`, hidden `validToken`, and `[data-captcha-box]`.
|
||||||
|
- `register.html` and `forgot-password.html` may keep TAC assets and hidden fields, but no PC/H5 scene is configured until backend confirms scene code.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: 认证与资料页面只接 PC auth schema
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- Modify: `public/js/profile-pages.js`
|
||||||
|
- Modify: `public/js/security-pages.js`
|
||||||
|
- Modify: `login.html`
|
||||||
|
- Modify: `register.html`
|
||||||
|
- Modify: `forgot-password.html`
|
||||||
|
- Modify: `profile.html`
|
||||||
|
- Modify: `profile-data.html`
|
||||||
|
- Modify: `profile-security.html`
|
||||||
|
- Test: `tests/auth-pages.test.js`
|
||||||
|
- Test: `tests/profile-pages.test.js`
|
||||||
|
- Test: `tests/security-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `GenealogyApi.defaultClient`
|
||||||
|
- Produces request bodies:
|
||||||
|
- `PasswordLoginBody`: `grantType/tenantId/phone/password/validToken`
|
||||||
|
- `PasswordRegisterBody`: `grantType/tenantId/phone/password/nickName/registerSource/validToken`
|
||||||
|
- `PasswordResetBody`: `tenantId/phone/smsCode/newPassword/validToken`
|
||||||
|
- `ProfileUpdateBody`: `nickName/avatarOssId/sex/birthday/provinceCode/cityCode/districtCode`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update body-builder tests**
|
||||||
|
|
||||||
|
`tests/auth-pages.test.js` must assert `registerSource: 'PC'` for register body and no `APP_*` scene in any body.
|
||||||
|
|
||||||
|
`tests/profile-pages.test.js` must assert profile update uses `provinceCode/cityCode/districtCode`, not `regionCode/addressDetail`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run focused tests**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-pages.test.js
|
||||||
|
node tests\profile-pages.test.js
|
||||||
|
node tests\security-pages.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected before implementation: FAIL where old scene/body fields remain.
|
||||||
|
Expected after implementation: PASS.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement auth body builders**
|
||||||
|
|
||||||
|
Use PC YAML schema fields only. For register:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function buildRegisterBody(values, config) {
|
||||||
|
var body = {
|
||||||
|
grantType: 'password',
|
||||||
|
tenantId: config.tenantId,
|
||||||
|
phone: values.phone,
|
||||||
|
password: values.password,
|
||||||
|
registerSource: 'PC'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (values.nickName) body.nickName = values.nickName;
|
||||||
|
if (values.validToken) body.validToken = values.validToken;
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Implement profile body builder**
|
||||||
|
|
||||||
|
Use schema fields:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function buildProfileUpdateBody(values) {
|
||||||
|
return removeEmpty({
|
||||||
|
nickName: values.nickName,
|
||||||
|
avatarOssId: toNumberOrUndefined(values.avatarOssId),
|
||||||
|
sex: values.sex,
|
||||||
|
birthday: values.birthday,
|
||||||
|
provinceCode: values.provinceCode,
|
||||||
|
cityCode: values.cityCode,
|
||||||
|
districtCode: values.districtCode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify page script order**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Select-String -Path login.html,register.html,forgot-password.html,profile.html,profile-data.html,profile-security.html -Pattern 'config.js|utils/StorageUtil.js|utils/FormUtil.js|utils/RequestUtil.js|public/js/api-client.js'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: every page that uses `GenealogyApi` loads config and utils before `api-client.js`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: 文件上传和文件引用只切 PC files
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/upload-pages.js`
|
||||||
|
- Modify: upload-related page scripts that call `GenealogyApi.defaultClient.uploadFile`
|
||||||
|
- Test: `tests/upload-pages.test.js`
|
||||||
|
- Test: `tests/api-client.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.uploadFile(formData)`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.initResumableUpload(body)`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.uploadChunk(formData)`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.completeResumableUpload(body)`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.bindFileReference(body)`
|
||||||
|
- Consumes: `GenealogyApi.defaultClient.releaseFileReference(query)`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add upload tests**
|
||||||
|
|
||||||
|
`tests/upload-pages.test.js` must verify:
|
||||||
|
- single upload calls `/genealogy/pc/files/upload`
|
||||||
|
- resumable init calls `/genealogy/pc/files/resumable/init`
|
||||||
|
- file reference body requires `bizType/bizTable/bizId/bizField`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run upload tests**
|
||||||
|
|
||||||
|
Run: `node tests\upload-pages.test.js`
|
||||||
|
Expected before implementation: FAIL if old APP file paths remain.
|
||||||
|
Expected after implementation: PASS.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement upload mapping**
|
||||||
|
|
||||||
|
Only map file capability. Do not submit article/feed/album/ceremony/growth/memo business forms unless PC YAML provides their business endpoints.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Verify no APP file path remains**
|
||||||
|
|
||||||
|
Run: `Select-String -Path public\js\api-client.js,public\js\upload-pages.js -Pattern '/genealogy/app/files'`
|
||||||
|
Expected: no matches.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 6: 行政区划接口和资料地区字段
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/region-pages.js`
|
||||||
|
- Modify: `public/js/profile-pages.js`
|
||||||
|
- Test: `tests/region-pages.test.js`
|
||||||
|
- Test: `tests/profile-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `GET /genealogy/region/children`
|
||||||
|
- Consumes: `GET /genealogy/region/path/{regionCode}`
|
||||||
|
- Consumes: `GET /genealogy/region/search`
|
||||||
|
- Consumes: `GET /genealogy/region/{regionCode}`
|
||||||
|
- Produces profile fields: `provinceCode/cityCode/districtCode`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add region tests**
|
||||||
|
|
||||||
|
`tests/region-pages.test.js` must assert:
|
||||||
|
- empty parent loads province list with no required parent code.
|
||||||
|
- search requires `keyword`.
|
||||||
|
- selected province/city/district writes `provinceCode/cityCode/districtCode` to the form.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run region tests**
|
||||||
|
|
||||||
|
Run: `node tests\region-pages.test.js`
|
||||||
|
Expected before implementation: FAIL if form still expects `regionCode/addressDetail`.
|
||||||
|
Expected after implementation: PASS.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement region mapping**
|
||||||
|
|
||||||
|
Use `GenealogyApi.defaultClient.getRegionChildren`, `getRegionPath`, `searchRegions`, `getRegion`. Do not create genealogy submit behavior here.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 7: PC YAML 未覆盖页面降级为接口待确认
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: page scripts that currently call APP-era business methods:
|
||||||
|
- `public/js/genealogy-pages.js`
|
||||||
|
- `public/js/join-apply-pages.js`
|
||||||
|
- `public/js/member-admin-pages.js`
|
||||||
|
- `public/js/article-pages.js`
|
||||||
|
- `public/js/feed-pages.js`
|
||||||
|
- `public/js/album-pages.js`
|
||||||
|
- `public/js/ceremony-pages.js`
|
||||||
|
- `public/js/growth-pages.js`
|
||||||
|
- `public/js/memo-pages.js`
|
||||||
|
- `public/js/generation-pages.js`
|
||||||
|
- `public/js/lineage-pages.js`
|
||||||
|
- `public/js/notification-pages.js`
|
||||||
|
- `public/js/help-pages.js`
|
||||||
|
- `public/js/promotion-pages.js`
|
||||||
|
- `public/js/feedback-pages.js`
|
||||||
|
- `public/js/vip-pages.js`
|
||||||
|
- Test: `tests/unsupported-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `PC_API_NOT_AVAILABLE` errors from `GenealogyApi`
|
||||||
|
- Produces: visible or console-safe page state that says PC interface is not configured, without issuing APP requests.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add unsupported-page smoke test**
|
||||||
|
|
||||||
|
Create `tests/unsupported-pages.test.js` to load each page script in Node with a fake client method that throws `{ code: 'PC_API_NOT_AVAILABLE' }`. Assert each script handles the error without rethrowing from its init function.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run unsupported-page test**
|
||||||
|
|
||||||
|
Run: `node tests\unsupported-pages.test.js`
|
||||||
|
Expected before implementation: FAIL for scripts that assume APP methods are valid.
|
||||||
|
Expected after implementation: PASS.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement shared page fallback**
|
||||||
|
|
||||||
|
In each affected page script, catch `PC_API_NOT_AVAILABLE` and render a small existing-style empty state. Add a Chinese comment: `// PC YAML 未提供该业务接口,页面先展示接口待确认状态。`
|
||||||
|
|
||||||
|
- [ ] **Step 4: Verify no APP business path is emitted from API client**
|
||||||
|
|
||||||
|
Run: `Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'`
|
||||||
|
Expected: no network path matches.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 8: 追踪表和执行记录
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Task 1-7 verification results.
|
||||||
|
- Produces: updated status rows with exact timestamps, changed files, interface paths and verification commands.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Mark task start before edits**
|
||||||
|
|
||||||
|
Before executing each PC task, update the row status from `待开始` to `进行中` with exact time from:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Get-Date -Format "yyyy-MM-dd HH:mm:ss zzz"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Mark task completion after verification**
|
||||||
|
|
||||||
|
After the task's verification commands pass, update status to `已完成` and record:
|
||||||
|
- completion time
|
||||||
|
- modified files
|
||||||
|
- interface paths
|
||||||
|
- verification commands
|
||||||
|
- verification result
|
||||||
|
|
||||||
|
- [ ] **Step 3: Keep missing interfaces in coverage matrix**
|
||||||
|
|
||||||
|
Any page whose main business path is absent from `genealogy-pc-openapi.yaml` remains in `PC YAML 未覆盖` or `接口待确认` and must not be promoted to full integration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Gate
|
||||||
|
|
||||||
|
Run these before marking the replan execution complete:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\config.test.js
|
||||||
|
node tests\utils.test.js
|
||||||
|
node tests\api-client.test.js
|
||||||
|
node tests\auth-pages.test.js
|
||||||
|
node tests\captcha-pages.test.js
|
||||||
|
node tests\profile-pages.test.js
|
||||||
|
node tests\security-pages.test.js
|
||||||
|
node tests\upload-pages.test.js
|
||||||
|
node tests\region-pages.test.js
|
||||||
|
node tests\unsupported-pages.test.js
|
||||||
|
Get-ChildItem -Path public\js -Filter *.js | Where-Object { $_.Name -notin @('jquery360.js','jquery.min.js') } | Sort-Object Name | ForEach-Object { node --check $_.FullName }
|
||||||
|
Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'
|
||||||
|
Select-String -Path public\js\auth-pages.js,public\js\captcha-pages.js,tests\auth-pages.test.js,tests\captcha-pages.test.js -Pattern 'PC_LOGIN|PC_REGISTER|PC_PASSWORD_RESET|APP_LOGIN|APP_REGISTER|APP_FORGOT_PASSWORD'
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- All listed Node tests pass.
|
||||||
|
- Business JS syntax check passes.
|
||||||
|
- `api-client.js` contains no `/genealogy/app/` network path.
|
||||||
|
- Auth and captcha code/tests contain no stale APP/old PC scene defaults.
|
||||||
|
- `git diff --check` passes, or if this directory is not a Git repository, record the exact output.
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
|
||||||
|
- Spec coverage: this plan covers latest PC YAML `paths`, test domain, config.js, utils/public-js separation, CSS/no style injection, Chinese comments, TAC login scene, profile schema mismatch, and PC-missing business interfaces.
|
||||||
|
- Placeholder scan: no implementation task asks the worker to invent missing PC endpoints or use APP paths as compatibility.
|
||||||
|
- Type consistency: `GenealogyConfig`, `StorageUtil`, `FormUtil`, `RequestUtil`, `GenealogyApi.createClient`, `AuthPages.getCaptchaScene`, and `CaptchaPages.ensureToken` names are consistent across tasks.
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
# PC Auth Three Pages Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 按 `genealogy-pc-openapi.yaml` 和 Apifox 截图,把登录、注册、忘记密码三页与 PC 认证接口、验证中心接口对齐。
|
||||||
|
|
||||||
|
**Architecture:** 根目录 `config.js` 继续作为环境、`clientid`、`tenantId` 的唯一配置入口;`utils` 继续存放跨页面公共工具;页面业务逻辑集中在 `public/js/auth-pages.js`,接口调用集中在 `public/js/api-client.js`,验证码适配集中在 `public/js/captcha-pages.js`。页面差异样式只写入对应 CSS 文件。
|
||||||
|
|
||||||
|
**Tech Stack:** 原生 HTML/CSS/JavaScript、`public/tac` 滑动验证、Node 断言测试。
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- 接口依据只使用 `genealogy-pc-openapi.yaml` 与用户补充的 Apifox 截图,不再使用 `APP.openapi.json`。
|
||||||
|
- 开发环境接口地址为 `https://test-genealogy-api.ddxcjp.cn`。
|
||||||
|
- PC `clientid` 为 `ced7e5f0498645c6ec642dcf450b036f`,租户 ID 为 `000000`。
|
||||||
|
- 登录验证码场景为 `WEB_H5_LOGIN`,注册验证码场景为 `WEB_H5_REGISTER`,忘记密码验证码场景为 `WEB_H5_FORGOT_PASSWORD`。
|
||||||
|
- 不在 JS 中注入样式;页面差异样式写入对应 CSS 文件,公共样式写入 `public/css/public.css`。
|
||||||
|
- 新增或修改的 HTML、CSS、JS 注释使用中文,代码保持可读,不压缩。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: 记录专项计划
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
|
- Create: `docs/superpowers/plans/2026-07-09-pc-auth-three-pages.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: 用户确认“可以”先做登录、注册、忘记密码三页。
|
||||||
|
- Produces: PC-009 专项计划记录。
|
||||||
|
|
||||||
|
- [x] **Step 1: 写入本计划**
|
||||||
|
|
||||||
|
创建本计划,明确页面、接口、验证码场景、样式和验证约束。
|
||||||
|
|
||||||
|
- [x] **Step 2: 写入追踪记录**
|
||||||
|
|
||||||
|
在追踪文档中新增 `PC-009`,状态为“进行中”,开始时间为 `2026-07-09 16:32:17 +08:00`。
|
||||||
|
|
||||||
|
### Task 2: 登录页补齐短信登录
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `login.html`
|
||||||
|
- Modify: `public/css/login.css`
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- Modify: `tests/auth-pages.test.js`
|
||||||
|
- Modify: `tests/api-client.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `ApiClient.login(body)`、`ApiClient.loginBySms(body)`、`ApiClient.sendSmsCode(body)`、`CaptchaPages.ensureToken(form, options)`。
|
||||||
|
- Produces: 登录页同时支持密码登录和短信登录。
|
||||||
|
|
||||||
|
- [x] **Step 1: 页面增加登录方式切换**
|
||||||
|
|
||||||
|
在 `login.html` 的登录表单内增加模式切换按钮,密码登录区域保留 `phone/password/validToken`,短信登录区域增加 `phone/smsCode/validToken` 和发送验证码按钮。
|
||||||
|
|
||||||
|
- [x] **Step 2: CSS 写入登录页专属样式**
|
||||||
|
|
||||||
|
在 `public/css/login.css` 增加模式切换、隐藏区域、验证码行样式,不在 JS 中写样式。
|
||||||
|
|
||||||
|
- [x] **Step 3: JS 支持短信登录提交**
|
||||||
|
|
||||||
|
在 `public/js/auth-pages.js` 增加 `buildSmsLoginBody(values)`,提交时按当前模式调用 `/genealogy/pc/auth/login` 或 `/genealogy/pc/auth/login/sms`。
|
||||||
|
|
||||||
|
- [x] **Step 4: 发送短信复用场景码**
|
||||||
|
|
||||||
|
登录页短信验证码按钮使用 `data-scene-code="WEB_H5_LOGIN"`,忘记密码页继续使用 `WEB_H5_FORGOT_PASSWORD`。
|
||||||
|
|
||||||
|
- [x] **Step 5: 更新测试**
|
||||||
|
|
||||||
|
`tests/auth-pages.test.js` 增加短信登录 body 断言;`tests/api-client.test.js` 增加 `loginBySms` 和 `sendSmsCode` 路径/入参断言。
|
||||||
|
|
||||||
|
### Task 3: 注册和忘记密码复核
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Verify: `register.html`
|
||||||
|
- Verify: `forgot-password.html`
|
||||||
|
- Verify: `public/js/auth-pages.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `/genealogy/pc/auth/register`、`/genealogy/pc/auth/sms/code`、`/genealogy/pc/auth/password/reset`。
|
||||||
|
- Produces: 注册和忘记密码页面确认继续按 PC 字段提交。
|
||||||
|
|
||||||
|
- [x] **Step 1: 注册页字段复核**
|
||||||
|
|
||||||
|
确认注册页只提交 `phone/password/nickName/validToken`,`grantType/tenantId/clientId/registerSource` 由 `api-client.js` 统一补齐。
|
||||||
|
|
||||||
|
- [x] **Step 2: 忘记密码页字段复核**
|
||||||
|
|
||||||
|
确认忘记密码页提交 `tenantId/phone/smsCode/newPassword/validToken`,不再出现邮箱找回文案。
|
||||||
|
|
||||||
|
### Task 4: 专项验证和完成记录
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Task 2 和 Task 3 的实现结果。
|
||||||
|
- Produces: PC-009 完成记录和验证结果。
|
||||||
|
|
||||||
|
- [x] **Step 1: 运行测试**
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests\auth-pages.test.js
|
||||||
|
node tests\api-client.test.js
|
||||||
|
node tests\captcha-pages.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
期望全部输出 `passed`。
|
||||||
|
|
||||||
|
- [x] **Step 2: 运行语法检查**
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node --check public\js\auth-pages.js
|
||||||
|
node --check public\js\api-client.js
|
||||||
|
node --check public\js\captcha-pages.js
|
||||||
|
```
|
||||||
|
|
||||||
|
期望无输出且退出码为 0。
|
||||||
|
|
||||||
|
- [x] **Step 3: 更新追踪文档**
|
||||||
|
|
||||||
|
把 `PC-009` 状态改为“已完成”,写入完成时间、修改文件、接口路径、验证码场景和验证结果。
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# TAC Captcha Auth Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 将 `public/tac` 滑动验证接入登录、注册、忘记密码三个认证页面,并按 `APP.openapi.json` 的验证中心接口换取 `validToken` 后再提交业务接口。
|
||||||
|
|
||||||
|
**Architecture:** 新增 `public/js/captcha-pages.js` 作为 TAC 与验证中心接口之间的适配层;`auth-pages.js` 在提交登录、注册、发送短信、重置密码前调用验证码适配层。API 基础地址、clientId、tenantId 继续由 `api-client.js` 统一提供。
|
||||||
|
|
||||||
|
**Tech Stack:** 静态 HTML、原生 JS、现有 `public/tac/js/tac.min.js`、现有 `public/tac/css/tac.css`、Node 单元测试。
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- 严格依据 `APP.openapi.json` 的 `/captcha/require`、`/captcha/challenge`、`/captcha/verify` 字段接入。
|
||||||
|
- 业务 JS 不压缩,新增注释使用中文。
|
||||||
|
- 自有样式写入 CSS 文件,不通过自有 JS 注入样式。
|
||||||
|
- 第三方 `tac.min.js` 保持原样,不重写其内部样式和 DOM 生成逻辑。
|
||||||
|
- 登录、注册、忘记密码三页都必须有隐藏 `validToken` 字段和验证码挂载容器。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: API Client Captcha Helpers
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/api-client.js`
|
||||||
|
- Modify: `tests/api-client.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `client.buildApiUrl(path, query)`
|
||||||
|
- Produces: `client.captchaRequirement({ sceneCode, subject })`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write failing tests** for captcha requirement URL, query, and public URL building.
|
||||||
|
- [ ] **Step 2: Run tests** and confirm missing methods fail.
|
||||||
|
- [ ] **Step 3: Implement minimal API client helpers**.
|
||||||
|
- [ ] **Step 4: Run tests** and confirm pass.
|
||||||
|
|
||||||
|
### Task 2: TAC Adapter Module
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `public/js/captcha-pages.js`
|
||||||
|
- Create: `tests/captcha-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `CaptchaPages.buildChallengeBody(options, api)`
|
||||||
|
- Produces: `CaptchaPages.adaptChallengeResponse(response)`
|
||||||
|
- Produces: `CaptchaPages.buildVerifyBody(requestData, context, api)`
|
||||||
|
- Produces: `CaptchaPages.extractValidToken(response)`
|
||||||
|
- Produces: `CaptchaPages.ensureToken(form, options)`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write failing tests** for OpenAPI-to-TAC mapping and validToken extraction.
|
||||||
|
- [ ] **Step 2: Run tests** and confirm module missing fails.
|
||||||
|
- [ ] **Step 3: Implement adapter with Chinese comments**.
|
||||||
|
- [ ] **Step 4: Run tests** and confirm pass.
|
||||||
|
|
||||||
|
### Task 3: Auth Flow Integration
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/auth-pages.js`
|
||||||
|
- Modify: `tests/auth-pages.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `CaptchaPages.ensureToken(form, { sceneCode, subject })`
|
||||||
|
- Updates: login/register/password reset/send code flows wait for captcha before API submission.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write failing tests** for login body validToken and scene code mapping.
|
||||||
|
- [ ] **Step 2: Run tests** and confirm expected failure.
|
||||||
|
- [ ] **Step 3: Integrate captcha gate before submit/send code**.
|
||||||
|
- [ ] **Step 4: Run tests** and confirm pass.
|
||||||
|
|
||||||
|
### Task 4: HTML/CSS Wiring
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `login.html`
|
||||||
|
- Modify: `register.html`
|
||||||
|
- Modify: `forgot-password.html`
|
||||||
|
- Modify: `public/css/public.css`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Adds: `<link rel="stylesheet" href="public/tac/css/tac.css" />`
|
||||||
|
- Adds: hidden `validToken`
|
||||||
|
- Adds: `data-captcha-box`
|
||||||
|
- Adds: `public/tac/js/tac.min.js` and `public/js/captcha-pages.js`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add page hooks** with Chinese HTML comments where helpful.
|
||||||
|
- [ ] **Step 2: Add CSS-only layout for captcha container**.
|
||||||
|
- [ ] **Step 3: Run static checks** for scripts, hooks, no self JS style injection.
|
||||||
|
|
||||||
|
### Task 5: Verification And Records
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/api-page-integration-2026-07-09.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Run all Node tests**.
|
||||||
|
- [ ] **Step 2: Run `node --check` for all business JS**.
|
||||||
|
- [ ] **Step 3: Run static checks for HTML hooks and style-injection patterns**.
|
||||||
|
- [ ] **Step 4: Append dated progress record**.
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>下载应用 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/download.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-download" data-promotion-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a><a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a class="active" href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero download-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Download</div>
|
||||||
|
<h1>下载代代相传 APP</h1>
|
||||||
|
<p class="lead">
|
||||||
|
手机端适合日常上传宣传相册、发布宣传视频、查看家谱和补充资料。
|
||||||
|
</p>
|
||||||
|
<div class="detail-actions">
|
||||||
|
<a class="btn primary magnetic" href="app.html">查看应用介绍</a
|
||||||
|
><a class="btn ghost magnetic" href="help.html">安装帮助</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card qr-card tilt-card">
|
||||||
|
<div class="qr-box"><span>扫码</span></div>
|
||||||
|
<h3>手机扫码下载</h3>
|
||||||
|
<p>支持 iOS 与 Android,实际项目可替换为真实下载二维码。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>下载方式</h2>
|
||||||
|
<p>前台先展示下载入口,后续可以接真实应用商店地址。</p>
|
||||||
|
</div>
|
||||||
|
<!-- 下载入口区域:内容来自 /genealogy/app/promotions 列表接口。 -->
|
||||||
|
<div class="grid-3" data-promotion-download-list>
|
||||||
|
<div class="api-empty">下载推广内容加载中</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a href="article-detail.html">家谱知识</a
|
||||||
|
><a href="notice-detail.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/promotion-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>四川武胜汤氏族 - 家谱详情 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/family-detail.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-family-detail">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a class="active" href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a>
|
||||||
|
<a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main data-family-detail>
|
||||||
|
<section class="inner-hero detail-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Family Detail</div>
|
||||||
|
<h1 data-family-text="title">四川武胜汤氏族</h1>
|
||||||
|
<p class="lead" data-family-text="intro|description|summary" data-fallback="公开展示家族源流、世系概览、字辈排行、谱文资料和宣传相册,让访客快速理解这一本家谱的内容结构。">
|
||||||
|
公开展示家族源流、世系概览、字辈排行、谱文资料和宣传相册,让访客快速理解这一本家谱的内容结构。
|
||||||
|
</p>
|
||||||
|
<div class="detail-actions">
|
||||||
|
<a class="btn primary magnetic" href="join-genealogy.html" data-family-join-link
|
||||||
|
>申请加入</a
|
||||||
|
>
|
||||||
|
<a class="btn ghost magnetic" href="plaza.html">返回广场</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card family-summary tilt-card">
|
||||||
|
<span class="summary-badge">公开家谱</span>
|
||||||
|
<h3 data-family-text="title">汤氏族谱</h3>
|
||||||
|
<div class="summary-grid" data-family-summary>
|
||||||
|
<span><b>128</b>成员</span>
|
||||||
|
<span><b>6</b>世代</span>
|
||||||
|
<span><b>18</b>谱文</span>
|
||||||
|
<span><b>7</b>相册</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container detail-layout">
|
||||||
|
<aside class="detail-panel tilt-card">
|
||||||
|
<h3>家谱信息</h3>
|
||||||
|
<p><b>主要姓氏:</b><span data-family-text="surname" data-fallback="汤">汤</span></p>
|
||||||
|
<p><b>地区:</b><span data-family-text="addressDetail|regionName|originPlace" data-fallback="四川武胜">四川武胜</span></p>
|
||||||
|
<p><b>堂号:</b><span data-family-text="ancestralHall" data-fallback="中山堂">中山堂</span></p>
|
||||||
|
<p><b>维护方式:</b><span data-family-text="joinModeName|joinMode" data-fallback="多人共修">多人共修</span></p>
|
||||||
|
</aside>
|
||||||
|
<div class="detail-main">
|
||||||
|
<article class="content-card tilt-card">
|
||||||
|
<h2>家族简介</h2>
|
||||||
|
<p data-family-text="intro|description|summary" data-fallback="本谱以四川武胜汤氏族人为主体,整理始祖源流、迁徙线索、字辈排行、重要人物与家风故事。公开内容用于展示家族文化,完整成员资料需申请加入后查看。">
|
||||||
|
本谱以四川武胜汤氏族人为主体,整理始祖源流、迁徙线索、字辈排行、重要人物与家风故事。公开内容用于展示家族文化,完整成员资料需申请加入后查看。
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
<div class="grid-3">
|
||||||
|
<div class="mini-card tilt-card">
|
||||||
|
<h3>世系概览</h3>
|
||||||
|
<p>按代际关系梳理成员结构,帮助族人找到自己的位置。</p>
|
||||||
|
</div>
|
||||||
|
<div class="mini-card tilt-card">
|
||||||
|
<h3>谱文资料</h3>
|
||||||
|
<p>收录谱序、家训、修谱说明和公开纪念文章。</p>
|
||||||
|
</div>
|
||||||
|
<div class="mini-card tilt-card">
|
||||||
|
<h3>宣传相册</h3>
|
||||||
|
<p>展示祠堂祖屋、修谱活动、老照片和家族纪念内容。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a href="article-detail.html">家谱知识</a
|
||||||
|
><a href="about.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>找回密码 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/tac/css/tac.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/forgot-password.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-forgot-password">
|
||||||
|
<main class="auth-layout auth-scenic-layout recover-layout">
|
||||||
|
<a class="brand auth-page-brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="card form-card auth-card recover-card"
|
||||||
|
aria-labelledby="recover-title"
|
||||||
|
>
|
||||||
|
<div class="eyebrow">Password Recovery</div>
|
||||||
|
<h1 id="recover-title">找回密码</h1>
|
||||||
|
<p class="lead">输入注册手机号,获取验证码后重设登录密码。</p>
|
||||||
|
<form class="form-grid" data-auth-form="password-reset" data-captcha-scene="WEB_H5_FORGOT_PASSWORD" data-success-url="login.html">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="phone"
|
||||||
|
type="tel"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="tel"
|
||||||
|
maxlength="11"
|
||||||
|
placeholder="手机号"
|
||||||
|
/>
|
||||||
|
<div class="code-row">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="smsCode"
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
placeholder="验证码"
|
||||||
|
/>
|
||||||
|
<button class="btn ghost" type="button" data-api-send-code data-scene-code="WEB_H5_FORGOT_PASSWORD">获取验证码</button>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="newPassword"
|
||||||
|
type="password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
placeholder="新密码"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="confirmPassword"
|
||||||
|
type="password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
placeholder="确认新密码"
|
||||||
|
/>
|
||||||
|
<input type="hidden" name="validToken" />
|
||||||
|
<button class="btn primary" type="submit">重设密码</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<!-- 滑动验证弹窗由 captcha-pages.js 按需挂载到页面级容器,避免挤占表单布局 -->
|
||||||
|
<div class="auth-captcha-modal" data-captcha-box aria-live="polite"></div>
|
||||||
|
<script src="public/js/md5.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="utils/MessageUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/tac/js/tac.min.js"></script>
|
||||||
|
<script src="public/js/captcha-pages.js"></script>
|
||||||
|
<script src="public/js/auth-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>数字家谱 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/genealogy.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-genealogy">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a class="active" href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero genealogy-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Digital Genealogy</div>
|
||||||
|
<h1>把成员关系整理成清晰可查的数字家谱</h1>
|
||||||
|
<p class="lead">
|
||||||
|
从始祖、分支、排行到个人资料,数字家谱帮助家族建立长期可维护的成员档案和世系关系。
|
||||||
|
</p>
|
||||||
|
<div class="genealogy-stats">
|
||||||
|
<div><strong>8</strong><span>资料模块</span></div>
|
||||||
|
<div><strong>3步</strong><span>快速建谱</span></div>
|
||||||
|
<div><strong>多人</strong><span>协作共修</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card tree-preview tilt-card">
|
||||||
|
<div class="tree-glow"></div>
|
||||||
|
<div class="tree-row root"><span>始祖</span></div>
|
||||||
|
<div class="tree-line"></div>
|
||||||
|
<div class="tree-row branch">
|
||||||
|
<span>长房</span><span>二房</span><span>三房</span>
|
||||||
|
</div>
|
||||||
|
<div class="tree-line short"></div>
|
||||||
|
<div class="tree-row generation">
|
||||||
|
<span>第六世</span><span>第七世</span><span>第八世</span
|
||||||
|
><span>第九世</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt capability-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>核心能力</h2>
|
||||||
|
<p>
|
||||||
|
围绕修谱、查谱和协作维护,把家族资料从零散记录整理成完整档案。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-4">
|
||||||
|
<div class="card soft feature-card tilt-card">
|
||||||
|
<div class="icon-word">世</div>
|
||||||
|
<h3>世系图</h3>
|
||||||
|
<p>
|
||||||
|
以树谱方式展示成员关系,支持查看个人资料、添加亲属和调整排行。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft feature-card tilt-card">
|
||||||
|
<div class="icon-word">字</div>
|
||||||
|
<h3>字辈谱</h3>
|
||||||
|
<p>记录各代字辈与人数,让世代脉络更加清楚。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft feature-card tilt-card">
|
||||||
|
<div class="icon-word">文</div>
|
||||||
|
<h3>谱文资料</h3>
|
||||||
|
<p>沉淀谱序、家训、人物传记和修谱说明。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft feature-card tilt-card">
|
||||||
|
<div class="icon-word">权</div>
|
||||||
|
<h3>权限管理</h3>
|
||||||
|
<p>设置管理员、内容可见范围与入谱审核,保护家族隐私。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section coedit-section">
|
||||||
|
<div class="container grid-2">
|
||||||
|
<div class="card dark coedit-card tilt-card">
|
||||||
|
<h2>适合多人共修</h2>
|
||||||
|
<p>
|
||||||
|
家族成员可以分别补充照片、成员资料、谱文和故事,再由管理员统一审核,避免资料越传越散。
|
||||||
|
</p>
|
||||||
|
<a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>开始创建</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="card process-card tilt-card">
|
||||||
|
<h3>修谱流程</h3>
|
||||||
|
<div class="step-list">
|
||||||
|
<p><b>1</b><span>创建家谱并填写姓氏、地区、堂号</span></p>
|
||||||
|
<p><b>2</b><span>录入第一批成员,建立上下辈关系</span></p>
|
||||||
|
<p><b>3</b><span>邀请亲人加入,共同完善资料</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>帮助中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/help.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-help">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a class="active" href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero help-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Help Center</div>
|
||||||
|
<h1>从创建到协作,快速解决常见问题</h1>
|
||||||
|
<p class="lead">
|
||||||
|
覆盖注册登录、创建家谱、邀请成员、资料审核、隐私设置和内容发布等流程。
|
||||||
|
</p>
|
||||||
|
<div class="help-tags">
|
||||||
|
<span>创建家谱</span><span>邀请成员</span><span>隐私权限</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card help-card tilt-card">
|
||||||
|
<div class="help-orb"></div>
|
||||||
|
<div class="help-icon">?</div>
|
||||||
|
<h3>需要人工协助?</h3>
|
||||||
|
<p class="muted">
|
||||||
|
遇到资料导入、权限或账号问题,可以提交说明,客服会协助处理。
|
||||||
|
</p>
|
||||||
|
<a class="btn primary magnetic" href="submit-ticket.html"
|
||||||
|
>提交工单</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt faq-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>常见问题</h2>
|
||||||
|
<p>把复杂流程拆成清楚步骤,便于用户第一次使用时快速上手。</p>
|
||||||
|
</div>
|
||||||
|
<div class="faq-list" data-help-list>
|
||||||
|
<details open class="tilt-card">
|
||||||
|
<summary>如何创建第一本家谱?</summary>
|
||||||
|
<p>
|
||||||
|
进入创建家谱页面,填写家族名称、姓氏、地区和简介,即可生成家谱空间。
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<details class="tilt-card">
|
||||||
|
<summary>如何邀请亲人一起维护?</summary>
|
||||||
|
<p>在家谱管理中生成邀请码,亲人可通过加入家谱页面提交申请。</p>
|
||||||
|
</details>
|
||||||
|
<details class="tilt-card">
|
||||||
|
<summary>公开家谱会展示哪些内容?</summary>
|
||||||
|
<p>仅展示管理员允许公开的家族介绍、动态和部分资料。</p>
|
||||||
|
</details>
|
||||||
|
<details class="tilt-card">
|
||||||
|
<summary>资料填错了怎么办?</summary>
|
||||||
|
<p>管理员可以编辑成员资料、调整世系关系,也可以设置审核流程。</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/help-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,625 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>代代相传家谱_在线修家谱_家谱查询_姓氏寻根_祠堂祭祀</title>
|
||||||
|
<meta
|
||||||
|
name="keywords"
|
||||||
|
content="电子家谱,在线修家谱,家谱制作,家谱查询,中国家谱网,寻根,祠堂,祭祀,祭拜,中华传统文化,生命文化,儒释道,姓氏源流;敬祖睦族,忠孝两全,传承家风;族谱网,族记;清明节家谱,过年修家谱,海外寻根"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="相传相传家谱网,大型生命文化平台,综合儒释道思想,弘扬中华传统文化,提供电子家谱_在线修家谱_网上修家谱,家谱制作_族谱制作_修谱软件,家谱查询_姓氏寻根_寻根问祖_姓氏源流,祠堂祭祀_祭拜_祭奠,弘扬孝敬_忠孝两全_相夫教子_敬祖睦族_慎终追远_传承家风,覆盖清明节家谱_过年修家谱_90后修家谱_海外华人寻根_老家谱电子化,代代相传_薪火相传"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img
|
||||||
|
class="brand-logo"
|
||||||
|
src="public/images/logo.png"
|
||||||
|
alt="我们的家谱,代代相传"
|
||||||
|
/></a>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a class="active" href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a>
|
||||||
|
<a href="register.html">注册</a>
|
||||||
|
<a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="hero">
|
||||||
|
<div class="container hero-inner">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">数字家谱与家族文化门户</div>
|
||||||
|
<h1>
|
||||||
|
一部会生长的<br /><span class="hero-title-mark">数字家谱</span>
|
||||||
|
</h1>
|
||||||
|
<p class="lead">
|
||||||
|
把姓氏源流、世系关系、字辈排行、宣传相册、谱文故事与亲人动态整理在一起,让家族的来处清晰可见,让记忆可以继续传下去。
|
||||||
|
</p>
|
||||||
|
<div class="word-scroll-card">
|
||||||
|
<div class="word-scroll-label">正在记录</div>
|
||||||
|
<div class="word-window">
|
||||||
|
<div class="word-track">
|
||||||
|
<div class="word">寻根问祖</div>
|
||||||
|
<div class="word">字辈排行</div>
|
||||||
|
<div class="word">世系关系</div>
|
||||||
|
<div class="word">宣传相册</div>
|
||||||
|
<div class="word">谱文故事</div>
|
||||||
|
<div class="word">亲人动态</div>
|
||||||
|
<div class="word">寻根问祖</div>
|
||||||
|
<div class="word">字辈排行</div>
|
||||||
|
<div class="word">世系关系</div>
|
||||||
|
<div class="word">宣传相册</div>
|
||||||
|
<div class="word">谱文故事</div>
|
||||||
|
<div class="word">亲人动态</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-path">
|
||||||
|
<span>1</span>创建家谱<i></i><span>2</span>邀请亲人<i></i
|
||||||
|
><span>3</span>共同传承
|
||||||
|
</div>
|
||||||
|
<div class="hero-action-card">
|
||||||
|
<div class="cta">
|
||||||
|
<a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>立即创建家谱</a
|
||||||
|
>
|
||||||
|
<a class="btn ghost magnetic" href="plaza.html">查看家谱示例</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="metrics">
|
||||||
|
<div class="metric"><strong>家谱广场</strong>浏览公开家族</div>
|
||||||
|
<div class="metric"><strong>姓氏百科</strong>了解姓氏源流</div>
|
||||||
|
<div class="metric"><strong>家族文化</strong>阅读传承故事</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-visual">
|
||||||
|
<div class="archive-stage"></div>
|
||||||
|
<div class="book-cover"></div>
|
||||||
|
<div class="hall">
|
||||||
|
<img src="public/images/ancestral-hall.png" alt="家族祠堂" />
|
||||||
|
</div>
|
||||||
|
<a class="video-card" href="promo-video.html">
|
||||||
|
<small>宣传影像</small>
|
||||||
|
<span>观看宣传视频</span>
|
||||||
|
</a>
|
||||||
|
<div class="search-panel">
|
||||||
|
<h3>查找公开家谱</h3>
|
||||||
|
<a class="search-box" href="search-result.html">
|
||||||
|
<span>输入姓氏、地区或家谱名称</span><b>搜索</b>
|
||||||
|
</a>
|
||||||
|
<div class="genealogy-list">
|
||||||
|
<div class="genealogy-item">
|
||||||
|
<strong>四川成都陈氏族</strong>共修入 128 人
|
||||||
|
</div>
|
||||||
|
<div class="genealogy-item">
|
||||||
|
<strong>湖广刘氏家谱</strong>收录 6 代字辈
|
||||||
|
</div>
|
||||||
|
<div class="genealogy-item">
|
||||||
|
<strong>岭南张氏宗谱</strong>开放谱文 18 篇
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="quick-strip">
|
||||||
|
<div class="container quick-inner">
|
||||||
|
<a class="quick-card tilt-card" href="create-genealogy.html">
|
||||||
|
<b>创建家谱</b><span>填写姓氏谱名,建立属于家族的数字空间。</span>
|
||||||
|
</a>
|
||||||
|
<a class="quick-card tilt-card" href="join-genealogy.html">
|
||||||
|
<b>加入家谱</b><span>通过邀请码加入亲人创建的家谱。</span>
|
||||||
|
</a>
|
||||||
|
<a class="quick-card tilt-card" href="plaza.html">
|
||||||
|
<b>浏览广场</b><span>查看公开家谱示例与家族故事。</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="quick-card tilt-card"
|
||||||
|
id="promo-video"
|
||||||
|
href="promo-video.html"
|
||||||
|
><b>宣传视频</b
|
||||||
|
><span>进入视频列表,查看宣传影像和纪念视频。</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="functions">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>数字家谱核心功能</h2>
|
||||||
|
</div>
|
||||||
|
<div class="function-grid">
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">世</div>
|
||||||
|
<h3>世系图</h3>
|
||||||
|
<p>
|
||||||
|
以树谱方式展示成员关系,支持查看个人资料、添加亲属、调整排行。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">字</div>
|
||||||
|
<h3>字辈谱</h3>
|
||||||
|
<p>记录各代字辈与人数,让家族世代脉络更加清楚。</p>
|
||||||
|
</div>
|
||||||
|
<a class="function-card tilt-card" href="promo-album.html">
|
||||||
|
<div class="icon">相</div>
|
||||||
|
<h3>宣传相册</h3>
|
||||||
|
<p>按相册归档宣传影像,展示祖屋、活动、老照片和重要时刻。</p>
|
||||||
|
</a>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">文</div>
|
||||||
|
<h3>谱文资料</h3>
|
||||||
|
<p>沉淀谱序、谱文、家训、恩荣录等文本内容。</p>
|
||||||
|
</div>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">圈</div>
|
||||||
|
<h3>家族圈</h3>
|
||||||
|
<p>发布动态、分享图片、评论互动,让亲人之间保持连接。</p>
|
||||||
|
</div>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">功</div>
|
||||||
|
<h3>功德录</h3>
|
||||||
|
<p>记录家族贡献人物与事迹,让善行与纪念被看见。</p>
|
||||||
|
</div>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">礼</div>
|
||||||
|
<h3>贺礼邀请</h3>
|
||||||
|
<p>发布婚礼、生日、升学等家族喜事,通知相关成员。</p>
|
||||||
|
</div>
|
||||||
|
<div class="function-card tilt-card">
|
||||||
|
<div class="icon">权</div>
|
||||||
|
<h3>权限管理</h3>
|
||||||
|
<p>设置管理员、内容可见范围与入谱审核,保护家族隐私。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="plaza">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>家谱广场</h2>
|
||||||
|
</div>
|
||||||
|
<div class="plaza-layout">
|
||||||
|
<a class="featured-family tilt-card" href="family-detail.html">
|
||||||
|
<h3>四川成都陈氏族</h3>
|
||||||
|
<p>
|
||||||
|
已收录成员 128 人,整理字辈 6 代,公开谱文 18 篇,宣传相册 7
|
||||||
|
组。家族资料由成员共同维护,持续更新。
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
<div class="family-cards">
|
||||||
|
<a class="family-card tilt-card" href="family-detail.html">
|
||||||
|
<h4>湖广刘氏家谱</h4>
|
||||||
|
<p>从始祖世系到现代家庭分支,保留字辈与迁徙记录。</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">公开家谱</span
|
||||||
|
><span class="tag">字辈完整</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="family-card tilt-card" href="family-detail.html">
|
||||||
|
<h4>岭南张氏宗谱</h4>
|
||||||
|
<p>以谱文、相册、家族动态为主,记录家风与重要纪念。</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">家族文化</span
|
||||||
|
><span class="tag">宣传相册</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="family-card tilt-card" href="family-detail.html">
|
||||||
|
<h4>川东李氏家谱</h4>
|
||||||
|
<p>多人共同完善成员资料,形成清晰的家族成员档案。</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">多人共修</span
|
||||||
|
><span class="tag">成员资料</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="culture">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>家族文化</h2>
|
||||||
|
</div>
|
||||||
|
<div class="article-grid">
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>为什么家谱不只是一本名册</h3>
|
||||||
|
<p>
|
||||||
|
家谱记录的是家族关系,也记录一个家庭如何理解自己的来处与传承。
|
||||||
|
</p>
|
||||||
|
<div class="article-meta">家谱知识 · 2026.05</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>字辈在家族传承中的作用</h3>
|
||||||
|
<p>字辈让不同世代的人能找到自己的位置,也让同族称谓更清晰。</p>
|
||||||
|
<div class="article-meta">姓氏文化 · 2026.05</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="article-card tilt-card" href="article-detail.html">
|
||||||
|
<div class="article-cover"></div>
|
||||||
|
<div class="article-body">
|
||||||
|
<h3>如何邀请亲人共同完善家谱</h3>
|
||||||
|
<p>从创建家谱、生成邀请码到设置管理员,逐步建立协作流程。</p>
|
||||||
|
<div class="article-meta">使用指南 · 2026.05</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="ad-slots">
|
||||||
|
<div class="container">
|
||||||
|
<div class="ad-grid">
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://3dyjs.cn/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="3D研究室广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/mlogo.png" alt="3D研究室" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/family-album"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="影像相册广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-album-small.png" alt="影像相册" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/family-video"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="活动视频广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-video-small.png" alt="活动视频" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/genealogy-print"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="族谱印制广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-print.png" alt="族谱印制" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/ancestral-hall"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="祠堂文化广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-hall.png" alt="祠堂文化" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/cloud-archive"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="云端存档广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-cloud.png" alt="云端存档" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/clan-reunion"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="宗亲联谊广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-reunion.png" alt="宗亲联谊" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/surname-research"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="姓氏研究广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-research.png" alt="姓氏研究" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/family-memory"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="家风记忆广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-memory.png" alt="家风记忆" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="ad-card tilt-card"
|
||||||
|
href="https://example.com/data-check"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="资料校对广告"
|
||||||
|
>
|
||||||
|
<img src="public/images/ad-data.png" alt="资料校对" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="surname">
|
||||||
|
<div class="container">
|
||||||
|
<div class="surname-panel tilt-card">
|
||||||
|
<div class="surname-intro">
|
||||||
|
<h2>姓氏百科</h2>
|
||||||
|
<p>
|
||||||
|
以姓氏为入口,整理姓氏源流、名人故事、地区分布、字辈参考和相关家谱。
|
||||||
|
</p>
|
||||||
|
<a class="btn primary magnetic" href="surname.html"
|
||||||
|
>进入姓氏百科</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="surname-grid">
|
||||||
|
<a class="surname-name" href="surname-detail.html">赵</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">钱</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">孙</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">李</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">周</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">吴</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">郑</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">王</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">冯</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">陈</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">褚</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">卫</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">蒋</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">沈</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">韩</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">杨</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">朱</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">秦</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">尤</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">许</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">何</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">吕</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">施</a>
|
||||||
|
<a class="surname-name" href="surname-detail.html">张</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="recommend">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>相关推荐</h2>
|
||||||
|
</div>
|
||||||
|
<div class="recommend-grid">
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/archive-guide"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>资料整理</span>
|
||||||
|
<h3>家庭档案整理指南</h3>
|
||||||
|
<p>参考照片、证件、谱牒、口述资料的归档方式。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/surname-origin"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>姓氏源流</span>
|
||||||
|
<h3>姓氏文化资料库</h3>
|
||||||
|
<p>查看姓氏源流、迁徙脉络、堂号和郡望参考资料。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/clan-culture"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>宗亲文化</span>
|
||||||
|
<h3>宗亲会活动参考</h3>
|
||||||
|
<p>了解宗亲联谊、祭祖活动和家风传播的组织方式。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/genealogy-tools"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>工具服务</span>
|
||||||
|
<h3>修谱工具与服务</h3>
|
||||||
|
<p>查找谱书排版、影像扫描、云端存储等外部服务。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/local-history"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>地方志</span>
|
||||||
|
<h3>地方文献检索入口</h3>
|
||||||
|
<p>从地方志、县志和族群资料中寻找家族线索。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/name-study"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>人名研究</span>
|
||||||
|
<h3>字辈与命名参考</h3>
|
||||||
|
<p>参考传统字辈、排行、称谓和家族命名资料。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/photo-restore"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>影像修复</span>
|
||||||
|
<h3>老照片修复服务</h3>
|
||||||
|
<p>了解老照片扫描、修复、上色和数字归档服务。</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="recommend-card tilt-card"
|
||||||
|
href="https://example.com/oral-history"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
<span>口述史</span>
|
||||||
|
<h3>家族故事采集方法</h3>
|
||||||
|
<p>参考长辈访谈、口述记录和家风故事整理方式。</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="friend-links">
|
||||||
|
<div class="container">
|
||||||
|
<div class="friend-links-panel">
|
||||||
|
<h2>友情链接</h2>
|
||||||
|
<div class="friend-link-list">
|
||||||
|
<a href="https://3d.3dyjs.cn/" target="_blank" rel="noopener"
|
||||||
|
>3D研究室</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com/surnames"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>姓氏源流资料</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com/genealogy"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>公开家谱资料</a
|
||||||
|
>
|
||||||
|
<a href="https://example.com/wiki" target="_blank" rel="noopener"
|
||||||
|
>修谱知识库</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com/history"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>地方文献</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com/archive"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>档案服务</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com/printing"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>谱书印制</a
|
||||||
|
>
|
||||||
|
<a href="https://example.com/photo" target="_blank" rel="noopener"
|
||||||
|
>老照片修复</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="download">
|
||||||
|
<div class="container">
|
||||||
|
<div class="download-panel tilt-card">
|
||||||
|
<div>
|
||||||
|
<h2>手机端随时记录,电脑端清晰浏览</h2>
|
||||||
|
<p>
|
||||||
|
家族成员可以在手机端上传照片、查看家谱、发布动态;PC
|
||||||
|
端适合浏览门户内容、查看公开家谱和进入家谱空间。
|
||||||
|
</p>
|
||||||
|
<div class="cta">
|
||||||
|
<a class="btn primary magnetic" href="download.html">下载应用</a
|
||||||
|
><a class="btn ghost magnetic" href="help.html">查看帮助</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="qr-wrap">
|
||||||
|
<div class="qr">
|
||||||
|
<div class="qr-box"></div>
|
||||||
|
<strong>小程序</strong>
|
||||||
|
<p class="qr-note">扫码体验</p>
|
||||||
|
</div>
|
||||||
|
<div class="qr">
|
||||||
|
<div class="qr-box"></div>
|
||||||
|
<strong>APP 下载</strong>
|
||||||
|
<p class="qr-note">手机查看</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img
|
||||||
|
class="brand-logo"
|
||||||
|
src="public/images/logo-light.png"
|
||||||
|
alt="我们的家谱,代代相传"
|
||||||
|
/></a>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a
|
||||||
|
><a href="notice-detail.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener"
|
||||||
|
>ICP备案:蜀ICP备2024044594号-1</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>加入家谱 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/join-genealogy.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-join-genealogy">
|
||||||
|
<main class="auth-layout">
|
||||||
|
<a class="brand auth-page-brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="card form-card auth-card join-card"
|
||||||
|
aria-labelledby="join-title"
|
||||||
|
>
|
||||||
|
<div class="eyebrow">Join Family</div>
|
||||||
|
<h1 id="join-title">加入家谱</h1>
|
||||||
|
<p class="lead">输入亲人分享的家谱ID或从详情页带入的链接,提交后等待管理员审核。</p>
|
||||||
|
<form class="form-grid" data-genealogy-form="join" data-success-url="profile-join-family.html">
|
||||||
|
<div class="invite-box">
|
||||||
|
<input class="input" name="genealogyId" inputmode="numeric" placeholder="请输入家谱ID或邀请码" />
|
||||||
|
</div>
|
||||||
|
<input class="input" name="applicantName" autocomplete="name" placeholder="你的姓名" />
|
||||||
|
<input class="input" name="phone" autocomplete="tel" placeholder="手机号" />
|
||||||
|
<input class="input" name="relationDesc" placeholder="与家族关系说明" />
|
||||||
|
<textarea class="input" name="applyReason" rows="4" placeholder="申请说明(选填)"></textarea>
|
||||||
|
<button class="btn primary" type="submit">提交申请</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>登录 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/tac/css/tac.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/login.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-login">
|
||||||
|
<main class="auth-layout auth-scenic-layout">
|
||||||
|
<a class="brand auth-page-brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<section class="card form-card auth-card" aria-labelledby="login-title">
|
||||||
|
<div class="eyebrow">Welcome Back</div>
|
||||||
|
<h1 id="login-title">登录账号</h1>
|
||||||
|
<p class="lead">登录后可创建、加入和维护家谱。</p>
|
||||||
|
<div class="login-mode-tabs" role="tablist" aria-label="登录方式">
|
||||||
|
<button class="login-mode-tab is-active" type="button" role="tab" aria-selected="true" data-login-mode-tab="password">
|
||||||
|
密码登录
|
||||||
|
</button>
|
||||||
|
<button class="login-mode-tab" type="button" role="tab" aria-selected="false" data-login-mode-tab="sms">
|
||||||
|
短信登录
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
class="form-grid login-mode-panel"
|
||||||
|
data-auth-form="login"
|
||||||
|
data-login-mode-panel="password"
|
||||||
|
data-captcha-scene="WEB_H5_LOGIN"
|
||||||
|
data-success-url="profile.html"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="phone"
|
||||||
|
type="tel"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="tel"
|
||||||
|
maxlength="11"
|
||||||
|
placeholder="手机号"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
autocomplete="current-password"
|
||||||
|
placeholder="密码"
|
||||||
|
/>
|
||||||
|
<input type="hidden" name="validToken" />
|
||||||
|
<button class="btn primary" type="submit">登录</button>
|
||||||
|
</form>
|
||||||
|
<form
|
||||||
|
class="form-grid login-mode-panel"
|
||||||
|
data-auth-form="sms-login"
|
||||||
|
data-login-mode-panel="sms"
|
||||||
|
data-captcha-scene="WEB_H5_LOGIN"
|
||||||
|
data-success-url="profile.html"
|
||||||
|
hidden
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="phone"
|
||||||
|
type="tel"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="tel"
|
||||||
|
maxlength="11"
|
||||||
|
placeholder="手机号"
|
||||||
|
/>
|
||||||
|
<div class="code-row">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
name="smsCode"
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
placeholder="短信验证码"
|
||||||
|
/>
|
||||||
|
<button class="btn ghost" type="button" data-api-send-code data-scene-code="WEB_H5_LOGIN">
|
||||||
|
获取验证码
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="validToken" />
|
||||||
|
<button class="btn primary" type="submit">短信登录</button>
|
||||||
|
</form>
|
||||||
|
<div class="auth-links">
|
||||||
|
<a href="register.html">注册新账号</a>
|
||||||
|
<a href="forgot-password.html">忘记密码</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<!-- 滑动验证弹窗由 captcha-pages.js 按需挂载到页面级容器,避免挤占表单布局 -->
|
||||||
|
<div class="auth-captcha-modal" data-captcha-box aria-live="polite"></div>
|
||||||
|
<script src="public/js/md5.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="utils/MessageUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/tac/js/tac.min.js"></script>
|
||||||
|
<script src="public/js/captcha-pages.js"></script>
|
||||||
|
<script src="public/js/auth-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>平台公告详情 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/notice-detail.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-notice-detail" data-promotion-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a><a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a class="active" href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero notice-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Notice</div>
|
||||||
|
<h1 data-promotion-title>平台内容公开展示规范说明</h1>
|
||||||
|
<p class="lead" data-promotion-summary>
|
||||||
|
为了保护家族资料安全,平台仅展示管理员确认公开的家谱介绍、文章、宣传相册和宣传视频。
|
||||||
|
</p>
|
||||||
|
<div class="article-meta">
|
||||||
|
<span>平台公告</span><span data-promotion-time>2026.05</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card notice-card tilt-card">
|
||||||
|
<span>告</span>
|
||||||
|
<p>公开有边界,传承更长久。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container notice-layout">
|
||||||
|
<!-- 公告详情区域:从 /genealogy/app/promotions 列表中按 id 选择一条展示。 -->
|
||||||
|
<article class="notice-content tilt-card" data-promotion-content>
|
||||||
|
<p>
|
||||||
|
平台前台页面主要用于展示家族文化与公开资料。涉及成员联系方式、详细个人信息、未审核资料等内容,不会在公开页面直接呈现。
|
||||||
|
</p>
|
||||||
|
<h2>公开内容范围</h2>
|
||||||
|
<p>
|
||||||
|
可公开内容包括家族简介、姓氏源流、谱文节选、宣传相册、宣传视频、平台公告和管理员允许展示的纪念内容。
|
||||||
|
</p>
|
||||||
|
<h2>资料维护建议</h2>
|
||||||
|
<p>
|
||||||
|
建议由管理员先整理资料,再邀请亲人补充和校对。需要修改公开范围时,可以在权限设置中调整。
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
<aside class="notice-side tilt-card">
|
||||||
|
<h3>相关页面</h3>
|
||||||
|
<a href="help.html">帮助中心</a
|
||||||
|
><a href="article-detail.html">家谱知识</a
|
||||||
|
><a href="about.html">关于我们</a>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a href="article-detail.html">家谱知识</a
|
||||||
|
><a href="notice-detail.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/promotion-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家谱广场 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/plaza.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-plaza">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a>
|
||||||
|
<a href="genealogy.html">数字家谱</a>
|
||||||
|
<a class="active" href="plaza.html">家谱广场</a>
|
||||||
|
<a href="culture.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero plaza-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Family Plaza</div>
|
||||||
|
<h1>浏览公开家谱,寻找同宗线索</h1>
|
||||||
|
<p class="lead">
|
||||||
|
按姓氏、地区、堂号和家谱名称检索公开家谱,先看示例,再创建自己的家族空间。
|
||||||
|
</p>
|
||||||
|
<div class="plaza-stats">
|
||||||
|
<span><b>128+</b>公开家谱</span>
|
||||||
|
<span><b>36</b>地区线索</span>
|
||||||
|
<span><b>18</b>谱文示例</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card search-card tilt-card">
|
||||||
|
<div class="search-ornament"></div>
|
||||||
|
<h3>查找公开家谱</h3>
|
||||||
|
<div class="toolbar search-toolbar">
|
||||||
|
<input class="input" placeholder="输入姓氏、地区或家谱名称" /><a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="search-result.html"
|
||||||
|
>搜索</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">公开家谱</span><span class="tag">字辈完整</span
|
||||||
|
><span class="tag">多人共修</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section alt plaza-list-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>推荐家谱</h2>
|
||||||
|
<p>展示公开或示例家谱,让访问者理解数字家谱最终会呈现成什么样。</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3" data-genealogy-list="public">
|
||||||
|
<a class="family-card featured tilt-card" href="family-detail.html">
|
||||||
|
<div class="family-card-shine"></div>
|
||||||
|
<div class="family-badge">推荐</div>
|
||||||
|
<h3>四川成都陈氏族</h3>
|
||||||
|
<p>
|
||||||
|
已收录成员 128 人,整理字辈 6 代,公开谱文 18 篇,宣传相册 7
|
||||||
|
组。
|
||||||
|
</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">四川</span><span class="tag">陈氏</span
|
||||||
|
><span class="tag">128人</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="card family-lite tilt-card" href="family-detail.html">
|
||||||
|
<div class="family-icon">刘</div>
|
||||||
|
<h3>湖广刘氏家谱</h3>
|
||||||
|
<p>从始祖世系到现代家庭分支,保留字辈与迁徙记录。</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">公开家谱</span
|
||||||
|
><span class="tag">字辈完整</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="card family-lite tilt-card" href="family-detail.html">
|
||||||
|
<div class="family-icon">张</div>
|
||||||
|
<h3>岭南张氏宗谱</h3>
|
||||||
|
<p>以谱文、相册、家族动态为主,记录家风与重要纪念。</p>
|
||||||
|
<div class="tag-row">
|
||||||
|
<span class="tag">家族文化</span
|
||||||
|
><span class="tag">宣传相册</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>管理员权限 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-admin-permission-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-family-admin.html">家族管理</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-family-admin.html">返回管理</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="admin-permission-form">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Permissions</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>管理员权限</h1>
|
||||||
|
<p>
|
||||||
|
分配全权管理员、全系管理员、支系管理员,以及入谱审核等具体权限。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a class="active" href="profile-admin-permissions.html"
|
||||||
|
>管理员权限</a
|
||||||
|
><a href="profile-messages.html">入谱审核</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>权限设置</h2>
|
||||||
|
<form id="admin-permission-form" class="editor-form" data-permission-form>
|
||||||
|
<!-- 成员下拉由 /members/options 接口渲染 -->
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="permission-member">选择成员</label>
|
||||||
|
<select id="permission-member" data-member-select>
|
||||||
|
<option value="">成员加载中...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="permission-role">角色权限</label>
|
||||||
|
<select id="permission-role" name="roleType">
|
||||||
|
<option value="admin">管理员</option>
|
||||||
|
<option value="member">普通成员</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary" type="submit">保存权限</button>
|
||||||
|
<button class="btn ghost" type="button" data-owner-transfer>转让所有者</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/member-admin-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家族相册 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-album-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="#album-form">新建相册</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Album</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>家族相册</h1>
|
||||||
|
<p>
|
||||||
|
管理相册名称、封面、描述和照片,作为个人中心内的独立相册管理页。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-article.html">谱文</a
|
||||||
|
><a class="active" href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a
|
||||||
|
><a href="profile-family-home.html">家谱主页</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>相册列表</h2>
|
||||||
|
<!-- 相册列表由 /albums 接口渲染,点击后加载照片 -->
|
||||||
|
<div class="module-list" data-album-list>
|
||||||
|
<div class="api-empty">相册加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>新建 / 编辑相册</h2>
|
||||||
|
<form id="album-form" class="editor-form" data-album-form>
|
||||||
|
<!-- 字段名称对应 APP.openapi.json 的 AlbumBody -->
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="albumName">相册名称</label>
|
||||||
|
<input id="albumName" name="albumName" type="text" placeholder="请输入相册名称" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="albumDesc">相册描述</label>
|
||||||
|
<textarea id="albumDesc" name="albumDesc" placeholder="请输入相册描述"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="coverOssId">封面 OSS ID</label>
|
||||||
|
<input id="coverOssId" name="coverOssId" type="text" placeholder="上传后填写 OSS ID" />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并回填封面 OSS ID -->
|
||||||
|
<label class="upload-control" for="albumCoverFile">选择封面图片</label>
|
||||||
|
<input id="albumCoverFile" class="upload-input" type="file" accept="image/*" data-upload-target="#coverOssId" data-upload-status="#albumCoverStatus" />
|
||||||
|
<p id="albumCoverStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="albumStatus">状态</label>
|
||||||
|
<select id="albumStatus" name="status">
|
||||||
|
<option value="0">启用</option>
|
||||||
|
<option value="1">停用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary" type="submit">保存相册</button>
|
||||||
|
<button class="btn ghost" type="reset">清空</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>照片管理</h2>
|
||||||
|
<!-- 选择相册后由 /albums/{albumId}/photos 接口渲染 -->
|
||||||
|
<div class="module-list" data-album-photo-list>
|
||||||
|
<div class="api-empty">请选择相册查看照片</div>
|
||||||
|
</div>
|
||||||
|
<form class="editor-form album-photo-form" data-album-photo-form>
|
||||||
|
<!-- 字段名称对应 APP.openapi.json 的 AlbumPhotoBody -->
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="photoOssId">照片 OSS ID</label>
|
||||||
|
<input id="photoOssId" name="ossId" type="text" placeholder="上传后填写 OSS ID" required />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并回填照片 OSS ID -->
|
||||||
|
<label class="upload-control" for="albumPhotoFile">选择照片</label>
|
||||||
|
<input id="albumPhotoFile" class="upload-input" type="file" accept="image/*" data-upload-target="#photoOssId" data-upload-status="#albumPhotoStatus" />
|
||||||
|
<p id="albumPhotoStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="photoTitle">照片标题</label>
|
||||||
|
<input id="photoTitle" name="photoTitle" type="text" placeholder="请输入照片标题" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="photoDesc">照片说明</label>
|
||||||
|
<textarea id="photoDesc" name="photoDesc" placeholder="请输入照片说明"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary" type="submit">添加照片</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/album-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>编辑谱文 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-article-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-article.html">谱文</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-article.html">返回谱文</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="article-edit-form">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Article Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>编辑谱文</h1>
|
||||||
|
<p>
|
||||||
|
使用富文本编辑器撰写谱文、谱序、谱论和恩荣录,支持图片、表格与排版。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-article.html">谱文</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>谱文内容</h2>
|
||||||
|
<form id="article-edit-form" class="editor-form layui-form" data-article-form>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleTitle">谱文标题</label
|
||||||
|
><input
|
||||||
|
id="articleTitle"
|
||||||
|
name="articleTitle"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入谱文标题"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleCategory">谱文类型</label
|
||||||
|
><select id="articleCategory" name="categoryId" data-article-category>
|
||||||
|
<option value="">分类加载中...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleSignature">落款</label
|
||||||
|
><input
|
||||||
|
id="articleSignature"
|
||||||
|
name="authorName"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入落款"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleContent">正文</label
|
||||||
|
><textarea
|
||||||
|
id="articleContent"
|
||||||
|
name="articleContent"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入谱文内容"
|
||||||
|
required
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleSummary">摘要</label>
|
||||||
|
<textarea id="articleSummary" name="articleSummary" placeholder="请输入谱文摘要"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="articleCoverOssId">封面 OSS ID</label>
|
||||||
|
<input id="articleCoverOssId" name="coverOssId" type="text" placeholder="上传封面后自动回填" />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并把 OSS ID 写入上方输入框 -->
|
||||||
|
<label class="upload-control" for="articleCoverFile">选择封面图片</label>
|
||||||
|
<input id="articleCoverFile" class="upload-input" type="file" accept="image/*" data-upload-target="#articleCoverOssId" data-upload-status="#articleCoverStatus" />
|
||||||
|
<p id="articleCoverStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-article.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/article-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>谱文管理 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-article-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-article.html">谱文</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-article-edit.html"
|
||||||
|
>添加谱文</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Article</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>谱文管理</h1>
|
||||||
|
<p>
|
||||||
|
管理谱文、谱序、谱论、恩荣录等家族文献,支持添加内容、图片与落款。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-article.html">谱文</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>谱文列表</h2>
|
||||||
|
<!-- 谱文列表由 /articles 接口渲染 -->
|
||||||
|
<div class="module-list" data-article-list>
|
||||||
|
<div class="api-empty">谱文加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>新建谱文</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>谱文标题</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-article-edit.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>谱文内容</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-article-edit.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>图片质量</span><b>原图</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-select="原图|高清|普通"
|
||||||
|
data-select-title="选择图片质量"
|
||||||
|
>选择</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/article-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>内容发布 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-content-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a class="active" href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Content Studio</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>内容发布</h1>
|
||||||
|
<p>
|
||||||
|
承接 APP
|
||||||
|
家谱主页里的谱文、视频、相册、功德录、贺礼邀请、成长日志、动态和备忘录。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="profile-article.html"
|
||||||
|
>添加谱文</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a class="active" href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>发布入口</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<a class="module-card tilt-card" href="profile-article.html"
|
||||||
|
><span class="icon">谱</span>
|
||||||
|
<h3>谱文</h3>
|
||||||
|
<p>添加谱文标题、内容、落款和图片质量设置。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-album.html"
|
||||||
|
><span class="icon">册</span>
|
||||||
|
<h3>家族相册</h3>
|
||||||
|
<p>新建相册、编辑封面、上传照片。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-video.html"
|
||||||
|
><span class="icon">影</span>
|
||||||
|
<h3>家族视频</h3>
|
||||||
|
<p>发布视频、编辑家族视频和视频描述。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-merit.html"
|
||||||
|
><span class="icon">德</span>
|
||||||
|
<h3>功德录</h3>
|
||||||
|
<p>添加功德人,记录事迹和时间。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-gift.html"
|
||||||
|
><span class="icon">礼</span>
|
||||||
|
<h3>贺礼邀请</h3>
|
||||||
|
<p>创建婚礼、升学、生日等贺礼邀请。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-feed.html"
|
||||||
|
><span class="icon">动</span>
|
||||||
|
<h3>发布动态</h3>
|
||||||
|
<p>向家族圈发布图文动态,可设置置顶和精华。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-growth.html"
|
||||||
|
><span class="icon">志</span>
|
||||||
|
<h3>成长日志</h3>
|
||||||
|
<p>记录个人成长节点,支持照片附件。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-memo.html"
|
||||||
|
><span class="icon">备</span>
|
||||||
|
<h3>人亲簿 / 备忘录</h3>
|
||||||
|
<p>保存人情往来、家族事务和纪念事项。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>最近内容</h2>
|
||||||
|
<!-- 最近内容先接谱文接口,其他内容类型按后续编号逐步接入 -->
|
||||||
|
<div class="module-list" data-recent-content>
|
||||||
|
<div class="api-empty">最近内容加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/article-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>创建家谱 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a class="active" href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-families.html">返回我的家谱</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Create Family</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>创建家谱</h1>
|
||||||
|
<p>
|
||||||
|
个人中心专用创建流程,用于录入姓氏、谱名、堂号、地望、祠堂和访问权限。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-create-family.html">创建家谱</a
|
||||||
|
><a href="profile-join-family.html">加入家谱</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>基础信息</h2>
|
||||||
|
<!-- 个人中心创建家谱复用创建接口,字段对应 GenealogyCreateBody。 -->
|
||||||
|
<form class="editor-form profile-create-family-form" data-genealogy-form="create" data-success-url="profile-families.html">
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="familySurname">姓氏</label>
|
||||||
|
<input id="familySurname" name="surname" type="text" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="familyName">谱名</label>
|
||||||
|
<input id="familyName" name="genealogyName" type="text" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="ancestralHall">堂号/祠堂</label>
|
||||||
|
<input id="ancestralHall" name="ancestralHall" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="originPlace">籍贯/起源地</label>
|
||||||
|
<input id="originPlace" name="originPlace" type="text" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label>家族所在地</label>
|
||||||
|
<div class="profile-region-picker" data-region-picker>
|
||||||
|
<select name="provinceCode" data-region-level="province">
|
||||||
|
<option value="">请选择省</option>
|
||||||
|
</select>
|
||||||
|
<select name="cityCode" data-region-level="city">
|
||||||
|
<option value="">请选择市</option>
|
||||||
|
</select>
|
||||||
|
<select name="districtCode" data-region-level="district">
|
||||||
|
<option value="">请选择区县</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="regionCode" data-region-code />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="addressDetail">详细地址</label>
|
||||||
|
<input id="addressDetail" name="addressDetail" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="intro">家谱简介</label>
|
||||||
|
<textarea id="intro" name="intro"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="visibility">可见范围</label>
|
||||||
|
<select id="visibility" name="visibility">
|
||||||
|
<option value="1">公开</option>
|
||||||
|
<option value="2">成员可见</option>
|
||||||
|
<option value="0">私密</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="joinMode">加入方式</label>
|
||||||
|
<select id="joinMode" name="joinMode">
|
||||||
|
<option value="1">审核加入</option>
|
||||||
|
<option value="2">邀请码加入</option>
|
||||||
|
<option value="0">关闭加入</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">确定创建</button>
|
||||||
|
<a class="btn ghost magnetic" href="profile-families.html">返回列表</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/region-pages.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>资料提醒 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a class="active" href="profile-data-reminders.html">资料提醒</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-messages.html">返回消息</a
|
||||||
|
><a class="btn primary magnetic" href="profile-data.html">完善资料</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Data Reminders</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>资料提醒</h1>
|
||||||
|
<p>
|
||||||
|
集中查看成员资料缺项,补齐头像、出生日期、亲属关系和联系方式。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-data.html">个人资料</a
|
||||||
|
><a class="active" href="profile-data-reminders.html">资料提醒</a
|
||||||
|
><a href="profile-join-review.html">入谱审核</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>待完善成员</h2>
|
||||||
|
<div class="module-list">
|
||||||
|
<a class="module-row" href="profile-data.html"
|
||||||
|
><div>
|
||||||
|
<h3>鹿野 Loyel</h3>
|
||||||
|
<p>缺少出生日期、出生地址和微信信息</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">完善</span></a
|
||||||
|
><a class="module-row" href="profile-data.html"
|
||||||
|
><div>
|
||||||
|
<h3>张三</h3>
|
||||||
|
<p>缺少头像和亲属关系</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">编辑</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>个人资料 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-profile-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a class="active" href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Profile Data</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>个人资料</h1>
|
||||||
|
<p>
|
||||||
|
对应 APP 的个人资料、亲属、完善资料、绑定账号和成员激活流程。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="#profile-edit-form"
|
||||||
|
>编辑资料</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>编辑资料</h2>
|
||||||
|
<!-- 个人资料表单:字段对应 /genealogy/app/auth/profile 的 ProfileUpdateBody。 -->
|
||||||
|
<form class="editor-form profile-data-form" id="profile-edit-form" data-profile-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="profileNickName">昵称</label>
|
||||||
|
<input
|
||||||
|
id="profileNickName"
|
||||||
|
name="nickName"
|
||||||
|
type="text"
|
||||||
|
autocomplete="nickname"
|
||||||
|
placeholder="请输入昵称"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="profileAvatarOssId">头像 OSS ID</label>
|
||||||
|
<input
|
||||||
|
id="profileAvatarOssId"
|
||||||
|
name="avatarOssId"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
step="1"
|
||||||
|
placeholder="上传后填写 OSS ID"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="profileSex">性别</label>
|
||||||
|
<select id="profileSex" name="sex">
|
||||||
|
<option value="">请选择</option>
|
||||||
|
<option value="0">男</option>
|
||||||
|
<option value="1">女</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="profileBirthday">出生日期</label>
|
||||||
|
<input id="profileBirthday" name="birthday" type="date" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions profile-form-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存资料</button>
|
||||||
|
<span class="form-status" data-profile-status></span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>基本资料</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>头像</span><b>已上传</b
|
||||||
|
><a class="link-btn" href="profile-data.html">更换</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>姓名</span><b data-profile-text="displayName">鹿野 Loyel</b
|
||||||
|
><a class="link-btn" href="profile-data.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>绑定账号</span><b data-profile-text="phone">已绑定</b
|
||||||
|
><a class="link-btn" href="profile-security.html">安全设置</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>血亲关系</span><b>第二代 顺字辈</b
|
||||||
|
><a class="link-btn" href="profile-family-admin.html"
|
||||||
|
>查看世系</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>个人信息</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>父亲</span><b>某某</b
|
||||||
|
><a class="link-btn" href="profile-data.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>出生日期</span><b data-profile-text="birthday">待选择</b
|
||||||
|
><a class="link-btn" href="profile-data.html">选择</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>现居地址</span><b data-profile-text="regionText">待填写</b
|
||||||
|
><a class="link-btn" href="profile-data.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>微信 / QQ</span><b>待填写</b
|
||||||
|
><a class="link-btn" href="profile-data.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>学历 / 职业</span><b>待填写</b
|
||||||
|
><a class="link-btn" href="profile-data.html">填写</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>现居地区</h2>
|
||||||
|
<!-- 地区资料表单:字段对应 ProfileUpdateBody 的省市区编码。 -->
|
||||||
|
<form class="editor-form region-profile-form" data-region-profile-form>
|
||||||
|
<div class="region-picker profile-region-picker" data-region-picker>
|
||||||
|
<select class="input" name="provinceCode" data-region-level="province">
|
||||||
|
<option value="">请选择省</option>
|
||||||
|
</select>
|
||||||
|
<select class="input" name="cityCode" data-region-level="city">
|
||||||
|
<option value="">请选择市</option>
|
||||||
|
</select>
|
||||||
|
<select class="input" name="districtCode" data-region-level="district">
|
||||||
|
<option value="">请选择区县</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存地区</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>亲属</h2>
|
||||||
|
<div class="module-list">
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>张三</h3>
|
||||||
|
<p>父亲 · 已绑定成员资料</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">查看</span>
|
||||||
|
</div>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>张三</h3>
|
||||||
|
<p>父亲 · 未绑定账号</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">邀请激活</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/region-pages.js"></script>
|
||||||
|
<script src="public/js/profile-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>我的家谱 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a class="active" href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Personal Center</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>我的家谱</h1>
|
||||||
|
<p>
|
||||||
|
集中管理你创建或加入的家谱,进入家谱主页后可继续处理世系图、相册、家族圈和成员协作。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a class="active" href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>家谱列表</h2>
|
||||||
|
<p>对应 APP 的“我的家谱”和“家谱主页”。</p>
|
||||||
|
<div class="module-list" data-genealogy-list="mine">
|
||||||
|
<a class="module-row" href="profile-family-home.html"
|
||||||
|
><div>
|
||||||
|
<h3>四川武胜汤氏族</h3>
|
||||||
|
<p>创建者 · 共修入 7 人 · 最近更新:家族圈动态</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">进入主页</span></a
|
||||||
|
>
|
||||||
|
<a class="module-row" href="profile-family-home.html"
|
||||||
|
><div>
|
||||||
|
<h3>四川达州刘氏族</h3>
|
||||||
|
<p>管理员 · 共修入 7 人 · 2 条内容待查看</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">进入主页</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>快捷操作</h2>
|
||||||
|
<div class="module-grid two">
|
||||||
|
<a
|
||||||
|
class="module-card tilt-card"
|
||||||
|
href="profile-create-family.html"
|
||||||
|
><span class="icon">建</span>
|
||||||
|
<h3>立即创建我的家谱</h3>
|
||||||
|
<p>创建新家谱,设置姓氏、谱名、堂号和访问权限。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-join-family.html"
|
||||||
|
><span class="icon">入</span>
|
||||||
|
<h3>加入家谱</h3>
|
||||||
|
<p>输入邀请码或由管理员邀请,加入已有家谱协作。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/genealogy-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家族管理 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-member-admin-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a class="active" href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Family Admin</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1 data-member-title>家族管理</h1>
|
||||||
|
<p>
|
||||||
|
承接 APP
|
||||||
|
里的世代管理、管理员权限、入谱审核和邀请绑定等后台能力。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="profile-data.html"
|
||||||
|
>添加成员</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a class="active" href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>管理入口</h2>
|
||||||
|
<p data-member-overview>家谱概览加载中...</p>
|
||||||
|
<div class="module-grid">
|
||||||
|
<a class="module-card tilt-card" href="profile-tree.html"
|
||||||
|
><span class="icon">世</span>
|
||||||
|
<h3>世系图</h3>
|
||||||
|
<p>查看树谱模式、搜索成员、进入个人资料。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-generation.html"
|
||||||
|
><span class="icon">辈</span>
|
||||||
|
<h3>字辈谱</h3>
|
||||||
|
<p>维护字辈和各世代人数。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-generation.html"
|
||||||
|
><span class="icon">代</span>
|
||||||
|
<h3>设置世代</h3>
|
||||||
|
<p>新增、编辑、调整始祖世代。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-messages.html"
|
||||||
|
><span class="icon">审</span>
|
||||||
|
<h3>入谱审核</h3>
|
||||||
|
<p>审核加入家谱与绑定账号申请。</p></a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="module-card tilt-card"
|
||||||
|
href="profile-admin-permissions.html"
|
||||||
|
><span class="icon">权</span>
|
||||||
|
<h3>管理员权限</h3>
|
||||||
|
<p>分配全权、全系、支系管理员。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-invite.html"
|
||||||
|
><span class="icon">邀</span>
|
||||||
|
<h3>邀请家人</h3>
|
||||||
|
<p>生成邀请入口,让亲人加入协作。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>当前管理员</h2>
|
||||||
|
<!-- 成员列表由 /members 接口渲染,权限按钮会提交 /members/{memberId} -->
|
||||||
|
<div class="module-list" data-member-list>
|
||||||
|
<div class="api-empty">成员加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/member-admin-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家谱主页 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-family-home-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a class="active" href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile.html">返回中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-feed.html">发布动态</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Family Home</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1 data-family-home-title>四川武胜汤氏族</h1>
|
||||||
|
<p>
|
||||||
|
后台家谱主页,用于进入世系、相册、家族圈、内容管理和成员协作。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn ghost magnetic" href="profile-family-admin.html"
|
||||||
|
>管理家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a class="active" href="profile-family-home.html">家谱主页</a
|
||||||
|
><a href="profile-tree.html">世系图</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-messages.html">消息中心</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>家谱概览</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<div class="module-card">
|
||||||
|
<span class="icon">谱</span>
|
||||||
|
<h3>家谱编号</h3>
|
||||||
|
<p data-family-home-summary>家谱信息加载中...</p>
|
||||||
|
</div>
|
||||||
|
<a class="module-card tilt-card" href="profile-tree.html"
|
||||||
|
><span class="icon">世</span>
|
||||||
|
<h3>世系图</h3>
|
||||||
|
<p>查看树谱模式和成员关系。</p></a
|
||||||
|
><a class="module-card tilt-card" href="profile-invite.html"
|
||||||
|
><span class="icon">邀</span>
|
||||||
|
<h3>邀请家人</h3>
|
||||||
|
<p>生成邀请入口,邀请亲人协作。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>世系预览</h2>
|
||||||
|
<!-- 家谱主页只展示世系树预览,完整维护进入世系图页面 -->
|
||||||
|
<div class="lineage-tree-wrap is-compact" data-lineage-home-tree>
|
||||||
|
<div class="api-empty">世系树加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>常用入口</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<a class="module-card tilt-card" href="profile-article.html"
|
||||||
|
><span class="icon">文</span>
|
||||||
|
<h3>谱文</h3>
|
||||||
|
<p>管理谱文、谱序和族史。</p></a
|
||||||
|
><a class="module-card tilt-card" href="profile-video.html"
|
||||||
|
><span class="icon">影</span>
|
||||||
|
<h3>视频</h3>
|
||||||
|
<p>发布和编辑家族视频。</p></a
|
||||||
|
><a class="module-card tilt-card" href="profile-merit.html"
|
||||||
|
><span class="icon">德</span>
|
||||||
|
<h3>功德录</h3>
|
||||||
|
<p>记录功德人和事迹。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/lineage-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>发布动态 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-feed-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-family-home.html">家谱主页</a
|
||||||
|
><a class="active" href="profile-feed.html">发布动态</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-feed.html">返回动态</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="feed-edit-form">发布</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Feed Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>发布动态</h1>
|
||||||
|
<p>面向家族圈发布图文动态,可设置置顶和精华。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-feed.html">发布动态</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>动态内容</h2>
|
||||||
|
<form id="feed-edit-form" class="editor-form layui-form" data-feed-form>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedContent">内容</label
|
||||||
|
><textarea
|
||||||
|
id="feedContent"
|
||||||
|
name="content"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入动态内容"
|
||||||
|
required
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedMedia">图片 OSS ID</label>
|
||||||
|
<input id="feedMedia" name="mediaOssIds" type="text" placeholder="多个图片 ID 用英文逗号分隔" />
|
||||||
|
<!-- 多图上传会追加 OSS ID 到 mediaOssIds 字段 -->
|
||||||
|
<label class="upload-control" for="feedMediaFile">选择动态图片</label>
|
||||||
|
<input id="feedMediaFile" class="upload-input" type="file" accept="image/*" data-upload-target="#feedMedia" data-upload-status="#feedMediaStatus" data-upload-multiple="true" />
|
||||||
|
<p id="feedMediaStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedVisibility">可见范围</label>
|
||||||
|
<select id="feedVisibility" name="visibility">
|
||||||
|
<option value="2">成员可见</option>
|
||||||
|
<option value="1">公开</option>
|
||||||
|
<option value="0">私密</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedStatus">状态</label>
|
||||||
|
<select id="feedStatus" name="status">
|
||||||
|
<option value="0">发布</option>
|
||||||
|
<option value="1">草稿</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">发布</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-feed.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/feed-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>发布动态 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-feed-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-family-home.html">家谱主页</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-feed.html">发布动态</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-family-home.html">返回家谱主页</a
|
||||||
|
><a class="btn primary magnetic" href="profile-feed-edit.html"
|
||||||
|
>发布</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Family Feed</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>发布动态</h1>
|
||||||
|
<p>向家族圈发布图文动态,可设置置顶和精华。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-feed.html">发布动态</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a href="profile-video.html">视频</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>动态草稿</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>内容</span><b>0/200</b
|
||||||
|
><a class="link-btn" href="profile-feed-edit.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>图片</span><b>可添加多张</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-msg="请选择要上传的图片"
|
||||||
|
>添加</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>置顶</span><b>否</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-select="是|否"
|
||||||
|
data-select-title="切换状态"
|
||||||
|
>切换</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>精华</span><b>否</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-select="是|否"
|
||||||
|
data-select-title="切换状态"
|
||||||
|
>切换</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>最近动态</h2>
|
||||||
|
<!-- 动态列表由 /feeds/page 接口渲染,点赞和评论走对应子接口 -->
|
||||||
|
<div class="module-list" data-feed-list>
|
||||||
|
<div class="api-empty">动态加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/feed-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>意见反馈 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a class="active" href="profile-feedback.html">意见反馈</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-services.html">返回服务中心</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="profileFeedbackForm">提交</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Feedback</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>意见反馈</h1>
|
||||||
|
<p>提交产品问题、资料异常和改进建议,个人中心内独立跟踪。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a href="profile-share.html">应用分享</a
|
||||||
|
><a class="active" href="profile-feedback.html">意见反馈</a
|
||||||
|
><a href="profile-security.html">安全设置</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>提交反馈</h2>
|
||||||
|
<form class="editor-form" id="profileFeedbackForm" data-feedback-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedbackType">反馈类型</label>
|
||||||
|
<select id="feedbackType" name="feedbackType">
|
||||||
|
<option value="suggestion">改进建议</option>
|
||||||
|
<option value="bug">问题反馈</option>
|
||||||
|
<option value="data">资料异常</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="contactInfo">联系方式</label>
|
||||||
|
<input id="contactInfo" name="contactInfo" type="text" placeholder="手机号 / 邮箱" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedbackTitle">反馈标题</label>
|
||||||
|
<input id="feedbackTitle" name="feedbackTitle" type="text" placeholder="请填写反馈标题" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="feedbackContent">反馈描述</label>
|
||||||
|
<textarea id="feedbackContent" name="feedbackContent" placeholder="请描述问题、页面位置和期望结果"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">提交反馈</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>历史反馈</h2>
|
||||||
|
<div class="module-list" data-feedback-list>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>资料导入建议</h3>
|
||||||
|
<p>已受理 · 2026.05</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">查看</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/feedback-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>字辈谱 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-family-admin.html">家族管理</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-family-admin.html">返回管理</a
|
||||||
|
><a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="#"
|
||||||
|
data-layer-confirm="进入字辈管理模式?"
|
||||||
|
data-confirm-title="管理字辈"
|
||||||
|
>管理</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Generation</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>字辈谱</h1>
|
||||||
|
<p>管理世代数字辈,查看各代人数,并维护同字辈多个用字。</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn primary magnetic"
|
||||||
|
type="button"
|
||||||
|
data-generation-add
|
||||||
|
>新增字辈</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-tree.html">世系图</a
|
||||||
|
><a class="active" href="profile-generation.html">字辈谱</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel generation-batch-panel">
|
||||||
|
<h2>批量字辈</h2>
|
||||||
|
<!-- 批量字辈表单:字段对应 GenerationPoemBatchBody。 -->
|
||||||
|
<form class="editor-form generation-batch-form" data-generation-batch-form>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="generationBatchContent">字辈内容</label>
|
||||||
|
<textarea
|
||||||
|
id="generationBatchContent"
|
||||||
|
name="content"
|
||||||
|
rows="4"
|
||||||
|
placeholder="例如:德承家亦"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<label class="check-row generation-batch-check" for="generationStopMissing">
|
||||||
|
<input
|
||||||
|
id="generationStopMissing"
|
||||||
|
name="stopMissingOldGeneration"
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
<span>遇到缺失旧世代时停止导入</span>
|
||||||
|
</label>
|
||||||
|
<div class="bottom-actions generation-batch-actions">
|
||||||
|
<button
|
||||||
|
class="btn ghost"
|
||||||
|
type="button"
|
||||||
|
data-generation-batch-action="preview"
|
||||||
|
>批量预览</button>
|
||||||
|
<button
|
||||||
|
class="btn primary magnetic"
|
||||||
|
type="button"
|
||||||
|
data-generation-batch-action="save"
|
||||||
|
>批量保存</button>
|
||||||
|
<span class="form-status" data-generation-batch-status></span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="module-list generation-batch-preview" data-generation-batch-preview>
|
||||||
|
<div class="api-empty">批量预览结果将在这里显示</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>字辈列表</h2>
|
||||||
|
<div class="module-list" data-generation-list>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>第 1 代:代</h3>
|
||||||
|
<p>1 人</p>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="pill"
|
||||||
|
href="#"
|
||||||
|
data-layer-prompt="请输入新的字辈"
|
||||||
|
data-prompt-title="编辑字辈"
|
||||||
|
>编辑</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>第 2 代:顺</h3>
|
||||||
|
<p>2 人</p>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="pill"
|
||||||
|
href="#"
|
||||||
|
data-layer-prompt="请输入新的字辈"
|
||||||
|
data-prompt-title="编辑字辈"
|
||||||
|
>编辑</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>第 3 代:万</h3>
|
||||||
|
<p>3 人</p>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="pill"
|
||||||
|
href="#"
|
||||||
|
data-layer-prompt="请输入新的字辈"
|
||||||
|
data-prompt-title="编辑字辈"
|
||||||
|
>编辑</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/generation-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>创建贺礼 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-ceremony-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-gift.html">贺礼邀请</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-gift.html">返回贺礼</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="ceremony-edit-form">确定创建</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Gift Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>创建贺礼</h1>
|
||||||
|
<p>维护贺礼类型、标题、时间地点、通知人员和邀请正文。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-merit.html">功德录</a
|
||||||
|
><a class="active" href="profile-gift.html">贺礼邀请</a
|
||||||
|
><a href="profile-feed.html">发布动态</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>贺礼信息</h2>
|
||||||
|
<form id="ceremony-edit-form" class="editor-form layui-form" data-ceremony-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftType">贺礼类型</label
|
||||||
|
><select id="giftType" name="ceremonyType">
|
||||||
|
<option value="wedding">婚礼</option>
|
||||||
|
<option value="education">升学</option>
|
||||||
|
<option value="birthday">生日</option>
|
||||||
|
<option value="ancestor">祭祀</option>
|
||||||
|
<option value="other">其他</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftDate">举办时间</label
|
||||||
|
><input
|
||||||
|
id="giftDate"
|
||||||
|
name="ceremonyTime"
|
||||||
|
type="text"
|
||||||
|
placeholder="请选择时间"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftTitle">贺礼标题</label
|
||||||
|
><input id="giftTitle" name="ceremonyTitle" type="text" placeholder="请输入标题" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftAddress">举办地点</label
|
||||||
|
><input
|
||||||
|
id="giftAddress"
|
||||||
|
name="location"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入地点"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftContent">贺礼内容</label
|
||||||
|
><textarea
|
||||||
|
id="giftContent"
|
||||||
|
name="ceremonyDesc"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入贺礼内容"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftCoverOssId">封面 OSS ID</label>
|
||||||
|
<input id="giftCoverOssId" name="coverOssId" type="text" placeholder="上传封面后自动回填" />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并回填封面 OSS ID -->
|
||||||
|
<label class="upload-control" for="giftCoverFile">选择封面图片</label>
|
||||||
|
<input id="giftCoverFile" class="upload-input" type="file" accept="image/*" data-upload-target="#giftCoverOssId" data-upload-status="#giftCoverStatus" />
|
||||||
|
<p id="giftCoverStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">确定创建</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-gift.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/ceremony-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>贺礼邀请 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-ceremony-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-gift.html">贺礼邀请</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-gift-edit.html"
|
||||||
|
>创建贺礼</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Invitation</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>贺礼邀请</h1>
|
||||||
|
<p>
|
||||||
|
管理婚礼、升学、生日和其他家族贺礼邀请,可进入管理模式删除或编辑。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-merit.html">功德录</a
|
||||||
|
><a class="active" href="profile-gift.html">贺礼邀请</a
|
||||||
|
><a href="profile-feed.html">发布动态</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>邀请列表</h2>
|
||||||
|
<!-- 贺礼/祭祀列表由 /ceremonies 接口渲染 -->
|
||||||
|
<div class="module-list" data-ceremony-list>
|
||||||
|
<div class="api-empty">贺礼邀请加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>献礼记录</h2>
|
||||||
|
<!-- 选择贺礼后由 /ceremonies/{ceremonyId}/gifts 接口渲染 -->
|
||||||
|
<div class="module-list" data-ceremony-gift-list>
|
||||||
|
<div class="api-empty">请选择贺礼查看献礼记录</div>
|
||||||
|
</div>
|
||||||
|
<form class="editor-form ceremony-gift-form" data-ceremony-gift-form>
|
||||||
|
<!-- 字段名称对应 APP.openapi.json 的 CeremonyGiftBody -->
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftGiverName">献礼人</label>
|
||||||
|
<input id="giftGiverName" name="giverName" type="text" placeholder="请输入献礼人姓名" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftAmount">礼金金额</label>
|
||||||
|
<input id="giftAmount" name="giftAmount" type="number" step="0.01" placeholder="请输入金额" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="giftMessage">献礼留言</label>
|
||||||
|
<textarea id="giftMessage" name="giftMessage" placeholder="请输入留言"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary" type="submit">保存献礼</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/ceremony-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>新建成长日志 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-growth-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-growth.html">成长日志</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-growth.html">返回日志</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="growth-edit-form">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Growth Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>新建成长日志</h1>
|
||||||
|
<p>记录成员成长节点、特殊情况、照片附件和补充资料。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-feed.html">发布动态</a
|
||||||
|
><a class="active" href="profile-growth.html">成长日志</a
|
||||||
|
><a href="profile-memo.html">备忘录</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>日志内容</h2>
|
||||||
|
<form id="growth-edit-form" class="editor-form layui-form" data-growth-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthPersonId">世系人物 ID</label
|
||||||
|
><input
|
||||||
|
id="growthPersonId"
|
||||||
|
name="lineagePersonId"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入世系人物 ID"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthDate">日期</label
|
||||||
|
><input
|
||||||
|
id="growthDate"
|
||||||
|
name="recordDate"
|
||||||
|
type="text"
|
||||||
|
placeholder="请选择日期"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthTitle">标题</label>
|
||||||
|
<input id="growthTitle" name="recordTitle" type="text" placeholder="请输入成长记录标题" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthType">类型</label>
|
||||||
|
<select id="growthType" name="recordType">
|
||||||
|
<option value="growth">成长</option>
|
||||||
|
<option value="birth">出生</option>
|
||||||
|
<option value="education">教育</option>
|
||||||
|
<option value="family">家庭</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthContent">内容</label
|
||||||
|
><textarea
|
||||||
|
id="growthContent"
|
||||||
|
name="recordContent"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入成长日志内容"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="growthMediaOssIds">附件 OSS ID</label>
|
||||||
|
<input id="growthMediaOssIds" name="mediaOssIds" type="text" placeholder="多个附件 ID 用英文逗号分隔" />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并追加 OSS ID -->
|
||||||
|
<label class="upload-control" for="growthMediaFile">添加照片</label>
|
||||||
|
<input id="growthMediaFile" class="upload-input" type="file" accept="image/*" data-upload-target="#growthMediaOssIds" data-upload-status="#growthMediaStatus" data-upload-multiple="true" />
|
||||||
|
<p id="growthMediaStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-growth.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/growth-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>成长日志 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-growth-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-growth.html">成长日志</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-growth-edit.html"
|
||||||
|
>新建日志</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Growth</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>成长日志</h1>
|
||||||
|
<p>记录成员成长节点、特殊情况、继承关系和个人资料补充。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-feed.html">发布动态</a
|
||||||
|
><a class="active" href="profile-growth.html">成长日志</a
|
||||||
|
><a href="profile-memo.html">备忘录</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>日志列表</h2>
|
||||||
|
<!-- 成长记录由 /growth-records 接口渲染 -->
|
||||||
|
<div class="module-list" data-growth-list>
|
||||||
|
<div class="api-empty">成长记录加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>新建成长日志</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>绑定账号</span><b>点击绑定</b
|
||||||
|
><a class="link-btn" href="profile-data.html">绑定</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>姓名</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-growth-edit.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>内容</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-growth-edit.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/growth-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>邀请家人 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-family-invite-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-family-admin.html">家族管理</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-family-admin.html">返回管理</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Invite</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>邀请家人</h1>
|
||||||
|
<p>生成家谱邀请链接或邀请码,引导亲人加入家谱并激活账号。</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="join-genealogy.html">打开加入页</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a class="active" href="profile-invite.html">邀请家人</a
|
||||||
|
><a href="profile-messages.html">邀请消息</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>邀请方式</h2>
|
||||||
|
<div class="module-grid two">
|
||||||
|
<div class="module-card">
|
||||||
|
<span class="icon">码</span>
|
||||||
|
<h3>邀请码</h3>
|
||||||
|
<p>当前邀请码:<b data-invite-code>加载中...</b></p>
|
||||||
|
</div>
|
||||||
|
<div class="module-card">
|
||||||
|
<span class="icon">链</span>
|
||||||
|
<h3>邀请链接</h3>
|
||||||
|
<p data-invite-link>邀请链接加载中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/member-admin-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>加入家谱 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a class="active" href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-families.html">返回我的家谱</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Join Family</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>加入家谱</h1>
|
||||||
|
<p>
|
||||||
|
输入亲人分享的邀请码,提交后进入个人中心消息流程等待管理员审核。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="join-genealogy.html"
|
||||||
|
>提交新申请</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-create-family.html">创建家谱</a
|
||||||
|
><a class="active" href="profile-join-family.html">加入家谱</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>我的加入申请</h2>
|
||||||
|
<div class="module-list" data-join-apply-list="mine">
|
||||||
|
<a class="module-row" href="join-genealogy.html">
|
||||||
|
<div>
|
||||||
|
<h3>提交新的加入申请</h3>
|
||||||
|
<p>输入家谱 ID 和关系说明,等待管理员审核。</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">去申请</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/join-apply-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>入谱审核 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a class="active" href="profile-join-review.html">入谱审核</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-messages.html">返回消息</a
|
||||||
|
><a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="#"
|
||||||
|
data-layer-confirm="确认批量处理当前审核申请?"
|
||||||
|
data-confirm-title="全部处理"
|
||||||
|
>全部处理</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Review</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>入谱审核</h1>
|
||||||
|
<p>
|
||||||
|
个人中心专用审核页,处理加入家谱、绑定账号和成员资料补全申请。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-messages.html">消息中心</a
|
||||||
|
><a class="active" href="profile-join-review.html">入谱审核</a
|
||||||
|
><a href="profile-invite.html">邀请家人</a
|
||||||
|
><a href="profile-admin-permissions.html">管理员权限</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>待审核申请</h2>
|
||||||
|
<div class="module-list" data-join-apply-list="pending">
|
||||||
|
<a class="module-row" href="profile-join-review.html"
|
||||||
|
><div>
|
||||||
|
<h3>某某人申请加入四川武胜汤氏族</h3>
|
||||||
|
<p>提交时间:2026.05.26 · 关系说明待确认</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">审核</span></a
|
||||||
|
><a class="module-row" href="profile-join-review.html"
|
||||||
|
><div>
|
||||||
|
<h3>张三申请绑定成员账号</h3>
|
||||||
|
<p>需要核对手机号和成员资料</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">处理</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>审核操作</h2>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="#"
|
||||||
|
data-layer-confirm="同意当前入谱申请?"
|
||||||
|
data-confirm-title="审核通过"
|
||||||
|
>同意</a
|
||||||
|
><a
|
||||||
|
class="btn ghost magnetic"
|
||||||
|
href="#"
|
||||||
|
data-layer-prompt="请输入拒绝原因"
|
||||||
|
data-prompt-title="拒绝申请"
|
||||||
|
data-prompt-type="textarea"
|
||||||
|
>拒绝</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/join-apply-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>添加备忘 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-memo-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-memo.html">备忘录</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-memo.html">返回备忘录</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="memo-edit-form">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Memo Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>添加备忘</h1>
|
||||||
|
<p>保存人情往来、家族事务、纪念事项和附件图片。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-growth.html">成长日志</a
|
||||||
|
><a class="active" href="profile-memo.html">备忘录</a
|
||||||
|
><a href="profile-gift.html">贺礼邀请</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>备忘内容</h2>
|
||||||
|
<form id="memo-edit-form" class="editor-form layui-form" data-memo-form>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="memoTitle">姓名 / 标题</label
|
||||||
|
><input
|
||||||
|
id="memoTitle"
|
||||||
|
name="memoTitle"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入姓名或标题"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="memoContent">内容</label
|
||||||
|
><textarea
|
||||||
|
id="memoContent"
|
||||||
|
name="memoContent"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="memoRemindTime">提醒时间</label>
|
||||||
|
<input id="memoRemindTime" name="remindTime" type="text" placeholder="例如 2026-08-01 09:00:00" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="memoCompleted">完成状态</label>
|
||||||
|
<select id="memoCompleted" name="completed">
|
||||||
|
<option value="0">未完成</option>
|
||||||
|
<option value="1">已完成</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="memoMediaOssIds">附件 OSS ID</label>
|
||||||
|
<input id="memoMediaOssIds" name="mediaOssIds" type="text" placeholder="多个附件 ID 用英文逗号分隔" />
|
||||||
|
<!-- 公共上传脚本会调用 /files/upload 并追加 OSS ID -->
|
||||||
|
<label class="upload-control" for="memoMediaFile">添加图片</label>
|
||||||
|
<input id="memoMediaFile" class="upload-input" type="file" accept="image/*" data-upload-target="#memoMediaOssIds" data-upload-status="#memoMediaStatus" data-upload-multiple="true" />
|
||||||
|
<p id="memoMediaStatus" class="upload-status">未选择文件</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-memo.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/upload-pages.js"></script>
|
||||||
|
<script src="public/js/memo-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>人情薄 / 备忘录 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-memo-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-memo.html">备忘录</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-memo-edit.html"
|
||||||
|
>发布备忘录</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Memo</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>人情薄 / 备忘录</h1>
|
||||||
|
<p>保存亲友往来、家族事务、纪念事项和待办提醒。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-growth.html">成长日志</a
|
||||||
|
><a class="active" href="profile-memo.html">备忘录</a
|
||||||
|
><a href="profile-gift.html">贺礼邀请</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>备忘录</h2>
|
||||||
|
<!-- 备忘录列表由 /memos 接口渲染 -->
|
||||||
|
<div class="module-list" data-memo-list>
|
||||||
|
<div class="api-empty">备忘录加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>添加备忘</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>姓名 / 标题</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-memo-edit.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>内容</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-memo-edit.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>附件</span><b>可添加图片</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-msg="请选择要上传的附件"
|
||||||
|
>添加</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/memo-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>添加功德人 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-merit-edit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-merit.html">功德录</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-merit.html">返回功德录</a
|
||||||
|
><button class="btn primary magnetic" type="submit" form="merit-edit-form">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Merit Editor</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>添加功德人</h1>
|
||||||
|
<p>
|
||||||
|
记录功德人姓名、事迹、时间和图片资料,正文使用富文本编辑器。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-merit.html">功德录</a
|
||||||
|
><a href="profile-gift.html">贺礼邀请</a
|
||||||
|
><a href="profile-growth.html">成长日志</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>功德资料</h2>
|
||||||
|
<form id="merit-edit-form" class="editor-form layui-form" data-merit-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritName">姓名</label
|
||||||
|
><input
|
||||||
|
id="meritName"
|
||||||
|
name="donorName"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入姓名"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritDate">日期</label
|
||||||
|
><input
|
||||||
|
id="meritDate"
|
||||||
|
name="meritTime"
|
||||||
|
type="text"
|
||||||
|
placeholder="请选择日期"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritTitle">功德标题</label>
|
||||||
|
<input id="meritTitle" name="meritTitle" type="text" placeholder="请输入功德标题" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritContent">事迹内容</label
|
||||||
|
><textarea
|
||||||
|
id="meritContent"
|
||||||
|
name="meritContent"
|
||||||
|
class="js-rich-editor"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritType">功德类型</label>
|
||||||
|
<select id="meritType" name="meritType">
|
||||||
|
<option value="donation">捐赠</option>
|
||||||
|
<option value="service">义务服务</option>
|
||||||
|
<option value="other">其他</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="meritAmount">金额</label>
|
||||||
|
<input id="meritAmount" name="amount" type="number" step="0.01" placeholder="请输入金额" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">保存</button
|
||||||
|
><a class="btn ghost magnetic" href="profile-merit.html"
|
||||||
|
>取消</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/ke/kindeditor.min.js"></script>
|
||||||
|
<script src="public/js/rich-editor.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/ceremony-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>功德录 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-merit-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-merit.html">功德录</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-merit-edit.html"
|
||||||
|
>添加功德人</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Merit</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>功德录</h1>
|
||||||
|
<p>记录功德人、事迹、时间和相关图片,沉淀家族贡献。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a class="active" href="profile-merit.html">功德录</a
|
||||||
|
><a href="profile-gift.html">贺礼邀请</a
|
||||||
|
><a href="profile-growth.html">成长日志</a
|
||||||
|
><a href="profile-memo.html">备忘录</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>功德人</h2>
|
||||||
|
<!-- 功德记录由 /merit-records 接口渲染 -->
|
||||||
|
<div class="module-list" data-merit-list>
|
||||||
|
<div class="api-empty">功德记录加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>添加功德人</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>姓名</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-merit-edit.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>内容</span><b>待输入</b
|
||||||
|
><a class="link-btn" href="profile-merit-edit.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>附件</span><b>可添加图片</b
|
||||||
|
><a
|
||||||
|
class="link-btn"
|
||||||
|
href="#"
|
||||||
|
data-layer-msg="请选择要上传的附件"
|
||||||
|
>添加</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/ceremony-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>消息中心 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a class="active" href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Messages</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>消息中心</h1>
|
||||||
|
<p>
|
||||||
|
处理入谱申请、贺礼邀请、资料提醒和系统通知,减少家族协作中的遗漏。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn ghost magnetic" href="profile.html">返回个人中心</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>待处理</h2>
|
||||||
|
<div class="module-list" data-notification-list>
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>某某人申请加入四川武胜汤氏族</h3>
|
||||||
|
<p>2026.05.25 09:20 · 需要管理员审核</p>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<a class="btn ghost" href="profile-messages.html">拒绝</a
|
||||||
|
><a class="btn primary" href="profile-messages.html"
|
||||||
|
>同意</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="module-row" href="profile-content.html"
|
||||||
|
><div>
|
||||||
|
<h3>张三&里斯于 2023年3月23日举办婚礼</h3>
|
||||||
|
<p>贺礼邀请 · 待确认公开状态</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">查看</span></a
|
||||||
|
>
|
||||||
|
<a class="module-row" href="profile-data-reminders.html"
|
||||||
|
><div>
|
||||||
|
<h3>2 位成员资料待完善</h3>
|
||||||
|
<p>头像、出生日期、亲属关系信息不完整</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">处理</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>系统通知</h2>
|
||||||
|
<div class="module-grid two">
|
||||||
|
<button class="module-card module-action-card" type="button" data-notification-read-all>
|
||||||
|
<span class="icon">通</span>
|
||||||
|
<h3>全部标记已读</h3>
|
||||||
|
<p>清理已处理提醒,保留重要审核消息。</p>
|
||||||
|
</button>
|
||||||
|
<button class="module-card module-action-card" type="button" data-notification-refresh>
|
||||||
|
<span class="icon">刷</span>
|
||||||
|
<h3>刷新消息</h3>
|
||||||
|
<p>同步最新入谱申请、评论和内容通知。</p>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/notification-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>安全设置 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-security-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a class="active" href="profile-security.html">安全设置</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-services.html">返回服务中心</a
|
||||||
|
><a class="btn primary magnetic" href="#" data-security-logout>退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Security</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>安全设置</h1>
|
||||||
|
<p>维护登录密码、手机号、微信快捷登录和账号安全提醒。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a class="active" href="profile-security.html">安全设置</a
|
||||||
|
><a href="profile-feedback.html">意见反馈</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>账号安全</h2>
|
||||||
|
<!-- 修改密码表单:字段对应 PasswordChangeBody。 -->
|
||||||
|
<form class="editor-form security-form" data-security-form="password">
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="oldPassword">当前密码</label>
|
||||||
|
<input id="oldPassword" name="oldPassword" type="password" autocomplete="current-password" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="newPassword">新密码</label>
|
||||||
|
<input id="newPassword" name="newPassword" type="password" autocomplete="new-password" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="confirmPassword">确认新密码</label>
|
||||||
|
<input id="confirmPassword" name="confirmPassword" type="password" autocomplete="new-password" required />
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">修改密码</button>
|
||||||
|
<span class="api-status" data-security-status>等待提交</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>换绑手机号</h2>
|
||||||
|
<!-- 换绑手机号表单:字段对应 PhoneChangeBody。 -->
|
||||||
|
<form class="editor-form security-form" data-security-form="phone">
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="newPhone">新手机号</label>
|
||||||
|
<input id="newPhone" name="newPhone" type="tel" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="phoneSmsCode">短信验证码</label>
|
||||||
|
<input id="phoneSmsCode" name="smsCode" type="text" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="phoneValidToken">滑动验证票据</label>
|
||||||
|
<input id="phoneValidToken" name="validToken" type="text" placeholder="可选,由验证组件返回" />
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">确认换绑</button>
|
||||||
|
<span class="api-status" data-security-status>等待验证码</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>短信登录校验</h2>
|
||||||
|
<!-- 短信登录表单:用于接入 /genealogy/app/auth/login/sms。 -->
|
||||||
|
<form class="editor-form security-form" data-security-form="sms-login">
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="loginPhone">手机号</label>
|
||||||
|
<input id="loginPhone" name="phone" type="tel" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="loginSmsCode">短信验证码</label>
|
||||||
|
<input id="loginSmsCode" name="smsCode" type="text" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="loginValidToken">滑动验证票据</label>
|
||||||
|
<input id="loginValidToken" name="validToken" type="text" placeholder="可选,由验证组件返回" />
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">短信登录验证</button>
|
||||||
|
<span class="api-status" data-security-status>等待提交</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel security-danger">
|
||||||
|
<h2>注销账号</h2>
|
||||||
|
<!-- 注销账号属于敏感操作,必须填写当前密码并输入确认文本。 -->
|
||||||
|
<form class="editor-form security-form" data-security-form="deactivate">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="deactivatePassword">当前密码</label>
|
||||||
|
<input id="deactivatePassword" name="password" type="password" autocomplete="current-password" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="deactivateReason">注销原因</label>
|
||||||
|
<textarea id="deactivateReason" name="reason" placeholder="可选"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="confirmText">确认文本</label>
|
||||||
|
<input id="confirmText" name="confirmText" type="text" placeholder="请输入:确认注销" required />
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">提交注销</button>
|
||||||
|
<button class="btn ghost magnetic" type="button" data-security-logout>退出登录</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/md5.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/security-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>帮助与服务 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-vip-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a
|
||||||
|
><a href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a
|
||||||
|
><a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a class="active" href="help.html">帮助中心</a
|
||||||
|
><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile.html">个人中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Services</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>帮助与服务</h1>
|
||||||
|
<p>
|
||||||
|
整合 APP
|
||||||
|
“我的”页中的应用推广、意见反馈、安全设置、帮助中心和应用分享。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn primary magnetic" href="profile-feedback.html"
|
||||||
|
>提交反馈</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a href="profile-messages.html">消息中心</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-data.html">个人资料</a
|
||||||
|
><a class="active" href="profile-services.html">帮助与服务</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>常用服务</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<a class="module-card tilt-card" href="profile-share.html"
|
||||||
|
><span class="icon">享</span>
|
||||||
|
<h3>应用分享</h3>
|
||||||
|
<p>邀请好友使用,了解应用下载和分享奖励。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-feedback.html"
|
||||||
|
><span class="icon">馈</span>
|
||||||
|
<h3>意见反馈</h3>
|
||||||
|
<p>提交产品问题、资料异常和改进建议。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="profile-security.html"
|
||||||
|
><span class="icon">安</span>
|
||||||
|
<h3>安全设置</h3>
|
||||||
|
<p>修改密码、找回账号、维护登录安全。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="help.html"
|
||||||
|
><span class="icon">助</span>
|
||||||
|
<h3>帮助中心</h3>
|
||||||
|
<p>查看新手常见问题、家谱优势和编辑字辈说明。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="app.html"
|
||||||
|
><span class="icon">下</span>
|
||||||
|
<h3>应用下载</h3>
|
||||||
|
<p>安装移动端,继续处理图片、视频和成员资料。</p></a
|
||||||
|
>
|
||||||
|
<a class="module-card tilt-card" href="about.html"
|
||||||
|
><span class="icon">联</span>
|
||||||
|
<h3>联系我们</h3>
|
||||||
|
<p>查看平台介绍、客服信息和服务说明。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 会员套餐区域:套餐列表和订单创建字段来自 APP.openapi.json 的 VIP 接口。 -->
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>会员服务</h2>
|
||||||
|
<p>选择适合当前家谱的会员套餐,创建订单后继续完成支付。</p>
|
||||||
|
<div class="vip-package-list" data-vip-package-list>
|
||||||
|
<div class="api-empty">会员套餐加载中</div>
|
||||||
|
</div>
|
||||||
|
<form class="editor-form vip-order-form" data-vip-order-form>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="packageId">套餐 ID</label>
|
||||||
|
<input id="packageId" name="packageId" type="number" placeholder="请先选择套餐" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="genealogyId">家谱 ID</label>
|
||||||
|
<input id="genealogyId" name="genealogyId" type="number" placeholder="可选,指定要开通的家谱" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="payType">支付方式</label>
|
||||||
|
<select id="payType" name="payType">
|
||||||
|
<option value="wechat">微信支付</option>
|
||||||
|
<option value="alipay">支付宝</option>
|
||||||
|
<option value="balance">余额支付</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary magnetic" type="submit">创建会员订单</button>
|
||||||
|
<span class="api-status" data-vip-order-status>等待选择套餐</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<!-- 会员订单区域:展示 GET /genealogy/app/vip/orders 的历史记录。 -->
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>会员订单</h2>
|
||||||
|
<div class="module-list" data-vip-order-list>
|
||||||
|
<div class="api-empty">会员订单加载中</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>推荐阅读</h2>
|
||||||
|
<div class="module-list">
|
||||||
|
<a class="module-row" href="help.html"
|
||||||
|
><div>
|
||||||
|
<h3>新手常见问题</h3>
|
||||||
|
<p>注册登录、创建家谱、邀请成员、资料审核等流程。</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">查看</span></a
|
||||||
|
><a class="module-row" href="profile-article.html"
|
||||||
|
><div>
|
||||||
|
<h3>为什么家谱不只是一本名册</h3>
|
||||||
|
<p>理解关系、故事和协作维护。</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">阅读</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/vip-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>应用分享 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-family-share-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a class="active" href="profile-share.html">应用分享</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-services.html">返回服务中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-share.html"
|
||||||
|
>立即分享</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Share</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>应用分享</h1>
|
||||||
|
<p>邀请好友创建和维护家谱,查看应用下载、分享奖励和推广入口。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-services.html">帮助与服务</a
|
||||||
|
><a class="active" href="profile-share.html">应用分享</a
|
||||||
|
><a href="profile-feedback.html">意见反馈</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>邀请好友奖励</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<div class="module-card">
|
||||||
|
<span class="icon">享</span>
|
||||||
|
<h3>每邀请一位好友</h3>
|
||||||
|
<p data-member-overview>分享概览加载中...</p>
|
||||||
|
</div>
|
||||||
|
<div class="module-card">
|
||||||
|
<span class="icon">码</span>
|
||||||
|
<h3>分享二维码</h3>
|
||||||
|
<p data-invite-link>分享链接加载中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>分享记录</h2>
|
||||||
|
<div class="module-list">
|
||||||
|
<div class="module-row">
|
||||||
|
<div>
|
||||||
|
<h3>本月邀请</h3>
|
||||||
|
<p>3 人访问 · 1 人完成注册</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">查看</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/member-admin-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>世系图 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module" data-lineage-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-families.html">我的家谱</a
|
||||||
|
><a class="active" href="profile-family-admin.html">家族管理</a
|
||||||
|
><a href="profile-data.html">个人资料</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-family-home.html">返回家谱主页</a
|
||||||
|
><a class="btn primary magnetic" href="profile-data.html">添加成员</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Tree Mode</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>世系图</h1>
|
||||||
|
<p>
|
||||||
|
个人中心内的树谱管理视图,用于查看成员关系、添加亲属和搜索成员。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="btn ghost magnetic" href="profile-family-admin.html"
|
||||||
|
>管理世代</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-family-home.html">家谱主页</a
|
||||||
|
><a class="active" href="profile-tree.html">世系图</a
|
||||||
|
><a href="profile-generation.html">字辈谱</a
|
||||||
|
><a href="profile-family-admin.html">家族管理</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>树谱操作</h2>
|
||||||
|
<div class="module-grid">
|
||||||
|
<button class="module-card module-action-card tilt-card" type="button" data-lineage-relation="parents"
|
||||||
|
><span class="icon">父</span>
|
||||||
|
<h3>添加父亲 / 母亲</h3>
|
||||||
|
<p>先选择成员,再为当前成员补充上一代关系。</p></button
|
||||||
|
><button class="module-card module-action-card tilt-card" type="button" data-lineage-relation="spouses"
|
||||||
|
><span class="icon">配</span>
|
||||||
|
<h3>添加配偶</h3>
|
||||||
|
<p>先选择成员,再维护配偶关系。</p></button
|
||||||
|
><button
|
||||||
|
class="module-card module-action-card tilt-card"
|
||||||
|
type="button"
|
||||||
|
data-lineage-relation="children"
|
||||||
|
><span class="icon">排</span>
|
||||||
|
<h3>添加子女</h3>
|
||||||
|
<p>先选择成员,再为当前成员补充下一代关系。</p></button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>世系树</h2>
|
||||||
|
<!-- 世系树由 public/js/lineage-pages.js 按接口数据渲染 -->
|
||||||
|
<div class="lineage-tree-wrap" data-lineage-tree>
|
||||||
|
<div class="api-empty">世系树加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>成员搜索</h2>
|
||||||
|
<div class="lineage-toolbar">
|
||||||
|
<input type="search" data-lineage-keyword placeholder="输入姓名或字辈搜索" />
|
||||||
|
<button class="btn primary" type="button" data-lineage-search>搜索</button>
|
||||||
|
</div>
|
||||||
|
<!-- 成员列表由世系人物分页接口渲染 -->
|
||||||
|
<div class="module-list" data-lineage-list>
|
||||||
|
<div class="api-empty">成员加载中...</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>成员详情</h2>
|
||||||
|
<!-- 点击成员列表或世系树节点后渲染详情 -->
|
||||||
|
<div data-lineage-detail>
|
||||||
|
<div class="api-empty">请选择一个成员查看资料</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>新增成员</h2>
|
||||||
|
<form class="editor-form" data-lineage-form>
|
||||||
|
<!-- 字段名称对应 APP.openapi.json 的 LineagePersonBody -->
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-person-name">姓名</label>
|
||||||
|
<input id="lineage-person-name" name="personName" type="text" placeholder="请输入成员姓名" required />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-sex">性别</label>
|
||||||
|
<select id="lineage-sex" name="sex">
|
||||||
|
<option value="0">男</option>
|
||||||
|
<option value="1">女</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-generation-no">世代序号</label>
|
||||||
|
<input id="lineage-generation-no" name="generationNo" type="number" min="1" placeholder="例如 3" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-generation-name">字辈</label>
|
||||||
|
<input id="lineage-generation-name" name="generationName" type="text" placeholder="例如 忠" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-person-no">人物编号</label>
|
||||||
|
<input id="lineage-person-no" name="personNo" type="text" placeholder="可选" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-alias-name">别名</label>
|
||||||
|
<input id="lineage-alias-name" name="aliasName" type="text" placeholder="可选" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-two">
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-birth-date">出生日期</label>
|
||||||
|
<input id="lineage-birth-date" name="birthDate" type="date" />
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-death-date">逝世日期</label>
|
||||||
|
<input id="lineage-death-date" name="deathDate" type="date" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-field">
|
||||||
|
<label for="lineage-introduction">简介</label>
|
||||||
|
<textarea id="lineage-introduction" name="introduction" placeholder="记录成员生平简介"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-actions">
|
||||||
|
<button class="btn primary" type="submit">保存成员</button>
|
||||||
|
<button class="btn ghost" type="reset">清空</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/lineage-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>家族视频 - 个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile-module.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile-module">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" /><span class="brand-text">个人中心</span></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a class="active" href="profile-video.html">视频</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="profile-content.html">返回发布中心</a
|
||||||
|
><a class="btn primary magnetic" href="profile-video.html"
|
||||||
|
>发布视频</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="module-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="module-kicker">Video</div>
|
||||||
|
<div class="module-title-row">
|
||||||
|
<div>
|
||||||
|
<h1>家族视频</h1>
|
||||||
|
<p>发布和管理家族视频,支持标题、描述、封面和上传状态维护。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container module-layout">
|
||||||
|
<aside class="module-nav">
|
||||||
|
<a href="profile-content.html">内容发布</a
|
||||||
|
><a href="profile-album.html">相册</a
|
||||||
|
><a class="active" href="profile-video.html">视频</a
|
||||||
|
><a href="profile-family-home.html">家谱主页</a>
|
||||||
|
</aside>
|
||||||
|
<div class="module-main">
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>视频列表</h2>
|
||||||
|
<div class="module-list">
|
||||||
|
<a class="module-row" href="profile-video.html"
|
||||||
|
><div>
|
||||||
|
<h3>四川武胜汤氏族视频</h3>
|
||||||
|
<p>已发布 · 2026.05 · 可编辑</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">管理</span></a
|
||||||
|
><a class="module-row" href="profile-video.html"
|
||||||
|
><div>
|
||||||
|
<h3>祭祖活动记录</h3>
|
||||||
|
<p>草稿 · 等待上传视频</p>
|
||||||
|
</div>
|
||||||
|
<span class="pill">继续</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="module-panel">
|
||||||
|
<h2>发布视频</h2>
|
||||||
|
<div class="form-like">
|
||||||
|
<p>
|
||||||
|
<span>视频标题</span><b>必填</b
|
||||||
|
><a class="link-btn" href="profile-video.html">填写</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>视频描述</span><b>0/200</b
|
||||||
|
><a class="link-btn" href="profile-video.html">编辑</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>上传视频</span><b>未上传</b
|
||||||
|
><a class="link-btn" href="profile-video.html">选择</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>个人中心 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/layui/css/layui.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/profile.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-profile" data-profile-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="profile.html">首页</a>
|
||||||
|
<a href="profile-families.html">数字家谱</a>
|
||||||
|
<a href="plaza.html">家谱广场</a>
|
||||||
|
<a href="profile-content.html">家族文化</a>
|
||||||
|
<a href="surname.html">姓氏百科</a>
|
||||||
|
<a href="app.html">应用下载</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a class="active" href="profile.html">个人中心</a>
|
||||||
|
<a class="btn primary magnetic" href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="profile-hero">
|
||||||
|
<div class="container profile-hero-grid">
|
||||||
|
<div class="profile-card tilt-card">
|
||||||
|
<div class="avatar-wrap">
|
||||||
|
<div class="avatar" data-profile-text="avatarText">鹿</div>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
<div class="profile-info">
|
||||||
|
<div class="eyebrow">Personal Center</div>
|
||||||
|
<h1 data-profile-text="displayName">鹿野 Loyel</h1>
|
||||||
|
<p>
|
||||||
|
管理家谱、亲属资料、家族内容和协作消息。APP
|
||||||
|
里的核心功能都收纳在这里,适合 PC 端集中处理。
|
||||||
|
</p>
|
||||||
|
<div class="profile-tags">
|
||||||
|
<span>血亲</span><span>第二代 顺字辈</span
|
||||||
|
><span>已绑定账号</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="profile-stats tilt-card">
|
||||||
|
<div><strong>2</strong><span>我的家谱</span></div>
|
||||||
|
<div><strong>7</strong><span>待处理</span></div>
|
||||||
|
<div><strong>18</strong><span>已发布内容</span></div>
|
||||||
|
<div><strong>86%</strong><span>资料完善度</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section dashboard-section">
|
||||||
|
<div class="container dashboard-layout">
|
||||||
|
<aside class="dashboard-side">
|
||||||
|
<div class="side-card user-actions tilt-card">
|
||||||
|
<h2>账户入口</h2>
|
||||||
|
<a href="profile-data.html"
|
||||||
|
><span>个人资料</span><b>完善成员档案</b></a
|
||||||
|
>
|
||||||
|
<a href="profile-messages.html"
|
||||||
|
><span>消息中心</span><b>审核、邀请与提醒</b></a
|
||||||
|
>
|
||||||
|
<a href="profile-services.html"
|
||||||
|
><span>帮助与服务</span><b>帮助、反馈、推广</b></a
|
||||||
|
>
|
||||||
|
<a class="logout-link" href="#logout" data-logout-open
|
||||||
|
><span>退出登录</span><b>返回登录页</b></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="side-card todo-card tilt-card" id="messages">
|
||||||
|
<div class="card-head">
|
||||||
|
<h2>待办消息</h2>
|
||||||
|
<span>7 条</span>
|
||||||
|
</div>
|
||||||
|
<div class="todo-list">
|
||||||
|
<a href="profile-join-review.html"
|
||||||
|
><b>入谱申请</b><span>3 人等待审核</span></a
|
||||||
|
>
|
||||||
|
<a href="profile-gift.html"
|
||||||
|
><b>贺礼邀请</b><span>2 条需要确认</span></a
|
||||||
|
>
|
||||||
|
<a href="profile-data-reminders.html"
|
||||||
|
><b>资料提醒</b><span>2 位成员待完善</span></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<div class="dashboard-main">
|
||||||
|
<section class="panel my-family-panel" id="families">
|
||||||
|
<div class="panel-head">
|
||||||
|
<div>
|
||||||
|
<h2>我的家谱</h2>
|
||||||
|
<p>
|
||||||
|
对应 APP
|
||||||
|
首页和家谱主页,进入后可查看家谱主页、世系图、相册和家族圈。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="link-btn" href="profile-families.html">查看全部</a>
|
||||||
|
<div class="toolbar">
|
||||||
|
<a
|
||||||
|
class="btn primary magnetic"
|
||||||
|
href="profile-create-family.html"
|
||||||
|
>创建家谱</a
|
||||||
|
><a class="btn ghost magnetic" href="profile-join-family.html"
|
||||||
|
>加入家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="family-grid">
|
||||||
|
<a
|
||||||
|
class="family-card tilt-card"
|
||||||
|
href="profile-family-home.html"
|
||||||
|
>
|
||||||
|
<div class="book-cover">汤氏<br />家谱</div>
|
||||||
|
<div>
|
||||||
|
<h3>四川武胜汤氏族</h3>
|
||||||
|
<p>
|
||||||
|
共修入 7 人,激活 7 人。你是创建者,可管理内容和成员权限。
|
||||||
|
</p>
|
||||||
|
<div class="mini-actions">
|
||||||
|
<span>家谱主页</span><span>家族圈</span
|
||||||
|
><span>管理员</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="family-card tilt-card"
|
||||||
|
href="profile-family-home.html"
|
||||||
|
>
|
||||||
|
<div class="book-cover alt">刘氏<br />家谱</div>
|
||||||
|
<div>
|
||||||
|
<h3>四川达州刘氏族</h3>
|
||||||
|
<p>共修入 7 人,近期有 2 条内容更新等待查看。</p>
|
||||||
|
<div class="mini-actions">
|
||||||
|
<span>世系图</span><span>相册</span><span>消息</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel" id="management">
|
||||||
|
<div class="panel-head compact">
|
||||||
|
<div>
|
||||||
|
<h2>家族管理</h2>
|
||||||
|
<p>
|
||||||
|
把 APP 里的世代、管理员、权限、入谱审核集中到一个管理区。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="link-btn" href="profile-family-admin.html"
|
||||||
|
>进入管理</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="feature-grid management-grid">
|
||||||
|
<a class="feature-tile tilt-card" href="profile-families.html"
|
||||||
|
><span>世</span>
|
||||||
|
<h3>世系图</h3>
|
||||||
|
<p>查看成员世系、搜索成员、进入树谱模式。</p></a
|
||||||
|
>
|
||||||
|
<a class="feature-tile tilt-card" href="profile-families.html"
|
||||||
|
><span>辈</span>
|
||||||
|
<h3>字辈谱</h3>
|
||||||
|
<p>管理字辈、统计各代人数和成员分布。</p></a
|
||||||
|
>
|
||||||
|
<a class="feature-tile tilt-card" href="profile-generation.html"
|
||||||
|
><span>代</span>
|
||||||
|
<h3>管理世代</h3>
|
||||||
|
<p>设置世代、调整始祖世代、维护排行。</p></a
|
||||||
|
>
|
||||||
|
<a class="feature-tile tilt-card" href="profile-messages.html"
|
||||||
|
><span>审</span>
|
||||||
|
<h3>入谱审核</h3>
|
||||||
|
<p>处理加入家谱、成员绑定和资料审核。</p></a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="feature-tile tilt-card"
|
||||||
|
href="profile-admin-permissions.html"
|
||||||
|
><span>权</span>
|
||||||
|
<h3>管理员权限</h3>
|
||||||
|
<p>分配全权、全系、支系管理员权限。</p></a
|
||||||
|
>
|
||||||
|
<a class="feature-tile tilt-card" href="profile-invite.html"
|
||||||
|
><span>邀</span>
|
||||||
|
<h3>邀请家人</h3>
|
||||||
|
<p>生成邀请入口,引导亲人激活使用。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel" id="content">
|
||||||
|
<div class="panel-head compact">
|
||||||
|
<div>
|
||||||
|
<h2>内容发布</h2>
|
||||||
|
<p>
|
||||||
|
对应 APP
|
||||||
|
家谱主页中的谱文、视频、相册、功德录、贺礼邀请、成长日志等内容入口。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a class="link-btn" href="profile-content.html">发布中心</a>
|
||||||
|
</div>
|
||||||
|
<div class="content-grid">
|
||||||
|
<a
|
||||||
|
class="content-tile large tilt-card"
|
||||||
|
href="profile-article.html"
|
||||||
|
><span>谱文</span>
|
||||||
|
<h3>撰写谱文与族史</h3>
|
||||||
|
<p>沉淀族训、谱序、谱论、恩荣录等家族文献。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-album.html"
|
||||||
|
><span>相册</span>
|
||||||
|
<h3>家族相册</h3>
|
||||||
|
<p>新建相册、上传照片、编辑封面。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-video.html"
|
||||||
|
><span>视频</span>
|
||||||
|
<h3>家族视频</h3>
|
||||||
|
<p>发布视频、管理家族影像。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-merit.html"
|
||||||
|
><span>功德</span>
|
||||||
|
<h3>功德录</h3>
|
||||||
|
<p>记录功德人、事迹与纪念内容。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-gift.html"
|
||||||
|
><span>贺礼</span>
|
||||||
|
<h3>贺礼邀请</h3>
|
||||||
|
<p>管理婚礼、生日、升学等贺礼。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-feed.html"
|
||||||
|
><span>动态</span>
|
||||||
|
<h3>发布动态</h3>
|
||||||
|
<p>面向家族圈发布图文近况。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-growth.html"
|
||||||
|
><span>日志</span>
|
||||||
|
<h3>成长日志</h3>
|
||||||
|
<p>记录成员成长和人生节点。</p></a
|
||||||
|
>
|
||||||
|
<a class="content-tile tilt-card" href="profile-memo.html"
|
||||||
|
><span>备忘</span>
|
||||||
|
<h3>人亲簿 / 备忘录</h3>
|
||||||
|
<p>保存亲友往来和家族事务。</p></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="profile-data-layout" id="profile-data">
|
||||||
|
<div class="panel data-panel">
|
||||||
|
<div class="panel-head compact">
|
||||||
|
<div>
|
||||||
|
<h2>个人资料</h2>
|
||||||
|
<p>来自 APP 的个人资料、亲属、完善资料和绑定账号流程。</p>
|
||||||
|
</div>
|
||||||
|
<a class="link-btn" href="profile-data.html">编辑资料</a>
|
||||||
|
</div>
|
||||||
|
<div class="data-list">
|
||||||
|
<p><span>绑定账号</span><b data-profile-text="phone">已绑定</b></p>
|
||||||
|
<p><span>姓名</span><b data-profile-text="displayName">鹿野 Loyel</b></p>
|
||||||
|
<p><span>出生日期</span><b data-profile-text="birthday">待填写</b></p>
|
||||||
|
<p><span>现居地区</span><b data-profile-text="regionText">待填写</b></p>
|
||||||
|
<p><span>亲属关系</span><b>父亲 2 人</b></p>
|
||||||
|
<p><span>补充资料</span><b>待完善 4 项</b></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel service-panel" id="services">
|
||||||
|
<div class="panel-head compact">
|
||||||
|
<div>
|
||||||
|
<h2>帮助与服务</h2>
|
||||||
|
<p>我的页面中的常用功能。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-grid">
|
||||||
|
<a href="profile-share.html">应用分享</a>
|
||||||
|
<a href="profile-feedback.html">意见反馈</a>
|
||||||
|
<a href="help.html">帮助中心</a>
|
||||||
|
<a href="profile-security.html">安全设置</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="profile.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a href="profile-families.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a href="profile-content.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a
|
||||||
|
><a href="profile-article.html">家谱知识</a
|
||||||
|
><a href="profile-messages.html">平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<div class="logout-modal" id="logoutModal" aria-hidden="true">
|
||||||
|
<div class="logout-modal-backdrop" data-logout-close></div>
|
||||||
|
<div
|
||||||
|
class="logout-dialog"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby="logoutTitle"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="logout-close"
|
||||||
|
type="button"
|
||||||
|
data-logout-close
|
||||||
|
aria-label="关闭"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
<span class="logout-icon">退</span>
|
||||||
|
<h2 id="logoutTitle">确认退出登录?</h2>
|
||||||
|
<p>退出后需要重新登录,才能继续管理家谱、审核消息和编辑资料。</p>
|
||||||
|
<div class="logout-actions">
|
||||||
|
<button class="btn ghost magnetic" type="button" data-logout-close>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<a class="btn primary magnetic" href="login.html">确认退出</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="public/js/jquery360.js"></script>
|
||||||
|
<script src="public/layui/layui.js"></script>
|
||||||
|
<script src="public/js/lay-config.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="utils/StorageUtil.js"></script>
|
||||||
|
<script src="utils/FormUtil.js"></script>
|
||||||
|
<script src="utils/RequestUtil.js"></script>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/profile-pages.js"></script>
|
||||||
|
<script src="public/js/profile-common.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>宣传相册 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/promo-album.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-promo-album" data-promo-album-page>
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a><a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero promo-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Public Album</div>
|
||||||
|
<h1>用公开相册展示家族故事</h1>
|
||||||
|
<p class="lead">
|
||||||
|
宣传相册用于前台展示祖屋、祠堂、家族活动、老照片和公开纪念内容,帮助访客更直观理解家族文化。
|
||||||
|
</p>
|
||||||
|
<div class="promo-tags">
|
||||||
|
<span>祖屋影像</span><span>活动纪念</span><span>公开展示</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card album-preview tilt-card">
|
||||||
|
<div class="album-photo large"></div>
|
||||||
|
<div class="album-photo"></div>
|
||||||
|
<div class="album-photo warm"></div>
|
||||||
|
<div class="album-photo green"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>相册分类</h2>
|
||||||
|
<p>把适合公开展示的影像整理成专题,让家族主页更有内容层次。</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3">
|
||||||
|
<!-- 宣传相册复用 /albums 列表接口渲染公开展示内容 -->
|
||||||
|
<div data-promo-album-list>
|
||||||
|
<div class="api-empty">相册加载中...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/api-client.js"></script>
|
||||||
|
<script src="public/js/album-pages.js"></script>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>宣传视频 - 代代相传</title>
|
||||||
|
<link rel="stylesheet" href="public/css/public.css" />
|
||||||
|
<link rel="stylesheet" href="public/css/promo-video.css" />
|
||||||
|
</head>
|
||||||
|
<body class="page-promo-video">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container nav">
|
||||||
|
<a class="brand magnetic" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="index.html">首页</a><a href="genealogy.html">数字家谱</a
|
||||||
|
><a href="plaza.html">家谱广场</a><a href="culture.html">家族文化</a
|
||||||
|
><a href="surname.html">姓氏百科</a><a href="app.html">应用下载</a
|
||||||
|
><a href="help.html">帮助中心</a><a href="about.html">关于我们</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<a href="login.html">登录</a><a href="register.html">注册</a
|
||||||
|
><a class="btn primary magnetic" href="create-genealogy.html"
|
||||||
|
>创建家谱</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="inner-hero promo-hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">Public Video</div>
|
||||||
|
<h1>用宣传视频讲述家族文化</h1>
|
||||||
|
<p class="lead">
|
||||||
|
宣传视频用于前台展示家族活动、祠堂风貌、修谱故事和公开纪念内容,让访问者更快进入家族叙事。
|
||||||
|
</p>
|
||||||
|
<div class="promo-tags">
|
||||||
|
<span>家族介绍</span><span>活动纪念</span><span>修谱故事</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card video-preview tilt-card">
|
||||||
|
<div class="play-button"></div>
|
||||||
|
<h3>四川成都陈氏族宣传片</h3>
|
||||||
|
<p>祠堂、谱文、人物与家风的公开展示。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section alt">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<h2>视频专题</h2>
|
||||||
|
<p>把适合公开传播的视频整理成栏目,增强家谱主页的展示力。</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3">
|
||||||
|
<div class="card soft video-card tilt-card">
|
||||||
|
<h3>家族介绍</h3>
|
||||||
|
<p>概述姓氏源流、家族分布和家风传承。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft video-card tilt-card">
|
||||||
|
<h3>活动纪念</h3>
|
||||||
|
<p>展示祭祖、聚会、修谱仪式等重要时刻。</p>
|
||||||
|
</div>
|
||||||
|
<div class="card soft video-card tilt-card">
|
||||||
|
<h3>人物故事</h3>
|
||||||
|
<p>以影像记录家族人物、贡献与纪念内容。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-grid">
|
||||||
|
<div>
|
||||||
|
<a class="brand" href="index.html"
|
||||||
|
><img class="brand-logo" src="public/images/logo-light.png" alt="我们的家谱,代代相传" /></a
|
||||||
|
>
|
||||||
|
<p>一个面向家庭和宗族的数字家谱与家族文化门户。</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品入口</h4>
|
||||||
|
<a>数字家谱</a><a>家谱广场</a><a>应用下载</a><a>帮助中心</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>文化内容</h4>
|
||||||
|
<a>家族文化</a><a>姓氏百科</a><a>家谱知识</a><a>平台公告</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<p>客服电话:400-000-0000</p>
|
||||||
|
<p>邮箱:service@example.com</p>
|
||||||
|
<p>地址:中国 · 成都</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-legal">
|
||||||
|
<div>© 2026 代代相传. All rights reserved.</div>
|
||||||
|
<a href="https://beian.miit.gov.cn" target="_blank" rel="noopener">ICP备案:蜀ICP备2024044594号-1</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="public/js/page-effects.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
.about-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-tags span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-tags span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-seal {
|
||||||
|
position: relative;
|
||||||
|
min-height: 260px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(155deg, var(--green-dark), var(--green));
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-seal:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255,255,255,.08) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,.08) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .34;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seal-orb {
|
||||||
|
position: absolute;
|
||||||
|
right: 76px;
|
||||||
|
top: 40px;
|
||||||
|
width: 110px;
|
||||||
|
height: 110px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255,255,255,.16);
|
||||||
|
box-shadow: 0 0 40px rgba(255,255,255,.1);
|
||||||
|
animation: sealPulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-seal span {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255,255,255,.94);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 48px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .24s ease, background .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-seal:hover span {
|
||||||
|
transform: rotate(-8deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-seal p {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(255,255,255,.84);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.values-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.values-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-card {
|
||||||
|
min-height: 190px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -42%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.54), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .56s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-card:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f7e4dc;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 900;
|
||||||
|
transition: transform .26s ease, background .26s ease, color .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-card:hover .value-icon {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: rotate(-6deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sealPulse {
|
||||||
|
0%, 100% { opacity: .55; transform: scale(.92); }
|
||||||
|
50% { opacity: .9; transform: scale(1.08); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
.app-hero .container {
|
||||||
|
min-height: 500px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 24px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-stats span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-stats span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-shot-wrap {
|
||||||
|
position: relative;
|
||||||
|
min-height: 390px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 30px;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 18% 20%, rgba(200,59,50,.12), transparent 24%),
|
||||||
|
radial-gradient(circle at 80% 24%, rgba(71,111,99,.16), transparent 30%),
|
||||||
|
linear-gradient(135deg, #f7efe2, #edf4ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-shot-wrap:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 22px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .62);
|
||||||
|
border-radius: 22px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-orbit {
|
||||||
|
position: absolute;
|
||||||
|
right: 64px;
|
||||||
|
top: 44px;
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(196, 146, 69, .18);
|
||||||
|
animation: appOrbit 4.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-shot {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
width: 185px;
|
||||||
|
height: 380px;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: top center;
|
||||||
|
border: 8px solid #252b28;
|
||||||
|
border-radius: 28px;
|
||||||
|
box-shadow: 0 26px 60px rgba(33, 28, 22, .2);
|
||||||
|
transition: transform .3s ease, box-shadow .3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-shot.first {
|
||||||
|
animation: phoneFloatA 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-shot.second {
|
||||||
|
transform: translateY(28px);
|
||||||
|
animation: phoneFloatB 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-shot-wrap:hover .phone-shot {
|
||||||
|
box-shadow: 0 34px 70px rgba(33, 28, 22, .26);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-card {
|
||||||
|
min-height: 190px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -42%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.54), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .56s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-card:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f7e4dc;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 900;
|
||||||
|
transition: transform .26s ease, background .26s ease, color .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-feature-card:hover .app-icon {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: rotate(-6deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-promotion-section {
|
||||||
|
/* 应用推广列表承载后端推广内容,不在 JS 中写样式 */
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffaf0;
|
||||||
|
box-shadow: 0 18px 42px rgba(57, 48, 36, .08);
|
||||||
|
transition: transform .24s ease, border-color .24s ease, box-shadow .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 24px 54px rgba(57, 48, 36, .12);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card img {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
background: #f3eadc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card div {
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card h3 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card p {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-card span {
|
||||||
|
color: var(--red);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes phoneFloatA {
|
||||||
|
0%, 100% { transform: translateY(0) rotate(-1deg); }
|
||||||
|
50% { transform: translateY(-8px) rotate(1deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes phoneFloatB {
|
||||||
|
0%, 100% { transform: translateY(28px) rotate(1deg); }
|
||||||
|
50% { transform: translateY(18px) rotate(-1deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes appOrbit {
|
||||||
|
0%, 100% { opacity: .5; transform: scale(.92); }
|
||||||
|
50% { opacity: 1; transform: scale(1.08); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
.phone-shot.second { display: none; }
|
||||||
|
.promotion-list { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
.article-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover-detail {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 72% 24%, rgba(255,255,255,.35) 0 9%, transparent 10%),
|
||||||
|
linear-gradient(135deg, #e7c89e, #b94135 48%, #143d57);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover-detail:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -40%;
|
||||||
|
top: 0;
|
||||||
|
width: 34%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.3), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .58s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover-detail:hover:after { left: 112%; }
|
||||||
|
|
||||||
|
.article-cover-detail span {
|
||||||
|
width: 86px;
|
||||||
|
height: 86px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255,253,248,.94);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 44px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover-detail p {
|
||||||
|
margin: 18px 0 0;
|
||||||
|
color: rgba(255,255,255,.9);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 820px) 300px;
|
||||||
|
gap: 28px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content,
|
||||||
|
.article-side {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255,253,248,.82);
|
||||||
|
box-shadow: 0 20px 54px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
padding: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content p {
|
||||||
|
color: #5f665f;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h2 {
|
||||||
|
margin-top: 34px;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-side {
|
||||||
|
position: sticky;
|
||||||
|
top: 108px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-side a {
|
||||||
|
display: block;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #6f4a37;
|
||||||
|
background: #fbf7ed;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-side a:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover { --lift: -6px; }
|
||||||
|
|
||||||
|
@media (max-width: 980px) {
|
||||||
|
.article-layout { grid-template-columns: 1fr; }
|
||||||
|
.article-side { position: static; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
.article-content { padding: 28px; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
.create-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-tags span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-tags span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-card:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(196,146,69,.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(196,146,69,.06) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-card h3,
|
||||||
|
.process-card .step-list {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-orb {
|
||||||
|
position: absolute;
|
||||||
|
right: -70px;
|
||||||
|
top: -80px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 62%);
|
||||||
|
animation: createPulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list p {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
transition: transform .22s ease, color .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list p:hover {
|
||||||
|
color: var(--green-dark);
|
||||||
|
transform: translateX(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list b {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
flex: 0 0 auto;
|
||||||
|
box-shadow: 0 12px 28px rgba(71, 111, 99, .18);
|
||||||
|
transition: transform .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list p:hover b {
|
||||||
|
background: var(--red);
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form {
|
||||||
|
max-width: 720px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-ornament {
|
||||||
|
position: absolute;
|
||||||
|
right: -82px;
|
||||||
|
top: -88px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(71, 111, 99, .12), transparent 66%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form h2,
|
||||||
|
.create-form .form-note,
|
||||||
|
.create-form .form-grid {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-note {
|
||||||
|
margin-bottom: 22px;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form .input,
|
||||||
|
.create-form textarea {
|
||||||
|
transition: border-color .22s ease, box-shadow .22s ease, background .22s ease, transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-region-picker {
|
||||||
|
/* 创建家谱页地区选择器占满表单宽度,编码通过隐藏字段提交 */
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form .input:focus,
|
||||||
|
.create-form textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: rgba(200, 59, 50, .62);
|
||||||
|
background: #fffdf8;
|
||||||
|
box-shadow: 0 0 0 4px rgba(200, 59, 50, .08);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes createPulse {
|
||||||
|
0%, 100% { opacity: .5; transform: scale(.92); }
|
||||||
|
50% { opacity: 1; transform: scale(1.08); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
.create-region-picker { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
.culture-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-stats span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-stats span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-quote {
|
||||||
|
position: relative;
|
||||||
|
min-height: 260px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(33,63,56,.18), rgba(33,63,56,.86)),
|
||||||
|
linear-gradient(135deg, #476f63, #c49245 50%, #c83b32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-quote:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255,255,255,.08) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,.08) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .34;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote-moon {
|
||||||
|
position: absolute;
|
||||||
|
right: 72px;
|
||||||
|
top: 34px;
|
||||||
|
width: 92px;
|
||||||
|
height: 92px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255,255,255,.32);
|
||||||
|
box-shadow: 0 0 34px rgba(255,255,255,.12);
|
||||||
|
animation: moonFloat 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-quote span {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255,255,255,.94);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .24s ease, background .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-quote:hover span {
|
||||||
|
transform: rotate(-8deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.culture-quote p {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(255,255,255,.86);
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
box-shadow: 0 18px 48px rgba(57, 48, 36, .07);
|
||||||
|
transition: transform .24s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 24px 60px rgba(57, 48, 36, .11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover {
|
||||||
|
position: relative;
|
||||||
|
height: 190px;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 74% 28%, rgba(255,255,255,.7) 0 8%, transparent 9%),
|
||||||
|
linear-gradient(135deg, #e7c89e, #b94135 48%, #143d57);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -42%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.34), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .58s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:hover .article-cover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-cover span {
|
||||||
|
position: absolute;
|
||||||
|
left: 22px;
|
||||||
|
bottom: 20px;
|
||||||
|
padding: 7px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: rgba(255,253,248,.86);
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:nth-child(2) .article-cover {
|
||||||
|
background: linear-gradient(135deg, #dfd1b5, #6b7f70 48%, #26302c);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:nth-child(3) .article-cover {
|
||||||
|
background: linear-gradient(135deg, #f0d8ac, #c49245 45%, #7d342d);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body { padding: 24px; }
|
||||||
|
.article-body h3 { transition: color .22s ease; }
|
||||||
|
.article-card:hover .article-body h3 { color: var(--red); }
|
||||||
|
.article-body p { color: var(--muted); line-height: 1.75; }
|
||||||
|
.article-body span { color: #9a8f82; font-size: 14px; }
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes moonFloat {
|
||||||
|
0%, 100% { transform: translateY(0) scale(1); opacity: .72; }
|
||||||
|
50% { transform: translateY(-8px) scale(1.04); opacity: .92; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
.download-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
margin-top: 30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-card {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-box {
|
||||||
|
width: 170px;
|
||||||
|
height: 170px;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, var(--green) 12px, transparent 12px) 0 0 / 32px 32px,
|
||||||
|
linear-gradient(var(--green) 12px, transparent 12px) 0 0 / 32px 32px,
|
||||||
|
#fffdf8;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
box-shadow: inset 0 0 0 12px #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-box span {
|
||||||
|
width: 62px;
|
||||||
|
height: 62px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-card p,
|
||||||
|
.download-card p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card {
|
||||||
|
transition: transform .24s ease, border-color .24s ease, box-shadow .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover { --lift: -6px; }
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
.page-family-detail [data-family-detail].is-loading {
|
||||||
|
/* 详情接口加载时只改变透明度,具体状态由公共 is-loading 类控制 */
|
||||||
|
opacity: .82;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
margin-top: 30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-summary {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 24px;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(33,63,56,.18), rgba(33,63,56,.88)),
|
||||||
|
linear-gradient(135deg, #476f63, #c49245 52%, #8f4634);
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-summary:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255,255,255,.08) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,.08) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .38;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-summary > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-badge {
|
||||||
|
width: fit-content;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: rgba(255,253,248,.88);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-grid {
|
||||||
|
/* 接口统计数据会替换这里的四个格子,固定列数避免加载后跳动 */
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-grid span {
|
||||||
|
min-height: 84px;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: rgba(255,255,255,.13);
|
||||||
|
border: 1px solid rgba(255,255,255,.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-grid b {
|
||||||
|
display: block;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-layout {
|
||||||
|
/* 详情页侧栏和正文为本页独有布局,不放入公共样式 */
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 330px 1fr;
|
||||||
|
gap: 26px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel,
|
||||||
|
.content-card,
|
||||||
|
.mini-card {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255,253,248,.78);
|
||||||
|
box-shadow: 0 20px 54px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel {
|
||||||
|
padding: 26px;
|
||||||
|
position: sticky;
|
||||||
|
top: 108px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel p,
|
||||||
|
.content-card p,
|
||||||
|
.mini-card p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-main {
|
||||||
|
display: grid;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-card {
|
||||||
|
min-height: 170px;
|
||||||
|
padding: 24px;
|
||||||
|
transition: transform .24s ease, border-color .24s ease, box-shadow .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 24px 60px rgba(57, 48, 36, .11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover { --lift: -6px; }
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.detail-layout { grid-template-columns: 1fr; }
|
||||||
|
.detail-panel { position: static; }
|
||||||
|
.summary-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* 找回密码页只保留单页装饰,公共认证卡片样式在 public.css */
|
||||||
|
.recover-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recover-card:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
right: -80px;
|
||||||
|
top: -90px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 64%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.recover-card > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 620px) {
|
||||||
|
.code-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
.page-genealogy {
|
||||||
|
background: #fbf7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-hero .container {
|
||||||
|
min-height: 470px;
|
||||||
|
padding-top: 76px;
|
||||||
|
padding-bottom: 76px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 136px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 16px 36px rgba(72, 57, 38, .07);
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-stats div {
|
||||||
|
min-width: 118px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-stats div + div {
|
||||||
|
border-left: 1px solid rgba(218, 201, 174, .78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-stats strong {
|
||||||
|
display: block;
|
||||||
|
color: var(--green);
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.genealogy-stats span {
|
||||||
|
color: #6d766f;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-preview {
|
||||||
|
position: relative;
|
||||||
|
min-height: 300px;
|
||||||
|
display: grid;
|
||||||
|
gap: 14px;
|
||||||
|
align-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, rgba(255,253,248,.95), rgba(255,253,248,.78)),
|
||||||
|
radial-gradient(circle at 78% 22%, rgba(196,146,69,.2), transparent 28%);
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-glow {
|
||||||
|
position: absolute;
|
||||||
|
right: -70px;
|
||||||
|
top: -80px;
|
||||||
|
width: 210px;
|
||||||
|
height: 210px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 62%);
|
||||||
|
animation: treePulse 4.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-row {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-row span {
|
||||||
|
min-width: 110px;
|
||||||
|
padding: 14px 18px;
|
||||||
|
border: 1px solid #dac9ae;
|
||||||
|
border-radius: 14px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: rgba(255,250,241,.9);
|
||||||
|
box-shadow: 0 12px 28px rgba(69, 53, 35, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .24s ease, color .24s ease, background .24s ease, box-shadow .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-preview:hover .tree-row span {
|
||||||
|
animation: nodeFloat 1.9s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-row span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
box-shadow: 0 16px 32px rgba(71, 111, 99, .22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-row.branch span:nth-child(2) { animation-delay: .08s; }
|
||||||
|
.tree-row.branch span:nth-child(3) { animation-delay: .16s; }
|
||||||
|
.tree-row.generation span:nth-child(2) { animation-delay: .08s; }
|
||||||
|
.tree-row.generation span:nth-child(3) { animation-delay: .16s; }
|
||||||
|
.tree-row.generation span:nth-child(4) { animation-delay: .24s; }
|
||||||
|
|
||||||
|
.tree-line {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: min(360px, 70%);
|
||||||
|
height: 1px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(196, 146, 69, .5), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-line.short {
|
||||||
|
width: min(500px, 86%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.capability-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capability-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card {
|
||||||
|
min-height: 210px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -40%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.48), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .56s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover:after {
|
||||||
|
left: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-word {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f7e4dc;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 900;
|
||||||
|
transition: transform .26s ease, background .26s ease, color .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover .icon-word {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: rotate(-6deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coedit-section {
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 18% 20%, rgba(200, 59, 50, .08), transparent 24%),
|
||||||
|
#f7efe2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coedit-card {
|
||||||
|
min-height: 260px;
|
||||||
|
padding: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coedit-card .btn {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-card {
|
||||||
|
min-height: 260px;
|
||||||
|
padding: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list p {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-list b {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
flex: 0 0 auto;
|
||||||
|
box-shadow: 0 12px 28px rgba(71, 111, 99, .18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes nodeFloat {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-5px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes treePulse {
|
||||||
|
0%, 100% { opacity: .5; transform: scale(.92); }
|
||||||
|
50% { opacity: 1; transform: scale(1.08); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
.genealogy-stats { flex-direction: column; }
|
||||||
|
.genealogy-stats div + div { border-left: 0; border-top: 1px solid rgba(218, 201, 174, .78); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
.help-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-tags span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-tags span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-card:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(196,146,69,.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(196,146,69,.06) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-card h3,
|
||||||
|
.help-card p,
|
||||||
|
.help-card .btn,
|
||||||
|
.help-icon {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-orb {
|
||||||
|
position: absolute;
|
||||||
|
right: -70px;
|
||||||
|
top: -80px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 62%);
|
||||||
|
animation: helpPulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-icon {
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
border-radius: 16px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 900;
|
||||||
|
box-shadow: 0 14px 32px rgba(71, 111, 99, .2);
|
||||||
|
transition: transform .26s ease, background .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-card:hover .help-icon {
|
||||||
|
background: var(--red);
|
||||||
|
transform: rotate(-8deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list {
|
||||||
|
/* 帮助文章接口会替换 FAQ 内容,固定列表容器宽度避免加载后跳动 */
|
||||||
|
position: relative;
|
||||||
|
max-width: 880px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: grid;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list details {
|
||||||
|
padding: 22px 24px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #fffdf8;
|
||||||
|
box-shadow: 0 12px 34px rgba(57, 48, 36, .06);
|
||||||
|
transition: transform .24s ease, box-shadow .24s ease, border-color .24s ease, background .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list.is-loading {
|
||||||
|
min-height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list details:hover,
|
||||||
|
.faq-list details[open] {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 22px 54px rgba(57, 48, 36, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list summary {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list summary:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 8px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 7px solid transparent;
|
||||||
|
border-bottom: 7px solid transparent;
|
||||||
|
border-left: 10px solid var(--green-dark);
|
||||||
|
transition: transform .24s ease, border-left-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list details[open] summary:before {
|
||||||
|
border-left-color: var(--red);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-list p {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
padding-left: 34px;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
animation: faqReveal .24s ease both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes helpPulse {
|
||||||
|
0%, 100% { opacity: .5; transform: scale(.92); }
|
||||||
|
50% { opacity: 1; transform: scale(1.08); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes faqReveal {
|
||||||
|
from { opacity: 0; transform: translateY(-4px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/* 加入家谱页只保留单页差异,公共认证卡片样式在 public.css */
|
||||||
|
.page-join-genealogy .auth-card {
|
||||||
|
width: min(500px, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-box {
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px dashed var(--gold);
|
||||||
|
border-radius: 22px;
|
||||||
|
background: #fffaf1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-join-genealogy textarea.input {
|
||||||
|
/* 申请说明需要多行输入,仍复用公共输入框视觉 */
|
||||||
|
min-height: 112px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/* 登录页只保留单页差异,公共认证卡片样式在 public.css */
|
||||||
|
.page-login .auth-card {
|
||||||
|
width: min(440px, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-mode-tabs {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
margin: 18px 0 16px;
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid rgba(138, 64, 42, .14);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255, 255, 255, .72);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 登录方式按钮只负责状态呈现,切换逻辑在 auth-pages.js */
|
||||||
|
.login-mode-tab {
|
||||||
|
min-height: 38px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
font: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-mode-tab.is-active {
|
||||||
|
background: var(--brand);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 8px 20px rgba(138, 64, 42, .18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-mode-panel[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-login .code-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 124px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.page-login .auth-layout {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 620px) {
|
||||||
|
.page-login .code-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
.notice-hero .container {
|
||||||
|
min-height: 420px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255,253,248,.74);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(145deg, var(--green-dark), var(--green));
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card span {
|
||||||
|
width: 88px;
|
||||||
|
height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255,253,248,.94);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 42px;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card p {
|
||||||
|
margin: 18px 0 0;
|
||||||
|
color: rgba(255,255,255,.88);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 820px) 300px;
|
||||||
|
gap: 28px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content,
|
||||||
|
.notice-side {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255,253,248,.82);
|
||||||
|
box-shadow: 0 20px 54px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
padding: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content p {
|
||||||
|
color: #5f665f;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-side {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-side a {
|
||||||
|
display: block;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #6f4a37;
|
||||||
|
background: #fbf7ed;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-side a:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover { --lift: -6px; }
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.notice-layout { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy { padding-left: 0; }
|
||||||
|
.hero-copy:before { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
.plaza-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.plaza-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plaza-stats span {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 16px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255, 253, 248, .74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plaza-stats b {
|
||||||
|
margin-right: 6px;
|
||||||
|
color: var(--green);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
gap: 20px;
|
||||||
|
align-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card h3 {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-ornament {
|
||||||
|
position: absolute;
|
||||||
|
right: -70px;
|
||||||
|
top: -84px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 62%);
|
||||||
|
animation: plazaPulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-toolbar {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 250, 241, .82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card .input {
|
||||||
|
flex: 1 1 280px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card .tag-row {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card.featured {
|
||||||
|
min-height: 300px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(28, 48, 45, .18), rgba(21, 55, 51, .84)),
|
||||||
|
linear-gradient(135deg, #476f63, #a95c3e);
|
||||||
|
border-radius: 18px;
|
||||||
|
padding: 28px;
|
||||||
|
box-shadow: 0 22px 58px rgba(42, 65, 59, .16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card.featured:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255, 255, 255, .08) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255, 255, 255, .08) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card.featured h3,
|
||||||
|
.family-card.featured p,
|
||||||
|
.family-card.featured .tag-row,
|
||||||
|
.family-badge {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card.featured p {
|
||||||
|
color: rgba(255, 255, 255, .82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-badge {
|
||||||
|
width: fit-content;
|
||||||
|
margin-bottom: auto;
|
||||||
|
padding: 7px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: rgba(255, 253, 248, .86);
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card-shine {
|
||||||
|
position: absolute;
|
||||||
|
left: -40%;
|
||||||
|
top: 0;
|
||||||
|
width: 34%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .28), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card.featured:hover .family-card-shine {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-lite {
|
||||||
|
min-height: 300px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-lite:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
right: -60px;
|
||||||
|
bottom: -70px;
|
||||||
|
width: 170px;
|
||||||
|
height: 170px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .13), transparent 68%);
|
||||||
|
transition: transform .28s ease, opacity .28s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-lite:hover:after {
|
||||||
|
transform: scale(1.25);
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-icon {
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
border-radius: 16px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f7e4dc;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .26s ease, background .26s ease, color .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-lite:hover .family-icon {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: rotate(-6deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes plazaPulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: .5;
|
||||||
|
transform: scale(.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-toolbar {
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,722 @@
|
|||||||
|
.page-profile-module {
|
||||||
|
background: #f8f4ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-hero {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 58px 0 42px;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 76% 18%, rgba(196, 146, 69, .16), transparent 25%),
|
||||||
|
linear-gradient(125deg, #fffaf0 0%, #f5eadb 52%, #eaf2ee 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-hero:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(138, 50, 43, .05) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(138, 50, 43, .05) 1px, transparent 1px);
|
||||||
|
background-size: 64px 64px;
|
||||||
|
mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-hero .container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-kicker {
|
||||||
|
width: fit-content;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(248, 229, 223, .92);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-title-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 22px;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-title-row h1 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-title-row p {
|
||||||
|
max-width: 780px;
|
||||||
|
margin: 0;
|
||||||
|
color: #636c65;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 280px minmax(0, 1fr);
|
||||||
|
gap: 24px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav,
|
||||||
|
.module-panel,
|
||||||
|
.module-card {
|
||||||
|
border: 1px solid rgba(224, 211, 189, .86);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255,253,248,.88);
|
||||||
|
box-shadow: 0 22px 58px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav {
|
||||||
|
position: sticky;
|
||||||
|
top: 106px;
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav a {
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #5e665f;
|
||||||
|
font-weight: 900;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav a:hover,
|
||||||
|
.module-nav a.active {
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-main {
|
||||||
|
display: grid;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-panel {
|
||||||
|
padding: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-panel h2 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-panel > p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-grid.two {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 170px;
|
||||||
|
padding: 22px;
|
||||||
|
transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-action-card {
|
||||||
|
/* 按钮型模块卡片用于消息中心操作,保留卡片视觉但去掉浏览器按钮默认样式 */
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-row.is-unread {
|
||||||
|
/* 未读消息用轻量背景强调,不新增内联样式 */
|
||||||
|
border-color: rgba(200, 59, 50, .28);
|
||||||
|
background: #fff7f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.join-apply-row {
|
||||||
|
/* 加入申请行复用 module-row,只补充审核业务的按钮对齐 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.join-apply-row .bottom-actions {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-row {
|
||||||
|
/* 字辈谱行复用 module-row,补充按钮型 pill 的对齐和点击反馈 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-row .pill {
|
||||||
|
border: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-row {
|
||||||
|
/* 世系人物行使用 button 承载点击详情,保留列表卡片视觉 */
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-row.is-selected {
|
||||||
|
border-color: rgba(200, 59, 50, .38);
|
||||||
|
background: #fff6f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-toolbar {
|
||||||
|
/* 搜索栏只做世系图页面差异布局,不放到 JS 内联样式 */
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-toolbar input {
|
||||||
|
min-height: 46px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
color: var(--ink);
|
||||||
|
font: inherit;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-tree-wrap {
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 18px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-tree-wrap.is-compact {
|
||||||
|
max-height: 420px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-tree,
|
||||||
|
.lineage-tree ul {
|
||||||
|
/* 树结构只负责层级缩进,避免用 JS 计算位置 */
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 24px;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-tree {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-node {
|
||||||
|
min-width: 168px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .86);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff7f2;
|
||||||
|
color: var(--ink);
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-node strong,
|
||||||
|
.lineage-node span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineage-node span {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-admin-row {
|
||||||
|
/* 成员管理行保留列表结构,右侧放权限和移除操作 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill.is-danger {
|
||||||
|
color: #8a322b;
|
||||||
|
background: #fde8e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-row {
|
||||||
|
/* 谱文列表行复用模块列表视觉,单独保留类名方便后续文章样式调整 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feed-row {
|
||||||
|
/* 家族圈动态行右侧承载点赞和评论按钮 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feed-row small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-row,
|
||||||
|
.album-photo-row {
|
||||||
|
/* 相册和照片行使用独立类名,便于后续相册页单独调样式 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo-form {
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-control {
|
||||||
|
/* 公共上传按钮使用 label 触发文件选择,避免 JS 注入按钮样式 */
|
||||||
|
width: fit-content;
|
||||||
|
min-height: 42px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-input {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-status {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ceremony-row,
|
||||||
|
.ceremony-gift-row,
|
||||||
|
.merit-row {
|
||||||
|
/* 贺礼、献礼和功德记录行复用模块列表,仅补业务类名方便维护 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ceremony-gift-form {
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.growth-row {
|
||||||
|
/* 成长记录行复用模块列表,单独留类名方便后续调整 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memo-row {
|
||||||
|
/* 备忘录行复用模块列表,单独留类名方便后续调整 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-list {
|
||||||
|
/* 会员套餐列表用网格呈现,套餐卡片由接口数据渲染 */
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin: 18px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-card {
|
||||||
|
min-height: 188px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .86);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
color: var(--ink);
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
transition: border-color .22s ease, box-shadow .22s ease, transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-card:hover,
|
||||||
|
.vip-package-card.is-selected {
|
||||||
|
border-color: rgba(200, 59, 50, .48);
|
||||||
|
box-shadow: 0 18px 42px rgba(57, 48, 36, .1);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-name,
|
||||||
|
.vip-package-card strong,
|
||||||
|
.vip-package-card small {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-name {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--red);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-card strong {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-card small {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-package-card p {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-order-form {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-order-row {
|
||||||
|
/* 会员订单行只补业务类名,方便和其他 module-row 分开维护 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-form {
|
||||||
|
/* 安全设置表单复用编辑表单结构,只补模块间距 */
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-danger {
|
||||||
|
border-color: rgba(138, 50, 43, .28);
|
||||||
|
background: #fff7f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-danger .editor-field input,
|
||||||
|
.security-danger .editor-field textarea {
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-profile-form {
|
||||||
|
/* 个人资料地区表单使用公共地区选择器,样式集中在 CSS */
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-region-picker {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-region-picker select {
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
color: var(--ink);
|
||||||
|
font: inherit;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-create-family-form {
|
||||||
|
/* 个人中心创建家谱页复用编辑表单,只保留页面级间距 */
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 24px 60px rgba(57, 48, 36, .11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card.is-selected {
|
||||||
|
border-color: rgba(200, 59, 50, .5);
|
||||||
|
background: #fff6f1;
|
||||||
|
box-shadow: 0 24px 60px rgba(200, 59, 50, .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 auto 0 -42%;
|
||||||
|
width: 34%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,.52), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .54s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card .icon {
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card h3 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 18px 20px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 15px;
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-row h3 {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-row p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
padding: 7px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
font-weight: 900;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like {
|
||||||
|
display: grid;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like p {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 170px 1fr auto;
|
||||||
|
gap: 16px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like p:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like span {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like b {
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-form {
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-data-form {
|
||||||
|
/* 个人资料编辑表单只补充本页间距,基础控件继续复用 editor-form。 */
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-field {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-field label {
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-field input,
|
||||||
|
.editor-field select,
|
||||||
|
.editor-field textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
color: var(--ink);
|
||||||
|
font: inherit;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color .2s ease, box-shadow .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-field textarea {
|
||||||
|
min-height: 160px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-field input:focus,
|
||||||
|
.editor-field select:focus,
|
||||||
|
.editor-field textarea:focus {
|
||||||
|
border-color: rgba(200, 59, 50, .45);
|
||||||
|
box-shadow: 0 0 0 4px rgba(200, 59, 50, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-two {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form-actions {
|
||||||
|
/* 保存状态跟随按钮排列,避免用 JS 写入临时样式。 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-status {
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-batch-form {
|
||||||
|
/* 批量字辈表单复用编辑表单,只补充本页预览前的间距。 */
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-batch-check {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-batch-check input {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
accent-color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-batch-actions {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-batch-preview {
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-box {
|
||||||
|
min-height: 136px;
|
||||||
|
border: 1px dashed rgba(138, 50, 43, .28);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #fff8f2;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 18px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1060px) {
|
||||||
|
.module-layout,
|
||||||
|
.module-grid,
|
||||||
|
.module-grid.two,
|
||||||
|
.vip-package-list {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav {
|
||||||
|
position: static;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.module-title-row {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-title-row h1 {
|
||||||
|
font-size: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-like p,
|
||||||
|
.module-row,
|
||||||
|
.editor-two,
|
||||||
|
.profile-region-picker {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,613 @@
|
|||||||
|
.page-profile {
|
||||||
|
background: #f8f4ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 62px 0 34px;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 78% 12%, rgba(196, 146, 69, .18), transparent 25%),
|
||||||
|
linear-gradient(125deg, #fffaf0 0%, #f4eadb 48%, #eaf2ee 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(138, 50, 43, .05) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(138, 50, 43, .05) 1px, transparent 1px);
|
||||||
|
background-size: 64px 64px;
|
||||||
|
mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero-grid {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 420px;
|
||||||
|
gap: 24px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-card,
|
||||||
|
.profile-stats,
|
||||||
|
.panel,
|
||||||
|
.side-card {
|
||||||
|
border: 1px solid rgba(224, 211, 189, .84);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255, 253, 248, .86);
|
||||||
|
box-shadow: 0 22px 58px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 116px 1fr;
|
||||||
|
gap: 28px;
|
||||||
|
padding: 34px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-wrap {
|
||||||
|
position: relative;
|
||||||
|
width: 108px;
|
||||||
|
height: 108px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 108px;
|
||||||
|
height: 108px;
|
||||||
|
border-radius: 28px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 30% 24%, rgba(255, 255, 255, .38), transparent 24%),
|
||||||
|
linear-gradient(145deg, var(--red), #ee8d60 52%, var(--green));
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 46px;
|
||||||
|
font-weight: 900;
|
||||||
|
box-shadow: 0 18px 40px rgba(200, 59, 50, .18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-wrap span {
|
||||||
|
position: absolute;
|
||||||
|
right: -4px;
|
||||||
|
bottom: -4px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border: 5px solid #fffdf8;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #31bf6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info h1 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info p {
|
||||||
|
max-width: 720px;
|
||||||
|
color: #636c65;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tags,
|
||||||
|
.mini-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tags span,
|
||||||
|
.mini-actions span {
|
||||||
|
padding: 7px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
padding: 22px;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stats div {
|
||||||
|
min-height: 116px;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
background: rgba(247, 239, 226, .72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stats strong {
|
||||||
|
color: var(--green);
|
||||||
|
font-size: 34px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stats span,
|
||||||
|
.panel-head p,
|
||||||
|
.data-list span,
|
||||||
|
.todo-list span,
|
||||||
|
.family-card p,
|
||||||
|
.feature-tile p,
|
||||||
|
.content-tile p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-section {
|
||||||
|
padding-top: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 300px minmax(0, 1fr);
|
||||||
|
gap: 24px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-side {
|
||||||
|
position: sticky;
|
||||||
|
top: 106px;
|
||||||
|
display: grid;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-card,
|
||||||
|
.panel {
|
||||||
|
padding: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-card h2,
|
||||||
|
.panel h2 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions a,
|
||||||
|
.todo-list a {
|
||||||
|
display: block;
|
||||||
|
padding: 15px 16px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: #fbf7ed;
|
||||||
|
transition: transform .22s ease, border-color .22s ease, background .22s ease, color .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions a:hover,
|
||||||
|
.todo-list a:hover {
|
||||||
|
transform: translateX(5px);
|
||||||
|
border-color: rgba(71, 111, 99, .28);
|
||||||
|
background: #eef4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions span,
|
||||||
|
.todo-list b {
|
||||||
|
display: block;
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-actions b {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-link span {
|
||||||
|
color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-head,
|
||||||
|
.panel-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 18px;
|
||||||
|
margin-bottom: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-head span {
|
||||||
|
padding: 6px 11px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-list,
|
||||||
|
.dashboard-main {
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head.compact {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head h2 {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 112px 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
min-height: 190px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #fffdf8;
|
||||||
|
transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card:hover,
|
||||||
|
.feature-tile:hover,
|
||||||
|
.content-tile:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 22px 52px rgba(57, 48, 36, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.book-cover {
|
||||||
|
min-height: 150px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fffdf8;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, transparent calc(100% - 16px), rgba(255, 255, 255, .7) calc(100% - 15px), transparent calc(100% - 14px)),
|
||||||
|
linear-gradient(135deg, #0f405c, #092c42);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 1.7;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: inset -12px 0 0 rgba(255, 255, 255, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.book-cover.alt {
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, transparent calc(100% - 16px), rgba(255, 255, 255, .7) calc(100% - 15px), transparent calc(100% - 14px)),
|
||||||
|
linear-gradient(135deg, #173c35, #785f35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card h3,
|
||||||
|
.feature-tile h3,
|
||||||
|
.content-tile h3 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-grid,
|
||||||
|
.content-grid,
|
||||||
|
.service-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.management-grid {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-tile,
|
||||||
|
.content-tile {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 170px;
|
||||||
|
padding: 22px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #fffdf8;
|
||||||
|
transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-tile span,
|
||||||
|
.content-tile span {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f7e4dc;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-tile:after,
|
||||||
|
.content-tile:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 auto 0 -42%;
|
||||||
|
width: 34%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .52), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .54s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-tile:hover:after,
|
||||||
|
.content-tile:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tile.large {
|
||||||
|
grid-column: span 2;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(145deg, var(--green-dark), var(--green));
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tile.large p,
|
||||||
|
.content-tile.large h3 {
|
||||||
|
color: rgba(255, 255, 255, .86);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tile.large span {
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: rgba(255, 253, 248, .9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-data-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.15fr .85fr;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-btn {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 9px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--red);
|
||||||
|
background: #f8e5df;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-list {
|
||||||
|
display: grid;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-list p {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 150px 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 16px 0;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-list b {
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid a {
|
||||||
|
min-height: 88px;
|
||||||
|
padding: 18px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #6f4a37;
|
||||||
|
background: #fbf7ed;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
font-weight: 900;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid a:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 80;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-modal.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-modal-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(32, 35, 34, .46);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-dialog {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: min(420px, 100%);
|
||||||
|
padding: 34px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 28px 80px rgba(61, 73, 68, .24);
|
||||||
|
text-align: center;
|
||||||
|
transform: translateY(12px) scale(.98);
|
||||||
|
transition: transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-modal.show .logout-dialog {
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 14px;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #f4f1eb;
|
||||||
|
color: #7f786f;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform .2s ease, background .2s ease, color .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-close:hover {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
background: var(--red-soft);
|
||||||
|
color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-icon {
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
width: 58px;
|
||||||
|
height: 58px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
background: var(--red-soft);
|
||||||
|
color: var(--red);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-dialog h2 {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 24px;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-dialog p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-actions .btn {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-modal-open {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1120px) {
|
||||||
|
|
||||||
|
.profile-hero-grid,
|
||||||
|
.dashboard-layout,
|
||||||
|
.profile-data-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-side {
|
||||||
|
position: static;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid,
|
||||||
|
.management-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.profile-hero {
|
||||||
|
padding-top: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info h1 {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stats,
|
||||||
|
.dashboard-side,
|
||||||
|
.family-grid,
|
||||||
|
.content-grid,
|
||||||
|
.management-grid,
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.family-card {
|
||||||
|
grid-template-columns: 88px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.book-cover {
|
||||||
|
min-height: 120px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tile.large {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head,
|
||||||
|
.card-head {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-list p {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-dialog {
|
||||||
|
padding: 30px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-actions {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
.promo-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255, 253, 248, .74);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-preview {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.2fr 1fr;
|
||||||
|
grid-template-rows: repeat(2, 130px);
|
||||||
|
gap: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo {
|
||||||
|
border-radius: 18px;
|
||||||
|
background: radial-gradient(circle at 72% 24%, rgba(255, 255, 255, .75) 0 8%, transparent 9%), linear-gradient(135deg, #e7c89e, #b94135 48%, #143d57);
|
||||||
|
box-shadow: 0 16px 36px rgba(57, 48, 36, .08);
|
||||||
|
transition: transform .26s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo.large {
|
||||||
|
grid-row: 1 / 3;
|
||||||
|
background: linear-gradient(180deg, rgba(28, 48, 45, .1), rgba(21, 55, 51, .72)), url("../images/ancestral-hall.png") center/cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo.warm {
|
||||||
|
background: linear-gradient(135deg, #f0d8ac, #c49245 45%, #7d342d);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo.green {
|
||||||
|
background: linear-gradient(135deg, #dfd1b5, #6b7f70 48%, #26302c);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-preview:hover .album-photo {
|
||||||
|
transform: scale(1.025);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card {
|
||||||
|
min-height: 180px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -42%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .54), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .56s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-preview {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: repeat(4, 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-photo.large {
|
||||||
|
grid-row: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
.promo-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags span {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255, 253, 248, .74);
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promo-tags span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-preview {
|
||||||
|
min-height: 300px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(180deg, rgba(31, 63, 55, .1), rgba(25, 39, 34, .86)), url("../images/ancestral-hall.png") center/cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-preview:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(rgba(255, 255, 255, .08) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, .08) 1px, transparent 1px);
|
||||||
|
background-size: 34px 34px;
|
||||||
|
opacity: .35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-preview h3,
|
||||||
|
.video-preview p,
|
||||||
|
.play-button {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-preview p {
|
||||||
|
color: rgba(255, 255, 255, .8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.play-button {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-bottom: 46px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, .94);
|
||||||
|
box-shadow: 0 14px 34px rgba(0, 0, 0, .2);
|
||||||
|
transition: transform .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.play-button:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 26px;
|
||||||
|
top: 19px;
|
||||||
|
border-top: 13px solid transparent;
|
||||||
|
border-bottom: 13px solid transparent;
|
||||||
|
border-left: 20px solid var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-preview:hover .play-button {
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-card {
|
||||||
|
min-height: 180px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -42%;
|
||||||
|
top: 0;
|
||||||
|
width: 36%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .54), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .56s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-card:hover:after {
|
||||||
|
left: 112%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,900 @@
|
|||||||
|
:root {
|
||||||
|
--red: #c83b32;
|
||||||
|
--red-soft: #f4ded8;
|
||||||
|
--green: #476f63;
|
||||||
|
--green-dark: #213f38;
|
||||||
|
--gold: #c49245;
|
||||||
|
--ink: #26302c;
|
||||||
|
--muted: #737b76;
|
||||||
|
--paper: #fbf7ed;
|
||||||
|
--paper-2: #f7efe2;
|
||||||
|
--line: #eadfce;
|
||||||
|
--white: #fffdf8;
|
||||||
|
--shadow: 0 24px 70px rgba(69, 53, 35, .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-layer-message {
|
||||||
|
/* 认证页 layui 消息提示皮肤,替代浏览器原生 alert。 */
|
||||||
|
min-width: 160px;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
background: rgba(38, 48, 44, .94) !important;
|
||||||
|
box-shadow: 0 16px 42px rgba(38, 48, 44, .24) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-layer-message .layui-layer-content {
|
||||||
|
padding: 10px 18px !important;
|
||||||
|
color: #fffdf8 !important;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
|
||||||
|
background: var(--paper);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: hover) and (pointer: fine) {
|
||||||
|
|
||||||
|
a,
|
||||||
|
.btn,
|
||||||
|
.card,
|
||||||
|
button,
|
||||||
|
summary {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: min(1280px, calc(100% - 72px));
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 20;
|
||||||
|
background:
|
||||||
|
linear-gradient(115deg, rgba(110, 38, 32, .96) 0%, rgba(200, 59, 50, .96) 48%, rgba(139, 52, 39, .96) 100%);
|
||||||
|
border-bottom: 1px solid rgba(255, 253, 248, .2);
|
||||||
|
box-shadow:
|
||||||
|
0 4px 0 rgba(93, 30, 26, .2),
|
||||||
|
0 18px 38px rgba(83, 32, 26, .34),
|
||||||
|
0 30px 70px rgba(83, 32, 26, .22);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
height: 82px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 253, 248, .92);
|
||||||
|
box-shadow: 0 10px 28px rgba(63, 28, 22, .18);
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-logo {
|
||||||
|
display: block;
|
||||||
|
width: 270px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .brand-logo {
|
||||||
|
width: 270px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-page-brand .brand-logo {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-logo-mark {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-text {
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-mark {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
box-shadow: 0 10px 24px rgba(200, 59, 50, .22);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 26px;
|
||||||
|
color: rgba(255, 253, 248, .78);
|
||||||
|
font-size: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a.active,
|
||||||
|
.nav-links a:hover {
|
||||||
|
color: #fff7d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a,
|
||||||
|
.nav-actions a {
|
||||||
|
position: relative;
|
||||||
|
transition: color .22s ease, transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: -10px;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(90deg, #f5d99b, #fff3c8);
|
||||||
|
transform: scaleX(0);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: transform .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a.active:after,
|
||||||
|
.nav-links a:hover:after {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
color: rgba(255, 253, 248, .86);
|
||||||
|
font-size: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
min-width: 118px;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 24px;
|
||||||
|
border-radius: 999px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease, background .22s ease;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.primary {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
box-shadow: 0 14px 30px rgba(200, 59, 50, .24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.primary:hover {
|
||||||
|
box-shadow: 0 18px 38px rgba(200, 59, 50, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header .btn.primary {
|
||||||
|
color: #8f332b;
|
||||||
|
background: linear-gradient(135deg, #fff8e6, #f1d49a);
|
||||||
|
box-shadow: 0 12px 28px rgba(64, 26, 21, .22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header .btn.primary:hover {
|
||||||
|
box-shadow: 0 16px 34px rgba(64, 26, 21, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.ghost {
|
||||||
|
color: var(--red);
|
||||||
|
border-color: rgba(200, 59, 50, .28);
|
||||||
|
background: rgba(255, 255, 255, .68);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-hero {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 82% 12%, rgba(196, 146, 69, .16), transparent 24%),
|
||||||
|
linear-gradient(125deg, #fffaf0 0%, #f7efe2 48%, #edf4ef 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-hero:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(138, 50, 43, .05) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(138, 50, 43, .05) 1px, transparent 1px);
|
||||||
|
background-size: 68px 68px;
|
||||||
|
mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-hero .container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
min-height: 410px;
|
||||||
|
padding: 68px 0 72px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: .9fr 1.1fr;
|
||||||
|
gap: 54px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 22px;
|
||||||
|
color: #8a5a3b;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow:before {
|
||||||
|
content: "";
|
||||||
|
width: 42px;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 52px;
|
||||||
|
line-height: 1.16;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 42px;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
max-width: 620px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: #645d52;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-card {
|
||||||
|
min-height: 260px;
|
||||||
|
padding: 28px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .88);
|
||||||
|
border-radius: 24px;
|
||||||
|
background: rgba(255, 253, 248, .92);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
padding: 76px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section.alt {
|
||||||
|
background: #fffdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head {
|
||||||
|
margin-bottom: 34px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head p {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 14px auto 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-2,
|
||||||
|
.grid-3,
|
||||||
|
.grid-4 {
|
||||||
|
display: grid;
|
||||||
|
gap: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-2 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-3 {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-4 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #fffdf8;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
box-shadow: 0 16px 42px rgba(57, 48, 36, .07);
|
||||||
|
transition: transform .24s ease, box-shadow .24s ease, border-color .24s ease, background .24s ease;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
border-color: rgba(196, 146, 69, .38);
|
||||||
|
box-shadow: 0 24px 60px rgba(57, 48, 36, .11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.soft {
|
||||||
|
background: #fbf7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.dark {
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(155deg, var(--green-dark), var(--green));
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.dark p {
|
||||||
|
color: rgba(255, 255, 255, .78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card p,
|
||||||
|
.muted {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--green);
|
||||||
|
background: #eaf0eb;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border: 1px solid #e2d4bf;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--ink);
|
||||||
|
background: #fbf8f1;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
min-height: 128px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: 18px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card {
|
||||||
|
max-width: 560px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-layout {
|
||||||
|
min-height: calc(100vh - 82px);
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 62px 24px;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 18% 20%, rgba(200, 59, 50, .09), transparent 24%),
|
||||||
|
linear-gradient(125deg, #fffaf0, #f7efe2 54%, #edf4ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 认证类页面共用祖堂背景,登录、注册、找回密码只保留自己的差异样式 */
|
||||||
|
.auth-scenic-layout {
|
||||||
|
position: relative;
|
||||||
|
isolation: isolate;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 56px 24px 72px;
|
||||||
|
place-items: center;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, rgba(255, 253, 248, .86), rgba(255, 253, 248, .46) 45%, rgba(255, 253, 248, .88)),
|
||||||
|
linear-gradient(135deg, rgba(200, 59, 50, .08), transparent 34%),
|
||||||
|
url("../images/ancestral-hall-new.png") center / cover no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-scenic-layout:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: -1;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(251, 247, 237, .42), rgba(251, 247, 237, .86)),
|
||||||
|
radial-gradient(circle at 50% 42%, rgba(255, 253, 248, .3), transparent 30%);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-page-brand {
|
||||||
|
position: absolute;
|
||||||
|
left: clamp(18px, 4vw, 56px);
|
||||||
|
top: clamp(18px, 4vw, 42px);
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 认证卡片公共样式,避免登录、注册、找回密码页面重复维护 */
|
||||||
|
.auth-card {
|
||||||
|
width: min(440px, 100%);
|
||||||
|
padding: 38px;
|
||||||
|
border-radius: 16px;
|
||||||
|
border-color: rgba(224, 211, 189, .9);
|
||||||
|
background: rgba(255, 253, 248, .94);
|
||||||
|
box-shadow: 0 26px 70px rgba(57, 48, 36, .16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card:hover {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card h1 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .lead {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .form-grid {
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .input {
|
||||||
|
height: 50px;
|
||||||
|
background: #fffaf1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary,
|
||||||
|
.auth-card .btn.ghost {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary:before,
|
||||||
|
.auth-card .btn.ghost:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: -45%;
|
||||||
|
width: 38%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .34), transparent);
|
||||||
|
transform: skewX(-18deg);
|
||||||
|
transition: left .48s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary:hover,
|
||||||
|
.auth-card .btn.ghost:hover {
|
||||||
|
transform: translateY(-3px) scale(1.012);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary:hover {
|
||||||
|
box-shadow: 0 18px 42px rgba(200, 59, 50, .34);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.ghost:hover {
|
||||||
|
color: #fff;
|
||||||
|
border-color: rgba(200, 59, 50, .2);
|
||||||
|
background: var(--red);
|
||||||
|
box-shadow: 0 16px 34px rgba(200, 59, 50, .2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary:hover:before,
|
||||||
|
.auth-card .btn.ghost:hover:before {
|
||||||
|
left: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .btn.primary:active,
|
||||||
|
.auth-card .btn.ghost:active {
|
||||||
|
transform: translateY(-1px) scale(.99);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
color: #8a5a3b;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-links a {
|
||||||
|
transition: color .22s ease, transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-links a:hover {
|
||||||
|
color: var(--red);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-box {
|
||||||
|
/* 认证页滑动验证挂载点,TAC 内部 DOM 由第三方库生成 */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-box:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-box #tianai-captcha-parent {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-modal {
|
||||||
|
/* 认证页滑动验证弹窗挂载点,TAC 内部 DOM 由第三方库生成 */
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
background: rgba(38, 48, 44, .32);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-modal:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-captcha-modal #tianai-captcha-parent {
|
||||||
|
max-width: min(318px, calc(100vw - 32px));
|
||||||
|
max-height: calc(100vh - 32px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 验证码输入和按钮的通用双列布局,窄屏在页面 CSS 中改为单列 */
|
||||||
|
.code-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 接口请求期间的公共状态,只由 JS 切换 class,不在 JS 内写样式 */
|
||||||
|
.is-loading {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: .72;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 接口列表为空时的统一占位样式 */
|
||||||
|
.api-empty {
|
||||||
|
padding: 22px;
|
||||||
|
border: 1px dashed var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
color: var(--muted);
|
||||||
|
background: rgba(255, 253, 248, .7);
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 60px 0 36px;
|
||||||
|
color: rgba(255, 255, 255, .78);
|
||||||
|
background: #3f3a35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.2fr repeat(3, 1fr);
|
||||||
|
gap: 48px;
|
||||||
|
padding-bottom: 38px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer h4 {
|
||||||
|
margin: 0 0 18px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer p,
|
||||||
|
.footer a {
|
||||||
|
display: block;
|
||||||
|
color: inherit;
|
||||||
|
margin: 10px 0;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
width: fit-content;
|
||||||
|
transition: color .22s ease, transform .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a:hover {
|
||||||
|
color: #fff;
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .brand {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .brand:hover {
|
||||||
|
transform: translateX(0) translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright,
|
||||||
|
.footer-legal {
|
||||||
|
padding-top: 28px;
|
||||||
|
color: rgba(255, 255, 255, .48);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-legal {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-legal a {
|
||||||
|
display: inline-flex;
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
color: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-legal a:hover {
|
||||||
|
color: #fff;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-layer-confirm {
|
||||||
|
border-radius: 8px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-layer-confirm .layui-layer-title {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
border-bottom: 1px solid rgba(224, 211, 189, .72);
|
||||||
|
background: #fffaf0;
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-layer-confirm .layui-layer-content {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-layer-confirm .layui-layer-btn a {
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-layer-confirm .layui-layer-btn .layui-layer-btn0 {
|
||||||
|
border-color: var(--red);
|
||||||
|
background: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog {
|
||||||
|
border-radius: 8px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 20px 60px rgba(38, 30, 21, .18) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog .layui-layer-title {
|
||||||
|
height: 52px;
|
||||||
|
line-height: 52px;
|
||||||
|
border-bottom: 1px solid rgba(224, 211, 189, .72);
|
||||||
|
background: #fffaf0;
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog .layui-layer-content {
|
||||||
|
padding: 28px 28px 16px !important;
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.8;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog .layui-layer-btn {
|
||||||
|
padding: 0 24px 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog .layui-layer-btn a {
|
||||||
|
height: 38px;
|
||||||
|
min-width: 108px;
|
||||||
|
padding: 0 24px;
|
||||||
|
border-radius: 999px;
|
||||||
|
line-height: 38px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-layer-dialog .layui-layer-btn .layui-layer-btn0 {
|
||||||
|
border-color: var(--red);
|
||||||
|
background: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-popup-select {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-popup-select button {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 42px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fffdf8;
|
||||||
|
color: var(--ink);
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color .2s ease, color .2s ease, background .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-popup-select button:hover {
|
||||||
|
border-color: rgba(200, 59, 50, .38);
|
||||||
|
color: var(--red);
|
||||||
|
background: #fff4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1120px) {
|
||||||
|
.nav-links {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-hero .container,
|
||||||
|
.grid-2 {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-3,
|
||||||
|
.grid-4 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.container {
|
||||||
|
width: calc(100% - 28px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-actions a:not(.btn) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-hero .container {
|
||||||
|
padding: 46px 0 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-3,
|
||||||
|
.grid-4,
|
||||||
|
.footer-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-scenic-layout {
|
||||||
|
padding: 36px 14px 48px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
padding: 28px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card h1 {
|
||||||
|
font-size: 34px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
animation-duration: .01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
scroll-behavior: auto !important;
|
||||||
|
transition-duration: .01ms !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/* 注册页只保留单页差异,公共认证卡片样式在 public.css */
|
||||||
|
.page-register .auth-links {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.page-register .auth-layout {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
.result-hero .container {
|
||||||
|
min-height: 420px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-search {
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-search .toolbar {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 250, 241, .82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-search .input {
|
||||||
|
flex: 1 1 260px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
max-width: 920px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 26px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255, 253, 248, .82);
|
||||||
|
box-shadow: 0 18px 48px rgba(57, 48, 36, .07);
|
||||||
|
transition: transform .24s ease, border-color .24s ease, box-shadow .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
right: -70px;
|
||||||
|
bottom: -80px;
|
||||||
|
width: 180px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .13), transparent 68%);
|
||||||
|
transition: transform .28s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card:hover {
|
||||||
|
border-color: rgba(196, 146, 69, .42);
|
||||||
|
box-shadow: 0 24px 60px rgba(57, 48, 36, .11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card:hover:after {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card span {
|
||||||
|
display: inline-flex;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 7px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--green-dark);
|
||||||
|
background: #e8f0eb;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-search .toolbar {
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
.ticket-hero .container {
|
||||||
|
min-height: 420px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-tip {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
background: linear-gradient(145deg, var(--green-dark), var(--green));
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-tip span {
|
||||||
|
width: 88px;
|
||||||
|
height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255, 253, 248, .94);
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-tip p {
|
||||||
|
max-width: 360px;
|
||||||
|
margin: 18px 0 0;
|
||||||
|
color: rgba(255, 255, 255, .86);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 720px) 320px;
|
||||||
|
gap: 26px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-form {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-form textarea {
|
||||||
|
min-height: 150px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-radius: 18px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-side {
|
||||||
|
padding: 26px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255, 253, 248, .82);
|
||||||
|
box-shadow: 0 20px 54px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-side p {
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-side a {
|
||||||
|
display: inline-flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: var(--red);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.ticket-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
.surname-detail-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
margin-top: 30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-emblem {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 72% 24%, rgba(255, 255, 255, .28) 0 10%, transparent 11%),
|
||||||
|
linear-gradient(135deg, #476f63, #c49245 54%, #8f4634);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-emblem span {
|
||||||
|
width: 112px;
|
||||||
|
height: 112px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: var(--red);
|
||||||
|
background: rgba(255, 253, 248, .95);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 58px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-emblem:hover span {
|
||||||
|
transform: rotate(-8deg) scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-emblem p {
|
||||||
|
margin: 18px 0 0;
|
||||||
|
color: rgba(255, 255, 255, .9);
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-detail-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card,
|
||||||
|
.related-panel {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255, 253, 248, .82);
|
||||||
|
box-shadow: 0 20px 54px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card:first-child {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card p {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-row span {
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #7c4a33;
|
||||||
|
background: #fbf7ed;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generation-row span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-panel {
|
||||||
|
padding: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-panel a {
|
||||||
|
display: block;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #6f4a37;
|
||||||
|
background: #fbf7ed;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-panel a:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--green);
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.surname-detail-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card:first-child {
|
||||||
|
grid-column: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
.surname-hero .container {
|
||||||
|
min-height: 440px;
|
||||||
|
padding-top: 74px;
|
||||||
|
padding-bottom: 74px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 58px;
|
||||||
|
width: 4px;
|
||||||
|
height: 132px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(180deg, var(--red), var(--gold));
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 28px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-stats span {
|
||||||
|
padding: 11px 14px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #6d766f;
|
||||||
|
background: rgba(255, 253, 248, .74);
|
||||||
|
box-shadow: 0 14px 32px rgba(72, 57, 38, .06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-stats b {
|
||||||
|
margin-right: 6px;
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-search-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-ornament {
|
||||||
|
position: absolute;
|
||||||
|
right: -72px;
|
||||||
|
top: -84px;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(200, 59, 50, .13), transparent 62%);
|
||||||
|
animation: surnamePulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-search-card h3,
|
||||||
|
.search-toolbar,
|
||||||
|
.hot-query {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-toolbar {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .78);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 250, 241, .82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-toolbar .input {
|
||||||
|
flex: 1 1 280px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-query {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-query span {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #7c4a33;
|
||||||
|
background: #fbf7ed;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .22s ease, color .22s ease, background .22s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-query span:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-list-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-list-section:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 58px;
|
||||||
|
width: 520px;
|
||||||
|
height: 180px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(196, 146, 69, .09), transparent 68%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
border: 1px solid rgba(224, 211, 189, .8);
|
||||||
|
border-radius: 24px;
|
||||||
|
background: rgba(255, 253, 248, .72);
|
||||||
|
box-shadow: 0 22px 60px rgba(57, 48, 36, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid a {
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 14px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #7c4a33;
|
||||||
|
background: #fbf7ed;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
font-family: "SimSun", "Songti SC", serif;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
transition: transform .24s ease, color .24s ease, background .24s ease, border-color .24s ease, box-shadow .24s ease;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid a:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--red);
|
||||||
|
border-color: rgba(200, 59, 50, .72);
|
||||||
|
box-shadow: 0 16px 34px rgba(200, 59, 50, .18);
|
||||||
|
transform: translateY(-6px) scale(1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid:hover a {
|
||||||
|
animation: surnameFloat 1.9s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid:hover a:nth-child(2n) {
|
||||||
|
animation-delay: .08s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid:hover a:nth-child(3n) {
|
||||||
|
animation-delay: .14s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid:hover a:nth-child(4n) {
|
||||||
|
animation-delay: .2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card {
|
||||||
|
transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));
|
||||||
|
transition: transform .18s ease, box-shadow .24s ease, border-color .24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tilt-card:hover {
|
||||||
|
--lift: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes surnameFloat {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes surnamePulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: .5;
|
||||||
|
transform: scale(.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.hero-copy {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-toolbar {
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.surname-grid {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |