| | |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="统计题目" prop="userName"> |
| | | <el-form-item label="服务类型" prop="userName"> |
| | | <el-select |
| | | v-model="queryParams.serviceType" |
| | | multiple |
| | |
| | | :data="userList" |
| | | :border="true" |
| | | @selection-change="handleSelectionChange" |
| | | @row-click="handleRowClick" |
| | | @expand-change="handleRowClick" |
| | | :row-key="getRowKey" |
| | | :expand-row-keys="expands" |
| | | > |
| | |
| | | <el-table-column |
| | | label="满意度题目总量" |
| | | align="center" |
| | | key="manual" |
| | | prop="manual" |
| | | key="joyAllCount" |
| | | prop="joyAllCount" |
| | | > |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="满意度填报量" |
| | | align="center" |
| | | key="sms" |
| | | prop="sms" |
| | | key="joyCount" |
| | | prop="joyCount" |
| | | > |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="完成比率" |
| | | align="center" |
| | | key="rate" |
| | | prop="rate" |
| | | key="joyTotal" |
| | | prop="joyTotal" |
| | | > |
| | | <template slot-scope="scope"> |
| | | <span class="button-zx" |
| | | >{{ (Number(scope.row.joyTotal) * 100).toFixed(2) }}%</span |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="操作" |
| | | align="center" |
| | | fixed="right" |
| | | width="300" |
| | | class-name="small-padding fixed-width" |
| | | > |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | size="medium" |
| | | type="text" |
| | | @click="Seedetails(scope.row)" |
| | | @click="getinfo(scope.row)" |
| | | ><span class="button-zx" |
| | | >{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span |
| | | ><i class="el-icon-s-order"></i>查看详情</span |
| | | ></el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="操作" |
| | | align="center" |
| | | fixed="right" |
| | | width="300" |
| | | class-name="small-padding fixed-width" |
| | | > |
| | | <template slot-scope="scope"> |
| | | <el-button size="medium" type="text" @click="Seedetails(scope.row)" |
| | | ><span class="button-zx" |
| | | ><i class="el-icon-s-order"></i>查看详情</span |
| | | ></el-button |
| | | > |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- <pagination |
| | |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | <!-- 单科室统计详情 --> |
| | | <el-dialog :visible.sync="topicVisible" width="45%"> |
| | | <div class="topicdia"> |
| | | <div class="top-text"> |
| | | {{ topicvalue.name }}<span>满意度指标详情</span> |
| | | </div> |
| | | <div style="overflow-x: hidden; overflow-y: auto; max-height: 65vh"> |
| | | <div |
| | | class="ttaabbcc" |
| | | v-for="(item, index) in topiclist" |
| | | :key="item.name" |
| | | > |
| | | <div class="describe"> |
| | | 第{{ index }}题: {{ item.scriptContent }}?<span |
| | | >[{{ item.scriptType == 1 ? "单选题" : "多选题" }}]</span |
| | | > |
| | | </div> |
| | | <div> |
| | | <el-table :data="item.details" style="width: 100%"> |
| | | <el-table-column prop="optionText" label="问题选项"> |
| | | </el-table-column> |
| | | <el-table-column prop="chosenQuantity" label="选择人数"> |
| | | </el-table-column> |
| | | <el-table-column prop="chosenPercentage" label="比例"> |
| | | <template slot-scope="scope"> |
| | | <span class="button-zx" |
| | | >{{ |
| | | (Number(scope.row.chosenPercentage) * 100).toFixed(2) |
| | | }}%</span |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <span slot="footer" class="dialog-footer"> |
| | | <el-button @click="topicVisible = false">关 闭</el-button> |
| | | </span> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | changetagcategory, |
| | | } from "@/api/system/label"; |
| | | import store from "@/store"; |
| | | import { getSfStatistics, selectTimelyRate } from "@/api/system/user"; |
| | | |
| | | import { |
| | | getSfStatisticsJoy, |
| | | getSfStatisticsJoyInfo, |
| | | selectTimelyRate, |
| | | } from "@/api/system/user"; |
| | | import ExcelJS from "exceljs"; |
| | | import { saveAs } from "file-saver"; |
| | | import Treeselect from "@riophae/vue-treeselect"; |
| | | import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
| | | const shortcuts = [ |
| | |
| | | pn: 1, |
| | | ps: 10, |
| | | }, |
| | | topiclist: [ |
| | | { |
| | | name: "您的身体康复情况如何", |
| | | number: 1, |
| | | type: 1, |
| | | }, |
| | | { |
| | | name: "您的饮食情况如何", |
| | | number: 2, |
| | | type: 2, |
| | | }, |
| | | { |
| | | name: "您的恢复情况如何", |
| | | number: 3, |
| | | type: 1, |
| | | }, |
| | | ], |
| | | tableData: [ |
| | | { |
| | | date: "好", |
| | | name: 12, |
| | | address: "50%", |
| | | }, |
| | | { |
| | | date: "一般", |
| | | name: 2, |
| | | address: "6.2%", |
| | | }, |
| | | { |
| | | date: "差", |
| | | name: 0, |
| | | address: "0%", |
| | | }, |
| | | ], |
| | | amendtag: false, //是否修改类别 |
| | | lstamendtag: false, //是否修改标签 |
| | | scavisible: false, //删除弹框 |
| | |
| | | dialogFormVisible: false, //添加、修改类别弹框 |
| | | lstamendtagVisible: false, //添加、修改标签弹框 |
| | | goQRCodeVisible: false, //二维码弹框 |
| | | topicVisible: false, //控制单题弹框 |
| | | topicvalue: { |
| | | name: "骨科随访模板", |
| | | number: 222, |
| | | }, |
| | | sidecolumnval: "", //类别搜索 |
| | | propss: { multiple: true }, |
| | | SeedetailsVisible: false, |
| | |
| | | }, |
| | | // 查询标签列表参数 |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | serviceType: [2], |
| | | dateRange: [], |
| | | statisticaltype: 1, |
| | |
| | | getList() { |
| | | // 处理查询参数 |
| | | const params = { |
| | | configKey: "joyCount", |
| | | ...this.queryParams, |
| | | // 如果选择了"全部",则传所有病区/科室代码 |
| | | leavehospitaldistrictcodes: |
| | |
| | | // 移除可能存在的"all"值 |
| | | delete params.leavehospitaldistrictcodes.all; |
| | | delete params.deptcodes.all; |
| | | getSfStatistics(params).then((response) => { |
| | | getSfStatisticsJoy(params).then((response) => { |
| | | console.log(response); |
| | | // this.total = response.total; |
| | | this.total = response.total; |
| | | this.userList = response.data; |
| | | }); |
| | | }, |
| | |
| | | return row.statisticaltype === 1 |
| | | ? row.leavehospitaldistrictcode |
| | | : row.deptcode; |
| | | }, |
| | | |
| | | // 处理行点击展开 |
| | | handleRowClick(row) { |
| | | console.log(row, "row"); |
| | | |
| | | // 如果已经展开则收起 |
| | | if (this.expands.includes(this.getRowKey(row))) { |
| | | this.expands = []; |
| | | return; |
| | | } |
| | | // 处理查询参数 |
| | | const params = { |
| | | ...this.queryParams, |
| | | // 如果选择了"全部",则传所有病区/科室代码 |
| | | leavehospitaldistrictcodes: [row.leavehospitaldistrictcode], |
| | | drcode: "1", |
| | | }; |
| | | // 如果该行还没有加载医生数据,则加载 |
| | | if (!row.doctorStats) { |
| | | this.loading = true; |
| | | getSfStatistics(params).then((res) => { |
| | | this.$set(row, "doctorStats", res.data); |
| | | this.expands = [this.getRowKey(row)]; |
| | | this.loading = false; |
| | | }); |
| | | } else { |
| | | this.expands = [this.getRowKey(row)]; |
| | | } |
| | | }, |
| | | /** 修改标签 */ |
| | | handleUpdate(row) { |
| | |
| | | }, |
| | | }); |
| | | }, 300); |
| | | }, |
| | | // 调起详情 |
| | | getinfo(row) { |
| | | this.topicVisible = true; |
| | | // 处理查询参数 |
| | | const params = { |
| | | configKey: "joyCount", |
| | | ...this.queryParams, |
| | | }; |
| | | if (this.queryParams.statisticaltype == 1) { |
| | | this.topicvalue.name = row.leavehospitaldistrictname; |
| | | |
| | | params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode]; |
| | | } else { |
| | | this.topicvalue.name = row.deptname; |
| | | |
| | | params.deptcodes = [row.deptcode]; |
| | | } |
| | | |
| | | // 移除可能存在的"all"值 |
| | | delete params.leavehospitaldistrictcodes.all; |
| | | delete params.deptcodes.all; |
| | | getSfStatisticsJoyInfo(params).then((response) => { |
| | | console.log(response); |
| | | this.topiclist = response.data; |
| | | }); |
| | | }, |
| | | // 添加/修改标签 |
| | | Maintenancetag() { |
| | |
| | | .catch(() => {}); |
| | | }, |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | this.download( |
| | | "smartor/serviceSubtask/getSfStatisticsExport", |
| | | { |
| | | ...this.queryParams, |
| | | }, |
| | | `user_${new Date().getTime()}.xlsx` |
| | | ); |
| | | /** 导出按钮操作 */ |
| | | async handleExport() { |
| | | try { |
| | | // 获取并格式化日期范围 |
| | | let dateRangeString = ""; |
| | | let sheetNameSuffix = ""; |
| | | |
| | | // 检查是否存在选中的日期范围 |
| | | if ( |
| | | this.queryParams.dateRange && |
| | | this.queryParams.dateRange.length === 2 |
| | | ) { |
| | | const startDateStr = this.queryParams.dateRange[0]; // 开始日期,格式 "yyyy-MM-dd" |
| | | const endDateStr = this.queryParams.dateRange[1]; // 结束日期 |
| | | |
| | | // 直接使用日期部分(已经是 yyyy-MM-dd 格式) |
| | | const startDateFormatted = startDateStr; |
| | | const endDateFormatted = endDateStr; |
| | | |
| | | // 构建日期范围字符串 |
| | | dateRangeString = `${startDateFormatted}至${endDateFormatted}`; |
| | | sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`; |
| | | } else { |
| | | // 如果没有选择日期范围,则使用当前月份作为备选方案 |
| | | const now = new Date(); |
| | | const currentMonth = now.getMonth() + 1; |
| | | dateRangeString = `${currentMonth}月`; |
| | | sheetNameSuffix = `${currentMonth}月`; |
| | | } |
| | | |
| | | // 构建文件名和工作表名 |
| | | const excelName = `满意度统计表_${dateRangeString}.xlsx`; |
| | | const worksheetName = `满意度统计_${sheetNameSuffix}`; |
| | | |
| | | // 创建工作簿和工作表 |
| | | const workbook = new ExcelJS.Workbook(); |
| | | const worksheet = workbook.addWorksheet(worksheetName); |
| | | |
| | | // 定义样式 |
| | | const titleStyle = { |
| | | font: { |
| | | name: "微软雅黑", |
| | | size: 16, |
| | | bold: true, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | fill: { |
| | | type: "pattern", |
| | | pattern: "solid", |
| | | fgColor: { argb: "FFE6F3FF" }, |
| | | }, |
| | | alignment: { |
| | | vertical: "middle", |
| | | horizontal: "center", |
| | | wrapText: true, |
| | | }, |
| | | border: { |
| | | top: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | left: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | bottom: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | right: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | }, |
| | | }; |
| | | |
| | | const headerStyle = { |
| | | font: { |
| | | name: "微软雅黑", |
| | | size: 11, |
| | | bold: true, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | fill: { |
| | | type: "pattern", |
| | | pattern: "solid", |
| | | fgColor: { argb: "FFF5F7FA" }, |
| | | }, |
| | | alignment: { |
| | | vertical: "middle", |
| | | horizontal: "center", |
| | | wrapText: true, |
| | | }, |
| | | border: { |
| | | top: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | left: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | bottom: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | right: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | }, |
| | | }; |
| | | |
| | | const cellStyle = { |
| | | font: { |
| | | name: "宋体", |
| | | size: 10, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | alignment: { |
| | | vertical: "middle", |
| | | horizontal: "center", |
| | | }, |
| | | border: { |
| | | top: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | left: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | bottom: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | right: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | }, |
| | | }; |
| | | |
| | | // 添加总标题 |
| | | worksheet.mergeCells(1, 1, 1, 10); |
| | | const titleCell = worksheet.getCell(1, 1); |
| | | titleCell.value = `满意度统计表(${sheetNameSuffix})`; |
| | | titleCell.style = titleStyle; |
| | | worksheet.getRow(1).height = 35; |
| | | |
| | | // 添加表头 |
| | | const headers = [ |
| | | "出院病区", |
| | | "科室", |
| | | "出院人次", |
| | | "无需随访人次", |
| | | "应随访人次", |
| | | "随访率", |
| | | "及时率", |
| | | "满意度题目总量", |
| | | "满意度填报量", |
| | | "完成比率", |
| | | ]; |
| | | |
| | | const headerRow = worksheet.addRow(headers); |
| | | headerRow.eachCell((cell) => { |
| | | cell.style = headerStyle; |
| | | }); |
| | | headerRow.height = 25; |
| | | |
| | | // 添加数据行 |
| | | this.userList.forEach((item) => { |
| | | const dataRow = worksheet.addRow([ |
| | | item.leavehospitaldistrictname || "", |
| | | item.deptname || "", |
| | | item.dischargeCount || 0, |
| | | item.nonFollowUp || 0, |
| | | item.followUpNeeded || 0, |
| | | item.followUpRate || "0%", |
| | | item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%", |
| | | item.joyAllCount || 0, |
| | | item.joyCount || 0, |
| | | item.joyTotal |
| | | ? (Number(item.joyTotal) * 100).toFixed(2) + "%" |
| | | : "0%", |
| | | ]); |
| | | |
| | | dataRow.eachCell((cell) => { |
| | | cell.style = cellStyle; |
| | | }); |
| | | dataRow.height = 22; |
| | | }); |
| | | |
| | | // 设置列宽 |
| | | worksheet.columns = [ |
| | | { width: 20 }, // 出院病区 |
| | | { width: 15 }, // 科室 |
| | | { width: 12 }, // 出院人次 |
| | | { width: 12 }, // 无需随访人次 |
| | | { width: 12 }, // 应随访人次 |
| | | { width: 12 }, // 随访率 |
| | | { width: 12 }, // 及时率 |
| | | { width: 15 }, // 满意度题目总量 |
| | | { width: 15 }, // 满意度填报量 |
| | | { width: 12 }, // 完成比率 |
| | | ]; |
| | | |
| | | // 生成并下载文件 |
| | | const buffer = await workbook.xlsx.writeBuffer(); |
| | | const blob = new Blob([buffer], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | }); |
| | | |
| | | // 使用FileSaver.js保存文件[2,3](@ref) |
| | | saveAs(blob, excelName); |
| | | |
| | | this.$message.success("导出成功"); |
| | | } catch (error) { |
| | | console.error("导出失败:", error); |
| | | this.$message.error(`导出失败: ${error.message}`); |
| | | } |
| | | }, |
| | | // 显示图表弹窗 |
| | | |
| | |
| | | height: 400px; |
| | | } |
| | | } |
| | | .topicdia { |
| | | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, |
| | | "Helvetica Neue", Arial, sans-serif; |
| | | color: #333; /* 主文字色 */ |
| | | } |
| | | |
| | | /* 头部标题样式 */ |
| | | .top-text { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | padding-bottom: 16px; |
| | | margin-bottom: 20px; |
| | | border-bottom: 1px solid #e8e8e8; /* 纤细的分隔线 */ |
| | | color: #1f2d3d; /* 深色标题 */ |
| | | } |
| | | .top-text span { |
| | | font-size: 14px; |
| | | font-weight: normal; |
| | | color: #666; /* 副标题颜色稍浅 */ |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | /* 题目容器样式 */ |
| | | .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; |
| | | } |
| | | |
| | | /* 表格整体样式调整 */ |
| | | .ttaabbcc .el-table { |
| | | border-radius: 4px; |
| | | overflow: hidden; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | /* 表头样式 */ |
| | | .ttaabbcc .el-table th { |
| | | background-color: #f1f5f9; /* 浅蓝色表头背景 */ |
| | | color: #333; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | /* 单元格样式 */ |
| | | .ttaabbcc .el-table td { |
| | | border-bottom: 1px solid #f0f0f0; /* 纤细的行分隔线 */ |
| | | padding: 12px 0; |
| | | } |
| | | |
| | | /* 比例数据样式 */ |
| | | .button-zx { |
| | | color: #4794c5; /* 使用与主题呼应的蓝色 */ |
| | | font-weight: 500; |
| | | } |
| | | ::v-deep.el-tabs--left, |
| | | .el-tabs--right { |
| | | overflow: hidden; |