220 lines
6.7 KiB
Vue
220 lines
6.7 KiB
Vue
<template>
|
||
<van-field
|
||
v-model="element.stem"
|
||
:label="element.stem"
|
||
:required="element.config.is_required === 1"
|
||
label-align="top"
|
||
class="contenteditable-question-title base-select"
|
||
>
|
||
<template #left-icon> {{ isPreview ? element.title : index + 1 }}. </template>
|
||
<template #label>
|
||
<contenteditable
|
||
v-model="element.stem"
|
||
className="contenteditable-label"
|
||
:active="active"
|
||
@blur="emitValue"
|
||
:errorMessage="errorMessage"
|
||
>
|
||
</contenteditable>
|
||
</template>
|
||
<template #input>
|
||
<template v-for="item /*optionIndex*/ in element.list ?? element.options" :key="item.id">
|
||
<van-radio-group v-if="element.question_type === 1" v-model="choiceValue">
|
||
<option-action
|
||
:data="isPreview ? item.options : item"
|
||
:active="active"
|
||
:is-preview="isPreview"
|
||
:question="element"
|
||
handle=".moverQues"
|
||
>
|
||
<template #item="{ element: it, index: itIndex }">
|
||
<div class="flex" style="flex-wrap: wrap; width: 100%">
|
||
<van-radio
|
||
:key="itIndex"
|
||
:name="it.option_index"
|
||
:label="it.label"
|
||
:disabled="it.disabled"
|
||
icon-size="0.45rem"
|
||
>
|
||
<!-- 自定义文本 -->
|
||
<template #default>
|
||
<div class="flex align-center van-cell">
|
||
<div class="flex" style="width: 100%; flex-wrap: wrap">
|
||
<contenteditable
|
||
v-model="it.option"
|
||
:className="active ? 'contenteditable-input' : ''"
|
||
:active="active"
|
||
>
|
||
<template #right-icon>
|
||
<div v-if="active" class="moverQues">
|
||
<van-icon class-prefix="mobilefont" name="option "></van-icon>
|
||
</div>
|
||
</template>
|
||
</contenteditable>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</van-radio>
|
||
<textarea class="other-input" type="text" v-if="it.is_other" style="width: 100%" />
|
||
</div>
|
||
</template>
|
||
</option-action>
|
||
</van-radio-group>
|
||
|
||
<van-checkbox-group
|
||
v-if="element.question_type === 2"
|
||
v-model="value"
|
||
shape="square"
|
||
@change="handleChange"
|
||
>
|
||
<option-action
|
||
:data="isPreview ? item.options : item"
|
||
handle=".moverQues"
|
||
:active="active"
|
||
:is-preview="isPreview"
|
||
:question="element"
|
||
>
|
||
<template #item="{ element: it, index: itIndex }">
|
||
<div class="flex" style="flex-wrap: wrap; width: 100%">
|
||
<van-checkbox
|
||
:key="itIndex"
|
||
:name="it.option_index"
|
||
:label="it.label"
|
||
:disabled="it.disabled"
|
||
icon-size="0.45rem"
|
||
>
|
||
<template #default>
|
||
<div class="flex align-center van-cell">
|
||
<div class="flex" style="width: 100%; flex-wrap: wrap">
|
||
<contenteditable
|
||
v-model="it.option"
|
||
:className="active ? 'contenteditable-input' : ''"
|
||
:active="active"
|
||
>
|
||
<template #right-icon>
|
||
<div v-if="active" class="moverQues">
|
||
<van-icon class-prefix="mobilefont" name="option "></van-icon>
|
||
</div>
|
||
</template>
|
||
</contenteditable>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</van-checkbox>
|
||
<textarea class="other-input" type="text" v-if="it.is_other" style="width: 100%" />
|
||
</div>
|
||
</template>
|
||
</option-action>
|
||
</van-checkbox-group>
|
||
</template>
|
||
</template>
|
||
</van-field>
|
||
</template>
|
||
<script setup>
|
||
import OptionAction from '@/views/Design/components/ActionCompoents/OptionAction.vue';
|
||
import { defineAsyncComponent } from 'vue';
|
||
|
||
// 是否是预览
|
||
const isPreview = defineModel('isPreview', { default: false, type: Boolean });
|
||
const choiceValue = defineModel('answer', { default: '', type: String });
|
||
const value = defineModel('checkboxAnswer', { default: [], type: Array });
|
||
const errorMessage = defineModel('errorMessage', { default: '', type: String });
|
||
const Contenteditable = defineAsyncComponent(() => import('@/components/contenteditable.vue'));
|
||
defineProps({
|
||
isPreview: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
active: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
index: {
|
||
default: ''
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 题目
|
||
* @type {ModelRef<Object, string, Object, Object>}
|
||
*/
|
||
const element = defineModel('element', {
|
||
type: Object,
|
||
default: () => {
|
||
return {
|
||
stem: ''
|
||
};
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 控制选项,如果新增排它项, 那么就直接重新取值
|
||
* 按理说是不是 watch 更加合理 ??
|
||
* @param names {number[]} 选中的项
|
||
*/
|
||
function handleChange(names) {
|
||
const newOption = names[names.length - 1];
|
||
// 如果names 长度小于1,直接返回,不处理
|
||
if (names.length < 1) return;
|
||
|
||
let options;
|
||
|
||
try {
|
||
options = element.value.options[0].options ?? element.value.list[0];
|
||
} catch (e) {
|
||
options = element.value.options[0];
|
||
}
|
||
|
||
// 如果不存在 options 和 list 属性,直接返回
|
||
if (!options) return;
|
||
|
||
// 如果 names 里面有其他的排它项,就把排它项的值去除
|
||
for (const option of options) {
|
||
if (option.is_remove_other === 1 && newOption !== option.option_index) {
|
||
value.value = value.value.filter((item) => item !== option.option_index);
|
||
}
|
||
}
|
||
|
||
if (options[Number(newOption) - 1]?.is_remove_other === 1) {
|
||
value.value = [newOption];
|
||
}
|
||
}
|
||
|
||
const emit = defineEmits(['update:element']);
|
||
const emitValue = () => {
|
||
emit('update:element', element.value);
|
||
};
|
||
</script>
|
||
<style scoped lang="scss">
|
||
.base-select {
|
||
& .van-checkbox-group,
|
||
.van-radio-group {
|
||
width: 100%;
|
||
|
||
& .van-checkbox,
|
||
.van-radio {
|
||
width: 100%;
|
||
|
||
& ::v-deep .van-checkbox__label {
|
||
width: 100%;
|
||
}
|
||
|
||
& ::v-deep .van-radio__label {
|
||
width: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
& .other-input {
|
||
width: 100%;
|
||
min-height: 89px;
|
||
margin-top: 4px;
|
||
margin-bottom: 10px;
|
||
padding: 12px;
|
||
border: 1px solid #f4f4f4;
|
||
border-radius: 5px;
|
||
outline: none;
|
||
}
|
||
}
|
||
</style>
|