落地输入合规、探索题库、报告日/时辰刷新、账号头像、OEJTS 量表,并补齐 H5 埋点与 Admin 漏斗;同步 ESS 工件、切至自建 Git、清理 GitHub Actions。 Co-authored-by: Cursor <cursoragent@cursor.com>
123 lines
3.6 KiB
Go
123 lines
3.6 KiB
Go
package scale
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strconv"
|
||
)
|
||
|
||
// JungianQuestionMeta is parsed from scale_questions.body for OEJTS-style items.
|
||
type JungianQuestionMeta struct {
|
||
Dimension string `json:"dimension"`
|
||
Format string `json:"format"`
|
||
Left string `json:"left"`
|
||
Right string `json:"right"`
|
||
Prompt string `json:"prompt"`
|
||
}
|
||
|
||
// ScoreJungian tallies 1–5 Likert answers per EI/SN/TF/JP (OEJTS rules).
|
||
// Left poles: E, S, F, J · Right poles: I, N, T, P · threshold = perDim*3.
|
||
func ScoreJungian(answers map[string]string, qMeta map[string]JungianQuestionMeta, perDim int) (typeCode string, raw map[string]int, pct map[string]int) {
|
||
raw = map[string]int{"EI": 0, "SN": 0, "TF": 0, "JP": 0}
|
||
if perDim <= 0 {
|
||
perDim = 8
|
||
}
|
||
for qid, ans := range answers {
|
||
meta, ok := qMeta[qid]
|
||
if !ok || meta.Dimension == "" {
|
||
continue
|
||
}
|
||
v, err := strconv.Atoi(ans)
|
||
if err != nil || v < 1 || v > 5 {
|
||
v = 3
|
||
}
|
||
raw[meta.Dimension] += v
|
||
}
|
||
thr := perDim * 3
|
||
pick := func(score int, left, right string) string {
|
||
if score > thr {
|
||
return right
|
||
}
|
||
return left
|
||
}
|
||
typeCode = pick(raw["EI"], "E", "I") +
|
||
pick(raw["SN"], "S", "N") +
|
||
pick(raw["TF"], "F", "T") +
|
||
pick(raw["JP"], "J", "P")
|
||
|
||
pct = map[string]int{}
|
||
minS, maxS := perDim, perDim*5
|
||
span := float64(maxS - minS)
|
||
rightPct := func(score int) int {
|
||
p := int(float64(score-minS)/span*100 + 0.5)
|
||
if p < 0 {
|
||
return 0
|
||
}
|
||
if p > 100 {
|
||
return 100
|
||
}
|
||
return p
|
||
}
|
||
eiR := rightPct(raw["EI"])
|
||
snR := rightPct(raw["SN"])
|
||
tfR := rightPct(raw["TF"])
|
||
jpR := rightPct(raw["JP"])
|
||
pct["E"], pct["I"] = 100-eiR, eiR
|
||
pct["S"], pct["N"] = 100-snR, snR
|
||
pct["F"], pct["T"] = 100-tfR, tfR
|
||
pct["J"], pct["P"] = 100-jpR, jpR
|
||
return typeCode, raw, pct
|
||
}
|
||
|
||
// ParseJungianMeta extracts dimension metadata from question body JSON.
|
||
func ParseJungianMeta(body json.RawMessage) JungianQuestionMeta {
|
||
var m JungianQuestionMeta
|
||
_ = json.Unmarshal(body, &m)
|
||
return m
|
||
}
|
||
|
||
// BuildJungianResult builds rich result with 4-letter code + preference bars.
|
||
func BuildJungianResult(typeCode string, pct map[string]int) map[string]interface{} {
|
||
label := MBTILabel(typeCode)
|
||
base := mbtiPack(typeCode, label)
|
||
base.Label = typeCode + " · " + label
|
||
base.ShareLine = "我的类型探索:" + typeCode + " · " + label
|
||
base.Dimensions = []map[string]interface{}{
|
||
{"title": "E/I 能量", "score": maxPct(pct, "E", "I"), "note": prefNote("E", "I", pct, "外向互动", "内向思考")},
|
||
{"title": "S/N 信息", "score": maxPct(pct, "S", "N"), "note": prefNote("S", "N", pct, "具体事实", "模式可能")},
|
||
{"title": "T/F 决策", "score": maxPct(pct, "T", "F"), "note": prefNote("T", "F", pct, "逻辑一致", "价值与人际")},
|
||
{"title": "J/P 节奏", "score": maxPct(pct, "J", "P"), "note": prefNote("J", "P", pct, "计划结构", "灵活开放")},
|
||
}
|
||
out := map[string]interface{}{
|
||
"title": "MBTI 探索结果",
|
||
"style_key": typeCode,
|
||
"type_code": typeCode,
|
||
"label": base.Label,
|
||
"summary": base.Summary,
|
||
"overview": base.Overview,
|
||
"share_line": base.ShareLine,
|
||
"dimensions": base.Dimensions,
|
||
"preferences": pct,
|
||
"strengths": base.Strengths,
|
||
"watchouts": base.Watchouts,
|
||
"tips": base.Tips,
|
||
"scripts": base.Scripts,
|
||
"growth_plan": base.GrowthPlan,
|
||
"faq": base.FAQ,
|
||
}
|
||
return out
|
||
}
|
||
|
||
func maxPct(pct map[string]int, a, b string) int {
|
||
if pct[a] >= pct[b] {
|
||
return pct[a]
|
||
}
|
||
return pct[b]
|
||
}
|
||
|
||
func prefNote(a, b string, pct map[string]int, aDesc, bDesc string) string {
|
||
if pct[a] >= pct[b] {
|
||
return a + " " + strconv.Itoa(pct[a]) + "% · " + aDesc
|
||
}
|
||
return b + " " + strconv.Itoa(pct[b]) + "% · " + bDesc
|
||
}
|