<template>
|
<div class="indexanalysis">
|
<div class="analysis-top">
|
<div class="title-top">查询条件</div>
|
<div class="value">
|
<el-form ref="form" :model="queryParams" label-width="120px">
|
<el-form-item label="选择问题名称">
|
<el-select
|
ref="questionSelect"
|
remote
|
:remote-method="remoteMethod"
|
default-first-option
|
v-model="selectedTargets"
|
@change="handleTargetChange"
|
@keyup.enter.native="handleEnterSearch"
|
filterable
|
multiple
|
collapse-tags
|
reserve-keyword
|
:loading="searchLoading"
|
placeholder="请输入问题名称搜索,按回车确认"
|
>
|
<el-option
|
v-for="item in targetList"
|
:key="item.id"
|
:label="item.scriptContent || item.targetname"
|
:value="item.id"
|
>
|
<span>{{ item.scriptContent || item.targetname }}</span>
|
<span style="float: right; color: #8492a6; font-size: 13px">
|
ID: {{ item.id }}
|
</span>
|
</el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="已选题目">
|
<div class="selected-ids">
|
{{ selectedContentsText }}
|
</div>
|
</el-form-item>
|
</el-form>
|
</div>
|
</div>
|
|
<div class="formindex">
|
<el-table
|
v-loading="loading"
|
:data="processedTableData"
|
:span-method="objectSpanMethod"
|
border
|
:summary-method="getSummaries"
|
show-summary
|
style="width: 100%"
|
empty-text="请选择要统计的题目"
|
>
|
<el-table-column prop="targetname" label="问题名称" width="200">
|
<template slot-scope="scope">
|
<div class="target-name-cell">
|
{{ scope.row.targetname }}
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column prop="targetShowCount" label="问题出现次数" width="120">
|
<template slot-scope="scope">
|
{{ scope.row.targetShowCount }}次
|
</template>
|
</el-table-column>
|
<el-table-column prop="completedPercentage" label="题目完成度" width="120">
|
<template slot-scope="scope">
|
{{ formatPercentage(scope.row.completedPercentage) }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="matchedtext" label="选项内容" width="150">
|
<template slot-scope="scope">
|
{{ scope.row.matchedtext || '-' }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="count" label="选中次数" width="100">
|
<template slot-scope="scope">
|
{{ scope.row.count }}次
|
</template>
|
</el-table-column>
|
<el-table-column prop="percentage" label="占比" width="100">
|
<template slot-scope="scope">
|
<span>{{ formatPercentage(scope.row.percentage) }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="进度条" min-width="200">
|
<template slot-scope="scope">
|
<el-progress
|
:percentage="Number(scope.row.percentage) * 100"
|
:show-text="false"
|
:color="customColors"
|
/>
|
<span class="progress-text">{{ formatPercentage(scope.row.percentage) }}</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { getissuelist, compileissuestatistics } from "@/api/AiCentre/index";
|
|
export default {
|
name: "indexanalysis",
|
data() {
|
return {
|
targetList: [],
|
selectedTargets: [], // 存储选中的题目ID
|
tableData: [],
|
processedTableData: [],
|
loading: false,
|
searchLoading: false,
|
queryParams: {
|
pageNum: 1,
|
pageSize: 66,
|
scriptContent: '',
|
},
|
customColors: [
|
{ color: '#f56c6c', percentage: 20 },
|
{ color: '#e6a23c', percentage: 40 },
|
{ color: '#5cb87a', percentage: 60 },
|
{ color: '#1989fa', percentage: 80 },
|
{ color: '#6f7ad3', percentage: 100 }
|
],
|
spanArr: [],
|
searchTimer: null,
|
currentSearchQuery: '', // 当前搜索关键词
|
};
|
},
|
|
computed: {
|
// 计算选中的问题内容文本
|
selectedContentsText() {
|
if (this.selectedTargets.length === 0) {
|
return '未选择任何题目';
|
}
|
|
// 根据选中的ID获取对应的scriptContent
|
const selectedContents = this.selectedTargets.map(id => {
|
const target = this.targetList.find(item => item.id === id);
|
return target ? (target.scriptContent || target.targetname || `题目${id}`) : `题目${id}`;
|
});
|
|
return selectedContents.join('; ');
|
},
|
|
// 获取选中项的内容数组(用于显示)
|
selectedContents() {
|
return this.selectedTargets.map(id => {
|
const target = this.targetList.find(item => item.id === id);
|
return target ? (target.scriptContent || target.targetname) : `题目${id}`;
|
});
|
}
|
},
|
|
watch: {
|
processedTableData: {
|
handler(newVal) {
|
if (newVal && newVal.length > 0) {
|
this.getSpanArr(newVal);
|
} else {
|
this.spanArr = [];
|
}
|
},
|
immediate: true,
|
deep: true
|
}
|
},
|
|
created() {
|
this.getList();
|
},
|
|
methods: {
|
// 查询问卷列表
|
async getList() {
|
this.loading = true;
|
try {
|
const response = await getissuelist(this.queryParams);
|
this.targetList = response.rows || [];
|
} catch (error) {
|
console.error('获取题目列表失败:', error);
|
this.$message.error('获取题目列表失败');
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 回车键搜索处理[6,8](@ref)
|
handleEnterSearch(event) {
|
const inputElement = event.target;
|
const searchQuery = inputElement.value.trim();
|
|
|
this.currentSearchQuery = searchQuery;
|
this.executeSearch(searchQuery);
|
|
// 防止默认行为
|
event.preventDefault();
|
event.stopPropagation();
|
|
},
|
|
// 远程搜索方法(带防抖)
|
remoteMethod(query) {
|
if (this.searchTimer) {
|
clearTimeout(this.searchTimer);
|
}
|
|
this.searchTimer = setTimeout(() => {
|
this.currentSearchQuery = query;
|
this.executeSearch(query);
|
}, 300);
|
},
|
|
// 执行搜索
|
async executeSearch(query) {
|
if (query === '') {
|
this.queryParams.scriptContent = '';
|
await this.getList();
|
return;
|
}
|
|
this.searchLoading = true;
|
|
try {
|
const searchParams = {
|
pageNum: 1,
|
pageSize: 50,
|
scriptType: "1",
|
scriptContent: query
|
};
|
|
const response = await getissuelist(searchParams);
|
this.targetList = response.rows || [];
|
|
if (this.targetList.length === 0) {
|
this.$message.info(`未找到包含"${query}"的问题`);
|
}
|
} catch (error) {
|
console.error('搜索题目失败:', error);
|
this.$message.error('搜索服务异常,请稍后重试');
|
this.targetList = [];
|
} finally {
|
this.searchLoading = false;
|
}
|
},
|
|
// 多选题目改变处理
|
handleTargetChange(selectedIds) {
|
if (selectedIds && selectedIds.length > 0) {
|
this.Labelstatistics(selectedIds.join(','));
|
} else {
|
this.processedTableData = [];
|
this.spanArr = [];
|
}
|
},
|
|
// 获取统计信息
|
async Labelstatistics(scriptIds) {
|
if (!scriptIds) {
|
this.processedTableData = [];
|
this.spanArr = [];
|
return;
|
}
|
|
this.loading = true;
|
try {
|
const response = await compileissuestatistics({ scriptids: scriptIds });
|
this.tableData = response.data || [];
|
this.processTableData();
|
} catch (error) {
|
console.error('获取统计信息失败:', error);
|
this.$message.error('获取统计信息失败');
|
this.processedTableData = [];
|
this.spanArr = [];
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 处理表格数据
|
processTableData() {
|
if (!this.tableData || Object.keys(this.tableData).length === 0) {
|
this.processedTableData = [];
|
return;
|
}
|
|
const processedData = [];
|
|
Object.keys(this.tableData).forEach(scriptId => {
|
const questionData = this.tableData[scriptId];
|
|
if (questionData && questionData.details) {
|
const targetName = questionData.scriptContent || `题目${scriptId}`;
|
const targetShowCount = questionData.allQuantity || 0;
|
const completedPercentage = questionData.completedPercentage || "0";
|
|
questionData.details.forEach(detail => {
|
if (detail.optionText) {
|
processedData.push({
|
scriptid: scriptId,
|
targetname: targetName,
|
targetShowCount: targetShowCount,
|
matchedtext: detail.optionText,
|
count: detail.chosenQuantity || 0,
|
percentage: detail.chosenPercentage || "0",
|
completedPercentage: completedPercentage,
|
allQuantity: questionData.allQuantity || 0,
|
completedQuantity: questionData.completedQuantity || 0
|
});
|
}
|
});
|
|
if (questionData.details.length === 0) {
|
processedData.push({
|
scriptid: scriptId,
|
targetname: targetName,
|
targetShowCount: targetShowCount,
|
matchedtext: '-',
|
count: 0,
|
percentage: "0",
|
completedPercentage: completedPercentage,
|
allQuantity: questionData.allQuantity || 0,
|
completedQuantity: questionData.completedQuantity || 0
|
});
|
}
|
}
|
});
|
|
this.processedTableData = processedData;
|
},
|
|
// 生成合并信息数组
|
getSpanArr(data) {
|
this.spanArr = [];
|
|
if (!data || data.length === 0) return;
|
|
for (let i = 0; i < data.length; i++) {
|
if (i === 0) {
|
this.spanArr.push(1);
|
this.pos = 0;
|
} else {
|
if (data[i].scriptid === data[i - 1].scriptid) {
|
this.spanArr[this.pos] += 1;
|
this.spanArr.push(0);
|
} else {
|
this.spanArr.push(1);
|
this.pos = i;
|
}
|
}
|
}
|
},
|
|
// 单元格合并方法
|
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
|
if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
|
if (this.spanArr.length > rowIndex) {
|
const rowspan = this.spanArr[rowIndex];
|
const colspan = rowspan > 0 ? 1 : 0;
|
|
return {
|
rowspan: rowspan,
|
colspan: colspan
|
};
|
}
|
}
|
},
|
|
// 格式化百分比显示
|
formatPercentage(value) {
|
const numValue = Number(value);
|
return isNaN(numValue) ? '0%' : `${(numValue * 100).toFixed(2)}%`;
|
},
|
|
// 表格合计行计算
|
getSummaries(param) {
|
const { columns, data } = param;
|
const sums = [];
|
|
columns.forEach((column, index) => {
|
if (index === 0) {
|
sums[index] = '合计';
|
return;
|
}
|
|
if (data.length === 0) {
|
sums[index] = '-';
|
return;
|
}
|
|
switch (column.property) {
|
case 'targetShowCount':
|
const totalQuestions = new Set(data.map(item => item.scriptid)).size;
|
sums[index] = `${totalQuestions}个题目`;
|
break;
|
|
case 'count':
|
const values = data.map(item => Number(item.count));
|
const totalCount = values.reduce((prev, curr) => prev + curr, 0);
|
sums[index] = `${totalCount}次`;
|
break;
|
|
case 'percentage':
|
const percentages = data.map(item => Number(item.percentage));
|
const validPercentages = percentages.filter(p => !isNaN(p));
|
if (validPercentages.length > 0) {
|
const avgPercentage = validPercentages.reduce((a, b) => a + b, 0) / validPercentages.length;
|
sums[index] = `${(avgPercentage * 100).toFixed(2)}%`;
|
} else {
|
sums[index] = '0%';
|
}
|
break;
|
|
case 'completedPercentage':
|
const completedPercentages = data.map(item => Number(item.completedPercentage));
|
const validCompleted = completedPercentages.filter(p => !isNaN(p));
|
if (validCompleted.length > 0) {
|
const avgCompleted = validCompleted.reduce((a, b) => a + b, 0) / validCompleted.length;
|
sums[index] = `${(avgCompleted * 100).toFixed(2)}%`;
|
} else {
|
sums[index] = '0%';
|
}
|
break;
|
|
default:
|
sums[index] = '-';
|
break;
|
}
|
});
|
|
return sums;
|
}
|
},
|
|
beforeDestroy() {
|
if (this.searchTimer) {
|
clearTimeout(this.searchTimer);
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.analysis-top {
|
border: 1px solid #dcdfe6;
|
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
|
margin: 15px;
|
|
.title-top {
|
background-color: #6784f2;
|
color: #fff;
|
padding: 10px 20px;
|
font-size: 20px;
|
font-weight: 500;
|
margin-bottom: 20px;
|
}
|
|
.value {
|
padding: 0 20px 20px;
|
}
|
}
|
|
.formindex {
|
margin: 0 15px;
|
border: 1px solid #dcdfe6;
|
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
|
padding: 20px;
|
}
|
|
.selected-ids {
|
padding: 8px 12px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
border: 1px solid #e4e7ed;
|
min-height: 36px;
|
word-break: break-all;
|
line-height: 1.5;
|
}
|
|
.target-name-cell {
|
font-weight: 600;
|
color: #409eff;
|
}
|
|
.progress-text {
|
margin-left: 10px;
|
font-size: 12px;
|
color: #909399;
|
}
|
|
::v-deep .el-progress-bar {
|
padding-right: 0;
|
margin-right: 0;
|
}
|
|
::v-deep .el-select {
|
width: 100%;
|
}
|
|
::v-deep .el-table {
|
.cell {
|
word-break: break-word;
|
}
|
|
.el-table__body tr:hover > td.el-table__cell {
|
background-color: #f5f7fa;
|
}
|
|
.el-table__body .el-table__cell {
|
vertical-align: top;
|
}
|
}
|
|
.merged-cell {
|
background-color: #f0f9ff;
|
font-weight: 600;
|
}
|
|
::v-deep .el-select__tags {
|
.el-tag {
|
max-width: 200px;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
|
.el-tag__close {
|
margin-left: 4px;
|
}
|
}
|
}
|
</style>
|