eslint
This commit is contained in:
@@ -1,2 +1,5 @@
|
||||
/src/views/Creative/3d
|
||||
/src/font
|
||||
/src/plugins/tinymce-placeholder.js
|
||||
/src/plugins/tinymce-quickbars.js
|
||||
/public
|
||||
|
||||
@@ -1,425 +0,0 @@
|
||||
import AnswerApi from "../../api";
|
||||
import { computed, getCurrentInstance, defineComponent, inject, ref } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import PfePagination from "@/components/PfePagination.vue";
|
||||
import Question from "../../questions/Question.vue";
|
||||
import QRadio from '@/views/Answer/questions/QRadio'
|
||||
import QCheckbox from "../../questions/QCheckbox.vue";
|
||||
import QCascader from "../../questions/QCascader.vue";
|
||||
import QInput from "../../questions/QInput.vue";
|
||||
import QRate from "../../questions/QRate.vue";
|
||||
import QImgText from "../../questions/QImgText.vue";
|
||||
import QDate from "../../questions/QDate.vue";
|
||||
import MatrixInput from "../../questions/QMatrix/MatrixInput.vue";
|
||||
import MatrixRadio from "../../questions/QMatrix/MatrixRadio.vue";
|
||||
import MatrixCheck from "../../questions/QMatrix/MatrixCheck.vue";
|
||||
import MatrixRate from "../../questions/QMatrix/MatrixRate.vue";
|
||||
import QImgShow from "../../questions/QImgShow.vue";
|
||||
import QImgRadio from "../../questions/QImgRadio.vue";
|
||||
import QImgCheck from "../../questions/QImgCheck.vue";
|
||||
import QClass from "../../questions/QClass.vue";
|
||||
import QSort from "../../questions/QSort.vue";
|
||||
import QSum from "../../questions/QSum.vue";
|
||||
import QUpload from "../../questions/QUpload.vue";
|
||||
import QMap from "../../questions/QMap.vue";
|
||||
import QPhone from "../../questions/QPhone.vue";
|
||||
import QPassword from "../../questions/QPassword.vue";
|
||||
import QSign from "../../questions/QSign.vue";
|
||||
import QConsent from "../../questions/QConsent.vue";
|
||||
import QPSM from "../../questions/high/QPSM.vue";
|
||||
import QKANO from "../../questions/high/QKANO.vue";
|
||||
import QBPTO from "../../questions/high/QBPTO.vue";
|
||||
import QMXD from "../../questions/high/QMXD.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
PfePagination,
|
||||
Question,
|
||||
QFirst,
|
||||
QLast,
|
||||
QRadio,
|
||||
QCheckbox,
|
||||
QInput,
|
||||
QCascader,
|
||||
QRate,
|
||||
QImgText,
|
||||
QDate,
|
||||
MatrixInput,
|
||||
MatrixRadio,
|
||||
MatrixCheck,
|
||||
MatrixRate,
|
||||
QImgShow,
|
||||
QImgRadio,
|
||||
QImgCheck,
|
||||
QClass,
|
||||
QSort,
|
||||
QSum,
|
||||
QUpload,
|
||||
QMap,
|
||||
QPhone,
|
||||
QPassword,
|
||||
QSign,
|
||||
QConsent,
|
||||
QPSM,
|
||||
QKANO,
|
||||
QBPTO,
|
||||
QMXD,
|
||||
},
|
||||
props: {
|
||||
// 是否答题模式
|
||||
isAnswer: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const page = ref(0); // 当前页数
|
||||
const questionsData = inject("questionsData"); // 问卷数据
|
||||
const { proxy } = getCurrentInstance();
|
||||
const loading = ref(false);
|
||||
|
||||
// 主题样式
|
||||
const styleInfo = computed(() => questionsData.value.survey?.style || {});
|
||||
// 分页
|
||||
const pages = computed(() => questionsData.value.answer?.pages || []);
|
||||
// 当前页问卷
|
||||
const questions = computed(() => {
|
||||
const currentPages = pages.value[page.value - 1] || [];
|
||||
return (questionsData.value.questions || []).filter((quetion) =>
|
||||
currentPages.find((index) => quetion.question_index === index)
|
||||
);
|
||||
});
|
||||
// 是否显示分页器
|
||||
const showPage = computed(() => {
|
||||
let show = true;
|
||||
if (questions.value[0]?.question_type === 104 || questions.value[0]?.question_type === 105) {
|
||||
show = false;
|
||||
}
|
||||
return show;
|
||||
});
|
||||
|
||||
// 答题
|
||||
async function answer(callback) {
|
||||
if ((questions.value.length && props.isAnswer) || !questionsData.value.questions.length) {
|
||||
// 表单验证(当前页)
|
||||
const errors = questions.value.filter((question) => {
|
||||
const { config, answer, question_type: questionType } = question;
|
||||
let isError = false;
|
||||
if (config.is_required && !answer) {
|
||||
isError = true;
|
||||
if (questionType === 10) {
|
||||
// 矩阵多选题
|
||||
question.error = `每行最少选${config.min_select}个`;
|
||||
} else if (questionType === 15) {
|
||||
// 分类题
|
||||
question.error = "部分选项未归类";
|
||||
} else if (!question.error) {
|
||||
question.error = "这是一道必答题";
|
||||
}
|
||||
} else if (
|
||||
answer &&
|
||||
questionType === 1 &&
|
||||
Object.keys(answer).findIndex((value) => !answer[value]) !== -1
|
||||
) {
|
||||
// 单选题
|
||||
isError = true;
|
||||
question.error = `请输入`;
|
||||
} else if (answer && questionType === 2) {
|
||||
// 多选题
|
||||
if (Object.keys(answer).length < config.min_select) {
|
||||
let options = [];
|
||||
question.list.forEach((list) => {
|
||||
options = [...options, ...list.options];
|
||||
});
|
||||
const index = options.findIndex(
|
||||
(option) => option.option_key === Object.keys(answer)[0] && option.is_remove_other
|
||||
);
|
||||
if (index === -1) {
|
||||
isError = true;
|
||||
question.error = `最少选择${config.min_select}个`;
|
||||
} else {
|
||||
question.error = "";
|
||||
}
|
||||
} else if (Object.keys(answer).findIndex((value) => !answer[value]) !== -1) {
|
||||
isError = true;
|
||||
question.error = `请输入`;
|
||||
} else {
|
||||
question.error = "";
|
||||
}
|
||||
} else if (
|
||||
answer &&
|
||||
questionType === 14 &&
|
||||
Object.keys(answer).length < config.min_select
|
||||
) {
|
||||
// 图片多选题
|
||||
isError = true;
|
||||
question.error = `最少选择${config.min_select}个`;
|
||||
} else if (answer && questionType === 17) {
|
||||
// 恒定总和题
|
||||
let sum = 0;
|
||||
Object.keys(answer).forEach((key) => {
|
||||
sum += answer[key] * 1;
|
||||
});
|
||||
if (sum === config.total) {
|
||||
question.error = "";
|
||||
} else {
|
||||
isError = true;
|
||||
question.error = `请让总和等于${config.total}`;
|
||||
}
|
||||
} else if (answer && questionType === 18 && answer.length < config.min_number) {
|
||||
// 文件上传题
|
||||
isError = true;
|
||||
question.error = `最少上传${config.min_number}个文件`;
|
||||
} else if (answer && questionType === 4) {
|
||||
question.error = "";
|
||||
// 填空题
|
||||
const { value } = answer;
|
||||
switch (config.text_type) {
|
||||
case 3: // 字母
|
||||
isError = !/^[a-zA-Z]+$/.test(value);
|
||||
question.error = isError ? "请输入字母" : "";
|
||||
break;
|
||||
case 4: // 中文
|
||||
isError =
|
||||
!/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? "请输入中文" : "";
|
||||
break;
|
||||
case 5: // 邮箱
|
||||
isError = !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? "请输入正确的email" : "";
|
||||
break;
|
||||
case 6: // 手机号
|
||||
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value);
|
||||
question.error = isError ? "请输入正确的手机号" : "";
|
||||
break;
|
||||
case 7: // 身份证号
|
||||
isError =
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? "请输入正确的身份证号" : "";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!isError && value.length < config.min) {
|
||||
isError = true;
|
||||
question.error = `请至少输入${config.min}个字`;
|
||||
}
|
||||
} else if (answer && questionType === 8) {
|
||||
// 矩阵填空题
|
||||
question.error = "";
|
||||
Object.keys(answer).forEach((key) => {
|
||||
const value = answer[key];
|
||||
switch (config.text_type) {
|
||||
case 3: // 字母
|
||||
if (!/^[a-zA-Z]+$/.test(value)) question.error = "请输入字母";
|
||||
break;
|
||||
case 4: // 中文
|
||||
if (
|
||||
!/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
value
|
||||
)
|
||||
)
|
||||
question.error = "请输入中文";
|
||||
break;
|
||||
case 5: // 邮箱
|
||||
if (!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value))
|
||||
question.error = "请输入正确的email";
|
||||
break;
|
||||
case 6: // 手机号
|
||||
if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value))
|
||||
question.error = "请输入正确的手机号";
|
||||
break;
|
||||
case 7: // 身份证号
|
||||
if (
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
)
|
||||
)
|
||||
question.error = "请输入正确的身份证号";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!question.error && value.length < config.min) {
|
||||
question.error = `请至少输入${config.min}个字`;
|
||||
}
|
||||
});
|
||||
if (question.error) isError = true;
|
||||
} else {
|
||||
question.error = "";
|
||||
}
|
||||
return isError;
|
||||
});
|
||||
if (!errors.length) {
|
||||
// 表单验证通过,开始答题
|
||||
const questionsAnswer = questions.value.map((question) => ({
|
||||
question_index: question.question_index,
|
||||
answer: question.answer || {},
|
||||
}));
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data } = await AnswerApi.answer({
|
||||
id: proxy.$route.query.sn,
|
||||
data: {
|
||||
answer: JSON.stringify(questionsAnswer),
|
||||
},
|
||||
});
|
||||
// 更新答案
|
||||
updateAnswer(data.answer_info_autofill);
|
||||
// 更新分页数组
|
||||
questionsData.value.answer.pages = data.pages;
|
||||
// 更新问卷状态
|
||||
if (data.action.code === 20014) {
|
||||
const timer = setTimeout(() => {
|
||||
let url = data.action.msg;
|
||||
if (url.indexOf("http://") === -1 && url.indexOf("https://") === -1) {
|
||||
url = `http://${url}`;
|
||||
}
|
||||
open(url);
|
||||
clearTimeout(timer);
|
||||
});
|
||||
}
|
||||
questionsData.value.action = data.action;
|
||||
callback();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false;
|
||||
} else {
|
||||
const { question_index, error } = errors[0];
|
||||
const index = questions.value.findIndex(
|
||||
(question) => question.question_index === question_index
|
||||
);
|
||||
message.error(`第${index + 1}题:${error}`);
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// 上一页
|
||||
function previous() {
|
||||
page.value -= 1;
|
||||
}
|
||||
|
||||
// 下一页
|
||||
async function next() {
|
||||
answer(() => {
|
||||
page.value += 1;
|
||||
});
|
||||
}
|
||||
|
||||
// 关联引用
|
||||
function onRelation(
|
||||
{ options, value, list },
|
||||
{ question_type, question_index, related, answer }
|
||||
) {
|
||||
// 关联
|
||||
related.forEach((relationItem) => {
|
||||
let relationOptions = [];
|
||||
if (question_type === 9 || question_type === 10) {
|
||||
// 矩阵选择
|
||||
list.forEach((item) => {
|
||||
if (item.type === relationItem.cite_type) {
|
||||
relationOptions = [...relationOptions, ...item.options];
|
||||
}
|
||||
if (relationItem.relation_type === 1) {
|
||||
relationOptions = relationOptions.filter((option) =>
|
||||
question_type === 9 ? option.value : option.value?.length
|
||||
);
|
||||
} else if (relationItem.relation_type === 2) {
|
||||
relationOptions = relationOptions.filter((option) =>
|
||||
question_type === 9 ? !option.value : !option.value?.length
|
||||
);
|
||||
}
|
||||
});
|
||||
} else if (question_type === 11) {
|
||||
// 矩阵打分
|
||||
list.forEach((item) => {
|
||||
if (item.type === relationItem.cite_type) {
|
||||
relationOptions = [...relationOptions, ...item.options];
|
||||
}
|
||||
});
|
||||
} else if (relationItem.relation_type === 0) {
|
||||
// 全部选项
|
||||
relationOptions = options;
|
||||
} else {
|
||||
// 过滤选中/未选中选项
|
||||
relationOptions = options.filter((option) => {
|
||||
if (question_type === 1) {
|
||||
// 单选
|
||||
if (relationItem.relation_type === 1) return value === option.option_key;
|
||||
return value !== option.option_key;
|
||||
} else if (question_type === 2) {
|
||||
// 多选
|
||||
if (relationItem.relation_type === 1) return value.includes(option.option_key);
|
||||
return !value.includes(option.option_key);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// 找到关联题
|
||||
const question = questionsData.value.questions.find(
|
||||
(question) => question.question_index === relationItem.relation_question_index
|
||||
);
|
||||
// 深拷贝关联选项
|
||||
const copyRelationOptions = JSON.parse(JSON.stringify(relationOptions));
|
||||
// 更新关联选项key
|
||||
copyRelationOptions.forEach((option) => {
|
||||
if (option.option_key[0] !== "Q") {
|
||||
let letter = "A";
|
||||
// 矩阵题行、列
|
||||
if (question_type >= 9 && question_type <= 11) {
|
||||
letter = relationItem.cite_type === 1 ? "R" : "C";
|
||||
}
|
||||
option.option_key = `Q${question_index}${letter}${option.option_key}`;
|
||||
}
|
||||
// 其他项特殊处理
|
||||
if (option.is_other) {
|
||||
// option.is_other = 0
|
||||
option.oldOption = option.option;
|
||||
option.option = option.value || option.option;
|
||||
}
|
||||
delete option.value;
|
||||
});
|
||||
// 更新关联题列表
|
||||
if (answer) {
|
||||
question.list[0].options = copyRelationOptions;
|
||||
} else {
|
||||
question.list[0].options = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateAnswer(auto) {
|
||||
if (auto) {
|
||||
auto.forEach((autoItem) => {
|
||||
const question = questionsData.value.questions.find(
|
||||
(question) => question.question_index === autoItem.question_index
|
||||
);
|
||||
question.answer = JSON.parse(autoItem.answer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
page,
|
||||
pages,
|
||||
loading,
|
||||
showPage,
|
||||
styleInfo,
|
||||
questions,
|
||||
questionsData,
|
||||
answer,
|
||||
previous,
|
||||
next,
|
||||
onRelation,
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user