feat: 增加本地测评档案与长期追踪

This commit is contained in:
2026-06-23 00:21:07 +02:00
parent fdfbfa063f
commit c8d5a918cf
19 changed files with 1509 additions and 14 deletions
@@ -10,6 +10,10 @@ import { saveResult } from '@/lib/result-storage';
import { Questionnaire as QuestionnaireType, QuestionType } from '@/types';
import { useRouter } from 'next/navigation';
import { toast } from "sonner"
import { ProfilePicker } from '@/components/records/ProfilePicker';
import { AssessmentProfile } from '@/lib/assessment-types';
import { addAssessmentRecord, ensureActiveProfile } from '@/lib/assessment-db';
import { buildScoreSummary } from '@/lib/score-summary';
interface QuestionnaireProps {
questionnaire: QuestionnaireType;
@@ -32,6 +36,7 @@ export function Questionnaire({
const questionRefs = useRef<{ [key: number]: HTMLDivElement | null }>({});
// Flag to indicate whether the questionnaire has been submitted
const hasSubmittedRef = useRef(false);
const [activeProfile, setActiveProfile] = useState<AssessmentProfile | null>(null);
// Save answers when component unmounts
useEffect(() => {
@@ -163,7 +168,7 @@ export function Questionnaire({
}
};
const handleSubmit = () => {
const handleSubmit = async () => {
// Check if all questions are answered first
if (answeredCount < questions.length) {
toast("请先完成所有题目");
@@ -179,7 +184,32 @@ export function Questionnaire({
// Store answers in this browser tab instead of putting them in the URL.
const resultAnswers = questions.map((q) => answers[q.id] ?? '0');
saveResult(id, resultAnswers);
const profile = activeProfile || await ensureActiveProfile();
const completedAt = new Date().toISOString();
const recordedAnswers = questionnaire.questions.map((question, index) => {
const value = resultAnswers[index];
const option = questionnaire.renderOptions(question.id).find(
(item) => String(item.value) === String(value),
);
return {
questionId: question.id,
question: question.content,
value,
answer: option?.content || value,
};
});
const record = await addAssessmentRecord({
profileId: profile.id,
questionnaireId: id,
questionnaireTitle: questionnaire.title,
category: questionnaire.category,
completedAt,
answers: recordedAnswers,
scoreSummary: buildScoreSummary(id, resultAnswers),
retestSuitable: questionnaire.evaluation?.retestSuitable,
recommendedInterval: questionnaire.evaluation?.recommendedInterval,
});
saveResult(id, resultAnswers, profile.id, record.id);
router.push(`/questionnaire/${id}/result`);
}
@@ -201,6 +231,8 @@ export function Questionnaire({
<div className="max-w-3xl mx-auto py-8 px-4">
<h1 className="text-2xl font-bold mb-8">{questionnaire.title}</h1>
<ProfilePicker onChange={setActiveProfile} />
<ProgressPanel
questions={questions}
answers={answers}