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:
jackyu66git
2026-08-03 11:37:53 +08:00
co-authored by Cursor
parent 15a9db374a
commit bd22d9dddd
248 changed files with 26309 additions and 842 deletions
+188
View File
@@ -0,0 +1,188 @@
package scale
// BuildResult returns a rich, lexicon-safe exploration result for a scale slug + style key.
func BuildResult(slug, styleKey, label string) map[string]interface{} {
pack := resultPack(slug, styleKey, label)
return map[string]interface{}{
"title": "探索结果",
"style_key": styleKey,
"label": pack.Label,
"summary": pack.Summary,
"overview": pack.Overview,
"share_line": pack.ShareLine,
"dimensions": pack.Dimensions,
"strengths": pack.Strengths,
"watchouts": pack.Watchouts,
"tips": pack.Tips,
"scripts": pack.Scripts,
"growth_plan": pack.GrowthPlan,
"faq": pack.FAQ,
}
}
type pack struct {
Label, Summary, Overview, ShareLine string
Dimensions []map[string]interface{}
Strengths, Watchouts, Tips, Scripts []string
GrowthPlan []map[string]string
FAQ []map[string]string
}
func resultPack(slug, key, fallbackLabel string) pack {
switch slug {
case "emotion-pattern":
return emotionPack(key, fallbackLabel)
default:
return communicationPack(key, fallbackLabel)
}
}
func communicationPack(key, fallback string) pack {
switch key {
case "A":
return pack{
Label: "理性澄清型", ShareLine: "我的沟通方式:理性澄清型",
Summary: "你倾向先澄清事实与目标,再进入感受层。这让协作高效,也要注意别让对方觉得被审问。",
Overview: "冲突或合作时,你本能想问清楚「发生了什么、目标是什么」。对方若正处在情绪里,过早追问细节可能升级张力。你的成长点是:先给一句承认,再启动澄清。",
Dimensions: []map[string]interface{}{
{"title": "澄清力", "score": 88, "note": "擅长把模糊说清楚"},
{"title": "共情节奏", "score": 62, "note": "可先共鸣再分析"},
{"title": "边界表达", "score": 78, "note": "需求通常比较明确"},
},
Strengths: []string{"逻辑清楚", "减少误解", "适合协作对齐"},
Watchouts: []string{"过早纠正", "忽略情绪信号", "听起来像质询"},
Tips: []string{"开口先复述对方一句", "结论前加「我听到你…」", "重要约定写成要点"},
Scripts: []string{"我先确认我理解对了:你是说……?", "我想先对齐事实,再一起看感受可以吗?", "我的需要是……,你呢?"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "三次对话里先共鸣再澄清"},
{"phase": "本月", "focus": "冲突后写复盘:事实 / 感受 / 约定"},
},
FAQ: []map[string]string{
{"q": "别人说我太冷静?", "a": "冷静是优势;补一句情绪确认,观感会柔和很多。"},
},
}
case "B":
return pack{
Label: "感受连接型", ShareLine: "我的沟通方式:感受连接型",
Summary: "你擅长用共鸣打开对话。记得在连接之后,也把需求和边界说清楚,避免长期亏空。",
Overview: "你对语气与气氛敏感,能很快让人感到被理解。挑战是容易承接对方情绪,或迟迟不谈具体安排。连接是起点,请求是终点。",
Dimensions: []map[string]interface{}{
{"title": "共情力", "score": 90, "note": "氛围与感受捕捉强"},
{"title": "需求表达", "score": 60, "note": "可练习更直接"},
{"title": "冲突耐受力", "score": 58, "note": "宜早谈小分歧"},
},
Strengths: []string{"让人安心", "破冰能力强", "关系温度高"},
Watchouts: []string{"边界模糊", "回避具体冲突", "情绪连带消耗"},
Tips: []string{"共鸣后补一句清晰请求", "每周提出一次真实偏好", "重要事不要只靠暗示"},
Scripts: []string{"我很理解你的难处,我能做的是……;我需要你……", "我刚才有点被带着走了,让我整理一下再回复。", "这件事我有点在意,我们可以商量吗?"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "一次温和且具体的请求"},
{"phase": "本月", "focus": "建立「情绪收支」复盘"},
},
FAQ: []map[string]string{
{"q": "怎样不那么累?", "a": "把理解与解决分开,不默认承包对方情绪。"},
},
}
default: // C or unknown
label := fallback
if label == "" {
label = "节奏尊重型"
}
return pack{
Label: label, ShareLine: "我的沟通方式:" + label,
Summary: "你重视对方的节奏与空间。这很加分,也要避免把「尊重」变成「不表达」,导致关系空转。",
Overview: "你不愿压迫别人,也反感被催促。优点是让人有安全感;风险是关键议题被无限推迟。可以为重要话题设定温和的时间盒。",
Dimensions: []map[string]interface{}{
{"title": "节奏感", "score": 86, "note": "懂得留白与等待"},
{"title": "推进力", "score": 64, "note": "重要事可设时间盒"},
{"title": "安全感营造", "score": 82, "note": "压迫感低"},
},
Strengths: []string{"尊重边界", "低压迫沟通", "适合长期协作"},
Watchouts: []string{"议题拖延", "需求不说出口", "被误解为漠不关心"},
Tips: []string{"重要话题约定讨论时间", "用「到点我们再谈」代替无限等待", "主动同步「我在意,只是需要准备」"},
Scripts: []string{"这件事对我重要,我们明天晚上 20 点谈 20 分钟可以吗?", "我不是不在乎,我需要一点时间想清楚。", "我想听完你的节奏,再说我的需要。"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "为一个拖延议题约定讨论时间"},
{"phase": "本月", "focus": "练习两次限时决策"},
},
FAQ: []map[string]string{
{"q": "会不会显得被动?", "a": "尊重节奏 + 明确时间点,就是主动而不压迫。"},
},
}
}
}
func emotionPack(key, fallback string) pack {
switch key {
case "A":
return pack{
Label: "觉察表达型", ShareLine: "我的情感模式:觉察表达型",
Summary: "你能较快察觉情绪并愿意说出来。注意表达时给对方消化空间,避免倾泻成压力。",
Overview: "觉察是调节的第一步。你已经具备命名与分享的能力;下一步是区分「分享」与「要求对方立刻修好」。",
Dimensions: []map[string]interface{}{
{"title": "觉察", "score": 88, "note": "情绪信号接收快"},
{"title": "表达", "score": 84, "note": "愿意说出口"},
{"title": "调节后行动", "score": 66, "note": "说完后可补一个小行动"},
},
Strengths: []string{"情绪可见", "利于早沟通", "减少闷烧"},
Watchouts: []string{"倾泻过量", "期待即时修复", "对方跟不上节奏"},
Tips: []string{"表达前先写三句提纲", "说明你要倾听还是建议", "给对方回应窗口"},
Scripts: []string{"我现在有点……,我需要你听我说 5 分钟,先不要给方案。", "我说完了,你方便的时候告诉我你的感受。"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "两次「只倾听请求」练习"},
{"phase": "本月", "focus": "表达后为自己设计一个调节行动"},
},
FAQ: []map[string]string{
{"q": "对方说我太敏感?", "a": "敏感是信息;把它翻译成具体需要,对方更容易配合。"},
},
}
case "B":
return pack{
Label: "安抚稳定型", ShareLine: "我的情感模式:安抚稳定型",
Summary: "你倾向先稳定场面与身心,再处理问题。记得稳定之后仍要把需求说清楚。",
Overview: "你擅长降温:深呼吸、抽离、安慰自己或他人。若只停在安抚、不进入表达与边界,问题可能反复出现。",
Dimensions: []map[string]interface{}{
{"title": "稳定力", "score": 90, "note": "善于降温"},
{"title": "表达力度", "score": 58, "note": "可加强具体诉求"},
{"title": "长期边界", "score": 62, "note": "防重复消耗"},
},
Strengths: []string{"冲突降温", "给人安全感", "自我安抚能力"},
Watchouts: []string{"压抑成真沉默", "问题被搁置", "被当成情绪垃圾桶还不设限"},
Tips: []string{"降温后补一句需求", "重复消耗的情境要设限", "用日记区分安抚与回避"},
Scripts: []string{"我先让自己稳一下,20 分钟后我们继续谈。", "我已经平静些了,我需要讨论的是……"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "安抚后至少表达一个具体需要"},
{"phase": "本月", "focus": "为反复场景写一条边界"},
},
FAQ: []map[string]string{
{"q": "是不是太忍?", "a": "稳定是能力;忍到失语就变成损耗。稳完要说。"},
},
}
default:
label := fallback
if label == "" {
label = "行动调节型"
}
return pack{
Label: label, ShareLine: "我的情感模式:" + label,
Summary: "你习惯用行动(做事、运动、推进)调节情绪。有效,但也要留下命名感受的空间。",
Overview: "行动能快速改变状态,是你的优势。若只用行动回避感受,亲密关系里的人可能觉得你「只顾做事」。行动前后各留一句感受命名。",
Dimensions: []map[string]interface{}{
{"title": "行动力", "score": 88, "note": "用做来调节"},
{"title": "感受命名", "score": 60, "note": "可加强语言化"},
{"title": "关系同步", "score": 64, "note": "行动前告知动机"},
},
Strengths: []string{"恢复快", "不沉溺反刍", "执行导向"},
Watchouts: []string{"跳过感受", "被看作冷漠", "用忙碌麻痹"},
Tips: []string{"行动前说清「我在用行动调节」", "每天写一句情绪命名", "重要关系里先连接再解决"},
Scripts: []string{"我有点烦,我想先去走走,回来再聊。", "我不是不理你,我在用行动让自己回来。"},
GrowthPlan: []map[string]string{
{"phase": "本周", "focus": "行动前后各做一次感受命名"},
{"phase": "本月", "focus": "一次冲突里先连接再给方案"},
},
FAQ: []map[string]string{
{"q": "伴侣说我不沟通?", "a": "把行动翻译成语言:你在调节,以及你何时回来继续谈。"},
},
}
}
}
+42
View File
@@ -0,0 +1,42 @@
// Package scale holds exploration-test scoring helpers.
package scale
// ScoreMajority picks the most frequent answer key and maps to a label set.
func ScoreMajority(answers map[string]string, labels map[string]string, defaultLabel string) (styleKey, label string) {
counts := map[string]int{}
for _, v := range answers {
counts[v]++
}
best, bestN := "", -1
for k, n := range counts {
if n > bestN {
best, bestN = k, n
}
}
if best == "" {
return "", defaultLabel
}
label = labels[best]
if label == "" {
label = defaultLabel
}
return best, label
}
// CommunicationLabels for communication-style scale.
func CommunicationLabels() map[string]string {
return map[string]string{
"A": "理性澄清型",
"B": "感受连接型",
"C": "节奏尊重型",
}
}
// EmotionLabels for emotion-pattern scale.
func EmotionLabels() map[string]string {
return map[string]string{
"A": "觉察表达型",
"B": "安抚稳定型",
"C": "行动调节型",
}
}
+39
View File
@@ -0,0 +1,39 @@
package scale
import "testing"
func TestScoreMajority_communication(t *testing.T) {
key, label := ScoreMajority(map[string]string{
"q1": "B", "q2": "B", "q3": "A",
}, CommunicationLabels(), "平衡探索型")
if key != "B" || label != "感受连接型" {
t.Fatalf("got %s %s", key, label)
}
}
func TestScoreMajority_emotion(t *testing.T) {
key, label := ScoreMajority(map[string]string{
"q1": "C", "q2": "C", "q3": "C",
}, EmotionLabels(), "平衡探索型")
if key != "C" || label != "行动调节型" {
t.Fatalf("got %s %s", key, label)
}
}
func TestScoreMajority_empty(t *testing.T) {
_, label := ScoreMajority(nil, CommunicationLabels(), "平衡探索型")
if label != "平衡探索型" {
t.Fatalf("got %s", label)
}
}
func TestBuildResult_rich(t *testing.T) {
r := BuildResult("communication-style", "B", "感受连接型")
if r["overview"] == nil || r["tips"] == nil || r["scripts"] == nil {
t.Fatalf("missing rich fields: %#v", r)
}
r2 := BuildResult("emotion-pattern", "A", "觉察表达型")
if r2["growth_plan"] == nil || r2["faq"] == nil {
t.Fatalf("missing emotion rich fields")
}
}