feat: 新增选项操作功能并优化问卷设计页面
- 新增 OptionAction 组件用于选项操作 - 更新 BaseSelect 组件,集成 OptionAction 功能 - 优化 Paging 组件样式 - 调整 Design 页面布局和样式
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -14,12 +14,15 @@ declare module 'vue' {
|
|||||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||||
|
VanDialog: typeof import('vant/es')['Dialog']
|
||||||
VanDivider: typeof import('vant/es')['Divider']
|
VanDivider: typeof import('vant/es')['Divider']
|
||||||
VanField: typeof import('vant/es')['Field']
|
VanField: typeof import('vant/es')['Field']
|
||||||
VanIcon: typeof import('vant/es')['Icon']
|
VanIcon: typeof import('vant/es')['Icon']
|
||||||
|
VanPopup: typeof import('vant/es')['Popup']
|
||||||
VanSearch: typeof import('vant/es')['Search']
|
VanSearch: typeof import('vant/es')['Search']
|
||||||
VanSwitch: typeof import('vant/es')['Switch']
|
VanSwitch: typeof import('vant/es')['Switch']
|
||||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||||
|
YLSelect: typeof import('./src/components/YLSelect.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
97
src/components/YLSelect.vue
Normal file
97
src/components/YLSelect.vue
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<el-select v-model="selectedValue" class="yl-select-wrapper" @change="handleChange">
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
import { ElSelect, ElOption } from 'element-plus';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'YLSelect',
|
||||||
|
components: {
|
||||||
|
ElSelect,
|
||||||
|
ElOption
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const selectedValue = ref(props.modelValue);
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(newVal) => {
|
||||||
|
selectedValue.value = newVal;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
emit('update:modelValue', event);
|
||||||
|
emit('change', event);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedValue,
|
||||||
|
handleChange
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.yl-select-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px; /* 增加字体大小 */
|
||||||
|
line-height: 1.5; /* 增加行高 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.yl-select {
|
||||||
|
height: 44px; /* 增加高度以适应触摸 */
|
||||||
|
padding: 10px; /* 增加内边距 */
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '\25BC'; /* 添加下拉箭头 */
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 10px;
|
||||||
|
color: #999;
|
||||||
|
pointer-events: none;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -181,6 +181,50 @@ export const useCommonStore = defineStore('common', {
|
|||||||
cell_indexs: []
|
cell_indexs: []
|
||||||
},
|
},
|
||||||
hide_option_index: []
|
hide_option_index: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 472152,
|
||||||
|
question_index: 24,
|
||||||
|
sample_number: 0,
|
||||||
|
skip_question_index: 0,
|
||||||
|
skip_type: 1,
|
||||||
|
question_id: '17852294',
|
||||||
|
logic: [
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
location: 0,
|
||||||
|
date: '',
|
||||||
|
time: '',
|
||||||
|
type: 0,
|
||||||
|
row_type: 0,
|
||||||
|
cell_type: 0,
|
||||||
|
logic: 'if',
|
||||||
|
operator: '=',
|
||||||
|
is_answer: 1,
|
||||||
|
is_select: 0,
|
||||||
|
row_index: 0,
|
||||||
|
cell_index: 0,
|
||||||
|
question_type: 1,
|
||||||
|
question_index: 0,
|
||||||
|
relation_question_index: 0,
|
||||||
|
relation_question_row_index: 0,
|
||||||
|
relation_question_cell_index: 0,
|
||||||
|
is_option_group: 0,
|
||||||
|
option_index: 0,
|
||||||
|
skip_type: null,
|
||||||
|
question_id: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
autofill: {
|
||||||
|
value: '',
|
||||||
|
date: '',
|
||||||
|
time: '',
|
||||||
|
question_type: 1,
|
||||||
|
option_indexs: [],
|
||||||
|
row_indexs: [],
|
||||||
|
cell_indexs: []
|
||||||
|
},
|
||||||
|
hide_option_index: []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
questions: [
|
questions: [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="design-create">
|
||||||
<draggable
|
<draggable
|
||||||
v-model:data="questionInfo.questions"
|
v-model:data="questionInfo.questions"
|
||||||
item-key="id"
|
item-key="id"
|
||||||
@@ -115,4 +115,10 @@ onMounted(() => {
|
|||||||
questionInfo.value = store.questionsInfo.value;
|
questionInfo.value = store.questionsInfo.value;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss">
|
||||||
|
.design-create {
|
||||||
|
min-height: calc(100vh);
|
||||||
|
background-color: #e9eef3;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-divider></van-divider>
|
<van-divider></van-divider>
|
||||||
<van-cell title="题前隐藏" :border="false">
|
<van-cell title="题前隐藏" :border="false" @click="questionSetting('before')">
|
||||||
<template #right-icon>
|
<template #right-icon>
|
||||||
<span> {{ getSkipTypeText(0) }} <van-icon name="arrow"></van-icon></span>
|
<span> {{ getSkipTypeText(0) }} <van-icon name="arrow"></van-icon></span>
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-cell title="题后跳转" :border="false">
|
<van-cell title="题后跳转" :border="false" @click="questionSetting('after')">
|
||||||
<template #right-icon>
|
<template #right-icon>
|
||||||
<span> {{ getSkipTypeText(1) }} <van-icon name="arrow"></van-icon></span>
|
<span> {{ getSkipTypeText(1) }} <van-icon name="arrow"></van-icon></span>
|
||||||
</template>
|
</template>
|
||||||
@@ -50,6 +50,30 @@
|
|||||||
</van-action-sheet>
|
</van-action-sheet>
|
||||||
|
|
||||||
<!-- 题目操作 题前 题后-->
|
<!-- 题目操作 题前 题后-->
|
||||||
|
|
||||||
|
<van-popup
|
||||||
|
v-model:show="questionBeforeShow"
|
||||||
|
title="题前隐藏逻辑"
|
||||||
|
position="bottom"
|
||||||
|
round
|
||||||
|
:style="{ minHeight: '60%' }"
|
||||||
|
>
|
||||||
|
<template v-for="(item, index) in logics" :key="index">
|
||||||
|
<div
|
||||||
|
v-if="item.skip_type === skipType && item.question_index === activeQuestion.question_index"
|
||||||
|
class="mv10 question-setting"
|
||||||
|
>
|
||||||
|
<template v-for="(log, logIndex) in item.logic" :key="logIndex">
|
||||||
|
<yl-select
|
||||||
|
v-model="log.logic"
|
||||||
|
:options="settingIfOption"
|
||||||
|
class="question-setting-if"
|
||||||
|
></yl-select>
|
||||||
|
<yl-select v-model="log.logic" :options="settingIfOption"></yl-select>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-popup>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { showConfirmDialog } from 'vant';
|
import { showConfirmDialog } from 'vant';
|
||||||
@@ -57,10 +81,17 @@ import { ref } from 'vue';
|
|||||||
import { useCounterStore } from '@/stores/counter';
|
import { useCounterStore } from '@/stores/counter';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
|
import YlSelect from '@/components/YLSelect.vue';
|
||||||
|
|
||||||
const store = useCounterStore();
|
const store = useCounterStore();
|
||||||
const { questionsInfo } = storeToRefs(store);
|
const { questionsInfo } = storeToRefs(store);
|
||||||
const logics = questionsInfo.value.logics;
|
const logics = questionsInfo.value.logics;
|
||||||
|
|
||||||
|
const settingIfOption = [
|
||||||
|
{ label: 'if', value: 'if' },
|
||||||
|
{ label: 'always', value: 'always' }
|
||||||
|
];
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -87,6 +118,7 @@ const questions = ref(props.questions);
|
|||||||
const activeQuestion = ref(props.data);
|
const activeQuestion = ref(props.data);
|
||||||
|
|
||||||
const show = ref(false);
|
const show = ref(false);
|
||||||
|
const questionBeforeShow = ref(false);
|
||||||
const deleteQuestion = () => {
|
const deleteQuestion = () => {
|
||||||
showConfirmDialog({
|
showConfirmDialog({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
@@ -124,6 +156,7 @@ const questionMove = (action) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const skipType = ref(-1);
|
||||||
// 获取题前隐藏 和题后 跳转 文字
|
// 获取题前隐藏 和题后 跳转 文字
|
||||||
const getSkipTypeText = (skipType) => {
|
const getSkipTypeText = (skipType) => {
|
||||||
const ls = [];
|
const ls = [];
|
||||||
@@ -141,12 +174,41 @@ const getSkipTypeText = (skipType) => {
|
|||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 题前 题后逻辑配置
|
||||||
|
|
||||||
|
const questionSetting = (type) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'before':
|
||||||
|
questionBeforeShow.value = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'after':
|
||||||
|
questionBeforeShow.value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
skipType.value = type === 'before' ? 0 : 1;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.ml10 {
|
.ml10 {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mv10 {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-select {
|
||||||
|
min-width: 10vw;
|
||||||
|
|
||||||
|
//max-width: 90vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-setting-if {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
.question-action-container {
|
.question-action-container {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user