feat: 完成 预览功能, 适配组件
- 完成预览的功能,可以提供回看已经提交的内容 - 适配单选、矩阵、文件上传、填空等组件 - question 的类型添加 answre 字段
This commit is contained in:
@@ -76,7 +76,7 @@
|
||||
:index="index"
|
||||
:active="chooseQuestionId === element.id"
|
||||
@update:element="updateElement"
|
||||
></file-upload>
|
||||
/>
|
||||
|
||||
<!--图文-->
|
||||
<TextWithImages
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<van-field
|
||||
v-model="element.stem"
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
v-model="element.stem" :label="element.stem" :required="element.config.is_required === 1" label-align="top"
|
||||
class="base-select"
|
||||
>
|
||||
<template #left-icon>
|
||||
@@ -15,17 +12,10 @@
|
||||
<template #input>
|
||||
<template v-for="(item, optionIndex) in element.options" :key="item.id">
|
||||
<van-radio-group v-if="element.question_type === 1" v-model="choiceValue">
|
||||
<option-action
|
||||
v-model:data="element.options[optionIndex]"
|
||||
:active="active"
|
||||
:question="element"
|
||||
>
|
||||
<option-action :data="isPreview ? item.options : item" :active="active" :question="element">
|
||||
<template #item="{ element: it, index: itIndex }">
|
||||
<van-radio
|
||||
:key="itIndex"
|
||||
:name="it.option_index"
|
||||
:label="it.label"
|
||||
:disabled="it.disabled"
|
||||
:key="itIndex" :name="it.option_index" :label="it.label" :disabled="it.disabled"
|
||||
icon-size="0.45rem"
|
||||
>
|
||||
<!-- 自定义文本 -->
|
||||
@@ -42,17 +32,10 @@
|
||||
</option-action>
|
||||
</van-radio-group>
|
||||
<van-checkbox-group v-if="element.question_type === 2" v-model="value" shape="square">
|
||||
<option-action
|
||||
v-model:data="element.options[optionIndex]"
|
||||
:active="active"
|
||||
:question="element"
|
||||
>
|
||||
<option-action v-model:data="element.options[optionIndex]" :active="active" :question="element">
|
||||
<template #item="{ element: it, index: itIndex }">
|
||||
<van-checkbox
|
||||
:key="itIndex"
|
||||
:name="it.option_index"
|
||||
:label="it.label"
|
||||
:disabled="it.disabled"
|
||||
:key="itIndex" :name="it.option_index" :label="it.label" :disabled="it.disabled"
|
||||
icon-size="0.45rem"
|
||||
>
|
||||
<template #default>
|
||||
@@ -75,7 +58,12 @@
|
||||
import OptionAction from '@/views/Design/components/ActionCompoents/OptionAction.vue';
|
||||
import { defineAsyncComponent, toRefs, ref } from 'vue';
|
||||
|
||||
const choiceValue = ref('checked');
|
||||
// 是否是预览
|
||||
const isPreview = defineModel('isPreview', { default: false });
|
||||
const choiceValue = defineModel('answer', { default: '1', type: String });
|
||||
|
||||
console.log(`choiceValue.value`, choiceValue.value);
|
||||
|
||||
const Contenteditable = defineAsyncComponent(() => import('@/components/contenteditable.vue'));
|
||||
const props = defineProps({
|
||||
element: {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
</template>
|
||||
<template #input>
|
||||
<textarea
|
||||
v-model="completionValue"
|
||||
class="other_input"
|
||||
:placeholder="element.config.placeholder"
|
||||
:rows="element.config.line_height"
|
||||
@@ -29,6 +30,8 @@
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
|
||||
const completionValue = defineModel('completionValue', { default: '' });
|
||||
const props = defineProps({
|
||||
element: {
|
||||
type: Object,
|
||||
|
||||
@@ -3,29 +3,23 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
v-if="col.editor" v-model="col.option" v-focus type="text" @focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option" />
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option" />
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@change="handleColNameChange(row.option, col.option, $event)"
|
||||
type="checkbox" :name="`R${rowIndex + 1}`" :value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)" @change="handleMatrixRadioChange(rowIndex, colIndex)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -37,50 +31,73 @@
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const props = defineProps<{
|
||||
rows: { option: string }[];
|
||||
columns: { option: string; editor?: boolean }[];
|
||||
questionType: number;
|
||||
matrixAnswer: { [key: string]: any };
|
||||
rowRecord:(number | string)[];
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<number[][]>('rowRecord', { required: false, default: () => [] });
|
||||
// const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) });
|
||||
// 检查 rowRecord 是否存在
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
/* const isPreview = */defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
|
||||
/* const emits = */ defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
// 判断是否选中
|
||||
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||
const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
return !!props.matrixAnswer[key];
|
||||
// [
|
||||
// [0, 1],
|
||||
// [0, 1]
|
||||
// ]
|
||||
if (!rowRecord.value[rowIndex]) {
|
||||
return false;
|
||||
}
|
||||
return rowRecord.value[rowIndex].includes(colIndex);
|
||||
};
|
||||
|
||||
const handleRowNameChange = () => {
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
// const handleColNameChange = (rowOption: string, colOption: string, e: Event) => {
|
||||
// const target = e.target as HTMLInputElement;
|
||||
// const col = props.columns.findIndex(option => option.option === colOption);
|
||||
// const row = props.rows.findIndex(option => option.option === rowOption);
|
||||
//
|
||||
// if (props.questionType === 10) {
|
||||
// if (target.checked) {
|
||||
// props.rowRecord[col] = (props.rowRecord[col] || []).concat(row + 1);
|
||||
// } else {
|
||||
// props.rowRecord[col] = (props.rowRecord[col] || []).filter(item => item !== row + 1);
|
||||
// }
|
||||
// const newMatrixAnswer: { [key: string]: boolean } = {};
|
||||
// const newRowRecord: (number | string)[] = [...props.rowRecord];
|
||||
// props.rows.forEach((rowOption, rowIndex) => {
|
||||
// const colOptions = newRowRecord[rowIndex];
|
||||
// if (colOptions) {
|
||||
// colOptions.forEach((col: any) => {
|
||||
// newMatrixAnswer[`R${rowIndex + 1}_C${col}`] = true;
|
||||
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
||||
function handleMatrixRadioChange(row: number, col: number) {
|
||||
// 获取 colIndexArray
|
||||
if (!rowRecord.value[row]) {
|
||||
// 如果没有对应的row,创建一个
|
||||
rowRecord.value[row] = [];
|
||||
}
|
||||
// cols 的逻辑 和 handleMatrixRadioChange 一致
|
||||
const cols = rowRecord.value[row];
|
||||
|
||||
// 检查 cols 对应的 col 是否有 数值
|
||||
if (cols.includes(col)) {
|
||||
// 如果有,删除
|
||||
cols.splice(cols.indexOf(col), 1);
|
||||
} else {
|
||||
// 如果没有,添加
|
||||
cols.push(col);
|
||||
}
|
||||
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
}
|
||||
// const handleColNameChange = (rowOption: string, colOption: string) => {
|
||||
// // const target = e.target as HTMLInputElement;
|
||||
// const col = props.columns.findIndex((option) => option.option === colOption);
|
||||
// const row = props.rows.findIndex((option) => option.option === rowOption);
|
||||
|
||||
// if (props.questionType === 9) {
|
||||
// props.rowRecord[col] = row + 1;
|
||||
// props.matrixAnswer = {};
|
||||
// props.rowRecord.forEach((row, index) => {
|
||||
// props.matrixAnswer[`${index + 1}_${row}`] = 1;
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// emits('update:matrixAnswer', newMatrixAnswer);
|
||||
// emits('update:rowRecord', newRowRecord);
|
||||
|
||||
// emits('update:matrixAnswer', props.matrixAnswer);
|
||||
// emits('update:rowRecord', props.rowRecord);
|
||||
// };
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,14 +3,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
v-if="col.editor" v-model="col.option" v-focus type="text" @focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
@@ -20,13 +16,10 @@
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="radio"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@change="handleColNameChange(row.option, col.option, $event)"
|
||||
type="radio" :name="`R${rowIndex + 1}`" :value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)" @change="handleMatrixRadioChange(rowIndex, colIndex)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -38,19 +31,28 @@
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const props = defineProps<{
|
||||
rows: { option: string }[];
|
||||
columns: { option: string; editor?: boolean }[];
|
||||
questionType: number;
|
||||
matrixAnswer: { [key: string]: any };
|
||||
rowRecord:(number | string)[];
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] });
|
||||
// const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) });
|
||||
// 检查 rowRecord 是否存在
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
/* const isPreview = */defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
|
||||
/* const emits = */ defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
// 判断是否选中
|
||||
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||
const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
return !!props.matrixAnswer[key];
|
||||
// console.log(`rowIndex: ${rowIndex}, colIndex: ${colIndex}`);
|
||||
// console.log(`rowRecord.value[rowIndex] === colIndex`, rowRecord.value[rowIndex] === colIndex);
|
||||
|
||||
return rowRecord.value[rowIndex] === colIndex;
|
||||
// const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
// return !!matrixAnswer.value?.[key];
|
||||
};
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
@@ -58,11 +60,19 @@ const handleRowNameChange = (/* value: string */) => {
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
||||
function handleMatrixRadioChange(row: number, col: number) {
|
||||
rowRecord.value[row] = col;
|
||||
// matrixAnswer.value = {};
|
||||
// rowRecord.value.forEach((row, col) => {
|
||||
// matrixAnswer.value[`${col + 1}_${row}`] = 1;
|
||||
// });
|
||||
}
|
||||
// const handleColNameChange = (rowOption: string, colOption: string) => {
|
||||
// // const target = e.target as HTMLInputElement;
|
||||
// const col = props.columns.findIndex((option) => option.option === colOption);
|
||||
// const row = props.rows.findIndex((option) => option.option === rowOption);
|
||||
//
|
||||
|
||||
// if (props.questionType === 9) {
|
||||
// props.rowRecord[col] = row + 1;
|
||||
// props.matrixAnswer = {};
|
||||
@@ -70,7 +80,7 @@ const handleRowNameChange = (/* value: string */) => {
|
||||
// props.matrixAnswer[`${index + 1}_${row}`] = 1;
|
||||
// });
|
||||
// }
|
||||
//
|
||||
|
||||
// emits('update:matrixAnswer', props.matrixAnswer);
|
||||
// emits('update:rowRecord', props.rowRecord);
|
||||
// };
|
||||
|
||||
@@ -3,14 +3,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
v-if="col.editor" v-model="col.option" v-focus type="text" @focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
@@ -20,11 +16,10 @@
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="text"
|
||||
:value="matrixAnswer[`${rowIndex + 1}_${colIndex + 1}`]"
|
||||
@change="handleColNameChange(row.option, col.option, $event, rowIndex, colIndex)"
|
||||
type="text" :name="`R${rowIndex + 1}`" :value="getInputValue(rowIndex, colIndex)"
|
||||
@change="handleMatrixTextChange(rowIndex, colIndex, $event)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -33,36 +28,66 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const props = defineProps<{
|
||||
rows: { option: string }[];
|
||||
columns: { option: string; editor?: boolean }[];
|
||||
questionType: number;
|
||||
matrixAnswer: { [key: string]: any };
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<string[][]>('rowRecord', { required: false, default: () => [] });
|
||||
// const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) });
|
||||
// 检查 rowRecord 是否存在
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
/* const isPreview = */defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
|
||||
const emits = defineEmits(['update:matrixAnswer']);
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
const handleColNameChange = (
|
||||
rowOption: string,
|
||||
colOption: string,
|
||||
e: Event,
|
||||
rowIndex: number,
|
||||
colIndex: number
|
||||
) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
const newMatrixAnswer = { ...props.matrixAnswer, [key]: target.value };
|
||||
function getInputValue(row: number, col: number) {
|
||||
console.log(`row: ${row}, col: ${col}`);
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
emits('update:matrixAnswer', newMatrixAnswer);
|
||||
};
|
||||
return rowRecord.value?.[row]?.[col] ?? '';
|
||||
}
|
||||
|
||||
// 当 matrix text 选中时,更新 rowRecord 和 matrixAnswer
|
||||
function handleMatrixTextChange(row: number, col: number, e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const inputValue = target.value;
|
||||
|
||||
// 获取 colIndexArray
|
||||
if (!rowRecord.value[row]) {
|
||||
// 如果没有对应的row,创建一个
|
||||
rowRecord.value[row] = [];
|
||||
}
|
||||
// cols 的逻辑 和 handleMatrixRadioChange 一致
|
||||
const cols = rowRecord.value[row];
|
||||
cols[col] = inputValue;
|
||||
console.log(`rowRecord:`, rowRecord.value);
|
||||
}
|
||||
// const handleColNameChange = (rowOption: string, colOption: string) => {
|
||||
// // const target = e.target as HTMLInputElement;
|
||||
// const col = props.columns.findIndex((option) => option.option === colOption);
|
||||
// const row = props.rows.findIndex((option) => option.option === rowOption);
|
||||
|
||||
// if (props.questionType === 9) {
|
||||
// props.rowRecord[col] = row + 1;
|
||||
// props.matrixAnswer = {};
|
||||
// props.rowRecord.forEach((row, index) => {
|
||||
// props.matrixAnswer[`${index + 1}_${row}`] = 1;
|
||||
// });
|
||||
// }
|
||||
|
||||
// emits('update:matrixAnswer', props.matrixAnswer);
|
||||
// emits('update:rowRecord', props.rowRecord);
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<van-field
|
||||
v-model="element.stem"
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
v-model="element.stem" :label="element.stem" :required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
>
|
||||
<template #left-icon>
|
||||
@@ -13,13 +11,13 @@
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="saveStem"></contenteditable>
|
||||
</template>
|
||||
<template #input>
|
||||
<div v-for="(optionItem, optionItemIndex) in element.options" :key="optionItemIndex">
|
||||
<div v-for="(optionItem, optionItemIndex) in isPreview ? element.list : element.options" :key="optionItemIndex">
|
||||
<div
|
||||
v-for="(item, optionIndex) in optionItem"
|
||||
:key="optionIndex"
|
||||
v-for="(item, optionIndex) in isPreview ? optionItem.options : optionItem" :key="optionIndex"
|
||||
@click="chooseOption(item)"
|
||||
>
|
||||
<RateCharacter v-model="answerValue" :config="element.config"></RateCharacter>
|
||||
<RateCharacter v-model="rate" :index="optionIndex" :config="element.config" @change="handleRateChange">
|
||||
</RateCharacter>
|
||||
<div class="tips">
|
||||
<p>{{ element.config.prompt_left }}</p>
|
||||
<p>{{ element.config.prompt_center }}</p>
|
||||
@@ -36,6 +34,7 @@
|
||||
import { ref, toRefs } from 'vue';
|
||||
import RateCharacter from './RateCharacter.vue';
|
||||
|
||||
const isPreview = defineModel('isPreview', { default: false });
|
||||
const props = defineProps({
|
||||
element: {
|
||||
type: Object
|
||||
@@ -51,6 +50,36 @@ const props = defineProps({
|
||||
sn: { type: String, default: '' },
|
||||
questionType: { type: [String, Number], default: 4 }
|
||||
});
|
||||
|
||||
// answer 的答案以 矩阵形式存储, 例如 [4,7],上层更新答案的时候也容易
|
||||
const rates = defineModel('rates', { default: [] });
|
||||
const rate = ref(0);
|
||||
|
||||
// 不知道的 BUG ,开始的时候不能重置颜色。 故如此
|
||||
setTimeout(() => {
|
||||
rate.value = localStorage.getItem(props.sn);
|
||||
console.log(`rate value:`, rate.value);
|
||||
// if (rates.value[0] !== undefined) {
|
||||
// console.log(`rates value:`, rates.value);
|
||||
// rate.value = rates.value[0]
|
||||
// }
|
||||
// else return
|
||||
}, 1000);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index {number} 索引
|
||||
* @param rate {number} 具体数值
|
||||
*/
|
||||
function handleRateChange(index, rate) {
|
||||
// 如果没有查询到对应索引的数值, 那么就直接push一个,直到有数值为止
|
||||
while (rates.value.length < index) {
|
||||
rates.value.push(NaN);
|
||||
}
|
||||
rates.value[index] = rate;
|
||||
localStorage.setItem(props.sn, rate.value);
|
||||
}
|
||||
|
||||
const { element } = toRefs(props);
|
||||
const chooseId = ref('');
|
||||
const emit = defineEmits(['update:element']);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul>
|
||||
<ul :key="test">
|
||||
<li
|
||||
v-for="(rate, rateIndex) in rateItem"
|
||||
:key="rateIndex"
|
||||
class="rate_item"
|
||||
:class="{ active_item: rate.active }"
|
||||
v-for="(rate, rateIndex) in rateItem" :key="rateIndex" class="rate_item" :class="{ active_item: rate.active }"
|
||||
@click="getItem(rate)"
|
||||
>
|
||||
{{ rate.label }}
|
||||
@@ -40,6 +37,11 @@ const rateItem = ref([
|
||||
}
|
||||
]);
|
||||
|
||||
const test = ref(1);
|
||||
|
||||
setTimeout(() => {
|
||||
test.value = 2;
|
||||
}, 300);
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
@@ -49,6 +51,8 @@ const props = defineProps({
|
||||
|
||||
const model = defineModel();
|
||||
|
||||
const index = defineModel('index');
|
||||
const emit = defineEmits(['change']);
|
||||
const renderScore = (min, max, interval) => {
|
||||
const result = [];
|
||||
for (let i = min; i <= max; i += interval) {
|
||||
@@ -64,15 +68,18 @@ const renderScore = (min, max, interval) => {
|
||||
rateItem.value = result;
|
||||
};
|
||||
// 重置颜色
|
||||
const getItem = (value) => {
|
||||
function getItem(value) {
|
||||
model.value = value.label;
|
||||
rateItem.value.forEach((item, index) => {
|
||||
rateItem.value[index].active = item.label <= value.label;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
watch(model, () => {
|
||||
getItem({ label: model.value, active: false });
|
||||
emit('change', index.value, model.value);
|
||||
}, {
|
||||
// immediate: true
|
||||
});
|
||||
|
||||
// 监听 min、max 和 score_interval 的变化
|
||||
|
||||
@@ -38,11 +38,12 @@ type questionsList = {
|
||||
};
|
||||
|
||||
type question = {
|
||||
answer?: unknown;
|
||||
id?: string;
|
||||
title?: string;
|
||||
stem?: string;
|
||||
other?: string;
|
||||
list: questionsList[][];
|
||||
list: questionsList[];
|
||||
question_index?: number;
|
||||
question_type?: number;
|
||||
config?: Config;
|
||||
|
||||
@@ -105,8 +105,7 @@ import { Io5EllipsisHorizontalSharp } from 'vue-icons-plus/io5';
|
||||
top: 0;
|
||||
right: 10px;
|
||||
padding: 28px 13px 19px 7px;
|
||||
background: url('https://lanhu-oss-2537-2.lanhuapp.com/SketchPngbb370d01215f9cedc28d567c637c011047f83a99fbb5e7ac348ebd0ef0015f32')
|
||||
100% no-repeat;
|
||||
background: url('https://lanhu-oss-2537-2.lanhuapp.com/SketchPngbb370d01215f9cedc28d567c637c011047f83a99fbb5e7ac348ebd0ef0015f32') 100% no-repeat;
|
||||
background-size: 100% 100%;
|
||||
opacity: 1;
|
||||
|
||||
|
||||
@@ -299,6 +299,7 @@
|
||||
:config="question.config"
|
||||
:question="question"
|
||||
isMobile
|
||||
:questionIndex="question.question_index"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<!-- <!– 地理位置题 –>-->
|
||||
|
||||
@@ -1,341 +1,42 @@
|
||||
<template>
|
||||
<van-field
|
||||
v-model="stem"
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
class="base-select"
|
||||
>
|
||||
<template #label>
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="emitValue"></contenteditable>
|
||||
</template>
|
||||
<template #input>
|
||||
<template v-for="listItem in list" :key="listItem.options">
|
||||
<template v-for="(option, optionIndex) in listItem.options" :key="option.option">
|
||||
<!-- 单选题 -->
|
||||
<van-radio-group v-if="question?.question_type === 1" v-model="choiceValue">
|
||||
<van-radio :name="optionIndex">{{ getDomText(option.option!) }}</van-radio>
|
||||
</van-radio-group>
|
||||
<!-- 多选题 -->
|
||||
<van-checkbox-group
|
||||
v-else-if="question!.question_type! === 2"
|
||||
v-model="choiceValue"
|
||||
shape="square"
|
||||
>
|
||||
<van-checkbox :name="optionIndex">{{ getDomText(option.option!) }}</van-checkbox>
|
||||
</van-checkbox-group>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</van-field>
|
||||
<choice v-model:answer="choiceValue" :element="question" :index="answerIndex" :is-preview="true" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineAsyncComponent, ref, watch } from 'vue';
|
||||
import { getDomText } from '@/utils/utils';
|
||||
import { watch, ref } from 'vue';
|
||||
import Choice from '@/views/Design/components/Questions/Choice.vue';
|
||||
|
||||
type answerType = {
|
||||
options: any[];
|
||||
value: number;
|
||||
};
|
||||
// // 预览新增 v-model
|
||||
const answer = defineModel('answer');
|
||||
// const answerIndex = defineModel('answerIndex');
|
||||
const stem = defineModel('stem');
|
||||
const question = defineModel<question>('question', {});
|
||||
const list = defineModel<questionsList[]>('list');
|
||||
const answer = defineModel<answerType>('answer', { default: undefined });
|
||||
const answerIndex = defineModel<number>('answerIndex');
|
||||
// const stem = defineModel<string>('stem', { default: '' });4
|
||||
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
|
||||
const list = defineModel<questionsList[]>('list', { default: [[]] });
|
||||
|
||||
const choiceValue = ref<string>((answer.value?.value - 1).toString() ?? '0');
|
||||
|
||||
// 初始化数据,因为 preview 的数据源和 element 的数据源不相同, 所以需要配置一遍数据
|
||||
initData();
|
||||
function initData() {
|
||||
question.value.options = list.value;
|
||||
}
|
||||
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
|
||||
const emit = defineEmits(['update:element', 'changeAnswer', 'previous', 'next', 'update:element']);
|
||||
|
||||
// 用戶選擇的答案
|
||||
const choiceValue = ref(answer.value?.value - 1 ?? undefined);
|
||||
const Contenteditable = defineAsyncComponent(() => import('@/components/contenteditable.vue'));
|
||||
|
||||
// console.log(`choice question.value:`, question.value);
|
||||
watch(choiceValue, () => {
|
||||
answer.value = {
|
||||
watch(
|
||||
() => choiceValue.value,
|
||||
() => {
|
||||
const res = {
|
||||
options: list.value.flatMap((group) => group.options || []),
|
||||
value: choiceValue.value + 1
|
||||
value: Number(choiceValue.value) + 1
|
||||
};
|
||||
// console.log(answer.value);
|
||||
|
||||
// 需要在 question 里面附加 answer 信息
|
||||
// question.value[`answer`] =
|
||||
emit('changeAnswer', {
|
||||
options: list.value.flatMap((group) => group.options || []),
|
||||
value: choiceValue.value + 1
|
||||
});
|
||||
});
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`list: `, list.value);
|
||||
// const props = defineProps({
|
||||
// // 预览新增 props
|
||||
// config: {
|
||||
// type: Object,
|
||||
// default: () => {
|
||||
// return {};
|
||||
// }
|
||||
// },
|
||||
// hideOptions: {
|
||||
// type: Object,
|
||||
// default: () => {
|
||||
// return {};
|
||||
// }
|
||||
// },
|
||||
// answerSn: {
|
||||
// type: String,
|
||||
// default: ''
|
||||
// },
|
||||
// answerSurveySn: {
|
||||
// type: String,
|
||||
// default: ''
|
||||
// },
|
||||
// // 原先 props
|
||||
// element: {
|
||||
// type: Object,
|
||||
// default: () => {
|
||||
// return {
|
||||
// config: {
|
||||
// is_required: undefined
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// },
|
||||
// active: {
|
||||
// type: Boolean,
|
||||
// default: false
|
||||
// },
|
||||
// index: {
|
||||
// type: Number,
|
||||
// default: 0
|
||||
// }
|
||||
// });
|
||||
|
||||
// initData();
|
||||
//
|
||||
// function initData() {
|
||||
// // 当预览时, 某些数据可能不存在
|
||||
// // 若 element有些数据不存在, 默认去 props 里面 取值
|
||||
// !props.element.stem && (props.element.stem = stem.value);
|
||||
//
|
||||
// !props.element.options && (props.element.stem = stem.value);
|
||||
// }
|
||||
|
||||
// console.log(`props.element`, props.element);
|
||||
// console.log(`props.question: `, question.value);
|
||||
// const { element } = toRefs(props);
|
||||
|
||||
const emitValue = () => {
|
||||
// emit('update:element', element.value);
|
||||
};
|
||||
|
||||
// const value = ref(''); // 值
|
||||
// const options = ref([]); // 选项
|
||||
// const optionGroups = ref([]); // 分组
|
||||
//
|
||||
// console.log(`radio input question: `, props.question);
|
||||
//
|
||||
// // 初始化
|
||||
// function init() {
|
||||
// props.list.forEach((list) => {
|
||||
// options.value = [...options.value, ...list.options];
|
||||
// });
|
||||
// if (props.answer) {
|
||||
// value.value = Object.keys(props.answer)[0];
|
||||
// options.value.forEach((option) => {
|
||||
// if (option.is_other && option.option_key === value.value) {
|
||||
// option.value = props.answer[value.value];
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// init();
|
||||
//
|
||||
// // 选项分组
|
||||
// function setOptionGroups() {
|
||||
// optionGroups.value = [];
|
||||
// const copyOptions = JSON.parse(JSON.stringify(options.value));
|
||||
// props.config.option_groups?.option_group.forEach((optionGroup) => {
|
||||
// const group = {
|
||||
// title: optionGroup.title,
|
||||
// options: []
|
||||
// };
|
||||
// optionGroup.groups.forEach((groups) => {
|
||||
// const index = copyOptions.findIndex((option) => option.option_key === groups.option_key);
|
||||
// if (index === -1) return;
|
||||
// group.options.push(copyOptions.splice(index, 1)[0]);
|
||||
// });
|
||||
// group.options = sortOptions(
|
||||
// group.options,
|
||||
// props.question.config.select_random && props.question.config.option_group_random_inside
|
||||
// );
|
||||
// optionGroups.value.push(group);
|
||||
// });
|
||||
// optionGroups.value = sortOptions(
|
||||
// optionGroups.value,
|
||||
// props.question.config.select_random && props.question.config.option_group_random_outside
|
||||
// );
|
||||
// // 若是 group 是undefined ,默认给一个空对象
|
||||
// const group = optionGroups.value.find((group) => !group.title) ?? {};
|
||||
// // console.log(group);
|
||||
// group.options = sortOptions(copyOptions, props.question.config.select_random);
|
||||
// }
|
||||
//
|
||||
// // 排序(固定项和其他项不参与随机)
|
||||
// function sortOptions(oldOptions, isRandom) {
|
||||
// const sorts = [];
|
||||
// const fixed = [];
|
||||
// const others = [];
|
||||
// const removeOther = [];
|
||||
// oldOptions.forEach((option) => {
|
||||
// if (option.is_remove_other) {
|
||||
// removeOther.push(option);
|
||||
// } else if (option.is_other) {
|
||||
// others.push(option);
|
||||
// } else if (option.is_fixed) {
|
||||
// fixed.push(option);
|
||||
// } else {
|
||||
// sorts.push(option);
|
||||
// }
|
||||
// });
|
||||
// return [...randomOptions(sorts, isRandom), ...fixed, ...others, ...removeOther];
|
||||
// }
|
||||
//
|
||||
// // 选择回调
|
||||
// function changeValue(e) {
|
||||
// // 更新答案
|
||||
// const option = options.value.find((option) => option.option_key === e.target.value);
|
||||
// context.emit('update:answer', {
|
||||
// [e.target.value]: option.value || (option.is_other ? '' : '1')
|
||||
// });
|
||||
// // 清空未选中项输入框值
|
||||
// options.value.forEach((option) => {
|
||||
// if (option.is_other && option.option_key !== e.target.value) {
|
||||
// option.value = '';
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// function onChangeValue(key) {
|
||||
// value.value = key;
|
||||
// changeValue({ target: { value: key } });
|
||||
// }
|
||||
//
|
||||
// // 输入回调
|
||||
// function changeInput(e, key) {
|
||||
// const option = options.value.find((option) => option.option_key === key);
|
||||
// option.value = e.target.value;
|
||||
// value.value = key;
|
||||
// // 更新答案
|
||||
// context.emit('update:answer', { [key]: e.target.value });
|
||||
// }
|
||||
//
|
||||
// // 监听答案
|
||||
// watch(
|
||||
// () => props.answer,
|
||||
// () => {
|
||||
// context.emit('changeAnswer', {
|
||||
// options: optionGroups.value.flatMap((group) => group.options || []),
|
||||
// value: value.value
|
||||
// });
|
||||
// // 质量控制
|
||||
// const timer = setTimeout(() => {
|
||||
// if (value.value) {
|
||||
// const index = optionGroups.value
|
||||
// .flatMap((group) => group.options.map((option) => option))
|
||||
// .findIndex((option) => option.option_key === value.value);
|
||||
// context.emit('update:answerIndex', `${index}`);
|
||||
// } else if (props.answerIndex) {
|
||||
// context.emit('update:answerIndex', '');
|
||||
// }
|
||||
// clearTimeout(timer);
|
||||
// });
|
||||
// },
|
||||
// {
|
||||
// deep: true,
|
||||
// immediate: true
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// // 监听list,更新关联选项
|
||||
// watch(
|
||||
// () => props.list,
|
||||
// () => {
|
||||
// // 更新关联题选项
|
||||
// let newOptions = [];
|
||||
// props.list.forEach((list) => {
|
||||
// newOptions = [...newOptions, ...list.options];
|
||||
// });
|
||||
// // 其他项
|
||||
// newOptions.forEach((option) => {
|
||||
// if (option.is_other && option.option_key === value.value) {
|
||||
// const timer = setTimeout(() => {
|
||||
// option.value = props.answer[value.value];
|
||||
// clearTimeout(timer);
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (
|
||||
// !compareArrayByField(options.value, newOptions, 'option_key') ||
|
||||
// !compareArrayByField(options.value, newOptions, 'option')
|
||||
// ) {
|
||||
// options.value = newOptions;
|
||||
// }
|
||||
//
|
||||
// // 清空值和答案
|
||||
// if (
|
||||
// value.value &&
|
||||
// options.value.findIndex((option) => option.option_key === value.value) === -1
|
||||
// ) {
|
||||
// // 清空值
|
||||
// value.value = '';
|
||||
// // 清空答案
|
||||
// context.emit('update:answer', null);
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// deep: true
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// // 监听list,更新关联选项
|
||||
// watch(
|
||||
// () => options.value,
|
||||
// (val, oldVal) => {
|
||||
// if (
|
||||
// compareArrayByField(val, oldVal || [], 'option_key') &&
|
||||
// compareArrayByField(val, oldVal || [], 'option')
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
// setOptionGroups();
|
||||
// },
|
||||
// {
|
||||
// deep: true,
|
||||
// immediate: true
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// const onHoldToCart = (target) => {
|
||||
// value.value = target.option_key;
|
||||
//
|
||||
// changeValue({
|
||||
// target: {
|
||||
// value: target.option_key
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// const cartWaresLength = computed(() => {
|
||||
// if (!props.answer) return 0;
|
||||
// return Object.keys(props.answer).length;
|
||||
// });
|
||||
//
|
||||
// console.log(`car wares length:`, cartWaresLength.value);
|
||||
//
|
||||
// // 显示分组标题
|
||||
// function showGroupTitle(groupOptions) {
|
||||
// const option = groupOptions.find((option) => !props.hideOptions.includes(option.option_key));
|
||||
// return !!option;
|
||||
// }
|
||||
answer.value = res;
|
||||
emit('changeAnswer', res);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.choice-html {
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
<template>
|
||||
<van-field v-model="inputValue" v-focus placeholder="请输入内容"> </van-field>
|
||||
<!-- <van-field v-model="inputValue" v-focus placeholder="请输入内容"> </van-field>-->
|
||||
<!-- <completion />-->
|
||||
<completion
|
||||
v-model:completionValue="completionValue"
|
||||
:index="answerIndex"
|
||||
:element="question"
|
||||
></completion>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineEmits, ref, watch } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
import Completion from '@/views/Design/components/Questions/Completion.vue';
|
||||
// 预览新增 v-model
|
||||
// const config = defineModel('config');
|
||||
const answer = defineModel<{ value: string | number }>('answer');
|
||||
// const answerIndex = defineModel('answerIndex');
|
||||
const answer = defineModel<{ value: string | number }>('answer', { default: { value: '' } });
|
||||
const answerIndex = defineModel<number>('answerIndex');
|
||||
// const stem = defineModel('stem');
|
||||
const question = defineModel<question>('question', {});
|
||||
// const list = defineModel<questionsList[]>('list');
|
||||
@@ -17,82 +23,24 @@ const question = defineModel<question>('question', {});
|
||||
|
||||
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
|
||||
const emit = defineEmits(['previous', 'next', 'update:modelValue', 'saveOption', 'changeAnswer']);
|
||||
// console.log(answer);
|
||||
const inputValue = ref(answer.value?.value ?? '');
|
||||
|
||||
console.log(`answer`, answer.value);
|
||||
console.log(question.value);
|
||||
const completionValue = ref(answer.value?.value ?? '');
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`list: `, list.value);
|
||||
|
||||
// console.log(question.value);
|
||||
// 进行提交答案
|
||||
watch(inputValue, () => {
|
||||
watch(
|
||||
() => completionValue.value,
|
||||
() => {
|
||||
const res = {
|
||||
value: inputValue.value
|
||||
value: completionValue.value
|
||||
};
|
||||
|
||||
question.value.answer = res;
|
||||
answer.value = res;
|
||||
question.value!.answer = res;
|
||||
emit('changeAnswer', res);
|
||||
});
|
||||
|
||||
// function handleKeyDown() {
|
||||
// emit('changeAnswer', {
|
||||
// options: list.value,
|
||||
// value: inputValue.value + 1
|
||||
// });
|
||||
// }
|
||||
|
||||
// const props = defineProps({
|
||||
// modelValue: {
|
||||
// type: Object,
|
||||
// required: false,
|
||||
// default: () => {
|
||||
// return {};
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// const selectTextTypeModel = ref(false);
|
||||
// const textTypeList = [
|
||||
// {
|
||||
// text: '不限',
|
||||
// value: 0
|
||||
// },
|
||||
// {
|
||||
// text: '整数',
|
||||
// value: 1
|
||||
// },
|
||||
// {
|
||||
// text: '小数',
|
||||
// value: 2
|
||||
// },
|
||||
// {
|
||||
// text: '字母',
|
||||
// value: 3
|
||||
// },
|
||||
// {
|
||||
// text: '中文',
|
||||
// value: 4
|
||||
// },
|
||||
// {
|
||||
// text: 'email',
|
||||
// value: 5
|
||||
// },
|
||||
// {
|
||||
// text: '手机号',
|
||||
// value: 6
|
||||
// },
|
||||
// {
|
||||
// text: '身份证号',
|
||||
// value: 7
|
||||
// }
|
||||
// ];
|
||||
|
||||
// const selectText = (textType) => {
|
||||
// return textTypeList.filter((item) => item.value === textType)[0]?.text;
|
||||
// };
|
||||
// const confirm = ({ selectedValues }) => {
|
||||
// actionQuestion.value.config.text_type = Number(selectedValues[0]);
|
||||
// selectTextTypeModel.value = false;
|
||||
// emit('saveOption');
|
||||
// };
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,82 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { showSuccessToast, showFailToast } from 'vant';
|
||||
|
||||
// const { element } = defineProps({
|
||||
// element: {
|
||||
// require: false
|
||||
import FileUpload from '@/views/Design/components/Questions/FileUpload.vue';
|
||||
const questionIndex = defineModel<number>('questionIndex', { default: NaN });
|
||||
const question = defineModel<question>('question', {});
|
||||
// 接口还未稳定
|
||||
// 需要的数据暂时先放在这里
|
||||
// 格式如下
|
||||
// {
|
||||
// "name": "3-12.png",
|
||||
// "size": 238875,
|
||||
// "type": "image/png",
|
||||
// "url": "https://test-cxp-public-web-1302259445.cos.ap-beijing.myqcloud.com/uat-yls/answer/7JjQp7am/1742022258458_388_3-12.png"
|
||||
// }
|
||||
// });
|
||||
|
||||
// const config = defineModel('question', { required: false });
|
||||
// console.log(config.value);
|
||||
/**
|
||||
* 文件大小限制
|
||||
* @property {number} max - 最大文件大小
|
||||
* @property {number} min - 最小文件大小
|
||||
*/
|
||||
const fileLimit = {
|
||||
// 默认4MB
|
||||
max: 1024 * 1024 * 40,
|
||||
min: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @description 上传文件
|
||||
*/
|
||||
function handleFileUpload() {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
// fileInput.accept = '.jpg,.jpeg,.png,.gif';
|
||||
// fileInput.multiple = true;
|
||||
fileInput.click();
|
||||
|
||||
fileInput.addEventListener('change', handleFileChange);
|
||||
|
||||
function handleFileChange(event: Event) {
|
||||
const files = (event.target as HTMLInputElement).files;
|
||||
if (files) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
// console.log(file.size);
|
||||
|
||||
if (file.size > fileLimit.max) {
|
||||
showFailToast(`文件太大,超过${fileLimit.max / 1024 / 1024}MB`);
|
||||
return;
|
||||
} else if (file.size < fileLimit.min) {
|
||||
showFailToast(`文件太小,小于${fileLimit.min / 1024 / 1024}MB`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 这里保留上传的区域
|
||||
|
||||
// 成功
|
||||
showSuccessToast('成功文案');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-field>
|
||||
<template #input>
|
||||
<div>
|
||||
<div class="file-upload-label" @click="handleFileUpload">
|
||||
<van-icon name="photo"></van-icon>
|
||||
<span>上传文件</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
<!-- 文件上传题 -->
|
||||
<file-upload :element="question" :index="questionIndex" :active="false" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.file-upload-label {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,132 +1,97 @@
|
||||
<template>
|
||||
<table class="matrix-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
<MatrixCheckbox
|
||||
v-model:rowRecord="rowRecord" v-model:matrix-radio-answer="answer!" :rows="rows" :cols="cols"
|
||||
:is-preview="true"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option" />
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option" />
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@change="handleColValueChange(row.option, col.option)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const rows = defineModel<OptionType[]>('rows', { required: false, default: [] });
|
||||
const columns = defineModel<OptionType[]>('columns', { required: false, default: [] });
|
||||
import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
// const questionType = defineModel<number>('questionType', { required: false });
|
||||
// const matrixAnswer = defineModel<{ [key: string]: any }>('matrixAnswer', { required: false });
|
||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false });
|
||||
|
||||
// 矩阵多选的答案类型
|
||||
type answerType = {
|
||||
[key: string]: 1;
|
||||
};
|
||||
|
||||
// preview props
|
||||
// const stem = defineModel('stem');
|
||||
const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const config = defineModel<OptionConfigType>('config', { required: false });
|
||||
// const question = defineModel('question');
|
||||
// const answer = defineModel('answer');
|
||||
const question = defineModel<question>('question');
|
||||
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
|
||||
// 示例
|
||||
// {
|
||||
// "1_1": 1,
|
||||
// "1_2": 1,
|
||||
// "2_1": 1,
|
||||
// "2_2": 1
|
||||
// }
|
||||
const answer = defineModel<answerType>('answer', {
|
||||
// 临时赋值, 用于测试
|
||||
// default: () => ({
|
||||
// "1_1": 1,
|
||||
// "1_2": 1,
|
||||
// "2_1": 1,
|
||||
// "2_2": 1
|
||||
// })
|
||||
});
|
||||
// const answerIndex = defineModel('answerIndex');
|
||||
// const answerSn = defineModel('answerSn');
|
||||
// const answerSurveySn = defineModel('answerSurveySn');
|
||||
|
||||
initData();
|
||||
// 记录行和列的索引
|
||||
// 记录的格式如下,
|
||||
// [
|
||||
// [0, 1],
|
||||
// [0, 1]
|
||||
// ]
|
||||
const rowRecord = ref<number[][]>([]);
|
||||
|
||||
// 数据初始化
|
||||
function initData() {
|
||||
if (!list.value) return;
|
||||
console.log(list.value);
|
||||
if (list.value[0].options.length >= 1) rows.value = list.value[0].options;
|
||||
if (list.value[1].options.length >= 1) columns.value = list.value[1].options;
|
||||
// 假如 answer 有数值,需要解析 answer ,然后传递 record 给子组件
|
||||
answer.value && parseAnswer(answer.value);
|
||||
|
||||
// 矩阵多选数组形式 [[1,2],[3]], 长度和 行数有关, 选中的位置跟里面的位置有关
|
||||
rowRecord.value = new Array(rows.value.length).fill(new Array(columns.value.length).fill(0));
|
||||
console.log(`answer value`, answer.value);
|
||||
/**
|
||||
* 解析 answer
|
||||
*/
|
||||
function parseAnswer(answer: answer) {
|
||||
console.log(`come in parseAnswer`);
|
||||
const rowRecordList: number[][] = [];
|
||||
Object.entries(answer).forEach(([key]) => {
|
||||
const [row, col] = key.split('_').map(Number);
|
||||
if (!rowRecordList[row - 1]) rowRecordList[row - 1] = [];
|
||||
rowRecordList[row - 1].push(col - 1);
|
||||
});
|
||||
rowRecord.value = rowRecordList;
|
||||
|
||||
return rowRecordList;
|
||||
}
|
||||
// 查看parseAnswer的返回值
|
||||
// console.log(`parseAnswer value:`, parseAnswer(answer.value!))
|
||||
|
||||
// console.log(`stem:`, stem.value);
|
||||
// console.log(`list:`, list.value);
|
||||
// console.log(`config:`, config.value);
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`answer:`, answer.value);
|
||||
// console.log(`answerIndex:`, answerIndex.value);
|
||||
// console.log(`answerSn:`, answerSn.value);
|
||||
// console.log(`answerSurveySn:`, answerSurveySn.value);
|
||||
/**
|
||||
* 获取行和列的内容
|
||||
* 行的内容在 question.list[0].options
|
||||
* 列的内容在 question.list[1].options
|
||||
*/
|
||||
const rows = computed(() => question.value?.list[0]?.options ?? []);
|
||||
const cols = computed(() => question.value?.list[1]?.options ?? []);
|
||||
|
||||
// rows.value && console.log(`matrix rows:`, rows.value);
|
||||
// columns.value && console.log(`matrix columns:`, columns.value);
|
||||
// columns.value && console.log(`matrix questionType:`, questionType.value);
|
||||
// columns.value && console.log(`matrix matrixAnswer:`, matrixAnswer.value);
|
||||
// columns.value && console.log(`matrix rowRecord:`, rowRecord.value);
|
||||
watch(rowRecord, () => {
|
||||
console.log(`record has changed`, rowRecord.value);
|
||||
// 重新生成 answer
|
||||
const newAnswer: answer = {};
|
||||
rowRecord.value.forEach((rowOptions, rowIndex) => {
|
||||
rowOptions.forEach((colIndex) => {
|
||||
newAnswer[`${rowIndex + 1}_${colIndex + 1}`] = 1;
|
||||
});
|
||||
});
|
||||
answer.value = newAnswer;
|
||||
emit('changeAnswer', newAnswer);
|
||||
}, { deep: true });
|
||||
|
||||
/* const emits = */
|
||||
defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
const isOptionChecked = (/* rowIndex: number, colIndex: number */): boolean => {
|
||||
// const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
// console.log(key);
|
||||
// return !!matrixAnswer.value[key];
|
||||
};
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
const handleColValueChange = (rowOption: string, colOption: string) => {
|
||||
// const target = e.target as HTMLInputElement;
|
||||
// 寻找行列的索引
|
||||
const col = columns.value.findIndex((option) => option.option === colOption);
|
||||
const row = rows.value.findIndex((option) => option.option === rowOption);
|
||||
|
||||
// 此处的矩阵是由二维数组组成,两者是通过 索引和 索引对应的数值来表示
|
||||
// rowRecord 是负责记录的数组
|
||||
// 记录之后清空结果对象,遍历数组获取相应的结果内容给 matrixAnswer
|
||||
// rowRecord.value[row] = col;
|
||||
// matrixAnswer.value = {};
|
||||
// rowRecord.value.forEach((row, col) => {
|
||||
// matrixAnswer.value[`${col + 1}_${row + 1}`] = 1;
|
||||
// });
|
||||
|
||||
// 获取row行对应的数组
|
||||
const rowArray = rowRecord.value[row];
|
||||
// console.log(...rowRecord.value);
|
||||
// console.log(`rowArray`, rowArray);
|
||||
// 检查第 col 个元素
|
||||
const value = rowArray[col];
|
||||
if (value) {
|
||||
// 若元素存在,则变动元素数值
|
||||
rowArray[col] = 0;
|
||||
} else {
|
||||
// 不存在记录为1
|
||||
rowArray[col] = 1;
|
||||
}
|
||||
|
||||
// console.log(...rowRecord.value);
|
||||
// emits('update:matrixAnswer', matrixAnswer.value);
|
||||
// emits('update:rowRecord', rowRecord.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,117 +1,80 @@
|
||||
<template>
|
||||
<table class="matrix-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<!-- 1 是行标签 -->
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 0 是列标签 -->
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<input
|
||||
type="radio"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@change="handleColValueChange(row.option, col.option, $event)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<matrix-radio
|
||||
v-model:rowRecord="rowRecord" v-model:matrix-radio-answer="answer!" :rows="rows" :cols="cols"
|
||||
:is-preview="true"
|
||||
></matrix-radio>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const rows = defineModel<OptionType[]>('rows', { required: false, default: [] });
|
||||
const columns = defineModel<OptionType[]>('columns', { required: false, default: [] });
|
||||
import matrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
// const questionType = defineModel<number>('questionType', { required: false });
|
||||
const matrixAnswer = defineModel<{ [key: string]: any }>('matrixAnswer', { required: false });
|
||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false });
|
||||
|
||||
// 矩阵单选的答案类型
|
||||
type answerType = {
|
||||
[key: string]: 1;
|
||||
};
|
||||
|
||||
// preview props
|
||||
// const stem = defineModel('stem');
|
||||
const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const config = defineModel<OptionConfigType>('config', { required: false });
|
||||
// const question = defineModel('question');
|
||||
// const answer = defineModel('answer');
|
||||
const question = defineModel<question>('question');
|
||||
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
|
||||
// 示例
|
||||
// {
|
||||
// "1_2": 1,
|
||||
// "2_2": 1
|
||||
// }
|
||||
const answer = defineModel<answerType>('answer', {
|
||||
// 临时赋值, 用于测试
|
||||
default: () => ({
|
||||
// "1_2": 1,
|
||||
// "2_2": 1
|
||||
})
|
||||
});
|
||||
// const answerIndex = defineModel('answerIndex');
|
||||
// const answerSn = defineModel('answerSn');
|
||||
// const answerSurveySn = defineModel('answerSurveySn');
|
||||
// 记录行和列的索引
|
||||
const rowRecord = ref<number[]>([]);
|
||||
|
||||
initData();
|
||||
// 数据初始化
|
||||
function initData() {
|
||||
if (!list.value) return;
|
||||
// console.log(list.value);
|
||||
rows.value = list.value[0].options;
|
||||
columns.value = list.value[1].options;
|
||||
// 假如 answer 有数值,需要解析 answer ,然后传递 record 给子组件
|
||||
answer.value && parseAnswer(answer.value);
|
||||
|
||||
rowRecord.value = new Array(rows.value.length);
|
||||
/**
|
||||
* 解析 answer
|
||||
*/
|
||||
function parseAnswer(answer: answerType) {
|
||||
console.log(`come in parseAnswer`);
|
||||
const rowRecordList: number[] = [];
|
||||
Object.entries(answer).forEach(([key]) => {
|
||||
const [row, col] = key.split('_');
|
||||
rowRecordList[Number(row) - 1] = Number(col) - 1;
|
||||
});
|
||||
rowRecord.value = rowRecordList;
|
||||
return rowRecordList;
|
||||
}
|
||||
|
||||
// console.log(`stem:`, stem.value);
|
||||
// console.log(`list:`, list.value);
|
||||
// console.log(`config:`, config.value);
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`answer:`, answer.value);
|
||||
// console.log(`answerIndex:`, answerIndex.value);
|
||||
// console.log(`answerSn:`, answerSn.value);
|
||||
// console.log(`answerSurveySn:`, answerSurveySn.value);
|
||||
//
|
||||
// rows.value && console.log(`matrix rows:`, rows.value);
|
||||
// columns.value && console.log(`matrix columns:`, columns.value);
|
||||
// columns.value && console.log(`matrix questionType:`, questionType.value);
|
||||
// columns.value && console.log(`matrix matrixAnswer:`, matrixAnswer.value);
|
||||
// columns.value && console.log(`matrix rowRecord:`, rowRecord.value);
|
||||
/**
|
||||
* 获取行和列的内容
|
||||
* 行的内容在 question.list[0].options
|
||||
* 列的内容在 question.list[1].options
|
||||
*/
|
||||
const rows = computed(() => question.value?.list[0]?.options ?? []);
|
||||
const cols = computed(() => question.value?.list[1]?.options ?? []);
|
||||
|
||||
/* const emits = */
|
||||
defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
const isOptionChecked = (/* rowIndex: number, colIndex: number */): boolean => {
|
||||
// const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
// console.log(key);
|
||||
// return !!matrixAnswer.value[key];
|
||||
};
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
const handleColValueChange = (rowOption: string, colOption: string) => {
|
||||
// const target = e.target as HTMLInputElement;
|
||||
// 寻找行列的索引
|
||||
const col = columns.value.findIndex((option) => option.option === colOption);
|
||||
const row = rows.value.findIndex((option) => option.option === rowOption);
|
||||
|
||||
// 此处的矩阵是由一维数组组成,两者是通过 索引和 索引对应的数值来表示
|
||||
// rowRecord 是负责记录的数组
|
||||
// 记录之后清空结果对象,遍历数组获取相应的结果内容给 matrixAnswer
|
||||
rowRecord.value[row] = col;
|
||||
matrixAnswer.value = {};
|
||||
watch(rowRecord, () => {
|
||||
console.log(`record has changed`, rowRecord.value);
|
||||
// 生成 answer
|
||||
const newAnswer: answerType = {};
|
||||
rowRecord.value.forEach((row, col) => {
|
||||
matrixAnswer.value[`${col + 1}_${row + 1}`] = 1;
|
||||
newAnswer[`${col + 1}_${row + 1}`] = 1;
|
||||
});
|
||||
// emits('update:matrixAnswer', matrixAnswer.value);
|
||||
// emits('update:rowRecord', rowRecord.value);
|
||||
};
|
||||
answer.value = newAnswer;
|
||||
emit('changeAnswer', newAnswer);
|
||||
}, { deep: true });
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,109 +1,97 @@
|
||||
<template>
|
||||
<table class="matrix-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in columns" :key="col.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
<MatrixText
|
||||
v-model:rowRecord="rowRecord" v-model:matrix-radio-answer="answer!" :rows="rows" :cols="cols"
|
||||
:is-preview="true"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in columns" :key="colIndex">
|
||||
<input type="text" @change="handleColValueChange(rowIndex, colIndex, $event)" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
const rows = defineModel<OptionType[]>('rows', { required: false, default: [] });
|
||||
const columns = defineModel<OptionType[]>('columns', { required: false, default: [] });
|
||||
import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
// const questionType = defineModel<number>('questionType', { required: false });
|
||||
const matrixAnswer = defineModel<{ [key: string]: any }>('matrixAnswer', { required: false });
|
||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false });
|
||||
|
||||
// 矩阵多选的答案类型
|
||||
type answerType = {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
// preview props
|
||||
// const stem = defineModel('stem');
|
||||
const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const list = defineModel<questionsList[]>('list', { required: false });
|
||||
// const config = defineModel<OptionConfigType>('config', { required: false });
|
||||
// const question = defineModel('question');
|
||||
// const answer = defineModel('answer');
|
||||
const question = defineModel<question>('question');
|
||||
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
|
||||
// 示例
|
||||
// {
|
||||
// "1_1": 1,
|
||||
// "1_2": 1,
|
||||
// "2_1": 1,
|
||||
// "2_2": 1
|
||||
// }
|
||||
const answer = defineModel<answerType>('answer', {
|
||||
// 临时赋值, 用于测试
|
||||
// default: () => ({
|
||||
// "1_1": 1,
|
||||
// "1_2": 1,
|
||||
// "2_1": 1,
|
||||
// "2_2": 1
|
||||
// })
|
||||
});
|
||||
// const answerIndex = defineModel('answerIndex');
|
||||
// const answerSn = defineModel('answerSn');
|
||||
// const answerSurveySn = defineModel('answerSurveySn');
|
||||
|
||||
initData();
|
||||
// 数据初始化
|
||||
function initData() {
|
||||
if (!list.value) return;
|
||||
// console.log(list.value);
|
||||
rows.value = list.value[0].options;
|
||||
columns.value = list.value[1].options;
|
||||
// 记录行和列的索引
|
||||
// 记录的格式如下,
|
||||
// [
|
||||
// ['', ''],
|
||||
// ['', '']
|
||||
// ]
|
||||
const rowRecord = ref<string[][]>([]);
|
||||
|
||||
rowRecord.value = new Array(rows.value.length);
|
||||
}
|
||||
// 假如 answer 有数值,需要解析 answer ,然后传递 record 给子组件
|
||||
answer.value && parseAnswer(answer.value);
|
||||
|
||||
// console.log(`stem:`, stem.value);
|
||||
// console.log(`list:`, list.value);
|
||||
// console.log(`config:`, config.value);
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`answer:`, answer.value);
|
||||
// console.log(`answerIndex:`, answerIndex.value);
|
||||
// console.log(`answerSn:`, answerSn.value);
|
||||
// console.log(`answerSurveySn:`, answerSurveySn.value);
|
||||
//
|
||||
// rows.value && console.log(`matrix rows:`, rows.value);
|
||||
// columns.value && console.log(`matrix columns:`, columns.value);
|
||||
// columns.value && console.log(`matrix questionType:`, questionType.value);
|
||||
// columns.value && console.log(`matrix matrixAnswer:`, matrixAnswer.value);
|
||||
// columns.value && console.log(`matrix rowRecord:`, rowRecord.value);
|
||||
|
||||
/* const emits = */
|
||||
defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
// const isOptionChecked = (/*rowIndex: number, colIndex: number*/): boolean => {
|
||||
// const key = `R${rowIndex + 1}_C${colIndex + 1}`;
|
||||
// console.log(key);
|
||||
// return !!matrixAnswer.value[key];
|
||||
// };
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
|
||||
const handleColValueChange = (row: number, col: number) => {
|
||||
// const target = e.target as HTMLInputElement;
|
||||
// 寻找行列的索引
|
||||
// const col = columns.value.findIndex((option) => option.option === colOption);
|
||||
// const row = rows.value.findIndex((option) => option.option === rowOption);
|
||||
// console.log(row, col);
|
||||
// 此处的矩阵是由一维数组组成,两者是通过 索引和 索引对应的数值来表示
|
||||
// rowRecord 是负责记录的数组
|
||||
// 记录之后清空结果对象,遍历数组获取相应的结果内容给 matrixAnswer
|
||||
rowRecord.value[row] = col;
|
||||
matrixAnswer.value = {};
|
||||
rowRecord.value.forEach((row, col) => {
|
||||
matrixAnswer.value[`${col + 1}_${row + 1}`] = 1;
|
||||
console.log(`answer value`, answer.value);
|
||||
/**
|
||||
* 解析 answer
|
||||
*/
|
||||
function parseAnswer(answer: answerType) {
|
||||
const rowRecordList: string[][] = [];
|
||||
Object.entries(answer).forEach(([key, value]) => {
|
||||
const [row, col] = key.split('_');
|
||||
// 如果对应位置不存在数组, 重新建立
|
||||
if (!rowRecordList[Number(row) - 1]) rowRecordList[Number(row) - 1] = [];
|
||||
console.log(`value ${value}`);
|
||||
rowRecordList[Number(row) - 1][Number(col) - 1] = value;
|
||||
});
|
||||
// emits('update:matrixAnswer', matrixAnswer.value);
|
||||
// emits('update:rowRecord', rowRecord.value);
|
||||
};
|
||||
rowRecord.value = rowRecordList;
|
||||
|
||||
return rowRecordList;
|
||||
}
|
||||
// 查看parseAnswer的返回值
|
||||
// console.log(`parseAnswer value:`, parseAnswer(answer.value!))
|
||||
|
||||
/**
|
||||
* 获取行和列的内容
|
||||
* 行的内容在 question.list[0].options
|
||||
* 列的内容在 question.list[1].options
|
||||
*/
|
||||
const rows = computed(() => question.value?.list[0]?.options ?? []);
|
||||
const cols = computed(() => question.value?.list[1]?.options ?? []);
|
||||
|
||||
watch(rowRecord, () => {
|
||||
// 重新生成 answer
|
||||
const newAnswer: answerType = {};
|
||||
rowRecord.value.forEach((rows, rowIndex) => {
|
||||
rows.forEach((col, colIndex) => {
|
||||
newAnswer[`${rowIndex + 1}_${colIndex + 1}`] = col;
|
||||
});
|
||||
});
|
||||
answer.value = newAnswer;
|
||||
emit('changeAnswer', newAnswer);
|
||||
}, { deep: true });
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,72 +1,43 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<van-field
|
||||
v-model="stem"
|
||||
:label="stem"
|
||||
:required="question.config.is_required === 1"
|
||||
label-align="top"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
<template #label>
|
||||
<contenteditable v-model="stem" :active="active" @blur="saveStem"></contenteditable>
|
||||
</template>
|
||||
<template #input>
|
||||
<div v-for="(optionItem, optionItemIndex) in list" :key="optionItemIndex">
|
||||
<div
|
||||
v-for="(item, optionIndex) in optionItem.options"
|
||||
:key="optionIndex"
|
||||
@click="chooseOption(item)"
|
||||
>
|
||||
<RateCharacter v-model="answerValue" :config="config"></RateCharacter>
|
||||
<div class="tips">
|
||||
<p>{{ config.prompt_left }}</p>
|
||||
<p>{{ config.prompt_center }}</p>
|
||||
<p>{{ config.prompt_right }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
</div>
|
||||
<n-p-s v-model:element="question" v-model:rates="rates" :active="false" :isPreview="true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import RateCharacter from '@/views/Design/components/Questions/RateCharacter.vue';
|
||||
import NPS from '@/views/Design/components/Questions/NPS.vue';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const answerValue = ref(false);
|
||||
// const isPreview = defineModel('isPreview', { required: false });
|
||||
const stem = defineModel('stem', { required: false });
|
||||
const element = defineModel('element', { required: false });
|
||||
const question = defineModel('question', { required: false });
|
||||
const list = defineModel('list', { required: false });
|
||||
const config = defineModel('config', { required: false });
|
||||
const index = defineModel('index', { required: false });
|
||||
const active = defineModel('active', { required: false });
|
||||
// const sn = defineModel('sn', { required: false });
|
||||
// const questionType = defineModel('questionType', { required: false });
|
||||
const question = defineModel<question>('question', { default: { config: { is_required: false } } });
|
||||
const answer = defineModel<{ [key: string]: number }>('answer', { default: undefined });
|
||||
|
||||
const chooseId = ref('');
|
||||
const emit = defineEmits(['update:element']);
|
||||
const saveStem = () => {
|
||||
emit('update:element', element.value);
|
||||
};
|
||||
// rates 数值取决与 answer , 没有数据重新建立一个对应长度的数组
|
||||
const rates = ref(answer.value ? getRates() : new Array(question.value.list[0].options!.length));
|
||||
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
|
||||
const emit = defineEmits(['changeAnswer', 'previous', 'next', 'update:element']);
|
||||
|
||||
const chooseOption = (item) => {
|
||||
chooseId.value = item.id;
|
||||
};
|
||||
// 获取 rates
|
||||
function getRates() {
|
||||
const keys = Object.keys(answer.value);
|
||||
return keys.map((item) => {
|
||||
return answer.value[item];
|
||||
});
|
||||
}
|
||||
|
||||
console.log(answer.value && getRates());
|
||||
watch(
|
||||
rates,
|
||||
() => {
|
||||
const res = {};
|
||||
rates.value.map((item, index) => {
|
||||
// index 是 key, item 是 value
|
||||
res[index + 1] = item;
|
||||
});
|
||||
answer.value = res;
|
||||
emit('changeAnswer', res);
|
||||
},
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,28 +1,18 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<van-field
|
||||
v-model="element.stem"
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
v-model="element.stem" :label="element.stem" :required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
<template #label>
|
||||
<contenteditable
|
||||
v-model="element.stem"
|
||||
:active="active"
|
||||
@blur="emitValue"
|
||||
></contenteditable>
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="emitValue"></contenteditable>
|
||||
</template>
|
||||
<template #input>
|
||||
<div v-for="(optionItem, optionItemIndex) in element.options" :key="optionItemIndex">
|
||||
<div
|
||||
v-for="(item, optionIndex) in optionItem"
|
||||
:key="optionIndex"
|
||||
@click="chooseOption(item)"
|
||||
>
|
||||
<div v-for="(item, optionIndex) in optionItem" :key="optionIndex" @click="chooseOption(item)">
|
||||
<contenteditable v-model="item.option" :active="active"></contenteditable>
|
||||
<RateCharacter :config="element.config"></RateCharacter>
|
||||
<div class="tips">
|
||||
@@ -39,7 +29,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, toRefs, watch } from 'vue';
|
||||
import RateCharacter from './RateCharacter.vue';
|
||||
// import RateCharacter from './RateCharacter.vue';
|
||||
|
||||
const props = defineProps({
|
||||
element: {
|
||||
|
||||
@@ -111,8 +111,8 @@ type OperateItem = (typeof operateList)[0];
|
||||
// }
|
||||
|
||||
function getCode() {
|
||||
publishInfo.value.img_url =
|
||||
'https://test-cxp-pubcos.yili.com/uat-yls//survey-api/publish/202503130938138261340.png';
|
||||
publishInfo.value.img_url
|
||||
= 'https://test-cxp-pubcos.yili.com/uat-yls//survey-api/publish/202503130938138261340.png';
|
||||
publishInfo.value.url = `${configUrl.proxyDomain}/publish?sn=${sn && sn !== undefined ? sn : ''}`;
|
||||
publishInfo.value.download_url = {
|
||||
title: '问卷下载',
|
||||
|
||||
Reference in New Issue
Block a user