Files
ylst-h5/src/views/Design/Index.vue
陈昱达 6e83ccdbb3 feat(design): 添加题目预览功能并优化题目组件
- 新增 Preview 组件用于题目预览
- 重构 Index 组件,移除冗余代码
-优化 QuestionBefore 组件,添加题目标题
- 重构 ChooseQuestion组件,支持自定义操作
- 新增题目类型判断和对应操作功能
2025-03-06 10:24:00 +08:00

215 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="design-create">
<draggable
v-model:data="questionInfo.questions"
item-key="id"
handle=".moverQues"
chosenClass="chosen"
animation="300"
:scroll="true"
>
<template #item="{ element, index }">
<choose-question
:element="element"
:questions="questionInfo.questions"
:index="index"
:chooseQuestionId="chooseQuestionId"
@get-choose-question-id="getChooseQuestionId"
>
<!-- 选择题 -->
<Choice
v-if="element.question_type === 1"
:element="element"
:active="chooseQuestionId === element.id"
></Choice>
<!-- 填空题 -->
<Completion
v-if="element.question_type === 4"
:element="element"
:active="chooseQuestionId === element.id"
sn="lXEBBpE2"
></Completion>
<martrix-question
v-if="element.question_type === 9"
:element="element"
:active="chooseQuestionId === element.id"
/>
<!-- 打分题 -->
<Rate
v-if="element.question_type === 5"
:element="element"
:active="chooseQuestionId === element.id"
sn="lXEBBpE2"
/>
<!--组件底部左侧操作-->
<template #action="{ element: el }">
<div class="flex slot-actions">
<template v-for="(item, optionIndex) in actionOptions">
<div
v-if="item.question_type.includes(el.question_type)"
:key="optionIndex"
class="flex"
>
<template v-for="(act, actIndex) in item.actions" :key="actIndex">
<div class="flex align-center action-item" @click="actionEvent(act, el)">
<van-icon :name="act.icon"></van-icon>
<span class="ml10">{{ act.label }}</span>
</div>
</template>
</div>
</template>
</div>
</template>
</choose-question>
<!-- {{ element.question_type }}-->
<!-- {{questionInfo.survey.pages.length}}-->
<paging
v-if="!element.question_type && questionInfo.survey.pages.length > 1"
:info="element"
:index="index"
:active="pageIsActive(activeIndex, questionInfo.questions, element.page)"
@click.stop=""
/>
</template>
</draggable>
</div>
</template>
<script setup>
import { v4 as uuidv4 } from 'uuid';
import { ref, onMounted } from 'vue';
import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia';
import Draggable from './components/Draggable.vue';
import Choice from './components/Questions/Choice.vue';
import ChooseQuestion from './components/ChooseQuestion.vue';
import Paging from './components/Questions/paging/Paging.vue';
import Completion from './components/Questions/Completion.vue';
import MartrixQuestion from './components/Questions/MartrixQuestion.vue';
import Rate from './components/Questions/Rate.vue';
const activeIndex = ref(-1);
/**
* 工具函数
*/
function util() {
/** 通过id找到数组中对应的下标 */
const getIndexById = (arr, id) => arr.findIndex((i) => i.id === id);
/** 通过分页找到数组中对应的下标 */
const getIndexByPage = (arr, page) => arr.findIndex((i) => i.page === page);
const quesIsActive = (activeIndex, questionList, eleId) => {
return activeIndex === getIndexById(questionList, eleId);
};
const pageIsActive = (activeIndex, questionList, elePage) => {
return activeIndex === getIndexByPage(questionList, elePage);
};
const quesIsDisabled = (questionIndex, disabledQuestionIndex) => {
return (disabledQuestionIndex || []).includes(questionIndex);
};
const pagingDisabled = (index, question, disabledQuestionIndex) => {
if (disabledQuestionIndex.includes(question?.[index - 1]?.questionIndex)) {
return true;
}
for (let i = 1; i < question.length - 1; i++) {
if (question?.[index + i]?.page) {
continue;
}
if (disabledQuestionIndex.includes(question?.[index + i]?.questionIndex)) {
return true;
}
}
return false;
};
/** 工具函数复制store中的数据避免直接更改store */
const copyStoreContent = (store) => {
return JSON.parse(JSON.stringify(store.state.common));
};
return {
getIndexById,
getIndexByPage,
quesIsActive,
pageIsActive,
quesIsDisabled,
pagingDisabled,
copyStoreContent
};
}
const { pageIsActive } = util();
// 获取 Store 实例
const counterStore = useCounterStore();
const store = storeToRefs(counterStore);
const chooseQuestionId = ref('');
const questionInfo = ref(store.questionsInfo.value);
// 获取选中的题目的ID
const getChooseQuestionId = (questionItem) => {
chooseQuestionId.value = questionItem.id;
};
// 组件对应的操作
const actionOptions = [
{
question_type: [1, 5],
actions: [
{
label: '添加选项',
icon: 'add',
fun: 'radioAddOption'
}
]
}
];
// 事件分发
const actionEvent = (item, el) => {
actionFun[item.fun](el);
};
// 总事件注册
const actionFun = {
// 单选事件 添加选项
radioAddOption: (element) => {
element.options.map((item) => {
item.push({
id: uuidv4(),
option: `选项${item.length + 1}`,
option_config: {
image_url: [],
title: '',
instructions: [],
option_type: 0,
limit_right_content: ''
},
option_index: element.last_option_index + 1,
parent_id: 0,
type: 0,
cascade: [],
config: []
});
});
element.last_option_index += 1;
}
};
onMounted(() => {
questionInfo.value = store.questionsInfo.value;
});
</script>
<style scoped lang="scss">
.ml10 {
margin-left: 5px;
}
.design-create {
min-height: calc(100vh);
background-color: #e9eef3;
color: #333;
.slot-actions {
& .action-item + .action-item {
margin-left: 10px;
}
}
}
</style>