矩阵题

This commit is contained in:
1378012178@qq.com 2025-02-05 11:25:07 +08:00
parent 1d8f10c94d
commit d5b5227c08
3 changed files with 577 additions and 5 deletions

View File

@ -172,13 +172,15 @@
<a-col :span="24" :lg="{ span: 4 }" style="padding: 10px;">
<a-row>
<a-col :span="12" :lg="{ span: 24 }">
<a-card title="可选题型" style="height: 370px; border: 1px solid #e8e8e8;">
<a-card title="可选题型" style="height: 410px; border: 1px solid #e8e8e8;">
<p><a-button type="primary" @click="addTigan(3)" :disabled="editDisabled">单选题</a-button></p>
<p><a-button type="primary" @click="addTigan(4)" :disabled="editDisabled">多选题</a-button></p>
<p><a-button type="primary" @click="addTigan(5)" :disabled="editDisabled">填空题</a-button></p>
<p><a-button type="primary" @click="addTigan(8)" :disabled="editDisabled">文件题</a-button></p>
<p><a-button type="primary" @click="addTigan(502)" :disabled="editDisabled">简答题</a-button></p>
<p><a-button type="primary" @click="addTigan(305)" :disabled="editDisabled">判断题</a-button></p>
<!-- 量表题矩阵题-->
<!-- <p><a-button type="primary" @click="addTigan(7)" :disabled="editDisabled">量表题</a-button></p> -->
</a-card>
</a-col>
<a-col :span="12" :lg="{ span: 24 }">
@ -609,7 +611,107 @@
</template>
</a-card>
</div>
<!-- 量表题 -->
<div style="width: 100%" v-else-if="item.wjType == 7">
<a-card>
<template #title>
<div>
<a-row>
<a-col :span="11">
<span>{{ index + 1 }}<span style="color: #c2bfbf">[量表题]</span></span>
</a-col>
<a-col :span="13" style="text-align: right;">
<a-tooltip placement="topRight" title="删除此题"
><Icon
icon="ant-design:delete-outlined"
style="cursor: pointer; font-size: 20px; margin: 10px"
@click="handleDelTigan(item, index)"
v-if="!editDisabled"
/></a-tooltip>
<Icon
v-if="isSmallScreen && !editDisabled"
icon="pixelarticons:chevrons-vertical"
class="drag-handle"
style="cursor: move; font-size: 20px; margin-right: 10px;"
/>
</a-col>
</a-row>
</div>
<JEditor2 placeholder="请填写文件题题干"
v-model:value="item.wjTitle"
:bordered="false"
:style="{ width: '30rem' }"
:auto-size="{ minRows: 1, maxRows: 5 }"
:disabled="editDisabled" v-if="!editDisabled"/>
<div v-else class="rich-text-container" v-html="item.wjTitle"></div>
<div>
<!-- 包裹表格以允许水平滚动 -->
<div class="scrollable-table-container">
<div class="custom-table">
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<td>标题/选项</td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<a-input v-model:value="item_.itemTitle" class="input-field flex-grow-1 mr-1" v-if="!editDisabled"/>
<div v-else style="width:100%; text-align: center;"><span>{{ item_.itemTitle }}</span></div>
<a-dropdown class="dropdown-menu" v-if="!editDisabled">
<Icon icon="ant-design:caret-down-filled" style="cursor: pointer;" @click.stop.prevent="handleColumnAction($event, item, index)" />
<template #overlay>
<a-menu>
<a-menu-item key="add" :disabled="item.items.length >= 10" @click="handleColumnAction('add', item)">添加</a-menu-item>
<a-menu-item key="delete" :disabled="item.items.length <= 3" @click="handleColumnAction('delete', item, index)">删除</a-menu-item>
<a-menu-item key="moveLeft" :disabled="index == 0" @click="handleColumnAction('moveLeft', item, index)">左移</a-menu-item>
<a-menu-item key="moveRight" :disabled="index >= item.items.length - 1" @click="handleColumnAction('moveRight', item, index)">右移</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</td>
</tr>
<tr>
<td>分值</td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<a-input-number v-if="!editDisabled" v-model:value="item_.itemScore" class="input-field flex-grow-1 mr-1" :min="1" :max="5" :precision="0" :step="1" />
<div v-else style="width:100%; text-align: center;"><span>{{ item_.itemScore }}</span></div>
</div>
</td>
</tr>
<tr v-for="(row, rowIndex) in item.itemRows" :key="rowIndex + 2">
<td class="row-cell">
<div class="input-with-dropdown d-flex align-items-center">
<a-input v-model:value="row.itemTitle" class="input-field flex-grow-1 mr-2" v-if="!editDisabled"/>
<div v-else style="width:100%; text-align: center;"><span>{{ row.itemTitle }}</span></div>
<a-dropdown class="dropdown-menu" v-if="!editDisabled">
<Icon icon="ant-design:caret-down-filled" style="cursor: pointer;" @click.stop.prevent="handleRowAction($event, item, rowIndex)" />
<template #overlay>
<a-menu>
<a-menu-item key="add" @click="handleRowAction('add', item)">添加</a-menu-item>
<a-menu-item key="delete" :disabled="item.itemRows.length <= 2" @click="handleRowAction('delete', item, rowIndex)">删除</a-menu-item>
<a-menu-item key="moveTop" :disabled="rowIndex == 0" @click="handleRowAction('moveTop', item, rowIndex)">上移</a-menu-item>
<a-menu-item key="moveDown" :disabled="rowIndex >= item.itemRows.length - 1" @click="handleRowAction('moveDown', item, rowIndex)">下移</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</td>
<td v-for="(item_, colIndex) in item.items" :key="colIndex">
<div class="circle"></div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div style="text-align: right;color: #c2bfbf" v-if="isShow">是否加入题库
<j-dict-select-tag type='radio' v-model:value="item.sftjtk" dictCode="yn" placeholder="是否加入题库" :disabled="editDisabled"/>
</div>
</template>
</a-card>
</div>
<div v-else></div>
</div>
</template>
@ -1304,7 +1406,16 @@ import { create } from 'sortablejs';
import { downloadByUrl } from '/@/utils/file/download';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import ZyCyFenxiangListModal from '/@/views/zy/zyCyFenxiang/ZyCyFenxiangListModal.vue';
import MatrixQuestion from './components/MatrixQuestion.vue';
//
function handleMatrixItemsUpdate(newItems) {
matrixItems.value = newItems;
}
function handleMatrixItemRowsUpdate(newItemRows) {
matrixItemRows.value = newItemRows;
}
const glob = useGlobSetting();
const globSetting = useGlobSetting();
@ -2007,9 +2118,71 @@ function addTigan(type) {
list.push(params);
tiganData.value = [...list];
//
} else if (type == 7){//
let params = {
wjType: 7,
wjSubtype: 701,
wjIndex: list.length + 1,
mainId: mainId,
wjTitle: null,
wjScore: null,
wjLeixing,
wjAnswer: null,
wjSfqh: '0',
sftjtk: '1',
itemRows: [
{ qIndex: 1, itemIndex: 1, itemTitle: '外观' },
{ qIndex: 2, itemIndex: 2, itemTitle: '功能' }
//
],
items: [
{ itemScore: '1', itemTitle: '很不满意' },
{ itemScore: '2', itemTitle: '不满意' },
{ itemScore: '3', itemTitle: '一般' },
{ itemScore: '4', itemTitle: '满意' },
{ itemScore: '5', itemTitle: '很满意' }
//
]
};
list.push(params);
tiganData.value = [...list];
}
}
const handleColumnAction = (action, item, index) => {
if (action === 'add' && item.items.length < 10) {
const newItem = { itemScore: '5', itemTitle: '' };
item.items.push(newItem);
} else if (action === 'delete' && item.items.length > 3) {
item.items.splice(index, 1);
}else if(action === 'moveLeft' ){
let temp = item.items[index];
item.items[index] = item.items[index - 1];
item.items[index - 1] = temp;
}else if(action === 'moveRight' ){
let temp = item.items[index];
item.items[index] = item.items[index + 1];
item.items[index + 1] = temp;
}
};
const handleRowAction = (action, item, rowIndex) => {
if (action === 'add') {
const newRow = { qIndex: item.itemRows.length + 1,itemIndex: item.itemRows.length + 1,itemTitle: '' };
item.itemRows.push(newRow);
} else if (action === 'delete' && item.itemRows.length > 2) {
item.itemRows.splice(rowIndex, 1);
} else if (action === 'moveTop' ) {
let temp = item.itemRows[rowIndex];
item.itemRows[rowIndex] = item.itemRows[rowIndex - 1];
item.itemRows[rowIndex - 1] = temp;
} else if (action === 'moveDown' ) {
let temp = item.itemRows[rowIndex];
item.itemRows[rowIndex] = item.itemRows[rowIndex + 1];
item.itemRows[rowIndex + 1] = temp;
}
};
/**
* 拖动结束事件
* @param evt
@ -2287,7 +2460,7 @@ async function submitForm() {
return;
}
if (isShow.value) {
if (!param.wjScore) {
if (!param.wjScore && param.wjType != 7) {
createMessage.error('请填写题目分数');
sfjx = '0';
confirmLoading.value = false;
@ -2843,4 +3016,92 @@ onMounted(() => {
word-break: break-all; /* 长单词和 URL 地址换行 */
overflow-wrap: break-word; /* 在长单词内部换行 */
}
.scrollable-table-container {
overflow-x: auto; /* 允许水平滚动 */
width: 100%;
-webkit-overflow-scrolling: touch; /* 确保移动端可以流畅滚动 */
}
.custom-table {
width: 100%;
margin-top: 10px;
}
.custom-table table {
width: max-content; /* 表格宽度根据内容自适应 */
border-collapse: collapse;
min-width: 100%; /* 确保表格至少占据父容器的全部宽度 */
}
.custom-table th,
.custom-table td {
border: 1px solid #ccc;
padding: 8px;
text-align: center;
white-space: nowrap; /* 单元格内容不换行,以保证内容完整显示 */
min-width: 130px; /* 设置最小宽度 */
width: 80px; /* 设置固定宽度 */
}
/* 输入框与下拉菜单的组合样式 */
.input-with-dropdown {
display: flex;
align-items: center;
justify-content: space-between;
}
.input-field {
width: calc(100% - 30px); /* 为图标留出空间 */
}
.dropdown-menu .anticon {
font-size: 16px;
color: #1890ff;
cursor: pointer;
}
.d-flex {
display: flex;
}
.align-items-center {
align-items: center;
}
.flex-grow-1 {
flex-grow: 1;
}
.mr-1 {
margin-right: 5px;
}
.mr-2 {
margin-right: 20px; /* 为图标留出一些空间 */
}
.row-cell {
position: relative;
}
.row-cell .dropdown-menu {
position: absolute;
right: 8px; /* 根据需要调整 */
top: 50%;
transform: translateY(-50%);
}
/* 自定义空白圈样式 */
.circle {
width: 20px;
height: 20px;
background-color: #F8F9FA; /* 乳白色 */
border-radius: 50%;
border: 1px solid #ccc; /* 灰色边框 */
display: flex;
align-items: center;
justify-content: center;
margin: auto;
}
</style>

