feat[survey]: NPS 内容调整
- NPS value使用 hooks 方式. - 解决 preview 的 NPS 组件无法调整的问题 - PreviewNPS 组件实现方式调整 - 增加 nps组件相应的类型文件
This commit is contained in:
@@ -30,7 +30,6 @@
|
||||
<p>{{ element.config.prompt_right }}</p>
|
||||
</div>
|
||||
<RateCharacter
|
||||
v-model="answerValue"
|
||||
:config="element.config"
|
||||
:index="optionIndex"
|
||||
@change="handleRateChange"
|
||||
@@ -47,7 +46,7 @@ import { ref } from 'vue';
|
||||
import RateCharacter from './RateCharacter.vue';
|
||||
|
||||
const isPreview = defineModel('isPreview', { default: false, type: Boolean });
|
||||
const props = defineProps({
|
||||
/*const props = */ defineProps({
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -60,11 +59,10 @@ const props = defineProps({
|
||||
questionType: { type: [String, Number], default: 4 }
|
||||
});
|
||||
|
||||
// answer 的答案以 矩阵形式存储, 例如 [4,7],上层更新答案的时候也容易
|
||||
const rates = defineModel('rates', { default: [], type: Array });
|
||||
const rate = ref(0);
|
||||
const answerValue = ref();
|
||||
|
||||
/**
|
||||
* element === question
|
||||
* @type {ModelRef<Object, string, Object, Object>}
|
||||
*/
|
||||
const element = defineModel('element', {
|
||||
type: Object,
|
||||
default: () => {
|
||||
@@ -72,29 +70,13 @@ const element = defineModel('element', {
|
||||
}
|
||||
});
|
||||
|
||||
// 不知道的 BUG ,开始的时候不能重置颜色。 故如此
|
||||
setTimeout(() => {
|
||||
rate.value = localStorage.getItem(props.sn);
|
||||
// console.log(`rate value:`, rate.value);
|
||||
// if (rates.value[0] !== undefined) {
|
||||
// console.log(`rates value:`, rates.value);
|
||||
// rate.value = rates.value[0]
|
||||
// }
|
||||
// else return
|
||||
}, 1000);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index {number} 索引
|
||||
* @param rate {number} 具体数值
|
||||
*/
|
||||
function handleRateChange(index, rate) {
|
||||
// 如果没有查询到对应索引的数值, 那么就直接push一个,直到有数值为止
|
||||
while (rates.value.length < index) {
|
||||
rates.value.push(NaN);
|
||||
}
|
||||
rates.value[index] = rate;
|
||||
localStorage.setItem(props.sn, rate.value);
|
||||
function handleRateChange(/* index, rate */) {
|
||||
// 占位
|
||||
}
|
||||
|
||||
const chooseId = ref('');
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { value as model } from '@/views/Design/components/Questions/hooks/useNPSHooks';
|
||||
|
||||
const rateItem = ref([
|
||||
{
|
||||
@@ -52,10 +53,6 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const model = defineModel('model', {
|
||||
type: Number
|
||||
});
|
||||
|
||||
const index = defineModel('index', {
|
||||
type: Number
|
||||
});
|
||||
@@ -74,12 +71,14 @@ const renderScore = (min, max, interval) => {
|
||||
}
|
||||
rateItem.value = result;
|
||||
};
|
||||
|
||||
// 重置颜色
|
||||
function getItem(value) {
|
||||
model.value = value.label;
|
||||
// console.log(value.label);
|
||||
rateItem.value.forEach((item, index) => {
|
||||
rateItem.value[index].active = item.label <= value.label;
|
||||
});
|
||||
model.value = value.label;
|
||||
}
|
||||
|
||||
watch(
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const value = ref<number>(-1);
|
||||
@@ -1208,6 +1208,174 @@ async function answer(callback, callbackBeforePage) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// 关联引用
|
||||
function onRelation(
|
||||
// 避免出现参数 undefined 情况
|
||||
{ options, value, list } = {},
|
||||
{ question_type: _questionType, question_index: _questionIndex, related, answer } = {}
|
||||
) {
|
||||
// 关联
|
||||
related.forEach((relationItem) => {
|
||||
let relationOptions = [];
|
||||
if (_questionType === 9 || _questionType === 10) {
|
||||
// 矩阵选择
|
||||
list.forEach((item) => {
|
||||
if (item.type === relationItem.cite_type) {
|
||||
relationOptions = [...relationOptions, ...item.options];
|
||||
}
|
||||
if (relationItem.relation_type === 1) {
|
||||
relationOptions = relationOptions.filter((option) =>
|
||||
_questionType === 9 ? option.value : option.value?.length
|
||||
);
|
||||
} else if (relationItem.relation_type === 2) {
|
||||
relationOptions = relationOptions.filter((option) =>
|
||||
_questionType === 9 ? !option.value : !option.value?.length
|
||||
);
|
||||
}
|
||||
});
|
||||
} else if (_questionType === 11) {
|
||||
// 矩阵打分
|
||||
list.forEach((item) => {
|
||||
if (item.type === relationItem.cite_type) {
|
||||
relationOptions = [...relationOptions, ...item.options];
|
||||
}
|
||||
});
|
||||
} else if (_questionType === 25 || _questionType === 26) {
|
||||
// 热区题
|
||||
relationOptions = options.filter((option) => {
|
||||
if (relationItem.relation_type === 1) {
|
||||
return option.status === 1;
|
||||
} else if (relationItem.relation_type === 2) {
|
||||
return option.status === 2;
|
||||
} else if (relationItem.relation_type === 3) {
|
||||
return !option.status;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else if (_questionType === 105) {
|
||||
// MXD
|
||||
options.forEach((currentOptions) => {
|
||||
currentOptions.forEach((option) => {
|
||||
const index = relationOptions.findIndex(
|
||||
(relationOption) => relationOption.option_key === option.option_key
|
||||
);
|
||||
if (index === -1) {
|
||||
// 全部项
|
||||
if (relationItem.relation_type === 0) {
|
||||
return relationOptions.push(option);
|
||||
}
|
||||
// 高相关
|
||||
if (relationItem.relation_type === 3) {
|
||||
return option.value === 'b' && relationOptions.push(option);
|
||||
}
|
||||
// 不相关
|
||||
if (relationItem.relation_type === 4) {
|
||||
return option.value === 'w' && relationOptions.push(option);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (relationItem.relation_type === 0) {
|
||||
// 全部选项
|
||||
relationOptions = options;
|
||||
} else {
|
||||
// 过滤选中/未选中选项
|
||||
relationOptions = options.filter((option) => {
|
||||
if (_questionType === 1) {
|
||||
// 单选
|
||||
if (relationItem.relation_type === 1) return value === option.option_key;
|
||||
return value !== option.option_key;
|
||||
} else if (_questionType === 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 (_questionType >= 9 && _questionType <= 11) {
|
||||
letter = relationItem.cite_type === 1 ? 'R' : 'C';
|
||||
}
|
||||
option.option_key = `Q${_questionIndex}${letter}${option.option_key}`;
|
||||
}
|
||||
// 其他项特殊处理
|
||||
if (option.is_other && option.value) {
|
||||
option.is_other = 0;
|
||||
option.option = option.value;
|
||||
}
|
||||
delete option.value;
|
||||
delete option.status;
|
||||
});
|
||||
// 更新关联题列表
|
||||
const relatedList = question.list.find(
|
||||
(relatedListItem) => relatedListItem.relation_question_index === _questionIndex
|
||||
);
|
||||
relatedList.options = answer ? copyRelationOptions : [];
|
||||
});
|
||||
}
|
||||
|
||||
function jumpImmediately() {
|
||||
const code = questionsData.value.action?.code;
|
||||
if (page.value !== pages.value.length + 1 && ![20004, 20011, 20016].includes(code)) {
|
||||
return;
|
||||
}
|
||||
const survey = questionsData.value.survey;
|
||||
let countTime = 0;
|
||||
let url = '';
|
||||
|
||||
if (code === 20004 && survey.screening_end_url_select && survey.screening_end_url) {
|
||||
countTime = survey.screening_standing_time;
|
||||
url = survey.screening_end_url;
|
||||
}
|
||||
if (code === 20011 && survey.success_end_url_select && survey.success_end_url) {
|
||||
countTime = survey.success_standing_time;
|
||||
url = survey.success_end_url;
|
||||
}
|
||||
if (code === 20016 && survey.quota_end_url_select && survey.quota_end_url) {
|
||||
countTime = survey.quota_standing_time;
|
||||
url = survey.quota_end_url;
|
||||
}
|
||||
|
||||
// 跳转链接
|
||||
if (countTime <= 0 && url) {
|
||||
questionsData.value.action.code = -1 * code; // 防止 AnswerMob AnswerPc 组件里显示最后一页
|
||||
|
||||
url = url.replaceAll('#sn#', questionsData.value.answer.sn);
|
||||
url = url.replaceAll('#user#', questionsData.value.answer.respondent);
|
||||
url = url.replaceAll('#survey_sn#', questionsData.value.answer.survey_sn);
|
||||
if (proxy.$route.query.source === 'YILI_APP_WANGYI') {
|
||||
Object.keys(proxy.$route.query).forEach((key) => {
|
||||
if (!['sn', 'source', 'is_template', 'channelUCode'].includes(key)) {
|
||||
url += `${url.indexOf('?') === -1 ? '?' : '&'}${key}=${proxy.$route.query[key]}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 判断是否小程序路径
|
||||
if (url[0] === '/') {
|
||||
// 判断是否在小程序环境
|
||||
wx.miniProgram.getEnv(() => {
|
||||
wx.miniProgram.redirectTo({ url });
|
||||
});
|
||||
} else {
|
||||
if (url.indexOf('http://') === -1 && url.indexOf('https://') === -1) {
|
||||
url = `http://${url}`;
|
||||
}
|
||||
open(url, '_self');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .van-cell::after {
|
||||
|
||||
@@ -1,43 +1,45 @@
|
||||
<template>
|
||||
<n-p-s v-model:element="question" v-model:rates="rates" :active="false" :isPreview="true" />
|
||||
<n-p-s v-model:element="question" v-model:value="value" :active="false" :isPreview="true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NPS from '@/views/Design/components/Questions/NPS.vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { watch } from 'vue';
|
||||
import { value } from '@/views/Design/components/Questions/hooks/useNPSHooks';
|
||||
|
||||
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
|
||||
const answer = defineModel<{ [key: string]: number }>('answer', { default: undefined });
|
||||
|
||||
// rates 数值取决与 answer , 没有数据重新建立一个对应长度的数组
|
||||
const rates = ref(answer.value ? getRates() : new Array(question.value.list[0].options!.length));
|
||||
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
|
||||
const emit = defineEmits(['changeAnswer', 'previous', 'next', 'update:element']);
|
||||
|
||||
// 获取 rates
|
||||
function getRates() {
|
||||
const keys = Object.keys(answer.value);
|
||||
return keys.map((item) => {
|
||||
return answer.value[item];
|
||||
});
|
||||
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
|
||||
|
||||
/**
|
||||
* answer 的答案类型
|
||||
* {
|
||||
* "1": 10
|
||||
* }
|
||||
*/
|
||||
const answer = defineModel<NPSAnswerType>('answer', { default: undefined });
|
||||
|
||||
// 解析答案
|
||||
// function parseAnswer() {
|
||||
// return answer.value[`1`];
|
||||
// }
|
||||
|
||||
/**
|
||||
* 生成NPS答案
|
||||
*/
|
||||
function genAnswer(value: number): NPSAnswerType {
|
||||
const res: any = {};
|
||||
res[`1`] = value;
|
||||
return res;
|
||||
}
|
||||
|
||||
// console.log(answer.value && getRates());
|
||||
watch(
|
||||
rates,
|
||||
() => {
|
||||
const res = {};
|
||||
rates.value.map((item, index) => {
|
||||
// index 是 key, item 是 value
|
||||
res[index + 1] = item;
|
||||
watch(value, (newValue) => {
|
||||
// console.log(genAnswer(newValue as number));
|
||||
answer.value = genAnswer(newValue as number);
|
||||
// 提交答案
|
||||
emit('changeAnswer', answer.value);
|
||||
});
|
||||
answer.value = res;
|
||||
emit('changeAnswer', res);
|
||||
},
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
1
src/views/Survey/views/Preview/components/questions/types/previewNPS.d.ts
vendored
Normal file
1
src/views/Survey/views/Preview/components/questions/types/previewNPS.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
type NPSAnswerType = { [key: string]: number };
|
||||
Reference in New Issue
Block a user