feat: 矩阵样式更改

- 通过 matrixQuestion 来适配相应的矩阵问题
- 矩阵的样式更新
This commit is contained in:
Huangzhe
2025-03-17 20:56:00 +08:00
parent 748f197ed3
commit f8f88ddb44
6 changed files with 287 additions and 324 deletions

3
components.d.ts vendored
View File

@@ -32,7 +32,6 @@ declare module 'vue' {
VanGrid: typeof import('vant/es')['Grid'] VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem'] VanGridItem: typeof import('vant/es')['GridItem']
VanIcon: typeof import('vant/es')['Icon'] VanIcon: typeof import('vant/es')['Icon']
VanList: typeof import('vant/es')['List']
VanNavBar: typeof import('vant/es')['NavBar'] VanNavBar: typeof import('vant/es')['NavBar']
VanPicker: typeof import('vant/es')['Picker'] VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup'] VanPopup: typeof import('vant/es')['Popup']
@@ -41,8 +40,6 @@ declare module 'vue' {
VanRow: typeof import('vant/es')['Row'] VanRow: typeof import('vant/es')['Row']
VanStepper: typeof import('vant/es')['Stepper'] VanStepper: typeof import('vant/es')['Stepper']
VanSwitch: typeof import('vant/es')['Switch'] VanSwitch: typeof import('vant/es')['Switch']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
YLCascader: typeof import('./src/components/YLCascader.vue')['default'] YLCascader: typeof import('./src/components/YLCascader.vue')['default']
YLInput: typeof import('./src/components/YLInput.vue')['default'] YLInput: typeof import('./src/components/YLInput.vue')['default']
YLPicker: typeof import('./src/components/YLPicker.vue')['default'] YLPicker: typeof import('./src/components/YLPicker.vue')['default']

View File

@@ -1,38 +1,38 @@
<script setup lang="ts"> <script setup lang="ts">
import { useTemplateRef, toRefs } from 'vue'; import { /* useTemplateRef, */ ref, computed, type Component } from 'vue';
import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels'); const question = defineModel<question>('element', { default: () => ({}), required: false });
// eslint-disable-next-line
const activeComponent = computed<Component>(() => {
switch (question.value.question_type) {
case 8:
return MatrixText;
case 9:
return MatrixRadio;
case 10:
return MatrixCheckbox;
}
});
if (question.value?.list) question.value.options = question.value?.list;
// 行标签
const rows = ref(question.value?.options[0] ?? []);
// 列标签
const cols = ref(question.value?.options[1] ?? []);
console.log(rows.value, cols.value);
// const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容 // 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
// 类型 AI 生成 切勿盲目相信,以实际为准 // 类型 AI 生成 切勿盲目相信,以实际为准
const props = defineProps<{ /* const props = */ defineProps<{
element: any;
index: number; index: number;
active: boolean; active: boolean;
}>(); }>();
const { element } = toRefs(props);
/**
* input 类型映射,里面自行处理逻辑返回对应类型
* // remark: 填空内容 question_type 8
* // remark: 单选打分矩阵 question_type 9
* // remark: 多选矩阵内容 question_type 10
* @default 'radio'
*/
const tableInputTypeMapping = (/** regx?: any */) => {
switch (element.value.question_type) {
case 8:
return 'text';
case 9:
return 'radio';
case 10:
return 'checkbox';
default:
return 'radio';
}
};
const emit = defineEmits(['update:element']);
const emitValue = () => { const emitValue = () => {
emit('update:element', element.value); emit('update:element', element.value);
}; };
@@ -50,67 +50,74 @@ const emitValue = () => {
</template> </template>
<!-- 使用 title 插槽来自定义标题 --> <!-- 使用 title 插槽来自定义标题 -->
<template #label> <template #label>
<contenteditable v-model="element.stem" :active="active" @blur="emitValue"></contenteditable> <h1>
<contenteditable v-model="element.stem" :active="active" @blur="emitValue" />
</h1>
</template> </template>
<!-- 使用 label 插槽来自定义标题 -->
<template #input> <template #input>
<table class="martrix-table"> <Component :is="activeComponent" v-model:rows="rows" v-model:cols="cols" />
<thead>
<tr>
<!-- 第一行内容为空 -->
<th></th>
<!-- 第二行内容开始填充 -->
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
<contenteditable
v-model="col.option"
:active="active"
@blur="emitValue"
></contenteditable>
</td>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="row in element.options[0]" :key="row.option">
<!-- 编辑状态单次点击出输入框失焦后关闭 -->
<td>
<contenteditable
v-model="row.option"
:active="active"
@blur="emitValue"
></contenteditable>
</td>
<td v-for="col in element.options[1]" :key="col.option" class="td-input">
<!-- 编辑状态单次点击出输入框失焦后关闭 -->
<input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />
</td>
<td v-if="element.config.is_limit_right_content === 1">
<contenteditable
v-model="row.option_config.limit_right_content"
:active="active"
@blur="emitValue"
>
</contenteditable>
</td>
</tr>
</tbody>
</table>
</template> </template>
<!-- 使用 label 插槽来自定义标题 -->
<!-- <template #input>-->
<!-- <table class="matrix-table">-->
<!-- <thead>-->
<!-- <tr>-->
<!-- &lt;!&ndash; 第一行内容为空 &ndash;&gt;-->
<!-- <th></th>-->
<!-- &lt;!&ndash; 第二行内容开始填充 &ndash;&gt;-->
<!-- <td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">-->
<!-- <contenteditable-->
<!-- v-model="col.option"-->
<!-- :active="active"-->
<!-- @blur="emitValue"-->
<!-- ></contenteditable>-->
<!-- </td>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr v-for="row in element.options[0]" :key="row.option">-->
<!-- &lt;!&ndash; 编辑状态单次点击出输入框失焦后关闭 &ndash;&gt;-->
<!-- <td>-->
<!-- <contenteditable-->
<!-- v-model="row.option"-->
<!-- :active="active"-->
<!-- @blur="emitValue"-->
<!-- ></contenteditable>-->
<!-- </td>-->
<!-- <td v-for="col in element.options[1]" :key="col.option" class="td-input">-->
<!-- &lt;!&ndash; 编辑状态单次点击出输入框失焦后关闭 &ndash;&gt;-->
<!-- <input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />-->
<!-- </td>-->
<!-- <td v-if="element.config.is_limit_right_content === 1">-->
<!-- <contenteditable-->
<!-- v-model="row.option_config.limit_right_content"-->
<!-- :active="active"-->
<!-- @blur="emitValue"-->
<!-- >-->
<!-- </contenteditable>-->
<!-- </td>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </template>-->
</van-field> </van-field>
</template> </template>
<style scoped lang="scss"> <style lang="scss">
.martrix-table { .matrix-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
color: black; color: black;
& > tbody {
overflow: scroll;
}
th, th,
td { td {
padding: 8px; //min-width: 80px;
border: 1px solid #ddd; //padding: 8px;
border-width: 0 0 1px; border-width: 0 0 1px;
text-align: center; text-align: center;
} }
@@ -130,6 +137,7 @@ input[type='text'] {
input[type='checkbox'] { input[type='checkbox'] {
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 5px; border-radius: 5px;
background-color: red;
outline: none; outline: none;
} }
@@ -138,23 +146,4 @@ input[type='radio'] {
border-radius: 5px; border-radius: 5px;
outline: none; outline: none;
} }
.martrix-table-action {
margin-top: 10px;
.van-icon {
color: lightgreen;
font-size: 12px;
}
.martrix-table-action-tool {
display: flex;
justify-content: flex-end;
& > span {
margin-right: 6px;
font-size: 16px;
}
}
}
</style> </style>

View File

@@ -4,23 +4,27 @@
<tr> <tr>
<th></th> <th></th>
<td v-for="col in cols" :key="col.option"> <td v-for="col in cols" :key="col.option">
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
<!-- 编辑状态单次点击出输入框失焦后关闭 --> <!-- 编辑状态单次点击出输入框失焦后关闭 -->
<input <!-- <input-->
v-if="col.editor" <!-- v-if="col.editor"-->
v-model="col.option" <!-- v-model="col.option"-->
v-focus <!-- v-focus-->
type="text" <!-- type="text"-->
@focusout="col.editor = false" <!-- @focusout="col.editor = false"-->
@click="handleRowNameChange(col.option!)" <!-- @click="handleRowNameChange(col.option!)"-->
/> <!-- />-->
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span> <!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
</td> </td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="(row, rowIndex) in rows" :key="rowIndex"> <tr v-for="(row, rowIndex) in rows" :key="rowIndex">
<th v-html="row.option"></th> <!-- <th v-html="row.option"></th>-->
<td v-for="(col, colIndex) in cols" :key="colIndex"> <contenteditable v-model="row.option" :active="active" @blur="emitValue" />
<th v-for="(col, colIndex) in cols" :key="colIndex">
<input <input
type="checkbox" type="checkbox"
:name="`R${rowIndex + 1}`" :name="`R${rowIndex + 1}`"
@@ -28,15 +32,15 @@
:checked="isOptionChecked(rowIndex, colIndex)" :checked="isOptionChecked(rowIndex, colIndex)"
@change="handleMatrixRadioChange(rowIndex, colIndex)" @change="handleMatrixRadioChange(rowIndex, colIndex)"
/> />
</td> </th>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps } from 'vue'; // import { defineProps } from 'vue';
import { vFocus } from '@/utils/directives/useVFocus'; // import { vFocus } from '@/utils/directives/useVFocus';
// 记录行和列的索引 // 记录行和列的索引
const rowRecord = defineModel<number[][]>('rowRecord', { required: false, default: () => [] }); const rowRecord = defineModel<number[][]>('rowRecord', { required: false, default: () => [] });
@@ -44,14 +48,16 @@ const rowRecord = defineModel<number[][]>('rowRecord', { required: false, defaul
// 检查 rowRecord 是否存在 // 检查 rowRecord 是否存在
// console.log(`rowRecord:`, rowRecord.value); // console.log(`rowRecord:`, rowRecord.value);
const active = defineModel('active', { required: false, default: true });
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false }); /* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
defineProps<{ const rows = defineModel('rows', { required: false, default: () => [] });
rows: OptionType[]; const cols = defineModel('cols', { required: false, default: () => [] });
cols: OptionType[];
}>();
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']); // const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
const emitValue = () => {
emit('update:element', element.value);
};
// 判断是否选中 // 判断是否选中
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => { const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
// [ // [
@@ -64,10 +70,10 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
return rowRecord.value[rowIndex].includes(colIndex); return rowRecord.value[rowIndex].includes(colIndex);
}; };
const handleRowNameChange = (/* value: string */) => { // const handleRowNameChange = (/* value: string */) => {
// console.log(`row change: ${value}`); // // console.log(`row change: ${value}`);
// 你可以在这里添加其他逻辑 // // 你可以在这里添加其他逻辑
}; // };
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer // 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
function handleMatrixRadioChange(row: number, col: number) { function handleMatrixRadioChange(row: number, col: number) {
@@ -108,16 +114,4 @@ function handleMatrixRadioChange(row: number, col: number) {
// }; // };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.matrix-table {
width: 100%;
border-collapse: collapse;
}
.matrix-table th,
.matrix-table td {
padding: 8px;
border: 1px solid #ddd;
text-align: center;
}
</style>

View File

@@ -1,123 +1,127 @@
<script setup lang="ts"> <script setup lang="ts">
import { useTemplateRef, ref, type Directive } from 'vue'; // import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
// import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels'); // import { useTemplateRef, ref, type Directive } from 'vue';
//
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容 // const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
// 类型 AI 生成 切勿盲目相信,以实际为准 //
const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>(); // // 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
// // 类型 AI 生成 切勿盲目相信,以实际为准
const rowRecord = new Array(element.options[0].length); // const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>();
// matrix 答案 //
const matrixAnswer = ref({ // const rowRecord = new Array(element.options[0].length);
question_index: index, // // matrix 答案
answer: {} as any // const matrixAnswer = ref({
}); // question_index: index,
// answer: {} as any
/** // });
* input 类型映射,里面自行处理逻辑返回对应类型 //
* // remark: 填空内容 question_type 8 // /**
* // remark: 单选打分矩阵 question_type 9 // * input 类型映射,里面自行处理逻辑返回对应类型
* // remark: 多选矩阵内容 question_type 10 // * // remark: 填空内容 question_type 8
* @default 'radio' // * // remark: 单选打分矩阵 question_type 9
*/ // * // remark: 多选矩阵内容 question_type 10
const tableInputTypeMapping = (/** regx?: any */) => { // * @default 'radio'
switch (element.question_type) { // */
case 8: // const tableInputTypeMapping = (/** regx?: any */) => {
return 'text'; // switch (element.question_type) {
case 9: // case 8:
return 'radio'; // return 'text';
case 10: // case 9:
return 'checkbox'; // return 'radio';
default: // case 10:
return 'radio'; // return 'checkbox';
} // default:
}; // return 'radio';
// }
/** // };
* 自定义指令,用于在元素挂载后自动获取焦点 //
*/ // /**
const vFocus: Directive = { // * 自定义指令,用于在元素挂载后自动获取焦点
mounted(el: HTMLInputElement) { // */
el.focus(); // const vFocus: Directive = {
} // mounted(el: HTMLInputElement) {
}; // el.focus();
// }
/** // };
* row 的数值变动之后,触发的事件 //
* @param {string} value // /**
* @return {void} // * row 的数值变动之后,触发的事件
*/ // * @param {string} value
function handleRowNameChange(/* value: string */) { // * @return {void}
// if (!value) return; // */
} // function handleRowNameChange(/* value: string */) {
// // if (!value) return;
/** // }
* col 的数值变动之后,触发的事件 //
*/ // /**
function handleColNameChange(rowOption: string, colOption: string, e: any) { // * col 的数值变动之后,触发的事件
// if (!value) return; // */
const col = element.options[0].findIndex((option) => { // function handleColNameChange(rowOption: string, colOption: string, e: any) {
return option.option === colOption; // // if (!value) return;
}); // const col = element.options[0].findIndex((option) => {
// return option.option === colOption;
const row = element.options[1].findIndex((option) => { // });
return option.option === rowOption; //
}); // const row = element.options[1].findIndex((option) => {
// return option.option === rowOption;
// 不同的 question_type 的 matrix 问卷处理不同的结果 // });
switch (element.question_type) { //
case 8: { // // 不同的 question_type 的 matrix 问卷处理不同的结果
// 获取输入框元素 // switch (element.question_type) {
const inputElement = e.target as HTMLInputElement; // case 8: {
// 如果没有获取输入框元素,则直接返回 // // 获取输入框元素
if (!inputElement) return; // const inputElement = e.target as HTMLInputElement;
// 将输入框的值保存到 rowRecord 对应位置 // // 如果没有获取到输入框元素,则直接返回
rowRecord[col] = e!.target!.value; // if (!inputElement) return;
// 清空 matrixAnswer 的 answer 属性 // // 将输入框的值保存到 rowRecord 对应位置
matrixAnswer.value.answer = {}; // rowRecord[col] = e!.target!.value;
// 遍历所有行选项 // // 清空 matrixAnswer 的 answer 属性
element.options[0].forEach((_, rowIndex) => { // matrixAnswer.value.answer = {};
// 获取当前行记录 // // 遍历所有行选项
const colOptions = rowRecord[rowIndex]; // element.options[0].forEach((_, rowIndex) => {
// 如果当前行记录,则更新 matrixAnswer 的 answer 属性 // // 获取当前行记录
if (colOptions) { // const colOptions = rowRecord[rowIndex];
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col + 1}`] = colOptions; // // 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
} // if (colOptions) {
}); // matrixAnswer.value.answer[`R${rowIndex + 1}_C${col + 1}`] = colOptions;
break; // }
} // });
case 9: // break;
// 将选择的行索引加1后保存到 rowRecord 对应位置 // }
rowRecord[col] = row + 1; // case 9:
// 清空 matrixAnswer 的 answer 属性 // // 将选择的行索引加1后保存到 rowRecord 对应位置
matrixAnswer.value.answer = {}; // rowRecord[col] = row + 1;
// 遍历 rowRecord更新 matrixAnswer 的 answer 属性 // // 清空 matrixAnswer 的 answer 属性
rowRecord.forEach((row, index) => { // matrixAnswer.value.answer = {};
matrixAnswer.value.answer[`${index + 1}_${row}`] = 1; // // 遍历 rowRecord更新 matrixAnswer 的 answer 属性
}); // rowRecord.forEach((row, index) => {
break; // matrixAnswer.value.answer[`${index + 1}_${row}`] = 1;
case 10: // });
// 将选择的行索引加1后添加到 rowRecord 对应位置的数组中 // break;
rowRecord[col] = (rowRecord[col] || []).concat(row + 1); // case 10:
// 清空 matrixAnswer 的 answer 属性 // // 将选择的行索引加1后添加到 rowRecord 对应位置的数组中
matrixAnswer.value.answer = {}; // rowRecord[col] = (rowRecord[col] || []).concat(row + 1);
// 遍历所有行选项 // // 清空 matrixAnswer 的 answer 属性
element.options[0].forEach((rowOption, rowIndex) => { // matrixAnswer.value.answer = {};
// 获取当前行记录 // // 遍历所有行选项
const colOptions = rowRecord[rowIndex]; // element.options[0].forEach((rowOption, rowIndex) => {
// 如果当前行记录,则更新 matrixAnswer 的 answer 属性 // // 获取当前行记录
if (colOptions) { // const colOptions = rowRecord[rowIndex];
colOptions.forEach((col: any) => { // // 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col}`] = true; // if (colOptions) {
}); // colOptions.forEach((col: any) => {
} // matrixAnswer.value.answer[`R${rowIndex + 1}_C${col}`] = true;
}); // });
break; // }
default: // });
break; // break;
} // default:
} // break;
// }
// }
</script> </script>
<template> <template>
@@ -200,7 +204,7 @@ input[type='text'] {
width: 85%; width: 85%;
} }
.martrix-table-action { .matrix-table-action {
margin-top: 10px; margin-top: 10px;
.van-icon { .van-icon {
@@ -208,7 +212,7 @@ input[type='text'] {
font-size: 12px; font-size: 12px;
} }
.martrix-table-action-tool { .matrix-table-action-tool {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -3,26 +3,27 @@
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<td v-for="col in cols" :key="col.option"> <th v-for="col in cols" :key="col.option">
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
<!-- 编辑状态单次点击出输入框失焦后关闭 --> <!-- 编辑状态单次点击出输入框失焦后关闭 -->
<input <!-- <input-->
v-if="col.editor" <!-- v-if="col.editor"-->
v-model="col.option" <!-- v-model="col.option"-->
v-focus <!-- v-focus-->
type="text" <!-- type="text"-->
@focusout="col.editor = false" <!-- @focusout="col.editor = false"-->
@click="handleRowNameChange(col.option!)" <!-- @click="handleRowNameChange(col.option!)"-->
/> <!-- />-->
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span> <!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
</td> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="(row, rowIndex) in rows" :key="rowIndex"> <tr v-for="(row, rowIndex) in rows" :key="rowIndex">
<th v-html="row.option"></th> <contenteditable v-model="row.option" :active="active" @blur="emitValue" />
<td v-for="(col, colIndex) in cols" :key="colIndex"> <td v-for="(col, colIndex) in cols" :key="colIndex">
<input <input
type=" " type="radio"
:name="`R${rowIndex + 1}`" :name="`R${rowIndex + 1}`"
:value="`${rowIndex + 1}_${colIndex + 1}`" :value="`${rowIndex + 1}_${colIndex + 1}`"
:checked="isOptionChecked(rowIndex, colIndex)" :checked="isOptionChecked(rowIndex, colIndex)"
@@ -35,8 +36,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps } from 'vue'; // import { defineProps } from 'vue';
import { vFocus } from '@/utils/directives/useVFocus'; // import { vFocus } from '@/utils/directives/useVFocus';
// 记录行和列的索引 // 记录行和列的索引
const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] }); const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] });
@@ -45,11 +46,11 @@ const rowRecord = defineModel<number[]>('rowRecord', { required: false, default:
// console.log(`rowRecord:`, rowRecord.value); // console.log(`rowRecord:`, rowRecord.value);
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false }); /* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
defineProps<{
rows: OptionType[];
cols: OptionType[];
}>();
const rows = defineModel('rows', { required: false, default: () => [] });
const cols = defineModel('cols', { required: false, default: () => [] });
const active = defineModel('active', { required: false, default: true });
console.log(rows.value, cols.value);
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']); // const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
// 判断是否选中 // 判断是否选中
@@ -62,10 +63,10 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
// return !!matrixAnswer.value?.[key]; // return !!matrixAnswer.value?.[key];
}; };
const handleRowNameChange = (/* value: string */) => { // const handleRowNameChange = (/* value: string */) => {
// console.log(`row change: ${value}`); // // console.log(`row change: ${value}`);
// 你可以在这里添加其他逻辑 // // 你可以在这里添加其他逻辑
}; // };
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer // 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
function handleMatrixRadioChange(row: number, col: number) { function handleMatrixRadioChange(row: number, col: number) {
@@ -91,18 +92,9 @@ function handleMatrixRadioChange(row: number, col: number) {
// emits('update:matrixAnswer', props.matrixAnswer); // emits('update:matrixAnswer', props.matrixAnswer);
// emits('update:rowRecord', props.rowRecord); // emits('update:rowRecord', props.rowRecord);
// }; // };
const emitValue = () => {
emit('update:element', element.value);
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.matrix-table {
width: 100%;
border-collapse: collapse;
}
.matrix-table th,
.matrix-table td {
padding: 8px;
border: 1px solid #ddd;
text-align: center;
}
</style>

View File

@@ -3,23 +3,26 @@
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<td v-for="col in cols" :key="col.option"> <th v-for="col in cols" :key="col.option">
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
<!-- 编辑状态单次点击出输入框失焦后关闭 --> <!-- 编辑状态单次点击出输入框失焦后关闭 -->
<input <!-- <input-->
v-if="col.editor" <!-- v-if="col.editor"-->
v-model="col.option" <!-- v-model="col.option"-->
v-focus <!-- v-focus-->
type="text" <!-- type="text"-->
@focusout="col.editor = false" <!-- @focusout="col.editor = false"-->
@click="handleRowNameChange(col.option!)" <!-- @click="handleRowNameChange(col.option!)"-->
/> <!-- />-->
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span> <!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
</td> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="(row, rowIndex) in rows" :key="rowIndex"> <tr v-for="(row, rowIndex) in rows" :key="rowIndex">
<th v-html="row.option"></th> <!-- <th v-html="row.option"></th>-->
<contenteditable v-model="row.option" :active="active" @blur="emitValue" />
<td v-for="(col, colIndex) in cols" :key="colIndex"> <td v-for="(col, colIndex) in cols" :key="colIndex">
<input <input
type="text" type="text"
@@ -34,27 +37,23 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps } from 'vue';
import { vFocus } from '@/utils/directives/useVFocus';
// 记录行和列的索引 // 记录行和列的索引
const rowRecord = defineModel<string[][]>('rowRecord', { required: false, default: () => [] }); const rowRecord = defineModel<string[][]>('rowRecord', { required: false, default: () => [] });
// const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) }); // const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) });
// 检查 rowRecord 是否存在 // 检查 rowRecord 是否存在
// console.log(`rowRecord:`, rowRecord.value); // console.log(`rowRecord:`, rowRecord.value);
const active = defineModel('active', { required: false, default: true });
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false }); /* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
defineProps<{ const rows = defineModel('rows', { required: false, default: () => [] });
rows: OptionType[]; const cols = defineModel('cols', { required: false, default: () => [] });
cols: OptionType[];
}>();
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']); // const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
const handleRowNameChange = (/* value: string */) => { // const handleRowNameChange = (/* value: string */) => {
// console.log(`row change: ${value}`); // console.log(`row change: ${value}`);
// 你可以在这里添加其他逻辑 // 你可以在这里添加其他逻辑
}; // };
function getInputValue(row: number, col: number) { function getInputValue(row: number, col: number) {
// console.log(`row: ${row}, col: ${col}`); // console.log(`row: ${row}, col: ${col}`);
@@ -96,16 +95,4 @@ function handleMatrixTextChange(row: number, col: number, e: Event) {
// }; // };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.matrix-table {
width: 100%;
border-collapse: collapse;
}
.matrix-table th,
.matrix-table td {
padding: 8px;
border: 1px solid #ddd;
text-align: center;
}
</style>