View File

@ -205,10 +205,64 @@
</a-row>
</a-card>
</div>
<!-- 量表题 -->
<div style="width: 100%" v-else-if="item.wjType == 7">
<div style="text-align: left; width: 100%; font-weight: bold; line-height: 80px; font-size: 18px">
量表题</div>
<a-card>
<template #title>
<div style="white-space: pre-wrap; word-wrap: break-word"><span>{{ index + 1 }}</span><span
v-html="item.wjTitle" style="white-space: pre-wrap; word-wrap: break-word"></span></div>
</template>
<a-row>
<a-col :span="24">
<div>
<!-- 包裹表格以允许水平滚动 -->
<div class="scrollable-table-container">
<div class="custom-table">
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<td></td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ item_.itemTitle }}</span></div>
</div>
</td>
</tr>
<!-- <tr>
<td>分值</td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ item_.itemScore }}</span></div>
</div>
</td>
</tr> -->
<tr v-for="(row, rowIndex) in item.itemRows" :key="rowIndex + 2">
<td class="row-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ row.itemTitle }}</span></div>
</div>
</td>
<!-- 确保每一行形成一组Radio -->
<td v-for="(item_, colIndex) in item.items" :key="colIndex">
<a-radio-group v-model:value="row.itemSelected" @change="changeScaleSelected(item)">
<a-radio :value="colIndex+1">
</a-radio>
</a-radio-group>
</td>
</tr>
</table>
</div>
</div>
</div>
</a-col>
</a-row>
</a-card>
</div>
<div v-else> 无对应类型-{{ item.wjType }}-{{ item.wjSubtype }}=</div>
</div>
</a-col>
<a-col :span="24" style="text-align: center" v-if="!sfsxs">
<a-col :span="24" style="text-align: center;margin-top: 20px;" v-if="!sfsxs">
<a-button type="primary" @click="submitForm">提交</a-button>
</a-col>
@ -346,6 +400,16 @@ async function submitForm() {
createMessage.warning('第' + (i + 1) + '题没有作答,请检查试卷,完成所有作答!');
return;
}
} else if (param.wjType == 7) {
let v = true
param.itemRows.forEach(element => {
if(!element.itemSelected)v = false
});
if(!v){
emit('closeLoading');
createMessage.warning('第' + (i + 1) + '题没有作答,请检查试卷,完成所有作答!');
return;
}
}
// values[i].openTime = openTime.value;
}
@ -495,6 +559,14 @@ async function refreshFT() {
finishTime.value = finishTimeData.result
}
function changeScaleSelected(item){
item.itemSelected = ''
item.itemRows.forEach((element,index) => {
item.itemSelected += ','+(index+1) + '!' + element.itemSelected
});
item.itemSelected = item.itemSelected.replace(',','')
}
//
onMounted(async () => {
//
@ -693,4 +765,92 @@ defineExpose({
margin-left: auto;
margin-right: auto;
}
.scrollable-table-container {
overflow-x: auto; /* 允许水平滚动 */
width: 100%;
-webkit-overflow-scrolling: touch; /* 确保移动端可以流畅滚动 */
}
.custom-table {
width: 100%;
margin-top: 10px;
}
.custom-table table {
width: max-content; /* 表格宽度根据内容自适应 */
border-collapse: collapse;
min-width: 100%; /* 确保表格至少占据父容器的全部宽度 */
}
.custom-table th,
.custom-table td {
// border: 1px solid #ccc;
padding: 8px;
text-align: center;
white-space: nowrap; /* 单元格内容不换行,以保证内容完整显示 */
min-width: 130px; /* 设置最小宽度 */
width: 80px; /* 设置固定宽度 */
}
/* 输入框与下拉菜单的组合样式 */
.input-with-dropdown {
display: flex;
align-items: center;
justify-content: space-between;
}
.input-field {
width: calc(100% - 30px); /* 为图标留出空间 */
}
.dropdown-menu .anticon {
font-size: 16px;
color: #1890ff;
cursor: pointer;
}
.d-flex {
display: flex;
}
.align-items-center {
align-items: center;
}
.flex-grow-1 {
flex-grow: 1;
}
.mr-1 {
margin-right: 5px;
}
.mr-2 {
margin-right: 20px; /* 为图标留出一些空间 */
}
.row-cell {
position: relative;
}
.row-cell .dropdown-menu {
position: absolute;
right: 8px; /* 根据需要调整 */
top: 50%;
transform: translateY(-50%);
}
/* 自定义空白圈样式 */
.circle {
width: 20px;
height: 20px;
background-color: #F8F9FA; /* 乳白色 */
border-radius: 50%;
border: 1px solid #ccc; /* 灰色边框 */
display: flex;
align-items: center;
justify-content: center;
margin: auto;
}
</style>

View File

@ -229,6 +229,69 @@
</a-row>
</a-card>
</div>
<!-- 量表题 -->
<div style="width: 92%; margin: 0 auto" v-else-if="item.wjType == '7'">
<div style="text-align: left; width: 100%; font-weight: bold; font-size: 18px; padding: 20px">量表题</div>
<a-card>
<template #title>
<span>{{ index + 1 }}</span><span v-html:value="item.wjTitle" style="white-space: pre-wrap; word-wrap: break-word" />
<div v-if="item.picPath">
<j-upload
v-model:value="item.picPath"
fileType="image"
disabled
:maxCount="item.picPath.split(',').length"
:buttonVisible="false"
></j-upload>
</div>
<!-- <span v-if="item.tktda" style="color:#9e9e9e;margin-left:30px;font-size:12px;">(正确答案:{{item.tktda}})</span> -->
</template>
<a-row>
<a-col :span="24">
<div>
<!-- 包裹表格以允许水平滚动 -->
<div class="scrollable-table-container">
<div class="custom-table">
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<td></td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ item_.itemTitle }}</span></div>
</div>
</td>
</tr>
<!-- <tr>
<td>分值</td>
<td v-for="(item_, index) in item.items" :key="index" class="column-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ item_.itemScore }}</span></div>
</div>
</td>
</tr> -->
<tr v-for="(row, rowIndex) in item.itemRows" :key="rowIndex + 2">
<td class="row-cell">
<div class="input-with-dropdown d-flex align-items-center">
<div style="width:100%; text-align: center;"><span>{{ row.itemTitle }}</span></div>
</div>
</td>
<!-- 确保每一行形成一组Radio -->
<td v-for="(item_, colIndex) in item.items" :key="colIndex">
<a-radio-group v-model:value="row.itemSelected" disabled>
<a-radio :value="item_.itemTitle">
</a-radio>
</a-radio-group>
</td>
</tr>
</table>
</div>
</div>
</div>
</a-col>
</a-row>
</a-card>
</div>
<div v-else> 无对应类型 </div>
</div>
</a-col>
@ -328,4 +391,92 @@ defineExpose({
.answer-word {
color: #ff8710;
}
.scrollable-table-container {
overflow-x: auto; /* 允许水平滚动 */
width: 100%;
-webkit-overflow-scrolling: touch; /* 确保移动端可以流畅滚动 */
}
.custom-table {
width: 100%;
margin-top: 10px;
}
.custom-table table {
width: max-content; /* 表格宽度根据内容自适应 */
border-collapse: collapse;
min-width: 100%; /* 确保表格至少占据父容器的全部宽度 */
}
.custom-table th,
.custom-table td {
// border: 1px solid #ccc;
padding: 8px;
text-align: center;
white-space: nowrap; /* 单元格内容不换行,以保证内容完整显示 */
min-width: 130px; /* 设置最小宽度 */
width: 80px; /* 设置固定宽度 */
}
/* 输入框与下拉菜单的组合样式 */
.input-with-dropdown {
display: flex;
align-items: center;
justify-content: space-between;
}
.input-field {
width: calc(100% - 30px); /* 为图标留出空间 */
}
.dropdown-menu .anticon {
font-size: 16px;
color: #1890ff;
cursor: pointer;
}
.d-flex {
display: flex;
}
.align-items-center {
align-items: center;
}
.flex-grow-1 {
flex-grow: 1;
}
.mr-1 {
margin-right: 5px;
}
.mr-2 {
margin-right: 20px; /* 为图标留出一些空间 */
}
.row-cell {
position: relative;
}
.row-cell .dropdown-menu {
position: absolute;
right: 8px; /* 根据需要调整 */
top: 50%;
transform: translateY(-50%);
}
/* 自定义空白圈样式 */
.circle {
width: 20px;
height: 20px;
background-color: #F8F9FA; /* 乳白色 */
border-radius: 50%;
border: 1px solid #ccc; /* 灰色边框 */
display: flex;
align-items: center;
justify-content: center;
margin: auto;
}
</style>