update bug1.0
@@ -134,7 +134,7 @@ class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
docs = Path(settings.PROJECT_ROOT) / "docs"
|
||||
mathbti_path = docs / "old_scripts" / "seed_mathbti.json"
|
||||
story_path = docs / "数学少年线_story.json"
|
||||
story_path = docs / "信仰者线_story.json"
|
||||
videos_path = docs / "old_scripts" / "seed_videos.json"
|
||||
if not mathbti_path.exists() or not story_path.exists() or not videos_path.exists():
|
||||
raise CommandError("缺少 docs 中的初始内容文件")
|
||||
@@ -167,7 +167,7 @@ class Command(BaseCommand):
|
||||
if errors:
|
||||
raise CommandError("; ".join(errors))
|
||||
flagship, _ = Story.objects.update_or_create(
|
||||
slug="believer-math-teen",
|
||||
slug="believer",
|
||||
defaults={
|
||||
"title": story_document["title"],
|
||||
"summary": story_document.get("description", ""),
|
||||
|
||||
@@ -274,3 +274,76 @@ dialog::backdrop { background: rgba(17,25,20,.55); backdrop-filter: blur(5px); }
|
||||
.map-stage { height: 480px; transform: scale(.92); }.ability-node { width: 108px; height: 94px; }.node-vision { left: calc(50% - 54px); }.node-humanities { left: 0; top: 100px; }.node-connection { right: 0; top: 100px; }.node-detection { left: 2%; bottom: 30px; }.node-modeling { right: 2%; bottom: 30px; }.pet-node { top: 190px; }
|
||||
.map-lines { display: none; }.ability-legend { margin-top: 14px; justify-content: start; }.video-cover { height: 150px; }
|
||||
}
|
||||
|
||||
.life-hub, .life-skills { animation: rise .35s ease; }
|
||||
.back-button { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line); border-radius: 10px; padding: 8px 16px; background: transparent; color: var(--muted); cursor: pointer; margin-bottom: 18px; font-size: 13px; transition: .2s ease; }
|
||||
.back-button:hover { color: var(--ink); border-color: var(--ink); }
|
||||
|
||||
.life-map { margin-top: 28px; }
|
||||
.life-map-canvas { position: relative; max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 40px; padding: 30px 0; }
|
||||
.life-map-lines { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
|
||||
.life-map-center { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 1; display: grid; place-items: center; text-align: center; pointer-events: none; }
|
||||
.life-map-center b { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%; background: var(--ink); color: var(--lime); font: 22px Georgia, serif; margin-bottom: 6px; }
|
||||
.life-map-center span { font-size: 9px; color: var(--muted); letter-spacing: .12em; line-height: 1.4; }
|
||||
|
||||
.route-card {
|
||||
position: relative; width: 100%; padding: 28px 26px 24px; border-radius: 22px; z-index: 2;
|
||||
border: 1px solid rgba(23,33,27,.1); background: rgba(255,255,252,.82); backdrop-filter: blur(14px);
|
||||
box-shadow: 0 24px 70px rgba(38,48,40,.06); cursor: pointer; transition: .25s ease; display: flex; flex-direction: column; min-height: 300px;
|
||||
}
|
||||
.route-card:hover { transform: translateY(-6px); box-shadow: 0 28px 80px rgba(38,48,40,.1); }
|
||||
.route-card::after { content: ""; position: absolute; width: 80px; height: 80px; border-radius: 50%; right: -28px; top: -28px; opacity: .5; }
|
||||
.route-believer::after { background: var(--lime); }
|
||||
.route-spreader::after { background: var(--blue); }
|
||||
.route-applier::after { background: var(--orange); }
|
||||
.route-seer::after { background: #bb8ac4; }
|
||||
|
||||
.route-index { font: 700 13px Georgia, serif; color: #b0b6ae; letter-spacing: .08em; }
|
||||
.route-spirit { margin-top: 14px; } .route-spirit b { display: block; font: 25px Georgia, serif; } .route-spirit small { font-size: 9px; color: var(--muted); letter-spacing: .22em; }
|
||||
.route-conflict { margin: 16px 0 18px; color: #3e4942; font-size: 14px; line-height: 1.7; }
|
||||
.route-mathematicians { display: flex; gap: 10px; margin-bottom: 18px; }
|
||||
.route-mathematician { display: flex; flex-direction: column; align-items: center; gap: 5px; flex: 1; }
|
||||
.route-mathematician img { width: 52px; height: 52px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(23,33,27,.08); }
|
||||
.route-mathematician b { font-size: 10px; text-align: center; }
|
||||
.route-mathematician small { font-size: 8px; color: var(--muted); text-align: center; line-height: 1.3; }
|
||||
.route-meta { margin-top: auto; margin-bottom: 16px; }
|
||||
.route-status { font-size: 10px; color: var(--green); font-weight: 700; letter-spacing: .06em; }
|
||||
.route-enter { border: 0; border-bottom: 2px solid currentColor; padding: 4px 0; background: transparent; cursor: pointer; font-size: 14px; font-weight: 650; text-align: left; }
|
||||
.route-believer .route-enter { color: var(--green); } .route-spreader .route-enter { color: var(--blue); }
|
||||
.route-applier .route-enter { color: var(--orange); } .route-seer .route-enter { color: #9b6bb0; }
|
||||
|
||||
.alumni-entry { margin-top: 50px; border-radius: 22px; background: var(--ink); color: white; padding: 40px 46px; overflow: hidden; position: relative; }
|
||||
.alumni-entry::after { content: ""; position: absolute; width: 280px; height: 280px; right: -80px; bottom: -120px; border: 45px solid rgba(204,232,91,.08); border-radius: 50%; }
|
||||
.alumni-entry-content { display: flex; align-items: center; justify-content: space-between; gap: 30px; position: relative; z-index: 1; }
|
||||
.alumni-entry .kicker { color: var(--lime); }
|
||||
.alumni-entry h2 { margin: 12px 0 10px; font: 30px Georgia, serif; }
|
||||
.alumni-entry p { color: #aeb9b1; font-size: 14px; line-height: 1.7; max-width: 480px; }
|
||||
.alumni-entry-action { display: flex; flex-direction: column; align-items: flex-end; gap: 14px; }
|
||||
.alumni-entry-action span { font-size: 11px; color: #aeb9b1; }
|
||||
.alumni-entry .primary-button { background: var(--lime); color: var(--ink); }
|
||||
|
||||
.skill-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
|
||||
.skill-grid.loading { display: block; color: var(--muted); padding: 40px 0; }
|
||||
.skill-card { border: 1px solid var(--line); border-radius: 18px; background: rgba(255,255,252,.82); overflow: hidden; transition: .2s ease; }
|
||||
.skill-card:hover { transform: translateY(-4px); box-shadow: 0 18px 38px rgba(38,48,40,.1); }
|
||||
.skill-header { height: 90px; background: var(--ink); display: flex; align-items: flex-end; padding: 18px; }
|
||||
.skill-meta { color: var(--lime); font-size: 10px; font-weight: 700; letter-spacing: .16em; }
|
||||
.skill-body { padding: 22px; display: flex; flex-direction: column; min-height: 180px; }
|
||||
.skill-body h3 { margin: 0 0 10px; font: 21px/1.3 Georgia, serif; }
|
||||
.skill-body p { color: var(--muted); font-size: 13px; line-height: 1.7; flex: 1; }
|
||||
.skill-body footer { display: flex; align-items: center; justify-content: space-between; margin-top: 18px; }
|
||||
.skill-body footer span { color: var(--muted); font-size: 12px; }
|
||||
.skill-body footer button { border: 0; border-bottom: 2px solid var(--green); background: transparent; color: var(--green); padding: 4px 0; cursor: pointer; font-weight: 650; }
|
||||
.skill-body footer button:disabled { cursor: not-allowed; opacity: .5; }
|
||||
|
||||
@media (max-width: 1050px) {
|
||||
.life-map-canvas { grid-template-columns: 1fr; }
|
||||
.life-map-lines, .life-map-center { display: none; }
|
||||
.alumni-entry-content { flex-direction: column; align-items: flex-start; }
|
||||
.alumni-entry-action { align-items: flex-start; }
|
||||
.skill-grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.skill-grid { grid-template-columns: 1fr; }
|
||||
.alumni-entry { padding: 28px 24px; }
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -1,3 +1,30 @@
|
||||
const ROUTE_MATHEMATICIANS = {
|
||||
believer: [
|
||||
{ name: "高斯", portrait: "/static/img/mathematicians/1000.png", identity: "定理工匠" },
|
||||
{ name: "祖冲之", portrait: "/static/img/mathematicians/1010.png", identity: "穷竭守尺人" },
|
||||
{ name: "欧拉", portrait: "/static/img/mathematicians/1001.png", identity: "公式狂僧" },
|
||||
{ name: "诺特", portrait: "/static/img/mathematicians/1011.png", identity: "抽象代数宗师" },
|
||||
],
|
||||
spreader: [
|
||||
{ name: "斐波那契", portrait: "/static/img/mathematicians/1100.png", identity: "商路算郎" },
|
||||
{ name: "华罗庚", portrait: "/static/img/mathematicians/1110.png", identity: "双法布道者" },
|
||||
{ name: "伽罗瓦", portrait: "/static/img/mathematicians/1101.png", identity: "决斗狂热者" },
|
||||
{ name: "Lovelace", portrait: "/static/img/mathematicians/1111.png", identity: "织机先知" },
|
||||
],
|
||||
applier: [
|
||||
{ name: "秦九韶", portrait: "/static/img/mathematicians/0100.png", identity: "大衍谋士" },
|
||||
{ name: "牛顿", portrait: "/static/img/mathematicians/0110.png", identity: "宇宙立法者" },
|
||||
{ name: "图灵", portrait: "/static/img/mathematicians/0111.png", identity: "密码破译使" },
|
||||
{ name: "冯·诺依曼", portrait: "/static/img/mathematicians/0101.png", identity: "博弈游侠" },
|
||||
],
|
||||
seer: [
|
||||
{ name: "希帕提娅", portrait: "/static/img/mathematicians/0000.png", identity: "几何殉道者" },
|
||||
{ name: "赵爽", portrait: "/static/img/mathematicians/0010.png", identity: "弦图先觉" },
|
||||
{ name: "庞加莱", portrait: "/static/img/mathematicians/0001.png", identity: "拓扑游方" },
|
||||
{ name: "约翰逊", portrait: "/static/img/mathematicians/0011.png", identity: "人脑计算机" },
|
||||
],
|
||||
};
|
||||
|
||||
const state = {
|
||||
user: null,
|
||||
stories: [],
|
||||
@@ -135,25 +162,100 @@ function card({ meta, title, body, foot, action, onClick, disabled = false }) {
|
||||
return article;
|
||||
}
|
||||
|
||||
function renderRouteMathematicians() {
|
||||
Object.entries(ROUTE_MATHEMATICIANS).forEach(([clan, mathematicians]) => {
|
||||
const root = $(`[data-mathematicians="${clan}"]`);
|
||||
if (!root) return;
|
||||
root.replaceChildren(...mathematicians.map((person) => {
|
||||
const item = document.createElement("div");
|
||||
item.className = "route-mathematician";
|
||||
const img = document.createElement("img");
|
||||
img.src = person.portrait;
|
||||
img.alt = person.name;
|
||||
img.loading = "lazy";
|
||||
const name = document.createElement("b");
|
||||
name.textContent = person.name;
|
||||
const identity = document.createElement("small");
|
||||
identity.textContent = person.identity;
|
||||
item.append(img, name, identity);
|
||||
return item;
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
async function loadStories() {
|
||||
const root = $("#story-list");
|
||||
try {
|
||||
state.stories = await api("math-life/stories/");
|
||||
root.classList.remove("loading");
|
||||
root.replaceChildren(...state.stories.map((story) => card({
|
||||
meta: story.kind === "flagship" ? "旗舰人生" : story.kind === "skill" ? "人物 Skill" : "特别篇",
|
||||
title: story.title,
|
||||
body: story.summary || "在不完整信息中判断机会、关系与代价。",
|
||||
foot: `约 ${story.estimated_minutes} 分钟`,
|
||||
action: story.available ? "开始人生 →" : "查看预告",
|
||||
disabled: !story.available,
|
||||
onClick: () => beginStory(story.slug),
|
||||
})));
|
||||
renderRouteBadges();
|
||||
renderSkillList();
|
||||
} catch (error) {
|
||||
root.textContent = error.message;
|
||||
showToast(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function renderRouteBadges() {
|
||||
const flagship = state.stories.find((story) => story.kind === "flagship" && story.available);
|
||||
const skillCount = state.stories.filter((story) => story.kind === "skill").length;
|
||||
const alumniCount = $("#alumni-count");
|
||||
alumniCount.textContent = skillCount > 0 ? `当前 ${skillCount} 个校友人生可体验` : "即将上线校友访谈";
|
||||
if (flagship) {
|
||||
const route = flagship.slug.includes("believer") ? "believer" : "believer";
|
||||
const card = $(`.route-card[data-route="${route}"]`);
|
||||
if (card) {
|
||||
card.querySelector(".route-status").textContent = `可体验 · 约 ${flagship.estimated_minutes} 分钟`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderSkillList() {
|
||||
const root = $("#skill-list");
|
||||
const skills = state.stories.filter((story) => story.kind === "skill");
|
||||
if (skills.length === 0) {
|
||||
root.classList.remove("loading");
|
||||
root.textContent = "校友访谈即将上线,敬请期待。";
|
||||
return;
|
||||
}
|
||||
root.classList.remove("loading");
|
||||
root.replaceChildren(...skills.map((story) => {
|
||||
const article = document.createElement("article");
|
||||
article.className = "skill-card";
|
||||
const header = document.createElement("div");
|
||||
header.className = "skill-header";
|
||||
const meta = document.createElement("span");
|
||||
meta.className = "skill-meta";
|
||||
meta.textContent = story.kind === "skill" ? "校友访谈" : "特别篇";
|
||||
header.append(meta);
|
||||
const body = document.createElement("div");
|
||||
body.className = "skill-body";
|
||||
const title = document.createElement("h3");
|
||||
title.textContent = story.title;
|
||||
const summary = document.createElement("p");
|
||||
summary.textContent = story.summary || "在不完整信息中判断机会、关系与代价。";
|
||||
const footer = document.createElement("footer");
|
||||
const duration = document.createElement("span");
|
||||
duration.textContent = `约 ${story.estimated_minutes} 分钟`;
|
||||
const button = document.createElement("button");
|
||||
button.textContent = story.available ? "开始人生 →" : "查看预告";
|
||||
button.disabled = !story.available;
|
||||
if (story.available) button.addEventListener("click", () => beginStory(story.slug));
|
||||
footer.append(duration, button);
|
||||
body.append(title, summary, footer);
|
||||
article.append(header, body);
|
||||
return article;
|
||||
}));
|
||||
}
|
||||
|
||||
function showLifeHub() {
|
||||
$("#life-hub").classList.remove("hidden");
|
||||
$("#life-skills").classList.add("hidden");
|
||||
}
|
||||
|
||||
function showLifeSkills() {
|
||||
$("#life-hub").classList.add("hidden");
|
||||
$("#life-skills").classList.remove("hidden");
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}
|
||||
|
||||
async function beginStory(slug) {
|
||||
if (!requireAuth()) return;
|
||||
try {
|
||||
@@ -909,6 +1011,18 @@ function switchTool(tool) {
|
||||
window.HuluToolbox?.activate(tool);
|
||||
}
|
||||
|
||||
function renderLatexPreview(source) {
|
||||
const target = $("#latex-preview");
|
||||
target.replaceChildren();
|
||||
if (!source.trim()) return;
|
||||
if (typeof katex === "undefined") { target.textContent = source; return; }
|
||||
try {
|
||||
katex.render(source, target, { throwOnError: false, displayMode: true });
|
||||
} catch {
|
||||
target.textContent = source;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveFormula() {
|
||||
if (!requireAuth()) return;
|
||||
try {
|
||||
@@ -928,13 +1042,34 @@ function bindUI() {
|
||||
$$("[data-open-auth]").forEach((button) => button.addEventListener("click", openAuth));
|
||||
$("#start-mathbti").addEventListener("click", startMathBTI);
|
||||
$("#save-formula").addEventListener("click", saveFormula);
|
||||
$("#latex-source").addEventListener("input", (event) => { $("#latex-preview").textContent = event.target.value; });
|
||||
$("#latex-source").addEventListener("input", (event) => { renderLatexPreview(event.target.value); });
|
||||
$$(".tool-card").forEach((button) => {
|
||||
button.addEventListener("click", () => switchTool(button.dataset.tool));
|
||||
});
|
||||
$("#symbol-search").addEventListener("input", (event) => {
|
||||
renderSymbols(event.target.value);
|
||||
});
|
||||
$("#enter-alumni").addEventListener("click", showLifeSkills);
|
||||
$("#back-to-hub").addEventListener("click", showLifeHub);
|
||||
$$(".route-card").forEach((card) => {
|
||||
card.addEventListener("click", (event) => {
|
||||
if (event.target.closest(".route-enter")) return;
|
||||
const route = card.dataset.route;
|
||||
const flagship = state.stories.find(
|
||||
(story) => story.kind === "flagship" && story.available && story.slug.includes(route),
|
||||
);
|
||||
if (flagship) beginStory(flagship.slug);
|
||||
else showToast(`${card.querySelector(".route-spirit b").textContent}人生即将开放`);
|
||||
});
|
||||
card.querySelector(".route-enter").addEventListener("click", () => {
|
||||
const route = card.dataset.route;
|
||||
const flagship = state.stories.find(
|
||||
(story) => story.kind === "flagship" && story.available && story.slug.includes(route),
|
||||
);
|
||||
if (flagship) beginStory(flagship.slug);
|
||||
else showToast(`${card.querySelector(".route-spirit b").textContent}人生即将开放`);
|
||||
});
|
||||
});
|
||||
$$(".ability-node").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
state.videoAbility =
|
||||
@@ -992,6 +1127,7 @@ function bindUI() {
|
||||
|
||||
async function boot() {
|
||||
bindUI();
|
||||
renderRouteMathematicians();
|
||||
window.HuluToolbox?.init();
|
||||
window.HuluRealtime?.init();
|
||||
renderSymbols();
|
||||
@@ -1002,6 +1138,7 @@ async function boot() {
|
||||
loadContent(),
|
||||
window.HuluGames?.load(),
|
||||
]);
|
||||
renderLatexPreview($("#latex-source").value);
|
||||
}
|
||||
|
||||
boot();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<meta name="description" content="葫芦数学:发现你的数学人格,经历属于你的数学人生。">
|
||||
<title>葫芦数学 · 数学人生宇宙</title>
|
||||
<link rel="stylesheet" href="{% static 'css/app.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'vendor/katex/katex.min.css' %}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="ambient ambient-one"></div>
|
||||
@@ -80,8 +81,90 @@
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-life">
|
||||
<div class="page-title"><span class="kicker">MATH LIFE HALL</span><h1>数学人生大厅</h1><p>长篇旗舰人生、人物 Skill 与特别篇,共用同一份成长档案。</p></div>
|
||||
<div id="story-list" class="content-grid loading">正在读取已发布人生…</div>
|
||||
<div class="life-hub" id="life-hub">
|
||||
<div class="page-title"><span class="kicker">MATH LIFE HALL</span><h1>数学人生大厅</h1><p>四条旗舰人生对应四种数学精神,人物 Skill 包持续扩展真实人生样本。</p></div>
|
||||
|
||||
<div class="life-map" id="life-map">
|
||||
<div class="life-map-canvas">
|
||||
<svg class="life-map-lines" viewBox="0 0 1200 520" preserveAspectRatio="xMidYMid meet" aria-hidden="true">
|
||||
<path d="M600 260 Q400 120 220 180" fill="none" stroke="rgba(25,101,72,.12)" stroke-width="2" stroke-dasharray="10 12"/>
|
||||
<path d="M600 260 Q800 120 980 180" fill="none" stroke="rgba(25,101,72,.12)" stroke-width="2" stroke-dasharray="10 12"/>
|
||||
<path d="M600 260 Q400 400 220 420" fill="none" stroke="rgba(25,101,72,.12)" stroke-width="2" stroke-dasharray="10 12"/>
|
||||
<path d="M600 260 Q800 400 980 420" fill="none" stroke="rgba(25,101,72,.12)" stroke-width="2" stroke-dasharray="10 12"/>
|
||||
<circle cx="600" cy="260" r="90" fill="rgba(25,101,72,.04)" stroke="rgba(25,101,72,.16)" stroke-width="2"/>
|
||||
<circle cx="600" cy="260" r="70" fill="none" stroke="rgba(25,101,72,.12)" stroke-width="2" stroke-dasharray="6 8"/>
|
||||
</svg>
|
||||
<div class="life-map-center">
|
||||
<b>葫</b><span>数学人生<br>交叉点</span>
|
||||
</div>
|
||||
<article class="route-card route-believer" data-clan="believer" data-route="believer">
|
||||
<span class="route-index">01</span>
|
||||
<div class="route-spirit">
|
||||
<b>信仰者</b><small>BELIEVER</small>
|
||||
</div>
|
||||
<p class="route-conflict">当答案还不存在,你是否仍愿意相信推理?</p>
|
||||
<div class="route-mathematicians" data-mathematicians="believer"></div>
|
||||
<div class="route-meta"><span class="route-status">旗舰人生 · 约 120 分钟</span></div>
|
||||
<button class="route-enter" data-route-enter="believer">进入信仰者人生 →</button>
|
||||
</article>
|
||||
|
||||
<article class="route-card route-spreader" data-clan="spreader" data-route="spreader">
|
||||
<span class="route-index">02</span>
|
||||
<div class="route-spirit">
|
||||
<b>传播者</b><small>SPREADER</small>
|
||||
</div>
|
||||
<p class="route-conflict">你会守住发现,还是让更多人理解它?</p>
|
||||
<div class="route-mathematicians" data-mathematicians="spreader"></div>
|
||||
<div class="route-meta"><span class="route-status">即将开放 · 序章可试</span></div>
|
||||
<button class="route-enter" data-route-enter="spreader">进入传播者人生 →</button>
|
||||
</article>
|
||||
|
||||
<article class="route-card route-applier" data-clan="applier" data-route="applier">
|
||||
<span class="route-index">03</span>
|
||||
<div class="route-spirit">
|
||||
<b>应用者</b><small>APPLIER</small>
|
||||
</div>
|
||||
<p class="route-conflict">数字进入现实之后,谁来承担模型的代价?</p>
|
||||
<div class="route-mathematicians" data-mathematicians="applier"></div>
|
||||
<div class="route-meta"><span class="route-status">即将开放 · 序章可试</span></div>
|
||||
<button class="route-enter" data-route-enter="applier">进入应用者人生 →</button>
|
||||
</article>
|
||||
|
||||
<article class="route-card route-seer" data-clan="seer" data-route="seer">
|
||||
<span class="route-index">04</span>
|
||||
<div class="route-spirit">
|
||||
<b>直觉者</b><small>SEER</small>
|
||||
</div>
|
||||
<p class="route-conflict">当形式尚未成形,你敢不敢追随结构感?</p>
|
||||
<div class="route-mathematicians" data-mathematicians="seer"></div>
|
||||
<div class="route-meta"><span class="route-status">即将开放 · 序章可试</span></div>
|
||||
<button class="route-enter" data-route-enter="seer">进入直觉者人生 →</button>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alumni-entry" id="alumni-entry">
|
||||
<div class="alumni-entry-content">
|
||||
<div>
|
||||
<span class="kicker">ALUMNI INTERVIEW</span>
|
||||
<h2>数学校友访谈</h2>
|
||||
<p>我们采访真实的数学校友,把他们的关键人生抉择浓缩为 20 分钟可体验的数学人生。</p>
|
||||
</div>
|
||||
<div class="alumni-entry-action">
|
||||
<span id="alumni-count">读取中…</span>
|
||||
<button class="primary-button" id="enter-alumni">进入访谈大厅 <b>→</b></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="life-skills hidden" id="life-skills">
|
||||
<div class="page-title">
|
||||
<button class="back-button" id="back-to-hub">← 返回数学人生大厅</button>
|
||||
<span class="kicker">ALUMNI INTERVIEW</span><h1>数学校友访谈</h1><p>每位校友的数学人生,浓缩为约 20 分钟的关键抉择体验。</p>
|
||||
</div>
|
||||
<div id="skill-list" class="skill-grid loading">正在读取校友人生…</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="view" id="view-contest">
|
||||
@@ -317,6 +400,7 @@
|
||||
|
||||
<div class="toast" id="toast" role="status"></div>
|
||||
<div class="csrf-token">{% csrf_token %}</div>
|
||||
<script src="{% static 'vendor/katex/katex.min.js' %}" defer></script>
|
||||
<script src="{% static 'js/toolbox.js' %}" defer></script>
|
||||
<script src="{% static 'js/games.js' %}" defer></script>
|
||||
<script src="{% static 'js/realtime.js' %}" defer></script>
|
||||
|
||||