188 lines
5.1 KiB
Vue
188 lines
5.1 KiB
Vue
<template>
|
||
<el-table :data="rows" style="width: 100%">
|
||
<el-table-column :width="tableWidth">
|
||
<template #header></template>
|
||
<template #default="{ row /*, column, $index*/ }">
|
||
<div style="position: relative">
|
||
<el-text truncated :style="{ width: `${tableWidth}px` }">
|
||
<contenteditable v-model="row.option" :active="active" @blur="emitValue" />
|
||
</el-text>
|
||
<van-popover
|
||
v-model="row.showAction"
|
||
placement="right"
|
||
trigger="click"
|
||
:actions="popoverActions"
|
||
@select="handleActionSelect($event, row, 'row')"
|
||
>
|
||
<template #reference>
|
||
<div v-if="active" class="icon">
|
||
<Io5EllipsisVerticalSharp />
|
||
</div>
|
||
</template>
|
||
</van-popover>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column v-for="(col, colIndex) in cols" :key="col.option" :width="tableWidth">
|
||
<template #header>
|
||
<div style="position: relative">
|
||
<el-text truncated :style="{ width: `${tableWidth}px` }">
|
||
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
|
||
</el-text>
|
||
<van-popover
|
||
v-model="col.showAction"
|
||
placement="right"
|
||
trigger="click"
|
||
:actions="popoverActions"
|
||
@select="handleActionSelect($event, col, 'col')"
|
||
>
|
||
<template #reference>
|
||
<div v-if="active" class="icon">
|
||
<Io5EllipsisVerticalSharp />
|
||
</div>
|
||
</template>
|
||
</van-popover>
|
||
</div>
|
||
</template>
|
||
<template #default="{ /*row, column, */ $index: rowIndex }">
|
||
<input
|
||
type="text"
|
||
style="width: 100%"
|
||
:name="`R${rowIndex + 1}`"
|
||
:value="getInputValue(rowIndex, colIndex)"
|
||
@change="handleMatrixTextChange(rowIndex, colIndex, $event)"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { Io5EllipsisVerticalSharp } from 'vue-icons-plus/io5';
|
||
|
||
// 添加激活 action 的选项
|
||
interface _questionOptionType extends questionOptionType {
|
||
showAction?: boolean;
|
||
}
|
||
|
||
// 记录行和列的索引
|
||
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 active = defineModel<boolean>('active', { required: false, default: true });
|
||
const element = defineModel<question>('element', {
|
||
required: false,
|
||
default: () => {
|
||
/**/
|
||
}
|
||
});
|
||
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
|
||
const rows = defineModel<_questionOptionType[]>('rows', { required: false, default: () => [] });
|
||
const cols = defineModel<_questionOptionType[]>('cols', { required: false, default: () => [] });
|
||
const tableWidth = defineModel<number>('tableWidth', { required: false, default: 110 });
|
||
|
||
const emit = defineEmits(['update:matrixAnswer', 'update:rowRecord', 'update:element']);
|
||
|
||
addShowActionOption();
|
||
/**
|
||
* 给行或者列选项 添加 showAction 选项
|
||
*/
|
||
function addShowActionOption() {
|
||
rows.value.forEach((row) => {
|
||
row.showAction = true;
|
||
});
|
||
cols.value.forEach((col) => {
|
||
col.showAction = true;
|
||
});
|
||
}
|
||
|
||
// 增加 popover 的 actions
|
||
const popoverActions = [
|
||
{
|
||
text: '删除'
|
||
}
|
||
// {
|
||
// text: '置底'
|
||
// }
|
||
];
|
||
|
||
// popover 的事件
|
||
function handleActionSelect(action: { text: string }, axi: any, type: 'row' | 'col') {
|
||
const data = type === 'row' ? rows : cols;
|
||
const index = data.value.indexOf(axi);
|
||
if (index < 0) return;
|
||
switch (action.text) {
|
||
case '删除':
|
||
data.value.splice(index, 1);
|
||
break;
|
||
|
||
case '置底':
|
||
data.value.push(data.value.splice(index, 1)[0]);
|
||
break;
|
||
}
|
||
}
|
||
|
||
function getInputValue(row: number, col: number) {
|
||
// console.log(`row: ${row}, col: ${col}`);
|
||
// console.log(`rowRecord:`, rowRecord.value);
|
||
|
||
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 emitValue = () => {
|
||
emit('update:element', element.value);
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import '@/assets/css/theme';
|
||
|
||
.matrix-table {
|
||
text-align: left;
|
||
|
||
tr,
|
||
td {
|
||
//width: 200px;
|
||
}
|
||
}
|
||
|
||
input {
|
||
width: 70%;
|
||
padding: 0 5px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
outline: 1px solid #f4f4f4;
|
||
|
||
&:focus {
|
||
outline: 1px solid $theme-color;
|
||
}
|
||
}
|
||
|
||
.icon {
|
||
position: absolute;
|
||
top: 0;
|
||
right: -5px;
|
||
|
||
& > svg {
|
||
height: 15px;
|
||
}
|
||
}
|
||
</style>
|