Merge branch 'feature/feature-20250331-h5' of https://e.coding.yili.com/yldc/ylst/ylst-survey-h5 into feature/feature-20250331-h5

This commit is contained in:
Huangzhe
2025-03-11 18:29:45 +08:00
42 changed files with 2891 additions and 496 deletions

View File

@@ -0,0 +1,211 @@
<script setup lang="ts">
import { useTemplateRef, ref, type Directive } from 'vue';
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
// 类型 AI 生成 切勿盲目相信,以实际为准
const { element, index } = defineProps<{ element: MatrixSurveyQuestion, index: number }>();
const rowRecord = new Array(element.options[0].length);
// matrix 答案
const matrixAnswer = ref({
question_index: index,
answer: {} as any
});
/**
* input 类型映射,里面自行处理逻辑返回对应类型
* // remark: 填空内容 question_type 8
* // remark: 单选打分矩阵 question_type 9
* // remark: 多选矩阵内容 question_type 10
* @default 'radio'
*/
const tableInputTypeMapping = (/** regx?: any */) => {
switch (element.question_type) {
case 8:
return 'text';
case 9:
return 'radio';
case 10:
return 'checkbox';
default:
return 'radio';
}
};
/**
* 自定义指令,用于在元素挂载后自动获取焦点
*/
const vFocus: Directive = {
mounted(el: HTMLInputElement) {
el.focus();
}
};
/**
* row 的数值变动之后,触发的事件
* @param {string} value
* @return {void}
*/
function handleRowNameChange(/* value: string */) {
// if (!value) return;
console.log(`row change`);
}
/**
* col 的数值变动之后,触发的事件
*/
function handleColNameChange(rowOption: string, colOption: string, e: any) {
// 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;
});
console.log(`${col + 1}_${row + 1}`);
// 不同的 question_type 的 matrix 问卷处理不同的结果
switch (element.question_type) {
case 8: {
// 获取输入框元素
const inputElement = e.target as HTMLInputElement;
// 如果没有获取到输入框元素,则直接返回
if (!inputElement) return;
// 将输入框的值保存到 rowRecord 对应位置
rowRecord[col] = e!.target!.value;
// 清空 matrixAnswer 的 answer 属性
matrixAnswer.value.answer = {};
// 遍历所有行选项
element.options[0].forEach((_, rowIndex) => {
// 获取当前行记录
const colOptions = rowRecord[rowIndex];
// 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
if (colOptions) {
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col + 1}`] = colOptions;
}
});
break;
}
case 9:
// 将选择的行索引加1后保存到 rowRecord 对应位置
rowRecord[col] = row + 1;
// 清空 matrixAnswer 的 answer 属性
matrixAnswer.value.answer = {};
// 遍历 rowRecord更新 matrixAnswer 的 answer 属性
rowRecord.forEach((row, index) => {
matrixAnswer.value.answer[`${index + 1}_${row}`] = 1;
});
break;
case 10:
// 将选择的行索引加1后添加到 rowRecord 对应位置的数组中
rowRecord[col] = (rowRecord[col] || []).concat(row + 1);
// 清空 matrixAnswer 的 answer 属性
matrixAnswer.value.answer = {};
// 遍历所有行选项
element.options[0].forEach((rowOption, rowIndex) => {
// 获取当前行记录
const colOptions = rowRecord[rowIndex];
// 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
if (colOptions) {
colOptions.forEach((col: any) => {
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col}`] = true;
});
}
});
break;
default:
break;
}
}
</script>
<template>
<van-cell>
<!-- 使用 title 插槽来自定义标题 -->
<template #title>
<span>
<span v-if="element?.config?.is_required">*</span>
<span v-html="element.title"></span>
<span v-html="element.stem"></span>
</span>
</template>
<!-- 使用 label 插槽来自定义标题 -->
<template #label>
<table class="matrix-table">
<thead>
<tr>
<!-- 第一行内容为空 -->
<th></th>
<!-- 第二行内容开始填充 -->
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
<!-- 编辑状态单次点击出输入框失焦后关闭 -->
<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="col.editor = true" v-html="col.option"></span>
</td>
</tr>
</thead>
<tbody>
<tr v-for="(row) in element.options[0]" :key="row.option">
<!-- 编辑状态单次点击出输入框失焦后关闭 -->
<td>
<input v-if="row.editor" v-model="row.option" v-focus type="text" @focusout="row.editor = false" />
<span v-else @click="row.editor = true" v-html="row.option"></span>
</td>
<td v-for="col in element.options[1]" :key="col.option">
<!-- 编辑状态单次点击出输入框失焦后关闭 -->
<input
:id="col.option" :type="tableInputTypeMapping()" :name="row.option"
@change="handleColNameChange(col.option!, row.option!,$event)"
/>
</td>
</tr>
</tbody>
</table>
</template>
</van-cell>
</template>
<style scoped lang="scss">
.matrix-table {
width: 100%;
border-collapse: collapse;
color: black;
th,
td {
padding: 8px;
border-width: 0 0 1px;
text-align: left;
}
}
input[type='text'] {
width: 85%;
}
.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>