feat: P1 合盘/星座/问答与测测完整设计包及模拟器取证工具
落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
// Package explore provides the L1→L3 explore catalog.
|
||||
package explore
|
||||
|
||||
// Item is a leaf tool in the catalog.
|
||||
type Item struct {
|
||||
Key string `json:"key"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Path string `json:"path"`
|
||||
Icon string `json:"icon"`
|
||||
Tone string `json:"tone"`
|
||||
Badge string `json:"badge,omitempty"`
|
||||
}
|
||||
|
||||
// Category is an L1 explore bucket.
|
||||
type Category struct {
|
||||
Key string `json:"key"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
Tone string `json:"tone"`
|
||||
Items []Item `json:"items"`
|
||||
}
|
||||
|
||||
// Catalog returns the full explore tree (deterministic, no DB).
|
||||
// Order: 四核心优先,量表后置。
|
||||
func Catalog() []Category {
|
||||
return []Category{
|
||||
{
|
||||
Key: "decode", Title: "愈心解码", Description: "一个生日,读懂性格与节奏",
|
||||
Icon: "△", Tone: "gold",
|
||||
Items: []Item{
|
||||
{Key: "portrait", Title: "愈心解码", Description: "生日生成性格解码报告", Path: "/portrait", Icon: "△", Tone: "gold", Badge: "热"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "star", Title: "星座", Description: "排盘 · 运势 · 合盘",
|
||||
Icon: "✦", Tone: "night",
|
||||
Items: []Item{
|
||||
{Key: "star-report", Title: "本命排盘", Description: "圆形星盘 / 宫位 / 相位 / 运势", Path: "/star", Icon: "✦", Tone: "night", Badge: "热"},
|
||||
{Key: "star-synastry", Title: "合盘", Description: "比较盘与恋爱/友情/婚姻指数", Path: "/synastry", Icon: "✧", Tone: "night", Badge: "AI"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "relation", Title: "人格匹配", Description: "双人风格对照 · 相处说明书",
|
||||
Icon: "♡", Tone: "rose",
|
||||
Items: []Item{
|
||||
{Key: "relation-insight", Title: "人格匹配", Description: "行为风格对照与相处建议", Path: "/relation", Icon: "♡", Tone: "rose", Badge: "热"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "rhythm", Title: "身心节律", Description: "五行倾向与生活节奏建议",
|
||||
Icon: "☯", Tone: "green",
|
||||
Items: []Item{
|
||||
{Key: "rhythm-report", Title: "身心节律报告", Description: "体质倾向与生活建议", Path: "/rhythm", Icon: "☯", Tone: "green"},
|
||||
{Key: "companion-term", Title: "今日节气陪伴", Description: "季节生活小建议", Path: "/companion", Icon: "♡", Tone: "green"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "cards", Title: "意象卡片", Description: "投射反思,整理当下感受",
|
||||
Icon: "◈", Tone: "teal",
|
||||
Items: []Item{
|
||||
{Key: "image-cards", Title: "抽取意象卡片", Description: "单卡或三卡组合练习", Path: "/cards", Icon: "◈", Tone: "teal"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "growth", Title: "情绪与成长", Description: "心情轨迹、成长计划与问答",
|
||||
Icon: "○", Tone: "green",
|
||||
Items: []Item{
|
||||
{Key: "mood-trail", Title: "心情轨迹", Description: "近七日心情回顾", Path: "/companion", Icon: "○", Tone: "green"},
|
||||
{Key: "growth-plan", Title: "成长计划", Description: "小目标与每日打卡", Path: "/growth-plan", Icon: "▽", Tone: "teal"},
|
||||
{Key: "ask", Title: "AI 成长助手", Description: "结合档案整理感受", Path: "/ask", Icon: "◎", Tone: "gold"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "tests", Title: "更多测评", Description: "轻量量表(次要入口)",
|
||||
Icon: "◆", Tone: "blue",
|
||||
Items: []Item{
|
||||
{Key: "mbti-lite", Title: "人格类型探索", Description: "能量与决策偏好(轻量)", Path: "/scales/mbti-lite", Icon: "◆", Tone: "blue"},
|
||||
{Key: "enneagram-lite", Title: "动机模式探索", Description: "内在动机九型向轻测", Path: "/scales/enneagram-lite", Icon: "⑨", Tone: "purple"},
|
||||
{Key: "bigfive-lite", Title: "性格五维探索", Description: "稳定特质速览", Path: "/scales/bigfive-lite", Icon: "◈", Tone: "teal"},
|
||||
{Key: "love-style", Title: "亲密互动探索", Description: "亲密关系中的互动偏好", Path: "/scales/love-style", Icon: "♡", Tone: "rose"},
|
||||
{Key: "eq-lite", Title: "情绪觉察探索", Description: "识别与调节情绪的习惯", Path: "/scales/eq-lite", Icon: "♥", Tone: "pink"},
|
||||
{Key: "stress-index", Title: "压力负荷探索", Description: "近期压力与恢复方式", Path: "/scales/stress-index", Icon: "☯", Tone: "green"},
|
||||
{Key: "career-interest", Title: "职业兴趣探索", Description: "工作动力与环境偏好", Path: "/scales/career-interest", Icon: "◎", Tone: "gold"},
|
||||
{Key: "communication-style", Title: "沟通方式探索", Description: "表达与倾听偏好", Path: "/scales/communication-style", Icon: "◆", Tone: "blue"},
|
||||
{Key: "emotion-pattern", Title: "情绪模式探索", Description: "情绪起伏与自我照顾", Path: "/scales/emotion-pattern", Icon: "♥", Tone: "pink"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CategoryByKey returns one category or nil.
|
||||
func CategoryByKey(key string) *Category {
|
||||
for _, c := range Catalog() {
|
||||
if c.Key == key {
|
||||
cp := c
|
||||
return &cp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package explore
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCatalogShape(t *testing.T) {
|
||||
cats := Catalog()
|
||||
if len(cats) < 6 {
|
||||
t.Fatalf("want ≥6 L1 categories, got %d", len(cats))
|
||||
}
|
||||
keys := map[string]bool{}
|
||||
for _, c := range cats {
|
||||
keys[c.Key] = true
|
||||
if len(c.Items) < 1 {
|
||||
t.Fatalf("category %s empty", c.Key)
|
||||
}
|
||||
for _, it := range c.Items {
|
||||
if it.Path == "" || !strings.HasPrefix(it.Path, "/") {
|
||||
t.Fatalf("bad path %#v", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, k := range []string{"decode", "star", "relation", "tests", "rhythm", "cards", "growth"} {
|
||||
if !keys[k] {
|
||||
t.Fatalf("missing category %s", k)
|
||||
}
|
||||
}
|
||||
// 四核心应排在量表之前
|
||||
if indexOf(cats, "tests") < indexOf(cats, "star") {
|
||||
t.Fatal("tests should come after star")
|
||||
}
|
||||
}
|
||||
|
||||
func indexOf(cats []Category, key string) int {
|
||||
for i, c := range cats {
|
||||
if c.Key == key {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func TestLexiconHardBanOnly(t *testing.T) {
|
||||
blob := ""
|
||||
for _, c := range Catalog() {
|
||||
blob += c.Title + c.Description
|
||||
for _, it := range c.Items {
|
||||
blob += it.Title + it.Description
|
||||
}
|
||||
}
|
||||
for _, bad := range []string{"占卜", "算命", "测测"} {
|
||||
if strings.Contains(blob, bad) {
|
||||
t.Fatalf("forbidden %q", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user