mirror of
https://github.com/patdelphi/suanming.git
synced 2026-02-28 05:33:11 +08:00
Fix AI interpretation button issues and animation conflicts
- Fix AI interpretation recordId parameter passing for all analysis types - Resolve double border issue in AI interpretation results display - Fix animation conflicts causing visual duplication - Update component interfaces to support recordId parameter - Add AI interpretation status indicators in history page - Disable conflicting animations in AI result containers
This commit is contained in:
@@ -17,6 +17,7 @@ interface AnalysisResultDisplayProps {
|
||||
userId?: string;
|
||||
divinationMethod?: string;
|
||||
preAnalysisData?: any; // 预先分析的数据,用于历史记录
|
||||
recordId?: number; // 历史记录ID,用于AI解读
|
||||
}
|
||||
|
||||
const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
@@ -26,7 +27,8 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
question,
|
||||
userId,
|
||||
divinationMethod,
|
||||
preAnalysisData
|
||||
preAnalysisData,
|
||||
recordId
|
||||
}) => {
|
||||
// 安全地获取数据的辅助函数
|
||||
const safeGet = (obj: any, path: string, defaultValue: any = '暂无数据') => {
|
||||
@@ -62,7 +64,7 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
const renderBaziAnalysis = () => {
|
||||
// 如果有 birthDate,使用新的 CompleteBaziAnalysis 组件
|
||||
if (birthDate) {
|
||||
return <CompleteBaziAnalysis birthDate={birthDate} analysisData={preAnalysisData} />;
|
||||
return <CompleteBaziAnalysis birthDate={birthDate} analysisData={preAnalysisData} recordId={recordId} />;
|
||||
}
|
||||
// 如果有分析结果但没有 birthDate,尝试从结果中提取出生信息
|
||||
if (analysisResult && analysisResult.data) {
|
||||
@@ -74,7 +76,7 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
name: basicInfo.personal_data.name || '',
|
||||
gender: basicInfo.personal_data.gender === '男性' ? 'male' : 'female'
|
||||
};
|
||||
return <CompleteBaziAnalysis birthDate={extractedBirthDate} analysisData={preAnalysisData} />;
|
||||
return <CompleteBaziAnalysis birthDate={extractedBirthDate} analysisData={preAnalysisData} recordId={recordId} />;
|
||||
}
|
||||
}
|
||||
// 如果没有足够的数据,返回错误提示
|
||||
@@ -89,7 +91,7 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
const renderZiweiAnalysis = () => {
|
||||
// 如果有 birthDate,使用新的 CompleteZiweiAnalysis 组件
|
||||
if (birthDate) {
|
||||
return <CompleteZiweiAnalysis birthDate={birthDate} analysisData={preAnalysisData} />;
|
||||
return <CompleteZiweiAnalysis birthDate={birthDate} analysisData={preAnalysisData} recordId={recordId} />;
|
||||
}
|
||||
// 如果有分析结果但没有 birthDate,尝试从结果中提取出生信息
|
||||
if (analysisResult && analysisResult.data) {
|
||||
@@ -101,7 +103,7 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
name: basicInfo.personal_data.name || '',
|
||||
gender: basicInfo.personal_data.gender === '男性' ? 'male' : 'female'
|
||||
};
|
||||
return <CompleteZiweiAnalysis birthDate={extractedBirthDate} analysisData={preAnalysisData} />;
|
||||
return <CompleteZiweiAnalysis birthDate={extractedBirthDate} analysisData={preAnalysisData} recordId={recordId} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +263,8 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
question={question}
|
||||
userId={userId}
|
||||
divinationMethod={divinationMethod}
|
||||
analysisData={preAnalysisData}
|
||||
recordId={recordId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -274,6 +278,8 @@ const AnalysisResultDisplay: React.FC<AnalysisResultDisplayProps> = ({
|
||||
question={basicInfo.divination_data.question || '综合运势如何?'}
|
||||
userId={userId || 'user123'}
|
||||
divinationMethod={divinationMethod || 'time'}
|
||||
analysisData={preAnalysisData}
|
||||
recordId={recordId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,10 @@ interface CompleteBaziAnalysisProps {
|
||||
gender?: string;
|
||||
};
|
||||
analysisData?: any; // 可选的预先分析的数据
|
||||
recordId?: number; // 历史记录ID,用于AI解读
|
||||
}
|
||||
|
||||
const CompleteBaziAnalysis: React.FC<CompleteBaziAnalysisProps> = ({ birthDate, analysisData: propAnalysisData }) => {
|
||||
const CompleteBaziAnalysis: React.FC<CompleteBaziAnalysisProps> = ({ birthDate, analysisData: propAnalysisData, recordId }) => {
|
||||
const [isLoading, setIsLoading] = useState(!propAnalysisData);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [analysisData, setAnalysisData] = useState<any>(propAnalysisData || null);
|
||||
@@ -286,6 +287,7 @@ const CompleteBaziAnalysis: React.FC<CompleteBaziAnalysisProps> = ({ birthDate,
|
||||
<AIInterpretationButton
|
||||
analysisData={analysisData}
|
||||
analysisType="bazi"
|
||||
analysisId={recordId?.toString()}
|
||||
onConfigClick={() => setShowAIConfig(true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -12,13 +12,15 @@ interface CompleteYijingAnalysisProps {
|
||||
userId?: string;
|
||||
divinationMethod?: string;
|
||||
analysisData?: any; // 可选的预先分析的数据
|
||||
recordId?: number; // 历史记录ID,用于AI解读
|
||||
}
|
||||
|
||||
const CompleteYijingAnalysis: React.FC<CompleteYijingAnalysisProps> = ({
|
||||
question,
|
||||
userId = 'user123',
|
||||
divinationMethod = 'time',
|
||||
analysisData: propAnalysisData
|
||||
analysisData: propAnalysisData,
|
||||
recordId
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState(!propAnalysisData);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -274,6 +276,7 @@ const CompleteYijingAnalysis: React.FC<CompleteYijingAnalysisProps> = ({
|
||||
<AIInterpretationButton
|
||||
analysisData={analysisData}
|
||||
analysisType="yijing"
|
||||
analysisId={recordId?.toString()}
|
||||
onConfigClick={() => setShowAIConfig(true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,10 @@ interface CompleteZiweiAnalysisProps {
|
||||
gender?: string;
|
||||
};
|
||||
analysisData?: any; // 可选的预先分析的数据
|
||||
recordId?: number; // 历史记录ID,用于AI解读
|
||||
}
|
||||
|
||||
const CompleteZiweiAnalysis: React.FC<CompleteZiweiAnalysisProps> = ({ birthDate, analysisData: propAnalysisData }) => {
|
||||
const CompleteZiweiAnalysis: React.FC<CompleteZiweiAnalysisProps> = ({ birthDate, analysisData: propAnalysisData, recordId }) => {
|
||||
const [isLoading, setIsLoading] = useState(!propAnalysisData);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [analysisData, setAnalysisData] = useState<any>(propAnalysisData || null);
|
||||
@@ -589,6 +590,7 @@ const CompleteZiweiAnalysis: React.FC<CompleteZiweiAnalysisProps> = ({ birthDate
|
||||
<AIInterpretationButton
|
||||
analysisData={analysisData}
|
||||
analysisType="ziwei"
|
||||
analysisId={recordId?.toString()}
|
||||
onConfigClick={() => setShowAIConfig(true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -277,19 +277,19 @@ const AIInterpretationButton: React.FC<AIInterpretationButtonProps> = ({
|
||||
|
||||
{/* AI解读结果显示 */}
|
||||
{(interpretation || streamingContent) && showResult && (
|
||||
<ChineseCard className="w-full border-2 border-purple-200 bg-gradient-to-br from-purple-50 to-blue-50">
|
||||
<ChineseCardHeader>
|
||||
<ChineseCardTitle className="flex items-center space-x-2 text-purple-800">
|
||||
<div className="w-full border-2 border-purple-200 bg-gradient-to-br from-purple-50 to-blue-50 rounded-lg shadow-sm" style={{transform: 'none', animation: 'none', transition: 'none'}}>
|
||||
<div className="p-4 border-b border-purple-200">
|
||||
<div className="flex items-center space-x-2 text-purple-800">
|
||||
{isLoading ? (
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
) : (
|
||||
<Sparkles className="h-5 w-5" />
|
||||
)}
|
||||
<span>AI智能解读 - {getAnalysisTypeName(analysisType)}</span>
|
||||
<span className="text-lg font-semibold">AI智能解读 - {getAnalysisTypeName(analysisType)}</span>
|
||||
{isLoading && streamingContent && (
|
||||
<span className="ml-2 text-sm font-normal text-purple-600">正在生成中...</span>
|
||||
)}
|
||||
</ChineseCardTitle>
|
||||
</div>
|
||||
{interpretation && (
|
||||
<div className="flex items-center space-x-4 text-xs text-gray-500 mt-2">
|
||||
<span>解读时间: {new Date(interpretation.timestamp).toLocaleString('zh-CN')}</span>
|
||||
@@ -297,8 +297,8 @@ const AIInterpretationButton: React.FC<AIInterpretationButtonProps> = ({
|
||||
{interpretation.tokensUsed && <span>消耗Token: {interpretation.tokensUsed}</span>}
|
||||
</div>
|
||||
)}
|
||||
</ChineseCardHeader>
|
||||
<ChineseCardContent>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
{interpretation && !interpretation.success ? (
|
||||
<div className="flex items-center space-x-2 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<AlertCircle className="h-4 w-4 text-red-600 flex-shrink-0" />
|
||||
@@ -371,11 +371,10 @@ const AIInterpretationButton: React.FC<AIInterpretationButtonProps> = ({
|
||||
</ReactMarkdown>
|
||||
{isLoading && streamingContent && (
|
||||
<span className="inline-block w-2 h-5 bg-purple-600 animate-pulse ml-1"></span>
|
||||
)} </div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</ChineseCardContent>
|
||||
</ChineseCard>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
278
src/components/ui/YijingQuestionSelector.tsx
Normal file
278
src/components/ui/YijingQuestionSelector.tsx
Normal file
@@ -0,0 +1,278 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ChineseInput } from './ChineseInput';
|
||||
import { ChineseSelect } from './ChineseSelect';
|
||||
import { ChineseButton } from './ChineseButton';
|
||||
import { Lightbulb, RefreshCw } from 'lucide-react';
|
||||
|
||||
interface YijingQuestionSelectorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// 问题分类和预设问题数据
|
||||
const questionCategories = {
|
||||
career: {
|
||||
name: '事业发展',
|
||||
icon: '💼',
|
||||
questions: [
|
||||
'我的事业发展前景如何?',
|
||||
'现在是否适合换工作?',
|
||||
'我应该选择哪个职业方向?',
|
||||
'创业的时机是否成熟?',
|
||||
'如何提升我的职场竞争力?',
|
||||
'我的工作能力能否得到认可?',
|
||||
'是否应该接受这个工作机会?',
|
||||
'我的事业何时能有突破?'
|
||||
]
|
||||
},
|
||||
love: {
|
||||
name: '感情婚姻',
|
||||
icon: '💕',
|
||||
questions: [
|
||||
'我的感情运势如何?',
|
||||
'现在的恋情能否修成正果?',
|
||||
'我何时能遇到真爱?',
|
||||
'这段感情是否值得继续?',
|
||||
'如何改善我们的关系?',
|
||||
'我应该主动表白吗?',
|
||||
'婚姻生活会幸福吗?',
|
||||
'如何处理感情中的矛盾?'
|
||||
]
|
||||
},
|
||||
wealth: {
|
||||
name: '财运投资',
|
||||
icon: '💰',
|
||||
questions: [
|
||||
'我的财运发展如何?',
|
||||
'这项投资是否明智?',
|
||||
'如何改善我的财务状况?',
|
||||
'现在适合创业吗?',
|
||||
'我的理财方向是否正确?',
|
||||
'何时能实现财务自由?',
|
||||
'这个商业机会值得把握吗?',
|
||||
'如何增加我的收入来源?'
|
||||
]
|
||||
},
|
||||
health: {
|
||||
name: '健康养生',
|
||||
icon: '🏥',
|
||||
questions: [
|
||||
'我的健康状况如何?',
|
||||
'如何改善我的身体状况?',
|
||||
'这个治疗方案是否有效?',
|
||||
'我需要注意哪些健康问题?',
|
||||
'如何调理我的身心状态?',
|
||||
'什么运动最适合我?',
|
||||
'我的饮食习惯需要调整吗?',
|
||||
'如何预防疾病的发生?'
|
||||
]
|
||||
},
|
||||
study: {
|
||||
name: '学业考试',
|
||||
icon: '📚',
|
||||
questions: [
|
||||
'我的学习成绩能否提升?',
|
||||
'这次考试能否顺利通过?',
|
||||
'应该选择哪个专业方向?',
|
||||
'如何提高学习效率?',
|
||||
'是否应该继续深造?',
|
||||
'我的学习方法是否正确?',
|
||||
'何时是最佳的考试时机?',
|
||||
'如何克服学习中的困难?'
|
||||
]
|
||||
},
|
||||
family: {
|
||||
name: '家庭生活',
|
||||
icon: '🏠',
|
||||
questions: [
|
||||
'我的家庭关系如何?',
|
||||
'如何处理家庭矛盾?',
|
||||
'子女教育应该注意什么?',
|
||||
'如何改善与父母的关系?',
|
||||
'家庭财务规划是否合理?',
|
||||
'搬家的时机是否合适?',
|
||||
'如何营造和谐的家庭氛围?',
|
||||
'家人的健康状况如何?'
|
||||
]
|
||||
},
|
||||
general: {
|
||||
name: '综合运势',
|
||||
icon: '🔮',
|
||||
questions: [
|
||||
'我的整体运势如何?',
|
||||
'近期需要注意什么?',
|
||||
'如何把握人生机遇?',
|
||||
'我的人生方向是否正确?',
|
||||
'如何化解当前的困境?',
|
||||
'什么时候运势会好转?',
|
||||
'我应该如何规划未来?',
|
||||
'如何提升我的整体运势?'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export const YijingQuestionSelector: React.FC<YijingQuestionSelectorProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
className
|
||||
}) => {
|
||||
const [selectedCategory, setSelectedCategory] = useState<string>('');
|
||||
const [selectedQuestion, setSelectedQuestion] = useState<string>('');
|
||||
const [showPresets, setShowPresets] = useState<boolean>(true);
|
||||
|
||||
// 分类选项
|
||||
const categoryOptions = Object.entries(questionCategories).map(([key, category]) => ({
|
||||
value: key,
|
||||
label: `${category.icon} ${category.name}`
|
||||
}));
|
||||
|
||||
// 当选择分类时,更新问题选项
|
||||
const questionOptions = selectedCategory && questionCategories[selectedCategory as keyof typeof questionCategories]
|
||||
? questionCategories[selectedCategory as keyof typeof questionCategories].questions.map((question, index) => ({
|
||||
value: question,
|
||||
label: question
|
||||
}))
|
||||
: [];
|
||||
|
||||
// 处理分类选择
|
||||
const handleCategoryChange = (category: string) => {
|
||||
setSelectedCategory(category);
|
||||
setSelectedQuestion('');
|
||||
// 选择分类后自动显示预设问题
|
||||
if (category) {
|
||||
setShowPresets(true);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理预设问题选择
|
||||
const handleQuestionSelect = (question: string) => {
|
||||
setSelectedQuestion(question);
|
||||
onChange(question);
|
||||
};
|
||||
|
||||
// 随机选择问题
|
||||
const handleRandomQuestion = () => {
|
||||
const allQuestions = Object.values(questionCategories).flatMap(category => category.questions);
|
||||
const randomQuestion = allQuestions[Math.floor(Math.random() * allQuestions.length)];
|
||||
onChange(randomQuestion);
|
||||
setSelectedQuestion(randomQuestion);
|
||||
|
||||
// 找到对应的分类
|
||||
const categoryKey = Object.entries(questionCategories).find(([_, category]) =>
|
||||
category.questions.includes(randomQuestion)
|
||||
)?.[0];
|
||||
if (categoryKey) {
|
||||
setSelectedCategory(categoryKey);
|
||||
}
|
||||
};
|
||||
|
||||
// 切换预设问题显示
|
||||
const togglePresets = () => {
|
||||
setShowPresets(!showPresets);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{/* 预设问题选择区域 */}
|
||||
<div className="mb-6 space-y-4">
|
||||
{/* 控制按钮 */}
|
||||
<div className="flex items-center space-x-3">
|
||||
<ChineseButton
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={togglePresets}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Lightbulb className="h-4 w-4" />
|
||||
<span>{showPresets ? '隐藏预设问题' : '选择预设问题'}</span>
|
||||
</ChineseButton>
|
||||
|
||||
<ChineseButton
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleRandomQuestion}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
<span>随机问题</span>
|
||||
</ChineseButton>
|
||||
</div>
|
||||
|
||||
{/* 预设问题选择界面 */}
|
||||
{showPresets && (
|
||||
<div className="bg-gradient-to-br from-amber-50 to-yellow-50 p-4 rounded-lg border border-amber-200">
|
||||
<h4 className="font-semibold text-amber-800 mb-3 flex items-center">
|
||||
<span className="mr-2">🎯</span>
|
||||
选择问题类别和预设问题
|
||||
</h4>
|
||||
|
||||
{/* 分类选择 */}
|
||||
<div className="mb-4">
|
||||
<ChineseSelect
|
||||
label="问题类别"
|
||||
value={selectedCategory}
|
||||
onChange={(e) => handleCategoryChange(e.target.value)}
|
||||
options={[
|
||||
{ value: '', label: '请选择问题类别' },
|
||||
...categoryOptions
|
||||
]}
|
||||
variant="default"
|
||||
className="mb-3 [&_select]:!bg-blue-50 [&_select]:!border-blue-200 [&_select:hover]:!bg-blue-100 [&_select:focus]:!bg-white [&_select:focus]:!border-blue-500 [&_select:focus]:!ring-blue-500/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 预设问题选择 */}
|
||||
{selectedCategory && questionOptions.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<ChineseSelect
|
||||
label="预设问题"
|
||||
value={selectedQuestion}
|
||||
onChange={(e) => handleQuestionSelect(e.target.value)}
|
||||
options={[
|
||||
{ value: '', label: '请选择预设问题' },
|
||||
...questionOptions
|
||||
]}
|
||||
variant="filled"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 快速选择按钮 */}
|
||||
{selectedCategory && questionOptions.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-amber-700 font-medium">或点击快速选择:</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
{questionOptions.slice(0, 6).map((option, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => handleQuestionSelect(option.value)}
|
||||
className="text-left p-2 text-sm bg-white hover:bg-amber-100 border border-amber-200 rounded-lg transition-colors duration-200 text-amber-800 hover:text-amber-900"
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 主要问题输入框 */}
|
||||
<ChineseInput
|
||||
label="占卜问题"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder="请输入您希望占卜的具体问题,或选择上方预设问题"
|
||||
required
|
||||
variant="filled"
|
||||
helperText="💡 提示:问题越具体,占卜结果越准确。您可以使用预设问题或自行输入。"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default YijingQuestionSelector;
|
||||
@@ -5,6 +5,7 @@ import { ChineseButton } from '../components/ui/ChineseButton';
|
||||
import { ChineseInput } from '../components/ui/ChineseInput';
|
||||
import { ChineseSelect } from '../components/ui/ChineseSelect';
|
||||
import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle } from '../components/ui/ChineseCard';
|
||||
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';
|
||||
@@ -24,7 +25,7 @@ const AnalysisPage: React.FC = () => {
|
||||
birth_time: '',
|
||||
gender: 'male' as 'male' | 'female',
|
||||
birth_place: '',
|
||||
question: '财运'
|
||||
question: ''
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [analysisResult, setAnalysisResult] = useState<any>(null);
|
||||
@@ -56,7 +57,7 @@ const AnalysisPage: React.FC = () => {
|
||||
birth_time: data.birth_time || '',
|
||||
gender: data.gender || 'male',
|
||||
birth_place: data.birth_location || '',
|
||||
question: '财运'
|
||||
question: ''
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -139,10 +140,38 @@ const AnalysisPage: React.FC = () => {
|
||||
// 后端返回格式: { data: { analysis } }
|
||||
const analysisData = data.analysis;
|
||||
|
||||
// 保存历史记录
|
||||
try {
|
||||
const saveResponse = await localApi.request('/analysis/save-history', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
analysis_type: analysisType,
|
||||
analysis_data: analysisData,
|
||||
input_data: analysisType === 'yijing' ? { question: formData.question } : birthData
|
||||
})
|
||||
});
|
||||
|
||||
if (saveResponse.data?.record_id) {
|
||||
// 将record_id添加到分析结果中,用于AI解读
|
||||
setAnalysisResult({
|
||||
type: analysisType,
|
||||
data: analysisData,
|
||||
recordId: saveResponse.data.record_id
|
||||
});
|
||||
} else {
|
||||
setAnalysisResult({
|
||||
type: analysisType,
|
||||
data: analysisData
|
||||
});
|
||||
}
|
||||
} catch (saveError) {
|
||||
console.error('保存历史记录失败:', saveError);
|
||||
// 即使保存失败,也显示分析结果
|
||||
setAnalysisResult({
|
||||
type: analysisType,
|
||||
data: analysisData
|
||||
});
|
||||
}
|
||||
|
||||
// 分析完成后,滚动到结果区域
|
||||
setTimeout(() => {
|
||||
@@ -278,14 +307,9 @@ const AnalysisPage: React.FC = () => {
|
||||
{analysisType === 'yijing' ? (
|
||||
// 易经占卜表单
|
||||
<div className="mb-6">
|
||||
<ChineseInput
|
||||
label="占卜问题"
|
||||
<YijingQuestionSelector
|
||||
value={formData.question}
|
||||
onChange={(e) => setFormData(prev => ({ ...prev, question: e.target.value }))}
|
||||
placeholder="请输入您希望占卜的具体问题,如:我的事业发展如何?"
|
||||
required
|
||||
variant="filled"
|
||||
helperText="💡 提示:问题越具体,占卜结果越准确。可以询问事业、感情、财运、健康等方面的问题。"
|
||||
onChange={(value) => setFormData(prev => ({ ...prev, question: value }))}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
@@ -402,6 +426,7 @@ const AnalysisPage: React.FC = () => {
|
||||
question={analysisType === 'yijing' ? formData.question : undefined}
|
||||
userId={user?.id?.toString()}
|
||||
divinationMethod="time"
|
||||
recordId={analysisResult.recordId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -21,6 +21,7 @@ const HistoryPage: React.FC = () => {
|
||||
|
||||
// 分页相关状态
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [aiInterpretations, setAiInterpretations] = useState<{[key: number]: boolean}>({});
|
||||
const itemsPerPage = 10;
|
||||
|
||||
// 安全地从input_data中获取值的辅助函数
|
||||
@@ -88,6 +89,20 @@ const HistoryPage: React.FC = () => {
|
||||
});
|
||||
|
||||
setReadings(processedData);
|
||||
|
||||
// 检查每个记录的AI解读状态
|
||||
const aiStatus: {[key: number]: boolean} = {};
|
||||
for (const reading of processedData) {
|
||||
try {
|
||||
const aiResponse = await localApi.request(`/ai-interpretation/get/${reading.id}`, {
|
||||
method: 'GET'
|
||||
});
|
||||
aiStatus[reading.id] = aiResponse.success && aiResponse.data;
|
||||
} catch {
|
||||
aiStatus[reading.id] = false;
|
||||
}
|
||||
}
|
||||
setAiInterpretations(aiStatus);
|
||||
} catch (error: any) {
|
||||
toast.error('加载历史记录失败:' + (error.message || '未知错误'));
|
||||
} finally {
|
||||
@@ -214,6 +229,7 @@ const HistoryPage: React.FC = () => {
|
||||
divinationMethod={selectedReading.reading_type === 'yijing' ?
|
||||
getInputDataValue(selectedReading.input_data, 'divination_method', 'time') : undefined}
|
||||
preAnalysisData={selectedReading.analysis}
|
||||
recordId={selectedReading.id}
|
||||
/>
|
||||
|
||||
</div>
|
||||
@@ -279,9 +295,17 @@ const HistoryPage: React.FC = () => {
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<h3 className="font-semibold text-gray-900 font-chinese">
|
||||
{reading.name || '未知姓名'} - {getAnalysisTypeName(reading.reading_type)}
|
||||
</h3>
|
||||
{aiInterpretations[reading.id] && (
|
||||
<div className="flex items-center space-x-1 bg-purple-100 text-purple-700 px-2 py-1 rounded-full text-xs">
|
||||
<Sparkles className="h-3 w-3" />
|
||||
<span>已有AI解读</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:space-x-4 text-sm text-gray-600 mt-1 space-y-1 sm:space-y-0">
|
||||
<div className="flex items-center space-x-1">
|
||||
<Calendar className="h-3 w-3" />
|
||||
|
||||
Reference in New Issue
Block a user