| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245 |
- /**
- * 八字计算工具类
- * 基于传统命理学理论实现八字计算、分析和配对功能
- * 支持专业API验证和本地算法双重计算
- */
- import { BAZI_API_CONFIG } from '@/config/api-config.js'
- // 天干
- const TIANGAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
- // 地支
- const DIZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
- // 天干五行
- const TIANGAN_WUXING = {
- '甲': '木', '乙': '木',
- '丙': '火', '丁': '火',
- '戊': '土', '己': '土',
- '庚': '金', '辛': '金',
- '壬': '水', '癸': '水'
- }
- // 地支五行
- const DIZHI_WUXING = {
- '子': '水', '丑': '土', '寅': '木', '卯': '木',
- '辰': '土', '巳': '火', '午': '火', '未': '土',
- '申': '金', '酉': '金', '戌': '土', '亥': '水'
- }
- // 天干阴阳
- const TIANGAN_YINYANG = {
- '甲': '阳', '乙': '阴', '丙': '阳', '丁': '阴', '戊': '阳',
- '己': '阴', '庚': '阳', '辛': '阴', '壬': '阳', '癸': '阴'
- }
- // 地支阴阳
- const DIZHI_YINYANG = {
- '子': '阳', '丑': '阴', '寅': '阳', '卯': '阴', '辰': '阳', '巳': '阴',
- '午': '阳', '未': '阴', '申': '阳', '酉': '阴', '戌': '阳', '亥': '阴'
- }
- // 十二生肖
- const SHENGXIAO = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
- // 月份地支对照表(节气月)
- const MONTH_DIZHI = {
- 2: '寅', 3: '卯', 4: '辰', 5: '巳', 6: '午', 7: '未',
- 8: '申', 9: '酉', 10: '戌', 11: '亥', 12: '子', 1: '丑'
- }
- // 时辰对照表
- const TIME_DIZHI = {
- 23: '子', 0: '子', 1: '丑', 2: '丑', 3: '寅', 4: '寅',
- 5: '卯', 6: '卯', 7: '辰', 8: '辰', 9: '巳', 10: '巳',
- 11: '午', 12: '午', 13: '未', 14: '未', 15: '申', 16: '申',
- 17: '酉', 18: '酉', 19: '戌', 20: '戌', 21: '亥', 22: '亥'
- }
- // 五行生克关系
- const WUXING_RELATION = {
- '生': {
- '木': '火', '火': '土', '土': '金', '金': '水', '水': '木'
- },
- '克': {
- '木': '土', '火': '金', '土': '水', '金': '木', '水': '火'
- }
- }
- // 纳音表(简化版)
- const NAYIN = {
- '甲子': '海中金', '乙丑': '海中金', '丙寅': '炉中火', '丁卯': '炉中火',
- '戊辰': '大林木', '己巳': '大林木', '庚午': '路旁土', '辛未': '路旁土',
- '壬申': '剑锋金', '癸酉': '剑锋金', '甲戌': '山头火', '乙亥': '山头火',
- '丙子': '涧下水', '丁丑': '涧下水', '戊寅': '城头土', '己卯': '城头土',
- '庚辰': '白蜡金', '辛巳': '白蜡金', '壬午': '杨柳木', '癸未': '杨柳木',
- '甲申': '泉中水', '乙酉': '泉中水', '丙戌': '屋上土', '丁亥': '屋上土',
- '戊子': '霹雳火', '己丑': '霹雳火', '庚寅': '松柏木', '辛卯': '松柏木',
- '壬辰': '长流水', '癸巳': '长流水', '甲午': '砂中金', '乙未': '砂中金',
- '丙申': '山下火', '丁酉': '山下火', '戊戌': '平地木', '己亥': '平地木',
- '庚子': '壁上土', '辛丑': '壁上土', '壬寅': '金箔金', '癸卯': '金箔金',
- '甲辰': '佛灯火', '乙巳': '佛灯火', '丙午': '天河水', '丁未': '天河水',
- '戊申': '大驿土', '己酉': '大驿土', '庚戌': '钗钏金', '辛亥': '钗钏金',
- '壬子': '桑柘木', '癸丑': '桑柘木', '甲寅': '大溪水', '乙卯': '大溪水',
- '丙辰': '砂中土', '丁巳': '砂中土', '戊午': '天上火', '己未': '天上火',
- '庚申': '石榴木', '辛酉': '石榴木', '壬戌': '大海水', '癸亥': '大海水'
- }
- /**
- * 计算八字
- * @param {Date} birthDate 出生日期
- * @param {Number} hour 出生时辰(0-23)
- * @returns {Object} 八字信息
- */
- export function calculateBaZi(birthDate, hour) {
- const year = birthDate.getFullYear()
- const month = birthDate.getMonth() + 1
- const day = birthDate.getDate()
-
- // 计算年柱
- const yearGanZhi = getYearGanZhi(year)
-
- // 计算月柱
- const monthGanZhi = getMonthGanZhi(year, month)
-
- // 计算日柱
- const dayGanZhi = getDayGanZhi(year, month, day)
-
- // 计算时柱
- const hourGanZhi = getHourGanZhi(dayGanZhi.gan, hour)
-
- // 分析八字
- const analysis = analyzeBaZi({
- year: yearGanZhi,
- month: monthGanZhi,
- day: dayGanZhi,
- hour: hourGanZhi
- })
-
- return {
- year: yearGanZhi,
- month: monthGanZhi,
- day: dayGanZhi,
- hour: hourGanZhi,
- birthInfo: {
- year: year,
- month: month,
- day: day,
- hour: hour,
- shengxiao: SHENGXIAO[(year - 4) % 12],
- nayin: NAYIN[yearGanZhi.ganZhi] || '未知'
- },
- analysis: analysis,
- baziString: `${yearGanZhi.ganZhi} ${monthGanZhi.ganZhi} ${dayGanZhi.ganZhi} ${hourGanZhi.ganZhi}`,
- rizhu: dayGanZhi.ganZhi,
- riganWuxing: TIANGAN_WUXING[dayGanZhi.gan]
- }
- }
- /**
- * 获取年柱干支
- */
- function getYearGanZhi(year) {
- // 以1900年庚子年为基准计算
- const baseYear = 1900
- const yearOffset = year - baseYear
-
- const ganIndex = (yearOffset + 6) % 10 // 庚为第7个天干,索引为6
- const zhiIndex = (yearOffset + 0) % 12 // 子为第1个地支,索引为0
-
- const gan = TIANGAN[ganIndex]
- const zhi = DIZHI[zhiIndex]
-
- return {
- gan: gan,
- zhi: zhi,
- ganZhi: gan + zhi,
- wuxing: TIANGAN_WUXING[gan],
- yinyang: TIANGAN_YINYANG[gan]
- }
- }
- /**
- * 获取月柱干支
- */
- function getMonthGanZhi(year, month) {
- // 简化计算,实际应该根据节气
- const zhi = MONTH_DIZHI[month]
-
- // 月干计算:年干为甲己配丙寅,乙庚丁卯始...
- const yearGan = getYearGanZhi(year).gan
- let ganIndex = 0
-
- switch (yearGan) {
- case '甲': case '己': ganIndex = 2; break // 丙
- case '乙': case '庚': ganIndex = 3; break // 丁
- case '丙': case '辛': ganIndex = 4; break // 戊
- case '丁': case '壬': ganIndex = 5; break // 己
- case '戊': case '癸': ganIndex = 6; break // 庚
- }
-
- // 从寅月开始计算
- const monthOffset = month === 1 ? 11 : (month === 2 ? 0 : month - 2)
- ganIndex = (ganIndex + monthOffset) % 10
-
- const gan = TIANGAN[ganIndex]
-
- return {
- gan: gan,
- zhi: zhi,
- ganZhi: gan + zhi,
- wuxing: TIANGAN_WUXING[gan],
- yinyang: TIANGAN_YINYANG[gan]
- }
- }
- /**
- * 获取日柱干支(简化算法)
- */
- function getDayGanZhi(year, month, day) {
- // 以公元1年1月1日为甲子日计算(简化)
- const date = new Date(year, month - 1, day)
- const daysSince1900 = Math.floor((date - new Date(1900, 0, 1)) / (24 * 60 * 60 * 1000))
-
- // 1900年1月1日为庚戌日
- const ganIndex = (daysSince1900 + 6) % 10 // 庚的索引是6
- const zhiIndex = (daysSince1900 + 10) % 12 // 戌的索引是10
-
- const gan = TIANGAN[ganIndex]
- const zhi = DIZHI[zhiIndex]
-
- return {
- gan: gan,
- zhi: zhi,
- ganZhi: gan + zhi,
- wuxing: TIANGAN_WUXING[gan],
- yinyang: TIANGAN_YINYANG[gan]
- }
- }
- /**
- * 获取时柱干支
- */
- function getHourGanZhi(dayGan, hour) {
- const zhi = TIME_DIZHI[hour] || '未知'
-
- // 时干计算:甲己还是甲,乙庚丙作初...
- let ganIndex = 0
- const zhiIndex = DIZHI.indexOf(zhi)
-
- switch (dayGan) {
- case '甲': case '己': ganIndex = 0; break // 甲
- case '乙': case '庚': ganIndex = 2; break // 丙
- case '丙': case '辛': ganIndex = 4; break // 戊
- case '丁': case '壬': ganIndex = 6; break // 庚
- case '戊': case '癸': ganIndex = 8; break // 壬
- }
-
- ganIndex = (ganIndex + zhiIndex) % 10
- const gan = TIANGAN[ganIndex]
-
- return {
- gan: gan,
- zhi: zhi,
- ganZhi: gan + zhi,
- wuxing: TIANGAN_WUXING[gan],
- yinyang: TIANGAN_YINYANG[gan]
- }
- }
- /**
- * 分析八字
- */
- function analyzeBaZi(bazi) {
- const wuxingCount = countWuXing(bazi)
- const qiangRuo = analyzeQiangRuo(bazi, wuxingCount)
- const yongshen = getYongShen(bazi, wuxingCount, qiangRuo)
- const personality = getPersonality(bazi)
-
- return {
- wuxingCount: wuxingCount,
- qiangRuo: qiangRuo,
- yongshen: yongshen,
- personality: personality,
- summary: generateBaziSummary(bazi, wuxingCount, qiangRuo, yongshen)
- }
- }
- /**
- * 统计五行个数
- */
- function countWuXing(bazi) {
- const count = { '金': 0, '木': 0, '水': 0, '火': 0, '土': 0 }
-
- // 统计天干
- Object.values(bazi).forEach(pillar => {
- const ganWuxing = TIANGAN_WUXING[pillar.gan]
- const zhiWuxing = DIZHI_WUXING[pillar.zhi]
- if (ganWuxing) count[ganWuxing]++
- if (zhiWuxing) count[zhiWuxing]++
- })
-
- return count
- }
- /**
- * 分析日主强弱
- */
- function analyzeQiangRuo(bazi, wuxingCount) {
- const riganWuxing = TIANGAN_WUXING[bazi.day.gan]
- const riganCount = wuxingCount[riganWuxing]
-
- // 简化分析:看日干五行在八字中的个数
- if (riganCount >= 3) {
- return { type: '身旺', description: '日主偏强,需要消耗和克制' }
- } else if (riganCount <= 1) {
- return { type: '身弱', description: '日主偏弱,需要生助和帮扶' }
- } else {
- return { type: '中和', description: '日主适中,平衡发展' }
- }
- }
- /**
- * 取用神
- */
- function getYongShen(bazi, wuxingCount, qiangRuo) {
- const riganWuxing = TIANGAN_WUXING[bazi.day.gan]
-
- if (qiangRuo.type === '身旺') {
- // 身旺用克泄耗
- const keWuxing = Object.keys(WUXING_RELATION.克).find(key => WUXING_RELATION.克[key] === riganWuxing)
- const xieWuxing = WUXING_RELATION.生[riganWuxing]
- return {
- primary: keWuxing || xieWuxing,
- description: `日主${riganWuxing}偏旺,宜用${keWuxing || xieWuxing}调候`
- }
- } else if (qiangRuo.type === '身弱') {
- // 身弱用生扶
- const shengWuxing = Object.keys(WUXING_RELATION.生).find(key => WUXING_RELATION.生[key] === riganWuxing)
- return {
- primary: shengWuxing || riganWuxing,
- description: `日主${riganWuxing}偏弱,宜用${shengWuxing || riganWuxing}生扶`
- }
- } else {
- return {
- primary: riganWuxing,
- description: `日主${riganWuxing}中和,保持平衡即可`
- }
- }
- }
- /**
- * 获取性格特征
- */
- function getPersonality(bazi) {
- const traits = []
-
- // 根据日干分析性格
- const rigan = bazi.day.gan
- switch (rigan) {
- case '甲':
- traits.push('正直', '有领导力', '创新精神')
- break
- case '乙':
- traits.push('温和', '适应力强', '善于变通')
- break
- case '丙':
- traits.push('热情', '积极向上', '善于表达')
- break
- case '丁':
- traits.push('细心', '有艺术天赋', '内心温暖')
- break
- case '戊':
- traits.push('踏实', '稳重可靠', '包容心强')
- break
- case '己':
- traits.push('务实', '善于理财', '注重细节')
- break
- case '庚':
- traits.push('果断', '意志坚强', '正义感强')
- break
- case '辛':
- traits.push('细腻', '品味高雅', '追求完美')
- break
- case '壬':
- traits.push('聪明', '适应力强', '善于沟通')
- break
- case '癸':
- traits.push('智慧', '直觉敏锐', '内心丰富')
- break
- }
-
- return traits
- }
- /**
- * 生成八字总结
- */
- function generateBaziSummary(bazi, wuxingCount, qiangRuo, yongshen) {
- const riganWuxing = TIANGAN_WUXING[bazi.day.gan]
- const maxWuxing = Object.keys(wuxingCount).reduce((a, b) => wuxingCount[a] > wuxingCount[b] ? a : b)
- const minWuxing = Object.keys(wuxingCount).reduce((a, b) => wuxingCount[a] < wuxingCount[b] ? a : b)
-
- return `您的八字为${bazi.baziString},日主${bazi.day.gan}${riganWuxing},${qiangRuo.description}。` +
- `八字中${maxWuxing}较旺,${minWuxing}较弱,${yongshen.description}。` +
- `建议在生活中多接触${yongshen.primary}属性的事物,有利于运势提升。`
- }
- /**
- * 八字配对分析
- * @param {Object} bazi1 第一个人的八字
- * @param {Object} bazi2 第二个人的八字
- * @returns {Object} 配对结果
- */
- export function analyzeBaziMatch(bazi1, bazi2) {
- // 日干配对
- const riganMatch = analyzeRiganMatch(bazi1.day.gan, bazi2.day.gan)
-
- // 五行配对
- const wuxingMatch = analyzeWuxingMatch(bazi1.riganWuxing, bazi2.riganWuxing)
-
- // 纳音配对
- const nayinMatch = analyzeNayinMatch(bazi1.birthInfo.nayin, bazi2.birthInfo.nayin)
-
- // 生肖配对
- const shengxiaoMatch = analyzeShengxiaoMatch(bazi1.birthInfo.shengxiao, bazi2.birthInfo.shengxiao)
-
- // 综合评分
- const totalScore = calculateMatchScore(riganMatch, wuxingMatch, nayinMatch, shengxiaoMatch)
-
- // 获取配对等级
- const level = getMatchLevel(totalScore)
-
- return {
- totalScore: totalScore,
- level: level.name,
- levelColor: level.color,
- riganMatch: riganMatch,
- wuxingMatch: wuxingMatch,
- nayinMatch: nayinMatch,
- shengxiaoMatch: shengxiaoMatch,
- advantages: generateMatchAdvantages(bazi1, bazi2),
- challenges: generateMatchChallenges(bazi1, bazi2),
- suggestions: generateMatchSuggestions(bazi1, bazi2, totalScore),
- summary: generateMatchSummary(bazi1, bazi2, totalScore)
- }
- }
- /**
- * 分析日干配对
- */
- function analyzeRiganMatch(gan1, gan2) {
- const wuxing1 = TIANGAN_WUXING[gan1]
- const wuxing2 = TIANGAN_WUXING[gan2]
- const yinyang1 = TIANGAN_YINYANG[gan1]
- const yinyang2 = TIANGAN_YINYANG[gan2]
-
- let score = 50
- let description = ''
-
- // 阴阳配合
- if (yinyang1 !== yinyang2) {
- score += 15
- description += '阴阳互补,'
- }
-
- // 五行关系
- if (WUXING_RELATION.生[wuxing1] === wuxing2) {
- score += 20
- description += `${gan1}生${gan2},相生和谐`
- } else if (WUXING_RELATION.生[wuxing2] === wuxing1) {
- score += 20
- description += `${gan2}生${gan1},相生和谐`
- } else if (WUXING_RELATION.克[wuxing1] === wuxing2) {
- score -= 10
- description += `${gan1}克${gan2},需要包容`
- } else if (WUXING_RELATION.克[wuxing2] === wuxing1) {
- score -= 10
- description += `${gan2}克${gan1},需要理解`
- } else if (wuxing1 === wuxing2) {
- score += 10
- description += '同气相求,志趣相投'
- } else {
- description += '五行中和,平稳发展'
- }
-
- return {
- score: Math.max(0, Math.min(100, score)),
- description: description
- }
- }
- /**
- * 分析五行配对
- */
- function analyzeWuxingMatch(wuxing1, wuxing2) {
- let score = 60
- let description = ''
-
- if (wuxing1 === wuxing2) {
- score = 75
- description = `同属${wuxing1},价值观相近,容易理解对方`
- } else if (WUXING_RELATION.生[wuxing1] === wuxing2 || WUXING_RELATION.生[wuxing2] === wuxing1) {
- score = 85
- description = `${wuxing1}与${wuxing2}相生,互相促进,相得益彰`
- } else if (WUXING_RELATION.克[wuxing1] === wuxing2 || WUXING_RELATION.克[wuxing2] === wuxing1) {
- score = 40
- description = `${wuxing1}与${wuxing2}相克,需要更多理解和包容`
- } else {
- score = 65
- description = `${wuxing1}与${wuxing2}中性关系,互补性较好`
- }
-
- return {
- score: score,
- description: description
- }
- }
- /**
- * 分析纳音配对
- */
- function analyzeNayinMatch(nayin1, nayin2) {
- // 简化的纳音配对逻辑
- let score = 60
- let description = ''
-
- if (nayin1 === nayin2) {
- score = 70
- description = `同为${nayin1},命理相同,默契度高`
- } else {
- // 根据纳音五行分析
- const nayin1Wuxing = getNayinWuxing(nayin1)
- const nayin2Wuxing = getNayinWuxing(nayin2)
-
- if (nayin1Wuxing && nayin2Wuxing) {
- if (WUXING_RELATION.生[nayin1Wuxing] === nayin2Wuxing || WUXING_RELATION.生[nayin2Wuxing] === nayin1Wuxing) {
- score = 80
- description = `${nayin1}与${nayin2}纳音相生,天作之合`
- } else if (WUXING_RELATION.克[nayin1Wuxing] === nayin2Wuxing || WUXING_RELATION.克[nayin2Wuxing] === nayin1Wuxing) {
- score = 45
- description = `${nayin1}与${nayin2}纳音相克,需要调和`
- } else {
- score = 65
- description = `${nayin1}与${nayin2}纳音和谐,关系稳定`
- }
- } else {
- description = `${nayin1}与${nayin2},命理互补`
- }
- }
-
- return {
- score: score,
- description: description
- }
- }
- /**
- * 获取纳音五行
- */
- function getNayinWuxing(nayin) {
- if (nayin.includes('金')) return '金'
- if (nayin.includes('木')) return '木'
- if (nayin.includes('水')) return '水'
- if (nayin.includes('火')) return '火'
- if (nayin.includes('土')) return '土'
- return null
- }
- /**
- * 分析生肖配对
- */
- function analyzeShengxiaoMatch(shengxiao1, shengxiao2) {
- // 生肖配对表
- const shengxiaoCompatibility = {
- '鼠': { '龙': 90, '猴': 85, '牛': 80, '马': 30, '羊': 40 },
- '牛': { '蛇': 90, '鸡': 85, '鼠': 80, '马': 35, '羊': 30 },
- '虎': { '马': 90, '狗': 85, '猪': 80, '猴': 30, '蛇': 35 },
- '兔': { '羊': 90, '猪': 85, '狗': 80, '鸡': 30, '龙': 35 },
- '龙': { '鼠': 90, '猴': 85, '鸡': 80, '狗': 30, '兔': 35 },
- '蛇': { '牛': 90, '鸡': 85, '猴': 80, '猪': 30, '虎': 35 },
- '马': { '虎': 90, '狗': 85, '羊': 80, '鼠': 30, '牛': 35 },
- '羊': { '兔': 90, '马': 80, '猪': 85, '牛': 30, '鼠': 40 },
- '猴': { '鼠': 85, '龙': 85, '蛇': 80, '虎': 30, '猪': 35 },
- '鸡': { '牛': 85, '蛇': 85, '龙': 80, '兔': 30, '狗': 35 },
- '狗': { '虎': 85, '马': 85, '兔': 80, '龙': 30, '鸡': 35 },
- '猪': { '兔': 85, '羊': 85, '虎': 80, '蛇': 30, '猴': 35 }
- }
-
- let score = 60
- let description = ''
-
- if (shengxiao1 === shengxiao2) {
- score = 70
- description = `同属${shengxiao1},性格相似,容易产生共鸣`
- } else if (shengxiaoCompatibility[shengxiao1] && shengxiaoCompatibility[shengxiao1][shengxiao2]) {
- score = shengxiaoCompatibility[shengxiao1][shengxiao2]
- if (score >= 85) {
- description = `${shengxiao1}与${shengxiao2}是最佳配对,天生一对`
- } else if (score >= 70) {
- description = `${shengxiao1}与${shengxiao2}配对良好,相处融洽`
- } else {
- description = `${shengxiao1}与${shengxiao2}需要更多磨合,相互理解`
- }
- } else {
- description = `${shengxiao1}与${shengxiao2}属于中性配对,平稳发展`
- }
-
- return {
- score: score,
- description: description
- }
- }
- /**
- * 计算总体配对分数
- */
- function calculateMatchScore(riganMatch, wuxingMatch, nayinMatch, shengxiaoMatch) {
- // 加权计算
- const weights = {
- rigan: 0.3, // 日干权重30%
- wuxing: 0.3, // 五行权重30%
- nayin: 0.2, // 纳音权重20%
- shengxiao: 0.2 // 生肖权重20%
- }
-
- const totalScore =
- riganMatch.score * weights.rigan +
- wuxingMatch.score * weights.wuxing +
- nayinMatch.score * weights.nayin +
- shengxiaoMatch.score * weights.shengxiao
-
- return Math.round(totalScore)
- }
- /**
- * 获取配对等级
- */
- function getMatchLevel(score) {
- if (score >= 90) {
- return { name: '天作之合', color: 'linear-gradient(135deg, #FF6B9D 0%, #FFA5C6 100%)' }
- } else if (score >= 80) {
- return { name: '绝配佳偶', color: 'linear-gradient(135deg, #4CAF50 0%, #81C784 100%)' }
- } else if (score >= 70) {
- return { name: '良缘美眷', color: 'linear-gradient(135deg, #2196F3 0%, #64B5F6 100%)' }
- } else if (score >= 60) {
- return { name: '尚可之配', color: 'linear-gradient(135deg, #FF9800 0%, #FFB74D 100%)' }
- } else if (score >= 50) {
- return { name: '需要磨合', color: 'linear-gradient(135deg, #FFC107 0%, #FFD54F 100%)' }
- } else {
- return { name: '挑战较大', color: 'linear-gradient(135deg, #F44336 0%, #EF5350 100%)' }
- }
- }
- /**
- * 生成配对优势
- */
- function generateMatchAdvantages(bazi1, bazi2) {
- const advantages = []
-
- // 分析共同特点
- const commonTraits = bazi1.analysis.personality.filter(trait =>
- bazi2.analysis.personality.includes(trait)
- )
-
- if (commonTraits.length > 0) {
- advantages.push(`你们都具有${commonTraits.join('、')}的特质,容易产生共鸣和理解`)
- }
-
- // 分析互补特点
- if (bazi1.analysis.qiangRuo.type === '身旺' && bazi2.analysis.qiangRuo.type === '身弱') {
- advantages.push('一强一弱的组合,能够互相补充,形成良好的平衡')
- } else if (bazi1.analysis.qiangRuo.type === '身弱' && bazi2.analysis.qiangRuo.type === '身旺') {
- advantages.push('强弱互补的搭配,能够相互扶持,共同成长')
- }
-
- // 分析用神关系
- if (bazi1.analysis.yongshen.primary === bazi2.riganWuxing) {
- advantages.push('对方的日主五行正好是您的用神,能够给您带来很好的帮助')
- }
-
- return advantages.length > 0 ? advantages : ['你们的八字搭配有其独特的魅力,能够在相处中发现彼此的闪光点']
- }
- /**
- * 生成配对挑战
- */
- function generateMatchChallenges(bazi1, bazi2) {
- const challenges = []
-
- // 分析冲突
- if (bazi1.riganWuxing && bazi2.riganWuxing &&
- WUXING_RELATION.克[bazi1.riganWuxing] === bazi2.riganWuxing) {
- challenges.push('日主五行相克,在性格和处事方式上可能存在一些分歧')
- }
-
- // 分析过旺或过弱
- if (bazi1.analysis.qiangRuo.type === '身旺' && bazi2.analysis.qiangRuo.type === '身旺') {
- challenges.push('双方都比较强势,在决策时可能需要更多的沟通和协调')
- } else if (bazi1.analysis.qiangRuo.type === '身弱' && bazi2.analysis.qiangRuo.type === '身弱') {
- challenges.push('双方都比较内敛,需要主动创造更多的交流机会')
- }
-
- return challenges.length > 0 ? challenges : ['每一对组合都有需要磨合的地方,这正是相处的乐趣所在']
- }
- /**
- * 生成配对建议
- */
- function generateMatchSuggestions(bazi1, bazi2, totalScore) {
- const suggestions = []
-
- if (totalScore >= 80) {
- suggestions.push('你们的八字配对很好,珍惜这份缘分,相互支持共同成长')
- } else if (totalScore >= 60) {
- suggestions.push('你们的配对有很好的基础,多一些包容和理解,感情会更加稳定')
- } else {
- suggestions.push('缘分需要用心经营,多沟通多理解,用爱化解所有的不合')
- }
-
- // 根据用神给建议
- if (bazi1.analysis.yongshen.primary && bazi2.analysis.yongshen.primary) {
- const commonYongshen = bazi1.analysis.yongshen.primary === bazi2.analysis.yongshen.primary
- if (commonYongshen) {
- suggestions.push(`你们的用神都是${bazi1.analysis.yongshen.primary},可以一起从事相关的活动来增进感情`)
- }
- }
-
- suggestions.push('建议选择有利于双方用神的环境和时间进行重要的决策和沟通')
-
- return suggestions
- }
- /**
- * 生成配对总结
- */
- function generateMatchSummary(bazi1, bazi2, totalScore) {
- const level = getMatchLevel(totalScore)
- const summary = `您的八字${bazi1.baziString}与对方的八字${bazi2.baziString},` +
- `综合评分${totalScore}分,属于"${level.name}"的配对等级。`
-
- if (totalScore >= 80) {
- return summary + '你们的八字搭配很好,是难得的良缘,要好好珍惜。'
- } else if (totalScore >= 60) {
- return summary + '你们有着不错的缘分基础,通过相互理解和包容,能够建立美好的关系。'
- } else {
- return summary + '虽然八字配对有些挑战,但真爱能够化解一切,只要相互理解,同样能够获得幸福。'
- }
- }
- /**
- * 智能API选择器 - 根据策略选择最佳API
- * @returns {Object} 选中的API配置
- */
- function selectBestAPI() {
- const settings = BAZI_API_CONFIG.SETTINGS
- const enabledAPIs = settings.ENABLED_APIS
-
- // 按优先级排序可用的API
- const sortedAPIs = enabledAPIs
- .map(apiName => ({
- name: apiName,
- config: BAZI_API_CONFIG[apiName],
- isConfigured: BAZI_API_CONFIG[apiName].API_KEY &&
- !BAZI_API_CONFIG[apiName].API_KEY.startsWith('YOUR_')
- }))
- .filter(api => api.isConfigured)
- .sort((a, b) => a.config.PRIORITY - b.config.PRIORITY)
-
- if (sortedAPIs.length === 0) {
- console.log('⚠️ 没有已配置的API,使用本地算法')
- return null
- }
-
- // 根据策略选择API
- switch (settings.STRATEGY) {
- case 'cost_first':
- return sortedAPIs.sort((a, b) => a.config.COST_PER_CALL - b.config.COST_PER_CALL)[0]
- case 'accuracy_first':
- return sortedAPIs[0] // 优先级最高的通常最准确
- case 'speed_first':
- return sortedAPIs.find(api => api.name === 'ALIYUN_API') || sortedAPIs[0]
- default:
- return sortedAPIs[0]
- }
- }
- /**
- * 调用专业八字API获取准确数据(支持多API自动切换)
- * @param {Date} birthDate 出生日期
- * @param {Number} hour 出生时辰(0-23)
- * @returns {Promise<Object>} API返回结果
- */
- export async function getBaziFromAPI(birthDate, hour) {
- const settings = BAZI_API_CONFIG.SETTINGS
- const maxRetries = settings.RETRY_COUNT || 2
-
- for (let attempt = 0; attempt < maxRetries + 1; attempt++) {
- try {
- console.log(`🔍 尝试调用专业八字API (第${attempt + 1}次)`)
- console.log('出生时间:', birthDate, '时辰:', hour)
-
- // 智能选择API
- const selectedAPI = selectBestAPI()
- if (!selectedAPI) {
- console.log('⚠️ 没有可用的专业API,使用本地算法')
- return null
- }
-
- console.log(`📡 选中API: ${selectedAPI.name}`, selectedAPI.config.DESCRIPTION)
-
- const result = await callSpecificAPI(selectedAPI, birthDate, hour)
- if (result) {
- console.log(`✅ ${selectedAPI.name} 调用成功`)
- return {
- ...result,
- apiProvider: selectedAPI.name,
- apiCost: selectedAPI.config.COST_PER_CALL
- }
- }
-
- // 如果启用自动故障转移,尝试下一个API
- if (settings.AUTO_FAILOVER && attempt < maxRetries) {
- console.log(`⚠️ ${selectedAPI.name} 调用失败,尝试故障转移`)
- // 临时禁用当前API,下次循环会选择下一个
- const index = settings.ENABLED_APIS.indexOf(selectedAPI.name)
- if (index > -1) {
- settings.ENABLED_APIS.splice(index, 1)
- }
- continue
- }
-
- } catch (error) {
- console.error(`❌ API调用异常 (尝试${attempt + 1}):`, error)
- if (attempt === maxRetries) {
- console.log('🔄 所有API均失败,降级到本地算法')
- return null
- }
- }
- }
-
- return null
- }
- /**
- * 调用特定的API服务
- * @param {Object} selectedAPI 选中的API配置
- * @param {Date} birthDate 出生日期
- * @param {Number} hour 出生时辰
- * @returns {Promise<Object>} API返回结果
- */
- async function callSpecificAPI(selectedAPI, birthDate, hour) {
- const { name, config } = selectedAPI
-
- // 根据不同API构建请求参数
- let params, url
-
- switch (name) {
- case 'JISU_API':
- params = {
- appkey: config.API_KEY,
- name: '用户', // 姓名参数(必填)
- city: '', // 城市参数(必填,可空)
- year: birthDate.getFullYear(),
- month: birthDate.getMonth() + 1,
- day: birthDate.getDate(),
- hour: hour,
- minute: 0, // 分钟,默认0
- sex: 1, // 性别,1男0女,默认男
- islunar: 0, // 是否阴历,0阳历1阴历
- istaiyang: 0, // 是否太阳时,0不使用1使用
- islunarmonth: 2 // 是否闰月,1是2否
- }
- url = `${config.BASE_URL}${config.ENDPOINTS.bazi}`
- break
-
- case 'JUHE_API':
- params = {
- key: config.API_KEY,
- year: birthDate.getFullYear(),
- month: birthDate.getMonth() + 1,
- day: birthDate.getDate(),
- hour: hour
- }
- url = `${config.BASE_URL}${config.ENDPOINTS.bazi}`
- break
-
- case 'ALIYUN_API':
- params = {
- year: birthDate.getFullYear(),
- month: birthDate.getMonth() + 1,
- day: birthDate.getDate(),
- hour: hour
- }
- url = `${config.BASE_URL}${config.ENDPOINTS.bazi}`
- break
-
- case 'TENCENT_API':
- params = {
- year: birthDate.getFullYear(),
- month: birthDate.getMonth() + 1,
- day: birthDate.getDate(),
- hour: hour
- }
- url = `${config.BASE_URL}${config.ENDPOINTS.bazi}`
- break
-
- default:
- console.error('❌ 不支持的API类型:', name)
- return null
- }
-
- console.log('📡 API请求地址:', url)
- console.log('📡 请求参数:', {
- ...params,
- [name === 'JISU_API' ? 'appkey' : 'key']: params.appkey || params.key ?
- `${(params.appkey || params.key).slice(0, 8)}...` : '未设置'
- })
-
- // 发送请求
- const response = await new Promise((resolve, reject) => {
- const headers = {}
-
- // 阿里云和腾讯云需要特殊的认证头
- if (name === 'ALIYUN_API') {
- headers['Authorization'] = `APPCODE ${config.API_KEY}`
- } else if (name === 'TENCENT_API') {
- headers['Authorization'] = config.API_KEY
- }
-
- uni.request({
- url: url,
- data: params,
- method: 'GET',
- header: headers,
- timeout: BAZI_API_CONFIG.SETTINGS.TIMEOUT || 10000,
- success: (res) => {
- console.log('📡 API响应状态:', res.statusCode)
- console.log('📡 API响应数据:', res.data)
- resolve(res)
- },
- fail: (err) => {
- console.error('📡 API请求失败:', err)
- reject(err)
- }
- })
- })
-
- // 解析不同API的响应格式
- return parseAPIResponse(name, response)
- }
- /**
- * 解析不同API的响应格式
- * @param {String} apiName API名称
- * @param {Object} response 响应对象
- * @returns {Object} 标准化的八字数据
- */
- function parseAPIResponse(apiName, response) {
- if (response.statusCode !== 200) {
- throw new Error(`HTTP ${response.statusCode}`)
- }
-
- const data = response.data
- let result = null
-
- switch (apiName) {
- case 'JISU_API':
- if (data.status === 0 && data.result) {
- result = data.result
- // 极速数据API返回的是完整的八字排盘数据
- console.log('✅ 极速数据返回完整八字排盘信息')
- }
- break
-
- case 'JUHE_API':
- if (data.error_code === 0 && data.result) {
- result = data.result
- }
- break
-
- case 'ALIYUN_API':
- case 'TENCENT_API':
- if (data.code === 200 && data.data) {
- result = data.data
- }
- break
- }
-
- if (!result) {
- console.log('⚠️ API返回数据格式异常')
- return null
- }
-
- // 极速数据API专用解析(更丰富的数据)
- if (apiName === 'JISU_API' && result.bazi) {
- // 解析八字数组 [年柱, 月柱, 日柱, 时柱]
- const baziArray = result.bazi
- const nayinArray = result.nayin || []
-
- return {
- year: {
- gan: baziArray[0]?.charAt(0) || '',
- zhi: baziArray[0]?.charAt(1) || '',
- ganZhi: baziArray[0] || '',
- nayin: nayinArray[0] || ''
- },
- month: {
- gan: baziArray[1]?.charAt(0) || '',
- zhi: baziArray[1]?.charAt(1) || '',
- ganZhi: baziArray[1] || '',
- nayin: nayinArray[1] || ''
- },
- day: {
- gan: baziArray[2]?.charAt(0) || '',
- zhi: baziArray[2]?.charAt(1) || '',
- ganZhi: baziArray[2] || '',
- nayin: nayinArray[2] || ''
- },
- hour: {
- gan: baziArray[3]?.charAt(0) || '',
- zhi: baziArray[3]?.charAt(1) || '',
- ganZhi: baziArray[3] || '',
- nayin: nayinArray[3] || ''
- },
- baziString: baziArray.join(' '),
-
- // 极速数据提供的专业信息
- animal: result.animal, // 生肖
- yearganzhi: result.yearganzhi, // 年干支
- taiyuan: result.taiyuan, // 胎元
- minggong: result.minggong, // 命宫
- xunkong: result.xunkong, // 旬空
- qiyun: result.qiyun, // 起运时间
- jiaoyun: result.jiaoyun, // 交运时间
- qiankunzao: result.qiankunzao, // 乾造/坤造
- shensha: result.shensha, // 神煞
- dayun: result.dayun, // 大运
- liunian: result.liunian, // 流年
-
- // 农历信息
- lunar: {
- year: result.lunaryear,
- month: result.lunarmonth,
- day: result.lunarday,
- hour: result.lunarhour
- },
-
- // 节气信息
- jieqi: {
- prev: result.jieqiprev,
- next: result.jieqinext
- },
-
- source: 'api',
- apiProvider: 'jisuapi',
- apiData: result
- }
- }
-
- // 通用API数据格式(其他API使用)
- return {
- year: {
- gan: result.year_gan || result.yearGan,
- zhi: result.year_zhi || result.yearZhi,
- ganZhi: (result.year_gan || result.yearGan) + (result.year_zhi || result.yearZhi),
- wuxing: result.year_wuxing || result.yearWuxing,
- yinyang: result.year_yinyang || result.yearYinyang
- },
- month: {
- gan: result.month_gan || result.monthGan,
- zhi: result.month_zhi || result.monthZhi,
- ganZhi: (result.month_gan || result.monthGan) + (result.month_zhi || result.monthZhi),
- wuxing: result.month_wuxing || result.monthWuxing,
- yinyang: result.month_yinyang || result.monthYinyang
- },
- day: {
- gan: result.day_gan || result.dayGan,
- zhi: result.day_zhi || result.dayZhi,
- ganZhi: (result.day_gan || result.dayGan) + (result.day_zhi || result.dayZhi),
- wuxing: result.day_wuxing || result.dayWuxing,
- yinyang: result.day_yinyang || result.dayYinyang
- },
- hour: {
- gan: result.hour_gan || result.hourGan,
- zhi: result.hour_zhi || result.hourZhi,
- ganZhi: (result.hour_gan || result.hourGan) + (result.hour_zhi || result.hourZhi),
- wuxing: result.hour_wuxing || result.hourWuxing,
- yinyang: result.hour_yinyang || result.hourYinyang
- },
- baziString: `${result.year_gan || result.yearGan}${result.year_zhi || result.yearZhi} ${result.month_gan || result.monthGan}${result.month_zhi || result.monthZhi} ${result.day_gan || result.dayGan}${result.day_zhi || result.dayZhi} ${result.hour_gan || result.hourGan}${result.hour_zhi || result.hourZhi}`,
- nayin: result.nayin || '',
- source: 'api',
- apiData: result
- }
- }
- /**
- * 增强版八字计算(API + 本地算法)
- * @param {Date} birthDate 出生日期
- * @param {Number} hour 出生时辰(0-23)
- * @returns {Object} 八字信息
- */
- export async function calculateEnhancedBaZi(birthDate, hour) {
- let localResult = null
- let apiResult = null
-
- try {
- // 1. 先计算本地结果
- localResult = calculateBaZi(birthDate, hour)
- console.log('✅ 本地八字计算完成')
-
- // 2. 尝试获取API结果
- if (BAZI_API_CONFIG.SETTINGS.ENABLE_VALIDATION) {
- apiResult = await getBaziFromAPI(birthDate, hour)
- }
-
- // 3. 结果对比和融合
- if (apiResult) {
- console.log('🔍 开始对比API与本地算法结果')
-
- const comparison = compareBaziResults(localResult, apiResult)
-
- if (comparison.accuracy >= 0.8) {
- console.log('✅ 本地算法准确度高,使用本地结果')
- localResult.validation = {
- status: 'verified',
- accuracy: comparison.accuracy,
- apiSource: 'professional',
- differences: comparison.differences
- }
- } else {
- console.log('⚠️ 发现差异,使用API结果并标记')
- const enhancedResult = mergeApiAndLocalResults(apiResult, localResult)
- enhancedResult.validation = {
- status: 'api_corrected',
- accuracy: comparison.accuracy,
- apiSource: 'professional',
- differences: comparison.differences
- }
- return enhancedResult
- }
- } else {
- localResult.validation = {
- status: 'local_only',
- accuracy: 0.85, // 本地算法估计准确度
- apiSource: 'none',
- note: '建议配置专业API以提高准确度'
- }
- }
-
- return localResult
-
- } catch (error) {
- console.error('❌ 增强版八字计算异常:', error)
- return localResult || calculateBaZi(birthDate, hour)
- }
- }
- /**
- * 对比八字计算结果
- * @param {Object} localResult 本地算法结果
- * @param {Object} apiResult API算法结果
- * @returns {Object} 对比结果
- */
- function compareBaziResults(localResult, apiResult) {
- const differences = []
- let correctCount = 0
- let totalCount = 8 // 四柱共8个字
-
- // 对比四柱
- const pillars = ['year', 'month', 'day', 'hour']
- pillars.forEach(pillar => {
- if (localResult[pillar].gan === apiResult[pillar].gan) {
- correctCount++
- } else {
- differences.push(`${pillar}干: 本地${localResult[pillar].gan} vs API${apiResult[pillar].gan}`)
- }
-
- if (localResult[pillar].zhi === apiResult[pillar].zhi) {
- correctCount++
- } else {
- differences.push(`${pillar}支: 本地${localResult[pillar].zhi} vs API${apiResult[pillar].zhi}`)
- }
- })
-
- const accuracy = correctCount / totalCount
-
- return {
- accuracy: accuracy,
- differences: differences,
- recommendation: accuracy >= 0.8 ? 'use_local' : 'use_api'
- }
- }
- /**
- * 融合API和本地结果
- * @param {Object} apiResult API结果
- * @param {Object} localResult 本地结果
- * @returns {Object} 融合后的结果
- */
- function mergeApiAndLocalResults(apiResult, localResult) {
- // 以API结果为准,但保留本地的详细分析
- return {
- ...apiResult,
- // 保留本地的详细分析
- analysis: localResult.analysis,
- birthInfo: {
- ...localResult.birthInfo,
- // 如果API提供了纳音,使用API的
- nayin: apiResult.nayin || localResult.birthInfo.nayin
- },
- // 标记数据来源
- dataSource: 'api_enhanced',
- localCalculation: localResult.baziString,
- apiCalculation: apiResult.baziString
- }
- }
- /**
- * 获取八字建议
- */
- export function getBaziSuggestions(bazi) {
- const suggestions = []
-
- // 根据验证状态添加可靠性说明
- if (bazi.validation) {
- if (bazi.validation.status === 'verified') {
- suggestions.push(`✅ 您的八字经过专业API验证,准确度${Math.round(bazi.validation.accuracy * 100)}%,结果可信度高`)
- } else if (bazi.validation.status === 'api_corrected') {
- suggestions.push(`🔍 已使用专业算法修正结果,确保测算准确性`)
- } else {
- suggestions.push(`💡 建议配置专业八字API以获得更准确的测算结果`)
- }
- }
-
- // 根据用神给建议
- const yongshen = bazi.analysis.yongshen.primary
- suggestions.push(`您的用神为${yongshen},建议多接触${yongshen}属性的事物,如颜色、方位、职业等`)
-
- // 根据强弱给建议
- if (bazi.analysis.qiangRuo.type === '身旺') {
- suggestions.push('您的日主偏强,适合发挥领导才能,但要注意不要过于强势')
- } else if (bazi.analysis.qiangRuo.type === '身弱') {
- suggestions.push('您的日主偏弱,需要多寻求他人的帮助和支持,团队合作会更有利')
- } else {
- suggestions.push('您的日主平衡,适合稳步发展,保持现有的良好状态')
- }
-
- return suggestions
- }
- // 导出默认对象
- export default {
- calculateBaZi,
- calculateEnhancedBaZi, // 新增:增强版八字计算
- getBaziFromAPI, // 新增:专业API调用
- analyzeBaziMatch,
- getBaziSuggestions,
- TIANGAN,
- DIZHI,
- TIANGAN_WUXING,
- DIZHI_WUXING,
- SHENGXIAO
- }
|