Merge remote-tracking branch 'origin/feature/feature-20250331-h5' into feature/feature-20250331-h5

# Conflicts:
#	src/views/Design/components/Questions/MatrixCheckbox.vue
#	src/views/Survey/views/Preview/components/questions/PreviewNPS.vue
#	src/views/Survey/views/Preview/components/questions/PreviewRate.vue
This commit is contained in:
陈昱达
2025-03-23 17:57:06 +08:00
22 changed files with 73 additions and 160 deletions

7
components.d.ts vendored
View File

@@ -8,14 +8,9 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
Contenteditable: typeof import('./src/components/contenteditable.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSpace: typeof import('element-plus/es')['ElSpace']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElText: typeof import('element-plus/es')['ElText']
@@ -34,7 +29,6 @@ declare module 'vue' {
VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem']
VanIcon: typeof import('vant/es')['Icon']
VanList: typeof import('vant/es')['List']
VanNavBar: typeof import('vant/es')['NavBar']
VanPicker: typeof import('vant/es')['Picker']
VanPopover: typeof import('vant/es')['Popover']
@@ -42,7 +36,6 @@ declare module 'vue' {
VanRadio: typeof import('vant/es')['Radio']
VanRadioGroup: typeof import('vant/es')['RadioGroup']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanStepper: typeof import('vant/es')['Stepper']
VanSwitch: typeof import('vant/es')['Switch']
VanTab: typeof import('vant/es')['Tab']

View File

@@ -69,9 +69,7 @@ const element = defineModel('element', {
return {};
}
});
const index = defineModel('index', {
type: Number
});
const index = defineModel('index');
// watch(
// () => index.value,

View File

@@ -130,8 +130,7 @@ defineProps({
default: false
},
index: {
type: Number,
default: 0
default: ''
}
});
@@ -157,6 +156,8 @@ function handleChange(names) {
const newOption = names[names.length - 1];
// 如果names 长度小于1直接返回不处理
if (names.length < 1) return;
// 如果不存在 options 和 list 属性,直接返回
if (!element.value.options || !element.value.list) return;
const options = element.value.options[0] ?? element.value.list[0];
// 如果新增的结果是排它项, 对结果进行处理

View File

@@ -45,7 +45,6 @@ const props = defineProps({
}
},
index: {
type: Number,
default: 0
},
active: {

View File

@@ -7,7 +7,7 @@ import { fileLimit, answer } from './hooks/useFileUploadHooks';
const isPreview = defineModel('isPreview', { default: false, type: Boolean, required: false });
const props = defineProps<{
element: any;
index: number;
index: number | String;
active: boolean;
}>();
const { element } = toRefs(props);

View File

@@ -28,7 +28,7 @@ const rows = defineModel<_questionOptionType[]>('rows', { required: false, defau
// 列标签
const cols = defineModel<_questionOptionType[]>('cols', { required: false, default: () => [] });
// 题的序号
const index = defineModel<number>('index', { required: false, default: 0 });
const index = defineModel<number|string>('index', { required: false, default: 0 });
// 是否是编辑状态
const active = defineModel<boolean>('active', { required: false, default: false });

View File

@@ -58,8 +58,7 @@ const isPreview = defineModel('isPreview', { default: false, type: Boolean });
default: false
},
index: {
type: Number,
default: 0
default: ''
},
active: {
type: Boolean,

View File

@@ -1,42 +1,22 @@
<template>
<div class="content">
<van-field
v-model="element.stem"
:label="element.stem"
:required="element.config.is_required === 1"
label-align="top"
class="contenteditable-question-title"
>
<van-field v-model="element.stem" :label="element.stem" :required="element.config.is_required === 1"
label-align="top" class="contenteditable-question-title">
<template #left-icon> {{ isPreview ? element.title : index + 1 }}. </template>
<template #label>
<contenteditable
v-model="element.stem"
:active="active"
@blur="emitValue"
className="contenteditable-label"
:errorMessage="errorMessage"
></contenteditable>
<contenteditable v-model="element.stem" :active="active" @blur="emitValue" className="contenteditable-label"
:errorMessage="errorMessage"></contenteditable>
</template>
<template #input>
<div
v-for="(optionItem, optionItemIndex) in element.list ?? element.options"
:key="optionItemIndex"
class="rate-content"
>
<div
v-for="(item, optionIndex) in isPreview ? optionItem.options : optionItem"
:key="optionIndex"
class="rate-item"
@click="chooseOption(item)"
>
<div v-for="(optionItem, optionItemIndex) in element.list ?? element.options" :key="optionItemIndex"
class="rate-content">
<div v-for="(item, optionIndex) in isPreview ? optionItem.options : optionItem" :key="optionIndex"
class="rate-item" @click="chooseOption(item)">
<div class="mb5">
<contenteditable v-model="item.option" :active="active"></contenteditable>
</div>
<div class="mb10">
<RateCharacter
v-model:model="answerValue[optionIndex]"
:config="element.config"
></RateCharacter>
<RateCharacter v-model:model="answerValue[optionIndex]" :config="element.config"></RateCharacter>
</div>
<div class="tips">
@@ -76,7 +56,6 @@ defineProps({
default: false
},
index: {
type: Number,
default: 0
},
sn: { type: String, default: '' },

View File

@@ -6,7 +6,7 @@ const element = defineModel<question>('element', { default: {} });
// 属性框是否激活
const active = defineModel<boolean>('active', { default: false });
// 题目索引
const index = defineModel<number>('index', { default: 0 });
const index = defineModel<number | string>('index', { default: 0 });
// 答案
const answer = defineModel<string>('answer', { default: '' });
// 错误信息
@@ -197,44 +197,23 @@ async function handleUploadImg() {
</script>
<template>
<van-field
:label="element.stem"
:required="element.config.is_required === 1"
label-align="top"
:border="false"
readonly
>
<van-field :label="element.stem" :required="element.config.is_required === 1" label-align="top" :border="false"
readonly>
<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>
<contenteditable v-model="element.stem" className="contenteditable-label" :active="active" @blur="emitValue"
:errorMessage="errorMessage"></contenteditable>
</template>
<template #input>
<div class="sign-question">
<canvas
ref="signatureCanvas"
:width="canvasWidth"
:height="canvasHeight"
style="border: 1px dashed #ccc; border-radius: 4px"
>
<canvas ref="signatureCanvas" :width="canvasWidth" :height="canvasHeight"
style="border: 1px dashed #ccc; border-radius: 4px">
</canvas>
<div class="sign-text" :class="{ show: true }">
<span
class="icon mobilefont mobilefont-qingkong"
title="清空"
@click="clearCanvas"
></span>
<span class="icon mobilefont mobilefont-qingkong" title="清空" @click="clearCanvas"></span>
<span class="icon mobilefont mobilefont-chexiao" @click="undo"></span>
<span
class="icon mobilefont"
:class="isEraser ? 'mobilefont-huabi' : 'mobilefont-rubber'"
@click="togglePen"
></span>
<span class="icon mobilefont" :class="isEraser ? 'mobilefont-huabi' : 'mobilefont-rubber'"
@click="togglePen"></span>
<span class="icon mobilefont mobilefont-shangchuan" @click="handleUploadImg"></span>
</div>
<div class="sign-tips">请在空白区域书写您的签名</div>

View File

@@ -1,21 +1,11 @@
<template>
<div class="text-with-images-container">
<van-field
readonly
:label="element.stem"
:required="element.config?.is_required === 1"
label-align="top"
class="base-select contenteditable-question-title"
>
<van-field readonly :label="element.stem" :required="element.config?.is_required === 1" label-align="top"
class="base-select contenteditable-question-title">
<template #left-icon> {{ isPreview ? element.title : index + 1 }}. </template>
<template #label>
<contenteditable
v-model="element.stem"
:active="active"
className="contenteditable-label"
@blur="emitValue"
:errorMessage="errorMessage"
></contenteditable>
<contenteditable v-model="element.stem" :active="active" className="contenteditable-label" @blur="emitValue"
:errorMessage="errorMessage"></contenteditable>
</template>
</van-field>
</div>
@@ -41,7 +31,6 @@ const props = defineProps({
default: false
},
index: {
type: Number,
default: 0
}
});

View File

@@ -8,7 +8,7 @@
/>
</template>
<script setup lang="ts">
import { watch, ref } from 'vue';
import { watch, ref, computed } from 'vue';
import Choice from '@/views/Design/components/Questions/Choice.vue';
type answerType = {
@@ -24,9 +24,9 @@ type answerType = {
*/
// 预览新增 v-model
const answer = defineModel<answerType>('answer', { default: undefined });
const answerIndex = defineModel<number>('answerIndex');
// const stem = defineModel<string>('stem', { default: '' });
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
const answerIndex = computed<string>(() => question.value.title);
// const list = defineModel<questionsList[]>('list', { default: [[]] });
initData();

View File

@@ -8,7 +8,7 @@
/>
</template>
<script setup lang="ts">
import { watch, ref } from 'vue';
import { watch, ref, computed } from 'vue';
import Choice from '@/views/Design/components/Questions/Choice.vue';
type answerType = {
@@ -17,7 +17,7 @@ type answerType = {
};
// // 预览新增 v-model
const answer = defineModel<answerType>('answer', { default: undefined });
const answerIndex = defineModel<number>('answerIndex');
const answerIndex = computed(() => question.value.title);
// const stem = defineModel<string>('stem', { default: '' });4
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
const list = defineModel<questionsList[]>('list', { default: [[]] });

View File

@@ -10,13 +10,15 @@
></completion>
</template>
<script setup lang="ts">
import { defineEmits, ref, watch } from 'vue';
import { computed, defineEmits, ref, watch } from 'vue';
import Completion from '@/views/Design/components/Questions/Completion.vue';
import Rate from '@/views/Design/components/Questions/Rate.vue';
// 预览新增 v-model
// const config = defineModel('config');
const answer = defineModel<{ value: string | number }>('answer', { default: { value: '' } });
const answerIndex = defineModel<number>('answerIndex');
const answerIndex = computed(() => {
return question.value.title;
});
// const stem = defineModel('stem');
const question = defineModel<question>('question', { default: () => {} });
// const list = defineModel<questionsList[]>('list');

View File

@@ -1,10 +1,10 @@
<script setup lang="ts">
import FileUpload from '@/views/Design/components/Questions/FileUpload.vue';
const questionIndex = defineModel<number>('questionIndex', { default: NaN });
const answerIndex = defineModel<number>('answerIndex', { default: NaN });
const answerIndex = computed(() => question.value.title);
const question = defineModel<question>('question', { default: () => {} });
import { answer } from '@/views/Design/components/Questions/hooks/useFileUploadHooks';
import { watch } from 'vue';
import { computed, watch } from 'vue';
const emit = defineEmits(['changeAnswer']);
watch(answer, () => {

View File

@@ -1,13 +1,6 @@
<template>
<MatrixQuestion
v-model:rowRecord="rowRecord"
v-model:matrix-radio-answer="answer!"
:rows="rows"
:cols="cols"
:is-preview="true"
:errorMessage="question.error"
:element="question"
/>
<MatrixQuestion :index="answerIndex" v-model:rowRecord="rowRecord" v-model:matrix-radio-answer="answer!" :rows="rows"
:cols="cols" :is-preview="true" :errorMessage="question.error" :element="question" />
</template>
<script setup lang="ts">
@@ -25,6 +18,7 @@ type answerType = {
// const list = defineModel<questionsList[]>('list', { required: false });
// const config = defineModel<OptionConfigType>('config', { required: false });
const question = defineModel<question>('question', { default: () => { } });
const answerIndex = computed(() => question.value.title);
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
// 示例
// {

View File

@@ -1,14 +1,6 @@
<template>
<MatrixQuestion
v-model:rowRecord="rowRecord"
:rows="rows"
:cols="cols"
:index="questionIndex"
:element="question"
:is-preview="true"
:active="false"
:errorMessage="question.error"
/>
<MatrixQuestion v-model:rowRecord="rowRecord" :rows="rows" :cols="cols" :index="answerIndex" :element="question"
:is-preview="true" :active="false" :errorMessage="question.error" />
</template>
<script setup lang="ts">
@@ -27,7 +19,7 @@ type answerType = {
// const list = defineModel<questionsList[]>('list', { required: false });
// const config = defineModel<OptionConfigType>('config', { required: false });
const question = defineModel<question>('question', { default: () => { } });
const questionIndex = defineModel<number>('answerIndex', { required: false, default: 0 });
const answerIndex = computed(() => question.value?.title ?? 0);
// console.log(question.value);
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
// 示例

View File

@@ -1,21 +1,13 @@
<template>
<MatrixQuestion
v-model:rowRecord="rowRecord"
:rows="rows"
:cols="cols"
:index="questionIndex"
:element="question"
:is-preview="true"
:active="false"
:errorMessage="question.error"
/>
<MatrixQuestion v-model:rowRecord="rowRecord" :rows="rows" :cols="cols" :index="answerIndex" :element="question"
:is-preview="true" :active="false" :errorMessage="question.error" />
</template>
<script setup lang="ts">
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
import { computed, ref, watch } from 'vue';
import MatrixQuestion from '@/views/Design/components/Questions/MatrixQuestion.vue';
const questionIndex = defineModel<number>('answerIndex', { required: false, default: 0 });
const answerIndex = computed(() => question.value?.title ?? 0);
// 矩阵多选的答案类型
type answerType = {

View File

@@ -13,13 +13,13 @@
<script setup lang="ts">
import NPS from '@/views/Design/components/Questions/NPS.vue';
import { watch, ref } from 'vue';
import Rate from '@/views/Design/components/Questions/Rate.vue';
import { watch, ref, computed } from 'vue';
const value = ref(-1);
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
const emit = defineEmits(['changeAnswer', 'previous', 'next', 'update:element']);
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
/**
* answer 的答案类型
* {
@@ -27,7 +27,9 @@ const question = defineModel<question>('question', { default: { config: { is_req
* }
*/
const answer = defineModel<NPSAnswerType>('answer', { default: undefined });
const answerIndex = defineModel<number>('answerIndex', { default: undefined });
const answerIndex = computed(() => {
return question.value.title;
});
// 解析答案
// function parseAnswer() {

View File

@@ -12,7 +12,7 @@
<script setup lang="ts">
import Rate from '@/views/Design/components/Questions/Rate.vue';
import { watch, ref, nextTick } from 'vue';
import { watch, ref, nextTick, computed } from 'vue';
const value = ref<number[]>([]);
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
@@ -26,7 +26,7 @@ const question = defineModel<question>('question', { default: { config: { is_req
* }
*/
const answer = defineModel<NPSAnswerType>('answer', { default: undefined });
const answerIndex = defineModel<number>('answerIndex', { default: undefined });
const answerIndex = computed(() => question.value?.title ?? 0);
parseAnswer();
// 解析答案

View File

@@ -1,12 +1,11 @@
<script setup lang="ts">
import SignQuestion from '@/views/Design/components/Questions/SignQuestion.vue';
import { ref, watch } from 'vue';
import Rate from '@/views/Design/components/Questions/Rate.vue';
import { ref, watch, computed } from 'vue';
const question = defineModel<question>('question', { default: {} });
const answer = defineModel<{ value: string }>('answer', { default: undefined });
const answerValue = ref<string>('');
const answerIndex = defineModel<number>('answerIndex', { default: 0 });
const answerIndex = computed(() => question.value?.title ?? 0);
// emit
const emit = defineEmits(['changeAnswer']);
@@ -32,13 +31,7 @@ function parseAnswer() {
</script>
<template>
<sign-question
:element="question"
:active="false"
:isPreview="true"
:index="answerIndex"
v-model:answer="answerValue"
:error-message="question.error"
/>
<sign-question :element="question" :active="false" :isPreview="true" :index="answerIndex" v-model:answer="answerValue"
:error-message="question.error" />
</template>
<style scoped lang="scss"></style>

View File

@@ -1,10 +1,11 @@
<script setup lang="ts">
import TextWithImages from '@/views/Design/components/Questions/TextWithImages.vue';
import { computed } from 'vue';
// 问题
const question = defineModel<question>('question', { default: {} });
// question 序号
const answerIndex = defineModel('answerIndex', { default: 0 });
const answerIndex = computed(() => question.value?.title ?? 0);
// 答案
const answer = defineModel('answer', { default: {} });
// answer 提供默认值