refactor(ECR-004): Synastry 再拆、Scale 测、Membership 守卫、OpenAPI 与 CI
压合盘贴线文件;补选答单测与 nil 守卫;对齐关键 OpenAPI schemas;加 GitHub Actions 门禁。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import type { GrowthReport, Profile } from '@yuxingu/types'
|
||||
import type { WheelPlanet } from '../components/NatalWheel.vue'
|
||||
import type { RelationSharePayload } from './shareLink'
|
||||
|
||||
export type SynastryMainTab = 'compare' | 'composite' | 'davison' | 'marks' | 'overlay'
|
||||
export type SynastrySubTab = 'natal' | 'prog'
|
||||
export type SynastryMarksWho = 'me' | 'other'
|
||||
|
||||
export const relationTypes = ['伴侣', '朋友', '家人', '其他']
|
||||
|
||||
export const mainTabs: { key: SynastryMainTab; label: string }[] = [
|
||||
{ key: 'compare', label: '比较' },
|
||||
{ key: 'composite', label: '组合' },
|
||||
{ key: 'davison', label: '时空' },
|
||||
{ key: 'marks', label: '马克斯' },
|
||||
{ key: 'overlay', label: '配对' },
|
||||
]
|
||||
|
||||
export function asPlanets(raw: unknown): WheelPlanet[] {
|
||||
if (!Array.isArray(raw)) return []
|
||||
return raw.map((p) => {
|
||||
const o = p as Record<string, unknown>
|
||||
return {
|
||||
key: String(o.key),
|
||||
title: String(o.title),
|
||||
sign: String(o.sign),
|
||||
degree: String(o.degree),
|
||||
house: Number(o.house),
|
||||
lon: Number(o.lon),
|
||||
element: o.element != null ? String(o.element) : undefined,
|
||||
modality: o.modality != null ? String(o.modality) : undefined,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function chartBlock(
|
||||
charts: Record<string, unknown>,
|
||||
key: string,
|
||||
): Record<string, unknown> | null {
|
||||
const c = charts[key]
|
||||
if (!c || typeof c !== 'object') return null
|
||||
return c as Record<string, unknown>
|
||||
}
|
||||
|
||||
export function chartTip(charts: Record<string, unknown>, key: string): string {
|
||||
return String(chartBlock(charts, key)?.tip || '')
|
||||
}
|
||||
|
||||
export function chartPlanetsFromSummary(
|
||||
summary: Record<string, unknown>,
|
||||
key: 'chart_a' | 'chart_b',
|
||||
): WheelPlanet[] {
|
||||
const c = summary[key]
|
||||
if (!c || typeof c !== 'object') return []
|
||||
return asPlanets((c as { planets?: unknown }).planets)
|
||||
}
|
||||
|
||||
export function ascLonFromChart(chart: unknown): number | null {
|
||||
const c = chart as { asc_lon?: number } | undefined
|
||||
return typeof c?.asc_lon === 'number' ? c.asc_lon : null
|
||||
}
|
||||
|
||||
export function labelList(raw: unknown): { label: string }[] {
|
||||
return Array.isArray(raw) ? (raw as { label: string }[]) : []
|
||||
}
|
||||
|
||||
export function resolveActiveChartKey(
|
||||
mainTab: SynastryMainTab,
|
||||
subTab: SynastrySubTab,
|
||||
marksWho: SynastryMarksWho,
|
||||
): string {
|
||||
if (mainTab === 'composite') {
|
||||
return subTab === 'prog' ? 'composite_progressed' : 'composite'
|
||||
}
|
||||
if (mainTab === 'davison') {
|
||||
return subTab === 'prog' ? 'davison_progressed' : 'davison'
|
||||
}
|
||||
if (mainTab === 'marks') {
|
||||
if (subTab === 'prog') return 'marks_progressed'
|
||||
return marksWho === 'other' ? 'marks_other' : 'marks_me'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export type OverlayEntry = {
|
||||
planet: string
|
||||
sign: string
|
||||
house: number
|
||||
house_tip: string
|
||||
}
|
||||
|
||||
export function overlayEntriesFrom(charts: Record<string, unknown>): OverlayEntry[] {
|
||||
const raw = chartBlock(charts, 'overlay')?.entries
|
||||
return Array.isArray(raw) ? (raw as OverlayEntry[]) : []
|
||||
}
|
||||
|
||||
export type SynastrySection = { title: string; body: string }
|
||||
|
||||
export function sectionsFromDetail(detail: Record<string, unknown> | null): SynastrySection[] {
|
||||
const raw = detail?.sections
|
||||
return Array.isArray(raw) ? (raw as SynastrySection[]) : []
|
||||
}
|
||||
|
||||
export function buildRelationSharePayload(
|
||||
report: GrowthReport | null,
|
||||
summary: Record<string, unknown>,
|
||||
headline: string,
|
||||
love: number,
|
||||
friend: number,
|
||||
marriage: number,
|
||||
): RelationSharePayload | null {
|
||||
if (!report) return null
|
||||
return {
|
||||
type: 'relation',
|
||||
me: String(summary.me_name || '我'),
|
||||
other: String(summary.other_name || 'TA'),
|
||||
diff: headline,
|
||||
keywords: [`恋爱${love}`, `友情${friend}`, `婚姻${marriage}`],
|
||||
}
|
||||
}
|
||||
|
||||
export function birthLabel(d?: string) {
|
||||
if (!d) return ''
|
||||
return String(d).slice(0, 10)
|
||||
}
|
||||
|
||||
export function profileInitial(p: Profile) {
|
||||
return (p.display_name || 'TA').slice(0, 1)
|
||||
}
|
||||
Reference in New Issue
Block a user