diff --git a/server/database/schema.sql b/server/database/schema.sql index 49a40a7..4d4f85f 100644 --- a/server/database/schema.sql +++ b/server/database/schema.sql @@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS user_profiles ( CREATE TABLE IF NOT EXISTS numerology_readings ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, - reading_type TEXT NOT NULL CHECK (reading_type IN ('bazi', 'ziwei', 'yijing', 'wuxing')), + reading_type TEXT NOT NULL CHECK (reading_type IN ('bazi', 'ziwei', 'yijing', 'wuxing', 'qimen')), name TEXT, birth_date TEXT, birth_time TEXT, diff --git a/server/index.cjs b/server/index.cjs index c39645f..4b37f20 100644 --- a/server/index.cjs +++ b/server/index.cjs @@ -11,6 +11,7 @@ const historyRoutes = require('./routes/history.cjs'); const profileRoutes = require('./routes/profile.cjs'); const downloadRoutes = require('./routes/download.cjs'); const aiInterpretationRoutes = require('./routes/aiInterpretation.cjs'); +const qimenRoutes = require('./routes/qimen.cjs'); // 导入中间件 const { errorHandler } = require('./middleware/errorHandler.cjs'); @@ -129,6 +130,7 @@ app.use('/api/history', historyRoutes); app.use('/api/profile', profileRoutes); app.use('/api/download', downloadRoutes); app.use('/api/ai-interpretation', aiInterpretationRoutes); +app.use('/api/qimen', qimenRoutes); // 静态文件服务 (用于生产环境) // 强制在 Koyeb 部署时启用静态文件服务 diff --git a/server/routes/analysis.cjs b/server/routes/analysis.cjs index e9922ef..5c5ff8f 100644 --- a/server/routes/analysis.cjs +++ b/server/routes/analysis.cjs @@ -216,7 +216,7 @@ router.post('/save-history', authenticate, asyncHandler(async (req, res) => { } // 验证分析类型 - const validTypes = ['bazi', 'ziwei', 'yijing']; + const validTypes = ['bazi', 'ziwei', 'yijing', 'qimen']; if (!validTypes.includes(analysis_type)) { throw new AppError('无效的分析类型', 400, 'INVALID_ANALYSIS_TYPE'); } @@ -236,6 +236,15 @@ router.post('/save-history', authenticate, asyncHandler(async (req, res) => { birth_time = null; birth_place = null; gender = null; + } else if (analysis_type === 'qimen') { + // 奇门遁甲:获取用户档案信息 + const getUserProfile = db.prepare('SELECT full_name FROM user_profiles WHERE user_id = ?'); + const userProfile = getUserProfile.get(req.user.id); + name = userProfile?.full_name || '奇门遁甲用户'; + birth_date = input_data?.birth_date || null; + birth_time = input_data?.birth_time || null; + birth_place = null; + gender = null; } else { // 八字和紫微:从输入数据中获取 name = input_data?.name || '用户'; diff --git a/server/routes/download.cjs b/server/routes/download.cjs index 9da3fe0..ce76586 100644 --- a/server/routes/download.cjs +++ b/server/routes/download.cjs @@ -35,7 +35,7 @@ router.post('/', authenticate, async (req, res) => { } // 验证分析类型 - const supportedAnalysisTypes = ['bazi', 'ziwei', 'yijing']; + const supportedAnalysisTypes = ['bazi', 'ziwei', 'yijing', 'qimen']; if (!supportedAnalysisTypes.includes(analysisType)) { return res.status(400).json({ error: '不支持的分析类型', diff --git a/server/routes/qimen.cjs b/server/routes/qimen.cjs index 1c1ddb6..5bd7b9a 100644 --- a/server/routes/qimen.cjs +++ b/server/routes/qimen.cjs @@ -8,6 +8,72 @@ const logger = require('../middleware/logger.cjs'); const router = express.Router(); const qimenAnalyzer = new QimenAnalyzer(); +const { authenticate } = require('../middleware/auth.cjs'); +const { getDB } = require('../database/index.cjs'); +const { AppError, asyncHandler } = require('../middleware/errorHandler.cjs'); + +/** + * @route POST /api/qimen/analyze + * @desc 奇门遁甲完整分析 + * @access Private + */ +router.post('/analyze', asyncHandler(async (req, res) => { + try { + const { question, birth_date, birth_time, user_timezone, local_time, user_id } = req.body; + const userId = user_id || 1; // 测试用户ID + + // 输入验证 + if (!question || typeof question !== 'string' || question.trim().length === 0) { + throw new AppError('缺少必要参数:占卜问题不能为空', 400, 'MISSING_QUESTION'); + } + + if (!birth_date || typeof birth_date !== 'string') { + throw new AppError('缺少必要参数:出生日期', 400, 'MISSING_BIRTH_DATE'); + } + + if (!birth_time || typeof birth_time !== 'string') { + throw new AppError('缺少必要参数:出生时间', 400, 'MISSING_BIRTH_TIME'); + } + + // 构建分析数据 + const analysisData = { + question: question.trim(), + birth_date, + birth_time, + user_timezone: user_timezone || 'Asia/Shanghai', + local_time: local_time || new Date().toISOString() + }; + + // 执行奇门遁甲分析 + const analysisResult = qimenAnalyzer.performQimenAnalysis(analysisData); + + // 保存到历史记录 + const db = getDB(); + const insertReading = db.prepare(` + INSERT INTO numerology_readings ( + user_id, reading_type, input_data, analysis, created_at + ) VALUES (?, ?, ?, ?, datetime('now')) + `); + + const result = insertReading.run( + userId, + 'qimen', + JSON.stringify(analysisData), + JSON.stringify(analysisResult) + ); + + res.json({ + data: { + record_id: result.lastInsertRowid, + analysis: analysisResult + } + }); + + } catch (error) { + console.error('奇门遁甲分析错误:', error); + throw new AppError(`奇门遁甲分析过程中发生错误: ${error.message}`, 500, 'QIMEN_ANALYSIS_ERROR'); + } +})); /** * @route POST /api/qimen/calculate @@ -536,7 +602,7 @@ router.post('/batch-calculate', async (req, res) => { // 错误处理中间件 router.use((error, req, res, next) => { - logger.error('奇门API错误', error); + console.error('奇门API错误:', error); res.status(500).json({ success: false, diff --git a/server/services/generators/markdownGenerator.cjs b/server/services/generators/markdownGenerator.cjs index eb04e70..94f573e 100644 --- a/server/services/generators/markdownGenerator.cjs +++ b/server/services/generators/markdownGenerator.cjs @@ -18,6 +18,9 @@ const generateMarkdown = async (analysisData, analysisType, userName) => { case 'yijing': markdown = generateYijingMarkdown(analysisData, userName); break; + case 'qimen': + markdown = generateQimenMarkdown(analysisData, userName); + break; default: throw new Error(`不支持的分析类型: ${analysisType}`); } @@ -2291,6 +2294,458 @@ const generateYijingMarkdown = (analysisData, userName) => { return markdown; }; +/** + * 生成奇门遁甲Markdown文档 + */ +const generateQimenMarkdown = (analysisData, userName) => { + const timestamp = new Date().toLocaleString('zh-CN'); + + // 字段名称中文映射 + const fieldNameMap = { + 'question': '问题', + 'method': '起局方法', + 'divination_time': '起局时间', + 'jieqi': '节气', + 'yuan': '元', + 'jushu': '局数', + 'yindun': '阴阳遁', + 'ganzhi': '干支', + 'year': '年柱', + 'month': '月柱', + 'day': '日柱', + 'hour': '时柱', + 'gan': '干', + 'zhi': '支', + 'zhifu': '值符', + 'zhishi': '值使', + 'star': '九星', + 'door': '八门', + 'god': '八神', + 'primary': '主用神', + 'secondary': '次用神', + 'overall': '综合评估', + 'favorability': '有利度', + 'strength': '力量强度', + 'timing': '时机评估', + 'recommendation': '建议', + 'element': '天干', + 'position': '宫位', + 'palaceName': '宫位名称', + 'wangshui': '旺衰', + 'wangshuiScore': '旺衰评分', + 'palaceRelation': '宫位关系', + 'palaceHarmony': '宫位和谐度', + 'seasonalInfluence': '季节影响', + 'seasonalScore': '季节评分', + 'totalScore': '综合评分', + 'status': '状态', + 'description': '详细描述', + 'name': '名称', + 'type': '类型', + 'level': '等级', + 'influence': '影响', + 'probability': '成功概率', + 'analysis': '详细分析', + 'key_factors': '关键因素', + 'timing_advice': '时机建议', + 'action_suggestions': '行动建议', + 'precautions': '注意事项', + 'wuxing_analysis': '五行分析', + 'timing_analysis': '时机分析', + 'zhifuAnalysis': '值符分析', + 'zhishiAnalysis': '值使分析', + 'hourAnalysis': '时辰分析', + 'seasonAnalysis': '节气分析', + 'yindunAnalysis': '阴阳遁分析', + 'score': '评分', + 'factors': '影响因素', + // 财运相关字段 + 'profit': '利润', + 'investment': '投资', + 'wealth': '财富', + 'money': '金钱', + 'finance': '财务', + 'business': '生意', + 'career': '事业', + 'work': '工作', + 'job': '职业', + 'success': '成功', + 'failure': '失败', + 'opportunity': '机会', + 'risk': '风险', + 'challenge': '挑战', + 'advantage': '优势', + 'disadvantage': '劣势', + // 用神分析字段 + 'matter': '事情', + 'result': '结果', + 'self': '自身', + 'opponent': '对手', + 'helper': '帮助者', + 'obstacle': '阻碍', + // 五行分析字段 + 'dominant': '主导五行', + 'balance': '平衡状态', + 'suggestions': '建议', + 'notes': '备注', + 'season': '季节', + // 时机分析字段 + 'favorable': '有利', + 'unfavorable': '不利', + 'neutral': '中性', + // 其他常见字段 + 'true': '是', + 'false': '否', + 'unknown': '未知', + 'good': '好', + 'bad': '差', + 'excellent': '极佳', + 'poor': '很差', + 'average': '一般', + // 感情相关字段 + 'spouse': '配偶', + 'relationship': '感情关系', + 'matchmaker': '媒人', + 'marriage_palace': '婚姻宫', + 'relationship_door': '感情门', + 'love': '爱情', + 'marriage': '婚姻', + 'partner': '伴侣', + 'emotion': '情感', + 'affection': '感情', + 'romance': '浪漫', + 'compatibility': '相配度', + 'harmony': '和谐度', + 'conflict': '冲突', + 'separation': '分离', + 'reunion': '复合', + 'commitment': '承诺', + 'trust': '信任', + 'loyalty': '忠诚' + }; + + // 获取中文字段名 + const getChineseFieldName = (fieldName) => { + return fieldNameMap[fieldName] || fieldName; + }; + + let markdown = `# 奇门遁甲分析报告\n\n`; + // 从userName中提取实际姓名,去掉"奇门_"前缀 + const actualUserName = userName ? userName.replace(/^奇门_/, '') : '用户'; + markdown += `**占卜者:** ${actualUserName}\n`; + markdown += `**生成时间:** ${timestamp}\n`; + markdown += `**分析类型:** 奇门遁甲\n\n`; + + markdown += `---\n\n`; + + // 占卜问题 + if (analysisData.basic_info?.divination_data) { + markdown += `## ❓ 占卜问题\n\n`; + const divination = analysisData.basic_info.divination_data; + if (divination.question) { + markdown += `**问题:** ${divination.question}\n\n`; + } + if (divination.method) { + markdown += `**起局方法:** ${divination.method}\n\n`; + } + if (divination.divination_time) { + const time = new Date(divination.divination_time).toLocaleString('zh-CN'); + markdown += `**起局时间:** ${time}\n\n`; + } + } + + // 时空信息 + if (analysisData.basic_info?.qimen_info) { + markdown += `## ⏰ 时空信息\n\n`; + const qimenInfo = analysisData.basic_info.qimen_info; + + if (qimenInfo.jieqi) { + markdown += `**节气:** ${qimenInfo.jieqi}\n`; + } + if (qimenInfo.yuan) { + markdown += `**元:** ${qimenInfo.yuan}\n`; + } + if (qimenInfo.jushu) { + markdown += `**局数:** ${qimenInfo.jushu}局\n`; + } + if (qimenInfo.yindun !== undefined) { + markdown += `**阴阳遁:** ${qimenInfo.yindun ? '阴遁' : '阳遁'}\n`; + } + + // 干支四柱 + if (qimenInfo.ganzhi) { + markdown += `\n### 🎋 干支四柱\n\n`; + const ganzhi = qimenInfo.ganzhi; + if (ganzhi.year) markdown += `- **年柱:** ${ganzhi.year.gan}${ganzhi.year.zhi}\n`; + if (ganzhi.month) markdown += `- **月柱:** ${ganzhi.month.gan}${ganzhi.month.zhi}\n`; + if (ganzhi.day) markdown += `- **日柱:** ${ganzhi.day.gan}${ganzhi.day.zhi}\n`; + if (ganzhi.hour) markdown += `- **时柱:** ${ganzhi.hour.gan}${ganzhi.hour.zhi}\n`; + } + + // 值符值使 + if (qimenInfo.zhifu || qimenInfo.zhishi) { + markdown += `\n### ⭐ 值符值使\n\n`; + if (qimenInfo.zhifu) markdown += `- **值符:** ${qimenInfo.zhifu}\n`; + if (qimenInfo.zhishi) markdown += `- **值使:** ${qimenInfo.zhishi}\n`; + } + + markdown += `\n`; + } + + // 奇门盘布局 + if (analysisData.detailed_analysis?.qimen_pan) { + markdown += `## 🔮 奇门盘布局\n\n`; + const qimenPan = analysisData.detailed_analysis.qimen_pan; + + if (qimenPan.dipan && Array.isArray(qimenPan.dipan)) { + const palaceNames = ['坎一宫', '坤二宫', '震三宫', '巽四宫', '中五宫', '乾六宫', '兑七宫', '艮八宫', '离九宫']; + + markdown += `| 宫位 | 九星 | 八门 | 八神 |\n`; + markdown += `|------|------|------|------|\n`; + + qimenPan.dipan.forEach((palace, index) => { + if (palace && palaceNames[index]) { + const star = palace.star || '-'; + const door = palace.door || '-'; + const god = palace.god || '-'; + markdown += `| ${palaceNames[index]} | ${star} | ${door} | ${god} |\n`; + } + }); + + markdown += `\n`; + } + } + + // 用神分析 + if (analysisData.detailed_analysis?.yongshen_analysis) { + markdown += `## 🎯 用神分析\n\n`; + const yongShenAnalysis = analysisData.detailed_analysis.yongshen_analysis; + + // 主用神 + if (yongShenAnalysis.primary) { + markdown += `### 主用神\n\n`; + Object.entries(yongShenAnalysis.primary).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + if (typeof value === 'object' && value !== null) { + markdown += `**${chineseKey}:**\n`; + Object.entries(value).forEach(([subKey, subValue]) => { + const chineseSubKey = getChineseFieldName(subKey); + markdown += `- ${chineseSubKey}:${subValue}\n`; + }); + } else { + markdown += `- **${chineseKey}:** ${value}\n`; + } + }); + markdown += `\n`; + } + + // 次用神 + if (yongShenAnalysis.secondary) { + markdown += `### 次用神\n\n`; + Object.entries(yongShenAnalysis.secondary).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + if (typeof value === 'object' && value !== null) { + markdown += `**${chineseKey}:**\n`; + Object.entries(value).forEach(([subKey, subValue]) => { + const chineseSubKey = getChineseFieldName(subKey); + markdown += `- ${chineseSubKey}:${subValue}\n`; + }); + } else { + markdown += `- **${chineseKey}:** ${value}\n`; + } + }); + markdown += `\n`; + } + + // 综合评估 + if (yongShenAnalysis.overall) { + markdown += `### 用神综合评估\n\n`; + if (typeof yongShenAnalysis.overall === 'object') { + Object.entries(yongShenAnalysis.overall).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + if (typeof value === 'object' && value !== null) { + if (Array.isArray(value)) { + markdown += `- **${chineseKey}:** ${value.join('、')}\n`; + } else { + const subEntries = Object.entries(value).map(([subK, subV]) => { + const chineseSubKey = getChineseFieldName(subK); + return `${chineseSubKey}:${subV}`; + }).join(';'); + markdown += `- **${chineseKey}:** ${subEntries}\n`; + } + } else { + markdown += `- **${chineseKey}:** ${value}\n`; + } + }); + } else { + markdown += `${yongShenAnalysis.overall}\n`; + } + markdown += `\n`; + } + } + + // 格局识别 + if (analysisData.detailed_analysis?.pattern_analysis && Array.isArray(analysisData.detailed_analysis.pattern_analysis)) { + markdown += `## ⭐ 格局识别\n\n`; + + const patterns = analysisData.detailed_analysis.pattern_analysis; + const auspiciousPatterns = patterns.filter(p => p.type === 'auspicious'); + const inauspiciousPatterns = patterns.filter(p => p.type === 'inauspicious'); + const neutralPatterns = patterns.filter(p => p.type === 'neutral'); + + if (auspiciousPatterns.length > 0) { + markdown += `### 🌟 吉利格局\n\n`; + auspiciousPatterns.forEach(pattern => { + markdown += `**${pattern.name}** (${pattern.level || '吉'})\n`; + if (pattern.description) markdown += `${pattern.description}\n`; + if (pattern.influence) markdown += `**影响:** ${pattern.influence}\n`; + markdown += `\n`; + }); + } + + if (neutralPatterns.length > 0) { + markdown += `### ⚖️ 中性格局\n\n`; + neutralPatterns.forEach(pattern => { + markdown += `**${pattern.name}** (${pattern.level || '中'})\n`; + if (pattern.description) markdown += `${pattern.description}\n`; + if (pattern.influence) markdown += `**影响:** ${pattern.influence}\n`; + markdown += `\n`; + }); + } + + if (inauspiciousPatterns.length > 0) { + markdown += `### ⚠️ 不利格局\n\n`; + inauspiciousPatterns.forEach(pattern => { + markdown += `**${pattern.name}** (${pattern.level || '凶'})\n`; + if (pattern.description) markdown += `${pattern.description}\n`; + if (pattern.influence) markdown += `**影响:** ${pattern.influence}\n`; + markdown += `\n`; + }); + } + } + + // 预测结果 + if (analysisData.prediction_result) { + markdown += `## 🔮 预测结果\n\n`; + const prediction = analysisData.prediction_result; + + if (prediction.probability !== undefined) { + markdown += `### 成功概率\n\n`; + markdown += `**概率:** ${prediction.probability}%\n\n`; + + let probabilityLevel = ''; + if (prediction.probability >= 80) probabilityLevel = '极高'; + else if (prediction.probability >= 60) probabilityLevel = '较高'; + else if (prediction.probability >= 40) probabilityLevel = '中等'; + else if (prediction.probability >= 20) probabilityLevel = '较低'; + else probabilityLevel = '很低'; + + markdown += `**评级:** ${probabilityLevel}\n\n`; + } + + if (prediction.analysis) { + markdown += `### 详细分析\n\n`; + if (typeof prediction.analysis === 'object') { + Object.entries(prediction.analysis).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + markdown += `**${chineseKey}:** ${value}\n`; + }); + } else { + markdown += `${prediction.analysis}\n`; + } + markdown += `\n`; + } + + if (prediction.key_factors) { + markdown += `### 关键因素\n\n`; + if (typeof prediction.key_factors === 'object') { + Object.entries(prediction.key_factors).forEach(([factor, impact]) => { + const chineseFactor = getChineseFieldName(factor); + markdown += `- **${chineseFactor}:** ${impact}\n`; + }); + } else { + markdown += `${prediction.key_factors}\n`; + } + markdown += `\n`; + } + } + + // 指导建议 + if (analysisData.guidance) { + markdown += `## 💡 指导建议\n\n`; + const guidance = analysisData.guidance; + + if (guidance.timing_advice) { + markdown += `### ⏰ 时机建议\n\n`; + if (typeof guidance.timing_advice === 'object') { + Object.entries(guidance.timing_advice).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + markdown += `**${chineseKey}:** ${value}\n`; + }); + } else { + markdown += `${guidance.timing_advice}\n`; + } + markdown += `\n`; + } + + if (guidance.action_suggestions && Array.isArray(guidance.action_suggestions)) { + markdown += `### 🎯 行动建议\n\n`; + guidance.action_suggestions.forEach(suggestion => { + markdown += `- ${suggestion}\n`; + }); + markdown += `\n`; + } + + if (guidance.precautions && Array.isArray(guidance.precautions)) { + markdown += `### ⚠️ 注意事项\n\n`; + guidance.precautions.forEach(precaution => { + markdown += `- ${precaution}\n`; + }); + markdown += `\n`; + } + } + + // 五行分析 + if (analysisData.detailed_analysis?.wuxing_analysis) { + markdown += `## 🌟 五行分析\n\n`; + const wuxingAnalysis = analysisData.detailed_analysis.wuxing_analysis; + + if (typeof wuxingAnalysis === 'object') { + Object.entries(wuxingAnalysis).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + markdown += `**${chineseKey}:** ${value}\n`; + }); + } else { + markdown += `${wuxingAnalysis}\n`; + } + markdown += `\n`; + } + + // 时机分析 + if (analysisData.detailed_analysis?.timing_analysis) { + markdown += `## ⏰ 时机分析\n\n`; + const timingAnalysis = analysisData.detailed_analysis.timing_analysis; + + if (typeof timingAnalysis === 'object') { + Object.entries(timingAnalysis).forEach(([key, value]) => { + const chineseKey = getChineseFieldName(key); + markdown += `**${chineseKey}:** ${value}\n`; + }); + } else { + markdown += `${timingAnalysis}\n`; + } + markdown += `\n`; + } + + // 页脚 + markdown += `---\n\n`; + markdown += `*本报告由神机阁AI命理分析平台生成*\n`; + markdown += `*生成时间:${timestamp}*\n`; + markdown += `*仅供参考,请理性对待*\n`; + + return markdown; +}; + module.exports = { generateMarkdown }; \ No newline at end of file diff --git a/server/services/qimenAnalyzer.cjs b/server/services/qimenAnalyzer.cjs index a612bad..393fc6b 100644 --- a/server/services/qimenAnalyzer.cjs +++ b/server/services/qimenAnalyzer.cjs @@ -5,6 +5,7 @@ const AnalysisCache = require('./common/AnalysisCache.cjs'); const EnhancedRandom = require('./common/EnhancedRandom.cjs'); const TimeConverter = require('../utils/timeConverter.cjs'); const SolarTerms = require('../utils/solarTerms.cjs'); +const BaziAnalyzer = require('./baziAnalyzer.cjs'); class QimenAnalyzer { constructor() { @@ -27,6 +28,9 @@ class QimenAnalyzer { // 初始化时间转换器 this.timeConverter = new TimeConverter(); + // 初始化八字分析器(复用农历计算功能) + this.baziAnalyzer = new BaziAnalyzer(); + // 初始化节气计算器 this.solarTerms = new SolarTerms(); @@ -334,19 +338,19 @@ class QimenAnalyzer { const currentTime = datetime ? new Date(datetime) : new Date(); // 起局 - const qimenPan = this.calculateQimenPan(currentTime); + const qimenPan = this.calculator.calculateQimenPan(currentTime); // 选择用神 - const yongShen = this.selectYongShen(question, birth_data, qimenPan); + const yongShen = this.yongShenAnalyzer.selectYongShen(question, birth_data, qimenPan); // 格局分析 - const patterns = this.analyzePatterns(qimenPan); + const patterns = this.patternAnalyzer.analyzePatterns(qimenPan); // 用神分析 - const yongShenAnalysis = this.analyzeYongShen(yongShen, qimenPan); + const yongShenAnalysis = this.yongShenAnalyzer.analyzeYongShen(yongShen, qimenPan); // 生成预测结果 - const prediction = this.generatePrediction(qimenPan, yongShenAnalysis, question, patterns); + const prediction = this.predictionGenerator.generatePrediction(qimenPan, yongShenAnalysis, question, patterns); const result = { analysis_type: 'qimen', @@ -359,17 +363,17 @@ class QimenAnalyzer { lunar_info: this.calculateLunarInfo(currentTime) }, qimen_info: { - jieqi: qimenPan.timeInfo.jieqi, - yuan: qimenPan.timeInfo.yuan, - jushu: qimenPan.timeInfo.jushu, - yindun: qimenPan.timeInfo.yindun ? '阴遁' : '阳遁', - zhifu: qimenPan.zhifu, - zhishi: qimenPan.zhishi, + jieqi: qimenPan.timeInfo?.jieqi || '未知', + yuan: qimenPan.timeInfo?.yuan || '未知', + jushu: qimenPan.timeInfo?.jushu || qimenPan.jushu || '未知', + yindun: qimenPan.timeInfo?.yindun !== undefined ? (qimenPan.timeInfo.yindun ? '阴遁' : '阳遁') : (qimenPan.yindun ? '阴遁' : '阳遁'), + zhifu: qimenPan.zhifu || '未知', + zhishi: qimenPan.zhishi || '未知', ganzhi: { - year: qimenPan.timeInfo.year, - month: qimenPan.timeInfo.month, - day: qimenPan.timeInfo.day, - hour: qimenPan.timeInfo.hour + year: qimenPan.timeInfo?.year || { gan: '未知', zhi: '未知' }, + month: qimenPan.timeInfo?.month || { gan: '未知', zhi: '未知' }, + day: qimenPan.timeInfo?.day || { gan: '未知', zhi: '未知' }, + hour: qimenPan.timeInfo?.hour || { gan: '未知', zhi: '未知' } } } }, @@ -957,17 +961,56 @@ class QimenAnalyzer { * @returns {number} 成功概率(0-100) */ calculateProbability(yongShenAnalysis, patterns) { - let baseProbability = yongShenAnalysis.overall.favorability || 50; + let baseProbability = 50; // 基础概率 + + // 基于用神分析调整概率 + if (yongShenAnalysis && yongShenAnalysis.overall) { + const favorability = yongShenAnalysis.overall.favorability; + if (typeof favorability === 'number') { + baseProbability = favorability; + } else { + // 如果没有favorability,基于用神旺衰计算 + let yongShenScore = 0; + let yongShenCount = 0; + + // 遍历所有用神分析 + ['primary', 'secondary', 'auxiliary'].forEach(category => { + if (yongShenAnalysis[category]) { + Object.values(yongShenAnalysis[category]).forEach(analysis => { + if (analysis && analysis.wangshui) { + yongShenCount++; + switch (analysis.wangshui) { + case '旺': yongShenScore += 20; break; + case '相': yongShenScore += 10; break; + case '休': yongShenScore += 0; break; + case '囚': yongShenScore -= 10; break; + case '死': yongShenScore -= 20; break; + } + } + }); + } + }); + + if (yongShenCount > 0) { + baseProbability = 50 + (yongShenScore / yongShenCount); + } + } + } // 根据格局调整概率 if (patterns && patterns.length > 0) { - const patternScore = patterns.reduce((sum, pattern) => sum + pattern.score, 0); - const patternAdjustment = Math.min(Math.max(patternScore, -20), 20); + const patternScore = patterns.reduce((sum, pattern) => { + const score = pattern.score || 0; + return sum + score; + }, 0); + + // 格局影响权重调整 + const patternAdjustment = Math.min(Math.max(patternScore * 0.8, -25), 25); baseProbability += patternAdjustment; } // 确保概率在合理范围内 - return Math.min(Math.max(baseProbability, 10), 90); + return Math.min(Math.max(Math.round(baseProbability), 15), 85); } /** @@ -1032,15 +1075,34 @@ class QimenAnalyzer { return '不利,建议暂缓或改变策略'; } - // 辅助方法:计算农历信息 + // 辅助方法:计算农历信息(复用八字分析器的农历算法) calculateLunarInfo(datetime) { - // 简化实现,实际应用中需要更精确的农历转换 - return { - year: '甲辰', - month: '丁卯', - day: '庚申', - description: '农历信息(简化版)' - }; + try { + // 将datetime转换为日期字符串格式 + const date = new Date(datetime); + const dateStr = date.toISOString().split('T')[0]; // YYYY-MM-DD格式 + + // 复用八字分析器的农历计算功能 + const lunarInfo = this.baziAnalyzer.calculateLunarInfo(dateStr); + + return { + year: lunarInfo.ganzhi_year, + month: lunarInfo.lunar_month, + day: lunarInfo.lunar_day, + description: lunarInfo.lunar_date, + zodiac: lunarInfo.zodiac, + solar_term: lunarInfo.solar_term + }; + } catch (error) { + console.error('农历信息计算失败:', error); + // 降级处理:返回基本信息 + return { + year: '未知', + month: '未知', + day: '未知', + description: '农历信息计算失败' + }; + } } // 辅助方法:分类问题类型 @@ -1928,14 +1990,265 @@ class QimenAnalyzer { }; } - generateDetailedAnalysis(yongShenAnalysis, patterns) { - // 生成详细分析 - return ['用神状态良好', '格局组合有利']; + /** + * 生成详细分析 + * @param {Object} qimenPan - 奇门盘 + * @param {Object} yongShenAnalysis - 用神分析 + * @param {Array} patterns - 格局列表 + * @returns {Object} 详细分析 + */ + generateDetailedAnalysis(qimenPan, yongShenAnalysis, patterns) { + const analysis = { + yongshen_status: this.generateYongShenStatusAnalysis(yongShenAnalysis), + pattern_influence: this.generatePatternInfluenceAnalysis(patterns), + palace_analysis: this.generatePalaceAnalysis(qimenPan), + wuxing_balance: this.generateWuXingAnalysis(qimenPan), + timing_factors: this.generateTimingAnalysis(qimenPan), + overall_trend: this.generateOverallTrendAnalysis(yongShenAnalysis, patterns) + }; + + return analysis; } - generateSuggestions(yongShenAnalysis, qimenPan, question) { - // 生成建议 - return ['把握时机', '积极行动']; + /** + * 生成用神状态分析 + */ + generateYongShenStatusAnalysis(yongShenAnalysis) { + if (!yongShenAnalysis || !yongShenAnalysis.overall) { + return '用神分析数据不完整,无法进行详细评估'; + } + + const favorability = yongShenAnalysis.overall.favorability || 50; + + if (favorability >= 80) { + return '用神状态极佳,各项要素配合得当,时机非常有利,建议积极行动'; + } else if (favorability >= 65) { + return '用神状态良好,大部分要素较为有利,整体趋势向好,可以适度推进'; + } else if (favorability >= 50) { + return '用神状态一般,有利不利因素并存,需要谨慎评估,稳步前进'; + } else if (favorability >= 35) { + return '用神状态偏弱,不利因素较多,建议暂缓行动,等待更好时机'; + } else { + return '用神状态不佳,阻力较大,不宜贸然行动,应重新规划策略'; + } + } + + /** + * 生成格局影响分析 + */ + generatePatternInfluenceAnalysis(patterns) { + if (!patterns || patterns.length === 0) { + return '未发现明显格局,整体影响中性,需要综合其他因素判断'; + } + + const auspiciousCount = patterns.filter(p => p.level === '吉' || p.level === '大吉').length; + const inauspiciousCount = patterns.filter(p => p.level === '凶' || p.level === '大凶').length; + + if (auspiciousCount > inauspiciousCount) { + return `发现${auspiciousCount}个吉利格局,${inauspiciousCount}个不利格局,整体格局偏向有利,可以借助吉格之力推进事情发展`; + } else if (inauspiciousCount > auspiciousCount) { + return `发现${inauspiciousCount}个不利格局,${auspiciousCount}个吉利格局,需要化解凶格影响,谨慎行事避免不利后果`; + } else { + return `吉凶格局数量相当,影响相互抵消,整体趋势平稳,需要依靠个人努力创造机会`; + } + } + + /** + * 生成宫位分析 + */ + generatePalaceAnalysis(qimenPan) { + if (!qimenPan || !qimenPan.dipan) { + return '奇门盘数据不完整,无法进行宫位分析'; + } + + const palaceNames = ['坎宫', '坤宫', '震宫', '巽宫', '中宫', '乾宫', '兑宫', '艮宫', '离宫']; + const activePalaces = []; + + for (let i = 0; i < 9; i++) { + const palace = qimenPan.dipan[i]; + if (palace && (palace.star || palace.door || palace.god)) { + activePalaces.push(palaceNames[i]); + } + } + + return `当前奇门盘中${activePalaces.join('、')}等宫位较为活跃,星门神配置完整,形成了相对稳定的能量分布格局`; + } + + /** + * 生成五行分析 + */ + generateWuXingAnalysis(qimenPan) { + const wuxingCount = { '金': 0, '木': 0, '水': 0, '火': 0, '土': 0 }; + + if (qimenPan && qimenPan.dipan) { + for (let i = 0; i < 9; i++) { + const palace = qimenPan.dipan[i]; + if (palace && palace.gan) { + const wuxing = this.getGanZhiWuXing(palace.gan); + if (wuxingCount[wuxing] !== undefined) { + wuxingCount[wuxing]++; + } + } + } + } + + const maxWuxing = Object.keys(wuxingCount).reduce((a, b) => wuxingCount[a] > wuxingCount[b] ? a : b); + const total = Object.values(wuxingCount).reduce((sum, count) => sum + count, 0); + + if (total === 0) { + return { dominant: '未知', balance: '无法判断', suggestions: '数据不足,无法分析' }; + } + + const dominantRatio = wuxingCount[maxWuxing] / total; + let balance, suggestions; + + if (dominantRatio >= 0.5) { + balance = '失衡'; + suggestions = `${maxWuxing}过旺,需要其他五行调和平衡`; + } else if (dominantRatio >= 0.3) { + balance = '较为平衡'; + suggestions = `${maxWuxing}稍强,整体尚可,注意维持平衡`; + } else { + balance = '平衡'; + suggestions = '五行分布均匀,相互制约,整体和谐'; + } + + return { dominant: maxWuxing, balance, suggestions }; + } + + /** + * 生成时机分析 + */ + generateTimingAnalysis(qimenPan) { + const currentDate = new Date(); + const season = this.getCurrentSeason(currentDate); + + let favorability, notes; + + switch (season) { + case '春季': + favorability = '有利'; + notes = '春季木旺,万物复苏,利于新的开始和发展'; + break; + case '夏季': + favorability = '较为有利'; + notes = '夏季火旺,阳气充沛,利于积极行动和扩展'; + break; + case '秋季': + favorability = '中等'; + notes = '秋季金旺,收获季节,利于总结和巩固成果'; + break; + case '冬季': + favorability = '需谨慎'; + notes = '冬季水旺,宜蛰伏养精,不宜大动作'; + break; + default: + favorability = '中等'; + notes = '时机平常,需要综合其他因素判断'; + } + + return { season, favorability, notes }; + } + + /** + * 生成整体趋势分析 + */ + generateOverallTrendAnalysis(yongShenAnalysis, patterns) { + const favorability = yongShenAnalysis?.overall?.favorability || 50; + const patternScore = patterns ? patterns.reduce((sum, p) => sum + (p.score || 0), 0) : 0; + + const totalScore = favorability + patternScore; + + if (totalScore >= 80) { + return '整体趋势非常积极,各项因素配合良好,成功概率很高,建议抓住机会全力推进'; + } else if (totalScore >= 60) { + return '整体趋势较为积极,大部分因素有利,有较好的成功基础,可以稳步推进'; + } else if (totalScore >= 40) { + return '整体趋势中性偏好,有利不利因素并存,需要谨慎规划,稳中求进'; + } else if (totalScore >= 20) { + return '整体趋势偏向不利,阻力较大,建议暂缓行动,寻找更好时机'; + } else { + return '整体趋势不佳,不利因素较多,不建议贸然行动,应重新评估策略'; + } + } + + /** + * 获取当前季节 + */ + getCurrentSeason(date) { + const month = date.getMonth() + 1; + + if (month >= 3 && month <= 5) { + return '春季'; + } else if (month >= 6 && month <= 8) { + return '夏季'; + } else if (month >= 9 && month <= 11) { + return '秋季'; + } else { + return '冬季'; + } + } + + /** + * 生成建议 + * @param {Object} yongShenAnalysis - 用神分析 + * @param {Array} patterns - 格局列表 + * @param {Object} timing - 应期分析 + * @returns {Array} 建议列表 + */ + generateSuggestions(yongShenAnalysis, patterns, timing) { + const suggestions = []; + + // 基于用神状态的建议 + if (yongShenAnalysis && yongShenAnalysis.overall) { + const favorability = yongShenAnalysis.overall.favorability || 50; + + if (favorability >= 70) { + suggestions.push('用神得力,时机有利,可以积极主动地推进计划'); + suggestions.push('抓住当前的有利时机,果断行动,成功概率较高'); + } else if (favorability >= 50) { + suggestions.push('用神状态一般,需要谨慎评估,稳步推进'); + suggestions.push('可以适度行动,但要做好充分准备和风险控制'); + } else { + suggestions.push('用神不利,建议暂缓行动,等待更好的时机'); + suggestions.push('当前阻力较大,宜以守为攻,积蓄力量'); + } + } + + // 基于格局的建议 + if (patterns && patterns.length > 0) { + const auspiciousPatterns = patterns.filter(p => p.level === '吉' || p.level === '大吉'); + const inauspiciousPatterns = patterns.filter(p => p.level === '凶' || p.level === '大凶'); + + if (auspiciousPatterns.length > inauspiciousPatterns.length) { + suggestions.push('格局组合整体有利,可以借助贵人力量,寻求合作机会'); + suggestions.push('吉格当头,宜主动出击,把握机遇,扩大成果'); + } else if (inauspiciousPatterns.length > 0) { + suggestions.push('存在不利格局,需要化解阻碍,避免冲动行事'); + suggestions.push('凶格影响,宜低调行事,避免锋芒太露,以免招致麻烦'); + } + } + + // 基于应期的建议 + if (timing && timing.mainTiming) { + switch (timing.mainTiming) { + case '近期': + suggestions.push('应期在即,宜抓紧时间行动,不可错失良机'); + break; + case '中期': + suggestions.push('需要耐心等待,做好充分准备,时机成熟时再行动'); + break; + case '远期': + suggestions.push('应期较远,宜长远规划,循序渐进,不可急于求成'); + break; + } + } + + // 通用建议 + suggestions.push('保持积极心态,相信自己的判断,同时要灵活应变'); + suggestions.push('多与有经验的人交流,听取不同意见,完善行动方案'); + + return suggestions; } calculateTiming(yongShenAnalysis, qimenPan) { @@ -2871,7 +3184,7 @@ class YongShenAnalyzer { * @returns {Object} 用神配置 */ selectYongShen(question, birthData, qimenPan) { - const questionType = this.classifyQuestion(question); + const questionType = this.analyzer.classifyQuestion(question); const rigan = qimenPan.timeInfo.day.gan; const gender = birthData?.gender || '未知'; @@ -3858,8 +4171,8 @@ class YongShenAnalyzer { recommendation, factors, analysis: { - zhifuAnalysis: zhifu ? `值符${zhifu.star}` : '值符未知', - zhishiAnalysis: zhishi ? `值使${zhishi.door}` : '值使未知', + zhifuAnalysis: zhifu ? `值符${typeof zhifu === 'object' ? zhifu.star : zhifu}` : '值符未知', + zhishiAnalysis: zhishi ? `值使${typeof zhishi === 'object' ? zhishi.door : zhishi}` : '值使未知', hourAnalysis: `${hourZhi}时`, seasonAnalysis: `${jieqi}节气`, yindunAnalysis: timeInfo.yindun ? '阴遁' : '阳遁' @@ -3887,13 +4200,14 @@ class PredictionGenerator { } generatePrediction(qimenPan, yongShenAnalysis, question, patterns) { - const score = this.calculateOverallScore(yongShenAnalysis, patterns); + // 使用主分析器的概率计算方法 + const probability = this.analyzer.calculateProbability(yongShenAnalysis, patterns); return { - overall: this.interpretScore(score), - probability: score, - details: this.generateDetailedAnalysis(yongShenAnalysis, patterns), - suggestions: this.generateSuggestions(yongShenAnalysis, qimenPan, question), + overall: this.analyzer.generateOverallAssessment(probability, yongShenAnalysis), + probability: probability, + details: this.analyzer.generateDetailedAnalysis(qimenPan, yongShenAnalysis, patterns), + suggestions: this.analyzer.generateSuggestions(yongShenAnalysis, patterns, { description: '时机分析' }), timing: this.calculateTiming(yongShenAnalysis, qimenPan) }; } diff --git a/server/services/ziweiAnalyzer.cjs b/server/services/ziweiAnalyzer.cjs index bff2c22..f32a930 100644 --- a/server/services/ziweiAnalyzer.cjs +++ b/server/services/ziweiAnalyzer.cjs @@ -1,11 +1,11 @@ // 专业紫微斗数分析服务模块 // 基于传统紫微斗数理论的精确实现 -const BaziAnalyzer = require('./baziAnalyzer.cjs'); const BaseData = require('./common/BaseData.cjs'); const AnalysisCache = require('./common/AnalysisCache.cjs'); const StarBrightness = require('./common/StarBrightness.cjs'); const EnhancedSiHua = require('./common/EnhancedSiHua.cjs'); +const BaziAnalyzer = require('./baziAnalyzer.cjs'); class ZiweiAnalyzer { constructor() { @@ -61,42 +61,27 @@ class ZiweiAnalyzer { }; } - // 计算农历信息(与八字分析器保持一致) + // 计算农历信息(复用八字分析器的农历算法) calculateLunarInfo(birth_date) { - const birthDate = new Date(birth_date); - const year = birthDate.getFullYear(); - const month = birthDate.getMonth() + 1; - const day = birthDate.getDate(); - - // 计算干支年 - const tianGan = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; - const diZhi = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; - const zodiacAnimals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']; - - const ganIndex = (year - 4) % 10; - const zhiIndex = (year - 4) % 12; - const ganzhiYear = tianGan[ganIndex] + diZhi[zhiIndex]; - const zodiac = zodiacAnimals[zhiIndex]; - - // 计算节气信息 - let solarTerm = this.calculateSolarTerm(month, day); - - // 改进的农历日期计算 - const lunarInfo = this.calculateAccurateLunarDate(year, month, day); - const lunarDay = lunarInfo.day; - const lunarMonth = lunarInfo.month; - const lunarYear = lunarInfo.year; - - return { - lunar_date: `农历${this.getChineseYear(lunarYear)}年${this.getChineseMonth(lunarMonth)}月${this.getChineseDay(lunarDay)}日`, - lunar_year: `${this.getChineseYear(lunarYear)}年`, - lunar_month: this.getChineseMonth(lunarMonth) + '月', - lunar_day: this.getChineseDay(lunarDay) + '日', - ganzhi_year: ganzhiYear, - zodiac: zodiac, - solar_term: this.calculateDetailedSolarTerm(month, day) + try { + // 直接复用八字分析器的农历计算功能,避免重复实现 + return this.baziAnalyzer.calculateLunarInfo(birth_date); + } catch (error) { + console.error('农历信息计算失败:', error); + // 降级处理:返回基本信息 + const birthDate = new Date(birth_date); + const year = birthDate.getFullYear(); + return { + lunar_date: '农历信息计算失败', + lunar_year: `${year}年`, + lunar_month: '未知月', + lunar_day: '未知日', + ganzhi_year: '未知', + zodiac: '未知', + solar_term: '未知' }; } + } // 转换为中文年份 getChineseYear(year) { @@ -152,81 +137,7 @@ class ZiweiAnalyzer { } } - // 改进的公历转农历计算方法(与八字分析器保持一致) - calculateAccurateLunarDate(year, month, day) { - // 农历年份对照表(部分年份的春节日期) - const springFestivals = { - 1976: { month: 1, day: 31 }, // 1976年春节:1月31日 - 1977: { month: 2, day: 18 }, - 1978: { month: 2, day: 7 }, - 1979: { month: 1, day: 28 }, - 1980: { month: 2, day: 16 }, - 1981: { month: 2, day: 5 }, - 1982: { month: 1, day: 25 }, - 1983: { month: 2, day: 13 }, - 1984: { month: 2, day: 2 }, - 1985: { month: 2, day: 20 }, - 1986: { month: 2, day: 9 }, - 1987: { month: 1, day: 29 }, - 1988: { month: 2, day: 17 }, - 1989: { month: 2, day: 6 }, - 1990: { month: 1, day: 27 } - }; - - const springFestival = springFestivals[year]; - if (!springFestival) { - // 如果没有对应年份数据,使用估算 - return { - year: year, - month: month > 2 ? month - 1 : month + 11, - day: Math.max(1, day - 15) - }; - } - - // 计算距离春节的天数 - const currentDate = new Date(year, month - 1, day); - const springDate = new Date(year, springFestival.month - 1, springFestival.day); - const daysDiff = Math.floor((currentDate - springDate) / (1000 * 60 * 60 * 24)); - - if (daysDiff < 0) { - // 在春节之前,属于上一年农历 - const prevSpringFestival = springFestivals[year - 1]; - if (prevSpringFestival) { - const prevSpringDate = new Date(year - 1, prevSpringFestival.month - 1, prevSpringFestival.day); - const prevDaysDiff = Math.floor((currentDate - prevSpringDate) / (1000 * 60 * 60 * 24)); - const totalDays = prevDaysDiff + 365; // 简化计算 - - // 估算农历月日 - const lunarMonth = Math.floor(totalDays / 30) + 1; - const lunarDay = (totalDays % 30) + 1; - - return { - year: year - 1, - month: Math.min(12, lunarMonth), - day: Math.min(30, lunarDay) - }; - } - } - - // 在春节之后,计算农历月日 - const lunarMonth = Math.floor(daysDiff / 30) + 1; - const lunarDay = (daysDiff % 30) + 1; - - // 特殊处理:1976年3月17日应该对应农历2月17日左右 - if (year === 1976 && month === 3 && day === 17) { - return { - year: 1976, - month: 2, - day: 17 - }; - } - - return { - year: year, - month: Math.min(12, lunarMonth), - day: Math.min(30, Math.max(1, lunarDay)) - }; - } + // 已删除重复的农历计算方法,现在复用八字分析器的功能 // 计算节气信息 calculateSolarTerm(month, day) { @@ -257,19 +168,7 @@ class ZiweiAnalyzer { return '节气间'; } - // 转换为中文月份 - getChineseMonth(month) { - const chineseMonths = ['', '正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '腊']; - return chineseMonths[month] || '未知'; - } - - // 转换为中文日期 - getChineseDay(day) { - const chineseDays = ['', '初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', - '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', - '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十']; - return chineseDays[day] || '未知'; - } + // 已删除重复的中文转换方法,现在复用八字分析器的功能 // 生成子时计算方法说明(紫微斗数版本) generateZishiCalculationNote(baziInfo, birth_time) { diff --git a/server/utils/solarTerms.cjs b/server/utils/solarTerms.cjs index 5f536f1..736a1f9 100644 --- a/server/utils/solarTerms.cjs +++ b/server/utils/solarTerms.cjs @@ -527,7 +527,7 @@ class SolarTerms { * @returns {Date} 立春时间 */ getSpringBeginning(year) { - return this.calculateSolarTerm(year, 0); + return this.calculateSolarTermDate(year, '立春'); } /** diff --git a/src/components/AnalysisResultDisplay.tsx b/src/components/AnalysisResultDisplay.tsx index 26bf3fc..7230ff6 100644 --- a/src/components/AnalysisResultDisplay.tsx +++ b/src/components/AnalysisResultDisplay.tsx @@ -2,11 +2,12 @@ import React from 'react'; import CompleteBaziAnalysis from './CompleteBaziAnalysis'; import CompleteZiweiAnalysis from './CompleteZiweiAnalysis'; import CompleteYijingAnalysis from './CompleteYijingAnalysis'; +import CompleteQimenAnalysis from './CompleteQimenAnalysis'; import BaziAnalysisDisplay from './BaziAnalysisDisplay'; interface AnalysisResultDisplayProps { analysisResult?: any; - analysisType: 'bazi' | 'ziwei' | 'yijing'; + analysisType: 'bazi' | 'ziwei' | 'yijing' | 'qimen'; birthDate?: { date: string; time: string; @@ -429,6 +430,8 @@ const AnalysisResultDisplay: React.FC = ({ return renderZiweiAnalysis(); case 'yijing': return renderYijingAnalysis(); + case 'qimen': + return ; default: return (
@@ -461,6 +464,11 @@ const AnalysisResultDisplay: React.FC = ({ return ; } + // 对于奇门遁甲,如果有预分析数据,直接返回 CompleteQimenAnalysis 组件 + if (analysisType === 'qimen' && preAnalysisData) { + return ; + } + // 如果没有分析结果数据 if (!analysisResult) { return ( diff --git a/src/components/CompleteQimenAnalysis.tsx b/src/components/CompleteQimenAnalysis.tsx new file mode 100644 index 0000000..52aeb7f --- /dev/null +++ b/src/components/CompleteQimenAnalysis.tsx @@ -0,0 +1,1457 @@ +import React, { useState } from 'react'; +import { Card, CardContent, CardHeader, CardTitle } from './ui/Card'; +import { Hexagon, Clock, MapPin, Star, Compass, Target, TrendingUp, AlertTriangle, Calendar, BookOpen, Sparkles, User, BarChart3, Zap, Activity } from 'lucide-react'; +import { cn } from '../lib/utils'; +import { BackToTop } from './ui/BackToTop'; +import DownloadButton from './ui/DownloadButton'; +import AIInterpretationButton from './ui/AIInterpretationButton'; +import AIConfigModal from './ui/AIConfigModal'; + +interface QimenAnalysisProps { + analysis: any; + className?: string; + recordId?: number; +} + +const CompleteQimenAnalysis: React.FC = ({ analysis, className, recordId }) => { + const [showAIConfig, setShowAIConfig] = useState(false); + + if (!analysis) { + return ( +
+

暂无奇门遁甲分析数据

+
+ ); + } + + // 从后端返回的嵌套结构中提取数据 + const qimenPan = analysis?.detailed_analysis?.qimen_pan; + const yongShenAnalysis = analysis?.detailed_analysis?.yongshen_analysis; + const patterns = analysis?.detailed_analysis?.pattern_analysis; + const prediction = analysis?.prediction_result; + const timeInfo = analysis?.basic_info?.qimen_info; + const basicInfo = analysis?.basic_info; + const guidance = analysis?.guidance; + + // 用神类型中文映射 - 移到组件级别 + const yongShenNameMap = { + 'rigan': '日干(求测人)', + 'self': '自身', + 'spouse': '配偶', + 'matchmaker': '媒人', + 'wealth': '财运', + 'capital': '资本', + 'opportunity': '机会', + 'illness': '疾病', + 'doctor': '医生', + 'medicine': '药物', + 'lawsuit': '官司', + 'judge': '法官', + 'opponent': '对手', + 'job': '工作', + 'company': '公司', + 'process': '过程', + 'matter': '事情', + 'result': '结果', + 'favorability': '有利度', + 'strength': '力量强度', + 'timing': '时机评估', + 'recommendation': '建议', + // 用神分析详细字段中文映射 + 'element': '天干', + 'position': '宫位', + 'palaceName': '宫位名称', + 'wangshui': '旺衰', + 'wangshuiScore': '旺衰评分', + 'palaceRelation': '宫位关系', + 'palaceHarmony': '宫位和谐度', + 'seasonalInfluence': '季节影响', + 'seasonalScore': '季节评分', + 'totalScore': '综合评分', + 'status': '状态', + 'description': '详细描述', + // 构成要素字段中文映射 + 'qi': '奇', + 'star': '星', + 'door': '门', + 'god': '神', + // 时机相关字段中文映射 + 'bestTime': '最佳时机', + 'avoidTime': '避免时机', + 'score': '评分', + 'factors': '影响因素', + 'analysis': '详细分析', + 'zhifuAnalysis': '值符分析', + 'zhishiAnalysis': '值使分析', + 'hourAnalysis': '时辰分析', + 'seasonAnalysis': '节气分析', + 'yindunAnalysis': '阴阳遁分析', + // 基础信息字段中文映射 + 'method': '占卜方法', + 'zhifu': '值符', + 'zhishi': '值使', + 'season': '季节', + 'daymaster': '日主', + 'dayMaster': '日主', + 'jieqi': '节气', + 'yuan': '元', + 'jushu': '局数', + 'yindun': '阴阳遁', + 'ganzhi': '干支', + 'year': '年', + 'month': '月', + 'day': '日', + 'hour': '时', + 'gan': '干', + 'zhi': '支', + // 奇门盘字段中文映射 + 'palace': '宫位', + 'wuxing': '五行', + 'type': '类型', + 'score': '评分', + 'level': '等级', + 'name': '名称', + 'elements': '构成要素', + 'overall': '综合评估', + 'primary': '主要用神', + 'secondary': '次要用神', + 'auxiliary': '辅助用神', + // 财运相关字段 + 'profit': '利润', + 'investment': '投资', + 'wealth': '财富', + 'money': '金钱', + 'finance': '财务', + 'business': '生意', + 'career': '事业', + 'work': '工作', + 'job': '职业', + 'success': '成功', + 'failure': '失败', + 'opportunity': '机会', + 'risk': '风险', + 'challenge': '挑战', + 'advantage': '优势', + 'disadvantage': '劣势', + // 用神分析字段 + 'matter': '事情', + 'result': '结果', + 'self': '自身', + 'opponent': '对手', + 'helper': '帮助者', + 'obstacle': '阻碍', + // 五行分析字段 + 'dominant': '主导五行', + 'balance': '平衡状态', + 'suggestions': '建议', + 'notes': '备注', + 'season': '季节', + // 时机分析字段 + 'favorable': '有利', + 'unfavorable': '不利', + 'neutral': '中性', + // 其他常见字段 + 'true': '是', + 'false': '否', + 'unknown': '未知', + 'good': '好', + 'bad': '差', + 'excellent': '极佳', + 'poor': '很差', + 'average': '一般', + // 感情相关字段 + 'spouse': '配偶', + 'relationship': '感情关系', + 'matchmaker': '媒人', + 'marriage_palace': '婚姻宫', + 'relationship_door': '感情门', + 'love': '爱情', + 'marriage': '婚姻', + 'partner': '伴侣', + 'emotion': '情感', + 'affection': '感情', + 'romance': '浪漫', + 'compatibility': '相配度', + 'harmony': '和谐度', + 'conflict': '冲突', + 'separation': '分离', + 'reunion': '复合', + 'commitment': '承诺', + 'trust': '信任', + 'loyalty': '忠诚' + }; + + const getYongShenName = (key: string) => { + return yongShenNameMap[key] || key; + }; + + // 用神分析值的中文映射 + const getChineseValue = (key: string, value: any) => { + // 旺衰状态映射 + const wangshuiMap = { + '旺': '旺', + '相': '相', + '休': '休', + '囚': '囚', + '死': '死' + }; + + // 状态映射 + const statusMap = { + '很强': '很强', + '较强': '较强', + '一般': '一般', + '较弱': '较弱', + '很弱': '很弱' + }; + + // 布尔值映射 + if (typeof value === 'boolean') { + return value ? '是' : '否'; + } + + // 数组类型处理 + if (Array.isArray(value)) { + return value.join('、'); + } + + // 数值处理 - 将小数转换为整数 + if (typeof value === 'number') { + if (key.includes('score') || key.includes('度') || key === 'favorability' || key === 'wangshuiScore' || key === 'seasonalScore' || key === 'totalScore') { + return Math.round(value).toString(); + } + return value.toString(); + } + + // 对象类型处理 + if (typeof value === 'object' && value !== null) { + // 如果是时机对象,特殊处理 - 简化显示 + if (key === 'timing' && typeof value === 'object') { + try { + // 提取关键信息进行简化显示 + const timing = value.timing || '未知'; + const score = value.score ? Math.round(value.score) : ''; + const recommendation = value.recommendation || ''; + + // 构建简洁的显示文本 + let result = timing; + if (score) { + result += `(${score}分)`; + } + if (recommendation && recommendation !== timing) { + result += ` - ${recommendation}`; + } + + return result; + } catch (error) { + console.error('时机对象处理错误:', error, value); + return '时机评估信息异常'; + } + } + + // 其他对象类型,尝试格式化显示 + try { + const entries = Object.entries(value).map(([k, v]) => { + const chineseKey = getYongShenName(k); + if (Array.isArray(v)) { + return `${chineseKey}:${v.join('、')}`; + } else if (typeof v === 'object' && v !== null) { + const subEntries = Object.entries(v).map(([subK, subV]) => { + const subChineseKey = getYongShenName(subK); + // 处理嵌套对象中的数值 + if (typeof subV === 'number' && (subK.includes('score') || subK.includes('度') || subK === 'favorability')) { + return `${subChineseKey}:${Math.round(subV)}`; + } + return `${subChineseKey}:${String(subV)}`; + }); + return `${chineseKey}:${subEntries.join(';')}`; + } else { + // 处理直接数值 + if (typeof v === 'number' && (k.includes('score') || k.includes('度') || k === 'favorability')) { + return `${chineseKey}:${Math.round(v)}`; + } + return `${chineseKey}:${String(v)}`; + } + }); + return entries.join(','); + } catch (e) { + console.error('对象处理错误:', e, value); + return JSON.stringify(value, null, 2); + } + } + + // 特定字段的值映射 + if (key === 'wangshui' && wangshuiMap[value]) { + return wangshuiMap[value]; + } + + if (key === 'status' && statusMap[value]) { + return statusMap[value]; + } + + return String(value); + }; + + // 渲染奇门盘九宫格(参考传统样式) + const renderQimenPan = () => { + if (!qimenPan || !qimenPan.dipan) return null; + + // 传统奇门盘布局:巽离坎/震中乾/兑坤艮 + const gridPositions = [ + [3, 8, 0], // 上排:巽四宫、离九宫、坎一宫 + [2, 4, 5], // 中排:震三宫、中五宫、乾六宫 + [6, 1, 7] // 下排:兑七宫、坤二宫、艮八宫 + ]; + + const palaceNames = ['坎', '坤', '震', '巽', '中', '乾', '兑', '艮', '离']; + const palacePositions = ['一', '二', '三', '四', '五', '六', '七', '八', '九']; + + return ( +
+ {/* 四柱信息 */} + {timeInfo?.ganzhi && ( +
+
+ 四柱:{timeInfo.ganzhi.year?.gan}{timeInfo.ganzhi.year?.zhi} {timeInfo.ganzhi.month?.gan}{timeInfo.ganzhi.month?.zhi} {timeInfo.ganzhi.day?.gan}{timeInfo.ganzhi.day?.zhi} {timeInfo.ganzhi.hour?.gan}{timeInfo.ganzhi.hour?.zhi} +
+
+
节气:{timeInfo.jieqi || '未知'} ~ {timeInfo.yuan || '未知'} {qimenPan?.yindun ? '阴遁' : '阳遁'}{qimenPan?.jushu || ''}局
+
值符:{timeInfo.zhifu || '未知'} 值使:{timeInfo.zhishi || '未知'}
+
旬首:甲戌旬 空亡:申酉 马星:寅
+
+
+ )} + + {/* 传统九宫格布局 */} +
+
+ {gridPositions.map((row, rowIndex) => + row.map((palaceIndex, colIndex) => { + const palace = qimenPan.dipan[palaceIndex]; + const isCenter = rowIndex === 1 && colIndex === 1; + + return ( +
+ {/* 宫位标识 */} +
+ {palaceNames[palaceIndex]} +
+ + {/* 宫位内容 */} +
+ {/* 天干 */} + {palace?.gan && ( +
+ {palace.gan} +
+ )} + + {/* 九星 */} + {palace?.star && ( +
+ {palace.star} +
+ )} + + {/* 八门 */} + {palace?.door && ( +
+ {palace.door} +
+ )} + + {/* 八神 */} + {palace?.god && ( +
+ {palace.god} +
+ )} +
+ + {/* 宫位编号 */} +
+ {palacePositions[palaceIndex]} +
+
+ ); + }) + )} +
+
+ + {/* 四害颜色说明 */} +
+ 四害颜色: 【刑墓】 空○ +
+ + {/* 奇门盘构成要素详解 */} +
+

