/** * 八字计算工具类 * 基于传统命理学理论实现八字计算、分析和配对功能 * 支持专业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) { 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} 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 { // 智能选择API const selectedAPI = selectBestAPI() if (!selectedAPI) { return null } const result = await callSpecificAPI(selectedAPI, birthDate, hour) if (result) { return { ...result, apiProvider: selectedAPI.name, apiCost: selectedAPI.config.COST_PER_CALL } } // 如果启用自动故障转移,尝试下一个API if (settings.AUTO_FAILOVER && attempt < maxRetries) { 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) { return null } } } return null } /** * 调用特定的API服务 * @param {Object} selectedAPI 选中的API配置 * @param {Date} birthDate 出生日期 * @param {Number} hour 出生时辰 * @returns {Promise} 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 } // 发送请求 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) => { 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返回的是完整的八字排盘数据 } 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) { 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) // 2. 尝试获取API结果 if (BAZI_API_CONFIG.SETTINGS.ENABLE_VALIDATION) { apiResult = await getBaziFromAPI(birthDate, hour) } // 3. 结果对比和融合 if (apiResult) { const comparison = compareBaziResults(localResult, apiResult) if (comparison.accuracy >= 0.8) { localResult.validation = { status: 'verified', accuracy: comparison.accuracy, apiSource: 'professional', differences: comparison.differences } } else { 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 }