commit 4983f342020517b874022fa1903572ec5203ac3d Author: Nelson <1475262689@qq.com> Date: Sun Apr 26 13:47:21 2026 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f331a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ + +# Superpowers (internal tooling) +.superpowers/ + +# Dependencies +node_modules/ + +# Environment +.env +.env.local diff --git a/assets/course-card.jpg b/assets/course-card.jpg new file mode 100644 index 0000000..317cd2a Binary files /dev/null and b/assets/course-card.jpg differ diff --git a/assets/icons/awakener.png b/assets/icons/awakener.png new file mode 100644 index 0000000..63f4487 Binary files /dev/null and b/assets/icons/awakener.png differ diff --git a/assets/icons/awakener.svg b/assets/icons/awakener.svg new file mode 100644 index 0000000..a9623b5 --- /dev/null +++ b/assets/icons/awakener.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/guardian.png b/assets/icons/guardian.png new file mode 100644 index 0000000..8d573bf Binary files /dev/null and b/assets/icons/guardian.png differ diff --git a/assets/icons/guardian.svg b/assets/icons/guardian.svg new file mode 100644 index 0000000..e5c27f0 --- /dev/null +++ b/assets/icons/guardian.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/habitual.png b/assets/icons/habitual.png new file mode 100644 index 0000000..9a266ec Binary files /dev/null and b/assets/icons/habitual.png differ diff --git a/assets/icons/habitual.svg b/assets/icons/habitual.svg new file mode 100644 index 0000000..8679bba --- /dev/null +++ b/assets/icons/habitual.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/icebreaker.png b/assets/icons/icebreaker.png new file mode 100644 index 0000000..e4188aa Binary files /dev/null and b/assets/icons/icebreaker.png differ diff --git a/assets/icons/icebreaker.svg b/assets/icons/icebreaker.svg new file mode 100644 index 0000000..c433134 --- /dev/null +++ b/assets/icons/icebreaker.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/pauser.png b/assets/icons/pauser.png new file mode 100644 index 0000000..f82a716 Binary files /dev/null and b/assets/icons/pauser.png differ diff --git a/assets/icons/pauser.svg b/assets/icons/pauser.svg new file mode 100644 index 0000000..6b12549 --- /dev/null +++ b/assets/icons/pauser.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/relational.png b/assets/icons/relational.png new file mode 100644 index 0000000..1924d96 Binary files /dev/null and b/assets/icons/relational.png differ diff --git a/assets/icons/relational.svg b/assets/icons/relational.svg new file mode 100644 index 0000000..a41da42 --- /dev/null +++ b/assets/icons/relational.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + ? + \ No newline at end of file diff --git a/assets/icons/seeker.png b/assets/icons/seeker.png new file mode 100644 index 0000000..7022e19 Binary files /dev/null and b/assets/icons/seeker.png differ diff --git a/assets/icons/seeker.svg b/assets/icons/seeker.svg new file mode 100644 index 0000000..5bdc345 --- /dev/null +++ b/assets/icons/seeker.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + ? + \ No newline at end of file diff --git a/assets/icons/sleeper.png b/assets/icons/sleeper.png new file mode 100644 index 0000000..a12c002 Binary files /dev/null and b/assets/icons/sleeper.png differ diff --git a/assets/icons/sleeper.svg b/assets/icons/sleeper.svg new file mode 100644 index 0000000..4d19ac6 --- /dev/null +++ b/assets/icons/sleeper.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + z + z + z + \ No newline at end of file diff --git a/assets/placeholder-qrcode.svg b/assets/placeholder-qrcode.svg new file mode 100644 index 0000000..97e088c --- /dev/null +++ b/assets/placeholder-qrcode.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/qrcode-site.png b/assets/qrcode-site.png new file mode 100644 index 0000000..f2efb2c Binary files /dev/null and b/assets/qrcode-site.png differ diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..b7efd82 --- /dev/null +++ b/css/style.css @@ -0,0 +1,1120 @@ +/* ======================================== + 传承基因测试 - 样式表 V2 + 设计方向:深邃、精致、有仪式感 + ======================================== */ + +/* ---------- CSS 变量 ---------- */ +:root { + --bg-deep: #0f0a1e; + --bg-mid: #1a1232; + --purple-1: #7c5cbf; + --purple-2: #a78bda; + --purple-3: #c4b5fd; + --gold: #f0c27a; + --gold-light: #fceabb; + --white: #ffffff; + --white-80: rgba(255,255,255,0.8); + --white-60: rgba(255,255,255,0.6); + --white-40: rgba(255,255,255,0.4); + --white-20: rgba(255,255,255,0.2); + --white-10: rgba(255,255,255,0.1); + --white-06: rgba(255,255,255,0.06); + --glass: rgba(255,255,255,0.07); + --glass-border: rgba(255,255,255,0.12); + --serif: 'Noto Serif SC', 'Songti SC', 'SimSun', serif; + --sans: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif; + --radius-sm: 10px; + --radius-md: 16px; + --radius-lg: 24px; + --radius-xl: 32px; +} + +/* ---------- 基础重置 ---------- */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-size: 16px; + -webkit-text-size-adjust: 100%; +} + +body { + font-family: var(--sans); + color: var(--white); + min-height: 100vh; + min-height: 100dvh; + overflow-x: hidden; + background: var(--bg-deep); +} + +/* ---------- 噪点纹理叠加 ---------- */ +.bg-noise { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E"); + background-size: 256px 256px; +} + +/* ---------- 页面切换 ---------- */ +.page { + display: none; + min-height: 100vh; + min-height: 100dvh; + position: relative; + z-index: 1; +} + +.page.active { + display: flex; + flex-direction: column; + animation: pageIn 0.5s cubic-bezier(0.22, 1, 0.36, 1); +} + +@keyframes pageIn { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +/* ---------- 按钮通用 ---------- */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 14px 32px; + border: none; + border-radius: var(--radius-lg); + font-family: var(--sans); + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1); + text-decoration: none; + text-align: center; + -webkit-tap-highlight-color: transparent; + position: relative; + overflow: hidden; +} + +.btn:active { + transform: scale(0.97); +} + +/* ======================================== + 首页 + ======================================== */ +#home { + justify-content: center; + align-items: center; + text-align: center; + padding: 24px; + overflow: hidden; + background: radial-gradient(ellipse at 50% 30%, rgba(124,92,191,0.25) 0%, transparent 60%), + radial-gradient(ellipse at 80% 80%, rgba(167,139,218,0.1) 0%, transparent 50%), + var(--bg-deep); +} + +/* 装饰 */ +.deco-circle { + position: absolute; + border-radius: 50%; + pointer-events: none; +} + +.deco-1 { + width: 400px; + height: 400px; + top: -150px; + right: -100px; + background: radial-gradient(circle, rgba(124,92,191,0.15) 0%, transparent 70%); +} + +.deco-2 { + width: 300px; + height: 300px; + bottom: -50px; + left: -100px; + background: radial-gradient(circle, rgba(240,194,122,0.08) 0%, transparent 70%); +} + +.deco-3 { + width: 200px; + height: 200px; + top: 50%; + left: 60%; + background: radial-gradient(circle, rgba(167,139,218,0.1) 0%, transparent 70%); +} + +.deco-glow { + position: absolute; + width: 500px; + height: 500px; + top: 50%; + left: 50%; + transform: translate(-50%, -60%); + background: radial-gradient(circle, rgba(124,92,191,0.12) 0%, transparent 60%); + pointer-events: none; + animation: glowPulse 6s ease-in-out infinite; +} + +@keyframes glowPulse { + 0%, 100% { opacity: 0.6; transform: translate(-50%, -60%) scale(1); } + 50% { opacity: 1; transform: translate(-50%, -60%) scale(1.1); } +} + +.home-content { + position: relative; + z-index: 1; +} + +.home-badge { + font-family: var(--sans); + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 4px; + color: var(--gold); + opacity: 0.7; + margin-bottom: 24px; + text-transform: uppercase; +} + +.home-title { + font-family: var(--serif); + font-size: 2.4rem; + font-weight: 900; + line-height: 1.35; + margin-bottom: 16px; + letter-spacing: 2px; + background: linear-gradient(135deg, var(--white) 0%, var(--purple-3) 50%, var(--gold-light) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.home-subtitle { + font-size: 1rem; + color: var(--white-60); + margin-bottom: 48px; + line-height: 1.6; + font-weight: 300; +} + +.btn-start { + background: linear-gradient(135deg, var(--purple-1) 0%, #9b6dd7 100%); + color: var(--white); + padding: 18px 48px; + font-size: 1.1rem; + border-radius: 60px; + box-shadow: 0 8px 32px rgba(124,92,191,0.4), 0 0 0 1px rgba(255,255,255,0.1) inset; + letter-spacing: 1px; +} + +.btn-start:hover { + box-shadow: 0 12px 40px rgba(124,92,191,0.5), 0 0 0 1px rgba(255,255,255,0.15) inset; + transform: translateY(-2px); +} + +.home-footer { + position: absolute; + bottom: 24px; + left: 0; + right: 0; + text-align: center; + z-index: 1; +} + +.privacy-link { + color: var(--white-40); + text-decoration: none; + font-size: 0.8rem; + cursor: pointer; + transition: color 0.2s; + border-bottom: 1px solid transparent; +} + +.privacy-link:hover { + color: var(--white-60); + border-bottom-color: var(--white-40); +} + +.disclaimer { + font-size: 0.7rem; + color: var(--white-20); + margin-top: 8px; + line-height: 1.6; + padding: 0 20px; +} + +/* ======================================== + 答题页 + ======================================== */ +#quiz { + padding: 0; + background: radial-gradient(ellipse at 50% 0%, rgba(124,92,191,0.15) 0%, transparent 50%), + var(--bg-deep); +} + +/* 顶部栏 */ +.quiz-topbar { + display: flex; + align-items: center; + gap: 12px; + padding: 16px 20px; + position: sticky; + top: 0; + z-index: 10; + background: rgba(15,10,30,0.8); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-bottom: 1px solid var(--glass-border); +} + +.btn-back { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid var(--glass-border); + background: var(--glass); + color: var(--white-80); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s; + flex-shrink: 0; + padding: 0; + font-size: 0; +} + +.btn-back:hover { + background: var(--white-10); + border-color: var(--white-20); +} + +.btn-back:active { + transform: scale(0.92); +} + +/* 进度条 - 高对比度设计 */ +.progress-area { + flex: 1; + display: flex; + align-items: center; + gap: 12px; +} + +.progress-track { + flex: 1; + height: 6px; + background: rgba(255,255,255,0.12); + border-radius: 3px; + overflow: hidden; + position: relative; +} + +.progress-fill { + height: 100%; + width: 0%; + border-radius: 3px; + background: linear-gradient(90deg, var(--purple-1), var(--gold)); + transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1); + position: relative; + box-shadow: 0 0 12px rgba(240,194,122,0.4); +} + +.progress-fill::after { + content: ''; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 12px; + height: 12px; + border-radius: 50%; + background: var(--gold); + box-shadow: 0 0 8px rgba(240,194,122,0.6), 0 0 20px rgba(240,194,122,0.3); + opacity: 0; + transition: opacity 0.3s; +} + +.progress-fill[style*="width: 0"]::after { + opacity: 0; +} + +.progress-fill:not([style*="width: 0"])::after { + opacity: 1; +} + +.progress-label { + font-size: 0.8rem; + font-weight: 600; + color: var(--white-60); + min-width: 42px; + text-align: right; + font-variant-numeric: tabular-nums; +} + +/* 题目区域 */ +.quiz-body { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 32px 24px 40px; + overflow: hidden; +} + +/* 题目切换动画容器 */ +.question-wrapper { + width: 100%; + max-width: 560px; + overflow: hidden; + margin-bottom: 40px; +} + +.question-inner { + transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), + opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1); +} + +.question-inner.slide-out-left { + transform: translateX(-60px); + opacity: 0; +} + +.question-inner.slide-in-right { + transform: translateX(60px); + opacity: 0; +} + +.question-inner.slide-out-right { + transform: translateX(60px); + opacity: 0; +} + +.question-inner.slide-in-left { + transform: translateX(-60px); + opacity: 0; +} + +.question-number { + display: inline-block; + font-family: var(--sans); + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 2px; + color: var(--gold); + background: rgba(240,194,122,0.1); + border: 1px solid rgba(240,194,122,0.2); + padding: 4px 14px; + border-radius: 20px; + margin-bottom: 20px; +} + +.quiz-question { + font-family: var(--serif); + font-size: 1.25rem; + line-height: 1.8; + text-align: center; + color: var(--white); + font-weight: 600; + min-height: 60px; + display: flex; + align-items: center; + justify-content: center; +} + +/* 量表按钮 - 全新设计 */ +.scale-buttons { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; + max-width: 400px; +} + +.btn-scale { + display: flex; + align-items: center; + gap: 14px; + width: 100%; + padding: 16px 20px; + border: 1.5px solid var(--glass-border); + border-radius: var(--radius-md); + background: var(--glass); + color: var(--white-80); + font-family: var(--sans); + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1); + text-align: left; + -webkit-tap-highlight-color: transparent; + min-height: 56px; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + /* 选项弹入动画 */ + opacity: 0; + transform: translateY(16px); + animation: scaleIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards; +} + +.btn-scale:nth-child(1) { animation-delay: 0.05s; } +.btn-scale:nth-child(2) { animation-delay: 0.1s; } +.btn-scale:nth-child(3) { animation-delay: 0.15s; } +.btn-scale:nth-child(4) { animation-delay: 0.2s; } +.btn-scale:nth-child(5) { animation-delay: 0.25s; } + +@keyframes scaleIn { + from { opacity: 0; transform: translateY(16px); } + to { opacity: 1; transform: translateY(0); } +} + +.btn-scale:hover { + background: rgba(255,255,255,0.12); + border-color: var(--white-20); + transform: translateY(-1px); +} + +.btn-scale:active { + transform: scale(0.98); +} + +.btn-scale.selected { + background: linear-gradient(135deg, rgba(124,92,191,0.4) 0%, rgba(167,139,218,0.3) 100%); + border-color: var(--purple-2); + box-shadow: 0 4px 20px rgba(124,92,191,0.3), inset 0 0 0 1px rgba(255,255,255,0.1); + color: var(--white); + font-weight: 600; +} + +.scale-emoji { + font-size: 1.3rem; + flex-shrink: 0; + width: 28px; + text-align: center; +} + +.scale-text { + flex: 1; +} + +.quiz-disclaimer { + font-size: 0.7rem; + color: var(--white-20); + margin-top: 32px; + text-align: center; + line-height: 1.5; + padding: 0 20px; +} + +/* ======================================== + 计算页 + ======================================== */ +#loading { + justify-content: center; + align-items: center; + background: var(--bg-deep); +} + +.loading-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 40px; +} + +/* DNA 动画 */ +.loading-dna { + position: relative; + width: 60px; + height: 120px; +} + +.dna-strand { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: center; + animation: dnaRotate 3s ease-in-out infinite; +} + +.dna-strand span { + width: 10px; + height: 10px; + border-radius: 50%; + background: var(--purple-2); + box-shadow: 0 0 12px rgba(167,139,218,0.6); +} + +.dna-strand-2 { + animation-delay: -1.5s; +} + +.dna-strand-2 span { + background: var(--gold); + box-shadow: 0 0 12px rgba(240,194,122,0.6); +} + +@keyframes dnaRotate { + 0%, 100% { transform: translateX(0); } + 25% { transform: translateX(20px); } + 75% { transform: translateX(-20px); } +} + +.loading-text { + font-family: var(--serif); + font-size: 1.1rem; + color: var(--white-60); + font-weight: 400; +} + +.loading-dots::after { + content: ''; + animation: dots 1.5s steps(4, end) infinite; +} + +@keyframes dots { + 0% { content: ''; } + 25% { content: '.'; } + 50% { content: '..'; } + 75% { content: '...'; } +} + +/* ======================================== + 结果页 + ======================================== */ +#result { + padding: 0; + background: radial-gradient(ellipse at 50% 0%, rgba(124,92,191,0.2) 0%, transparent 50%), + radial-gradient(ellipse at 50% 100%, rgba(240,194,122,0.08) 0%, transparent 40%), + var(--bg-deep); +} + +.result-scroll { + flex: 1; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + padding: 0 20px 60px; + max-width: 560px; + margin: 0 auto; + width: 100%; +} + +.result-scroll::-webkit-scrollbar { display: none; } +.result-scroll { -ms-overflow-style: none; scrollbar-width: none; } + +/* 类型展示区 - Hero设计 */ +.result-hero { + text-align: center; + padding: 48px 0 32px; + position: relative; +} + +.result-icon-ring { + width: 140px; + height: 140px; + margin: 0 auto 24px; + border-radius: 50%; + background: linear-gradient(135deg, rgba(124,92,191,0.3) 0%, rgba(240,194,122,0.2) 100%); + border: 2px solid var(--glass-border); + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; + animation: iconFloat 4s ease-in-out infinite; + box-shadow: 0 0 40px rgba(124,92,191,0.2), 0 0 80px rgba(124,92,191,0.1); +} + +.result-icon-ring::before { + content: ''; + position: absolute; + inset: -6px; + border-radius: 50%; + border: 1px solid rgba(240,194,122,0.2); + animation: ringPulse 3s ease-in-out infinite; +} + +@keyframes iconFloat { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-8px); } +} + +@keyframes ringPulse { + 0%, 100% { opacity: 0.3; transform: scale(1); } + 50% { opacity: 0.8; transform: scale(1.05); } +} + +.result-icon { + width: 210px; + height: 210px; + filter: drop-shadow(0 2px 8px rgba(0,0,0,0.3)); +} + +.result-label { + font-size: 0.8rem; + color: var(--white-40); + letter-spacing: 3px; + text-transform: uppercase; + margin-bottom: 8px; + font-weight: 500; +} + +.result-name { + font-family: var(--serif); + font-size: 2.6rem; + font-weight: 900; + margin-bottom: 12px; + background: linear-gradient(135deg, var(--white) 20%, var(--gold-light) 80%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + letter-spacing: 4px; +} + +.result-desc { + font-size: 0.95rem; + color: var(--white-60); + line-height: 1.6; + font-weight: 300; +} + +/* 结果卡片 */ +.result-card { + background: var(--glass); + border: 1px solid var(--glass-border); + border-radius: var(--radius-lg); + padding: 24px 20px; + margin-bottom: 16px; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} + +.card-title { + font-size: 0.9rem; + font-weight: 600; + color: var(--white-80); + margin-bottom: 20px; + display: flex; + align-items: center; + gap: 8px; + letter-spacing: 1px; +} + +.card-title svg { + color: var(--gold); + flex-shrink: 0; +} + +/* 雷达图 */ +#radar-canvas { + display: block; + margin: 0 auto; + max-width: 100%; +} + +/* 分析文字 */ +.result-analysis { + font-size: 0.92rem; + line-height: 2; + color: var(--white-80); + text-align: justify; +} + +/* 课程推荐 */ +.recommend-card { + text-align: center; + border-color: rgba(240,194,122,0.15); + background: linear-gradient(135deg, rgba(240,194,122,0.05) 0%, var(--glass) 100%); +} + +.result-recommend { + font-size: 0.92rem; + line-height: 1.8; + color: var(--white-80); + margin-bottom: 24px; +} + +.course-card-wrapper { + display: flex; + flex-direction: column; + align-items: center; +} + +.course-card-img { + width: 100%; + max-width: 320px; + height: auto; + display: block; + border-radius: var(--radius-md); + box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.08); + cursor: pointer; + transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.3s ease; + -webkit-user-select: none; + user-select: none; + -webkit-touch-callout: none; +} + +.course-card-img:active { + transform: scale(0.98); +} + +.course-card-hint { + font-size: 0.8rem; + color: var(--white-40); + margin-top: 16px; + letter-spacing: 1px; +} + +/* 课程大图弹窗 */ +.course-modal-img { + max-width: 92vw; + max-height: 85vh; + object-fit: contain; + border-radius: var(--radius-md); + box-shadow: 0 16px 64px rgba(0,0,0,0.6); + -webkit-user-select: none; + user-select: none; + -webkit-touch-callout: default; +} + +/* 操作按钮 */ +.result-actions { + display: flex; + flex-direction: column; + gap: 12px; + margin: 32px 0 20px; +} + +.btn-share { + background: linear-gradient(135deg, var(--purple-1) 0%, #9b6dd7 100%); + color: var(--white); + padding: 16px 32px; + font-size: 1rem; + border-radius: 60px; + box-shadow: 0 8px 24px rgba(124,92,191,0.3); +} + +.btn-share:hover { + box-shadow: 0 12px 32px rgba(124,92,191,0.4); + transform: translateY(-2px); +} + +.btn-retry { + background: transparent; + color: var(--white-40); + border: 1.5px solid var(--glass-border); + padding: 14px 32px; + font-size: 0.9rem; + border-radius: 60px; +} + +.btn-retry:hover { + color: var(--white-60); + border-color: var(--white-20); + background: var(--glass); +} + +.result-disclaimer { + text-align: center; +} + +/* ======================================== + 海报 + ======================================== */ +.poster-container { + display: none; + position: fixed; + inset: 0; + z-index: 1000; + background: rgba(0,0,0,0.92); + overflow: hidden; +} + +.poster-container.active { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.poster-content { + width: 750px; + height: 1334px; + background: linear-gradient(160deg, #1a1232 0%, #0f0a1e 40%, #1a1232 100%); + position: fixed; + left: -9999px; + top: 0; + overflow: hidden; + border-radius: var(--radius-md); +} + +.poster-header { + text-align: center; + padding: 60px 40px 30px; +} + +.poster-brand { + font-family: var(--sans); + font-size: 16px; + font-weight: 600; + letter-spacing: 6px; + color: var(--gold); + opacity: 0.6; + margin-bottom: 30px; + text-transform: uppercase; +} + +.poster-icon { + width: 180px; + height: 180px; + margin-bottom: 24px; +} + +.poster-name { + font-family: var(--serif); + font-size: 52px; + font-weight: 900; + margin-bottom: 16px; + color: var(--white); + letter-spacing: 6px; +} + +.poster-desc { + font-size: 24px; + color: var(--white-60); + line-height: 1.6; + margin-bottom: 24px; +} + +.poster-quote { + font-family: var(--serif); + font-size: 22px; + color: var(--gold); + line-height: 1.6; + letter-spacing: 2px; + opacity: 0.8; +} + +.poster-radar-wrap { + display: flex; + justify-content: center; + padding: 20px 0; +} + +#poster-radar-canvas { + display: block; +} + +.poster-footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + text-align: center; + padding: 40px 40px 80px; + background: linear-gradient(to top, rgba(15,10,30,0.95), transparent); +} + +.poster-slogan { + font-family: var(--serif); + font-size: 28px; + color: var(--white-80); + margin-bottom: 8px; + font-weight: 600; + letter-spacing: 2px; +} + +.poster-cta { + font-family: var(--serif); + font-size: 32px; + color: var(--white); + font-weight: 700; + letter-spacing: 3px; + margin-bottom: 24px; +} + +.poster-qrcode { + width: 160px; + height: 160px; + background: var(--white); + border-radius: var(--radius-sm); + padding: 10px; + margin: 0 auto; +} + +.poster-preview { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 90%; + max-width: 400px; +} + +.poster-preview-title { + color: var(--white-80); + font-size: 1rem; + margin-bottom: 16px; + font-weight: 500; +} + +.poster-image { + max-width: 100%; + max-height: 70vh; + border-radius: var(--radius-md); + box-shadow: 0 12px 40px rgba(0,0,0,0.5); + object-fit: contain; +} + +.poster-preview .btn { + margin-top: 24px; + margin-bottom: max(20px, env(safe-area-inset-bottom)); +} + +/* ======================================== + 隐私弹窗 + ======================================== */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0,0,0,0.7); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + z-index: 2000; + display: flex; + justify-content: center; + align-items: center; + padding: 24px; + animation: modalIn 0.3s cubic-bezier(0.22, 1, 0.36, 1); +} + +@keyframes modalIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.modal-card { + background: linear-gradient(135deg, #1e1638 0%, #15102a 100%); + color: var(--white); + border: 1px solid var(--glass-border); + border-radius: var(--radius-xl); + padding: 36px 28px; + max-width: 420px; + width: 100%; + max-height: 80vh; + overflow-y: auto; + animation: cardSlideUp 0.4s cubic-bezier(0.22, 1, 0.36, 1); +} + +@keyframes cardSlideUp { + from { transform: translateY(30px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} + +.modal-title { + font-family: var(--serif); + font-size: 1.3rem; + font-weight: 700; + color: var(--gold); + margin-bottom: 24px; + text-align: center; + letter-spacing: 2px; +} + +.modal-body p { + font-size: 0.88rem; + line-height: 1.8; + margin-bottom: 14px; + color: var(--white-60); +} + +.modal-body strong { + color: var(--purple-2); +} + +.btn-modal-confirm { + margin-top: 24px; + background: linear-gradient(135deg, var(--purple-1), #9b6dd7); + color: var(--white); + width: 100%; + padding: 14px; + border-radius: 60px; + box-shadow: 0 4px 16px rgba(124,92,191,0.3); +} + +/* ======================================== + 响应式 + ======================================== */ + +@media (min-width: 360px) { + .home-title { font-size: 2.6rem; } + .quiz-question { font-size: 1.3rem; } +} + +@media (min-width: 480px) { + .home-title { font-size: 3rem; } + .home-subtitle { font-size: 1.1rem; } + .quiz-question { font-size: 1.4rem; } + .result-name { font-size: 3rem; } + .result-icon-ring { width: 160px; height: 160px; } + .result-icon { width: 240px; height: 240px; } +} + +@media (min-width: 768px) { + .home-title { font-size: 3.6rem; } + + .scale-buttons { + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + gap: 10px; + } + + .btn-scale { + width: auto; + min-width: 160px; + flex-direction: column; + align-items: center; + gap: 6px; + padding: 14px 18px; + } + + .scale-emoji { + font-size: 1.5rem; + } + + .result-scroll { padding: 0 40px 80px; } + .result-card { padding: 28px 28px; } + + .result-actions { + flex-direction: row; + justify-content: center; + max-width: 400px; + margin: 32px auto 20px; + } + + .result-actions .btn { margin: 0; } +} + +@media (min-width: 1024px) { + .home-title { font-size: 4rem; } + .quiz-question { font-size: 1.5rem; } + .result-name { font-size: 3.4rem; } + .result-icon-ring { width: 180px; height: 180px; } + .result-icon { width: 270px; height: 270px; } + .result-scroll { padding: 0 60px 100px; } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..6dc8005 --- /dev/null +++ b/index.html @@ -0,0 +1,218 @@ + + + + + + + 传承基因测试 + + + + + + + + +
+
+
+
+
+
+ +
+
HERITAGE GENE TEST
+

