<template>
|
<div class="topic-dialog">
|
<div class="dialog-header">
|
<span class="title"> {{ configTitle }}指标详情 </span>
|
<el-button
|
type="primary"
|
size="mini"
|
icon="el-icon-download"
|
:disabled="!processedTopicList.length"
|
@click="exportTopicDetail"
|
>
|
导出
|
</el-button>
|
</div>
|
|
<div class="topicdia">
|
<div style="overflow-x: hidden; overflow-y: auto; max-height: 65vh">
|
<!-- 修改这里:使用 processedTopicList 而不是 topicList -->
|
<div
|
v-for="(item, index) in processedTopicList"
|
:key="item.scriptid"
|
class="ttaabbcc"
|
>
|
<div class="describe">
|
第{{ index + 1 }}题: {{ item.scriptContent }}
|
<span>[{{ item.scriptType == 1 ? "单选题" : "多选题" }}]</span>
|
</div>
|
<div>
|
<el-table :data="item.details" style="width: 100%">
|
<el-table-column
|
prop="optionText"
|
label="问题选项"
|
align="center"
|
min-width="200"
|
/>
|
<el-table-column
|
prop="chosenQuantity"
|
label="选择人数"
|
align="center"
|
min-width="120"
|
>
|
<template slot-scope="{ row }">
|
{{ row.chosenQuantity || 0 }}
|
</template>
|
</el-table-column>
|
<el-table-column
|
prop="chosenPercentage"
|
label="比例"
|
align="center"
|
min-width="120"
|
>
|
<template slot-scope="{ row }">
|
<span
|
v-if="
|
row.chosenPercentage !== null &&
|
row.chosenPercentage !== undefined
|
"
|
>
|
{{ (Number(row.chosenPercentage) * 100).toFixed(2) }}%
|
</span>
|
<span v-else>-</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 如果没有数据 -->
|
<div
|
v-if="!processedTopicList.length"
|
class="no-data"
|
style="text-align: center; padding: 50px 0"
|
>
|
<el-empty description="暂无数据"></el-empty>
|
</div>
|
|
<div
|
slot="footer"
|
class="dialog-footer"
|
style="text-align: center; padding-top: 20px"
|
>
|
<el-button @click="handleClose">关 闭</el-button>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import ExcelJS from "exceljs";
|
import { saveAs } from "file-saver";
|
|
export default {
|
name: "TopicDialog",
|
props: {
|
rowData: {
|
type: Object,
|
default: () => ({}),
|
},
|
queryParams: {
|
type: Object,
|
default: () => ({}),
|
},
|
topType: {
|
type: String,
|
},
|
topicList: {
|
type: [Array, Object],
|
default: () => ({}),
|
},
|
},
|
data() {
|
return {
|
processedTopicList: [],
|
orgname: "", // 新增:医院名称
|
};
|
},
|
computed: {
|
configTitle() {
|
const key = this.queryParams?.configKey;
|
return key === "returnVisitCount" ? "复诊通知" : "满意度";
|
},
|
},
|
created() {
|
// 获取医院名称
|
this.orgname = localStorage.getItem("orgname") || "";
|
},
|
watch: {
|
topicList: {
|
immediate: true,
|
handler(newVal) {
|
this.processTopicList(newVal);
|
},
|
},
|
},
|
methods: {
|
processTopicList(data) {
|
if (!data || typeof data !== "object") {
|
this.processedTopicList = [];
|
return;
|
}
|
|
const result = [];
|
Object.keys(data).forEach((key) => {
|
const item = data[key];
|
if (item && item.scriptContent) {
|
const processedItem = JSON.parse(JSON.stringify(item));
|
|
if (processedItem.details && Array.isArray(processedItem.details)) {
|
processedItem.details = processedItem.details.filter(
|
(detail) => detail && detail.optionText
|
);
|
}
|
result.push(processedItem);
|
}
|
});
|
|
this.processedTopicList = result;
|
},
|
|
// 格式化日期范围字符串(与主页面一致)
|
formatDateRangeForExport() {
|
let dateRangeString = "";
|
let sheetNameSuffix = "";
|
const isLishuiHospital = this.orgname == "丽水市中医院";
|
|
if (
|
this.queryParams.dateRange &&
|
this.queryParams.dateRange.length === 2
|
) {
|
const startDateStr = this.queryParams.dateRange[0];
|
const endDateStr = this.queryParams.dateRange[1];
|
|
if (isLishuiHospital) {
|
// 丽水市中医院:只显示年月
|
const formatMonthOnly = (dateStr) => {
|
const date = new Date(dateStr);
|
const year = date.getFullYear();
|
const month = date.getMonth() + 1;
|
return `${year}年${month}月`;
|
};
|
const startDateFormatted = formatMonthOnly(startDateStr);
|
const endDateFormatted = formatMonthOnly(endDateStr);
|
dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
|
sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
|
} else {
|
// 其他医院:显示年月日
|
const formatDateForDisplay = (dateStr) => {
|
return dateStr.split(" ")[0]; // 如果包含时间部分,只取日期
|
};
|
const startDateFormatted = formatDateForDisplay(startDateStr);
|
const endDateFormatted = formatDateForDisplay(endDateStr);
|
dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
|
sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
|
}
|
} else {
|
const now = new Date();
|
const currentMonth = now.getMonth() + 1;
|
const currentYear = now.getFullYear();
|
|
if (isLishuiHospital) {
|
// 丽水市中医院:显示年月
|
dateRangeString = `${currentYear}年${currentMonth}月`;
|
sheetNameSuffix = `${currentYear}年${currentMonth}月`;
|
} else {
|
// 其他医院:显示月份
|
dateRangeString = `${currentMonth}月`;
|
sheetNameSuffix = `${currentMonth}月`;
|
}
|
}
|
|
return { dateRangeString, sheetNameSuffix };
|
},
|
|
// 导出题目明细
|
async exportTopicDetail() {
|
if (!this.processedTopicList.length) {
|
this.$message.warning("暂无数据可导出");
|
return;
|
}
|
|
try {
|
// 获取格式化后的日期范围
|
const { dateRangeString, sheetNameSuffix } =
|
this.formatDateRangeForExport();
|
|
const workbook = new ExcelJS.Workbook();
|
const sheetName = `${
|
this.rowData.leavehospitaldistrictname || this.rowData.deptname
|
}${this.configTitle}明细_${sheetNameSuffix}`;
|
const worksheet = workbook.addWorksheet(sheetName);
|
|
// 样式定义(保持不变)
|
const titleStyle = {
|
font: { name: "微软雅黑", size: 14, bold: true },
|
alignment: { horizontal: "center", vertical: "middle" },
|
fill: {
|
type: "pattern",
|
pattern: "solid",
|
fgColor: { argb: "FFF5F7FA" },
|
},
|
};
|
|
const subtitleStyle = {
|
font: { name: "微软雅黑", size: 12, bold: true },
|
alignment: { horizontal: "left", vertical: "middle" },
|
};
|
|
const headerStyle = {
|
font: { name: "微软雅黑", size: 11, bold: true },
|
fill: {
|
type: "pattern",
|
pattern: "solid",
|
fgColor: { argb: "FFEBEEF5" },
|
},
|
alignment: { horizontal: "center", vertical: "middle" },
|
border: {
|
top: { style: "thin" },
|
left: { style: "thin" },
|
bottom: { style: "thin" },
|
right: { style: "thin" },
|
},
|
};
|
|
const cellStyle = {
|
font: { name: "宋体", size: 10 },
|
alignment: { horizontal: "center", vertical: "middle" },
|
border: {
|
top: { style: "thin" },
|
left: { style: "thin" },
|
bottom: { style: "thin" },
|
right: { style: "thin" },
|
},
|
};
|
|
// 标题区
|
worksheet.mergeCells(1, 1, 1, 4);
|
worksheet.getCell(
|
1,
|
1
|
).value = `${this.configTitle}题目明细(${dateRangeString})`;
|
worksheet.getCell(1, 1).style = titleStyle;
|
|
worksheet.mergeCells(2, 1, 2, 4);
|
worksheet.getCell(2, 1).value = `统计对象:${
|
this.rowData.leavehospitaldistrictname || this.rowData.deptname
|
}`;
|
worksheet.getCell(2, 1).style = subtitleStyle;
|
|
let currentRow = 4;
|
|
// 逐题写入
|
this.processedTopicList.forEach((item, index) => {
|
worksheet.mergeCells(currentRow, 1, currentRow, 4);
|
worksheet.getCell(currentRow, 1).value = `第${index + 1}题:${
|
item.scriptContent
|
} [${item.scriptType == 1 ? "单选题" : "多选题"}]`;
|
worksheet.getCell(currentRow, 1).style = subtitleStyle;
|
currentRow++;
|
|
const headerRow = worksheet.addRow([
|
"问题选项",
|
"选择人数",
|
"占比",
|
"",
|
]);
|
headerRow.eachCell((cell) => {
|
cell.style = headerStyle;
|
});
|
currentRow++;
|
|
item.details.forEach((detail) => {
|
const percent =
|
detail.chosenPercentage != null
|
? (Number(detail.chosenPercentage) * 100).toFixed(2) + "%"
|
: "-";
|
|
const row = worksheet.addRow([
|
detail.optionText,
|
detail.chosenQuantity || 0,
|
percent,
|
"",
|
]);
|
row.eachCell((cell) => {
|
cell.style = cellStyle;
|
});
|
currentRow++;
|
});
|
|
currentRow++;
|
});
|
|
// 设置列宽
|
worksheet.columns = [
|
{ width: 40 },
|
{ width: 12 },
|
{ width: 12 },
|
{ width: 10 },
|
];
|
|
// 生成文件名(与主页面保持一致)
|
const fileName = `${
|
this.rowData.leavehospitaldistrictname || this.rowData.deptname
|
}${this.configTitle}明细_${dateRangeString}.xlsx`;
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
saveAs(
|
new Blob([buffer], {
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
}),
|
fileName
|
);
|
|
this.$message.success("导出成功");
|
} catch (error) {
|
console.error("导出失败:", error);
|
this.$message.error(`导出失败: ${error.message}`);
|
}
|
},
|
|
formatPercent(value) {
|
if (value === null || value === undefined) return "-";
|
const num = parseFloat(value);
|
if (isNaN(num)) return "-";
|
return `${num.toFixed(2)}%`;
|
},
|
|
handleClose() {
|
this.$emit("close");
|
},
|
},
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.topic-dialog {
|
.topicdia {
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
"Helvetica Neue", Arial, sans-serif;
|
color: #333;
|
}
|
|
.ttaabbcc {
|
background: #fafafa;
|
border-radius: 6px;
|
padding: 16px;
|
margin-bottom: 20px;
|
border-left: 4px solid #4794c5;
|
}
|
|
.describe {
|
font-size: 15px;
|
line-height: 1.6;
|
margin-bottom: 12px;
|
color: #1f2d3d;
|
}
|
|
.describe span {
|
font-size: 13px;
|
color: #999;
|
font-style: italic;
|
margin-left: 8px;
|
}
|
|
::v-deep .el-table {
|
border-radius: 4px;
|
overflow: hidden;
|
font-size: 14px;
|
}
|
|
.dialog-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 12px 16px;
|
border-bottom: 1px solid #ebeef5;
|
background: #fafafa;
|
|
.title {
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
}
|
}
|
|
::v-deep .el-table th {
|
background-color: #f1f5f9;
|
color: #333;
|
font-weight: 600;
|
}
|
|
::v-deep .el-table td {
|
border-bottom: 1px solid #f0f0f0;
|
padding: 12px 0;
|
}
|
}
|
</style>
|