feat: 抽离答题校验逻辑
- 纠正 Preview/index 错误的逻辑,开始检测 error 字段 - validateAnswer 类型纠正,修复 answerItem 验证逻辑 - 答题校验抽离
This commit is contained in:
4
src/types/question.d.ts
vendored
4
src/types/question.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user