你的传承基因
是什么?

+

3 分钟测试,发现你的家族传承类型

+ +
+ + +
+ + +
+
+ + +
+ +
+
+
+
+ 1 / 18 +
+
+
+ + +
+
+
+ Q1 +

+
+
+ +
+ + + + + +
+ +

本测试仅供自我探索参考,不构成专业心理评估或诊断

+
+
+ + +
+
+
+
+
+ +
+
+ +
+
+

正在解码你的传承基因

+
+
+ + +
+
+
+ +
+
+ 类型图标 +
+
+

你的传承类型是

+

+

+
+
+ + +
+

+ + 六维能力图谱 +

+ +
+ + +
+

+ + 深度解析 +

+

+
+ + +
+

+ + 专属成长建议 +

+

+
+ 卢慧-家庭关系直播课 +

👆 点击查看大图 · 长按识别二维码

+
+
+ + +
+ + +
+ +

本测试仅供自我探索参考,不构成专业心理评估或诊断

+
+
+ + +
+
+
+

传承基因测试

+ +

+

+

+
+
+ +
+ +
+ +
+ + + + + + + + + + + \ No newline at end of file diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..6138aa1 --- /dev/null +++ b/js/app.js @@ -0,0 +1,684 @@ +/** + * 传承基因测试 - 主逻辑 + * 包含:题目数据、类型数据、答题流程、计分逻辑、雷达图绘制、海报生成 + */ + +(function () { + 'use strict'; + + // ======================================== + // 题目数据(18题,6个维度,每维度3题) + // ======================================== + const questions = [ + // 维度1 - 自我觉察力(题1-3) + '当我感到烦躁时,我能说出自己真正在气什么,而不是只觉得"烦"', + '我经常反思自己的行为模式,而不是只看到别人的问题', + '面对冲突时,我能觉察到自己身体的变化(心跳加速、肌肉紧绷等)', + // 维度2 - 情绪驾驭力(题4-6) + '在和孩子吵架后,我能让自己冷静下来再去沟通,而不是冷战或翻旧账', + '当情绪上来时,我能让自己暂停几秒再回应,而不是脱口而出', + '我很少因为一时冲动说出让自己后悔的话', + // 维度3 - 关系修复力(题7-9) + '我发现自己和父母的相处方式,正在不知不觉中复制到我和孩子的关系上', + '当关系出现问题时,我愿意主动去修复,而不是等对方先改变', + '我能分辨哪些情绪是自己的,哪些是"替别人承担的"', + // 维度4 - 传承意识(题10-12) + '我想过自己的某些性格特点或反应模式,可能是从祖辈那里继承来的', + '我注意到家族里有些模式在一代代重复(比如某种情绪、某种关系模式)', + '我相信了解家族的历史和故事,对理解和教育孩子有帮助', + // 维度5 - 内在驱动力(题13-15) + '我清楚自己为什么要做现在做的事,而不是随大流或被外界推着走', + '我觉得自己的人生是自己主动选择的,而不是被安排好的', + '遇到困难时,我能找到继续前行的内在力量,而不是只靠外部压力', + // 维度6 - 成长信念(题16-18) + '我相信不管现在是什么状态,人都可以改变和成长', + '我愿意为了长远的目标,每天坚持做一点小事', + '我觉得"慢慢来"不是放弃,而是一种智慧' + ]; + + // 维度名称(用于雷达图标签) + const dimensionNames = [ + '自我觉察力', '情绪驾驭力', '关系修复力', + '传承意识', '内在驱动力', '成长信念' + ]; + + // ======================================== + // 8种类型数据 + // ======================================== + const types = { + awakener: { + name: '觉醒者', + icon: 'assets/icons/awakener.png', + desc: '已走在自我成长路上,觉察力和情绪力都很强', + quote: '「看见即觉察,觉察即涨心」', + analysis: '你拥有出色的自我觉察能力,能够清晰地看见自己的情绪和念头。在情绪管理方面,你已经掌握了"知止"的智慧,能在关键时刻停住并选择回应方式。你正在成为自己生活的"第一目击证人",内在诚信正在建立。继续深化修炼,从"看见"走向"止于至善",你将影响整个家族的传承模式。', + recommend: '你已经走在觉醒的路上,课程将帮你从"看见"走向"止于至善",深化修炼,让美好状态持续。' + }, + icebreaker: { + name: '破冰人', + icon: 'assets/icons/icebreaker.png', + desc: '正在打破家族旧模式,传承意识和关系修复力突出', + quote: '「旧地图无法发现新大陆」', + analysis: '你对家族传承有着深刻的意识,能够看到代际之间传递的模式。你已经开始打破那些不再服务于你的共生剧本,在关系修复方面展现出勇气和行动力。你正在成为家族中"那个不一样的人"。系统学习冰山模型,将帮助你更深入地理解这些模式背后的根源。', + recommend: '你已开始打破旧模式,课程将带你系统理解冰山下的家族数据,找到真正的破冰点。' + }, + pauser: { + name: '知止行者', + icon: 'assets/icons/pauser.png', + desc: '情绪驾驭力突出,能在关键时刻停住', + quote: '「在电光火石间看见自己」', + analysis: '你拥有强大的情绪驾驭能力,能够在情绪升起的瞬间停住,善用那0.0001秒的间隙。这是非常珍贵的能力——很多人终其一生都在被情绪带着走。不过,你还可以更进一步:从"知止"到"看见",觉察情绪背后的根源。当你能看见情绪从哪里来,你就真正掌握了选择的自由。', + recommend: '你已能在情绪中停住,课程将帮你看见情绪背后的根源,从"知止"走向"格物致知"。' + }, + guardian: { + name: '传承守护者', + icon: 'assets/icons/guardian.png', + desc: '传承意识强、成长信念坚定,但行动力还不足', + quote: '「冰冻三尺非一日之寒,精诚所至金石为开」', + analysis: '你对家族传承有着深刻的理解和坚定的成长信念,你知道改变需要时间和耐心。你的内在已经有了清晰的认知,但从意识到行动之间还有一段距离。这不是你的问题——冰冻三尺非一日之寒。关键是从最小的行动开始,日拱一卒,让认知慢慢落地为每天的功课。', + recommend: '你对传承有深刻意识,课程将帮你把意识转化为每天的功课,从"知道"到"做到"。' + }, + seeker: { + name: '寻道者', + icon: 'assets/icons/seeker.png', + desc: '成长信念强、内在驱动力高,但方向还不够清晰', + quote: '「通过外面生活现象,找到内在卡点」', + analysis: '你拥有强大的内在驱动力和坚定的成长信念,这是非常宝贵的品质。你已经准备好改变,也愿意为此投入时间和精力。但有时候你可能感到方向不够清晰——知道要改变,但不知道从哪里开始。这正是"格物致知"的用武之地:通过外面生活现象找到内在卡点,方向自然就会浮现。', + recommend: '你有强大的成长动力,课程将帮你找到内在卡点,明确方向,从"寻找"到"看见"。' + }, + sleeper: { + name: '沉睡者', + icon: 'assets/icons/sleeper.png', + desc: '多维度偏低,但成长信念还在,是觉醒的起点', + quote: '「每个人本自具足,生来就足够好」', + analysis: '你可能觉得自己在生活的惯性中运转,很多方面都还没有找到方向。但请看到一件重要的事:你的成长信念还在——你相信人可以改变,这本身就是觉醒的种子。很多人连这颗种子都没有。觉醒的第一步,不是做更多,而是"看见"——看见自己的情绪、念头和模式。从"我看见我"开始,一切都会不同。', + recommend: '觉醒的第一步是看见。课程将从最基础的"我看见我"开始,帮你唤醒内在的力量。' + }, + relational: { + name: '关系困者', + icon: 'assets/icons/relational.png', + desc: '关系是最大痛点,情绪驾驭和关系修复都较弱', + quote: '「找回足够好的自己,用它修复生活」', + analysis: '关系是你当前最大的挑战和突破口。你可能发现自己总是在重复某些关系模式——和父母的、和伴侣的、和孩子的。这些模式不是你的错,它们是家族大数据通过代际传承传递下来的"共生剧本"。好消息是,你已经意识到了问题所在,这就是改变的开始。从"我看见我的妈妈"开始,你将慢慢解开这些关系的结。', + recommend: '关系是你的突破口,课程将教你从"我看见我的妈妈"开始,修复关系,走出共生剧本。' + }, + habitual: { + name: '惯性行者', + icon: 'assets/icons/habitual.png', + desc: '在惯性中运转,内在驱动力和自我觉察都较弱', + quote: '「慢慢来比较快」', + analysis: '你可能感觉自己像一台被程序化运转的机器——每天做着差不多的事,想着差不多的念头,每一念都来自过去。这不是你的问题,而是每个人都可能陷入的状态,课程中称之为"空心人"或"NPC"。但旧地图无法发现新大陆,看见即觉察,觉察即涨心。当你开始看见自己的惯性,改变就已经发生了。', + recommend: '看见即觉察,觉察即涨心。课程将帮你走出惯性,找回内在力量,从"NPC"变回自己。' + } + }; + + // ======================================== + // 状态管理 + // ======================================== + let currentQuestion = 0; // 当前题目索引(0-17) + let answers = []; // 答题记录(长度18,每项1-5) + + // localStorage 键名 + const STORAGE_KEY = 'heritage_gene_test'; + + // ======================================== + // DOM 元素引用 + // ======================================== + const $home = document.getElementById('home'); + const $quiz = document.getElementById('quiz'); + const $loading = document.getElementById('loading'); + const $result = document.getElementById('result'); + const $poster = document.getElementById('poster'); + + const $progressFill = document.getElementById('progress-fill'); + const $progressText = document.getElementById('progress-text'); + const $quizQuestion = document.getElementById('quiz-question'); + const $questionNumber = document.getElementById('question-number'); + const $questionInner = document.getElementById('question-wrapper').querySelector('.question-inner'); + const $scaleButtons = document.getElementById('scale-buttons'); + const $btnPrev = document.getElementById('btn-prev'); + + const $resultIcon = document.getElementById('result-icon'); + const $resultName = document.getElementById('result-name'); + const $resultDesc = document.getElementById('result-desc'); + const $resultAnalysis = document.getElementById('result-analysis'); + const $resultRecommend = document.getElementById('result-recommend'); + const $radarCanvas = document.getElementById('radar-canvas'); + + const $posterIcon = document.getElementById('poster-icon'); + const $posterName = document.getElementById('poster-name'); + const $posterDesc = document.getElementById('poster-desc'); + const $posterQuote = document.getElementById('poster-quote'); + const $posterRadarCanvas = document.getElementById('poster-radar-canvas'); + const $posterContent = document.getElementById('poster-content'); + const $posterPreview = document.getElementById('poster-preview'); + const $posterImage = document.getElementById('poster-image'); + + const $privacyModal = document.getElementById('privacy-modal'); + const $courseModal = document.getElementById('course-modal'); + const $courseModalImg = document.getElementById('course-modal-img'); + const $courseCardImg = document.getElementById('course-card-img'); + + // ======================================== + // 初始化 + // ======================================== + function init() { + // 尝试从 localStorage 恢复进度 + loadProgress(); + + // 绑定事件 + document.getElementById('btn-start').addEventListener('click', startQuiz); + document.getElementById('btn-prev').addEventListener('click', prevQuestion); + document.getElementById('btn-share').addEventListener('click', generatePoster); + document.getElementById('btn-retry').addEventListener('click', retryQuiz); + document.getElementById('btn-privacy').addEventListener('click', function () { + $privacyModal.style.display = 'flex'; + }); + document.getElementById('btn-close-privacy').addEventListener('click', function () { + $privacyModal.style.display = 'none'; + }); + document.getElementById('btn-poster-close').addEventListener('click', closePoster); + + // 点击遮罩关闭弹窗 + $privacyModal.addEventListener('click', function (e) { + if (e.target === $privacyModal) { + $privacyModal.style.display = 'none'; + } + }); + + // 课程卡片:点击查看大图 + $courseCardImg.addEventListener('click', function () { + $courseModalImg.src = $courseCardImg.src; + $courseModal.style.display = 'flex'; + }); + + // 课程大图:点击遮罩关闭 + $courseModal.addEventListener('click', function (e) { + if (e.target === $courseModal) { + $courseModal.style.display = 'none'; + } + }); + + // 量表按钮事件委托 + $scaleButtons.addEventListener('click', function (e) { + var btn = e.target.closest('.btn-scale'); + if (!btn) return; + var value = parseInt(btn.getAttribute('data-value')); + selectAnswer(value); + }); + } + + // ======================================== + // 页面切换 + // ======================================== + function showPage(pageId) { + var pages = document.querySelectorAll('.page'); + pages.forEach(function (p) { + p.classList.remove('active'); + }); + document.getElementById(pageId).classList.add('active'); + // 滚动到顶部 + window.scrollTo(0, 0); + } + + // ======================================== + // 答题流程 + // ======================================== + + /** 开始测试 */ + function startQuiz() { + currentQuestion = 0; + answers = new Array(questions.length).fill(0); + saveProgress(); + showPage('quiz'); + renderQuestion(); + } + + /** 渲染当前题目(带滑动动画) */ + function renderQuestion(direction) { + // direction: 'next' | 'prev' | undefined(首次) + var doRender = function() { + // 更新进度 + var progress = ((currentQuestion) / questions.length) * 100; + $progressFill.style.width = progress + '%'; + $progressText.textContent = (currentQuestion + 1) + ' / ' + questions.length; + + // 更新题目 + $questionNumber.textContent = 'Q' + (currentQuestion + 1); + $quizQuestion.textContent = questions[currentQuestion]; + + // 更新量表按钮状态 + var btns = $scaleButtons.querySelectorAll('.btn-scale'); + var currentAnswer = answers[currentQuestion]; + btns.forEach(function (btn) { + var val = parseInt(btn.getAttribute('data-value')); + if (val === currentAnswer) { + btn.classList.add('selected'); + } else { + btn.classList.remove('selected'); + } + }); + + // 重置选项弹入动画 + resetScaleAnimation(); + + // 上一题按钮 + $btnPrev.style.visibility = currentQuestion > 0 ? 'visible' : 'hidden'; + + // 滑入 + if (direction === 'next') { + $questionInner.classList.remove('slide-in-right', 'slide-out-left', 'slide-in-left', 'slide-out-right'); + $questionInner.classList.add('slide-in-right'); + requestAnimationFrame(function() { + requestAnimationFrame(function() { + $questionInner.classList.remove('slide-in-right'); + }); + }); + } else if (direction === 'prev') { + $questionInner.classList.remove('slide-in-right', 'slide-out-left', 'slide-in-left', 'slide-out-right'); + $questionInner.classList.add('slide-in-left'); + requestAnimationFrame(function() { + requestAnimationFrame(function() { + $questionInner.classList.remove('slide-in-left'); + }); + }); + } + }; + + if (!direction) { + doRender(); + return; + } + + // 先滑出当前题目 + var outClass = direction === 'next' ? 'slide-out-left' : 'slide-out-right'; + $questionInner.classList.remove('slide-in-right', 'slide-out-left', 'slide-in-left', 'slide-out-right'); + $questionInner.classList.add(outClass); + + setTimeout(function() { + doRender(); + }, 250); + } + + /** 重置量表按钮的弹入动画 */ + function resetScaleAnimation() { + var btns = $scaleButtons.querySelectorAll('.btn-scale'); + btns.forEach(function(btn) { + btn.style.animation = 'none'; + btn.offsetHeight; // 触发重排 + btn.style.animation = ''; + }); + } + + /** 选择答案 */ + function selectAnswer(value) { + answers[currentQuestion] = value; + saveProgress(); + + // 高亮选中按钮 + var btns = $scaleButtons.querySelectorAll('.btn-scale'); + btns.forEach(function (btn) { + var val = parseInt(btn.getAttribute('data-value')); + if (val === value) { + btn.classList.add('selected'); + } else { + btn.classList.remove('selected'); + } + }); + + // 更新进度条到当前题的完成状态 + var progress = ((currentQuestion + 1) / questions.length) * 100; + $progressFill.style.width = progress + '%'; + + // 0.3秒后自动跳下一题 + setTimeout(function () { + if (currentQuestion < questions.length - 1) { + currentQuestion++; + renderQuestion('next'); + } else { + // 最后一题,进入计算页 + showLoading(); + } + }, 300); + } + + /** 上一题 */ + function prevQuestion() { + if (currentQuestion > 0) { + currentQuestion--; + renderQuestion('prev'); + } + } + + // ======================================== + // 计算页 + // ======================================== + function showLoading() { + showPage('loading'); + // 2.5秒后跳转结果页 + setTimeout(function () { + calculateAndShowResult(); + }, 2500); + } + + // ======================================== + // 计分与类型匹配 + // ======================================== + function calculateAndShowResult() { + // 计算各维度分数(每维度3题,分值3-15) + var dimensions = []; + for (var d = 0; d < 6; d++) { + var sum = 0; + for (var q = 0; q < 3; q++) { + sum += answers[d * 3 + q]; + } + dimensions.push(sum); + } + + // 维度:觉察、情绪、关系、传承、驱动、成长 + var 觉察 = dimensions[0]; + var 情绪 = dimensions[1]; + var 关系 = dimensions[2]; + var 传承 = dimensions[3]; + var 驱动 = dimensions[4]; + var 成长 = dimensions[5]; + + // 类型匹配(按优先级) + var typeKey; + if (觉察 >= 10 && 情绪 >= 10) { + typeKey = 'awakener'; + } else if (传承 >= 10 && 关系 >= 10) { + typeKey = 'icebreaker'; + } else if (情绪 >= 10 && 觉察 <= 9) { + typeKey = 'pauser'; + } else if (传承 >= 10 && 成长 >= 10 && 驱动 <= 9) { + typeKey = 'guardian'; + } else if (成长 >= 10 && 驱动 >= 10 && 觉察 <= 9) { + typeKey = 'seeker'; + } else if (关系 <= 9 && 情绪 <= 9) { + typeKey = 'relational'; + } else if (驱动 <= 9 && 觉察 <= 9) { + typeKey = 'habitual'; + } else { + typeKey = 'sleeper'; + } + + var typeData = types[typeKey]; + + // 渲染结果页 + $resultIcon.src = typeData.icon; + $resultIcon.alt = typeData.name; + $resultName.textContent = typeData.name; + $resultDesc.textContent = typeData.desc; + $resultAnalysis.textContent = typeData.analysis; + $resultRecommend.textContent = typeData.recommend; + + // 绘制雷达图 + drawRadarChart($radarCanvas, dimensions, 300); + + // 保存结果到 localStorage + localStorage.setItem(STORAGE_KEY + '_result', JSON.stringify({ + typeKey: typeKey, + dimensions: dimensions + })); + + // 清除答题进度 + localStorage.removeItem(STORAGE_KEY); + + showPage('result'); + } + + // ======================================== + // 雷达图绘制(Canvas API) + // ======================================== + function drawRadarChart(canvas, dimensions, size) { + var ctx = canvas.getContext('2d'); + var dpr = window.devicePixelRatio || 1; + + // 高清屏适配 + canvas.width = size * dpr; + canvas.height = size * dpr; + canvas.style.width = size + 'px'; + canvas.style.height = size + 'px'; + ctx.scale(dpr, dpr); + + var centerX = size / 2; + var centerY = size / 2; + var maxRadius = size * 0.3; + var levels = 5; // 5层网格 + var sides = 6; // 6个维度 + var angleStep = (Math.PI * 2) / sides; + var startAngle = -Math.PI / 2; // 从顶部开始 + + ctx.clearRect(0, 0, size, size); + + // 绘制背景网格(5层) + for (var level = 1; level <= levels; level++) { + var r = (maxRadius / levels) * level; + ctx.beginPath(); + for (var i = 0; i <= sides; i++) { + var angle = startAngle + angleStep * i; + var x = centerX + r * Math.cos(angle); + var y = centerY + r * Math.sin(angle); + if (i === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + } + ctx.closePath(); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)'; + ctx.lineWidth = 1; + ctx.stroke(); + } + + // 绘制轴线 + for (var i = 0; i < sides; i++) { + var angle = startAngle + angleStep * i; + ctx.beginPath(); + ctx.moveTo(centerX, centerY); + ctx.lineTo( + centerX + maxRadius * Math.cos(angle), + centerY + maxRadius * Math.sin(angle) + ); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'; + ctx.lineWidth = 1; + ctx.stroke(); + } + + // 绘制数据区域 + ctx.beginPath(); + for (var i = 0; i < sides; i++) { + // 维度分值范围3-15,映射到0-1 + var value = (dimensions[i] - 3) / 12; + value = Math.max(0, Math.min(1, value)); + var r = maxRadius * value; + var angle = startAngle + angleStep * i; + var x = centerX + r * Math.cos(angle); + var y = centerY + r * Math.sin(angle); + if (i === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + } + ctx.closePath(); + + // 渐变填充 + var gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, maxRadius); + gradient.addColorStop(0, 'rgba(124, 92, 191, 0.45)'); + gradient.addColorStop(1, 'rgba(240, 194, 122, 0.2)'); + ctx.fillStyle = gradient; + ctx.fill(); + ctx.strokeStyle = 'rgba(196, 181, 253, 0.6)'; + ctx.lineWidth = 2; + ctx.stroke(); + + // 绘制数据点 + for (var i = 0; i < sides; i++) { + var value = (dimensions[i] - 3) / 12; + value = Math.max(0, Math.min(1, value)); + var r = maxRadius * value; + var angle = startAngle + angleStep * i; + var x = centerX + r * Math.cos(angle); + var y = centerY + r * Math.sin(angle); + + ctx.beginPath(); + ctx.arc(x, y, 4, 0, Math.PI * 2); + ctx.fillStyle = '#f0c27a'; + ctx.fill(); + ctx.strokeStyle = 'rgba(240, 194, 122, 0.4)'; + ctx.lineWidth = 6; + ctx.stroke(); + } + + // 绘制维度标签 + ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; + ctx.font = '11px "Noto Sans SC", -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + var labelRadius = maxRadius + 24; + for (var i = 0; i < sides; i++) { + var angle = startAngle + angleStep * i; + var x = centerX + labelRadius * Math.cos(angle); + var y = centerY + labelRadius * Math.sin(angle); + ctx.fillText(dimensionNames[i], x, y); + } + } + + // ======================================== + // 海报生成 + // ======================================== + function generatePoster() { + // 获取结果数据 + var resultData = JSON.parse(localStorage.getItem(STORAGE_KEY + '_result') || '{}'); + if (!resultData.typeKey) return; + + var typeData = types[resultData.typeKey]; + var dimensions = resultData.dimensions; + + // 填充海报内容 + $posterIcon.src = typeData.icon; + $posterName.textContent = typeData.name; + $posterDesc.textContent = typeData.desc; + $posterQuote.textContent = typeData.quote; + + // 在海报canvas上重新绘制雷达图 + drawRadarChart($posterRadarCanvas, dimensions, 400); + + // 显示海报容器 + $poster.classList.add('active'); + $posterContent.style.display = 'block'; + $posterPreview.style.display = 'none'; + + // 等待图片和canvas渲染完成后截图 + setTimeout(function () { + capturePoster(); + }, 500); + } + + /** 使用 html2canvas 截图 */ + function capturePoster() { + if (typeof html2canvas === 'undefined') { + alert('海报生成组件加载失败,请刷新页面重试'); + return; + } + + // 先显示加载提示 + $posterPreview.style.display = 'block'; + $posterImage.style.display = 'none'; + var previewTitle = document.querySelector('.poster-preview-title'); + if (previewTitle) previewTitle.textContent = '正在生成海报...'; + + html2canvas($posterContent, { + scale: 2, + useCORS: true, + allowTaint: true, + backgroundColor: '#0f0a1e', + width: 750, + height: 1334, + logging: false + }).then(function (canvas) { + $posterContent.style.display = 'none'; + var dataUrl = canvas.toDataURL('image/png'); + $posterImage.src = dataUrl; + $posterImage.style.display = 'block'; + if (previewTitle) previewTitle.textContent = '长按图片保存分享'; + }).catch(function (err) { + console.error('海报生成失败:', err); + $posterContent.style.display = 'none'; + $posterPreview.style.display = 'block'; + $posterImage.style.display = 'none'; + if (previewTitle) previewTitle.textContent = '海报生成失败,请重试'; + }); + } + + /** 关闭海报 */ + function closePoster() { + $poster.classList.remove('active'); + $posterContent.style.display = 'block'; + $posterPreview.style.display = 'none'; + } + + // ======================================== + // 重新测试 + // ======================================== + function retryQuiz() { + localStorage.removeItem(STORAGE_KEY); + localStorage.removeItem(STORAGE_KEY + '_result'); + answers = new Array(questions.length).fill(0); + currentQuestion = 0; + showPage('home'); + } + + // ======================================== + // localStorage 进度保存/恢复 + // ======================================== + function saveProgress() { + var data = { + currentQuestion: currentQuestion, + answers: answers + }; + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); + } catch (e) { + // localStorage 不可用时静默失败 + } + } + + function loadProgress() { + try { + var raw = localStorage.getItem(STORAGE_KEY); + if (raw) { + var data = JSON.parse(raw); + if (data.answers && data.answers.length === questions.length) { + answers = data.answers; + currentQuestion = data.currentQuestion || 0; + // 如果有未完成的测试,恢复到答题页 + var allAnswered = answers.every(function (a) { return a > 0; }); + if (allAnswered) { + // 所有题都答完了,直接计算结果 + calculateAndShowResult(); + } else if (currentQuestion > 0) { + // 有部分进度,恢复答题 + showPage('quiz'); + renderQuestion(); + } + } + } + } catch (e) { + // 解析失败时忽略 + } + } + + // ======================================== + // 启动 + // ======================================== + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + +})(); diff --git a/传承基因测试网站-设计方案.md b/传承基因测试网站-设计方案.md new file mode 100644 index 0000000..26462da --- /dev/null +++ b/传承基因测试网站-设计方案.md @@ -0,0 +1,326 @@ +# 「传承基因」测试网站 — 设计方案 + +> 创建日期:2026-04-24 +> 状态:设计已完成,待开发 + +--- + +## 一、项目概述 + +### 1.1 项目目标 + +构建一个类似 MBTI 风格的静态测试网站,通过 18 道场景化测试题,分析用户在"代继传承"方面的 6 个核心维度,最终给出一个类型标签和详细分析,并推荐「代继传承」课程。 + +### 1.2 目标用户 + +- **核心人群**:有孩子的中年父母(30-55岁) +- **用户画像**:带着各种家庭困惑而来——孩子躺平、亲子关系紧张、夫妻关系问题、婆媳矛盾、财富传承焦虑等 +- **使用场景**:微信朋友圈/群分享 → 手机打开 → 3-5分钟完成测试 → 查看结果 → 分享海报 + +### 1.3 核心约束 + +- 纯静态网站(HTML + CSS + JS),无需后端服务 +- 手机优先,同时适配电脑端 +- 课程推荐以链接/二维码形式呈现 +- 最终生成可分享的结果海报 + +--- + +## 二、设计风格 + +### 2.1 视觉风格:简约专业风 + +- **主色调**:蓝紫渐变(#667eea → #764ba2) +- **辅助色**:白色、浅灰背景 +- **字体**:系统默认无衬线字体(-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif) +- **设计语言**:干净利落、专业感强,类似 16personalities / MBTI 官方风格 +- **圆角**:按钮和卡片使用大圆角(30px 按钮,16px 卡片) +- **装饰**:几何圆形装饰元素,半透明,增加层次感 + +### 2.2 情感调性 + +- 专业但不冰冷 +- 有深度但不晦涩 +- 让用户感到"被理解"而非"被评判" +- 避免负面标签,所有类型名称都是正向或中性的 + +--- + +## 三、用户流程 + +``` +首页(吸引点击) + ↓ 点击"开始测试" +答题页(18题,逐题展示) + ↓ 最后一题提交 +计算页(动画过渡,2-3秒) + ↓ 自动跳转 +结果页(类型分析 + 课程推荐) + ↓ 点击"分享我的结果" +海报页(生成结果海报图片) + ↓ 长按保存/截图 +分享到朋友圈/微信群 +``` + +--- + +## 四、页面设计 + +### 4.1 首页 + +| 元素 | 内容 | +|------|------| +| 主标题 | "你的传承基因是什么?" | +| 副标题 | "3分钟测试,发现你的家族传承类型" | +| 按钮 | "开始测试 →" | +| 装饰 | 蓝紫渐变背景 + 半透明几何圆形 | +| 底部 | 简短说明:"基于心理学理论,已帮助 XXX 人发现自我"(可选) | + +### 4.2 答题页 + +| 元素 | 内容 | +|------|------| +| 顶部 | 进度条(当前题号/总题数) | +| 题目区 | 场景化描述文字 | +| 选项区 | 5级李克特量表:非常不符合 / 比较不符合 / 一般 / 比较符合 / 非常符合 | +| 交互 | 选择后自动跳转下一题(0.3秒延迟,给用户反馈感) | +| 返回 | 允许返回上一题修改 | + +### 4.3 计算页 + +| 元素 | 内容 | +|------|------| +| 动画 | "正在分析你的传承基因..." + 脉冲/呼吸动画 | +| 时长 | 2-3秒,营造"认真分析"的感觉 | + +### 4.4 结果页 + +| 元素 | 内容 | +|------|------| +| 类型图标 | 每种类型配一个简笔画/图标 | +| 类型标签 | 大字展示,如"觉醒者" | +| 一句话描述 | 该类型的核心特征 | +| 雷达图 | 6个维度的得分可视化 | +| 详细分析 | 200字左右,包含优势和成长方向 | +| 课程推荐 | 推荐语 + 课程链接/二维码 | +| 按钮 | "分享我的结果" / "重新测试" | + +### 4.5 海报页 + +| 元素 | 内容 | +|------|------| +| 背景 | 蓝紫渐变 | +| 内容 | 类型图标 + 类型名称 + 一句话描述 + 雷达图(简化版) | +| 底部 | "扫码测测你的传承基因" + 网站二维码 | +| 交互 | 提示"长按保存图片"或"截图分享" | + +--- + +## 五、测试维度设计 + +### 5.1 六大维度 + +| # | 维度名称 | 高分特征(觉醒端) | 低分特征(惯性端) | 对应课程理论 | +|---|---------|-------------------|-------------------|-------------| +| 1 | 自我觉察力 | 能看见自己的情绪和念头,对自己真实 | 习惯性压抑或忽视内在感受 | "我看见我的XX"、内在诚信 | +| 2 | 情绪驾驭力 | 能在情绪升起时停住,选择回应方式 | 容易被情绪带着走,事后后悔 | 知止、0.0001秒的间隙 | +| 3 | 关系修复力 | 能识别共生剧本,主动修复关系 | 在重复的关系模式中打转 | 亲民、共生剧本 | +| 4 | 传承意识 | 意识到家族模式在影响自己和孩子 | 没想过家族对自己的影响 | 代际传承、冰山模型 | +| 5 | 内在驱动力 | 行动来自内在力量和清晰意图 | 在惯性中生活,感觉被动 | 内驱力 vs NPC/空心人 | +| 6 | 成长信念 | 相信人可以持续改变,愿意长期投入 | 觉得"我就是这样了",难以改变 | 日拱一卒、止于至善 | + +### 5.2 计分规则 + +- 每题 1-5 分(非常不符合=1,非常符合=5) +- 每个维度 3 题,维度得分 = 3题总分(3-15分) +- 维度得分 ≥ 10 为"觉醒端",≤ 9 为"惯性端" +- 根据6个维度的觉醒/惯性组合,匹配到8种类型之一 + +--- + +## 六、8种传承类型 + +| # | 类型标签 | 核心特征 | 维度组合特征 | 课程推荐切入点 | +|---|---------|---------|-------------|--------------| +| 1 | **觉醒者** | 已走在自我成长路上,觉察力和情绪力都很强 | 觉察力高 + 情绪力高 | 深化修炼,止于至善 | +| 2 | **破冰人** | 正在打破家族旧模式,传承意识和关系修复力突出 | 传承意识高 + 关系修复力强 | 系统学习冰山模型 | +| 3 | **知止行者** | 情绪驾驭力突出,能在关键时刻停住,但自我觉察还需提升 | 情绪力高 + 觉察力待提升 | 从"知止"到"看见" | +| 4 | **传承守护者** | 传承意识强、成长信念坚定,但行动力还不足 | 传承意识高 + 成长信念强 + 驱动力待提升 | 从意识到行动,日拱一卒 | +| 5 | **寻道者** | 成长信念强、内在驱动力高,但方向还不够清晰 | 成长信念强 + 驱动力高 + 觉察力待提升 | 格物致知,找到内在卡点 | +| 6 | **沉睡者** | 多维度偏低,但成长信念还在,是觉醒的起点 | 多维度偏低 + 成长信念尚可 | 从最基础的"我看见我"开始 | +| 7 | **关系困者** | 关系是最大痛点,情绪驾驭和关系修复都较弱 | 关系修复力低 + 情绪力弱 | 从"我看见我的妈妈"开始 | +| 8 | **惯性行者** | 在惯性中运转,内在驱动力和自我觉察都较弱 | 驱动力低 + 觉察力弱 | 看见即觉察,觉察即涨心 | + +### 6.1 类型匹配逻辑 + +``` +IF 觉察力≥10 AND 情绪力≥10 → 觉醒者 +ELSE IF 传承意识≥10 AND 关系修复力≥10 → 破冰人 +ELSE IF 情绪力≥10 AND 觉察力≤9 → 知止行者 +ELSE IF 传承意识≥10 AND 成长信念≥10 AND 驱动力≤9 → 传承守护者 +ELSE IF 成长信念≥10 AND 驱动力≥10 AND 觉察力≤9 → 寻道者 +ELSE IF 关系修复力≤9 AND 情绪力≤9 → 关系困者 +ELSE IF 驱动力≤9 AND 觉察力≤9 → 惯性行者 +ELSE → 沉睡者(兜底) +``` + +--- + +## 七、测试题目(18题) + +### 维度1:自我觉察力(题1-3) + +| # | 题目 | +|---|------| +| 1 | 当我感到烦躁时,我能说出自己真正在气什么,而不是只觉得"烦" | +| 2 | 我经常反思自己的行为模式,而不是只看到别人的问题 | +| 3 | 面对冲突时,我能觉察到自己身体的变化(心跳加速、肌肉紧绷等) | + +### 维度2:情绪驾驭力(题4-6) + +| # | 题目 | +|---|------| +| 4 | 在和孩子吵架后,我能让自己冷静下来再去沟通,而不是冷战或翻旧账 | +| 5 | 当情绪上来时,我能让自己暂停几秒再回应,而不是脱口而出 | +| 6 | 我很少因为一时冲动说出让自己后悔的话 | + +### 维度3:关系修复力(题7-9) + +| # | 题目 | +|---|------| +| 7 | 我发现自己和父母的相处方式,正在不知不觉中复制到我和孩子的关系上 | +| 8 | 当关系出现问题时,我愿意主动去修复,而不是等对方先改变 | +| 9 | 我能分辨哪些情绪是自己的,哪些是"替别人承担的" | + +### 维度4:传承意识(题10-12) + +| # | 题目 | +|---|------| +| 10 | 我想过自己的某些性格特点或反应模式,可能是从祖辈那里继承来的 | +| 11 | 我注意到家族里有些模式在一代代重复(比如某种情绪、某种关系模式) | +| 12 | 我相信了解家族的历史和故事,对理解和教育孩子有帮助 | + +### 维度5:内在驱动力(题13-15) + +| # | 题目 | +|---|------| +| 13 | 我清楚自己为什么要做现在做的事,而不是随大流或被外界推着走 | +| 14 | 我觉得自己的人生是自己主动选择的,而不是被安排好的 | +| 15 | 遇到困难时,我能找到继续前行的内在力量,而不是只靠外部压力 | + +### 维度6:成长信念(题16-18) + +| # | 题目 | +|---|------| +| 16 | 我相信不管现在是什么状态,人都可以改变和成长 | +| 17 | 我愿意为了长远的目标,每天坚持做一点小事 | +| 18 | 我觉得"慢慢来"不是放弃,而是一种智慧 | + +--- + +## 八、技术方案 + +### 8.1 技术栈 + +| 项目 | 方案 | +|------|------| +| 结构 | HTML5 | +| 样式 | CSS3 + 响应式设计(Mobile First) | +| 交互 | 原生 JavaScript(无框架依赖) | +| 图表 | Canvas 绘制雷达图 | +| 海报 | html2canvas 库生成图片 | +| 部署 | 任意静态托管(GitHub Pages / Vercel / 阿里云 OSS 等) | + +### 8.2 文件结构 + +``` +/ +├── index.html # 首页 +├── quiz.html # 答题页 +├── result.html # 结果页 +├── css/ +│ └── style.css # 全局样式 +├── js/ +│ ├── quiz.js # 答题逻辑 +│ ├── result.js # 计分 + 类型匹配 +│ ├── radar.js # 雷达图绘制 +│ └── poster.js # 海报生成 +└── assets/ + └── icons/ # 8种类型的简笔画图标 +``` + +### 8.3 响应式断点 + +| 断点 | 适配设备 | +|------|---------| +| < 480px | 小屏手机 | +| 480-768px | 大屏手机 | +| 768-1024px | 平板 | +| > 1024px | 电脑 | + +--- + +## 九、课程推荐策略 + +### 9.1 推荐逻辑 + +每种类型的结果页底部,根据该类型的"薄弱维度"推荐对应的课程内容: + +| 类型 | 推荐切入点 | 推荐话术方向 | +|------|-----------|-------------| +| 觉醒者 | 深化修炼 | "你已经走在觉醒的路上,课程将帮你从'看见'走向'止于至善'" | +| 破冰人 | 冰山模型 | "你已开始打破旧模式,课程将带你系统理解冰山下的家族数据" | +| 知止行者 | 从知止到看见 | "你已能在情绪中停住,课程将帮你看见情绪背后的根源" | +| 传承守护者 | 从意识到行动 | "你对传承有深刻意识,课程将帮你把意识转化为每天的功课" | +| 寻道者 | 格物致知 | "你有强大的成长动力,课程将帮你找到内在卡点,明确方向" | +| 沉睡者 | 基础功课 | "觉醒的第一步,是看见。课程将从最基础的'我看见我'开始" | +| 关系困者 | 关系修复 | "关系是你的突破口,课程将教你从'我看见我的妈妈'开始修复" | +| 惯性行者 | 看见即觉察 | "看见即觉察,觉察即涨心。课程将帮你走出惯性,找回内在力量" | + +### 9.2 推荐展示形式 + +- 推荐语(2-3句) +- 课程链接按钮 +- 课程二维码(图片) + +--- + +## 十、分享海报设计 + +### 10.1 海报内容 + +``` +┌─────────────────────────┐ +│ │ +│ [类型简笔画图标] │ +│ │ +│ 你的传承基因是 │ +│ 「 觉醒者 」 │ +│ │ +│ "已走在自我成长路上, │ +│ 觉察力和情绪力都很强" │ +│ │ +│ ┌─────────────┐ │ +│ │ 简化雷达图 │ │ +│ └─────────────┘ │ +│ │ +│ 扫码测测你的传承基因 │ +│ [网站二维码] │ +│ │ +└─────────────────────────┘ +``` + +### 10.2 海报规格 + +- 尺寸:750 × 1334px(适合手机屏幕分享) +- 背景:蓝紫渐变 +- 字体:白色为主,类型标签加大加粗 + +--- + +## 十一、后续待确认事项 + +- [ ] 课程链接/二维码素材 +- [ ] 8种类型的简笔画图标设计(可用AI生成或手绘) +- [ ] 网站域名和部署方式 +- [ ] 是否需要统计答题数据(如需则需接入简单后端或第三方统计)