mirror of
https://github.com/grey-cat-1908/formaptix-web.git
synced 2024-11-11 18:47:27 +03:00
more question types creation support && made questions prototypes draggable
This commit is contained in:
parent
6bcf0a1467
commit
4d7b0636ab
3 changed files with 127 additions and 23 deletions
|
@ -15,7 +15,8 @@
|
||||||
"@phosphor-icons/vue": "^2.2.1",
|
"@phosphor-icons/vue": "^2.2.1",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "^3.4.29",
|
"vue": "^3.4.29",
|
||||||
"vue-router": "^4.3.3"
|
"vue-router": "^4.3.3",
|
||||||
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node20": "^20.1.4",
|
"@tsconfig/node20": "^20.1.4",
|
||||||
|
|
|
@ -2,29 +2,51 @@
|
||||||
import { PhX, PhXCircle } from '@phosphor-icons/vue'
|
import { PhX, PhXCircle } from '@phosphor-icons/vue'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: {
|
||||||
|
label: 'Пустой Вопрос',
|
||||||
|
description: null,
|
||||||
|
question_type: 1,
|
||||||
|
required: false,
|
||||||
|
validator: null,
|
||||||
|
min_length: null,
|
||||||
|
max_length: null,
|
||||||
|
options: [],
|
||||||
|
min_values: null,
|
||||||
|
max_values: null,
|
||||||
|
min_value: 1,
|
||||||
|
max_value: 5,
|
||||||
|
min_label: null,
|
||||||
|
max_label: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
const emit = defineEmits(['input'])
|
const emit = defineEmits(['input'])
|
||||||
const data = ref({})
|
const data = ref({})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
data.value = {
|
data.value = { ...props.data }
|
||||||
label: null,
|
|
||||||
description: null,
|
|
||||||
question_type: 1,
|
|
||||||
required: false,
|
|
||||||
validator: null,
|
|
||||||
min_length: null,
|
|
||||||
max_length: null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function submitForm() {
|
async function submitForm() {
|
||||||
if (data.value.question_type === 1 && data.value.validator === null) {
|
if (data.value.question_type === 1) {
|
||||||
if (data.value.min_length !== null && data.value.min_length < 0) return
|
if (data.value.min_length !== null && data.value.min_length < 0) return
|
||||||
if (data.value.max_length !== null) {
|
if (data.value.max_length !== null) {
|
||||||
if (data.value.max_length <= 0) return
|
if (data.value.max_length <= 0) return
|
||||||
if (data.value.min_length !== null && data.value.max_length < data.value.min_length) return
|
if (data.value.min_length !== null && data.value.max_length < data.value.min_length) return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (data.value.question_type === 2) {
|
||||||
|
if (data.value.options.length < 1) return
|
||||||
|
if (data.value.min_values && data.value.min_values < 1) return
|
||||||
|
if (data.value.max_values && data.value.min_values > data.value.max_values) return
|
||||||
|
}
|
||||||
|
if (data.value.question_type === 3) {
|
||||||
|
if (!(data.value.min_value in [0, 1])) return
|
||||||
|
if (data.value.max_value < 2 || data.value.max_value > 10) return
|
||||||
|
}
|
||||||
|
|
||||||
emit('input', data.value)
|
emit('input', data.value)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +101,61 @@ async function submitForm() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="" v-if="data.question_type === 2">
|
||||||
|
<div class="">
|
||||||
|
<div class="">
|
||||||
|
<p>Варианты</p>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(option, index) in data.options">
|
||||||
|
<input v-model="data.options[index].label" />
|
||||||
|
<span @click="data.options.splice(index, 1)">X</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span
|
||||||
|
style="text-decoration: underline dashed"
|
||||||
|
@click="data.options.push({ label: 'Вариант' })"
|
||||||
|
>Добавить вариант</span
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<p>Минимум значений</p>
|
||||||
|
<input v-model="data.min_values" type="number" placeholder="1" />
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<p>Максимум значений</p>
|
||||||
|
<input v-model="data.max_values" type="number" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="" v-if="data.question_type === 3">
|
||||||
|
<div class="">
|
||||||
|
<div class="">
|
||||||
|
<div class="">
|
||||||
|
<p>
|
||||||
|
От
|
||||||
|
<select required v-model="data.min_value">
|
||||||
|
<option :value="0">0</option>
|
||||||
|
<option :value="1">1</option>
|
||||||
|
</select>
|
||||||
|
до
|
||||||
|
<select required v-model="data.max_value">
|
||||||
|
<option v-for="value in 9" :value="1 + value">{{ 1 + value }}</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<p>{{ data.min_value }}</p>
|
||||||
|
<input v-model="data.min_label" />
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<p>{{ data.max_value }}</p>
|
||||||
|
<input v-model="data.max_label" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<p>Обязательный?</p>
|
<p>Обязательный?</p>
|
||||||
|
@ -87,7 +164,7 @@ async function submitForm() {
|
||||||
<span class="slider"></span>
|
<span class="slider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit">Сохранить</button>
|
<button>Сохранить</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,27 +1,53 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import QuestionEdit from '@/components/edit/QuestionEdit.vue'
|
import QuestionEdit from '@/components/edit/QuestionEdit.vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
const questions = ref([])
|
const pages = ref([
|
||||||
|
{ text: 'Тестовый текст 1', questions: [] },
|
||||||
|
{ text: 'лоре ипсум долор сит амет', questions: [] }
|
||||||
|
])
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
|
|
||||||
|
function addNewQuestion(event: any) {
|
||||||
|
pages.value[pages.value.length - 1].questions.push(event)
|
||||||
|
showDialog.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QuestionEdit
|
<QuestionEdit v-if="showDialog" @input="addNewQuestion($event)" />
|
||||||
v-if="showDialog"
|
|
||||||
@input="
|
|
||||||
questions.push($event)
|
|
||||||
showDialog = false
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<button @click="showDialog = true">Создать</button>
|
<button @click="showDialog = true">Создать</button>
|
||||||
<button>Сохранить</button>
|
<button>Сохранить</button>
|
||||||
<button>Превью</button>
|
<button>Превью</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div>
|
||||||
{{ questions }}
|
<div v-for="(page, index) in pages">
|
||||||
|
<div>
|
||||||
|
<h3>Страница {{ index + 1 }}</h3>
|
||||||
|
<p>{{ page.text }}</p>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<draggable group="questions" :list="page.questions">
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div style="cursor: pointer">{{ element.label }}</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss">
|
||||||
|
.drop-zone {
|
||||||
|
background-color: #eee;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-el {
|
||||||
|
background-color: #fff;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue