482 lines
13 KiB
JavaScript
482 lines
13 KiB
JavaScript
import { showConfirmDialog } from 'vant';
|
||
import { getQuestionList, getCheckSurvey } from '@/api/survey';
|
||
import appBridge from '@/assets/js/appBridge';
|
||
import { QUESTION_TYPE } from '@/layouts/config3d.constant.js';
|
||
import { loopingAvailable } from '@/layouts/logic.js';
|
||
import { getDomText } from '@/utils/utils';
|
||
// /**
|
||
// * 统一的弹窗
|
||
// * @param options
|
||
// */
|
||
/**
|
||
* 统一的弹窗
|
||
* @param options
|
||
*/
|
||
function showModal(options) {
|
||
showConfirmDialog({
|
||
title: '提示',
|
||
icon: null,
|
||
...options
|
||
})
|
||
.then(() => {})
|
||
.catch(() => {});
|
||
}
|
||
|
||
/**
|
||
* PSM的判断
|
||
* @param {*} data
|
||
* @returns
|
||
*/
|
||
const canPlanetPublishPSM = function (data) {
|
||
let isFb = true;
|
||
let message = '';
|
||
let title = '题目设置未完成';
|
||
const incompleteQuestionList = [];
|
||
data.questions &&
|
||
data.questions.forEach((s) => {
|
||
if (s.question_type === 101 && s.config.price_gradient.length <= 0) {
|
||
isFb = false;
|
||
message = 'psm题目未完成设置,请设置价格区间后投放';
|
||
title = '题目设置未完成';
|
||
incompleteQuestionList.push(s);
|
||
}
|
||
});
|
||
if (isFb === true && data.questions.length > 0) {
|
||
return true;
|
||
} else {
|
||
const titleStr = incompleteQuestionList.map((item) => item.title).join('、') || '';
|
||
showModal({
|
||
title,
|
||
message: `${titleStr} ${message}`,
|
||
incompleteQuestionList
|
||
});
|
||
}
|
||
};
|
||
/**
|
||
* Mxd和热区的判断
|
||
* @param {*} data
|
||
* @returns
|
||
*/
|
||
const canPlanetPublishMxdAndHotArea = function (data) {
|
||
let isFb = true;
|
||
let message = '';
|
||
const qSteams = [];
|
||
const incompleteQuestionList = [];
|
||
let type = 0;
|
||
let title = '题目设置未完成';
|
||
data.questions &&
|
||
data.questions.forEach((s) => {
|
||
if (s.question_type === 105 && s.config.design_version <= 0) {
|
||
isFb = false;
|
||
message = 'maxdiff题目未完成设置,请生成设计后投放';
|
||
title = '题目设置未完成';
|
||
type = 1;
|
||
incompleteQuestionList.push(s);
|
||
}
|
||
if (s.question_type === 25 || s.question_type === 26) {
|
||
if ((s.options?.[0]?.length || 0) <= 0 && (s?.associate?.length || 0) <= 0) {
|
||
isFb = false;
|
||
qSteams.push(`(${s.title})`);
|
||
type = 2;
|
||
incompleteQuestionList.push(s);
|
||
}
|
||
}
|
||
});
|
||
|
||
if (isFb === true) {
|
||
return true;
|
||
} else {
|
||
if (type === 2) {
|
||
const titleStr = qSteams.join(',');
|
||
title = '添加选区';
|
||
message = `${titleStr} 未添加选区,请添加选区后进行投放`;
|
||
}
|
||
showModal({
|
||
title,
|
||
message,
|
||
incompleteQuestionList
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 3D相关的判断
|
||
* @param {*} data
|
||
* @returns
|
||
*/
|
||
const canPlanetPublish3D = function (data) {
|
||
{
|
||
let canFB = true;
|
||
let message = '';
|
||
const qSteams = [];
|
||
let title = '';
|
||
data.questions &&
|
||
data.questions.forEach((s) => {
|
||
if (QUESTION_TYPE.contains(s.question_type)) {
|
||
try {
|
||
if (s.config.is_three_dimensions && !s.config.scene) {
|
||
canFB = false;
|
||
qSteams.push(`(${s.title})`);
|
||
}
|
||
} catch (error) {
|
||
// error
|
||
}
|
||
}
|
||
});
|
||
|
||
if (!canFB === true) {
|
||
const titleStr = qSteams.join(',');
|
||
title = '选择场景';
|
||
message = `${titleStr} 未选择场景,请选择场景后进行投放`;
|
||
showModal({
|
||
title,
|
||
message
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
{
|
||
let canFB = true;
|
||
let message = '';
|
||
const qSteams = [];
|
||
let title = '';
|
||
data.questions &&
|
||
data.questions.forEach((s) => {
|
||
if (QUESTION_TYPE.contains(s.question_type)) {
|
||
try {
|
||
if (s.config.is_three_dimensions && s.config.is_binding_goods) {
|
||
const wares = [];
|
||
const _sceneInformation = s.config.scene_information;
|
||
const sceneInformation =
|
||
typeof _sceneInformation === 'string'
|
||
? JSON.parse(_sceneInformation)
|
||
: _sceneInformation;
|
||
sceneInformation.shelves.forEach((shelf) => {
|
||
shelf.wares.forEach((ware) => {
|
||
if (!ware.option_index) return;
|
||
wares.push(ware);
|
||
});
|
||
});
|
||
|
||
const options = s.options.flat();
|
||
s.associate.forEach((ass) => {
|
||
// eslint-disable-next-line no-eval
|
||
const question = data.questions.find(
|
||
(q) => q.question_index === ass.question_index
|
||
);
|
||
if (!question) return;
|
||
options.push(...question.options.flat());
|
||
});
|
||
// 判定是否有选项未关联商品
|
||
if (options.length > wares.length) {
|
||
canFB = false;
|
||
qSteams.push(`(${s.title})`);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
// error
|
||
}
|
||
}
|
||
});
|
||
|
||
if (!canFB === true) {
|
||
const titleStr = qSteams.join(',');
|
||
title = '商品关联选项';
|
||
message = `${titleStr} 仍有选项未关联商品,无法进行投放`;
|
||
showModal({
|
||
title,
|
||
message
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
/**
|
||
* 图片题的判断
|
||
* @param {*} data
|
||
* @returns
|
||
*/
|
||
const canPlanetPublishImage = function (data) {
|
||
{
|
||
let canFB = true;
|
||
let message = '';
|
||
const qSteams = [];
|
||
let title = '';
|
||
data.questions &&
|
||
data.questions.forEach((s) => {
|
||
if (s.question_type === 13) {
|
||
try {
|
||
if (s.options.length <= 0 || s.options.some((y) => y.length <= 0)) {
|
||
canFB = false;
|
||
qSteams.push(`(${s.title})`);
|
||
}
|
||
} catch (error) {
|
||
// console.warn(error);
|
||
}
|
||
}
|
||
});
|
||
if (!canFB === true) {
|
||
const titleStr = qSteams.join(',');
|
||
title = '题目设置未完成';
|
||
message = `图片题 ${titleStr} 未上传图片,请设置后投放`;
|
||
showModal({
|
||
title,
|
||
message
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* 多项填空题
|
||
* @param data
|
||
* @param publishType
|
||
*/
|
||
function canPublishMultiCompletion(data, publishType) {
|
||
const publishStr = ['', '预览', '投放'][publishType] || '投放';
|
||
const questions = [];
|
||
|
||
if (!data?.questions?.length) {
|
||
return true;
|
||
}
|
||
|
||
data.questions.forEach((quiz) => {
|
||
if (quiz.question_type !== 27) {
|
||
return;
|
||
}
|
||
|
||
if (!getDomText(quiz.config?.text_content)) {
|
||
questions.push(quiz.title);
|
||
}
|
||
});
|
||
|
||
if (questions.length) {
|
||
showModal({
|
||
title: '题目设置未完成',
|
||
message: `多项填空题 (${questions.join('、')}) 未设置填空,请设置后${publishStr}`
|
||
});
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 校验 "逻辑 -> 随机列表" 是否满足投放条件
|
||
* @param data
|
||
* @return {boolean}
|
||
*/
|
||
function canPublishRandom(data, publishType) {
|
||
const publishStr = ['', '预览', '投放'][publishType] || '投放';
|
||
|
||
const errors = [];
|
||
// eslint-disable-next-line no-eval
|
||
const randomList = data?.survey?.group_pages || [];
|
||
|
||
randomList.forEach((random) => {
|
||
const list = random.list || [];
|
||
|
||
// 每一个随机,至少要有两个随机题组
|
||
if (list.length < 2) {
|
||
errors.push({ message: `"${random.title}"需至少配置2个"随机题组"` });
|
||
return false;
|
||
}
|
||
|
||
list.forEach((item, index) => {
|
||
// 这三个是必填的
|
||
const fields = [
|
||
{ label: 'title', name: '题组名称', validator: (value) => !!value },
|
||
{ label: 'start', name: '题组起点', validator: (value) => !!value },
|
||
{ label: 'end', name: '题组终点', validator: (value) => !!value }
|
||
];
|
||
|
||
fields.forEach((field) => {
|
||
const isValidated = field.validator(item[field.label]);
|
||
if (!isValidated) {
|
||
errors.push({
|
||
message:
|
||
field.message ||
|
||
`请填写"${random.title}"中第${index + 1}组"随机题组"的"${field.name}"`
|
||
});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
if (errors.length) {
|
||
showModal({
|
||
title: '修改随机题组',
|
||
message: `随机题组设置不完全,请前往"逻辑设置-随机列表"修改后${publishStr}`
|
||
});
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
/**
|
||
* 将接口返回的题目和分页两个数组合并为一个
|
||
* @param {Array} quesList 要合并的题目
|
||
* @param {Array} pages 分页完成的题目id数组
|
||
* @param {Array} pagesStr 分页的内容数组
|
||
* @returns
|
||
*/
|
||
function combineQuesAndPage(quesList, pages, pagesStr) {
|
||
if (pages.length === 0) return quesList;
|
||
const newPages = `${pages.join(',empty,')},empty`.split(',').filter((x) => x.length !== 0);
|
||
const copyList = quesList.filter((x) => x.id);
|
||
let startIndex = 0;
|
||
newPages.forEach((x, index) => {
|
||
if (x === 'empty') {
|
||
copyList.splice(index, 0, pagesStr[startIndex]);
|
||
startIndex += 1;
|
||
}
|
||
});
|
||
return copyList;
|
||
}
|
||
/**
|
||
* 根据原始数据pages和问题列表quesList处理成包含分页的quesList
|
||
* @param {Array} questions 要合并的题目
|
||
* @param {Array} page 分页完成的题目ques_index数组
|
||
* @param {Array} pageConfig 分页配置,由于是后添加的功能,所以只好分开传,再合到一起了
|
||
* @returns
|
||
*/
|
||
function getQuesByPages(questions, page, pageConfig) {
|
||
const oldPages = questions.filter((q) => !!q.page);
|
||
const quesList = questions.filter((ques) => ques.id);
|
||
const pageStr = [];
|
||
page.forEach((x, xIndex) => {
|
||
const temp = {
|
||
...(oldPages[xIndex] || {}),
|
||
page: xIndex + 1,
|
||
total: page.length,
|
||
first_title: '',
|
||
last_title: '',
|
||
...(pageConfig?.[xIndex] || {})
|
||
};
|
||
x.forEach((y, yIndex) => {
|
||
if (yIndex === 0) {
|
||
temp.first_title = quesList.find((ques) => ques.question_index === y)?.title || '';
|
||
}
|
||
if (yIndex === x.length - 1) {
|
||
temp.last_title = quesList.find((ques) => ques.question_index === y)?.title || '';
|
||
}
|
||
});
|
||
pageStr.push(temp);
|
||
});
|
||
return combineQuesAndPage(quesList, page, pageStr);
|
||
}
|
||
/**
|
||
* 循环逻辑的判断
|
||
* @param data
|
||
* @param publishType
|
||
*/
|
||
function isLoopingLogicValid(data, publishType) {
|
||
const publishStr = ['', '预览', '投放'][publishType] || '投放';
|
||
if (
|
||
(data?.cycle_pages || []).every((i) => {
|
||
return (
|
||
i.question_index &&
|
||
i.relation_type !== undefined &&
|
||
i.relation_type !== null &&
|
||
i.first_page &&
|
||
i.last_page
|
||
);
|
||
})
|
||
) {
|
||
return loopingAvailable({
|
||
cycles: data.cycle_pages || [],
|
||
questions: getQuesByPages(data.questions || [], data.survey.pages),
|
||
logics: data.logics || [],
|
||
isPerPage: data.survey?.is_one_page_one_question
|
||
});
|
||
}
|
||
|
||
showModal({
|
||
title: '修改循环',
|
||
message: `循环题组不完全,请前往循环列表修改后${publishStr}`
|
||
});
|
||
|
||
return false;
|
||
}
|
||
/**
|
||
* 判断问卷是否可以投放(原本应该后端实现,前端实现会有并发的问题,但后端表示做不了)
|
||
* @param sn
|
||
* @param publishType undefined投放;null投放;0投放;1预览;2投放;3测试
|
||
*/
|
||
export const canPlanetPublish = async function (sn, publishType) {
|
||
const parsedPublishType = !publishType ? 2 : publishType;
|
||
const num = window.location.href.indexOf('code=');
|
||
let code;
|
||
if (num > -1) {
|
||
code = window.location.href.slice(num + 5, window.location.href.length);
|
||
} else {
|
||
code = '';
|
||
}
|
||
const { data } = await getQuestionList(sn, code);
|
||
if (!canPlanetPublishPSM(data?.data)) return false;
|
||
if (!canPlanetPublishMxdAndHotArea(data?.data)) return false;
|
||
if (!canPlanetPublish3D(data?.data)) return false;
|
||
if (!canPlanetPublishImage(data?.data)) return false;
|
||
if (!canPublishMultiCompletion(data, parsedPublishType)) return false;
|
||
if (!canPublishRandom(data?.data, parsedPublishType)) return false;
|
||
if (!isLoopingLogicValid(data?.data, parsedPublishType)) return false;
|
||
|
||
if (parsedPublishType === 2) {
|
||
const qrcodeRes = await getCheckSurvey(sn);
|
||
if (qrcodeRes?.data?.data?.show_test_button) {
|
||
const res = await new Promise((resolve) => {
|
||
showConfirmDialog({
|
||
class: 'custom-modal custom-modal-title-confirm-notice show-icon',
|
||
title: '确认要投放这个问卷吗?',
|
||
messageStyle: {
|
||
position: 'absolute',
|
||
top: '0',
|
||
right: '0',
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
width: '56px',
|
||
height: '56px',
|
||
fontSize: '14px',
|
||
cursor: 'pointer'
|
||
},
|
||
message:
|
||
'投放前测试能帮助您确认问卷设计逻辑及作答数据是否正确,避免因问卷设计问题造成重大损失。',
|
||
confirmButtonText: '去测试',
|
||
onConfirm() {
|
||
resolve(false);
|
||
if (utils.getSessionStorage('xToken')) {
|
||
appBridge.openInBrowser(
|
||
`${location.origin}/preview?sn=${sn}&name=${data.data.survey.project_name}+source=0&is_test=1`
|
||
);
|
||
} else {
|
||
window.open(
|
||
`${location.origin}/preview?sn=${sn}&name=${data.data.survey.project_name}+source=0&is_test=1`
|
||
);
|
||
}
|
||
},
|
||
width: '640px',
|
||
height: '364px',
|
||
cancelButtonText: '继续投放',
|
||
onCancel() {
|
||
resolve(true);
|
||
},
|
||
dialogStyle: {
|
||
fontSize: '44px'
|
||
},
|
||
zIndex: 9999999
|
||
});
|
||
});
|
||
if (!res) return;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|