feat: 矩阵抽离组件
- 矩阵的三个组件抽离,由 MatrixQuestion 内部管理
This commit is contained in:
@@ -49,12 +49,14 @@
|
|||||||
></Completion>
|
></Completion>
|
||||||
|
|
||||||
<!-- 矩阵题 -->
|
<!-- 矩阵题 -->
|
||||||
<martrix-question
|
<matrix-question
|
||||||
v-if="
|
v-if="
|
||||||
element.question_type === 8 ||
|
element.question_type === 8 ||
|
||||||
element.question_type === 9 ||
|
element.question_type === 9 ||
|
||||||
element.question_type === 10
|
element.question_type === 10
|
||||||
"
|
"
|
||||||
|
v-model:cols="element.options[1]"
|
||||||
|
v-model:rows="element.options[0]"
|
||||||
:element="computedElement(element)"
|
:element="computedElement(element)"
|
||||||
:index="index"
|
:index="index"
|
||||||
:active="chooseQuestionId === element.id"
|
:active="chooseQuestionId === element.id"
|
||||||
@@ -149,7 +151,7 @@ import Choice from './components/Questions/Choice.vue';
|
|||||||
import ChooseQuestion from './components/ChooseQuestion.vue';
|
import ChooseQuestion from './components/ChooseQuestion.vue';
|
||||||
import Paging from './components/Questions/paging/Paging.vue';
|
import Paging from './components/Questions/paging/Paging.vue';
|
||||||
import Completion from './components/Questions/Completion.vue';
|
import Completion from './components/Questions/Completion.vue';
|
||||||
import MartrixQuestion from './components/Questions/MartrixQuestion.vue';
|
import MatrixQuestion from './components/Questions/MatrixQuestion.vue';
|
||||||
import Rate from './components/Questions/Rate.vue';
|
import Rate from './components/Questions/Rate.vue';
|
||||||
import TextWithImages from '@/views/Design/components/Questions/TextWithImages.vue';
|
import TextWithImages from '@/views/Design/components/Questions/TextWithImages.vue';
|
||||||
import SignQuestion from './components/Questions/SignQuestion.vue';
|
import SignQuestion from './components/Questions/SignQuestion.vue';
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { type Component, computed, defineModel } 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 question = defineModel<question>('element', {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const rowRecord = defineModel<unknown[]>('rowRecord', { required: false, default: () => [] });
|
|
||||||
const isPreview = defineModel<boolean>('isPreview', { required: false, default: 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 = defineModel<questionOptionType[]>('rows', { required: false, default: () => [] });
|
|
||||||
rows.value.length < 1 && (rows.value = question.value?.options[0] ?? []);
|
|
||||||
// 列标签
|
|
||||||
const cols = defineModel<questionOptionType[]>('cols', { required: false, default: () => [] });
|
|
||||||
cols.value.length < 1 && (cols.value = question.value?.options[1] ?? []);
|
|
||||||
|
|
||||||
// console.log(rows.value, cols.value);
|
|
||||||
// const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
|
||||||
|
|
||||||
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
|
||||||
// 类型 AI 生成 切勿盲目相信,以实际为准
|
|
||||||
/* const props = */
|
|
||||||
defineProps<{
|
|
||||||
index: number;
|
|
||||||
active: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:element']);
|
|
||||||
const emitValue = () => {
|
|
||||||
// console.log(question.value);
|
|
||||||
emit('update:element', question.value);
|
|
||||||
};
|
|
||||||
const errorMessage = defineModel('errorMessage', {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<van-field
|
|
||||||
v-model="question.stem"
|
|
||||||
:label="question.stem"
|
|
||||||
:required="question.config.is_required === 1"
|
|
||||||
label-align="top"
|
|
||||||
class="contenteditable-question-title"
|
|
||||||
>
|
|
||||||
<template #left-icon>
|
|
||||||
{{ index + 1 }}
|
|
||||||
</template>
|
|
||||||
<!-- 使用 title 插槽来自定义标题 -->
|
|
||||||
<template #label>
|
|
||||||
<contenteditable
|
|
||||||
v-model="question.stem"
|
|
||||||
:active="active"
|
|
||||||
className="contenteditable-label"
|
|
||||||
@blur="emitValue"
|
|
||||||
:errorMessage="errorMessage"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #input>
|
|
||||||
<Component
|
|
||||||
:is="activeComponent"
|
|
||||||
v-model:rowRecord="rowRecord"
|
|
||||||
v-model:element="question"
|
|
||||||
v-model:rows="rows"
|
|
||||||
v-model:cols="cols"
|
|
||||||
:is-preview="isPreview"
|
|
||||||
:active="active"
|
|
||||||
style="overflow: scroll; width: 88vw"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
</template>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.matrix-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
& > tbody {
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
border-width: 0 0 1px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.td-input {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,50 +1,4 @@
|
|||||||
<template>
|
<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="left-end"
|
|
||||||
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="left-end"
|
|
||||||
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
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:name="`R${rowIndex + 1}`"
|
:name="`R${rowIndex + 1}`"
|
||||||
@@ -52,35 +6,20 @@
|
|||||||
@change="handleMatrixCheckboxChange(rowIndex, colIndex)"
|
@change="handleMatrixCheckboxChange(rowIndex, colIndex)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Io5EllipsisVerticalSharp } from 'vue-icons-plus/io5';
|
// 接受获取到的 col row 的索引参数
|
||||||
|
const rowIndex = defineModel<number>('rowIndex', { required: true, default: 0 });
|
||||||
|
const colIndex = defineModel<number>('colIndex', { required: true, default: 0 });
|
||||||
|
|
||||||
// 添加激活 action 的选项
|
|
||||||
interface _questionOptionType extends questionOptionType {
|
|
||||||
showAction?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录行和列的索引
|
|
||||||
const rowRecord = defineModel<number[][]>('rowRecord', { required: false, default: () => [] });
|
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 tableWidth = defineModel<number>('tableWidth', { required: false, default: 110 });
|
|
||||||
const active = defineModel<boolean>('active', { required: false, default: true });
|
|
||||||
/* 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 element = defineModel<question>('element', {
|
const element = defineModel<question>('element', {
|
||||||
required: false,
|
required: false,
|
||||||
default: () => {
|
default: () => {
|
||||||
/**/
|
/**/
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:matrixAnswer', 'update:rowRecord', 'update:element']);
|
const emit = defineEmits(['update:matrixAnswer', 'update:rowRecord', 'update:element']);
|
||||||
|
|
||||||
// 判断是否选中
|
// 判断是否选中
|
||||||
@@ -95,45 +34,6 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
|||||||
return rowRecord.value[rowIndex].includes(colIndex);
|
return rowRecord.value[rowIndex].includes(colIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
||||||
function handleMatrixCheckboxChange(row: number, col: number) {
|
function handleMatrixCheckboxChange(row: number, col: number) {
|
||||||
// 获取 colIndexArray
|
// 获取 colIndexArray
|
||||||
@@ -158,49 +58,3 @@ const emitValue = (/* val: unknown */) => {
|
|||||||
emit('update:element', element.value);
|
emit('update:element', element.value);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
@import '@/assets/css/theme';
|
|
||||||
|
|
||||||
.matrix-table {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-checkbox {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
border: 1px solid #f4f4f4;
|
|
||||||
border-radius: 4px;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
appearance: none; /* 去除默认样式 */
|
|
||||||
//transition: border-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-checkbox:checked {
|
|
||||||
border-color: transparent; /* 选中时边框颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-checkbox:checked::before {
|
|
||||||
content: '\e728';
|
|
||||||
position: absolute;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
background-color: $theme-color; /* 选中颜色 */
|
|
||||||
color: #fff;
|
|
||||||
line-height: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 3px;
|
|
||||||
right: -10px;
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
height: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,225 +1,246 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
|
import { type Component, defineModel } from 'vue';
|
||||||
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
import { Io5EllipsisVerticalSharp } from 'vue-icons-plus/io5';
|
||||||
// import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.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';
|
||||||
|
|
||||||
// import { useTemplateRef, ref, type Directive } from 'vue';
|
// 添加激活 action 的选项
|
||||||
//
|
interface _questionOptionType extends questionOptionType {
|
||||||
// const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
showAction?: boolean;
|
||||||
//
|
}
|
||||||
// // 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
|
||||||
// // 类型 AI 生成 切勿盲目相信,以实际为准
|
// 题目
|
||||||
// const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>();
|
const element = defineModel<question>('element', {
|
||||||
//
|
type: Object,
|
||||||
// const rowRecord = new Array(element.options[0].length);
|
default: () => {
|
||||||
// // matrix 答案
|
return {};
|
||||||
// const matrixAnswer = ref({
|
}
|
||||||
// question_index: index,
|
});
|
||||||
// answer: {} as any
|
|
||||||
// });
|
// table 宽度
|
||||||
//
|
const tableWidth = defineModel<number>('tableWidth', { required: false, default: 110 });
|
||||||
// /**
|
// 行记录(相关答案的记录)
|
||||||
// * input 类型映射,里面自行处理逻辑返回对应类型
|
const rowRecord = defineModel<unknown[]>('rowRecord', { required: false, default: () => [] });
|
||||||
// * // remark: 填空内容 question_type 8
|
// 是否是预览状态
|
||||||
// * // remark: 单选打分矩阵 question_type 9
|
const isPreview = defineModel<boolean>('isPreview', { required: false, default: false });
|
||||||
// * // remark: 多选矩阵内容 question_type 10
|
// 行标签
|
||||||
// * @default 'radio'
|
const rows = defineModel<_questionOptionType[]>('rows', { required: false, default: () => [] });
|
||||||
// */
|
// 列标签
|
||||||
// const tableInputTypeMapping = (/** regx?: any */) => {
|
const cols = defineModel<_questionOptionType[]>('cols', { required: false, default: () => [] });
|
||||||
// switch (element.question_type) {
|
// 题的序号
|
||||||
// case 8:
|
const index = defineModel<number>('index', { required: false, default: 0 });
|
||||||
// return 'text';
|
// 是否是编辑状态
|
||||||
// case 9:
|
const active = defineModel<boolean>('active', { required: false, default: false });
|
||||||
// return 'radio';
|
|
||||||
// case 10:
|
const emit = defineEmits(['update:element']);
|
||||||
// return 'checkbox';
|
// 更新题
|
||||||
// default:
|
const emitValue = () => {
|
||||||
// return 'radio';
|
// console.log(question.value);
|
||||||
// }
|
emit('update:element', element.value);
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// /**
|
// 组件选择
|
||||||
// * 自定义指令,用于在元素挂载后自动获取焦点
|
const activeComponent = selectActiveComponent();
|
||||||
// */
|
function selectActiveComponent(): Component {
|
||||||
// const vFocus: Directive = {
|
console.log(`question_type`, element.value.question_type);
|
||||||
// mounted(el: HTMLInputElement) {
|
switch (element.value.question_type) {
|
||||||
// el.focus();
|
case 8:
|
||||||
// }
|
return MatrixText;
|
||||||
// };
|
case 9:
|
||||||
//
|
return MatrixRadio;
|
||||||
// /**
|
case 10:
|
||||||
// * row 的数值变动之后,触发的事件
|
return MatrixCheckbox;
|
||||||
// * @param {string} value
|
default:
|
||||||
// * @return {void}
|
return MatrixText;
|
||||||
// */
|
}
|
||||||
// function handleRowNameChange(/* value: string */) {
|
}
|
||||||
// // if (!value) return;
|
|
||||||
// }
|
console.log(`active component`, activeComponent);
|
||||||
//
|
// 增加 popover 的 actions
|
||||||
// /**
|
const popoverActions = [
|
||||||
// * col 的数值变动之后,触发的事件
|
{
|
||||||
// */
|
text: '删除'
|
||||||
// function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
}
|
||||||
// // if (!value) return;
|
// 置底功能暂时屏蔽
|
||||||
// const col = element.options[0].findIndex((option) => {
|
// {
|
||||||
// return option.option === colOption;
|
// text: '置底'
|
||||||
// });
|
|
||||||
//
|
|
||||||
// const row = element.options[1].findIndex((option) => {
|
|
||||||
// return option.option === rowOption;
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // 不同的 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;
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* popover 被选中的事件
|
||||||
|
* @param action { text: string }
|
||||||
|
* @param axi { option: string, showAction: boolean }
|
||||||
|
* @param type { 'row' | 'col' }
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addShowActionOption();
|
||||||
|
/**
|
||||||
|
* 给行或者列选项 添加 showAction 选项
|
||||||
|
*/
|
||||||
|
function addShowActionOption() {
|
||||||
|
rows.value.forEach((row) => {
|
||||||
|
row.showAction = true;
|
||||||
|
});
|
||||||
|
cols.value.forEach((col) => {
|
||||||
|
col.showAction = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorMessage = defineModel('errorMessage', {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-cell>
|
<van-field
|
||||||
|
v-model="element.stem"
|
||||||
|
:label="element.stem"
|
||||||
|
:required="element.config?.is_required === 1"
|
||||||
|
label-align="top"
|
||||||
|
class="contenteditable-question-title"
|
||||||
|
>
|
||||||
|
<template #left-icon>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</template>
|
||||||
<!-- 使用 title 插槽来自定义标题 -->
|
<!-- 使用 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>
|
<template #label>
|
||||||
<table class="matrix-table">
|
<contenteditable
|
||||||
<thead>
|
v-model="element.stem"
|
||||||
<tr>
|
:active="active"
|
||||||
<!-- 第一行内容为空 -->
|
@blur="emitValue"
|
||||||
<th></th>
|
:errorMessage="errorMessage"
|
||||||
<!-- 第二行内容开始填充 -->
|
|
||||||
<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>
|
|
||||||
<th></th>
|
|
||||||
</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>
|
</template>
|
||||||
</van-cell>
|
|
||||||
</template>
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.matrix-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
th,
|
<template #input>
|
||||||
td {
|
<el-table :data="rows" style="width: 90vw">
|
||||||
padding: 8px;
|
<el-table-column :width="tableWidth">
|
||||||
border-width: 0 0 1px;
|
<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="left-end"
|
||||||
|
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="left-end"
|
||||||
|
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 }">
|
||||||
|
<component
|
||||||
|
:is="activeComponent"
|
||||||
|
:element="element"
|
||||||
|
:rowIndex="rowIndex"
|
||||||
|
:colIndex="colIndex"
|
||||||
|
v-model:rowRecord="rowRecord"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</template>
|
||||||
|
<style lang="scss">
|
||||||
|
@import '@/assets/css/theme';
|
||||||
|
|
||||||
|
.matrix-table {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
input[type='text'] {
|
input[type='text'] {
|
||||||
width: 85%;
|
width: 70%;
|
||||||
|
padding: 0 5px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: 1px solid #f4f4f4;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 1px solid $theme-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.matrix-radio {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border: 1px solid #f4f4f4;
|
||||||
|
border-radius: 50%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none; /* 去除默认样式 */
|
||||||
|
//transition: border-color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.matrix-table-action {
|
.matrix-radio:checked {
|
||||||
margin-top: 10px;
|
border-color: transparent; /* 选中时边框颜色 */
|
||||||
|
|
||||||
.van-icon {
|
|
||||||
color: lightgreen;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.matrix-table-action-tool {
|
.matrix-radio:checked::before {
|
||||||
display: flex;
|
content: '\e728';
|
||||||
justify-content: flex-end;
|
position: absolute;
|
||||||
|
width: 15px;
|
||||||
& > span {
|
height: 15px;
|
||||||
margin-right: 6px;
|
background-color: $theme-color; /* 选中颜色 */
|
||||||
font-size: 16px;
|
color: #fff;
|
||||||
|
line-height: 15px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
right: -10px;
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
height: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,50 +1,4 @@
|
|||||||
<template>
|
<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="left-end"
|
|
||||||
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="left-end"
|
|
||||||
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
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
:name="`R${rowIndex + 1}`"
|
:name="`R${rowIndex + 1}`"
|
||||||
@@ -52,24 +6,14 @@
|
|||||||
@change="handleMatrixRadioChange(rowIndex, colIndex)"
|
@change="handleMatrixRadioChange(rowIndex, colIndex)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Io5EllipsisVerticalSharp } from 'vue-icons-plus/io5';
|
// 接受获取到的 col row 的索引参数
|
||||||
|
const rowIndex = defineModel('rowIndex', { required: true, default: 0 });
|
||||||
// 添加激活 action 的选项
|
const colIndex = defineModel('colIndex', { required: true, default: 0 });
|
||||||
interface _questionOptionType extends questionOptionType {
|
|
||||||
showAction?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] });
|
const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] });
|
||||||
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
|
|
||||||
const tableWidth = defineModel<number>('tableWidth', { required: false, default: 110 });
|
|
||||||
const rows = defineModel<_questionOptionType[]>('rows', { required: false, default: () => [] });
|
|
||||||
const cols = defineModel<_questionOptionType[]>('cols', { required: false, default: () => [] });
|
|
||||||
const active = defineModel<boolean>('active', { required: false, default: true });
|
|
||||||
const element = defineModel<question>('element', {
|
const element = defineModel<question>('element', {
|
||||||
required: false,
|
required: false,
|
||||||
default: () => {
|
default: () => {
|
||||||
@@ -78,45 +22,6 @@ const element = defineModel<question>('element', {
|
|||||||
});
|
});
|
||||||
const emit = defineEmits(['update:matrixAnswer', 'update:rowRecord', 'update:element']);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否选中
|
// 判断是否选中
|
||||||
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||||
// console.log(`rowIndex: ${rowIndex}, colIndex: ${colIndex}`);
|
// console.log(`rowIndex: ${rowIndex}, colIndex: ${colIndex}`);
|
||||||
@@ -140,49 +45,3 @@ const emitValue = () => {
|
|||||||
emit('update:element', element.value);
|
emit('update:element', element.value);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
@import '@/assets/css/theme';
|
|
||||||
|
|
||||||
.matrix-table {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-radio {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
border: 1px solid #f4f4f4;
|
|
||||||
border-radius: 50%;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
appearance: none; /* 去除默认样式 */
|
|
||||||
//transition: border-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-radio:checked {
|
|
||||||
border-color: transparent; /* 选中时边框颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-radio:checked::before {
|
|
||||||
content: '\e728';
|
|
||||||
position: absolute;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
background-color: $theme-color; /* 选中颜色 */
|
|
||||||
color: #fff;
|
|
||||||
line-height: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 3px;
|
|
||||||
right: -10px;
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
height: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,50 +1,4 @@
|
|||||||
<template>
|
<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="left-end"
|
|
||||||
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="left-end"
|
|
||||||
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
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@@ -53,76 +7,21 @@
|
|||||||
@change="handleMatrixTextChange(rowIndex, colIndex, $event)"
|
@change="handleMatrixTextChange(rowIndex, colIndex, $event)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Io5EllipsisVerticalSharp } from 'vue-icons-plus/io5';
|
// 接受获取到的 col row 的索引参数
|
||||||
|
const rowIndex = defineModel('rowIndex', { required: true, default: 0 });
|
||||||
// 添加激活 action 的选项
|
const colIndex = defineModel('colIndex', { required: true, default: 0 });
|
||||||
interface _questionOptionType extends questionOptionType {
|
|
||||||
showAction?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录行和列的索引
|
// 记录行和列的索引
|
||||||
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: () => ({}) });
|
|
||||||
// 检查 rowRecord 是否存在
|
|
||||||
// console.log(`rowRecord:`, rowRecord.value);
|
|
||||||
const active = defineModel<boolean>('active', { required: false, default: true });
|
|
||||||
const element = defineModel<question>('element', {
|
const element = defineModel<question>('element', {
|
||||||
required: false,
|
required: false,
|
||||||
default: () => {
|
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']);
|
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) {
|
function getInputValue(row: number, col: number) {
|
||||||
// console.log(`row: ${row}, col: ${col}`);
|
// console.log(`row: ${row}, col: ${col}`);
|
||||||
// console.log(`rowRecord:`, rowRecord.value);
|
// console.log(`rowRecord:`, rowRecord.value);
|
||||||
@@ -153,35 +52,4 @@ const emitValue = () => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '@/assets/css/theme';
|
@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: 3px;
|
|
||||||
right: -10px;
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
height: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -216,7 +216,6 @@
|
|||||||
:list="question.list"
|
:list="question.list"
|
||||||
:config="question.config"
|
:config="question.config"
|
||||||
:question="question"
|
:question="question"
|
||||||
isMobile
|
|
||||||
@change-answer="onRelation($event, question)"
|
@change-answer="onRelation($event, question)"
|
||||||
/>
|
/>
|
||||||
<!-- <!– 矩阵打分题 –>-->
|
<!-- <!– 矩阵打分题 –>-->
|
||||||
@@ -538,7 +537,6 @@ import answerMock from '@/views/Survey/views/Preview/js/mock.js';
|
|||||||
import { getQuestionIndex } from '@/utils/utils.js';
|
import { getQuestionIndex } from '@/utils/utils.js';
|
||||||
|
|
||||||
// hooks file
|
// hooks file
|
||||||
import icon from '@/assets/img/create-right-back.png';
|
|
||||||
import PreviewCheckbox from '@/views/Survey/views/Preview/components/questions/PreviewCheckbox.vue';
|
import PreviewCheckbox from '@/views/Survey/views/Preview/components/questions/PreviewCheckbox.vue';
|
||||||
import PreviewRate from '@/views/Survey/views/Preview/components/questions/PreviewRate.vue';
|
import PreviewRate from '@/views/Survey/views/Preview/components/questions/PreviewRate.vue';
|
||||||
import PreviewSign from '@/views/Survey/views/Preview/components/questions/PreviewSign.vue';
|
import PreviewSign from '@/views/Survey/views/Preview/components/questions/PreviewSign.vue';
|
||||||
@@ -937,7 +935,7 @@ async function answer(callback, callbackBeforePage) {
|
|||||||
// 邮箱
|
// 邮箱
|
||||||
case 5:
|
case 5:
|
||||||
if (
|
if (
|
||||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<MatrixCheckbox
|
<MatrixQuestion
|
||||||
v-model:rowRecord="rowRecord"
|
v-model:rowRecord="rowRecord"
|
||||||
v-model:matrix-radio-answer="answer!"
|
v-model:matrix-radio-answer="answer!"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
:is-preview="true"
|
:is-preview="true"
|
||||||
:errorMessage="question.error"
|
:errorMessage="question.error"
|
||||||
|
:element="question"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
|
import MatrixQuestion from '@/views/Design/components/Questions/MatrixQuestion.vue';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import Rate from '@/views/Design/components/Questions/Rate.vue';
|
|
||||||
// const questionType = defineModel<number>('questionType', { required: false });
|
// const questionType = defineModel<number>('questionType', { required: false });
|
||||||
|
|
||||||
// 矩阵多选的答案类型
|
// 矩阵多选的答案类型
|
||||||
@@ -101,17 +101,3 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.matrix-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-table th,
|
|
||||||
.matrix-table td {
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MartrixQuestion
|
<MatrixQuestion
|
||||||
v-model:rowRecord="rowRecord"
|
v-model:rowRecord="rowRecord"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
import MartrixQuestion from '@/views/Design/components/Questions/MartrixQuestion.vue';
|
import MatrixQuestion from '@/views/Design/components/Questions/MatrixQuestion.vue';
|
||||||
import Rate from '@/views/Design/components/Questions/Rate.vue';
|
|
||||||
// const questionType = defineModel<number>('questionType', { required: false });
|
// const questionType = defineModel<number>('questionType', { required: false });
|
||||||
|
|
||||||
// 矩阵单选的答案类型
|
// 矩阵单选的答案类型
|
||||||
@@ -89,17 +88,3 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.matrix-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-table th,
|
|
||||||
.matrix-table td {
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MartrixQuestion
|
<MatrixQuestion
|
||||||
v-model:rowRecord="rowRecord"
|
v-model:rowRecord="rowRecord"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
:cols="cols"
|
:cols="cols"
|
||||||
@@ -14,9 +14,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import MartrixQuestion from '@/views/Design/components/Questions/MartrixQuestion.vue';
|
import MatrixQuestion from '@/views/Design/components/Questions/MatrixQuestion.vue';
|
||||||
import Rate from '@/views/Design/components/Questions/Rate.vue';
|
|
||||||
// const questionType = defineModel<number>('questionType', { required: false });
|
|
||||||
const questionIndex = defineModel<number>('answerIndex', { required: false, default: 0 });
|
const questionIndex = defineModel<number>('answerIndex', { required: false, default: 0 });
|
||||||
|
|
||||||
// 矩阵多选的答案类型
|
// 矩阵多选的答案类型
|
||||||
@@ -24,10 +22,6 @@ type answerType = {
|
|||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// preview props
|
|
||||||
// const stem = defineModel('stem');
|
|
||||||
// const list = defineModel<questionsList[]>('list', { required: false });
|
|
||||||
// const config = defineModel<OptionConfigType>('config', { required: false });
|
|
||||||
const question = defineModel<question>('question', { default: () => {} });
|
const question = defineModel<question>('question', { default: () => {} });
|
||||||
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
|
const emit = defineEmits(['changeAnswer', 'previous', 'next']);
|
||||||
// 示例
|
// 示例
|
||||||
@@ -105,17 +99,3 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.matrix-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matrix-table th,
|
|
||||||
.matrix-table td {
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user