fix: linkedGroupIds null check in validateRequiredFields

null !== undefined was true, causing false validation failure on templates
without linked groups. Changed to != null check.
This commit is contained in:
Developer
2026-05-21 11:17:45 +08:00
parent 54762ca299
commit 240aea24aa
5 changed files with 27 additions and 25 deletions
@@ -77,14 +77,13 @@ export const interviewerNode = async (
? `質問 ${currentQuestionIndex + 1}` ? `質問 ${currentQuestionIndex + 1}`
: `Question ${currentQuestionIndex + 1}`; : `Question ${currentQuestionIndex + 1}`;
const optionsText = currentQuestion.options.join('\n');
const instruction = isZh const instruction = isZh
? '请选择一个选项(输入字母 A/B/C/D' ? '请选择一个选项'
: isJa : isJa
? '選択肢から1つ選んでくださいA/B/C/Dを入力)' ? '選択肢から1つ選んでください'
: 'Please select one option (enter A, B, C, or D)'; : 'Please select one option';
prompt = `${label}: ${currentQuestion.questionText}\n\n${optionsText}\n\n${instruction}`; prompt = `${label}: ${currentQuestion.questionText}\n\n${instruction}`;
} else { } else {
const label = isZh const label = isZh
? `问题 ${currentQuestionIndex + 1}` ? `问题 ${currentQuestionIndex + 1}`
@@ -20,16 +20,16 @@ export class TemplateService {
) {} ) {}
private validateRequiredFields(data: { private validateRequiredFields(data: {
linkedGroupIds?: string[]; linkedGroupIds?: string[] | null;
dimensions?: Array<{ name: string; label?: string; weight?: number }>; dimensions?: Array<{ name: string; label?: string; weight?: number }> | null;
}) { }) {
if (data.linkedGroupIds !== undefined) { if (data.linkedGroupIds != null && Array.isArray(data.linkedGroupIds)) {
if (!Array.isArray(data.linkedGroupIds) || data.linkedGroupIds.length === 0) { if (data.linkedGroupIds.length === 0) {
throw new BadRequestException('At least one knowledge group must be linked'); throw new BadRequestException('At least one knowledge group must be linked');
} }
} }
if (data.dimensions !== undefined) { if (data.dimensions != null && Array.isArray(data.dimensions)) {
if (!Array.isArray(data.dimensions) || data.dimensions.length === 0) { if (data.dimensions.length === 0) {
throw new BadRequestException('At least one dimension must be defined'); throw new BadRequestException('At least one dimension must be defined');
} }
for (const d of data.dimensions) { for (const d of data.dimensions) {
File diff suppressed because one or more lines are too long
@@ -135,9 +135,10 @@ export const AssessmentTemplateManager: React.FC = () => {
} }
setShowModal(false); setShowModal(false);
fetchTemplates(); fetchTemplates();
} catch (error) { } catch (error: any) {
console.error('Save failed:', error); console.error('Save failed:', error);
showError(t('actionFailed')); const msg = error?.message;
showError(msg && msg !== 'Request failed' ? msg : t('actionFailed'));
} finally { } finally {
setIsSaving(false); setIsSaving(false);
} }
+13 -11
View File
@@ -610,6 +610,7 @@ export const AssessmentView: React.FC<AssessmentViewProps> = ({
{currentQuestion.options.map((opt: string, i: number) => { {currentQuestion.options.map((opt: string, i: number) => {
const letter = optionLabels[i]; const letter = optionLabels[i];
const isSelected = selectedChoice === letter; const isSelected = selectedChoice === letter;
const displayText = opt.replace(/^[A-D][.)、]\s*/, '');
return ( return (
<button <button
key={letter} key={letter}
@@ -626,7 +627,7 @@ export const AssessmentView: React.FC<AssessmentViewProps> = ({
<span className="inline-flex items-center justify-center w-7 h-7 rounded-xl text-xs font-black mr-3 shrink-0 border-2 border-current"> <span className="inline-flex items-center justify-center w-7 h-7 rounded-xl text-xs font-black mr-3 shrink-0 border-2 border-current">
{letter} {letter}
</span> </span>
{opt} {displayText}
</button> </button>
); );
})} })}
@@ -853,16 +854,17 @@ export const AssessmentView: React.FC<AssessmentViewProps> = ({
<p className="font-bold text-slate-800 text-sm leading-relaxed">{q.questionText}</p> <p className="font-bold text-slate-800 text-sm leading-relaxed">{q.questionText}</p>
{isChoice && ( {isChoice && (
<div className="mt-2 flex flex-wrap gap-2 text-xs"> <div className="mt-2 flex flex-wrap gap-2 text-xs">
{q.options?.map((opt: string, oi: number) => { {q.options?.map((opt: string, oi: number) => {
const letter = String.fromCharCode(65 + oi); const letter = String.fromCharCode(65 + oi);
const isAnswer = letter === q.correctAnswer; const isAnswer = letter === q.correctAnswer;
return ( const displayText = opt.replace(/^[A-D][.)、]\s*/, '');
<span key={oi} className={cn( return (
"px-3 py-1 rounded-lg font-medium", <span key={oi} className={cn(
isAnswer ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-slate-50 text-slate-500" "px-3 py-1 rounded-lg font-medium",
)}> isAnswer ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-slate-50 text-slate-500"
{letter}. {opt} )}>
</span> {letter}. {displayText}
</span>
); );
})} })}
</div> </div>