Files
everything-is-suitable/everything-is-suitable-uniapp/src/algorithms/fortune.ts
T
张翔 0c9a4ac96b feat: 添加 UniApp 核心源码文件
- App.vue 应用入口
- algorithms/ 算法模块(黄历、紫微斗数、运势、日历等)
- services/ 业务服务层
- utils/ 工具函数(storage、exportImport)
- 配置文件(manifest.json、pages.json、vite.config.ts)
- H5 入口 index.html
2026-04-29 21:15:55 +08:00

511 lines
21 KiB
TypeScript

import { PalaceType, StarNature, EarthlyBranch } from './enums'
import { determineLuckLevel } from './ziweiAlgorithm'
import {
generateDailyFortune,
generateMonthlyFortune,
generateYearlyFortune,
calculateDailyAdjustment,
calculateMonthlyAdjustment,
calculateYearlyAdjustment,
} from './fortuneStrategy'
import type {
ZiweiChart,
Palace,
LoveFortuneDetail,
StudyFortuneDetail,
SocialFortuneDetail,
TravelFortuneDetail,
DailyFortune,
MonthlyFortune,
YearlyFortune,
} from './types'
const PEACH_BLOSSOM_STARS = ['HONGLUAN', 'TIANXI', 'TANLANG']
const STUDY_STARS = ['WENCHANG', 'WENQU']
const NOBLE_STARS = ['ZUOFU', 'YOUBI', 'TIANKUI', 'TIANYUE']
const TRAVEL_STARS = ['TIANMA']
const DATING_TIME_MAP: Record<string, string> = {
'大吉': '下午3点至5点,傍晚6点至8点',
'吉': '下午2点至4点,晚上7点至9点',
'中吉': '上午10点至12点,下午3点至5点',
'平': '下午1点至3点',
'中平': '上午9点至11点',
'小凶': '暂不宜约会,宜先调整自身状态',
'凶': '不宜约会,宜静待时机',
}
const STUDY_TIME_MAP: Record<string, string> = {
'大吉': '清晨6点至8点,晚上8点至10点',
'吉': '上午8点至10点,晚上7点至9点',
'中吉': '上午9点至11点,下午3点至5点',
'平': '上午10点至12点',
'中平': '下午2点至4点',
'小凶': '学习效率较低,建议短暂休息后复习',
'凶': '不宜高强度学习,宜轻松阅读',
}
const SOCIAL_TIME_MAP: Record<string, string> = {
'大吉': '中午12点至2点,晚上6点至9点',
'吉': '下午1点至3点,晚上7点至10点',
'中吉': '上午10点至12点,下午3点至5点',
'平': '下午2点至4点',
'中平': '上午9点至11点',
'小凶': '社交运势偏弱,宜减少应酬',
'凶': '不宜社交,宜独处调整',
}
const TRAVEL_TIME_MAP: Record<string, string> = {
'大吉': '上午8点至10点出发最佳',
'吉': '上午9点至11点出发较佳',
'中吉': '上午10点至12点可出行',
'平': '中午前后出行即可',
'中平': '下午出行较为稳妥',
'小凶': '出行需谨慎,注意安全',
'凶': '不宜远行,近处活动为佳',
}
const SUITABLE_SUBJECTS_MAP: Record<string, string> = {
'大吉': '文学、哲学、历史等文科类,或管理、领导力相关',
'吉': '语言、艺术、社会科学等,或技术类基础学科',
'中吉': '数学、逻辑、计算机等理科类',
'平': '实用技能、职业培训等应用型学科',
'中平': '通识类课程,宜广泛涉猎',
'小凶': '宜复习巩固已有知识,不宜开启新领域',
'凶': '宜休息调整,轻松阅读即可',
}
const SUITABLE_OCCASION_MAP: Record<string, string> = {
'大吉': '商务宴请、高端社交、行业峰会',
'吉': '朋友聚会、团队活动、文化交流',
'中吉': '社区活动、兴趣小组、学习交流',
'平': '日常社交、同事聚餐',
'中平': '小范围聚会、线上交流',
'小凶': '减少社交活动,宜小范围相处',
'凶': '不宜参加社交活动,宜独处',
}
const SUITABLE_TRANSPORT_MAP: Record<string, string> = {
'大吉': '飞机、高铁等快速交通工具',
'吉': '高铁、自驾等舒适出行方式',
'中吉': '火车、大巴等常规交通',
'平': '公共交通、地铁等日常出行',
'中平': '短途公交、步行等',
'小凶': '出行需注意安全,避免自驾',
'凶': '不宜远行,就近活动为佳',
}
const DIRECTION_LIST = ['东方', '南方', '西方', '北方', '东南', '西南', '东北', '西北']
function findPalace(chart: ZiweiChart, palaceType: PalaceType): Palace | undefined {
return chart.palaces.find(p => p.palaceType === palaceType)
}
function countMinorStars(palace: Palace | undefined, starNames: string[]): number {
if (palace == null) return 0
let count = 0
for (const star of starNames) {
if (palace.minorStars.includes(star)) count++
}
return count
}
function countMajorStars(palace: Palace | undefined, starNames: string[]): number {
if (palace == null) return 0
let count = 0
for (const starInfo of palace.majorStars) {
if (starNames.includes(starInfo.star)) count++
}
return count
}
function clampScore(score: number): number {
return Math.max(0, Math.min(100, Math.floor(score)))
}
export function analyzeLoveFortune(chart: ZiweiChart, date: Date): LoveFortuneDetail {
const fuqiPalace = findPalace(chart, PalaceType.FUQI)
const baseScore = fuqiPalace?.score ?? 50
const peachBlossomCount =
countMinorStars(fuqiPalace, PEACH_BLOSSOM_STARS) +
countMajorStars(fuqiPalace, PEACH_BLOSSOM_STARS)
const peachBonus = peachBlossomCount * 5
const dayAdj = fuqiPalace ? calculateDailyAdjustment(fuqiPalace, date) : 0
const loveScore = clampScore(baseScore + peachBonus + dayAdj)
const luckLevel = determineLuckLevel(loveScore)
const peachBlossomIndex = getPeachBlossomLevel(peachBlossomCount)
return {
loveScore,
overallLoveLuck: luckLevel,
peachBlossomIndex,
singleAdvice: getSingleAdvice(luckLevel, peachBlossomCount),
datingAdvice: getDatingAdvice(luckLevel),
marriageAdvice: getMarriageAdvice(luckLevel),
bestDatingTime: DATING_TIME_MAP[luckLevel] ?? '下午2点至4点',
}
}
function getPeachBlossomLevel(count: number): string {
if (count >= 3) return '极旺'
if (count >= 2) return '旺盛'
if (count >= 1) return '一般'
return '偏弱'
}
function getSingleAdvice(luckLevel: string, peachCount: number): string {
if (peachCount >= 2) return '桃花旺盛,有望遇到心仪对象,可主动出击'
if (luckLevel === '大吉' || luckLevel === '吉') return '感情运势良好,可多参加社交活动,增加遇见良缘的机会'
if (luckLevel === '中吉' || luckLevel === '平') return '感情运势平稳,宜耐心等待,不宜急于求成'
return '感情运势偏弱,宜先提升自我,静待良缘'
}
function getDatingAdvice(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '感情甜蜜,适合深入交流,增进彼此了解'
if (luckLevel === '中吉' || luckLevel === '平') return '感情平稳,保持日常沟通,多关心对方需求'
if (luckLevel === '中平') return '感情略显平淡,可制造小惊喜,增添情趣'
return '感情易生波折,需多包容理解,避免争执'
}
function getMarriageAdvice(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '婚姻运势良好,适合商讨婚事或增进夫妻感情'
if (luckLevel === '中吉' || luckLevel === '平') return '婚姻运势平稳,宜相互扶持,共同经营家庭'
if (luckLevel === '中平') return '婚姻运势一般,需多沟通协调,避免误解'
return '婚姻运势欠佳,需多忍让包容,共同面对困难'
}
export function analyzeStudyFortune(chart: ZiweiChart, date: Date): StudyFortuneDetail {
const guanluPalace = findPalace(chart, PalaceType.GUANLU)
const baseScore = guanluPalace?.score ?? 50
const studyStarCount = countMinorStars(guanluPalace, STUDY_STARS)
const studyBonus = studyStarCount * 6
const dayAdj = guanluPalace ? calculateDailyAdjustment(guanluPalace, date) : 0
const studyScore = clampScore(baseScore + studyBonus + dayAdj)
const luckLevel = determineLuckLevel(studyScore)
return {
studyScore,
overallStudyLuck: luckLevel,
focusIndex: getFocusLevel(studyScore),
memoryIndex: getMemoryLevel(studyScore),
studyAdvice: getStudyAdvice(luckLevel, studyStarCount),
examLuck: getExamLuck(luckLevel),
bestStudyTime: STUDY_TIME_MAP[luckLevel] ?? '上午9点至11点',
suitableSubjects: SUITABLE_SUBJECTS_MAP[luckLevel] ?? '通识类课程',
studyEnvironmentAdvice: getStudyEnvironmentAdvice(luckLevel),
}
}
function getFocusLevel(score: number): string {
if (score >= 80) return '高度集中'
if (score >= 60) return '较为集中'
if (score >= 40) return '一般'
return '容易分心'
}
function getMemoryLevel(score: number): string {
if (score >= 80) return '记忆力佳'
if (score >= 60) return '记忆力良好'
if (score >= 40) return '记忆力一般'
return '记忆力偏弱'
}
function getStudyAdvice(luckLevel: string, studyStarCount: number): string {
if (studyStarCount >= 2) return '文昌文曲双星照耀,学业运势极佳,适合攻克难题和备考'
if (luckLevel === '大吉' || luckLevel === '吉') return '学业运势良好,适合深入学习新知识,效率较高'
if (luckLevel === '中吉' || luckLevel === '平') return '学业运势平稳,按计划学习即可,注意劳逸结合'
return '学业运势偏弱,宜复习巩固已有知识,不宜开启新领域'
}
function getExamLuck(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '考试运佳,发挥出色'
if (luckLevel === '中吉' || luckLevel === '平') return '考试运平稳,正常发挥'
if (luckLevel === '中平') return '考试运一般,需多加准备'
return '考试运欠佳,需格外用心准备'
}
function getStudyEnvironmentAdvice(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '宜在安静明亮的环境中学习,效率最佳'
if (luckLevel === '中吉' || luckLevel === '平') return '宜选择图书馆或自习室等安静场所'
return '宜在熟悉的环境中学习,减少外界干扰'
}
export function analyzeSocialFortune(chart: ZiweiChart, date: Date): SocialFortuneDetail {
const xiongPalace = findPalace(chart, PalaceType.XIONG)
const baseScore = xiongPalace?.score ?? 50
const nobleStarCount = countMinorStars(xiongPalace, NOBLE_STARS)
const nobleBonus = nobleStarCount * 5
const dayAdj = xiongPalace ? calculateDailyAdjustment(xiongPalace, date) : 0
const socialScore = clampScore(baseScore + nobleBonus + dayAdj)
const luckLevel = determineLuckLevel(socialScore)
return {
socialScore,
overallSocialLuck: luckLevel,
popularityIndex: getPopularityLevel(socialScore),
communicationAbility: getCommunicationLevel(socialScore),
socialAdvice: getSocialAdvice(luckLevel, nobleStarCount),
nobleLuck: getNobleLuck(nobleStarCount),
bestSocialTime: SOCIAL_TIME_MAP[luckLevel] ?? '下午2点至4点',
suitableOccasion: SUITABLE_OCCASION_MAP[luckLevel] ?? '日常社交',
interpersonalAdvice: getInterpersonalAdvice(luckLevel),
}
}
function getPopularityLevel(score: number): string {
if (score >= 80) return '人气旺盛'
if (score >= 60) return '人缘良好'
if (score >= 40) return '人缘一般'
return '人缘偏弱'
}
function getCommunicationLevel(score: number): string {
if (score >= 80) return '表达流畅'
if (score >= 60) return '沟通顺畅'
if (score >= 40) return '沟通一般'
return '沟通不畅'
}
function getSocialAdvice(luckLevel: string, nobleStarCount: number): string {
if (nobleStarCount >= 2) return '贵人星照耀,社交运势极佳,易获他人帮助与支持'
if (luckLevel === '大吉' || luckLevel === '吉') return '社交运势良好,适合拓展人脉,参加社交活动'
if (luckLevel === '中吉' || luckLevel === '平') return '社交运势平稳,保持正常交往即可'
return '社交运势偏弱,宜减少不必要的应酬,专注自身'
}
function getNobleLuck(nobleStarCount: number): string {
if (nobleStarCount >= 3) return '贵人运极旺,多有助力'
if (nobleStarCount >= 2) return '贵人运旺盛,易遇贵人'
if (nobleStarCount >= 1) return '贵人运一般,偶有助力'
return '贵人运偏弱,需自力更生'
}
function getInterpersonalAdvice(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '人际关系和谐,宜主动关心他人,增进感情'
if (luckLevel === '中吉' || luckLevel === '平') return '人际关系平稳,保持真诚待人即可'
if (luckLevel === '中平') return '人际关系略显平淡,可主动联络朋友'
return '人际关系易生摩擦,需多忍让,避免冲突'
}
export function analyzeTravelFortune(chart: ZiweiChart, date: Date): TravelFortuneDetail {
const qianPalace = findPalace(chart, PalaceType.QIAN)
const baseScore = qianPalace?.score ?? 50
const travelStarCount = countMinorStars(qianPalace, TRAVEL_STARS)
const travelBonus = travelStarCount * 5
const dayAdj = qianPalace ? calculateDailyAdjustment(qianPalace, date) : 0
const travelScore = clampScore(baseScore + travelBonus + dayAdj)
const luckLevel = determineLuckLevel(travelScore)
return {
travelScore,
overallTravelLuck: luckLevel,
safetyIndex: getSafetyLevel(travelScore),
smoothnessIndex: getSmoothnessLevel(travelScore),
travelAdvice: getTravelAdvice(luckLevel, travelStarCount),
bestTravelTime: TRAVEL_TIME_MAP[luckLevel] ?? '中午前后',
suitableTransport: SUITABLE_TRANSPORT_MAP[luckLevel] ?? '常规交通',
precautions: getPrecautions(luckLevel),
nobleDirection: getNobleDirection(chart, date),
}
}
function getSafetyLevel(score: number): string {
if (score >= 80) return '安全指数高'
if (score >= 60) return '安全指数良好'
if (score >= 40) return '安全指数一般'
return '安全指数偏低'
}
function getSmoothnessLevel(score: number): string {
if (score >= 80) return '顺畅无阻'
if (score >= 60) return '较为顺畅'
if (score >= 40) return '一般'
return '可能受阻'
}
function getTravelAdvice(luckLevel: string, travelStarCount: number): string {
if (travelStarCount >= 1) return '天马星动,出行运势佳,适合出差旅行'
if (luckLevel === '大吉' || luckLevel === '吉') return '出行运势良好,旅途顺利,可安排出行计划'
if (luckLevel === '中吉' || luckLevel === '平') return '出行运势平稳,按计划出行即可'
return '出行运势欠佳,建议减少不必要的外出'
}
function getPrecautions(luckLevel: string): string {
if (luckLevel === '大吉' || luckLevel === '吉') return '出行顺利,注意常规安全即可'
if (luckLevel === '中吉' || luckLevel === '平') return '出行注意交通安全,提前查看天气'
if (luckLevel === '中平') return '出行需谨慎,注意人身和财物安全'
return '出行风险较高,务必注意安全,避免夜间出行'
}
function getNobleDirection(chart: ZiweiChart, _date: Date): string {
const mingGong = findPalace(chart, PalaceType.MING)
if (mingGong == null) return '东方'
const hasJiStar = mingGong.majorStars.some(s => s.nature === StarNature.JI)
const branchIndex = EarthlyBranch.index(chart.mingGongBranch) - 1
const directionIndex = hasJiStar
? (branchIndex + 1) % DIRECTION_LIST.length
: (branchIndex + 3) % DIRECTION_LIST.length
return DIRECTION_LIST[directionIndex]
}
export function generateComprehensiveFortune(chart: ZiweiChart, date: Date): DailyFortune {
const baseFortune = generateDailyFortune(chart, date)
const loveFortune = analyzeLoveFortune(chart, date)
const studyFortune = analyzeStudyFortune(chart, date)
const socialFortune = analyzeSocialFortune(chart, date)
const travelFortune = analyzeTravelFortune(chart, date)
return {
...baseFortune,
loveScore: loveFortune.loveScore,
overallLoveLuck: loveFortune.overallLoveLuck,
peachBlossomIndex: loveFortune.peachBlossomIndex,
singleAdvice: loveFortune.singleAdvice,
datingAdvice: loveFortune.datingAdvice,
marriageAdvice: loveFortune.marriageAdvice,
bestDatingTime: loveFortune.bestDatingTime,
studyScore: studyFortune.studyScore,
overallStudyLuck: studyFortune.overallStudyLuck,
focusIndex: studyFortune.focusIndex,
memoryIndex: studyFortune.memoryIndex,
studyAdvice: studyFortune.studyAdvice,
examLuck: studyFortune.examLuck,
bestStudyTime: studyFortune.bestStudyTime,
suitableSubjects: studyFortune.suitableSubjects,
studyEnvironmentAdvice: studyFortune.studyEnvironmentAdvice,
socialScore: socialFortune.socialScore,
overallSocialLuck: socialFortune.overallSocialLuck,
popularityIndex: socialFortune.popularityIndex,
communicationAbility: socialFortune.communicationAbility,
socialAdvice: socialFortune.socialAdvice,
nobleLuck: socialFortune.nobleLuck,
bestSocialTime: socialFortune.bestSocialTime,
suitableOccasion: socialFortune.suitableOccasion,
interpersonalAdvice: socialFortune.interpersonalAdvice,
travelScore: travelFortune.travelScore,
overallTravelLuck: travelFortune.overallTravelLuck,
safetyIndex: travelFortune.safetyIndex,
smoothnessIndex: travelFortune.smoothnessIndex,
travelAdvice: travelFortune.travelAdvice,
bestTravelTime: travelFortune.bestTravelTime,
suitableTransport: travelFortune.suitableTransport,
precautions: travelFortune.precautions,
nobleDirection: travelFortune.nobleDirection,
}
}
export function generateComprehensiveMonthlyFortune(
chart: ZiweiChart,
year: number,
month: number,
): MonthlyFortune {
const baseFortune = generateMonthlyFortune(chart, year, month)
const midMonthDate = new Date(year, month - 1, 15)
const loveFortune = analyzeLoveFortune(chart, midMonthDate)
const studyFortune = analyzeStudyFortune(chart, midMonthDate)
const socialFortune = analyzeSocialFortune(chart, midMonthDate)
const travelFortune = analyzeTravelFortune(chart, midMonthDate)
return {
...baseFortune,
loveScore: loveFortune.loveScore,
overallLoveLuck: loveFortune.overallLoveLuck,
peachBlossomIndex: loveFortune.peachBlossomIndex,
singleAdvice: loveFortune.singleAdvice,
datingAdvice: loveFortune.datingAdvice,
marriageAdvice: loveFortune.marriageAdvice,
bestDatingTime: loveFortune.bestDatingTime,
studyScore: studyFortune.studyScore,
overallStudyLuck: studyFortune.overallStudyLuck,
focusIndex: studyFortune.focusIndex,
memoryIndex: studyFortune.memoryIndex,
studyAdvice: studyFortune.studyAdvice,
examLuck: studyFortune.examLuck,
bestStudyTime: studyFortune.bestStudyTime,
suitableSubjects: studyFortune.suitableSubjects,
studyEnvironmentAdvice: studyFortune.studyEnvironmentAdvice,
socialScore: socialFortune.socialScore,
overallSocialLuck: socialFortune.overallSocialLuck,
popularityIndex: socialFortune.popularityIndex,
communicationAbility: socialFortune.communicationAbility,
socialAdvice: socialFortune.socialAdvice,
nobleLuck: socialFortune.nobleLuck,
bestSocialTime: socialFortune.bestSocialTime,
suitableOccasion: socialFortune.suitableOccasion,
interpersonalAdvice: socialFortune.interpersonalAdvice,
travelScore: travelFortune.travelScore,
overallTravelLuck: travelFortune.overallTravelLuck,
safetyIndex: travelFortune.safetyIndex,
smoothnessIndex: travelFortune.smoothnessIndex,
travelAdvice: travelFortune.travelAdvice,
bestTravelTime: travelFortune.bestTravelTime,
suitableTransport: travelFortune.suitableTransport,
precautions: travelFortune.precautions,
nobleDirection: travelFortune.nobleDirection,
}
}
export function generateComprehensiveYearlyFortune(
chart: ZiweiChart,
year: number,
): YearlyFortune {
const baseFortune = generateYearlyFortune(chart, year)
const midYearDate = new Date(year, 6, 1)
const loveFortune = analyzeLoveFortune(chart, midYearDate)
const studyFortune = analyzeStudyFortune(chart, midYearDate)
const socialFortune = analyzeSocialFortune(chart, midYearDate)
const travelFortune = analyzeTravelFortune(chart, midYearDate)
return {
...baseFortune,
loveScore: loveFortune.loveScore,
overallLoveLuck: loveFortune.overallLoveLuck,
peachBlossomIndex: loveFortune.peachBlossomIndex,
singleAdvice: loveFortune.singleAdvice,
datingAdvice: loveFortune.datingAdvice,
marriageAdvice: loveFortune.marriageAdvice,
bestDatingTime: loveFortune.bestDatingTime,
studyScore: studyFortune.studyScore,
overallStudyLuck: studyFortune.overallStudyLuck,
focusIndex: studyFortune.focusIndex,
memoryIndex: studyFortune.memoryIndex,
studyAdvice: studyFortune.studyAdvice,
examLuck: studyFortune.examLuck,
bestStudyTime: studyFortune.bestStudyTime,
suitableSubjects: studyFortune.suitableSubjects,
studyEnvironmentAdvice: studyFortune.studyEnvironmentAdvice,
socialScore: socialFortune.socialScore,
overallSocialLuck: socialFortune.overallSocialLuck,
popularityIndex: socialFortune.popularityIndex,
communicationAbility: socialFortune.communicationAbility,
socialAdvice: socialFortune.socialAdvice,
nobleLuck: socialFortune.nobleLuck,
bestSocialTime: socialFortune.bestSocialTime,
suitableOccasion: socialFortune.suitableOccasion,
interpersonalAdvice: socialFortune.interpersonalAdvice,
travelScore: travelFortune.travelScore,
overallTravelLuck: travelFortune.overallTravelLuck,
safetyIndex: travelFortune.safetyIndex,
smoothnessIndex: travelFortune.smoothnessIndex,
travelAdvice: travelFortune.travelAdvice,
bestTravelTime: travelFortune.bestTravelTime,
suitableTransport: travelFortune.suitableTransport,
precautions: travelFortune.precautions,
nobleDirection: travelFortune.nobleDirection,
}
}