aboutsummaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
authorMichaela Brückner <brueckner@data-quest.de>2026-03-11 15:17:34 +0100
committerMichaela Brückner <brueckner@data-quest.de>2026-03-17 10:55:55 +0100
commit3b41f51cde8107d6143ef0644305af1c8bd55e32 (patch)
treed6e789698617eeefa34ccbf0ee079aa4f0e332dd /resources
parentb8be6de23339c7a6e8bdd512924b86812ff35782 (diff)
re #6193issue-6193
Diffstat (limited to 'resources')
-rw-r--r--resources/vue/apps/questionnaires/QuestionnaireAnswer.vue39
-rw-r--r--resources/vue/components/questionnaires/VoteAnswer.vue91
2 files changed, 90 insertions, 40 deletions
diff --git a/resources/vue/apps/questionnaires/QuestionnaireAnswer.vue b/resources/vue/apps/questionnaires/QuestionnaireAnswer.vue
index 178930c..169550a 100644
--- a/resources/vue/apps/questionnaires/QuestionnaireAnswer.vue
+++ b/resources/vue/apps/questionnaires/QuestionnaireAnswer.vue
@@ -7,8 +7,6 @@
:data-dialog="asDialog ? true : null"
:data-secure="activateFormSecure"
>
-
-
<div v-if="questionnaireData.questions[currentPage]">
<div class="questionnaire_answer">
@@ -40,14 +38,11 @@
<button :style="{visibility: currentPage > 0 ? 'visible' : 'hidden'}" class="button arr_left" @click="prevPage">
{{ $gettext('zurück') }}
</button>
-
<button :style="{visibility: currentPage < totalPages - 1 ? 'visible' : 'hidden'}" class="button arr_right" @click="nextPage">
{{ $gettext('weiter') }}
</button>
-
</div>
-
<div class="terms">
<span v-if="questionnaireData.anonymous == 1 ">{{ $gettext('Die Teilnahme ist anonym.') }}</span>
<span v-else>{{ $gettext('Die Teilnahme ist nicht anonym.') }}</span>
@@ -55,7 +50,35 @@
<span v-if="questionnaireData.stopdate">{{ $gettext('Sie können den Fragebogen beantworten bis zum %{date} um %{time} Uhr.', {date:getFormattedDate, time:getFormattedTime}) }}</span>
</div>
+ <div data-dialog-button style="text-align: center;">
+
+ <template v-if="config.isAnswerable">
+ <button class="button">{{ $gettext('Speichern') }}</button>
+ </template>
+ <template v-if="config.resultsVisible">
+ <button class="button">{{ $gettext('Ergebnisse anzeigen') }}</button>
+ </template>
+ <template v-if="config.isEditable && (!config.isRunning || config.countAnswers.length > 0)">
+ <button class="button">{{ $gettext('Bearbeiten') }}</button>
+ </template>
+ <template v-if="config.isEditable">
+ <button class="button">{{ $gettext('Kontext auswählen') }}</button>
+ </template>
+ <template v-if="config.isCopyable">
+ <button class="button">{{ $gettext('Kopieren') }}</button>
+ </template>
+ <template v-if="config.isEditable && !config.isRunning">
+ <button class="button">{{ $gettext('Starten') }}</button>
+ </template>
+ <template v-if="config.isEditable && config.isRunning">
+ <button class="button">{{ $gettext('Beenden') }}</button>
+ </template>
+
+
+ </div>
+
</form>
+ {{ config }}
</template>
<script setup>
@@ -77,7 +100,8 @@ import LikertAnswer from '../../components/questionnaires/LikertAnswer.vue';
import AutomatedDataAnswer from '../../components/questionnaires/AutomatedDataAnswer.vue';
const props = defineProps({
- questionnaireData: Object
+ questionnaireData: Object,
+ config: Object
})
const currentPage = ref(0)
@@ -117,4 +141,7 @@ const getFormattedTime = computed(() => {
})
+
+
+
</script>
diff --git a/resources/vue/components/questionnaires/VoteAnswer.vue b/resources/vue/components/questionnaires/VoteAnswer.vue
index 7ee5cbd..57ff98a 100644
--- a/resources/vue/components/questionnaires/VoteAnswer.vue
+++ b/resources/vue/components/questionnaires/VoteAnswer.vue
@@ -1,18 +1,6 @@
-<!--
-$answers = $vote->questiondata['options'];
-$indexMap = count($answers) ? range(0, count($answers) - 1) : [];
-if ($vote->questiondata['randomize']) {
-shuffle($indexMap);
-}
-
-$response = $vote->getMyAnswer();
-$responseData = $response['answerdata'] ? $response['answerdata']->getArrayCopy() : [];
--->
-
<template>
<div :class="{ mandatory: question.questiondata.mandatory == 1}">
- <!-- TODO questionnaire/_answer_description_container as template? -->
<div class="description_container">
<div class="icon_container">
<StudipIcon shape="vote"
@@ -26,31 +14,50 @@ $responseData = $response['answerdata'] ? $response['answerdata']->getArrayCopy(
<div v-html="question.questiondata.description"></div>
</article>
</div>
- <!-- -->
<!-- hidden invalidation notice -->
<ul class="clean">
- <li v-for="(answer, index) in shuffledOptions"
- :key="index">
- <label>
+ <li v-for="option in shuffledOptions" :key="option.index">
+ <!-- name="answers[<?= $vote->getId() ?>][answerdata][answers][<?= $index ?>]" -->
<input
:type="question.questiondata.multiplechoice == 1 ? 'checkbox' : 'radio'"
- :name="'question-' + question.id"
- :value="answer"
+ :name="'answers[' + question.id + '][answerdata][answers][' + option.index + ']'"
+ :value="option.index"
v-model="userAnswer"
+ :id="'question-' + question.id + '-' + option.index"
/>
-
- {{ answer }}
- </label>
-
+ <label :for="'question-' + question.id + '-' + option.index" class="question-label">{{ option.answer }}</label>
</li>
+ <template v-if="question.questiondata.freetextfield == 1">
+ <li>
+ <input
+ :type="question.questiondata.multiplechoice == 1 ? 'checkbox' : 'radio'"
+ :name="'question-' + question.id"
+ v-model="freeTextEnabled"
+ id="free_answer"
+ :aria-label="$gettext('Geben Sie eine andere Antwort an')"
+ />
+ <label id="free_answer_label" for="free_answer" class="question-label">{{ $gettext('Sonstiges') + ':' }}</label>
+
+ <div>
+ <textarea
+ v-model="freeTextAnswer"
+ :disabled="!freeTextEnabled"
+ aria-labelledby="free_answer_label"
+ ></textarea>
+ </div>
+
+ </li>
+ </template>
+
</ul>
</div>
<pre>{{ userAnswer }}</pre>
+ <pre>{{ freeTextAnswer }}</pre>
</template>
@@ -68,31 +75,38 @@ const props = defineProps({
})
const shuffledOptions = ref([])
-const userAnswer = ref(null) // Radio
-// Für Checkbox später automatisch Array
+const userAnswer = ref([])
+const freeTextAnswer = ref('')
+const freeTextEnabled = ref(false)
function prepareAnswers() {
- const options = [...props.question.questiondata.options]
+ const options = props.question.questiondata.options
+
+ // Antworten mit Originalindex kombinieren
+ const mapped = options.map((answer, index) => ({
+ answer,
+ index
+ }))
+ // Shuffle falls aktiviert
if (props.question.questiondata.randomize == 1) {
- for (let i = options.length - 1; i > 0; i--) {
+ for (let i = mapped.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
- ;[options[i], options[j]] = [options[j], options[i]]
+ ;[mapped[i], mapped[j]] = [mapped[j], mapped[i]]
}
}
- shuffledOptions.value = options
+ shuffledOptions.value = mapped
}
+
function initUserAnswer() {
+ const answers = props.question.responseData?.answers ?? []
+
if (props.question.questiondata.multiplechoice == 1) {
- // Checkbox → Array
- userAnswer.value = Array.isArray(props.question.responseData)
- ? props.question.responseData
- : []
+ userAnswer.value = answers
} else {
- // Radio → Einzelwert
- userAnswer.value = props.question.responseData || null
+ userAnswer.value = answers[0] ?? null
}
}
@@ -112,3 +126,12 @@ watch(
</script>
+<style scoped lang="scss">
+
+
+ .question-label {
+ display: inline !important;
+ }
+
+
+</style>