eslint
This commit is contained in:
@@ -1,2 +1,5 @@
|
|||||||
/src/views/Creative/3d
|
/src/views/Creative/3d
|
||||||
/src/font
|
/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