151 lines
4.9 KiB
JavaScript
151 lines
4.9 KiB
JavaScript
const dimensionMeta = require("../constants/dimensions");
|
|
const { formatDisplayDateTime } = require("./date");
|
|
|
|
const dimensionMap = dimensionMeta.reduce((acc, item) => {
|
|
acc[item.key] = item;
|
|
return acc;
|
|
}, {});
|
|
|
|
function pickValue(source, keys, fallback) {
|
|
if (!source) {
|
|
return fallback;
|
|
}
|
|
for (const key of keys) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
const value = source[key];
|
|
if (value !== undefined && value !== null) {
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
function mapTrendText(trend) {
|
|
if (trend === "up") {
|
|
return "回升";
|
|
}
|
|
if (trend === "down") {
|
|
return "波动";
|
|
}
|
|
return "平稳";
|
|
}
|
|
|
|
function normalizePillars(pillars) {
|
|
if (!Array.isArray(pillars)) {
|
|
return [];
|
|
}
|
|
return pillars
|
|
.map((item) => ({
|
|
label: pickValue(item, ["label", "Label"], ""),
|
|
value: pickValue(item, ["value", "Value"], "")
|
|
}))
|
|
.filter((item) => item.label || item.value);
|
|
}
|
|
|
|
function formatListText(list, separator = " · ") {
|
|
if (!Array.isArray(list) || !list.length) {
|
|
return "";
|
|
}
|
|
return list.join(separator);
|
|
}
|
|
|
|
function normalizeFortunePayload(fortune) {
|
|
if (!fortune) {
|
|
return null;
|
|
}
|
|
const dimensionListRaw = pickValue(fortune, ["dimensions", "Dimensions"], []);
|
|
const dimensionList = Array.isArray(dimensionListRaw) ? dimensionListRaw : [];
|
|
const dimensions = dimensionList.map((item) => {
|
|
const key = pickValue(item, ["key", "Key"], "");
|
|
const meta = dimensionMap[key] || {};
|
|
const trend = pickValue(item, ["trend", "Trend"], "steady");
|
|
return {
|
|
key,
|
|
title: pickValue(item, ["title", "Title"], meta.title || key),
|
|
score: pickValue(item, ["score", "Score"], 0),
|
|
trend,
|
|
insight: pickValue(item, ["insight", "Insight"], ""),
|
|
suggestion: pickValue(item, ["suggestion", "Suggestion"], ""),
|
|
icon: meta.icon || "⭐",
|
|
accent: meta.accent || "#ffb85c",
|
|
trendText: mapTrendText(trend)
|
|
};
|
|
});
|
|
const total = dimensions.reduce((acc, current) => acc + (current.score || 0), 0);
|
|
const overallScore = dimensions.length ? Math.round(total / dimensions.length) : 0;
|
|
|
|
return {
|
|
fortuneDate: pickValue(fortune, ["fortuneDate", "FortuneDate"], ""),
|
|
summary: pickValue(fortune, ["summary", "Summary"], ""),
|
|
narrative: pickValue(fortune, ["narrative", "Narrative"], ""),
|
|
dimensions,
|
|
overallScore,
|
|
luckyGuide: normalizeGuide(pickValue(fortune, ["luckyGuide", "LuckyGuide"], null)),
|
|
profile: normalizeProfile(pickValue(fortune, ["profile", "Profile"], null))
|
|
};
|
|
}
|
|
|
|
function normalizeProfile(profile) {
|
|
if (!profile) {
|
|
return null;
|
|
}
|
|
const fiveElements = pickValue(profile, ["fiveElementDistribution", "FiveElementDistribution"], []);
|
|
const total = fiveElements.reduce((acc, item) => acc + (pickValue(item, ["count", "Count"], 0) || 0), 0) || 1;
|
|
const distribution = fiveElements.map((item) => {
|
|
const count = pickValue(item, ["count", "Count"], 0);
|
|
const percent = Math.round(((count || 0) / total) * 100);
|
|
return {
|
|
element: pickValue(item, ["element", "Element"], "未知"),
|
|
count,
|
|
percent,
|
|
width: `${Math.max(percent, 6)}%`
|
|
};
|
|
});
|
|
const birthDateTimeRaw = pickValue(profile, ["birthDateTime", "BirthDateTime"], "");
|
|
return {
|
|
birthCity: pickValue(profile, ["birthCity", "BirthCity"], ""),
|
|
birthProvince: pickValue(profile, ["birthProvince", "BirthProvince"], ""),
|
|
birthDateTime: birthDateTimeRaw ? formatDisplayDateTime(birthDateTimeRaw) : "",
|
|
birthPillars: normalizePillars(pickValue(profile, ["birthPillars", "BirthPillars"], [])),
|
|
todayPillars: normalizePillars(pickValue(profile, ["todayPillars", "TodayPillars"], [])),
|
|
distribution,
|
|
weakElements: pickValue(profile, ["weakElements", "WeakElements"], []),
|
|
strongElements: pickValue(profile, ["strongElements", "StrongElements"], [])
|
|
};
|
|
}
|
|
|
|
function normalizeGuide(guide) {
|
|
if (!guide) {
|
|
return null;
|
|
}
|
|
const slots = pickValue(guide, ["bestTimeSlots", "BestTimeSlots"], []);
|
|
const colors = pickValue(guide, ["colors", "Colors"], []);
|
|
const directions = pickValue(guide, ["directions", "Directions"], []);
|
|
const props = pickValue(guide, ["props", "Props"], []);
|
|
const activities = pickValue(guide, ["activities", "Activities"], []);
|
|
return {
|
|
element: pickValue(guide, ["element", "Element"], "木"),
|
|
colors,
|
|
colorText: formatListText(colors),
|
|
directions,
|
|
directionText: formatListText(directions),
|
|
props,
|
|
propsText: formatListText(props),
|
|
activities,
|
|
activitiesText: formatListText(activities, " / "),
|
|
bestTimeSlots: Array.isArray(slots)
|
|
? slots.map((slot) => ({
|
|
label: pickValue(slot, ["label", "Label"], "时段"),
|
|
period: pickValue(slot, ["period", "Period"], ""),
|
|
reason: pickValue(slot, ["reason", "Reason"], "")
|
|
}))
|
|
: []
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
normalizeFortunePayload
|
|
};
|
|
|