refactor(Design): 重构设计页面组件和逻辑
- 修改 QuestionAction 组件,优化题前隐藏和题后跳转的逻辑和界面 - 更新 ChooseQuestion 组件,改进选项索引的处理方式 - 调整 Design/Index 组件,替换 BaseSelect 为 Choice 组件 - 更新 components.d.ts,添加 VanButton 和 VanDialog 的类型声明
This commit is contained in:
5
components.d.ts
vendored
5
components.d.ts
vendored
@@ -2,7 +2,7 @@
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
export {};
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
@@ -10,15 +10,16 @@ declare module 'vue' {
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanCell: typeof import('vant/es')['Cell']
|
||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||
VanDialog: typeof import('vant/es')['Dialog']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanRate: typeof import('vant/es')['Rate']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanSwitch: typeof import('vant/es')['Switch']
|
||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||
|
||||
@@ -32,6 +32,10 @@ a,
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.flex-warp {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
>
|
||||
<span style="float: left" v-html="item.label"></span>
|
||||
</el-option>
|
||||
<template #label="{ label }">
|
||||
<!-- {{ option }}-->
|
||||
<div v-html="label"></div>
|
||||
</template>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
@@ -70,7 +76,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.yl-select {
|
||||
height: 44px; /* 增加高度以适应触摸 */
|
||||
height: 35px; /* 增加高度以适应触摸 */
|
||||
padding: 10px; /* 增加内边距 */
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,11 +17,11 @@
|
||||
@get-choose-question-id="getChooseQuestionId"
|
||||
>
|
||||
<!-- 选择题 -->
|
||||
<base-select
|
||||
<Choice
|
||||
v-if="element.question_type === 1"
|
||||
:element="element"
|
||||
:active="chooseQuestionId === element.id"
|
||||
></base-select>
|
||||
></Choice>
|
||||
<!-- 填空题 -->
|
||||
<Completion
|
||||
v-if="element.question_type === 4"
|
||||
@@ -57,7 +57,7 @@ import { ref, onMounted } from 'vue';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Draggable from './components/Draggable.vue';
|
||||
import BaseSelect from './components/Questions/BaseSelect.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';
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
<van-divider></van-divider>
|
||||
<van-cell title="题前隐藏" :border="false" @click="questionSetting('before')">
|
||||
<template #right-icon>
|
||||
<span> {{ getSkipTypeText(0) }} <van-icon name="arrow"></van-icon></span>
|
||||
<span> {{ getSkipTypeText(1) }} <van-icon name="arrow"></van-icon></span>
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell title="题后跳转" :border="false" @click="questionSetting('after')">
|
||||
<template #right-icon>
|
||||
<span> {{ getSkipTypeText(1) }} <van-icon name="arrow"></van-icon></span>
|
||||
<span> {{ getSkipTypeText(0) }} <van-icon name="arrow"></van-icon></span>
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-divider></van-divider>
|
||||
@@ -54,25 +54,52 @@
|
||||
<van-popup
|
||||
v-model:show="questionBeforeShow"
|
||||
title="题前隐藏逻辑"
|
||||
label="题前隐藏逻辑"
|
||||
position="bottom"
|
||||
:overlay="false"
|
||||
closeable
|
||||
close-icon="close"
|
||||
round
|
||||
:style="{ minHeight: '60%' }"
|
||||
:style="{ maxHeight: '75%' }"
|
||||
>
|
||||
<template v-for="(item, logicIndex) in logics" :key="logicIndex">
|
||||
<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 class="mv10">
|
||||
<header><strong>题前隐藏逻辑</strong></header>
|
||||
<question-before
|
||||
v-model="questionsInfo.logics"
|
||||
:skipType="skipType"
|
||||
:activeQuestion="activeQuestion"
|
||||
></question-before>
|
||||
<van-button>添加逻辑</van-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <template v-for="(item, index) in logics" :key="index" class="flex">-->
|
||||
<!-- <div class="flex space-between mv10">-->
|
||||
<!-- <div-->
|
||||
<!-- v-if="-->
|
||||
<!-- item.skip_type === skipType && item.question_index === activeQuestion.question_index-->
|
||||
<!-- "-->
|
||||
<!-- class="question-setting"-->
|
||||
<!-- >-->
|
||||
<!-- <template v-for="(log, logIndex) in item.logic" :key="logIndex">-->
|
||||
<!-- <div>-->
|
||||
<!-- <yl-select-->
|
||||
<!-- v-model="log.logic"-->
|
||||
<!-- :options="settingIfOption"-->
|
||||
<!-- class="question-setting-if"-->
|
||||
<!-- ></yl-select>-->
|
||||
<!-- <yl-select v-model="log.logic" :options="settingIfOption"></yl-select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div-->
|
||||
<!-- v-if="-->
|
||||
<!-- item.skip_type === skipType && item.question_index === activeQuestion.question_index-->
|
||||
<!-- "-->
|
||||
<!-- >-->
|
||||
<!-- del-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
</van-popup>
|
||||
</template>
|
||||
<script setup>
|
||||
@@ -80,18 +107,11 @@ import { showConfirmDialog } from 'vant';
|
||||
import { ref } from 'vue';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import YlSelect from '@/components/YLSelect.vue';
|
||||
|
||||
import QuestionBefore from '@/views/Design/components/ActionCompoents/components/QuestionBefore.vue';
|
||||
const store = useCounterStore();
|
||||
const { questionsInfo } = storeToRefs(store);
|
||||
const logics = questionsInfo.value.logics;
|
||||
|
||||
const settingIfOption = [
|
||||
{ label: 'if', value: 'if' },
|
||||
{ label: 'always', value: 'always' }
|
||||
];
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
type: Number,
|
||||
@@ -187,7 +207,7 @@ const questionSetting = (type) => {
|
||||
questionBeforeShow.value = true;
|
||||
break;
|
||||
}
|
||||
skipType.value = type === 'before' ? 0 : 1;
|
||||
skipType.value = type === 'before' ? 1 : 0;
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@@ -205,10 +225,6 @@ const questionSetting = (type) => {
|
||||
//max-width: 90vw;
|
||||
}
|
||||
|
||||
.question-setting-if {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.question-action-container {
|
||||
font-size: 20px;
|
||||
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<template v-for="(item, index) in logics" :key="index">
|
||||
<div
|
||||
v-if="item.skip_type === skipType && item.question_index === activeQuestion.question_index"
|
||||
>
|
||||
<div class="mt10">
|
||||
<template v-for="(log, logIndex) in item.logic" :key="logIndex">
|
||||
<div class="flex align-center space-between">
|
||||
<div class="question-before mb10">
|
||||
<!-- if always-->
|
||||
<yl-select
|
||||
v-model="log.logic"
|
||||
:options="logIndex === 0 ? settingIfOptions : settingAndOptions"
|
||||
class="if mr10"
|
||||
@change="logicIf($event, index)"
|
||||
></yl-select>
|
||||
<!-- 问题-->
|
||||
<yl-select
|
||||
v-if="log.logic !== 'always'"
|
||||
v-model="log.question_index"
|
||||
class="question"
|
||||
:options="beforeQuesOptions"
|
||||
placeholder="请选择问题"
|
||||
></yl-select>
|
||||
<!-- 为空 不为空-->
|
||||
<yl-select
|
||||
v-if="log.logic !== 'always'"
|
||||
v-model="log.is_answer"
|
||||
class="answer mr10 mt10"
|
||||
:options="answerOptions"
|
||||
></yl-select>
|
||||
<!-- 选项 or 分组 -->
|
||||
<yl-select
|
||||
v-if="log.logic !== 'always' && log.is_answer !== 0"
|
||||
v-model="log.is_option_group"
|
||||
:options="groupOptions"
|
||||
class="mr10 group mt10"
|
||||
></yl-select>
|
||||
<!-- 符号-->
|
||||
<yl-select
|
||||
v-if="log.logic !== 'always' && log.is_answer !== 0"
|
||||
v-model="log.operator"
|
||||
:options="symbolOptions"
|
||||
class="mr10 symbol mt10"
|
||||
></yl-select>
|
||||
<!-- 分组 option 选项option-->
|
||||
<div
|
||||
v-if="log.logic !== 'always' && log.is_answer !== 0"
|
||||
class="flex align-center space-between option mt10"
|
||||
>
|
||||
<yl-select
|
||||
v-if="log.is_option_group === 0"
|
||||
v-model="log.option_index"
|
||||
class="mr10"
|
||||
:options="changeQuestionIndex(log.question_index, log)"
|
||||
></yl-select>
|
||||
<yl-select
|
||||
v-else
|
||||
v-model="log.group_index"
|
||||
class="mr10"
|
||||
:options="changeQuestionIndex(log.question_index, log)"
|
||||
></yl-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action">
|
||||
<van-icon
|
||||
v-if="logIndex !== 0 || log.logic === 'always'"
|
||||
name="clear"
|
||||
class="mr10"
|
||||
@click="deleteLogic(logIndex, item.logic, index)"
|
||||
></van-icon>
|
||||
<van-icon
|
||||
v-if="log.logic !== 'always'"
|
||||
name="add"
|
||||
@click="addLogic(logIndex, item.logic)"
|
||||
></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 如果是题前隐藏-->
|
||||
<div v-if="skipType === 1">隐藏本题</div>
|
||||
</div>
|
||||
|
||||
<van-divider
|
||||
:dashed="true"
|
||||
:hairline="false"
|
||||
content-position="right"
|
||||
:style="{ borderColor: '#bfbfbf' }"
|
||||
>
|
||||
<van-icon name="delete">删除</van-icon>
|
||||
</van-divider>
|
||||
<!-- <div-->
|
||||
<!-- v-if="item.skip_type === skipType && item.question_index === activeQuestion.question_index"-->
|
||||
<!-- >-->
|
||||
<!-- del-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import YlSelect from '@/components/YLSelect.vue';
|
||||
import { ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
const store = useCounterStore();
|
||||
const { questionsInfo } = storeToRefs(store);
|
||||
const logics = ref(questionsInfo.value.logics);
|
||||
const questions = questionsInfo.value.questions;
|
||||
const props = defineProps({
|
||||
activeQuestion: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
skipType: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
// 变量为beforeList questions里面 获取activeQuestion 之前所有的题目
|
||||
|
||||
const questionIndex = questions.findIndex((item) => {
|
||||
return item.id === props.activeQuestion.id;
|
||||
});
|
||||
|
||||
// 当前题目之前的列表
|
||||
let beforeQuesOptions = [];
|
||||
if (questionIndex > 0) {
|
||||
beforeQuesOptions = questions.slice(0, questionIndex).map((item) => {
|
||||
return {
|
||||
...item,
|
||||
label: item.stem,
|
||||
value: item.question_index
|
||||
};
|
||||
});
|
||||
}
|
||||
// 题目选项
|
||||
let optionOptions = [];
|
||||
|
||||
const changeQuestionIndex = (value, logicItem) => {
|
||||
if (!value) {
|
||||
return [];
|
||||
}
|
||||
beforeQuesOptions.map((item) => {
|
||||
if (item.question_index === value) {
|
||||
if (logicItem.is_option_group === 0) {
|
||||
optionOptions = item.options[0].map((optItem) => {
|
||||
return {
|
||||
...optItem,
|
||||
label: optItem.option,
|
||||
value: optItem.option_index
|
||||
};
|
||||
});
|
||||
} else if (logicItem.is_option_group === 1) {
|
||||
optionOptions = item.config.option_groups.option_group.map((groupItem) => {
|
||||
return {
|
||||
...groupItem,
|
||||
label: groupItem.title,
|
||||
value: groupItem.group_index
|
||||
};
|
||||
});
|
||||
} else {
|
||||
optionOptions = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
return optionOptions;
|
||||
};
|
||||
|
||||
// 删除 题目设置
|
||||
const deleteLogic = (logIndex, item, index) => {
|
||||
item.splice(logIndex, 1);
|
||||
// 如果小删除 删除后一个都没有了 就删除掉整个数组
|
||||
if (item.length === 0) {
|
||||
logics.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
// 添加题目
|
||||
const addLogic = (logIndex, item) => {
|
||||
item.splice(logIndex + 1, 0, {
|
||||
logic: 'and',
|
||||
question_index: '',
|
||||
question_type: '',
|
||||
is_answer: 1,
|
||||
operator: '=',
|
||||
option_index: '',
|
||||
relation_question_index: 0,
|
||||
type: 0,
|
||||
is_option_group: '',
|
||||
group_index: null
|
||||
});
|
||||
};
|
||||
const groupOptions = [
|
||||
{
|
||||
label: '选项',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: '分组',
|
||||
value: 1
|
||||
// disabled: true
|
||||
}
|
||||
];
|
||||
const settingIfOptions = [
|
||||
{ label: 'if', value: 'if' },
|
||||
{ label: 'always', value: 'always' }
|
||||
];
|
||||
const settingAndOptions = [{ label: 'and', value: 'and' }];
|
||||
const answerOptions = [
|
||||
{ label: '为空', value: 0 },
|
||||
{ label: '不为空', value: 1 }
|
||||
];
|
||||
|
||||
const symbolOptions = [
|
||||
{
|
||||
label: '=',
|
||||
value: '='
|
||||
},
|
||||
{
|
||||
label: '≠',
|
||||
value: '≠'
|
||||
},
|
||||
{
|
||||
label: '>',
|
||||
value: '>'
|
||||
},
|
||||
{
|
||||
label: '≥',
|
||||
value: '>'
|
||||
},
|
||||
{
|
||||
label: '<',
|
||||
value: '<'
|
||||
},
|
||||
{
|
||||
label: '≤',
|
||||
value: '≤'
|
||||
}
|
||||
];
|
||||
|
||||
const logicIf = (value, index) => {
|
||||
if (value === 'always') {
|
||||
logics.value[index].logic = [logics.value[index].logic[0]];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.flex1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mr10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mb10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mv10 {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.action {
|
||||
flex: none;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.question-before {
|
||||
& .if {
|
||||
flex: none;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
& .question {
|
||||
flex: none;
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
& .group {
|
||||
flex: none;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
& .answer {
|
||||
flex: none;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
& .symbol {
|
||||
flex: none;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
& .option {
|
||||
//width: 120px;
|
||||
width: 100%;
|
||||
|
||||
//flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -79,13 +79,14 @@ const radioAddOption = () => {
|
||||
option_type: 0,
|
||||
limit_right_content: ''
|
||||
},
|
||||
option_index: 1,
|
||||
option_index: element.value.last_option_index + 1,
|
||||
parent_id: 0,
|
||||
type: 0,
|
||||
cascade: [],
|
||||
config: []
|
||||
});
|
||||
});
|
||||
element.value.last_option_index += 1;
|
||||
};
|
||||
|
||||
// emit 事件
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
class="iconfont active-icon"
|
||||
:style="{ marginRight: isLastPage ? '0' : '16px' }"
|
||||
@click="activePage"
|
||||
></i>
|
||||
></i
|
||||
>
|
||||
<template v-if="!isLastPage">
|
||||
<i class="iconfont moverQues" style="margin-right: 16px"></i>
|
||||
<i class="iconfont" @click="deleteHandle"></i>
|
||||
|
||||
Reference in New Issue
Block a user