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,237 @@
|
||||
package portrait
|
||||
|
||||
// Triangle is the classic life-number pyramid from js/common.js calc().
|
||||
type Triangle struct {
|
||||
AB, CD, EF, GH [2]int
|
||||
I, J, K, L int
|
||||
M, N, O int
|
||||
Q, P, R int
|
||||
T, S, U int
|
||||
V, W, X int
|
||||
}
|
||||
|
||||
// Calc builds the digital psychology triangle for a birth date.
|
||||
func Calc(y, m, d int) Triangle {
|
||||
dd := digs(d, 2)
|
||||
mm := digs(m, 2)
|
||||
yy := digs(y, 4)
|
||||
a, b := dd[0], dd[1]
|
||||
c, dd1 := mm[0], mm[1]
|
||||
e, f, g, h := yy[0], yy[1], yy[2], yy[3]
|
||||
v := Triangle{
|
||||
AB: [2]int{a, b},
|
||||
CD: [2]int{c, dd1},
|
||||
EF: [2]int{e, f},
|
||||
GH: [2]int{g, h},
|
||||
}
|
||||
v.I = s1(a + b)
|
||||
v.J = s1(c + dd1)
|
||||
v.K = s1(e + f)
|
||||
v.L = s1(g + h)
|
||||
v.M = s1(v.I + v.J)
|
||||
v.N = s1(v.K + v.L)
|
||||
v.O = s1(v.M + v.N)
|
||||
v.Q = s1(v.N + v.O)
|
||||
v.P = s1(v.M + v.O)
|
||||
v.R = s1(v.Q + v.P)
|
||||
v.T = s1(v.I + v.M)
|
||||
v.S = s1(v.J + v.M)
|
||||
v.U = s1(v.T + v.S)
|
||||
v.V = s1(v.K + v.N)
|
||||
v.W = s1(v.L + v.N)
|
||||
v.X = s1(v.V + v.W)
|
||||
return v
|
||||
}
|
||||
|
||||
// PyramidMap returns grid values for H5 mini-triangle rendering.
|
||||
func (v Triangle) PyramidMap() map[string]int {
|
||||
return map[string]int{
|
||||
"I": v.I, "J": v.J, "K": v.K, "L": v.L,
|
||||
"M": v.M, "N": v.N, "O": v.O,
|
||||
"Q": v.Q, "P": v.P, "R": v.R,
|
||||
"T": v.T, "S": v.S, "U": v.U,
|
||||
"V": v.V, "W": v.W, "X": v.X,
|
||||
}
|
||||
}
|
||||
|
||||
func s1(n int) int {
|
||||
for n >= 10 {
|
||||
sum := 0
|
||||
for n > 0 {
|
||||
sum += n % 10
|
||||
n /= 10
|
||||
}
|
||||
n = sum
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func digs(n, l int) []int {
|
||||
s := fmtPad(n, l)
|
||||
out := make([]int, l)
|
||||
for i := 0; i < l; i++ {
|
||||
out[i] = int(s[i] - '0')
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func fmtPad(n, l int) string {
|
||||
if n < 0 {
|
||||
n = -n
|
||||
}
|
||||
buf := make([]byte, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
buf[i] = byte('0' + n%10)
|
||||
n /= 10
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func cell(v Triangle, key string) int {
|
||||
switch key {
|
||||
case "I":
|
||||
return v.I
|
||||
case "J":
|
||||
return v.J
|
||||
case "K":
|
||||
return v.K
|
||||
case "L":
|
||||
return v.L
|
||||
case "M":
|
||||
return v.M
|
||||
case "N":
|
||||
return v.N
|
||||
case "O":
|
||||
return v.O
|
||||
case "Q":
|
||||
return v.Q
|
||||
case "P":
|
||||
return v.P
|
||||
case "R":
|
||||
return v.R
|
||||
case "T":
|
||||
return v.T
|
||||
case "S":
|
||||
return v.S
|
||||
case "U":
|
||||
return v.U
|
||||
case "V":
|
||||
return v.V
|
||||
case "W":
|
||||
return v.W
|
||||
case "X":
|
||||
return v.X
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// jointGroups builds age-grouped joint codes (付费层).
|
||||
func jointGroups(v Triangle) []map[string]any {
|
||||
pairs := [][2]string{
|
||||
{"I", "J"}, {"J", "M"}, {"M", "I"}, {"K", "L"},
|
||||
{"L", "N"}, {"N", "K"}, {"M", "O"}, {"O", "N"},
|
||||
{"M", "N"}, {"Q", "P"}, {"Q", "O"}, {"P", "O"},
|
||||
}
|
||||
joints := make([]map[string]any, 0, len(pairs))
|
||||
for _, p := range pairs {
|
||||
code := fmtInt(cell(v, p[0])) + fmtInt(cell(v, p[1]))
|
||||
label := "—"
|
||||
for k, desc := range jointCodes {
|
||||
if len(k) >= len(code) && k[:len(code)] == code {
|
||||
label = desc
|
||||
break
|
||||
}
|
||||
}
|
||||
joints = append(joints, map[string]any{"code": code, "label": label})
|
||||
}
|
||||
g1Desc := "由潜意识码主导,反映你在职场上升期和社交圈中的表现模式。"
|
||||
if v.I+v.J+v.M >= 10 {
|
||||
g1Desc += "能量较强,事业心旺盛,社交活跃。"
|
||||
} else {
|
||||
g1Desc += "能量内敛,更注重深度而非广度。"
|
||||
}
|
||||
g2Desc := "由内心码和主性格主导,体现你对下一代和下级的培养方式及中年价值观。"
|
||||
if v.K+v.L+v.N >= 10 {
|
||||
g2Desc += "有较强的责任感和支配欲。"
|
||||
} else {
|
||||
g2Desc += "倾向于给予空间,放手让他人成长。"
|
||||
}
|
||||
g3Desc := "由外心码主导,展现你晚年的生活智慧和家庭关系的最终呈现。"
|
||||
if v.M+v.N+v.O >= 10 {
|
||||
g3Desc += "晚年活跃,持续发挥影响力。"
|
||||
} else {
|
||||
g3Desc += "晚年宁静,享受内在平和。"
|
||||
}
|
||||
return []map[string]any{
|
||||
{"label": "21—40岁 · 工作和朋友", "codes": joints[0:4], "desc": g1Desc},
|
||||
{"label": "41—60岁 · 儿女和下属", "codes": joints[4:8], "desc": g2Desc},
|
||||
{"label": "61岁至晚年 · 晚年和家庭", "codes": joints[8:12], "desc": g3Desc},
|
||||
}
|
||||
}
|
||||
|
||||
func missAndOver(v Triangle) (missing []map[string]any, over []map[string]any) {
|
||||
innerSet := map[int]bool{v.O: true, v.M: true, v.N: true, v.I: true, v.J: true, v.K: true, v.L: true}
|
||||
outerVals := []int{v.Q, v.P, v.R, v.T, v.S, v.U, v.V, v.W, v.X}
|
||||
present := map[int]bool{}
|
||||
for n := range innerSet {
|
||||
present[n] = true
|
||||
}
|
||||
for _, n := range outerVals {
|
||||
present[n] = true
|
||||
}
|
||||
for _, n := range []int{v.AB[0], v.AB[1], v.CD[0], v.CD[1], v.EF[0], v.EF[1], v.GH[0], v.GH[1]} {
|
||||
present[n] = true
|
||||
}
|
||||
freq := map[int]int{}
|
||||
for i := 1; i <= 9; i++ {
|
||||
freq[i] = 0
|
||||
}
|
||||
allVals := []int{
|
||||
v.O, v.M, v.N, v.I, v.J, v.K, v.L, v.Q, v.P, v.R, v.T, v.S, v.U, v.V, v.W, v.X,
|
||||
v.AB[0], v.AB[1], v.CD[0], v.CD[1], v.EF[0], v.EF[1], v.GH[0], v.GH[1],
|
||||
}
|
||||
for _, x := range allVals {
|
||||
if x >= 1 && x <= 9 {
|
||||
freq[x]++
|
||||
}
|
||||
}
|
||||
missBoth := []int{}
|
||||
for n := 0; n <= 9; n++ {
|
||||
if !present[n] {
|
||||
missBoth = append(missBoth, n)
|
||||
}
|
||||
}
|
||||
missSet := map[int]bool{}
|
||||
for _, n := range missBoth {
|
||||
missSet[n] = true
|
||||
if n >= 1 && n <= 9 {
|
||||
missing = append(missing, map[string]any{"n": n, "msg": missMsg[n]})
|
||||
}
|
||||
}
|
||||
for i := 1; i <= 9; i++ {
|
||||
if freq[i] >= 4 && !missSet[i] {
|
||||
over = append(over, map[string]any{"n": i, "msg": missStrong[i], "count": freq[i]})
|
||||
}
|
||||
}
|
||||
return missing, over
|
||||
}
|
||||
|
||||
func fmtInt(n int) string {
|
||||
if n < 0 {
|
||||
n = -n
|
||||
}
|
||||
if n < 10 {
|
||||
return string(rune('0' + n))
|
||||
}
|
||||
return fmtPad(n, 2)
|
||||
}
|
||||
|
||||
func firstSentence(s string) string {
|
||||
for i, r := range s {
|
||||
if r == '。' || r == '.' {
|
||||
return s[:i]
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user