奇门盘构成要素详解

+
+
+
+ + 九星:天蓬、天任、天冲、天辅、天英、天芮、天柱、天心、天禽,代表天时因素 +
+
+ + 八门:休、生、伤、杜、景、死、惊、开,代表人事因素 +
+
+
+
+ + 八神:值符、腾蛇、太阴、六合、白虎、玄武、九地、九天,代表神煞因素 +
+
+ + 天干:甲乙丙丁戊己庚辛壬癸,代表地利因素 +
+
+
+
+
+ ); + }; + + // 渲染用神分析 + const renderYongShenAnalysis = () => { + if (!yongShenAnalysis) return null; + + const renderYongShenItem = (key: string, value: any, bgColor: string, textColor: string) => { + if (typeof value === 'object' && value !== null) { + return ( +
+
{getYongShenName(key)}
+
+ {Object.entries(value).map(([subKey, subValue]) => ( +
+ {getYongShenName(subKey)}: + {getChineseValue(subKey, subValue)} +
+ ))} +
+
+ ); + } else { + return ( +
+
{getYongShenName(key)}
+
{getChineseValue(key, value)}
+
+ ); + } + }; + + return ( +
+ {/* 用神概述 */} +
+

+ + 用神概述 +

+

+ 用神是奇门遁甲分析的核心要素,代表与占卜问题相关的关键因素。通过分析用神在奇门盘中的状态、位置和相互关系, + 可以判断事情的发展趋势、成功概率和最佳时机。不同类型的问题对应不同的用神配置。 +

+
+ + {yongShenAnalysis.primary && Object.keys(yongShenAnalysis.primary).length > 0 && ( +
+

+ + 主要用神分析 +

+

主要用神是与占卜问题直接相关的核心要素,其状态直接影响事情的成败。

+
+ {Object.entries(yongShenAnalysis.primary).map(([key, value]: [string, any]) => + renderYongShenItem(key, value, 'bg-red-50', 'text-red-700') + )} +
+
+ )} + + {yongShenAnalysis.secondary && Object.keys(yongShenAnalysis.secondary).length > 0 && ( +
+

+ + 次要用神分析 +

+

次要用神是影响事情发展的辅助因素,虽不是决定性的,但对结果有重要影响。

+
+ {Object.entries(yongShenAnalysis.secondary).map(([key, value]: [string, any]) => + renderYongShenItem(key, value, 'bg-blue-50', 'text-blue-700') + )} +
+
+ )} + + {yongShenAnalysis.auxiliary && Object.keys(yongShenAnalysis.auxiliary).length > 0 && ( +
+

+ + 辅助用神分析 +

+

辅助用神提供额外的参考信息,有助于全面理解事情的发展环境和背景。

+
+ {Object.entries(yongShenAnalysis.auxiliary).map(([key, value]: [string, any]) => + renderYongShenItem(key, value, 'bg-green-50', 'text-green-700') + )} +
+
+ )} + + {yongShenAnalysis.overall && ( +
+

+ + 用神综合评估 +

+
+ {typeof yongShenAnalysis.overall === 'string' + ? ( +

{yongShenAnalysis.overall}

+ ) : ( +
+ {Object.entries(yongShenAnalysis.overall).map(([key, value]) => ( +
+
+ {getYongShenName(key)}: + + {key === 'favorability' ? `${Math.round(value)}分` : getChineseValue(key, value)} + +
+ {key === 'favorability' && ( +
+
+
= 70 ? 'bg-green-500' : + value >= 50 ? 'bg-yellow-500' : 'bg-red-500' + }`} + style={{ width: `${Math.min(value, 100)}%` }} + >
+
+
+ )} +
+ ))} +
+ ) + } +
+
+ )} +
+ ); + }; + + // 渲染格局识别 + const renderPatterns = () => { + if (!patterns || patterns.length === 0) return null; + + // 格局类型中文映射 + const patternTypeMap = { + '三奇格局': '三奇格局(乙丙丁三奇的特殊组合)', + '六仪格局': '六仪格局(戊己庚辛壬癸六仪的特殊组合)', + '特殊格局': '特殊格局(罕见的吉凶组合)', + '组合格局': '组合格局(多种要素的综合组合)', + '飞宫格局': '飞宫格局(宫位之间的特殊关系)' + }; + + const getPatternTypeDescription = (type: string) => { + return patternTypeMap[type] || type; + }; + + // 按吉凶程度分组 + const auspiciousPatterns = patterns.filter((p: any) => p.type === 'auspicious' || p.level === '吉' || p.level === '大吉'); + const neutralPatterns = patterns.filter((p: any) => p.level === '中'); + const inauspiciousPatterns = patterns.filter((p: any) => p.type === 'inauspicious' || p.level === '凶' || p.level === '大凶'); + + const renderPatternGroup = (groupPatterns: any[], title: string, bgColor: string, borderColor: string, textColor: string) => { + if (groupPatterns.length === 0) return null; + + return ( +
+
+ + {title}({groupPatterns.length}个) +
+
+ {groupPatterns.map((pattern: any, index: number) => ( +
+
+
+
{pattern.name}
+

{getPatternTypeDescription(pattern.type)}

+
+
+ + {pattern.type === 'auspicious' ? '吉格' : pattern.type === 'inauspicious' ? '凶格' : pattern.level || '未知'} + + {pattern.score && ( +
+ 影响分数:{pattern.score > 0 ? '+' : ''}{pattern.score} +
+ )} +
+
+ +
+

+ {pattern.description} +

+ + {pattern.palaceName && ( +
+ 所在宫位: + {pattern.palaceName} +
+ )} + + {pattern.elements && ( +
+ 构成要素: +
+ {Object.entries(pattern.elements).map(([key, value]) => ( + + {getYongShenName(key)}:{String(value)} + + ))} +
+
+ )} + + {pattern.influence && ( +
+ 影响: + {pattern.influence} +
+ )} +
+
+ ))} +
+
+ ); + }; + + return ( +
+ {/* 格局概述 */} +
+

格局分析概述

+

+ 奇门遁甲格局是指奇门盘中特定要素的组合形式,反映了天时、地利、人和的综合状况。 + 吉格表示有利因素,凶格表示不利因素。格局的数量和质量直接影响事情的成败概率。 +

+
+
+
{auspiciousPatterns.length}
+
吉利格局
+
+
+
{neutralPatterns.length}
+
中性格局
+
+
+
{inauspiciousPatterns.length}
+
不利格局
+
+
+
+ + {renderPatternGroup(auspiciousPatterns, '吉利格局', 'bg-green-50', 'border-green-500', 'text-green-700')} + {renderPatternGroup(neutralPatterns, '中性格局', 'bg-yellow-50', 'border-yellow-500', 'text-yellow-700')} + {renderPatternGroup(inauspiciousPatterns, '不利格局', 'bg-red-50', 'border-red-500', 'text-red-700')} +
+ ); + }; + + // 渲染预测结果 + const renderPrediction = () => { + if (!prediction) return null; + + return ( +
+ {/* 预测概述 */} +
+

预测结果概述

+

+ 基于奇门遁甲盘的综合分析,结合用神状态、格局组合、五行生克等因素, + 对所占问题的发展趋势和成功概率进行科学预测。 +

+
+ + {prediction.probability && ( +
+
+
+ {prediction.probability}% +
+
成功概率
+
+ + {/* 概率等级指示器 */} +
+
+
= 80 ? 'bg-green-500' : + prediction.probability >= 60 ? 'bg-yellow-500' : + prediction.probability >= 40 ? 'bg-orange-500' : 'bg-red-500' + }`} + style={{ width: `${Math.min(prediction.probability, 100)}%` }} + >
+
+
+ 极低 + 较低 + 中等 + 较高 + 极高 +
+
+ + {/* 概率等级说明 */} +
+ = 80 ? 'bg-green-100 text-green-800' : + prediction.probability >= 60 ? 'bg-yellow-100 text-yellow-800' : + prediction.probability >= 40 ? 'bg-orange-100 text-orange-800' : 'bg-red-100 text-red-800' + }`}> + { + prediction.probability >= 80 ? '成功概率极高' : + prediction.probability >= 60 ? '成功概率较高' : + prediction.probability >= 40 ? '成功概率中等' : '成功概率较低' + } + +
+
+ )} + + {prediction.analysis && ( +
+

+ + 详细分析 +

+
+ {typeof prediction.analysis === 'string' + ? ( +
+

{prediction.analysis}

+
+ ) : ( +
+ {Object.entries(prediction.analysis).map(([key, value]) => { + // 预测分析术语中文映射 + const analysisTermMap = { + 'yongshen_status': '用神状态分析', + 'pattern_influence': '格局影响分析', + 'palace_analysis': '宫位分布分析', + 'wuxing_balance': '五行平衡分析', + 'timing_factors': '时机因素分析', + 'overall_trend': '整体趋势分析', + 'success_probability': '成功概率', + 'risk_assessment': '风险评估', + 'favorable_factors': '有利因素', + 'unfavorable_factors': '不利因素', + 'recommendations': '专业建议', + 'timing_advice': '时机建议' + }; + + const getChineseKey = (k: string) => { + return analysisTermMap[k] || k; + }; + + return ( +
+
+ {getChineseKey(key)}: + {String(value)} +
+
+ ); + })} +
+ ) + } +
+
+ )} + + {/* 关键因素分析 */} + {prediction.key_factors && ( +
+

+ + 关键影响因素 +

+
+ {Object.entries(prediction.key_factors).map(([factor, impact]) => ( +
+
+ {factor} + + {String(impact)} + +
+
+ ))} +
+
+ )} + + {prediction.suggestions && prediction.suggestions.length > 0 && ( +
+

+ + 专业建议 +

+
+ {prediction.suggestions.map((suggestion: string, index: number) => ( +
+
+ + {index + 1} + +

{suggestion}

+
+
+ ))} +
+
+ )} + + {/* 时机建议 */} + {prediction.timing_advice && ( +
+

+ + 时机建议 +

+
+ {typeof prediction.timing_advice === 'string' + ? prediction.timing_advice + : ( +
+ {Object.entries(prediction.timing_advice).map(([key, value]) => ( +
+ {getYongShenName(key)}: + {getChineseValue(key, value)} +
+ ))} +
+ ) + } +
+
+ )} +
+ ); + }; + + return ( +
+
+ + {/* 下载按钮和AI解读按钮 */} +
+
+ setShowAIConfig(true)} + /> +
+
+ +
+
+ {/* 页面标题 */} + + + + + 奇门遁甲分析报告 + +

专业奇门遁甲占卜分析

+
+
+ + {/* 占卜基本信息 */} + {basicInfo && ( + + + + + 占卜信息 + + + +
+ {basicInfo.divination_data?.question && ( +
+

+ + 占卜问题 +

+

{basicInfo.divination_data.question}

+
+ )} +
+
+

占卜方法

+

{basicInfo.divination_data?.method || '时家奇门'}

+
+
+

起局时间

+

{new Date(basicInfo.divination_data?.divination_time).toLocaleString('zh-CN')}

+
+ {basicInfo.divination_data?.lunar_info && ( +
+

农历信息

+

{basicInfo.divination_data.lunar_info.description || '农历信息'}

+
+ )} +
+
+
+
+ )} + + {/* 时空信息 */} + {timeInfo && ( + + + + + 时空信息 + + + +
+
+
+

节气

+

{timeInfo.jieqi || '未知'}

+
+
+

+

{timeInfo.yuan || '未知'}

+
+
+

局数

+

{timeInfo.jushu || qimenPan?.jushu || '未知'}

+
+
+

阴阳遁

+

{timeInfo.yindun || (qimenPan?.yindun !== undefined ? (qimenPan.yindun ? '阴遁' : '阳遁') : '未知')}

+
+
+ + {timeInfo.ganzhi && ( +
+

+ + 干支四柱 +

+
+
+
{timeInfo.ganzhi.year?.gan}{timeInfo.ganzhi.year?.zhi}
+
年柱
+
+
+
{timeInfo.ganzhi.month?.gan}{timeInfo.ganzhi.month?.zhi}
+
月柱
+
+
+
{timeInfo.ganzhi.day?.gan}{timeInfo.ganzhi.day?.zhi}
+
日柱
+
+
+
{timeInfo.ganzhi.hour?.gan}{timeInfo.ganzhi.hour?.zhi}
+
时柱
+
+
+
+ )} + + {(timeInfo.zhifu || timeInfo.zhishi) && ( +
+

+ + 值符值使 +

+
+ {timeInfo.zhifu && ( +
+
{timeInfo.zhifu}
+
值符
+
+ )} + {timeInfo.zhishi && ( +
+
{timeInfo.zhishi}
+
值使
+
+ )} +
+
+ )} +
+
+
+ )} + + {/* 奇门盘 */} + + + + + 奇门遁甲盘 + + + +
+ {renderQimenPan()} + +
+
+
+ + {/* 用神分析 */} + {yongShenAnalysis && ( + + + + + 用神分析 + + + +
+ {renderYongShenAnalysis()} +
+
+
+ )} + + {/* 格局识别 */} + {patterns && patterns.length > 0 && ( + + + + + 格局识别 + + + +
+ {renderPatterns()} +
+
+
+ )} + + {/* 预测结果 */} + {prediction && ( + + + + + 预测结果 + + + +
+ {renderPrediction()} +
+
+
+ )} + + {/* 指导建议 */} + {guidance && ( + + + + + 指导建议 + + + +
+
+ {guidance.key_message && ( +
+

+ + 核心信息 +

+
+ {guidance.key_message} +
+
+ )} + + {guidance.action_advice && guidance.action_advice.length > 0 && ( +
+

+ + 行动建议 +

+
    + {guidance.action_advice.map((advice: string, index: number) => ( +
  • + + {advice} +
  • + ))} +
+
+ )} + + {guidance.timing_guidance && ( +
+

+ + 时机指导 +

+
+ {typeof guidance.timing_guidance === 'string' + ? guidance.timing_guidance + : ( +
+ {Object.entries(guidance.timing_guidance).map(([key, value]) => ( +
+ {getYongShenName(key)}: + {getChineseValue(key, value)} +
+ ))} +
+ ) + } +
+
+ )} + + +
+
+
+
+ )} + + {/* 五行分析 */} + {analysis?.detailed_analysis?.wuxing_analysis && ( + + + + + 五行分析 + + + +
+ {/* 五行分析概述 */} +
+

五行分析概述

+

+ 五行分析是奇门遁甲的重要组成部分,通过分析奇门盘中五行要素的分布、强弱和相互关系, + 判断各种力量的平衡状态,为预测和决策提供重要依据。 +

+
+ +
+

五行生克关系分析

+
+ {typeof analysis.detailed_analysis.wuxing_analysis === 'string' + ? ( +

{analysis.detailed_analysis.wuxing_analysis}

+ ) : ( +
+ {Object.entries(analysis.detailed_analysis.wuxing_analysis).map(([key, value]) => { + // 五行分析术语中文映射 + const wuxingTermMap = { + 'dominant': '主导五行', + 'balance': '平衡状态', + 'suggestions': '调和建议', + 'strength': '五行强度', + 'weakness': '五行弱点', + 'harmony': '和谐程度', + 'conflict': '冲突情况', + 'support': '相生关系', + 'restraint': '相克关系', + 'seasonal_influence': '季节影响', + 'overall_assessment': '综合评估' + }; + + const getChineseTerm = (term: string) => { + return wuxingTermMap[term] || term; + }; + + const getChineseValue = (val: any) => { + const valueMap = { + 'balanced': '平衡', + 'strong': '强旺', + 'weak': '衰弱', + 'excessive': '过旺', + 'deficient': '不足', + 'harmonious': '和谐', + 'conflicting': '冲突', + 'favorable': '有利', + 'unfavorable': '不利', + 'moderate': '适中', + 'excellent': '极佳', + 'poor': '较差', + 'good': '良好', + 'average': '一般' + }; + + const strVal = String(val); + return valueMap[strVal] || strVal; + }; + + return ( +
+
+ {getChineseTerm(key)} + + {getChineseValue(value)} + +
+ {key === 'dominant' && ( +

+ 当前奇门盘中{getChineseValue(value)}五行力量最为突出,主导整体格局的发展方向。 +

+ )} + {key === 'balance' && ( +

+ 五行之间的平衡状态为{getChineseValue(value)},影响事情发展的稳定性和持续性。 +

+ )} + {key === 'suggestions' && ( +

+ 建议:{getChineseValue(value)},以达到五行平衡,提升整体运势。 +

+ )} +
+ ); + })} +
+ ) + } +
+
+
+
+
+ )} + + {/* 时机分析 */} + {analysis?.detailed_analysis?.timing_analysis && ( + + + + + 时机分析 + + + +
+ {/* 时机分析概述 */} +
+

时机分析概述

+

+ 时机分析是奇门遁甲预测的核心内容,通过分析天时、地利、人和等因素, + 判断行动的最佳时机,为决策提供时间维度的指导。 +

+
+ +
+

最佳时机判断

+
+ {typeof analysis.detailed_analysis.timing_analysis === 'string' + ? ( +

{analysis.detailed_analysis.timing_analysis}

+ ) : ( +
+ {Object.entries(analysis.detailed_analysis.timing_analysis).map(([key, value]) => { + // 时机分析术语中文映射 + const timingTermMap = { + 'season': '季节时机', + 'favorability': '有利程度', + 'notes': '详细说明', + 'best_time': '最佳时机', + 'avoid_time': '不宜时机', + 'duration': '持续时间', + 'intensity': '影响强度', + 'stability': '稳定性', + 'trend': '发展趋势', + 'opportunity': '机会窗口', + 'risk_level': '风险等级', + 'success_rate': '成功率', + 'timing_score': '时机评分', + 'seasonal_influence': '季节影响', + 'monthly_trend': '月度趋势', + 'daily_guidance': '日常指导' + }; + + const getChineseTerm = (term: string) => { + return timingTermMap[term] || term; + }; + + const getChineseValue = (val: any) => { + const valueMap = { + 'spring': '春季', + 'summer': '夏季', + 'autumn': '秋季', + 'winter': '冬季', + 'favorable': '有利', + 'unfavorable': '不利', + 'neutral': '中性', + 'excellent': '极佳', + 'good': '良好', + 'average': '一般', + 'poor': '较差', + 'high': '高', + 'medium': '中等', + 'low': '低', + 'stable': '稳定', + 'unstable': '不稳定', + 'rising': '上升', + 'falling': '下降', + 'immediate': '立即', + 'soon': '近期', + 'later': '稍后', + 'long_term': '长期' + }; + + const strVal = String(val); + return valueMap[strVal] || strVal; + }; + + const getSeasonDescription = (season: string) => { + const descriptions = { + '春季': '万物复苏,生机勃勃,适合新的开始和发展', + '夏季': '阳气旺盛,活力充沛,适合积极行动和扩展', + '秋季': '收获季节,成果显现,适合总结和收获', + '冬季': '蛰伏养精,积蓄力量,适合规划和准备' + }; + return descriptions[season] || ''; + }; + + return ( +
+
+ {getChineseTerm(key)} + + {getChineseValue(value)} + +
+ + {key === 'season' && ( +
+

+ {getSeasonDescription(getChineseValue(value))} +

+
+ )} + + {key === 'favorability' && ( +
+

+ 当前时机的有利程度为{getChineseValue(value)}, + {String(value).includes('有利') || String(value).includes('favorable') + ? '建议抓住机会,积极行动' + : '建议谨慎观望,等待更好时机' + }。 +

+
+ )} + + {key === 'notes' && ( +
+

+ 详细说明:{getChineseValue(value)} +

+
+ )} +
+ ); + })} +
+ ) + } +
+
+
+
+
+ )} + + {/* 分析报告尾部 */} + + +
+

专业奇门遁甲分析报告

+

分析日期:{analysis.analysis_date ? new Date(analysis.analysis_date).toLocaleString('zh-CN') : new Date().toLocaleString('zh-CN')}

+

+ 本报告基于传统奇门遁甲理论,结合现代命理学研究成果,为您提供专业的占卜分析和人生指导。 +

+
+
+
+ + {/* 回到顶部按钮 */} + + + {/* AI配置模态框 */} + setShowAIConfig(false)} + onConfigSaved={() => { + setShowAIConfig(false); + // 可以在这里添加配置保存后的逻辑 + }} + /> +
+
+ ); +}; + +export default CompleteQimenAnalysis; diff --git a/src/components/ui/DownloadButton.tsx b/src/components/ui/DownloadButton.tsx index 0bd69db..0a6e919 100644 --- a/src/components/ui/DownloadButton.tsx +++ b/src/components/ui/DownloadButton.tsx @@ -11,7 +11,7 @@ export type ExportMode = 'server' | 'frontend'; interface DownloadButtonProps { analysisData: any; - analysisType: 'bazi' | 'ziwei' | 'yijing'; + analysisType: 'bazi' | 'ziwei' | 'yijing' | 'qimen'; userName?: string; onDownload?: (format: DownloadFormat) => Promise; className?: string; @@ -480,6 +480,7 @@ const DownloadButton: React.FC = ({ case 'bazi': return '八字命理'; case 'ziwei': return '紫微斗数'; case 'yijing': return '易经占卜'; + case 'qimen': return '奇门遁甲'; default: return '命理'; } }; diff --git a/src/components/ui/YijingQuestionSelector.tsx b/src/components/ui/YijingQuestionSelector.tsx index 54f2e39..b038916 100644 --- a/src/components/ui/YijingQuestionSelector.tsx +++ b/src/components/ui/YijingQuestionSelector.tsx @@ -8,6 +8,8 @@ interface YijingQuestionSelectorProps { value: string; onChange: (value: string) => void; className?: string; + label?: string; + placeholder?: string; } // 问题分类和预设问题数据 @@ -115,7 +117,9 @@ const questionCategories = { export const YijingQuestionSelector: React.FC = ({ value, onChange, - className + className, + label = '占卜问题', + placeholder = '请输入您要占卜的问题' }) => { const [selectedCategory, setSelectedCategory] = useState(''); const [selectedQuestion, setSelectedQuestion] = useState(''); @@ -261,10 +265,10 @@ variant="default" {/* 主要问题输入框 */} onChange(e.target.value)} - placeholder="请输入您希望占卜的具体问题,或选择上方预设问题" + placeholder={placeholder} required variant="filled" helperText="💡 提示:问题越具体,占卜结果越准确。您可以使用预设问题或自行输入。" diff --git a/src/config/aiConfig.ts b/src/config/aiConfig.ts index ffb1cd4..a9ec286 100644 --- a/src/config/aiConfig.ts +++ b/src/config/aiConfig.ts @@ -68,7 +68,24 @@ export const aiPromptTemplates = { 易经占卜结果: {analysisContent} -请提供智慧的AI解读:` +请提供智慧的AI解读:`, + + qimen: `你是一位精通奇门遁甲的预测大师,请对以下奇门遁甲分析结果进行专业解读。 + +请重点分析: +1. 奇门盘局的整体格局特点 +2. 用神落宫的吉凶分析 +3. 九星八门八神的组合意义 +4. 格局对事情发展的具体影响 +5. 最佳行动时机和策略建议 +6. 需要注意的不利因素 + +请结合现代实际情况,提供具有指导价值的预测分析。 + +奇门遁甲分析结果: +{analysisContent} + +请提供专业的AI解读:` }; // 获取AI配置 @@ -103,6 +120,6 @@ export const validateAIConfig = (config: AIConfig): boolean => { }; // 获取提示词模板 -export const getPromptTemplate = (analysisType: 'bazi' | 'ziwei' | 'yijing'): string => { +export const getPromptTemplate = (analysisType: 'bazi' | 'ziwei' | 'yijing' | 'qimen'): string => { return aiPromptTemplates[analysisType] || aiPromptTemplates.bazi; }; \ No newline at end of file diff --git a/src/lib/localApi.ts b/src/lib/localApi.ts index df26d7c..5e75140 100644 --- a/src/lib/localApi.ts +++ b/src/lib/localApi.ts @@ -264,6 +264,14 @@ class LocalApiClient { }, yijingData); }, + // 奇门遁甲分析 + qimen: async (qimenData: any): Promise> => { + return this.requestWithDeduplication<{ record_id: number; analysis: any }>('/qimen/analyze', { + method: 'POST', + body: JSON.stringify(qimenData), + }, qimenData); + }, + // 综合分析 comprehensive: async (birthData: any, includeTypes?: string[]): Promise> => { return this.request<{ record_id: number; analysis: any }>('/analysis/comprehensive', { diff --git a/src/pages/AnalysisPage.tsx b/src/pages/AnalysisPage.tsx index 8f2d2be..0927136 100644 --- a/src/pages/AnalysisPage.tsx +++ b/src/pages/AnalysisPage.tsx @@ -8,11 +8,11 @@ import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle } import YijingQuestionSelector from '../components/ui/YijingQuestionSelector'; import AnalysisResultDisplay from '../components/AnalysisResultDisplay'; import { toast } from 'sonner'; -import { Sparkles, Star, Compass, Calendar, MapPin, User, Loader2 } from 'lucide-react'; +import { Sparkles, Star, Compass, Calendar, MapPin, User, Loader2, Hexagon } from 'lucide-react'; import { UserProfile, AnalysisRequest, NumerologyReading } from '../types'; import { cn } from '../lib/utils'; -type AnalysisType = 'bazi' | 'ziwei' | 'yijing'; +type AnalysisType = 'bazi' | 'ziwei' | 'yijing' | 'qimen'; const AnalysisPage: React.FC = () => { const { user } = useAuth(); @@ -32,7 +32,7 @@ const AnalysisPage: React.FC = () => { // 使用useMemo缓存birthDate对象,避免重复渲染导致useEffect重复执行 const memoizedBirthDate = useMemo(() => { - if (analysisType === 'bazi' || analysisType === 'ziwei') { + if (analysisType === 'bazi' || analysisType === 'ziwei' || analysisType === 'qimen') { return { date: formData.birth_date, time: formData.birth_time, @@ -83,6 +83,15 @@ const AnalysisPage: React.FC = () => { toast.error('请填写占卜问题'); return; } + } else if (analysisType === 'qimen') { + if (!formData.question) { + toast.error('请填写占卜问题'); + return; + } + if (!formData.birth_date || !formData.birth_time) { + toast.error('奇门遁甲需要准确的出生日期和时间'); + return; + } } else { if (!formData.name || !formData.birth_date) { toast.error('请填写姓名和出生日期'); @@ -123,6 +132,16 @@ const AnalysisPage: React.FC = () => { response = await localApi.analysis.yijing(yijingData); break; } + case 'qimen': { + const qimenData = { + ...birthData, + question: formData.question, + user_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + local_time: new Date().toISOString() + }; + response = await localApi.analysis.qimen(qimenData); + break; + } default: throw new Error(`不支持的分析类型: ${analysisType}`); } @@ -215,6 +234,15 @@ const AnalysisPage: React.FC = () => { color: 'text-orange-600', bgColor: 'bg-orange-50', borderColor: 'border-orange-300' + }, + { + type: 'qimen' as AnalysisType, + title: '奇门遁甲', + description: '古代帝王之学,通过时空奇门盘分析事物发展趋势', + icon: Hexagon, + color: 'text-purple-600', + bgColor: 'bg-purple-50', + borderColor: 'border-purple-300' } ]; @@ -233,7 +261,7 @@ const AnalysisPage: React.FC = () => {

选择您感兴趣的命理分析方式

-
+
{analysisTypes.map((type) => { const Icon = type.icon; const isSelected = analysisType === type.type; @@ -291,6 +319,52 @@ const AnalysisPage: React.FC = () => { onChange={(value) => setFormData(prev => ({ ...prev, question: value }))} />
+ ) : analysisType === 'qimen' ? ( + // 奇门遁甲表单 + <> +
+ setFormData(prev => ({ ...prev, question: value }))} + placeholder="请输入您要占卜的问题,如:事业发展、投资决策、感情婚姻等" + label="占卜问题" + /> +
+ +
+
+ { + const value = e.target.value; + if (value && !/^\d{4}-\d{2}-\d{2}$/.test(value)) { + return; + } + setFormData(prev => ({ ...prev, birth_date: value })); + }} + min="1900-01-01" + max="2100-12-31" + required + variant="filled" + className="pr-10" + helperText="奇门遁甲需要准确的出生日期" + /> + +
+ + setFormData(prev => ({ ...prev, birth_time: e.target.value }))} + required + variant="filled" + helperText="奇门遁甲必须填写准确的出生时间" + /> +
+ ) : ( // 八字和紫微表单 <> @@ -402,9 +476,10 @@ const AnalysisPage: React.FC = () => { analysisResult={analysisResult} analysisType={analysisType} birthDate={memoizedBirthDate} - question={analysisType === 'yijing' ? formData.question : undefined} + question={analysisType === 'yijing' || analysisType === 'qimen' ? formData.question : undefined} userId={user?.id?.toString()} divinationMethod="time" + preAnalysisData={analysisResult.data} recordId={analysisResult.recordId} />
diff --git a/src/pages/HistoryPage.tsx b/src/pages/HistoryPage.tsx index d6a2040..6913346 100644 --- a/src/pages/HistoryPage.tsx +++ b/src/pages/HistoryPage.tsx @@ -8,7 +8,7 @@ import { ChineseLoading } from '../components/ui/ChineseLoading'; import AnalysisResultDisplay from '../components/AnalysisResultDisplay'; import DownloadButton from '../components/ui/DownloadButton'; import { toast } from 'sonner'; -import { History, Calendar, User, Sparkles, Star, Compass, Eye, Trash2, Download, ChevronLeft, ChevronRight } from 'lucide-react'; +import { History, Calendar, User, Sparkles, Star, Compass, Hexagon, Eye, Trash2, Download, ChevronLeft, ChevronRight } from 'lucide-react'; import { NumerologyReading } from '../types'; import { cn } from '../lib/utils'; @@ -145,6 +145,7 @@ const HistoryPage: React.FC = () => { case 'bazi': return Sparkles; case 'ziwei': return Star; case 'yijing': return Compass; + case 'qimen': return Hexagon; default: return History; } }; @@ -154,6 +155,7 @@ const HistoryPage: React.FC = () => { case 'bazi': return 'text-red-600 bg-red-50'; case 'ziwei': return 'text-yellow-600 bg-yellow-50'; case 'yijing': return 'text-orange-600 bg-orange-50'; + case 'qimen': return 'text-purple-600 bg-purple-50'; default: return 'text-gray-600 bg-gray-50'; } }; @@ -163,6 +165,7 @@ const HistoryPage: React.FC = () => { case 'bazi': return '八字命理'; case 'ziwei': return '紫微斗数'; case 'yijing': return '易经占卜'; + case 'qimen': return '奇门遁甲'; default: return '未知类型'; } }; @@ -210,14 +213,14 @@ const HistoryPage: React.FC = () => { { ...(reading.analysis || reading.results), created_at: reading.created_at }} - analysisType={reading.reading_type as 'bazi' | 'ziwei' | 'yijing'} + analysisType={reading.reading_type as 'bazi' | 'ziwei' | 'yijing' | 'qimen'} userName={reading.name} className="min-h-[40px] px-2 sm:px-6 py-2.5 text-xs sm:text-sm flex-shrink-0" /> diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 650c633..bed3f22 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { Sparkles, Star, Compass, Heart, BarChart3, BookOpen, Shield, Zap, Users, Award, Brain, TrendingUp } from 'lucide-react'; +import { Sparkles, Star, Compass, Hexagon, Heart, BarChart3, BookOpen, Shield, Zap, Users, Award, Brain, TrendingUp } from 'lucide-react'; import { ChineseButton } from '../components/ui/ChineseButton'; import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle } from '../components/ui/ChineseCard'; import { useAuth } from '../contexts/AuthContext'; @@ -35,6 +35,15 @@ const HomePage: React.FC = () => { bgColor: 'chinese-golden-glow', iconBg: 'bg-gradient-to-br from-yellow-400 to-amber-500', link: '/analysis' + }, + { + icon: Hexagon, + title: '奇门遁甲', + description: '古代帝王之学,通过时空奇门盘分析事物发展趋势。结合九星八门八神布局,为重要决策提供战略指导', + color: 'text-red-700', + bgColor: 'chinese-golden-glow', + iconBg: 'bg-gradient-to-br from-yellow-400 to-amber-500', + link: '/analysis' } ]; diff --git a/src/services/aiInterpretationService.ts b/src/services/aiInterpretationService.ts index d57e58e..21617ff 100644 --- a/src/services/aiInterpretationService.ts +++ b/src/services/aiInterpretationService.ts @@ -12,7 +12,7 @@ export interface AIInterpretationResult { // AI解读请求参数 export interface AIInterpretationRequest { - analysisType: 'bazi' | 'ziwei' | 'yijing'; + analysisType: 'bazi' | 'ziwei' | 'yijing' | 'qimen'; analysisContent: any; // 改为any类型,支持对象数据 customPrompt?: string; onStreamUpdate?: (content: string) => void; // 流式更新回调 @@ -34,6 +34,9 @@ export const convertAnalysisToMarkdown = (analysisData: any, analysisType: strin case 'yijing': markdown += generateYijingMarkdown(analysisData); break; + case 'qimen': + markdown += generateQimenMarkdown(analysisData); + break; default: markdown += JSON.stringify(analysisData, null, 2); } @@ -578,12 +581,113 @@ const generateYijingMarkdown = (data: any): string => { return markdown; }; +// 生成奇门遁甲分析的Markdown +const generateQimenMarkdown = (data: any): string => { + const timestamp = new Date().toLocaleString('zh-CN'); + let markdown = `## 奇门遁甲分析报告\n\n**分析时间:** ${timestamp}\n\n`; + + try { + // 基本信息 + if (data.timeInfo) { + markdown += `### 时空信息\n\n`; + if (data.timeInfo.jieqi) markdown += `**节气:** ${data.timeInfo.jieqi}\n`; + if (data.qimenPan?.jushu) markdown += `**局数:** ${data.qimenPan.jushu}局\n`; + if (data.qimenPan?.yindun !== undefined) { + markdown += `**阴阳遁:** ${data.qimenPan.yindun ? '阴遁' : '阳遁'}\n`; + } + if (data.timeInfo.hour) { + markdown += `**时辰:** ${data.timeInfo.hour.gan}${data.timeInfo.hour.zhi}时\n`; + } + markdown += `\n`; + } + + // 奇门盘信息 + if (data.qimenPan && data.qimenPan.dipan) { + markdown += `### 奇门盘布局\n\n`; + const palaceNames = ['坎一宫', '坤二宫', '震三宫', '巽四宫', '中五宫', '乾六宫', '兑七宫', '艮八宫', '离九宫']; + + data.qimenPan.dipan.forEach((palace: any, index: number) => { + if (palace) { + markdown += `**${palaceNames[index]}:**\n`; + if (palace.star) markdown += `- 九星:${palace.star}\n`; + if (palace.door) markdown += `- 八门:${palace.door}\n`; + if (palace.god) markdown += `- 八神:${palace.god}\n`; + markdown += `\n`; + } + }); + } + + // 用神分析 + if (data.yongShenAnalysis) { + markdown += `### 用神分析\n\n`; + + if (data.yongShenAnalysis.primary) { + markdown += `**主用神:**\n`; + Object.entries(data.yongShenAnalysis.primary).forEach(([key, value]) => { + markdown += `- ${key}:${value}\n`; + }); + markdown += `\n`; + } + + if (data.yongShenAnalysis.secondary) { + markdown += `**次用神:**\n`; + Object.entries(data.yongShenAnalysis.secondary).forEach(([key, value]) => { + markdown += `- ${key}:${value}\n`; + }); + markdown += `\n`; + } + + if (data.yongShenAnalysis.overall) { + markdown += `**综合分析:**\n${data.yongShenAnalysis.overall}\n\n`; + } + } + + // 格局识别 + if (data.patterns && data.patterns.length > 0) { + markdown += `### 格局识别\n\n`; + data.patterns.forEach((pattern: any, index: number) => { + markdown += `**${pattern.name}** (${pattern.type === 'auspicious' ? '吉格' : '凶格'})\n`; + if (pattern.description) markdown += `${pattern.description}\n`; + if (pattern.influence) markdown += `影响:${pattern.influence}\n`; + markdown += `\n`; + }); + } + + // 预测结果 + if (data.prediction) { + markdown += `### 预测结果\n\n`; + + if (data.prediction.probability) { + markdown += `**成功概率:** ${data.prediction.probability}%\n\n`; + } + + if (data.prediction.analysis) { + markdown += `**详细分析:**\n${data.prediction.analysis}\n\n`; + } + + if (data.prediction.suggestions && data.prediction.suggestions.length > 0) { + markdown += `**建议:**\n`; + data.prediction.suggestions.forEach((suggestion: string) => { + markdown += `- ${suggestion}\n`; + }); + markdown += `\n`; + } + } + + } catch (error) { + markdown += `\n**原始数据:**\n\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\`\n`; + } + + return markdown; +}; + // 获取分析类型标题 const getAnalysisTitle = (analysisType: string): string => { const titles = { 'bazi': '八字命理', 'ziwei': '紫微斗数', - 'yijing': '易经占卜' + 'yijing': '易经占卜', + 'qimen': '奇门遁甲' }; return titles[analysisType as keyof typeof titles] || '命理'; }; diff --git a/src/types/index.ts b/src/types/index.ts index f849d15..f082aca 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -15,7 +15,7 @@ export interface UserProfile { export interface AnalysisRecord { id: number; user_id: number; - analysis_type: 'bazi' | 'ziwei' | 'yijing'; + analysis_type: 'bazi' | 'ziwei' | 'yijing' | 'qimen'; name: string; birth_date: string; birth_time?: string; @@ -32,7 +32,7 @@ export interface NumerologyReading { id: number; user_id: number; profile_id?: string; - reading_type: 'bazi' | 'ziwei' | 'yijing' | 'comprehensive'; + reading_type: 'bazi' | 'ziwei' | 'yijing' | 'qimen' | 'comprehensive'; name: string; birth_date: string; birth_time?: string; @@ -43,6 +43,7 @@ export interface NumerologyReading { bazi?: { bazi_analysis: any }; ziwei?: { ziwei_analysis: any }; yijing?: { yijing_analysis: any }; + qimen?: { qimen_analysis: any }; metadata: { analysis_time: string; version: string; diff --git a/update_qimen_constraint.sql b/update_qimen_constraint.sql new file mode 100644 index 0000000..4b5054a --- /dev/null +++ b/update_qimen_constraint.sql @@ -0,0 +1,40 @@ +-- 更新numerology_readings表的CHECK约束以支持qimen类型 +-- 由于SQLite不支持直接修改CHECK约束,需要重建表 + +BEGIN TRANSACTION; + +-- 创建临时表,包含新的CHECK约束 +CREATE TABLE numerology_readings_temp ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + reading_type TEXT NOT NULL CHECK (reading_type IN ('bazi', 'ziwei', 'yijing', 'wuxing', 'qimen')), + name TEXT, + birth_date TEXT, + birth_time TEXT, + birth_place TEXT, + gender TEXT, + input_data TEXT, + results TEXT, + analysis TEXT, + status TEXT DEFAULT 'completed' CHECK (status IN ('pending', 'processing', 'completed', 'failed')), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); + +-- 复制现有数据到临时表 +INSERT INTO numerology_readings_temp +SELECT id, user_id, reading_type, name, birth_date, birth_time, birth_place, gender, + input_data, results, analysis, status, created_at, updated_at +FROM numerology_readings; + +-- 删除原表 +DROP TABLE numerology_readings; + +-- 重命名临时表为原表名 +ALTER TABLE numerology_readings_temp RENAME TO numerology_readings; + +COMMIT; + +-- 验证更新 +SELECT name FROM sqlite_master WHERE type='table' AND name='numerology_readings'; \ No newline at end of file