feat: 抽离答题校验逻辑

- 纠正 Preview/index 错误的逻辑,开始检测 error 字段
- validateAnswer 类型纠正,修复 answerItem 验证逻辑
- 答题校验抽离
This commit is contained in:
Huangzhe
2025-04-01 15:13:16 +08:00
parent 7de06d5ff4
commit b1cd7cf799
4 changed files with 46 additions and 15 deletions

View File

@@ -34,7 +34,7 @@ declare interface IQuestionOption {
relation_last_scope: number;
relation_first_scope: number;
relation_question_index: number;
options?: IMatrixCheckboxOption[];
options: IMatrixCheckboxOption[];
}
// 答案 config 类型
@@ -93,7 +93,7 @@ export declare interface IQuestion<QuestionConfig = IBaseConfig> {
question_index?: number;
question_type?: number;
// 如果没有自定义类型,那么就直接用基础 config 类型
config?: QuestionConfig;
config: QuestionConfig;
created_at?: string;
created_user_id?: number;
updated_user_id?: number | null;

View File

@@ -640,10 +640,11 @@ async function answer(callback, callbackBeforePage) {
if ((questions.value.length || !questionsData.value.questions.length) && !props.isTemplate) {
// 表单验证(当前页)
const errors = questions.value.filter((question) => {
const { config, answer, question_type: questionType } = question;
const { config, answer, question_type: questionType, error } = question;
let isError = false;
// 如果问题没有答案还有是必须填空的,就往下处理
if (config.is_required && !answer) {
// 2025/4/1新增 如果有 error 内容, 同样视为有错误
if (!answer || error.length) {
isError = true;
// 各个问题单独处理
if (questionType === 10) {

View File

@@ -12,9 +12,12 @@
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { computed, onUnmounted, ref, watch } from 'vue';
import MatrixQuestion from '@/views/Design/components/Questions/MatrixQuestion.vue';
import type { IQuestion } from '@/types/question';
import type { IQuestion, IQuestionOption } from '@/types/question';
import { validateAnswerNum } from '@/views/Survey/views/Preview/components/questions/validate/validateAnswer';
import type { IMatrixCheckboxConfig } from '@/types/questions/matrixCheckbox';
import { validateList } from '@/views/Survey/views/Preview/hooks/useValidateQuestion';
// const questionType = defineModel<number>('questionType', { required: false });
// 矩阵单选的答案类型
@@ -25,8 +28,10 @@ type answerType = {
// preview props
// const stem = defineModel('stem');
// const list = defineModel<questionsList[]>('list', { required: false });
// const config = defineModel<OptionConfigType>('config', { required: false });
const question = defineModel<IQuestion>('question', { default: () => {} });
const config = defineModel<IMatrixCheckboxConfig>('config', { required: false });
const question = defineModel<IQuestion>('question', {
default: () => {}
});
// console.log(`question`, question.value);
@@ -73,7 +78,20 @@ function parseAnswer(answer: answerType) {
* 行的内容在 question.list[0].options
* 列的内容在 question.list[1].options
*/
const [rows, cols] = question.value?.list;
const [rows, cols] = <IQuestionOption[]>question.value?.list;
// 将校验函数 push 给 validateList以便与点击下一页进行校验。
// 备选方法,此外还可以兼容 pc 答题行为
const validateFun = () => {
// 答案长度校验
question.value.error = validateAnswerNum(rowRecord.value, config.value!, rows.options);
};
validateList.value.push(validateFun);
onUnmounted(() => {
// 在页面卸载的时候,将校验函数从 validateList 中移除
validateList.value = validateList.value.filter((func) => func !== validateFun);
});
watch(
rowRecord,
@@ -86,7 +104,15 @@ watch(
});
// 如果行记录答案不够,那么就不进行传递答案
if (rowRecord.value.length !== rows.options.length) return;
// if (rowRecord.value.length !== rows.options.length) return;
const errMsg = validateAnswerNum(rowRecord.value, config.value!, rows.options);
question.value.error = errMsg;
// 如果答案有错误,那么就不进行传递答案,并重置之前的答案
if (errMsg.length > 0) {
answer.value = {};
return;
}
answer.value = newAnswer;
emit('changeAnswer', newAnswer);

View File

@@ -1,20 +1,23 @@
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
import type { IRateConfig } from '@/types/questions/rateConfig';
import type { IQuestionOption } from '@/types/question';
import type { IBaseConfig } from '@/types/baseConfig';
/**
* 检验答案是否数量是否符合题目要求
* @param answer 答案
* @param config 配置
* @param options 选项
* @param translatedText 错误提示
*/
function validateAnswerNum(
function validateAnswerNum<T extends IBaseConfig>(
answer: number[],
config: IRateConfig,
config: T,
options: IQuestionOption[],
translatedText = getLanguage(['zh'])
) {
const { is_required, max, min } = config;
const { is_required } = config;
const min = config.min || 0;
const max = config.max || 0;
let errorMessage: string = '';
// 如果不是必答题,跳过检验
@@ -22,7 +25,8 @@ function validateAnswerNum(
// 检测答案数量是否在范围内
answer.forEach((answerItem) => {
if (answerItem < min || answerItem > max) {
// 如果不在范围内,提示错误, answerItem < min 或者 max 存在,并且 answerItem > max
if (answerItem < min || (answerItem > max && max)) {
errorMessage = translatedText.PleaseSelectAValueThatIsNoLessThanOneAndNoMoreThanOne(min, max);
}
});