From a7eb9f0ef66e3528a58f0f6c140e7bf3eda6e596 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 15 四月 2026 09:04:29 +0800
Subject: [PATCH] 测试完成
---
src/views/sfstatistics/percentage/components/SecondFollowUp.vue | 679 +++
src/api/system/user.js | 8
src/views/sfstatistics/percentage/index copy.vue | 2898 ++++++++++++++++
dist.zip | 0
src/views/sfstatistics/percentage/components/TimelyRateDialog.vue | 249 +
vue.config.js | 5
市一.zip | 0
ls&sltd.zip | 0
src/views/sfstatistics/percentage/components/FirstFollowUp.vue | 728 ++++
src/views/sfstatistics/percentage/components/styles.scss | 90
sltd.zip | 0
src/views/sfstatistics/percentage/components/ChartDialog.vue | 579 +++
src/views/followvisit/record/detailpage/index.vue | 169
src/views/sfstatistics/percentage/index.vue | 3910 +--------------------
src/views/sfstatistics/percentage/components/ContinuedCare.vue | 633 +++
src/views/sfstatistics/percentage/components/DetailDialog.vue | 302 +
src/views/Satisfaction/configurationmyd/index.vue | 18
src/views/followvisit/discharge/index.vue | 6
18 files changed, 6,541 insertions(+), 3,733 deletions(-)
diff --git a/dist.zip b/dist.zip
new file mode 100644
index 0000000..549a409
--- /dev/null
+++ b/dist.zip
Binary files differ
diff --git a/ls&sltd.zip b/ls&sltd.zip
new file mode 100644
index 0000000..faee31d
--- /dev/null
+++ b/ls&sltd.zip
Binary files differ
diff --git a/sltd.zip b/sltd.zip
new file mode 100644
index 0000000..20682a0
--- /dev/null
+++ b/sltd.zip
Binary files differ
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 53e4168..6d5b155 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -102,6 +102,14 @@
data: data,
});
}
+// 寤剁画鎶ょ悊缁熻
+export function getContinueNerseCount(data) {
+ return request({
+ url: "/smartor/serviceSubtask/getContinueNerseCount",
+ method: "post",
+ data: data,
+ });
+}
// 婊℃剰搴︾粺璁¤鎯�
export function getSfStatisticsJoyInfo(data) {
return request({
diff --git a/src/views/Satisfaction/configurationmyd/index.vue b/src/views/Satisfaction/configurationmyd/index.vue
index 75038c3..5029a05 100644
--- a/src/views/Satisfaction/configurationmyd/index.vue
+++ b/src/views/Satisfaction/configurationmyd/index.vue
@@ -976,12 +976,16 @@
return new Promise((resolve) => {
getQtemplatelist({ pageSize: 1000 })
.then((res) => {
- if (res.code === 200) {
+ console.log(res.rows, "res.rows");
+ if (res.code == 200) {
+ console.log(res.rows, 2);
this.questionnaireTemplates = (res.rows || []).map((item) => ({
id: item.svyid,
templateName: item.svyname,
isavailable: item.isavailable,
}));
+ console.log(this.followupTemplates, 3);
+
} else {
this.$message.error(res.msg || "鍔犺浇闂嵎妯℃澘澶辫触");
}
@@ -1000,12 +1004,16 @@
return new Promise((resolve) => {
getFollowuplist({ pageSize: 1000 })
.then((res) => {
- if (res.code === 200) {
+ console.log(res.rows, "res.rows");
+ if (res.code == 200) {
+ console.log(res.rows, 2);
+
this.followupTemplates = (res.rows || []).map((item) => ({
id: item.id,
templateName: item.templateName,
isavailable: item.isavailable,
}));
+ console.log(this.followupTemplates, 3);
} else {
this.$message.error(res.msg || "鍔犺浇璇煶妯℃澘澶辫触");
}
@@ -1200,8 +1208,10 @@
/** 閰嶇疆鍙樻洿澶勭悊 */
handleConfigChange(question) {
this.$nextTick(() => {
- const index = this.filteredQuestionList.findIndex((q) => q.id === question.id);
- console.log(index,'index');
+ const index = this.filteredQuestionList.findIndex(
+ (q) => q.id === question.id
+ );
+ console.log(index, "index");
if (index !== -1) {
const formRef = this.$refs.configForm && this.$refs.configForm[index];
diff --git a/src/views/followvisit/discharge/index.vue b/src/views/followvisit/discharge/index.vue
index 9b176e5..9e91878 100644
--- a/src/views/followvisit/discharge/index.vue
+++ b/src/views/followvisit/discharge/index.vue
@@ -210,7 +210,7 @@
</el-form>
<el-divider></el-divider>
<el-row :gutter="10" class="mb8">
- <!-- <el-col :span="1.5">
+ <el-col :span="1.5">
<div class="documentf">
<div class="document">
<el-button
@@ -223,7 +223,7 @@
>
</div>
</div>
- </el-col> -->
+ </el-col>
<el-col :span="1.5">
<el-button
type="primary"
@@ -2047,7 +2047,7 @@
{
...this.topqueryParams,
},
- `user_${new Date().getTime()}.xlsx`
+ `user_${new Date().getTime()}.xlsx`,
);
},
// 寮傚父鍒楁覆鏌�
diff --git a/src/views/followvisit/record/detailpage/index.vue b/src/views/followvisit/record/detailpage/index.vue
index a58c449..65aeb31 100644
--- a/src/views/followvisit/record/detailpage/index.vue
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -447,7 +447,7 @@
<div class="scriptTopic-dev" :key="index" v-else>
<div class="dev-text">
{{ index + 1 }}銆乕闂瓟]<span>{{
- item.scriptContent
+ item.questiontext
}}</span>
<span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
</div>
@@ -1570,8 +1570,6 @@
methods: {
// 鑾峰彇涓婚鏍峰紡绫�
getTopicClass(item) {
- console.log(item.isabnormal, "getTopicClass");
-
// 鏍规嵁鐘舵�佸�艰繑鍥炲搴旂殑鏍峰紡绫�
if (item.isabnormal == 1) {
return "scriptTopic-isabnormal"; // 寮傚父 - 绾㈣壊
@@ -1614,13 +1612,15 @@
this.tableDatatop = res.data.scriptResult;
this.tableDatatop.forEach((item) => {
- if (item.scriptType == 2) item.scriptResult = [];
if (item.scriptResultId && item.scriptType != 2) {
item.isoption = 3;
item.scriptResult = item.scriptResult;
} else if (item.scriptResultId && item.scriptType == 2) {
+ console.log(item.scriptResult, "item.scriptResult");
item.scriptResult = item.scriptResult.split("&");
item.isoption = 3;
+ } else if (!item.scriptResultId && item.scriptType == 2) {
+ item.scriptResult = [];
}
});
this.taskname = res.data.taskName;
@@ -1744,7 +1744,7 @@
if (item.targetvalue) {
item.scriptResult = item.targetvalue.split("&");
} else {
- item.scriptResult = [];
+ item.scriptResult = item.asrtext;
}
});
@@ -1763,7 +1763,7 @@
item.scriptID = item.id;
item.id = null;
// 绫诲瀷鍒ゆ柇璧嬪��
- if (item.ivrTaskScriptTargetoptionList) {
+ if (item.ivrTaskScriptTargetoptionList.length) {
item.targetvalue = 1;
item.questiontext = item.scriptContent;
@@ -1773,8 +1773,6 @@
}
if (item.targetvalue) {
item.scriptResult = item.targetvalue.split("&");
- } else {
- item.scriptResult = [];
}
});
}
@@ -1782,16 +1780,18 @@
},
// 鍖绘姢浜哄憳瀛樺偍鏁版嵁
getdetail() {
+ console.log(1);
let excep = "";
- const promises = [];
+
+ // 鍏堝鐞� tableDatatop 涓殑鏁版嵁
this.tableDatatop.forEach((item) => {
if (item.valueType == 3 && item.scriptResult) {
- // 楠岃瘉鏄惁涓烘湁鏁堟暟瀛�
if (!/^\d+$/.test(item.scriptResult)) {
this.$message.error(`闂 "${item.scriptContent}" 蹇呴』杈撳叆鏁板瓧`);
return;
}
}
+
var objs = item.svyTaskTemplateTargetoptions.find(
(items) => items.optioncontent == item.scriptResult
);
@@ -1802,36 +1802,36 @@
this.selectedTag = objs.isabnormal;
}
}
- console.log(excep, "excep");
- let obj = {
- asrtext: null,
- patid: this.patid,
- subId: this.id,
- taskid: this.taskid,
- scriptid: item.id,
- excep: excep,
- questiontext: item.scriptContent,
- categoryid: item.categoryid,
- answerps: item.answerps || null, // 娣诲姞闄勫姞淇℃伅
- };
- if (item.scriptType == 2 && item.scriptResult[0]) {
- obj.asrtext = item.scriptResult.join("&");
- obj.ivrtext = item.scriptResult.join("&");
+ // 澶勭悊 scriptResult锛岀洿鎺ヤ慨鏀瑰師濮嬫暟鎹�
+ if (item.scriptType == 2 && item.scriptResult) {
+ // 澶勭悊鏁扮粍绫诲瀷鐨� scriptResult
+ if (
+ Array.isArray(item.scriptResult) &&
+ item.scriptResult.length > 0
+ ) {
+ item.originalScriptResult = item.scriptResult; // 淇濆瓨鍘熷鏁扮粍锛堝彲閫夛級
+ item.scriptResult = item.scriptResult.join("&"); // 杞崲涓哄瓧绗︿覆
+ }
} else if (item.scriptType != 2 && item.scriptResult) {
- obj.asrtext = item.scriptResult;
- obj.ivrtext = item.scriptResult;
+ // 纭繚闈炴暟缁勭被鍨嬪凡缁忔槸瀛楃涓�
+ if (Array.isArray(item.scriptResult)) {
+ item.originalScriptResult = item.scriptResult; // 淇濆瓨鍘熷鏁扮粍锛堝彲閫夛級
+ item.scriptResult =
+ item.scriptResult.length > 0 ? item.scriptResult[0] : "";
+ }
}
-
- // if (item.isoption == 3) {
- // promises.push(serviceSubtaskDetailedit(obj));
- // } else {
- // promises.push(serviceSubtaskDetailadd(obj));
- // }
});
- console.log(this.tableDatatop);
+
+ // 鍒涘缓鍓湰鐢ㄤ簬淇濆瓨锛岄伩鍏嶅奖鍝嶆樉绀�
+ const saveData = this.tableDatatop.map((item) => ({
+ ...item,
+ // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屽仛鏈�鍚庣殑鏁版嵁娓呯悊
+ scriptResult: item.scriptResult || "", // 纭繚涓嶄负 undefined
+ }));
+
let obj = {
- svyTaskTemplateScriptVOS: this.tableDatatop, // 鎻愪氦澶勭悊鍚庣殑鍓湰
+ svyTaskTemplateScriptVOS: saveData, // 浣跨敤澶勭悊鍚庣殑鏁版嵁
param1: this.taskid,
param2: this.patid,
param6: this.id,
@@ -1872,51 +1872,6 @@
});
}
});
- // 浣跨敤 Promise.all 绛夊緟鎵�鏈夊紓姝ユ搷浣滃畬鎴�
- // Promise.all(promises)
- // .then((results) => {
- // // 鎵�鏈夊紓姝ユ搷浣滄垚鍔熷畬鎴愬悗鐨勯�昏緫
- // results.forEach((res) => {
- // if (res.code !== 200) {
- // this.$modal.error("淇敼澶辫触");
- // }
- // });
- // this.Editsingletasksonyic(6);
- // const orgName = localStorage.getItem("orgname");
- // console.log(orgName, "orgName");
-
- // if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
- // this.Torouter();
- // return;
- // }
- // this.$modal
- // .confirm(
- // '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
- // this.userform.name +
- // '"鍐嶆闅忚锛�',
- // "纭",
- // {
- // confirmButtonText: "纭畾",
- // cancelButtonText: "鍙栨秷",
- // showCancelButton: true,
- // dangerouslyUseHTMLString: true,
- // confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
- // cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
- // }
- // )
- // .then(() => {
- // document.querySelector("#app").scrollTo(0, 0);
- // this.formtidy();
- // this.dialogFormVisible = true;
- // })
- // .catch(() => {
- // this.Torouter();
- // });
- // })
- // .catch((error) => {
- // // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
- // console.error("鍙戠敓閿欒锛�", error);
- // });
},
Torouter() {
if (this.form.serviceType == 13) {
@@ -2048,20 +2003,28 @@
},
yuyingetdetail() {
const dataToSubmit = JSON.parse(JSON.stringify(this.tableDatatop));
+
dataToSubmit.forEach((item, index) => {
// 瀵规嫹璐濈殑鏁版嵁杩涜鎿嶄綔锛屼笉褰卞搷鍘熷鐨� scriptResult 鏁扮粍
- item.scriptResult = item.scriptResult.join("&");
+ if (item.targetvalue) {
+ item.scriptResult = item.scriptResult.join("&");
+ item.asrtext = item.matchedtext;
+ item.ivrtext = item.matchedtext;
+ } else {
+ item.asrtext = item.scriptResult;
+ item.ivrtext = item.scriptResult;
+ }
item.templatequestionnum = index + 1;
item.subId = this.id;
+
item.taskid = this.taskid;
- item.asrtext = item.matchedtext;
- item.ivrtext = item.matchedtext;
if (!item.id) {
item.isoperation = 1;
}
item.patid = this.patid;
item.templateid = item.templateID;
});
+ console.log("c", 3);
let obj = {
ivrTaskTemplateScriptVOList: dataToSubmit, // 鎻愪氦澶勭悊鍚庣殑鍓湰
@@ -2070,6 +2033,7 @@
param6: this.id,
type: 1,
};
+ console.log("c", 4);
const orgName = localStorage.getItem("orgname");
console.log(orgName, "orgName");
@@ -2322,35 +2286,7 @@
})
.catch(() => {});
},
- aahandleOptionChange(a, b, c) {
- const result = c.find((item) => item.optioncontent == a);
- if (result.nextQuestion == 0) {
- this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
- acc.push(i > b ? { ...item, astrict: 1 } : item);
- return acc;
- }, []);
- } else {
- this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
- acc.push(i > b ? { ...item, astrict: 0 } : item);
- return acc;
- }, []);
- }
- if (this.Voicetype) {
- var obj = this.tableDatatop[b].ivrTaskScriptTargetoptionList.find(
- (item) => item.optioncontent == a
- );
- } else {
- var obj = this.tableDatatop[b].svyTaskTemplateTargetoptions.find(
- (item) => item.optioncontent == a
- );
- }
- if (obj.isabnormal) {
- this.tableDatatop[b].isabnormal = true;
- } else {
- this.tableDatatop[b].isabnormal = false;
- }
- this.$forceUpdate();
- },
+
handleRadioToggles(questionItem, optionValue) {
if (!questionItem.matchedtext) {
questionItem.matchedtext == "";
@@ -2409,7 +2345,13 @@
this.tableDatatop[questionIndex].showAppendInput =
selectedOptionObj.appendflag == 1;
console.log(this.tableDatatop);
-
+ if (
+ selectedOptionObj.nextQuestion !== undefined &&
+ selectedOptionObj.nextQuestion !== null
+ ) {
+ this.tableDatatop[questionIndex].nextScriptno =
+ selectedOptionObj.nextQuestion;
+ }
// if (!this.tableDatatop[questionIndex].showAppendInput) {
// this.tableDatatop[questionIndex].answerps = ""; // 娓呴櫎闄勫姞淇℃伅
// }
@@ -2479,7 +2421,6 @@
hiddenByEnd: index === questionIndex + 1 ? false : item.hiddenByEnd,
}));
}
- 2;
this.$forceUpdate();
},
diff --git a/src/views/sfstatistics/percentage/components/ChartDialog.vue b/src/views/sfstatistics/percentage/components/ChartDialog.vue
new file mode 100644
index 0000000..4172811
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/ChartDialog.vue
@@ -0,0 +1,579 @@
+<template>
+ <el-dialog
+ title="闅忚缁熻瓒嬪娍鍥�"
+ :visible.sync="visible"
+ width="80%"
+ :close-on-click-modal="false"
+ @close="handleClose"
+ >
+ <div class="chart-container">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <div class="chart-title">闅忚鐘舵�佸垎甯�</div>
+ <div id="pieChart" style="width: 100%; height: 400px"></div>
+ </el-col>
+ <el-col :span="12">
+ <div class="chart-title">闅忚瓒嬪娍鍒嗘瀽</div>
+ <div id="barLineChart" style="width: 100%; height: 400px"></div>
+ </el-col>
+ </el-row>
+ </div>
+ </el-dialog>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+
+export default {
+ name: 'ChartDialog',
+ props: {
+ visible: {
+ type: Boolean,
+ default: false
+ },
+ data: {
+ type: Array,
+ default: () => []
+ },
+ activeTab: {
+ type: String,
+ default: 'first'
+ }
+ },
+ data() {
+ return {
+ pieChart: null,
+ barLineChart: null
+ }
+ },
+ watch: {
+ visible(newVal) {
+ if (newVal) {
+ this.$nextTick(() => {
+ this.initCharts()
+ })
+ } else {
+ this.destroyCharts()
+ }
+ }
+ },
+ mounted() {
+ if (this.visible) {
+ this.$nextTick(() => {
+ this.initCharts()
+ })
+ }
+ },
+ beforeDestroy() {
+ this.destroyCharts()
+ },
+ methods: {
+ initCharts() {
+ this.initPieChart()
+ this.initBarLineChart()
+ },
+
+ initPieChart() {
+ const pieDom = document.getElementById('pieChart')
+ if (!pieDom) return
+
+ if (this.pieChart) {
+ this.pieChart.dispose()
+ }
+
+ this.pieChart = echarts.init(pieDom)
+
+ // 鏍规嵁褰撳墠tab璁$畻楗煎浘鏁版嵁
+ const pieData = this.getPieChartData()
+
+ const pieOption = {
+ title: {
+ text: '闅忚鐘舵�佸垎甯�',
+ left: 'center',
+ textStyle: {
+ color: '#333',
+ fontSize: 16
+ }
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left',
+ data: pieData.legendData,
+ textStyle: {
+ color: '#666'
+ }
+ },
+ color: ['#FF9D4D', '#36B37E', '#FF5C5C'],
+ series: [
+ {
+ name: '闅忚鐘舵��',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ avoidLabelOverlap: true,
+ itemStyle: {
+ borderRadius: 10,
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: true,
+ formatter: '{b}: {c} ({d}%)',
+ color: '#333'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '18',
+ fontWeight: 'bold'
+ },
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ },
+ data: pieData.seriesData
+ }
+ ]
+ }
+
+ this.pieChart.setOption(pieOption)
+ window.addEventListener('resize', this.resizePieChart)
+ },
+
+ getPieChartData() {
+ let legendData = []
+ let seriesData = []
+
+ if (this.activeTab === 'first') {
+ legendData = ['寰呴殢璁�', '闅忚鎴愬姛', '闅忚澶辫触']
+ const followUpData = {
+ pending: 0,
+ success: 0,
+ fail: 0
+ }
+
+ this.data.forEach((item) => {
+ followUpData.pending += item.pendingFollowUp || 0
+ followUpData.success += item.followUpSuccess || 0
+ followUpData.fail += item.followUpFail || 0
+ })
+
+ seriesData = [
+ { value: followUpData.pending, name: '寰呴殢璁�' },
+ { value: followUpData.success, name: '闅忚鎴愬姛' },
+ { value: followUpData.fail, name: '闅忚澶辫触' }
+ ]
+ } else if (this.activeTab === 'second') {
+ legendData = ['寰呴殢璁�(鍐嶆)', '闅忚鎴愬姛(鍐嶆)', '闅忚澶辫触(鍐嶆)']
+ const followUpData = {
+ pending: 0,
+ success: 0,
+ fail: 0
+ }
+
+ this.data.forEach((item) => {
+ followUpData.pending += item.pendingFollowUpAgain || 0
+ followUpData.success += item.followUpSuccessAgain || 0
+ followUpData.fail += item.followUpFailAgain || 0
+ })
+
+ seriesData = [
+ { value: followUpData.pending, name: '寰呴殢璁�(鍐嶆)' },
+ { value: followUpData.success, name: '闅忚鎴愬姛(鍐嶆)' },
+ { value: followUpData.fail, name: '闅忚澶辫触(鍐嶆)' }
+ ]
+ } else if (this.activeTab === 'continued') {
+ legendData = ['鎶ょ悊瀹屾垚', '鎶ょ悊杩涜涓�', '鎶ょ悊鏈紑濮�']
+ const careData = {
+ completed: 0,
+ inProgress: 0,
+ notStarted: 0
+ }
+
+ this.data.forEach((item) => {
+ careData.completed += item.careCompleted || 0
+ careData.inProgress += item.careInProgress || 0
+ careData.notStarted += item.careNotStarted || 0
+ })
+
+ seriesData = [
+ { value: careData.completed, name: '鎶ょ悊瀹屾垚' },
+ { value: careData.inProgress, name: '鎶ょ悊杩涜涓�' },
+ { value: careData.notStarted, name: '鎶ょ悊鏈紑濮�' }
+ ]
+ }
+
+ return { legendData, seriesData }
+ },
+
+ initBarLineChart() {
+ const barDom = document.getElementById('barLineChart')
+ if (!barDom) return
+
+ if (this.barLineChart) {
+ this.barLineChart.dispose()
+ }
+
+ this.barLineChart = echarts.init(barDom)
+
+ // 鍑嗗鏁版嵁
+ const chartData = this.getBarLineChartData()
+
+ const option = {
+ title: {
+ text: `${chartData.title}瓒嬪娍`,
+ left: 'center',
+ textStyle: {
+ color: '#333',
+ fontSize: 16
+ }
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross',
+ crossStyle: {
+ color: '#999'
+ }
+ }
+ },
+ legend: {
+ data: chartData.legendData,
+ top: 'bottom',
+ textStyle: {
+ color: '#666'
+ }
+ },
+ color: chartData.colors,
+ xAxis: {
+ type: 'category',
+ data: chartData.categories,
+ axisLabel: {
+ interval: 0,
+ rotate: 30,
+ color: '#666'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#ddd'
+ }
+ }
+ },
+ yAxis: [
+ {
+ type: 'value',
+ name: chartData.yAxisName1,
+ min: 0,
+ axisLabel: {
+ color: '#666'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#ddd'
+ }
+ },
+ splitLine: {
+ lineStyle: {
+ color: '#f0f0f0'
+ }
+ }
+ },
+ {
+ type: 'value',
+ name: '鐧惧垎姣�(%)',
+ min: 0,
+ max: 100,
+ axisLabel: {
+ color: '#666',
+ formatter: '{value}%'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#ddd'
+ }
+ },
+ splitLine: {
+ show: false
+ }
+ }
+ ],
+ series: chartData.series,
+ grid: {
+ top: '15%',
+ left: '3%',
+ right: '4%',
+ bottom: '15%',
+ containLabel: true
+ }
+ }
+
+ this.barLineChart.setOption(option)
+ window.addEventListener('resize', this.resizeBarLineChart)
+ },
+
+ getBarLineChartData() {
+ const categories = this.data.map(
+ (item) => item.leavehospitaldistrictname || item.deptname
+ )
+
+ let title = '绉戝/鐥呭尯'
+ let yAxisName1 = '浜烘'
+ let legendData = []
+ let colors = []
+ let series = []
+
+ if (this.activeTab === 'first') {
+ title = '棣栨闅忚'
+ yAxisName1 = '浜烘'
+ legendData = ['鍑洪櫌浜烘', '搴旈殢璁夸汉娆�', '闅忚鐜�(%)', '鍙婃椂鐜�(%)']
+ colors = ['#5470C6', '#91CC75', '#EE6666', '#9A60B4']
+
+ const dischargeData = this.data.map((item) => item.dischargeCount || 0)
+ const followUpData = this.data.map((item) => item.followUpNeeded || 0)
+ const followUpRateData = this.data.map((item) => {
+ if (!item.followUpRate) return 0
+ const rateStr = String(item.followUpRate).replace('%', '')
+ return parseFloat(rateStr) || 0
+ })
+ const timelyRateData = this.data.map((item) =>
+ item.rate ? (Number(item.rate) * 100).toFixed(2) : 0
+ )
+
+ series = [
+ {
+ name: '鍑洪櫌浜烘',
+ type: 'bar',
+ barWidth: '25%',
+ data: dischargeData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '搴旈殢璁夸汉娆�',
+ type: 'bar',
+ barWidth: '25%',
+ data: followUpData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '闅忚鐜�(%)',
+ type: 'line',
+ yAxisIndex: 1,
+ data: followUpRateData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 80,
+ lineStyle: {
+ color: '#EE6666',
+ type: 'dashed'
+ }
+ }
+ ]
+ }
+ },
+ {
+ name: '鍙婃椂鐜�(%)',
+ type: 'line',
+ yAxisIndex: 1,
+ data: timelyRateData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3,
+ type: 'dotted'
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 90,
+ lineStyle: {
+ color: '#9A60B4',
+ type: 'dashed'
+ }
+ }
+ ]
+ }
+ }
+ ]
+ } else if (this.activeTab === 'second') {
+ title = '鍐嶆闅忚'
+ yAxisName1 = '浜烘'
+ legendData = ['鍑洪櫌浜烘', '搴旈殢璁夸汉娆�', '闅忚鐜�(%)']
+ colors = ['#5470C6', '#91CC75', '#EE6666']
+
+ const dischargeData = this.data.map((item) => item.dischargeCount || 0)
+ const followUpData = this.data.map((item) => item.followUpNeeded || 0)
+ const followUpRateAgainData = this.data.map((item) => {
+ if (!item.followUpRateAgain) return 0
+ const rateStr = String(item.followUpRateAgain).replace('%', '')
+ return parseFloat(rateStr) || 0
+ })
+
+ series = [
+ {
+ name: '鍑洪櫌浜烘',
+ type: 'bar',
+ barWidth: '25%',
+ data: dischargeData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '搴旈殢璁夸汉娆�',
+ type: 'bar',
+ barWidth: '25%',
+ data: followUpData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '闅忚鐜�(%)',
+ type: 'line',
+ yAxisIndex: 1,
+ data: followUpRateAgainData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 80,
+ lineStyle: {
+ color: '#EE6666',
+ type: 'dashed'
+ }
+ }
+ ]
+ }
+ }
+ ]
+ } else if (this.activeTab === 'continued') {
+ title = '寤剁画鎶ょ悊'
+ yAxisName1 = '浜烘'
+ legendData = ['寤剁画鎶ょ悊浜烘', '鎶ょ悊瀹屾垚', '瀹屾垚鐜�(%)']
+ colors = ['#5470C6', '#91CC75', '#EE6666']
+
+ const continuedCareData = this.data.map((item) => item.continuedCareCount || 0)
+ const careCompletedData = this.data.map((item) => item.careCompleted || 0)
+ const completionRateData = this.data.map((item) => {
+ if (!item.completionRate) return 0
+ const rateStr = String(item.completionRate).replace('%', '')
+ return parseFloat(rateStr) || 0
+ })
+
+ series = [
+ {
+ name: '寤剁画鎶ょ悊浜烘',
+ type: 'bar',
+ barWidth: '25%',
+ data: continuedCareData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '鎶ょ悊瀹屾垚',
+ type: 'bar',
+ barWidth: '25%',
+ data: careCompletedData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0]
+ }
+ },
+ {
+ name: '瀹屾垚鐜�(%)',
+ type: 'line',
+ yAxisIndex: 1,
+ data: completionRateData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 85,
+ lineStyle: {
+ color: '#EE6666',
+ type: 'dashed'
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+
+ return {
+ title,
+ yAxisName1,
+ categories,
+ legendData,
+ colors,
+ series
+ }
+ },
+
+ resizePieChart() {
+ if (this.pieChart) {
+ this.pieChart.resize()
+ }
+ },
+
+ resizeBarLineChart() {
+ if (this.barLineChart) {
+ this.barLineChart.resize()
+ }
+ },
+
+ destroyCharts() {
+ if (this.pieChart) {
+ this.pieChart.dispose()
+ this.pieChart = null
+ }
+ if (this.barLineChart) {
+ this.barLineChart.dispose()
+ this.barLineChart = null
+ }
+ window.removeEventListener('resize', this.resizePieChart)
+ window.removeEventListener('resize', this.resizeBarLineChart)
+ },
+
+ handleClose() {
+ this.destroyCharts()
+ this.$emit('close')
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.chart-container {
+ .chart-title {
+ text-align: center;
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 20px;
+ color: #333;
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/ContinuedCare.vue b/src/views/sfstatistics/percentage/components/ContinuedCare.vue
new file mode 100644
index 0000000..2cf6f31
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/ContinuedCare.vue
@@ -0,0 +1,633 @@
+<template>
+ <div class="continued-care">
+ <div class="your-table-container">
+ <el-table
+ v-loading="loading"
+ :data="tableData"
+ :border="true"
+ show-summary
+ :summary-method="getSummaries"
+ >
+ <!-- 琛ㄦ牸鍒楀畾涔� -->
+ <el-table-column
+ label="搴忓彿"
+ type="index"
+ align="center"
+ width="60"
+ />
+
+ <el-table-column
+ label="鐥呭尯鍚嶇О"
+ align="center"
+ prop="wardName"
+ width="200"
+ :show-overflow-tooltip="true"
+ />
+
+ <el-table-column
+ label="宸插欢缁暟閲�"
+ align="center"
+ prop="continuedCount"
+ >
+ <template slot-scope="scope">
+ <el-button
+ size="medium"
+ type="text"
+ @click="handleViewDetails(scope.row, 'continued', '宸插欢缁垪琛�')"
+ >
+ <span class="button-zx">{{ scope.row.continuedCount }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ label="鏈欢缁暟閲�"
+ align="center"
+ prop="unContinuedCount"
+ >
+ <template slot-scope="scope">
+ <el-button
+ size="medium"
+ type="text"
+ @click="handleViewDetails(scope.row, 'uncontinued', '鏈欢缁垪琛�')"
+ >
+ <span class="button-zx">{{ scope.row.unContinuedCount }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ label="寤剁画鐜�"
+ align="center"
+ prop="continuedRate"
+ width="120"
+ />
+
+ <!-- <el-table-column
+ label="鎿嶄綔"
+ align="center"
+ width="150"
+ >
+ <template slot-scope="scope">
+ <el-button
+ size="small"
+ type="primary"
+ @click="handleRowClick(scope.row)"
+ >
+ 鏌ョ湅鎶ゅ+璇︽儏
+ </el-button>
+ </template>
+ </el-table-column> -->
+ </el-table>
+ </div>
+
+ <!-- 鎶ゅ+璇︽儏寮圭獥 -->
+ <el-dialog
+ title="鎶ゅ+寤剁画鎶ょ悊璇︽儏"
+ :visible.sync="nurseDialogVisible"
+ width="80%"
+ :close-on-click-modal="false"
+ >
+ <div v-if="currentWardData">
+ <el-table
+ v-loading="nurseLoading"
+ :data="nurseData"
+ :border="true"
+ >
+ <el-table-column
+ label="鎶ゅ+濮撳悕"
+ prop="nurseName"
+ align="center"
+ width="120"
+ />
+ <el-table-column
+ label="绉戝"
+ prop="deptName"
+ align="center"
+ width="150"
+ />
+ <el-table-column
+ label="宸插欢缁暟閲�"
+ prop="continuedCount"
+ align="center"
+ />
+ <el-table-column
+ label="鏈欢缁暟閲�"
+ prop="unContinuedCount"
+ align="center"
+ />
+ <el-table-column
+ label="寤剁画鐜�"
+ prop="continuedRate"
+ align="center"
+ width="120"
+ />
+ </el-table>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getContinueNerseCount, getNurseContinuedDetail } from "@/api/system/user";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
+
+export default {
+ name: "ContinuedCare",
+ props: {
+ queryParams: {
+ type: Object,
+ required: true,
+ },
+ flatArrayhospit: {
+ type: Array,
+ default: () => [],
+ },
+ flatArraydept: {
+ type: Array,
+ default: () => [],
+ },
+ options: {
+ type: Array,
+ default: () => [],
+ },
+ orgname: {
+ type: String,
+ default: "",
+ },
+ },
+ data() {
+ return {
+ tableData: [],
+ loading: false,
+ nurseDialogVisible: false,
+ nurseLoading: false,
+ currentWardData: null,
+ nurseData: [],
+ originalData: {},
+ totalData: {
+ continued: 0,
+ uncontinued: 0
+ }
+ };
+ },
+ methods: {
+ loadData() {
+ this.loading = true;
+
+ const params = {
+ leavehospitaldistrictcodes:
+ this.queryParams.leavehospitaldistrictcodes.includes("all")
+ ? this.getAllWardCodes()
+ : this.queryParams.leavehospitaldistrictcodes,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.getAllDeptCodes()
+ : this.queryParams.deptcodes,
+
+ };
+
+ delete params.leavehospitaldistrictcodes.all;
+ delete params.deptcodes.all;
+
+ getContinueNerseCount(params)
+ .then((response) => {
+ this.originalData = response.data;
+ this.processData(response.data);
+ })
+ .catch((error) => {
+ console.error("鑾峰彇寤剁画鎶ょ悊鏁版嵁澶辫触:", error);
+ this.$message.error("鑾峰彇寤剁画鎶ょ悊鏁版嵁澶辫触");
+ })
+ .finally(() => {
+ this.loading = false;
+ });
+ },
+
+ processData(data) {
+ this.totalData = {
+ continued: data.宸插欢缁�绘暟閲� || 0,
+ uncontinued: data.鏈欢缁�绘暟閲� || 0
+ };
+
+ const processedData = [];
+
+ if (data.璇︽儏 && Array.isArray(data.璇︽儏)) {
+ data.璇︽儏.forEach((item) => {
+ // 鎻愬彇鐥呭尯鍚嶇О鍜屾暟鎹�
+ Object.keys(item).forEach(key => {
+ if (key.startsWith('宸插欢缁璤')) {
+ const wardName = key.replace('宸插欢缁璤', '');
+ const continuedCount = item[key];
+ const unContinuedCount = item[`鏈欢缁璤${wardName}`] || 0;
+ const total = continuedCount + unContinuedCount;
+ const continuedRate = total > 0 ? ((continuedCount / total) * 100).toFixed(2) + '%' : '0.00%';
+
+ processedData.push({
+ wardName,
+ continuedCount,
+ unContinuedCount,
+ continuedRate,
+ originalData: item
+ });
+ }
+ });
+ });
+ }
+
+ // 鎺掑簭
+ this.tableData = this.customSort(processedData);
+ },
+
+ getAllWardCodes() {
+ return this.flatArrayhospit
+ .filter((item) => item.value !== "all")
+ .map((item) => item.value);
+ },
+
+ getAllDeptCodes() {
+ return this.flatArraydept
+ .filter((item) => item.value !== "all")
+ .map((item) => item.value);
+ },
+
+ customSort(data) {
+ const order = [
+ "涓�", "浜�", "涓�", "鍥�", "浜�", "鍏�", "涓�", "鍏�", "涔�", "鍗�",
+ "鍗佷竴", "鍗佷簩", "鍗佷笁", "鍗佸洓", "鍗佷簲", "鍗佸叚", "鍗佷竷", "鍗佸叓", "鍗佷節", "浜屽崄",
+ "浜屽崄涓�", "浜屽崄浜�", "浜屽崄涓�", "浜屽崄鍥�", "浜屽崄浜�", "浜屽崄鍏�", "浜屽崄涓�", "浜屽崄鍏�", "浜屽崄涔�", "涓夊崄",
+ "涓夊崄涓�", "涓夊崄浜�", "涓夊崄涓�", "涓夊崄鍥�", "涓夊崄浜�", "涓夊崄鍏�", "涓夊崄涓�", "涓夊崄鍏�", "涓夊崄涔�", "鍥涘崄",
+ "鍥涘崄涓�", "鍥涘崄浜�", "鍥涘崄涓�", "鍥涘崄鍥�", "鍥涘崄浜�"
+ ];
+
+ return data.sort((a, b) => {
+ const getIndex = (name) => {
+ if (!name || typeof name !== "string") return -1;
+ const chineseMatch = name.match(/^(\d+)-/);
+ if (chineseMatch && chineseMatch[1]) {
+ const num = parseInt(chineseMatch[1], 10);
+ if (num >= 1 && num <= 45) {
+ return num - 1;
+ }
+ }
+
+ // 灏濊瘯鍖归厤涓枃鏁板瓧
+ for (let i = 0; i < order.length; i++) {
+ if (name.includes(order[i])) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ const indexA = getIndex(a.wardName);
+ const indexB = getIndex(b.wardName);
+
+ if (indexA === -1 && indexB === -1) {
+ return (a.wardName || "").localeCompare(b.wardName || "");
+ }
+ if (indexA === -1) return 1;
+ if (indexB === -1) return -1;
+ return indexA - indexB;
+ });
+ },
+
+ getSummaries(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣";
+ return;
+ }
+
+ if (index === 1) { // 鐥呭尯鍚嶇О鍒�
+ sums[index] = "/";
+ return;
+ }
+
+ if (index === 2) { // 宸插欢缁暟閲忓悎璁�
+ const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
+ sums[index] = this.formatNumber(totalContinued);
+ } else if (index === 3) { // 鏈欢缁暟閲忓悎璁�
+ const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
+ sums[index] = this.formatNumber(totalUnContinued);
+ } else if (index === 4) { // 寤剁画鐜囧钩鍧囧��
+ const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
+ const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
+ const total = totalContinued + totalUnContinued;
+ const avgRate = total > 0 ? ((totalContinued / total) * 100).toFixed(2) + '%' : '0.00%';
+ sums[index] = avgRate;
+ } else {
+ sums[index] = "";
+ }
+ });
+
+ return sums;
+ },
+
+ formatNumber(num) {
+ if (isNaN(num)) return "-";
+ return Number.isInteger(num) ? num.toString() : num.toFixed(0);
+ },
+
+ handleViewDetails(row, type, titleSuffix) {
+ const title = `${row.wardName}${titleSuffix}`;
+ // 杩欓噷闇�瑕佹牴鎹綘鐨勫疄闄呮儏鍐佃幏鍙栬鎯呮暟鎹�
+ // 浣犲彲浠ヤ粠row.originalData涓幏鍙栵紝鎴栬�呰皟鐢ㄦ柊鐨凙PI
+ const detailData = this.getMockDetailData(row, type);
+ this.$emit("view-details", detailData, title);
+ },
+
+ handleRowClick(row) {
+ this.currentWardData = row;
+ this.nurseDialogVisible = true;
+ this.loadNurseData(row.wardName);
+ },
+
+ async loadNurseData(wardName) {
+ this.nurseLoading = true;
+ try {
+ const params = {
+ wardName: wardName,
+ startTime: this.queryParams.startTime,
+ endTime: this.queryParams.endTime
+ };
+
+ const response = await getNurseContinuedDetail(params);
+ this.nurseData = this.processNurseData(response.data);
+ } catch (error) {
+ console.error("鑾峰彇鎶ゅ+璇︽儏澶辫触:", error);
+ this.$message.error("鑾峰彇鎶ゅ+璇︽儏澶辫触");
+ } finally {
+ this.nurseLoading = false;
+ }
+ },
+
+ processNurseData(data) {
+ // 鏍规嵁浣犵殑瀹為檯API鍝嶅簲缁撴瀯澶勭悊鏁版嵁
+ // 杩欓噷鏄竴涓ず渚�
+ return [
+ {
+ nurseName: "鎶ゅ+A",
+ deptName: this.currentWardData.wardName,
+ continuedCount: Math.floor(this.currentWardData.continuedCount * 0.3),
+ unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.3),
+ continuedRate: "75.00%"
+ },
+ {
+ nurseName: "鎶ゅ+B",
+ deptName: this.currentWardData.wardName,
+ continuedCount: Math.floor(this.currentWardData.continuedCount * 0.4),
+ unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.4),
+ continuedRate: "80.00%"
+ },
+ {
+ nurseName: "鎶ゅ+C",
+ deptName: this.currentWardData.wardName,
+ continuedCount: Math.floor(this.currentWardData.continuedCount * 0.3),
+ unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.3),
+ continuedRate: "70.00%"
+ }
+ ];
+ },
+
+ getMockDetailData(row, type) {
+ // 妯℃嫙璇︽儏鏁版嵁锛屽疄闄呭簲璇ヨ皟鐢ˋPI
+ const detailData = [];
+ const count = type === 'continued' ? row.continuedCount : row.unContinuedCount;
+
+ for (let i = 1; i <= Math.min(count, 10); i++) {
+ detailData.push({
+ sendname: `鎮h��${i}`,
+ taskName: `${row.wardName}寤剁画鎶ょ悊`,
+ sendstate: type === 'continued' ? 6 : 2,
+ preachform: ["浜哄伐闅忚", "鐢佃瘽闅忚"],
+ visitTime: "2024-01-15 10:00:00",
+ finishtime: type === 'continued' ? "2024-01-15 11:00:00" : "",
+ endtime: "2024-01-10 09:00:00",
+ nurseName: "鎶ゅ+A",
+ drname: "鍖荤敓A",
+ excep: 1,
+ suggest: 2,
+ templatename: "寤剁画鎶ょ悊鏈嶅姟妯℃澘",
+ remark: type === 'continued' ? "宸插畬鎴愬欢缁姢鐞�" : "鏈紑濮嬪欢缁姢鐞�",
+ bankcardno: "宸插畬鎴�"
+ });
+ }
+
+ return detailData;
+ },
+
+ async exportTable() {
+ try {
+ let dateRangeString = "";
+ let sheetNameSuffix = "";
+
+ if (
+ this.queryParams.dateRange &&
+ this.queryParams.dateRange.length === 2
+ ) {
+ const startDateStr = this.queryParams.dateRange[0];
+ const endDateStr = this.queryParams.dateRange[1];
+ const formatDateForDisplay = (dateTimeStr) => {
+ return dateTimeStr.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;
+ dateRangeString = `${currentMonth}鏈坄;
+ sheetNameSuffix = `${currentMonth}鏈坄;
+ }
+
+ const excelName = `寤剁画鎶ょ悊缁熻琛╛${dateRangeString}.xlsx`;
+ const worksheetName = `寤剁画鎶ょ悊缁熻_${sheetNameSuffix}`;
+
+ if (!this.tableData || this.tableData.length === 0) {
+ this.$message.warning("鏆傛棤寤剁画鎶ょ悊鏁版嵁鍙鍑�");
+ return false;
+ }
+
+ const workbook = new ExcelJS.Workbook();
+ const worksheet = workbook.addWorksheet(worksheetName);
+
+ this.buildExportSheet(worksheet, sheetNameSuffix);
+
+ const buffer = await workbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ saveAs(blob, excelName);
+
+ this.$message.success("瀵煎嚭鎴愬姛");
+ return true;
+ } catch (error) {
+ console.error("瀵煎嚭澶辫触:", error);
+ this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+ return false;
+ }
+ },
+
+ buildExportSheet(worksheet, sheetNameSuffix) {
+ 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" } },
+ },
+ };
+
+ const summaryStyle = {
+ font: {
+ name: "瀹嬩綋",
+ size: 10,
+ bold: true,
+ color: { argb: "FF409EFF" },
+ },
+ fill: {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "FFF5F7FA" },
+ },
+ 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, 6);
+ const titleCell = worksheet.getCell(1, 1);
+ titleCell.value = `寤剁画鎶ょ悊缁熻琛╛${sheetNameSuffix}`;
+ titleCell.style = titleStyle;
+ worksheet.getRow(1).height = 35;
+
+ // 琛ㄥご
+ const headers = ["搴忓彿", "鐥呭尯鍚嶇О", "宸插欢缁暟閲�", "鏈欢缁暟閲�", "寤剁画鐜�", "鎿嶄綔"];
+
+ headers.forEach((header, index) => {
+ const cell = worksheet.getCell(2, index + 1);
+ cell.value = header;
+ cell.style = headerStyle;
+ });
+
+ worksheet.getRow(2).height = 25;
+
+ // 鏁版嵁琛�
+ this.tableData.forEach((item, rowIndex) => {
+ const dataRow = worksheet.addRow(
+ [
+ rowIndex + 1,
+ item.wardName,
+ item.continuedCount,
+ item.unContinuedCount,
+ item.continuedRate,
+ "鏌ョ湅鎶ゅ+璇︽儏"
+ ],
+ rowIndex + 3
+ );
+
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle;
+ });
+ dataRow.height = 24;
+ });
+
+ // 鍚堣琛�
+ const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
+ const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
+ const total = totalContinued + totalUnContinued;
+ const totalRate = total > 0 ? ((totalContinued / total) * 100).toFixed(2) + '%' : '0.00%';
+
+ const summaryRow = worksheet.addRow([
+ "鍚堣",
+ "/",
+ totalContinued,
+ totalUnContinued,
+ totalRate,
+ "/"
+ ]);
+
+ summaryRow.eachCell((cell, colNumber) => {
+ cell.style = summaryStyle;
+ });
+ summaryRow.height = 28;
+
+ // 鍒楀
+ worksheet.columns = [
+ { width: 8 },
+ { width: 30 },
+ { width: 15 },
+ { width: 15 },
+ { width: 12 },
+ { width: 15 }
+ ];
+ }
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+.continued-care {
+ .your-table-container {
+ margin-top: 10px;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/DetailDialog.vue b/src/views/sfstatistics/percentage/components/DetailDialog.vue
new file mode 100644
index 0000000..2209b13
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/DetailDialog.vue
@@ -0,0 +1,302 @@
+<template>
+ <el-dialog
+ :title="title"
+ :visible.sync="visible"
+ v-loading="loading"
+ width="70%"
+ :close-on-click-modal="false"
+ @close="handleClose"
+ >
+ <div class="detail-dialog">
+ <div style="margin-bottom: 16px; display: flex; align-items: center">
+ <span style="margin-right: 10px; font-weight: bold">鎮h�呭鍚嶆煡璇�:</span>
+ <el-input
+ v-model="searchName"
+ placeholder="璇疯緭鍏ユ偅鑰呭鍚嶈繘琛岀瓫閫�"
+ clearable
+ style="width: 300px"
+ @input="handleSearch"
+ @clear="handleSearch"
+ />
+ <span style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px">
+ 鍏� {{ displayList.length }} 鏉¤褰�
+ </span>
+ </div>
+
+ <div class="examine-jic">
+ <div class="jic-value">
+ <el-row :gutter="20">
+ <div class="data-list" ref="dataList" @scroll="handleScroll" v-loading="loading">
+ <el-table :data="currentDisplayList" height="660" style="width: 100%">
+ <el-table-column prop="sendname" align="center" label="濮撳悕" width="100" />
+ <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="浠诲姟鍚嶇О" />
+
+ <el-table-column prop="sendstate" align="center" width="200" label="浠诲姟鐘舵��">
+ <template slot-scope="scope">
+ <el-tag
+ :type="getStateTagType(scope.row.sendstate)"
+ :disable-transitions="false"
+ >
+ {{ getStateText(scope.row.sendstate) }}
+ </el-tag>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ label="浠诲姟鎵ц鏂瑰紡"
+ align="center"
+ key="preachform"
+ prop="preachform"
+ width="160"
+ :show-overflow-tooltip="true"
+ >
+ <template slot-scope="scope">
+ <span v-for="(item, index) in scope.row.preachform" :key="index">
+ {{ item }}{{ index < scope.row.preachform.length - 1 ? '銆�' : '' }}
+ </span>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ prop="visitTime"
+ align="center"
+ label="搴旈殢璁挎椂闂�"
+ width="200"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ prop="finishtime"
+ align="center"
+ label="闅忚瀹屾垚鏃堕棿"
+ width="200"
+ show-overflow-tooltip
+ />
+ <el-table-column label="鍑洪櫌鏃ユ湡" width="200" align="center" key="endtime" prop="endtime">
+ <template slot-scope="scope">
+ <span>{{ formatTime(scope.row.endtime) }}</span>
+ </template>
+ </el-table-column>
+
+ <el-table-column label="璐d换鎶ゅ+" width="120" align="center" key="nurseName" prop="nurseName" />
+ <el-table-column label="涓绘不鍖荤敓" width="120" align="center" key="drname" prop="drname" />
+
+ <el-table-column label="缁撴灉鐘舵��" align="center" key="excep" prop="excep" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
+ </template>
+ </el-table-column>
+
+ <el-table-column label="澶勭悊鎰忚" align="center" key="suggest" prop="suggest" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="templatename" align="center" label="鏈嶅姟妯℃澘" width="200" show-overflow-tooltip />
+ <el-table-column prop="remark" align="center" label="鏈嶅姟璁板綍" width="200" show-overflow-tooltip />
+
+ <el-table-column prop="bankcardno" align="center" label="鍛煎彨鐘舵��" width="210" />
+
+ <el-table-column label="鎿嶄綔" fixed="right" align="center" width="200" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleDetailsGo(scope.row)">
+ <span class="button-zx">
+ <i class="el-icon-s-order"></i>鏌ョ湅
+ </span>
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-row>
+ </div>
+ </div>
+ </div>
+ </el-dialog>
+</template>
+
+<script>
+export default {
+ name: 'DetailDialog',
+ dicts: ['sys_yujing', 'sys_suggest'],
+ props: {
+ visible: {
+ type: Boolean,
+ default: false
+ },
+ title: {
+ type: String,
+ default: ''
+ },
+ data: {
+ type: Array,
+ default: () => []
+ },
+ searchName: {
+ type: String,
+ default: ''
+ },
+ loading: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data() {
+ return {
+ localSearchName: '',
+ displayList: [],
+ currentDisplayList: [],
+ loadIndex: 0,
+ pageSize: 100,
+ isLoading: false
+ }
+ },
+ watch: {
+ data: {
+ immediate: true,
+ handler(newData) {
+ this.initializeData(newData)
+ }
+ },
+ searchName(newVal) {
+ this.localSearchName = newVal
+ this.handleSearch()
+ }
+ },
+ mounted() {
+ if (this.data && this.data.length > 0) {
+ this.initializeData(this.data)
+ }
+ },
+ methods: {
+ initializeData(data) {
+ this.displayList = [...data]
+ this.formatPreachformData()
+ this.loadIndex = 0
+ this.currentDisplayList = []
+ this.$nextTick(() => {
+ this.loadMoreData()
+ })
+ },
+
+ formatPreachformData() {
+ this.displayList.forEach((item) => {
+ if (item.preachform) {
+ if (item.endtime) {
+ item.preachformson = item.preachform
+ const idArray = item.preachform.split(',')
+
+ item.preachform = idArray.map((value) => {
+ const checkboxlist = this.$store.getters.checkboxlist
+ const foundItem = checkboxlist.find((item) => item.value == value)
+ return foundItem ? foundItem.label : null
+ }).filter(label => label !== null)
+ }
+ }
+ })
+ },
+
+ handleSearch() {
+ if (!this.localSearchName.trim()) {
+ this.displayList = [...this.data]
+ this.formatPreachformData()
+ } else {
+ const keyword = this.localSearchName.toLowerCase()
+ this.displayList = this.data.filter((item) => {
+ return item.sendname && item.sendname.toLowerCase().includes(keyword)
+ })
+ this.formatPreachformData()
+ }
+
+ this.loadIndex = 0
+ this.currentDisplayList = []
+ this.$nextTick(() => {
+ this.loadMoreData()
+ })
+
+ this.$emit('search', this.localSearchName)
+ },
+
+ loadMoreData() {
+ if (this.isLoading || this.loadIndex >= this.displayList.length) return
+
+ this.isLoading = true
+
+ setTimeout(() => {
+ const nextChunk = this.displayList.slice(
+ this.loadIndex,
+ this.loadIndex + this.pageSize
+ )
+ this.currentDisplayList = this.currentDisplayList.concat(nextChunk)
+ this.loadIndex += this.pageSize
+ this.isLoading = false
+ }, 200)
+ },
+
+ handleScroll(event) {
+ const scrollContainer = event.target
+ const isAtBottom =
+ scrollContainer.scrollTop + scrollContainer.clientHeight >=
+ scrollContainer.scrollHeight - 10
+
+ if (
+ isAtBottom &&
+ !this.isLoading &&
+ this.loadIndex < this.displayList.length
+ ) {
+ this.loadMoreData()
+ }
+ },
+
+ getStateTagType(state) {
+ const stateMap = {
+ 1: 'primary', // 琛ㄥ崟宸查鍙�
+ 2: 'primary', // 寰呴殢璁�
+ 3: 'success', // 琛ㄥ崟宸插彂閫�
+ 4: 'info', // 涓嶆墽琛�
+ 5: 'danger', // 鍙戦�佸け璐�
+ 6: 'success' // 宸插畬鎴�
+ }
+ return stateMap[state] || 'info'
+ },
+
+ getStateText(state) {
+ const stateTextMap = {
+ 1: '琛ㄥ崟宸查鍙�',
+ 2: '寰呴殢璁�',
+ 3: '琛ㄥ崟宸插彂閫�',
+ 4: '涓嶆墽琛�',
+ 5: '鍙戦�佸け璐�',
+ 6: '宸插畬鎴�'
+ }
+ return stateTextMap[state] || '鏈煡鐘舵��'
+ },
+
+ formatTime(time) {
+ if (!time) return ''
+ return this.parseTime(time)
+ },
+
+ handleDetailsGo(row) {
+ this.$emit('details-go', row)
+ },
+
+ handleClose() {
+ this.$emit('close')
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.detail-dialog {
+ .data-list {
+ max-height: 800px;
+ overflow-y: auto;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/FirstFollowUp.vue b/src/views/sfstatistics/percentage/components/FirstFollowUp.vue
new file mode 100644
index 0000000..3b71ece
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/FirstFollowUp.vue
@@ -0,0 +1,728 @@
+<template>
+ <div class="first-follow-up">
+ <div class="your-table-container">
+ <el-table
+ ref="exportTable"
+ id="exportTableid"
+ v-loading="loading"
+ :data="tableData"
+ :border="true"
+ @selection-change="handleSelectionChange"
+ @expand-change="handleRowClick"
+ :row-key="getRowKey"
+ show-summary
+ :summary-method="getSummaries"
+ :expand-row-keys="expands"
+ >
+ <!-- 灞曞紑琛岀澶村垪 -->
+ <el-table-column type="expand">
+ <template slot-scope="props">
+ <el-table
+ :data="props.row.doctorStats"
+ border
+ style="width: 95%; margin: 0 auto"
+ class="inner-table"
+ show-summary
+ :summary-method="getInnerSummaries"
+ >
+ <el-table-column label="鍖荤敓濮撳悕" prop="drname" align="center" />
+ <el-table-column label="绉戝" width="120" prop="deptname" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" prop="dischargeCount" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount" />
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
+
+ <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUp" prop="needFollowUp" />
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUp" prop="pendingFollowUp" />
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccess" prop="followUpSuccess" />
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFail" prop="followUpFail" />
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRate" prop="followUpRate" />
+ <el-table-column v-if="orgname != '涓芥按甯備腑鍖婚櫌'" label="鍙婃椂鐜�" align="center" width="120" key="rate" prop="rate">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleSeeDetails(scope.row)">
+ <span class="button-zx">{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manual" prop="manual" />
+ <el-table-column label="鐭俊" align="center" key="sms" prop="sms" />
+ <el-table-column label="寰俊" align="center" key="weChat" prop="weChat" />
+ </el-table-column>
+ </el-table>
+ </template>
+ </el-table-column>
+
+ <!-- 琛ㄦ牸鍒楀畾涔� -->
+ <el-table-column
+ label="鍑洪櫌鐥呭尯"
+ align="center"
+ sortable
+ key="leavehospitaldistrictname"
+ prop="leavehospitaldistrictname"
+ width="150"
+ :show-overflow-tooltip="true"
+ :sort-method="sortChineseNumber"
+ />
+ <el-table-column label="绉戝" align="center" key="deptname" prop="deptname" :show-overflow-tooltip="true" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount" />
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
+
+ <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUp" prop="needFollowUp">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'needFollowUpInfo', '闇�闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.needFollowUp }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUp" prop="pendingFollowUp">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpInfo', '寰呴殢璁垮垪琛�')">
+ <span class="button-zx">{{ scope.row.pendingFollowUp }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccess" prop="followUpSuccess">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'followUpSuccessInfo', '闅忚鎴愬姛鍒楄〃')">
+ <span class="button-zx">{{ scope.row.followUpSuccess }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFail" prop="followUpFail">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'followUpFailInfo', '闅忚澶辫触鍒楄〃')">
+ <span class="button-zx">{{ scope.row.followUpFail }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRate" prop="followUpRate" />
+ <el-table-column v-if="orgname != '涓芥按甯備腑鍖婚櫌'" label="鍙婃椂鐜�" align="center" width="120" key="rate" prop="rate">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleSeeDetails(scope.row)">
+ <span class="button-zx">{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manual" prop="manual">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'manualInfo', '浜哄伐闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.manual }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="sms" prop="sms">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'smsInfo', '鐭俊闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.sms }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChat" prop="weChat">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'weChatInfo', '寰俊闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.weChat }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table-column>
+
+ <!-- 闅忚鎯呭喌鍒楋紙浠呬附姘村競涓尰闄㈡樉绀猴級 -->
+ <el-table-column v-if="orgname == '涓芥按甯備腑鍖婚櫌'" align="center" label="闅忚鎯呭喌">
+ <el-table-column label="姝e父璇煶" align="center" width="100" key="taskSituation1" prop="taskSituation1" />
+ <el-table-column label="鎮h�呮嫆鎺ユ垨鎷掕" align="center" width="100" key="taskSituation2" prop="taskSituation2" />
+ <el-table-column label="闈㈣鎴栬�呮帴璇�" align="center" width="100" key="taskSituation3" prop="taskSituation3" />
+ <el-table-column label="寰俊闅忚" align="center" width="100" key="taskSituation4" prop="taskSituation4" />
+ <el-table-column label="闅忚鐢佃瘽涓嶆纭�" align="center" width="100" key="taskSituation5" prop="taskSituation5" />
+ <el-table-column label="鍏朵粬鎯呭喌涓嶅疁闅忚" align="center" width="100" key="taskSituation6" prop="taskSituation6" />
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getSfStatistics, selectTimelyRate } from "@/api/system/user";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
+
+export default {
+ name: 'FirstFollowUp',
+ props: {
+ queryParams: {
+ type: Object,
+ required: true
+ },
+ flatArrayhospit: {
+ type: Array,
+ default: () => []
+ },
+ flatArraydept: {
+ type: Array,
+ default: () => []
+ },
+ options: {
+ type: Array,
+ default: () => []
+ },
+ orgname: {
+ type: String,
+ default: ''
+ }
+ },
+ data() {
+ return {
+ tableData: [],
+ loading: false,
+ expands: [],
+ ids: []
+ }
+ },
+ methods: {
+ loadData() {
+ this.loading = true
+ const params = {
+ ...this.queryParams,
+ visitCount: 1,
+ leavehospitaldistrictcodes: this.queryParams.leavehospitaldistrictcodes.includes("all")
+ ? this.getAllWardCodes()
+ : this.queryParams.leavehospitaldistrictcodes,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.getAllDeptCodes()
+ : this.queryParams.deptcodes
+ }
+
+ delete params.leavehospitaldistrictcodes.all
+ delete params.deptcodes.all
+
+ getSfStatistics(params)
+ .then(response => {
+ this.tableData = this.customSort(response.data)
+ })
+ .catch(error => {
+ console.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触:", error)
+ this.$message.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触")
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ },
+
+ getAllWardCodes() {
+ return this.flatArrayhospit
+ .filter(item => item.value !== 'all')
+ .map(item => item.value)
+ },
+
+ getAllDeptCodes() {
+ return this.flatArraydept
+ .filter(item => item.value !== 'all')
+ .map(item => item.value)
+ },
+
+ customSort(data) {
+ const order = [
+ "涓�","浜�","涓�","鍥�","浜�","鍏�","涓�","鍏�","涔�","鍗�",
+ "鍗佷竴","鍗佷簩","鍗佷笁","鍗佸洓","鍗佷簲","鍗佸叚","鍗佷竷","鍗佸叓","鍗佷節","浜屽崄",
+ "浜屽崄涓�","浜屽崄浜�","浜屽崄涓�","浜屽崄鍥�","浜屽崄浜�","浜屽崄鍏�","浜屽崄涓�","浜屽崄鍏�","浜屽崄涔�","涓夊崄",
+ "涓夊崄涓�","涓夊崄浜�","涓夊崄涓�","涓夊崄鍥�","涓夊崄浜�","涓夊崄鍏�","涓夊崄涓�","涓夊崄鍏�","涓夊崄涔�","鍥涘崄",
+ "鍥涘崄涓�","鍥涘崄浜�","鍥涘崄涓�","鍥涘崄鍥�","鍥涘崄浜�"
+ ]
+
+ return data.sort((a, b) => {
+ const getIndex = (name) => {
+ if (!name || typeof name !== "string") return -1
+ const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/)
+ if (chineseMatch && chineseMatch[1]) {
+ return order.indexOf(chineseMatch[1])
+ }
+ const arabicMatch = name.match(/^(\d+)/)
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10)
+ if (num >= 1 && num <= 45) {
+ return num - 1
+ }
+ }
+ return -1
+ }
+
+ const indexA = getIndex(a.leavehospitaldistrictname)
+ const indexB = getIndex(b.leavehospitaldistrictname)
+
+ if (indexA === -1 && indexB === -1) {
+ return (a.leavehospitaldistrictname || "").localeCompare(b.leavehospitaldistrictname || "")
+ }
+ if (indexA === -1) return 1
+ if (indexB === -1) return -1
+ return indexA - indexB
+ })
+ },
+
+ sortChineseNumber(aRow, bRow) {
+ const a = aRow.leavehospitaldistrictname
+ const b = bRow.leavehospitaldistrictname
+
+ const chineseNumMap = {
+ 涓�:1,浜�:2,涓�:3,鍥�:4,浜�:5,鍏�:6,涓�:7,鍏�:8,涔�:9,鍗�:10,
+ 鍗佷竴:11,鍗佷簩:12,鍗佷笁:13,鍗佸洓:14,鍗佷簲:15,鍗佸叚:16,鍗佷竷:17,鍗佸叓:18,鍗佷節:19,浜屽崄:20,
+ 浜屽崄涓�:21,浜屽崄浜�:22,浜屽崄涓�:23,浜屽崄鍥�:24,浜屽崄浜�:25,浜屽崄鍏�:26,浜屽崄涓�:27,浜屽崄鍏�:28,浜屽崄涔�:29,涓夊崄:30,
+ 涓夊崄涓�:31,涓夊崄浜�:32,涓夊崄涓�:33,涓夊崄鍥�:34,涓夊崄浜�:35,涓夊崄鍏�:36,涓夊崄涓�:37,涓夊崄鍏�:38,涓夊崄涔�:39,鍥涘崄:40,
+ 鍥涘崄涓�:41,鍥涘崄浜�:42,鍥涘崄涓�:43,鍥涘崄鍥�:44,鍥涘崄浜�:45
+ }
+
+ const getNumberFromText = (text) => {
+ if (!text || typeof text !== "string") return -1
+ const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/)
+ if (match && match[1]) {
+ const chineseNum = match[1]
+ return chineseNumMap[chineseNum] !== undefined ? chineseNumMap[chineseNum] : -1
+ }
+ const arabicMatch = text.match(/^(\d+)/)
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10)
+ return num >= 1 && num <= 45 ? num : -1
+ }
+ return -1
+ }
+
+ const numA = getNumberFromText(a)
+ const numB = getNumberFromText(b)
+
+ if (numA === -1 && numB === -1) {
+ return (a || "").localeCompare(b || "")
+ }
+ if (numA === -1) return 1
+ if (numB === -1) return -1
+ return numA - numB
+ },
+
+ getRowKey(row) {
+ return row.statisticaltype === 1 ? row.leavehospitaldistrictcode : row.deptcode
+ },
+
+ handleRowClick(row) {
+ if (this.expands.includes(this.getRowKey(row))) {
+ this.expands = []
+ return
+ }
+
+ const params = {
+ ...this.queryParams,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.getAllDeptCodes()
+ : this.queryParams.deptcodes,
+ leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
+ drcode: "1",
+ visitCount: 1
+ }
+
+ delete params.leavehospitaldistrictcodes.all
+ delete params.deptcodes.all
+
+ 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)]
+ }
+ },
+
+ getSummaries(param) {
+ const { columns, data } = param
+ const sums = []
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣"
+ return
+ }
+ if (index === 1 || index === 2) {
+ sums[index] = "/"
+ return
+ }
+
+ if (column.property === "followUpRate" || column.property === "rate") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property]
+ if (!value || value === "-" || value === "0%") return null
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100
+ return isNaN(numValue) ? null : numValue
+ } else {
+ const numValue = parseFloat(value)
+ return isNaN(numValue) ? null : numValue
+ }
+ })
+ .filter((value) => value !== null && value !== 0)
+
+ if (percentageValues.length > 0) {
+ const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
+ sums[index] = (average * 100).toFixed(2) + "%"
+ } else {
+ sums[index] = "0.00%"
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property]
+ if (value === "-" || value === "" || value === null) return 0
+ return Number(value) || 0
+ })
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0)
+ sums[index] = this.formatNumber(sums[index])
+ } else {
+ sums[index] = "-"
+ }
+ }
+ })
+
+ return sums
+ },
+
+ getInnerSummaries(param) {
+ const { columns, data } = param
+ const sums = []
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "灏忚"
+ return
+ }
+
+ if (column.property === "drname" || column.property === "deptname") {
+ sums[index] = "-"
+ return
+ }
+
+ if (column.property === "followUpRate" || column.property === "rate") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property]
+ if (!value || value === "-" || value === "0%") return null
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100
+ return isNaN(numValue) ? null : numValue
+ } else {
+ const numValue = parseFloat(value)
+ return isNaN(numValue) ? null : numValue
+ }
+ })
+ .filter((value) => value !== null && value !== 0)
+
+ if (percentageValues.length > 0) {
+ const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
+ sums[index] = (average * 100).toFixed(2) + "%"
+ } else {
+ sums[index] = "0.00%"
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property]
+ if (value === "-" || value === "" || value === null) return 0
+ return Number(value) || 0
+ })
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0)
+ sums[index] = this.formatNumber(sums[index])
+ } else {
+ sums[index] = "-"
+ }
+ }
+ })
+
+ return sums
+ },
+
+ formatNumber(num) {
+ if (isNaN(num)) return "-"
+ return Number.isInteger(num) ? num.toString() : num.toFixed(0)
+ },
+
+ handleSelectionChange(selection) {
+ this.ids = selection.map((item) => item.tagid)
+ },
+
+ handleViewDetails(row, infoKey, titleSuffix) {
+ const title = `${row.leavehospitaldistrictname || row.deptname}${titleSuffix}`
+ this.$emit('view-details', row[infoKey], title)
+ },
+
+ handleSeeDetails(row) {
+ this.$emit('see-details', row)
+ },
+
+ async exportTable() {
+ try {
+ let dateRangeString = ""
+ let sheetNameSuffix = ""
+
+ if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
+ const startDateStr = this.queryParams.dateRange[0]
+ const endDateStr = this.queryParams.dateRange[1]
+ const formatDateForDisplay = (dateTimeStr) => {
+ return dateTimeStr.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
+ dateRangeString = `${currentMonth}鏈坄
+ sheetNameSuffix = `${currentMonth}鏈坄
+ }
+
+ const excelName = `棣栨鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`
+ const worksheetName = `棣栨闅忚缁熻_${sheetNameSuffix}`
+
+ if (!this.tableData || this.tableData.length === 0) {
+ this.$message.warning("鏆傛棤棣栨闅忚鏁版嵁鍙鍑�")
+ return false
+ }
+
+ const workbook = new ExcelJS.Workbook()
+ const worksheet = workbook.addWorksheet(worksheetName)
+
+ // 鏋勫缓琛ㄦ牸
+ this.buildExportSheet(worksheet, sheetNameSuffix)
+
+ const buffer = await workbook.xlsx.writeBuffer()
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ })
+ saveAs(blob, excelName)
+
+ this.$message.success("瀵煎嚭鎴愬姛")
+ return true
+ } catch (error) {
+ console.error("瀵煎嚭澶辫触:", error)
+ this.$message.error(`瀵煎嚭澶辫触: ${error.message}`)
+ return false
+ }
+ },
+
+ buildExportSheet(worksheet, sheetNameSuffix) {
+ 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" } }
+ }
+ }
+
+ const summaryStyle = {
+ font: { name: "瀹嬩綋", size: 10, bold: true, color: { argb: "FF409EFF" } },
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
+ 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, 16)
+ const titleCell = worksheet.getCell(1, 1)
+ titleCell.value = `棣栨鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`
+ titleCell.style = titleStyle
+ worksheet.getRow(1).height = 35
+
+ // 琛ㄥご
+ const secondRowHeaders = [
+ "", "鍑洪櫌鐥呭尯", "绉戝", "鍑洪櫌浜烘", "鏃犻渶闅忚浜烘", "搴旈殢璁夸汉娆�",
+ "闇�闅忚", "寰呴殢璁�", "闅忚鎴愬姛", "闅忚澶辫触", "闅忚鐜�", "鍙婃椂鐜�", "浜哄伐", "鐭俊", "寰俊"
+ ]
+
+ secondRowHeaders.forEach((header, index) => {
+ const cell = worksheet.getCell(3, index + 1)
+ cell.value = header
+ cell.style = headerStyle
+ })
+
+ // 鍚堝苟鍗曞厓鏍�
+ for (let i = 1; i <= 6; i++) {
+ worksheet.mergeCells(2, i, 3, i)
+ const cell = worksheet.getCell(2, i)
+ cell.style = headerStyle
+ }
+
+ worksheet.getCell(2, 1).value = ""
+ worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯"
+ worksheet.getCell(2, 3).value = "绉戝"
+ worksheet.getCell(2, 4).value = "鍑洪櫌浜烘"
+ worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘"
+ worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�"
+
+ worksheet.mergeCells(2, 7, 2, 15)
+ worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚"
+ worksheet.getCell(2, 7).style = headerStyle
+
+ worksheet.getRow(2).height = 28
+ worksheet.getRow(3).height = 25
+
+ // 鏁版嵁琛�
+ this.tableData.forEach((item, rowIndex) => {
+ const dataRow = worksheet.addRow([
+ "",
+ item.leavehospitaldistrictname || "",
+ item.deptname || "",
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ item.needFollowUp || 0,
+ item.pendingFollowUp || 0,
+ item.followUpSuccess || 0,
+ item.followUpFail || 0,
+ item.followUpRate || "0%",
+ item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
+ item.manual || 0,
+ item.sms || 0,
+ item.weChat || 0
+ ], rowIndex + 4)
+
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle
+ })
+ dataRow.height = 24
+ })
+
+ // 鍚堣琛�
+ const summaries = this.getExportSummaries()
+ const summaryRow = worksheet.addRow(summaries)
+ summaryRow.eachCell((cell, colNumber) => {
+ cell.style = summaryStyle
+ if (colNumber === 1) {
+ cell.value = "鍚堣"
+ }
+ })
+ summaryRow.height = 28
+
+ // 鍒楀
+ worksheet.columns = [
+ { width: 8 }, { width: 20 }, { width: 15 }, { width: 12 }, { width: 12 }, { width: 12 },
+ { width: 10 }, { width: 10 }, { width: 10 }, { width: 10 }, { width: 12 }, { width: 12 },
+ { width: 8 }, { width: 8 }, { width: 8 }
+ ]
+ },
+
+ getExportSummaries() {
+ const summaries = ["鍚堣", "/", "/", 0, 0, 0, 0, 0, 0, 0, "0%", "0%", 0, 0, 0]
+
+ this.tableData.forEach((item) => {
+ summaries[3] += Number(item.dischargeCount) || 0
+ summaries[4] += Number(item.nonFollowUp) || 0
+ summaries[5] += Number(item.followUpNeeded) || 0
+ summaries[6] += Number(item.needFollowUp) || 0
+ summaries[7] += Number(item.pendingFollowUp) || 0
+ summaries[8] += Number(item.followUpSuccess) || 0
+ summaries[9] += Number(item.followUpFail) || 0
+ summaries[12] += Number(item.manual) || 0
+ summaries[13] += Number(item.sms) || 0
+ summaries[14] += Number(item.weChat) || 0
+ })
+
+ const followUpRateValues = this.tableData
+ .map((item) => this.extractPercentageValue(item.followUpRate))
+ .filter((value) => value !== null)
+
+ const rateValues = this.tableData
+ .map((item) => this.extractPercentageValue(item.rate))
+ .filter((value) => value !== null)
+
+ if (followUpRateValues.length > 0) {
+ const avgFollowUpRate = followUpRateValues.reduce((sum, val) => sum + val, 0) / followUpRateValues.length
+ summaries[10] = (avgFollowUpRate * 100).toFixed(2) + "%"
+ }
+
+ if (rateValues.length > 0) {
+ const avgRate = rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length
+ summaries[11] = (avgRate * 100).toFixed(2) + "%"
+ }
+
+ summaries[3] = this.formatNumber(summaries[3])
+ summaries[4] = this.formatNumber(summaries[4])
+ summaries[5] = this.formatNumber(summaries[5])
+ summaries[6] = this.formatNumber(summaries[6])
+ summaries[7] = this.formatNumber(summaries[7])
+ summaries[8] = this.formatNumber(summaries[8])
+ summaries[9] = this.formatNumber(summaries[9])
+ summaries[12] = this.formatNumber(summaries[12])
+ summaries[13] = this.formatNumber(summaries[13])
+ summaries[14] = this.formatNumber(summaries[14])
+
+ return summaries
+ },
+
+ extractPercentageValue(value) {
+ if (!value) return null
+ if (typeof value === "string" && value.includes("%")) {
+ const num = parseFloat(value.replace("%", ""))
+ return isNaN(num) ? null : num / 100
+ }
+ const num = parseFloat(value)
+ return isNaN(num) ? null : num
+ },
+
+ selectTimelyRate(row, dateRange) {
+ const params = {
+ ...this.patientqueryParams,
+ starttime: this.parseTime(dateRange[0]),
+ endtime: this.parseTime(dateRange[1]),
+ deptcode: row.deptcode
+ }
+ return selectTimelyRate(params)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.first-follow-up {
+ .your-table-container {
+ margin-top: 10px;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/SecondFollowUp.vue b/src/views/sfstatistics/percentage/components/SecondFollowUp.vue
new file mode 100644
index 0000000..703b5c2
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/SecondFollowUp.vue
@@ -0,0 +1,679 @@
+<template>
+ <div class="second-follow-up">
+ <div class="your-table-container">
+ <el-table
+ ref="exportTableSecond"
+ id="exportTableidSecond"
+ v-loading="loading"
+ :data="tableData"
+ :border="true"
+ @selection-change="handleSelectionChange"
+ @expand-change="handleRowClick"
+ :row-key="getRowKey"
+ show-summary
+ :summary-method="getSummaries"
+ :expand-row-keys="expands"
+ >
+ <!-- 灞曞紑琛岀澶村垪 -->
+ <el-table-column type="expand">
+ <template slot-scope="props">
+ <el-table
+ :data="props.row.doctorStats"
+ border
+ style="width: 95%; margin: 0 auto"
+ class="inner-table"
+ show-summary
+ :summary-method="getInnerSummaries"
+ >
+ <el-table-column label="鍖荤敓濮撳悕" prop="drname" align="center" />
+ <el-table-column label="绉戝" width="120" prop="deptname" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" prop="dischargeCount" align="center" />
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
+
+ <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUpAgain" prop="needFollowUpAgain" />
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUpAgain" prop="pendingFollowUpAgain" />
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccessAgain" prop="followUpSuccessAgain" />
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFailAgain" prop="followUpFailAgain" />
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRateAgain" prop="followUpRateAgain" />
+ <el-table-column label="浜哄伐" align="center" key="manualAgain" prop="manualAgain" />
+ <el-table-column label="鐭俊" align="center" key="smsAgain" prop="smsAgain" />
+ <el-table-column label="寰俊" align="center" key="weChatAgain" prop="weChatAgain" />
+ </el-table-column>
+ </el-table>
+ </template>
+ </el-table-column>
+
+ <!-- 琛ㄦ牸鍒楀畾涔� -->
+ <el-table-column
+ label="鍑洪櫌鐥呭尯"
+ align="center"
+ sortable
+ key="leavehospitaldistrictname"
+ prop="leavehospitaldistrictname"
+ width="150"
+ :show-overflow-tooltip="true"
+ :sort-method="sortChineseNumber"
+ />
+ <el-table-column label="绉戝" align="center" key="deptname" prop="deptname" :show-overflow-tooltip="true" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount" />
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
+
+ <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUpAgain" prop="needFollowUpAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'needFollowUpAgainInfo', '鍐嶆闅忚闇�闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.needFollowUpAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUpAgain" prop="pendingFollowUpAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpAgainInfo', '鍐嶆闅忚寰呴殢璁垮垪琛�')">
+ <span class="button-zx">{{ scope.row.pendingFollowUpAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccessAgain" prop="followUpSuccessAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'followUpSuccessAgainInfo', '鍐嶆闅忚闅忚鎴愬姛鍒楄〃')">
+ <span class="button-zx">{{ scope.row.followUpSuccessAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFailAgain" prop="followUpFailAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'followUpFailAgainInfo', '鍐嶆闅忚闅忚澶辫触鍒楄〃')">
+ <span class="button-zx">{{ scope.row.followUpFailAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRateAgain" prop="followUpRateAgain" />
+ <el-table-column label="浜哄伐" align="center" key="manualAgain" prop="manualAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'manualAgainInfo', '鍐嶆闅忚浜哄伐闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.manualAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="smsAgain" prop="smsAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'smsAgainInfo', '鍐嶆闅忚鐭俊闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.smsAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChatAgain" prop="weChatAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'weChatAgainInfo', '鍐嶆闅忚寰俊闅忚鍒楄〃')">
+ <span class="button-zx">{{ scope.row.weChatAgain }}</span>
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getSfStatistics } from "@/api/system/user";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
+
+export default {
+ name: 'SecondFollowUp',
+ props: {
+ queryParams: {
+ type: Object,
+ required: true
+ },
+ flatArrayhospit: {
+ type: Array,
+ default: () => []
+ },
+ flatArraydept: {
+ type: Array,
+ default: () => []
+ },
+ options: {
+ type: Array,
+ default: () => []
+ },
+ orgname: {
+ type: String,
+ default: ''
+ }
+ },
+ data() {
+ return {
+ tableData: [],
+ loading: false,
+ expands: [],
+ ids: []
+ }
+ },
+ methods: {
+ loadData() {
+ this.loading = true
+ const params = {
+ ...this.queryParams,
+ visitCount: 2,
+ leavehospitaldistrictcodes: this.queryParams.leavehospitaldistrictcodes.includes("all")
+ ? this.getAllWardCodes()
+ : this.queryParams.leavehospitaldistrictcodes,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.getAllDeptCodes()
+ : this.queryParams.deptcodes
+ }
+
+ delete params.leavehospitaldistrictcodes.all
+ delete params.deptcodes.all
+
+ getSfStatistics(params)
+ .then(response => {
+ this.tableData = this.customSort(response.data)
+ })
+ .catch(error => {
+ console.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触:", error)
+ this.$message.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触")
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ },
+
+ getAllWardCodes() {
+ return this.flatArrayhospit
+ .filter(item => item.value !== 'all')
+ .map(item => item.value)
+ },
+
+ getAllDeptCodes() {
+ return this.flatArraydept
+ .filter(item => item.value !== 'all')
+ .map(item => item.value)
+ },
+
+ customSort(data) {
+ const order = [
+ "涓�","浜�","涓�","鍥�","浜�","鍏�","涓�","鍏�","涔�","鍗�",
+ "鍗佷竴","鍗佷簩","鍗佷笁","鍗佸洓","鍗佷簲","鍗佸叚","鍗佷竷","鍗佸叓","鍗佷節","浜屽崄",
+ "浜屽崄涓�","浜屽崄浜�","浜屽崄涓�","浜屽崄鍥�","浜屽崄浜�","浜屽崄鍏�","浜屽崄涓�","浜屽崄鍏�","浜屽崄涔�","涓夊崄",
+ "涓夊崄涓�","涓夊崄浜�","涓夊崄涓�","涓夊崄鍥�","涓夊崄浜�","涓夊崄鍏�","涓夊崄涓�","涓夊崄鍏�","涓夊崄涔�","鍥涘崄",
+ "鍥涘崄涓�","鍥涘崄浜�","鍥涘崄涓�","鍥涘崄鍥�","鍥涘崄浜�"
+ ]
+
+ return data.sort((a, b) => {
+ const getIndex = (name) => {
+ if (!name || typeof name !== "string") return -1
+ const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/)
+ if (chineseMatch && chineseMatch[1]) {
+ return order.indexOf(chineseMatch[1])
+ }
+ const arabicMatch = name.match(/^(\d+)/)
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10)
+ if (num >= 1 && num <= 45) {
+ return num - 1
+ }
+ }
+ return -1
+ }
+
+ const indexA = getIndex(a.leavehospitaldistrictname)
+ const indexB = getIndex(b.leavehospitaldistrictname)
+
+ if (indexA === -1 && indexB === -1) {
+ return (a.leavehospitaldistrictname || "").localeCompare(b.leavehospitaldistrictname || "")
+ }
+ if (indexA === -1) return 1
+ if (indexB === -1) return -1
+ return indexA - indexB
+ })
+ },
+
+ sortChineseNumber(aRow, bRow) {
+ const a = aRow.leavehospitaldistrictname
+ const b = bRow.leavehospitaldistrictname
+
+ const chineseNumMap = {
+ 涓�:1,浜�:2,涓�:3,鍥�:4,浜�:5,鍏�:6,涓�:7,鍏�:8,涔�:9,鍗�:10,
+ 鍗佷竴:11,鍗佷簩:12,鍗佷笁:13,鍗佸洓:14,鍗佷簲:15,鍗佸叚:16,鍗佷竷:17,鍗佸叓:18,鍗佷節:19,浜屽崄:20,
+ 浜屽崄涓�:21,浜屽崄浜�:22,浜屽崄涓�:23,浜屽崄鍥�:24,浜屽崄浜�:25,浜屽崄鍏�:26,浜屽崄涓�:27,浜屽崄鍏�:28,浜屽崄涔�:29,涓夊崄:30,
+ 涓夊崄涓�:31,涓夊崄浜�:32,涓夊崄涓�:33,涓夊崄鍥�:34,涓夊崄浜�:35,涓夊崄鍏�:36,涓夊崄涓�:37,涓夊崄鍏�:38,涓夊崄涔�:39,鍥涘崄:40,
+ 鍥涘崄涓�:41,鍥涘崄浜�:42,鍥涘崄涓�:43,鍥涘崄鍥�:44,鍥涘崄浜�:45
+ }
+
+ const getNumberFromText = (text) => {
+ if (!text || typeof text !== "string") return -1
+ const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/)
+ if (match && match[1]) {
+ const chineseNum = match[1]
+ return chineseNumMap[chineseNum] !== undefined ? chineseNumMap[chineseNum] : -1
+ }
+ const arabicMatch = text.match(/^(\d+)/)
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10)
+ return num >= 1 && num <= 45 ? num : -1
+ }
+ return -1
+ }
+
+ const numA = getNumberFromText(a)
+ const numB = getNumberFromText(b)
+
+ if (numA === -1 && numB === -1) {
+ return (a || "").localeCompare(b || "")
+ }
+ if (numA === -1) return 1
+ if (numB === -1) return -1
+ return numA - numB
+ },
+
+ getRowKey(row) {
+ return row.statisticaltype === 1 ? row.leavehospitaldistrictcode : row.deptcode
+ },
+
+ handleRowClick(row) {
+ if (this.expands.includes(this.getRowKey(row))) {
+ this.expands = []
+ return
+ }
+
+ const params = {
+ ...this.queryParams,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.getAllDeptCodes()
+ : this.queryParams.deptcodes,
+ leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
+ drcode: "1",
+ visitCount: 2
+ }
+
+ delete params.leavehospitaldistrictcodes.all
+ delete params.deptcodes.all
+
+ 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)]
+ }
+ },
+
+ getSummaries(param) {
+ const { columns, data } = param
+ const sums = []
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣"
+ return
+ }
+ if (index === 1 || index === 2) {
+ sums[index] = "/"
+ return
+ }
+
+ if (column.property === "followUpRateAgain") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property]
+ if (!value || value === "-" || value === "0%") return null
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100
+ return isNaN(numValue) ? null : numValue
+ } else {
+ const numValue = parseFloat(value)
+ return isNaN(numValue) ? null : numValue
+ }
+ })
+ .filter((value) => value !== null && value !== 0)
+
+ if (percentageValues.length > 0) {
+ const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
+ sums[index] = (average * 100).toFixed(2) + "%"
+ } else {
+ sums[index] = "0.00%"
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property]
+ if (value === "-" || value === "" || value === null) return 0
+ return Number(value) || 0
+ })
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0)
+ sums[index] = this.formatNumber(sums[index])
+ } else {
+ sums[index] = "-"
+ }
+ }
+ })
+
+ return sums
+ },
+
+ getInnerSummaries(param) {
+ const { columns, data } = param
+ const sums = []
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "灏忚"
+ return
+ }
+
+ if (column.property === "drname" || column.property === "deptname") {
+ sums[index] = "-"
+ return
+ }
+
+ if (column.property === "followUpRateAgain") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property]
+ if (!value || value === "-" || value === "0%") return null
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100
+ return isNaN(numValue) ? null : numValue
+ } else {
+ const numValue = parseFloat(value)
+ return isNaN(numValue) ? null : numValue
+ }
+ })
+ .filter((value) => value !== null && value !== 0)
+
+ if (percentageValues.length > 0) {
+ const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
+ sums[index] = (average * 100).toFixed(2) + "%"
+ } else {
+ sums[index] = "0.00%"
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property]
+ if (value === "-" || value === "" || value === null) return 0
+ return Number(value) || 0
+ })
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0)
+ sums[index] = this.formatNumber(sums[index])
+ } else {
+ sums[index] = "-"
+ }
+ }
+ })
+
+ return sums
+ },
+
+ formatNumber(num) {
+ if (isNaN(num)) return "-"
+ return Number.isInteger(num) ? num.toString() : num.toFixed(0)
+ },
+
+ handleSelectionChange(selection) {
+ this.ids = selection.map((item) => item.tagid)
+ },
+
+ handleViewDetails(row, infoKey, titleSuffix) {
+ const title = `${row.leavehospitaldistrictname || row.deptname}${titleSuffix}`
+ this.$emit('view-details', row[infoKey], title)
+ },
+
+ async exportTable() {
+ try {
+ let dateRangeString = ""
+ let sheetNameSuffix = ""
+
+ if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
+ const startDateStr = this.queryParams.dateRange[0]
+ const endDateStr = this.queryParams.dateRange[1]
+ const formatDateForDisplay = (dateTimeStr) => {
+ return dateTimeStr.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
+ dateRangeString = `${currentMonth}鏈坄
+ sheetNameSuffix = `${currentMonth}鏈坄
+ }
+
+ const excelName = `鍐嶆鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`
+ const worksheetName = `鍐嶆闅忚缁熻_${sheetNameSuffix}`
+
+ if (!this.tableData || this.tableData.length === 0) {
+ this.$message.warning("鏆傛棤鍐嶆闅忚鏁版嵁鍙鍑�")
+ return false
+ }
+
+ const workbook = new ExcelJS.Workbook()
+ const worksheet = workbook.addWorksheet(worksheetName)
+
+ // 鏋勫缓琛ㄦ牸
+ this.buildExportSheet(worksheet, sheetNameSuffix)
+
+ const buffer = await workbook.xlsx.writeBuffer()
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ })
+ saveAs(blob, excelName)
+
+ this.$message.success("瀵煎嚭鎴愬姛")
+ return true
+ } catch (error) {
+ console.error("瀵煎嚭澶辫触:", error)
+ this.$message.error(`瀵煎嚭澶辫触: ${error.message}`)
+ return false
+ }
+ },
+
+ buildExportSheet(worksheet, sheetNameSuffix) {
+ 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" } }
+ }
+ }
+
+ const summaryStyle = {
+ font: { name: "瀹嬩綋", size: 10, bold: true, color: { argb: "FF409EFF" } },
+ fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
+ 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, 15)
+ const titleCell = worksheet.getCell(1, 1)
+ titleCell.value = `鍐嶆鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`
+ titleCell.style = titleStyle
+ worksheet.getRow(1).height = 35
+
+ // 琛ㄥご
+ const secondRowHeaders = [
+ "", "鍑洪櫌鐥呭尯", "绉戝", "鍑洪櫌浜烘", "鏃犻渶闅忚浜烘", "搴旈殢璁夸汉娆�",
+ "闇�闅忚", "寰呴殢璁�", "闅忚鎴愬姛", "闅忚澶辫触", "闅忚鐜�", "浜哄伐", "鐭俊", "寰俊"
+ ]
+
+ secondRowHeaders.forEach((header, index) => {
+ const cell = worksheet.getCell(3, index + 1)
+ cell.value = header
+ cell.style = headerStyle
+ })
+
+ // 鍚堝苟鍗曞厓鏍�
+ for (let i = 1; i <= 6; i++) {
+ worksheet.mergeCells(2, i, 3, i)
+ const cell = worksheet.getCell(2, i)
+ cell.style = headerStyle
+ }
+
+ worksheet.getCell(2, 1).value = ""
+ worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯"
+ worksheet.getCell(2, 3).value = "绉戝"
+ worksheet.getCell(2, 4).value = "鍑洪櫌浜烘"
+ worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘"
+ worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�"
+
+ worksheet.mergeCells(2, 7, 2, 14)
+ worksheet.getCell(2, 7).value = "鍐嶆鍑洪櫌闅忚"
+ worksheet.getCell(2, 7).style = headerStyle
+
+ worksheet.getRow(2).height = 28
+ worksheet.getRow(3).height = 25
+
+ // 鏁版嵁琛�
+ this.tableData.forEach((item, rowIndex) => {
+ const dataRow = worksheet.addRow([
+ "",
+ item.leavehospitaldistrictname || "",
+ item.deptname || "",
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ item.needFollowUpAgain || 0,
+ item.pendingFollowUpAgain || 0,
+ item.followUpSuccessAgain || 0,
+ item.followUpFailAgain || 0,
+ item.followUpRateAgain || "0%",
+ item.manualAgain || 0,
+ item.smsAgain || 0,
+ item.weChatAgain || 0
+ ], rowIndex + 4)
+
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle
+ })
+ dataRow.height = 24
+ })
+
+ // 鍚堣琛�
+ const summaries = this.getExportSummaries()
+ const summaryRow = worksheet.addRow(summaries)
+ summaryRow.eachCell((cell, colNumber) => {
+ cell.style = summaryStyle
+ if (colNumber === 1) {
+ cell.value = "鍚堣"
+ }
+ })
+ summaryRow.height = 28
+
+ // 鍒楀
+ worksheet.columns = [
+ { width: 8 }, { width: 20 }, { width: 15 }, { width: 12 }, { width: 12 }, { width: 12 },
+ { width: 10 }, { width: 10 }, { width: 10 }, { width: 10 }, { width: 12 },
+ { width: 8 }, { width: 8 }, { width: 8 }
+ ]
+ },
+
+ getExportSummaries() {
+ const summaries = ["鍚堣", "/", "/", 0, 0, 0, 0, 0, 0, 0, "0%", 0, 0, 0]
+
+ this.tableData.forEach((item) => {
+ summaries[3] += Number(item.dischargeCount) || 0
+ summaries[4] += Number(item.nonFollowUp) || 0
+ summaries[5] += Number(item.followUpNeeded) || 0
+ summaries[6] += Number(item.needFollowUpAgain) || 0
+ summaries[7] += Number(item.pendingFollowUpAgain) || 0
+ summaries[8] += Number(item.followUpSuccessAgain) || 0
+ summaries[9] += Number(item.followUpFailAgain) || 0
+ summaries[11] += Number(item.manualAgain) || 0
+ summaries[12] += Number(item.smsAgain) || 0
+ summaries[13] += Number(item.weChatAgain) || 0
+ })
+
+ const followUpRateAgainValues = this.tableData
+ .map((item) => this.extractPercentageValue(item.followUpRateAgain))
+ .filter((value) => value !== null)
+
+ if (followUpRateAgainValues.length > 0) {
+ const avgFollowUpRateAgain = followUpRateAgainValues.reduce((sum, val) => sum + val, 0) / followUpRateAgainValues.length
+ summaries[10] = (avgFollowUpRateAgain * 100).toFixed(2) + "%"
+ }
+
+ summaries[3] = this.formatNumber(summaries[3])
+ summaries[4] = this.formatNumber(summaries[4])
+ summaries[5] = this.formatNumber(summaries[5])
+ summaries[6] = this.formatNumber(summaries[6])
+ summaries[7] = this.formatNumber(summaries[7])
+ summaries[8] = this.formatNumber(summaries[8])
+ summaries[9] = this.formatNumber(summaries[9])
+ summaries[11] = this.formatNumber(summaries[11])
+ summaries[12] = this.formatNumber(summaries[12])
+ summaries[13] = this.formatNumber(summaries[13])
+
+ return summaries
+ },
+
+ extractPercentageValue(value) {
+ if (!value) return null
+ if (typeof value === "string" && value.includes("%")) {
+ const num = parseFloat(value.replace("%", ""))
+ return isNaN(num) ? null : num / 100
+ }
+ const num = parseFloat(value)
+ return isNaN(num) ? null : num
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.second-follow-up {
+ .your-table-container {
+ margin-top: 10px;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/TimelyRateDialog.vue b/src/views/sfstatistics/percentage/components/TimelyRateDialog.vue
new file mode 100644
index 0000000..e3122a4
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/TimelyRateDialog.vue
@@ -0,0 +1,249 @@
+<template>
+ <el-dialog
+ title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�"
+ :visible.sync="visible"
+ v-loading="loading"
+ width="70%"
+ :close-on-click-modal="false"
+ @close="handleClose"
+ >
+ <div class="timely-rate-dialog">
+ <div class="examine-jic">
+ <div class="jic-value">
+ <el-row :gutter="20">
+ <!-- 鎼滅储琛ㄥ崟 -->
+ <el-form
+ :model="queryParams"
+ ref="queryForm"
+ size="small"
+ :inline="true"
+ label-width="98px"
+ class="search-form"
+ >
+ <el-form-item label="鎮h�咃細">
+ <el-input
+ v-model="queryParams.name"
+ placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+ @keyup.enter.native="handleSearch"
+ />
+ </el-form-item>
+ <el-form-item label="鎮h�呰瘖鏂細">
+ <el-input
+ v-model="queryParams.leavediagname"
+ placeholder="璇疯緭鍏ユ偅鑰呰瘖鏂�"
+ @keyup.enter.native="handleSearch"
+ />
+ </el-form-item>
+
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="el-icon-search"
+ size="medium"
+ @click="handleSearch"
+ >
+ 鎼滅储
+ </el-button>
+ <el-button
+ icon="el-icon-refresh"
+ size="medium"
+ @click="resetQuery"
+ >
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 鎮h�呭垪琛� -->
+ <el-table :data="data" style="width: 100%" v-loading="loading">
+ <el-table-column prop="sendname" align="center" label="濮撳悕" width="100" />
+ <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="浠诲姟鍚嶇О" />
+
+ <el-table-column prop="sendstate" align="center" width="200" label="浠诲姟鐘舵��">
+ <template slot-scope="scope">
+ <el-tag
+ :type="getStateTagType(scope.row.sendstate)"
+ :disable-transitions="false"
+ >
+ {{ getStateText(scope.row.sendstate) }}
+ </el-tag>
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="visitTime" align="center" label="搴旈殢璁挎椂闂�" width="200" show-overflow-tooltip />
+ <el-table-column prop="finishtime" align="center" label="闅忚瀹屾垚鏃堕棿" width="200" show-overflow-tooltip />
+
+ <el-table-column label="鍑洪櫌鏃ユ湡" width="200" align="center" key="endtime" prop="endtime">
+ <template slot-scope="scope">
+ <span>{{ formatTime(scope.row.endtime) }}</span>
+ </template>
+ </el-table-column>
+
+ <el-table-column label="璐d换鎶ゅ+" width="120" align="center" key="nurseName" prop="nurseName" />
+ <el-table-column label="涓绘不鍖荤敓" width="120" align="center" key="drname" prop="drname" />
+
+ <el-table-column label="缁撴灉鐘舵��" align="center" key="excep" prop="excep" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
+ </template>
+ </el-table-column>
+
+ <el-table-column label="澶勭悊鎰忚" align="center" key="suggest" prop="suggest" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="templatename" align="center" label="鏈嶅姟妯℃澘" width="200" show-overflow-tooltip />
+ <el-table-column prop="remark" align="center" label="鏈嶅姟璁板綍" width="200" show-overflow-tooltip />
+
+ <el-table-column prop="bankcardno" align="center" label="鍛煎彨鐘舵��" width="210" />
+
+ <el-table-column label="鎿嶄綔" fixed="right" align="center" width="200" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="handleDetailsGo(scope.row)">
+ <span class="button-zx">
+ <i class="el-icon-s-order"></i>鏌ョ湅
+ </span>
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-row>
+
+ <!-- 鍒嗛〉 -->
+ <pagination
+ v-show="total > 0"
+ :total="total"
+ :page.sync="queryParams.pn"
+ :limit.sync="queryParams.ps"
+ @pagination="handlePagination"
+ />
+ </div>
+ </div>
+ </div>
+ </el-dialog>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination'
+
+export default {
+ name: 'TimelyRateDialog',
+ components: {
+ Pagination
+ },
+ dicts: ['sys_yujing', 'sys_suggest'],
+ props: {
+ visible: {
+ type: Boolean,
+ default: false
+ },
+ loading: {
+ type: Boolean,
+ default: false
+ },
+ data: {
+ type: Array,
+ default: () => []
+ },
+ total: {
+ type: Number,
+ default: 0
+ },
+ queryParams: {
+ type: Object,
+ default: () => ({
+ pn: 1,
+ ps: 10
+ })
+ }
+ },
+ data() {
+ return {
+ localQueryParams: { ...this.queryParams }
+ }
+ },
+ watch: {
+ queryParams: {
+ deep: true,
+ handler(newParams) {
+ this.localQueryParams = { ...newParams }
+ }
+ }
+ },
+ mounted() {
+ this.localQueryParams = { ...this.queryParams }
+ },
+ methods: {
+ handleSearch() {
+ this.$emit('search', this.localQueryParams)
+ },
+
+ resetQuery() {
+ this.localQueryParams = {
+ pn: 1,
+ ps: 10,
+ name: '',
+ leavediagname: ''
+ }
+ this.$emit('search', this.localQueryParams)
+ },
+
+ handlePagination(pagination) {
+ this.localQueryParams.pn = pagination.page
+ this.localQueryParams.ps = pagination.limit
+ this.$emit('search', this.localQueryParams)
+ },
+
+ getStateTagType(state) {
+ const stateMap = {
+ 1: 'primary',
+ 2: 'primary',
+ 3: 'success',
+ 4: 'info',
+ 5: 'danger',
+ 6: 'success'
+ }
+ return stateMap[state] || 'info'
+ },
+
+ getStateText(state) {
+ const stateTextMap = {
+ 1: '琛ㄥ崟宸查鍙�',
+ 2: '寰呴殢璁�',
+ 3: '琛ㄥ崟宸插彂閫�',
+ 4: '涓嶆墽琛�',
+ 5: '鍙戦�佸け璐�',
+ 6: '宸插畬鎴�'
+ }
+ return stateTextMap[state] || '鏈煡鐘舵��'
+ },
+
+ formatTime(time) {
+ if (!time) return ''
+ return this.parseTime(time)
+ },
+
+ handleDetailsGo(row) {
+ this.$emit('details-go', row)
+ },
+
+ handleClose() {
+ this.$emit('close')
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.timely-rate-dialog {
+ .search-form {
+ margin-bottom: 20px;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/components/styles.scss b/src/views/sfstatistics/percentage/components/styles.scss
new file mode 100644
index 0000000..49f2005
--- /dev/null
+++ b/src/views/sfstatistics/percentage/components/styles.scss
@@ -0,0 +1,90 @@
+// 鍏ㄥ眬鏍峰紡
+.follow-up-statistics,
+.first-follow-up,
+.second-follow-up,
+.continued-care {
+ .your-table-container {
+ margin-top: 10px;
+ }
+
+ .button-zx {
+ color: rgb(70, 204, 238);
+ }
+
+ // 缇庡寲鍚堣琛屾牱寮�
+ ::v-deep .el-table__footer {
+ .el-table__cell {
+ background-color: #f5f7fa;
+ font-weight: 600;
+ color: #409eff;
+
+ .cell {
+ font-weight: 600;
+ color: #409eff;
+ }
+ }
+ }
+
+ // 鍐呴儴琛ㄦ牸鍚堣琛屾牱寮�
+ ::v-deep .inner-table .el-table__footer {
+ .el-table__cell {
+ background-color: #ecf5ff;
+ font-weight: 500;
+ color: #67c23a;
+
+ .cell {
+ font-weight: 500;
+ color: #67c23a;
+ }
+ }
+ }
+
+ // 鐧惧垎姣斿瓧娈电壒娈婃牱寮�
+ ::v-deep .el-table__footer .el-table__cell[data-field="followUpRate"] .cell,
+ ::v-deep .el-table__footer .el-table__cell[data-field="rate"] .cell,
+ ::v-deep .el-table__footer .el-table__cell[data-field="followUpRateAgain"] .cell,
+ ::v-deep .el-table__footer .el-table__cell[data-field="completionRate"] .cell {
+ color: #e6a23c !important;
+ font-weight: 700 !important;
+ }
+
+ // 鍐呭眰鍖荤敓琛ㄦ牸鏍峰紡
+ .inner-table {
+ ::v-deep .el-table__header-wrapper {
+ background-color: #f0f7ff !important;
+
+ th {
+ background-color: #f0f7ff !important;
+ }
+ }
+
+ ::v-deep .el-table__body-wrapper {
+ tr {
+ background-color: #f9fbfe !important;
+
+ &:hover {
+ background-color: #e6f1ff !important;
+ }
+ }
+ }
+
+ ::v-deep .el-table--border {
+ border-color: #d9e8ff !important;
+
+ td, th {
+ border-color: #d9e8ff !important;
+ }
+ }
+ }
+
+ /* 浣胯鏈夋墜鍨嬫寚閽� */
+ ::v-deep .el-table__row {
+ cursor: pointer;
+ }
+
+ /* 灞曞紑琛屾牱寮� */
+ ::v-deep .el-table__expanded-cell {
+ padding: 10px 0 !important;
+ background: #f8f8f8;
+ }
+}
diff --git a/src/views/sfstatistics/percentage/index copy.vue b/src/views/sfstatistics/percentage/index copy.vue
new file mode 100644
index 0000000..d025fa2
--- /dev/null
+++ b/src/views/sfstatistics/percentage/index copy.vue
@@ -0,0 +1,2898 @@
+<template>
+ <div class="Questionnairemanagement">
+ <div class="leftvlue">
+ <div class="leftvlue-bg">
+ <el-row :gutter="20">
+ <!--鏍囩鏁版嵁-->
+ <el-col :span="24" :xs="24">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
+ label-width="98px">
+ <el-form-item label="缁熻绫诲瀷" prop="userName">
+ <el-select v-model="queryParams.statisticaltype" placeholder="璇烽�夋嫨缁熻绫诲瀷">
+ <el-option v-for="item in Statisticallist" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ <el-select style="margin-left: 10px" v-if="queryParams.statisticaltype == 1"
+ v-model="queryParams.leavehospitaldistrictcodes" size="medium" multiple filterable
+ placeholder="璇烽�夋嫨鐥呭尯">
+ <el-option v-for="item in flatArrayhospit" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ <el-select v-else-if="queryParams.statisticaltype == 2" v-model="queryParams.deptcodes" size="medium"
+ multiple filterable placeholder="璇烽�夋嫨绉戝">
+ <el-option v-for="item in flatArraydept" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="鏈嶅姟绫诲瀷" prop="userName">
+ <el-select v-model="queryParams.serviceType" multiple placeholder="璇烽�夋嫨">
+ <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label-width="200" label="搴旈殢璁挎椂闂磋寖鍥�" prop="userName">
+ <el-date-picker v-model="queryParams.dateRange" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
+ range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡"
+ :default-time="['00:00:00', '23:59:59']">
+ </el-date-picker>
+ </el-form-item>
+
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="medium" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="medium" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ <el-button type="warning" plain icon="el-icon-download" size="medium" @click="exportTable">瀵煎嚭</el-button>
+ <el-button type="primary" plain icon="el-icon-data-line" size="medium"
+ @click="showChartDialog">缁熻瓒嬪娍鍥�</el-button>
+ </el-form>
+
+ <!-- 鏂板锛歍ab鏍囩椤� -->
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+ <el-tab-pane label="棣栨闅忚" name="first">
+ <div class="your-table-container">
+ <el-table ref="exportTable" id="exportTableid" v-loading="loading" :data="firstFollowUpList"
+ :border="true" @selection-change="handleSelectionChange" @expand-change="handleRowClick"
+ :row-key="getRowKey" show-summary :summary-method="getSummaries" :expand-row-keys="expands">
+ <!-- 灞曞紑琛岀澶村垪 -->
+ <el-table-column type="expand">
+ <template slot-scope="props">
+ <el-table :data="props.row.doctorStats" border style="width: 95%; margin: 0 auto"
+ class="inner-table" show-summary :summary-method="getInnerSummaries">
+ <el-table-column label="鍖荤敓濮撳悕" prop="drname" align="center" />
+ <el-table-column label="绉戝" width="120" prop="deptname" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" prop="dischargeCount" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount">
+ </el-table-column>
+
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp"
+ prop="nonFollowUp">
+ </el-table-column>
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded"
+ prop="followUpNeeded">
+ </el-table-column>
+ <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUp" prop="needFollowUp">
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUp" prop="pendingFollowUp">
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccess" prop="followUpSuccess">
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFail" prop="followUpFail">
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRate"
+ prop="followUpRate">
+ </el-table-column>
+ <el-table-column v-if="orgname != '涓芥按甯備腑鍖婚櫌'" label="鍙婃椂鐜�" align="center" width="120"
+ key="rate" prop="rate">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="Seedetails(scope.row)"><span
+ class="button-zx">{{
+ (Number(scope.row.rate) * 100).toFixed(2)
+ }}%</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manual" prop="manual">
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="sms" prop="sms">
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChat" prop="weChat">
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍑洪櫌鐥呭尯" align="center" sortable key="leavehospitaldistrictname"
+ prop="leavehospitaldistrictname" width="150" :show-overflow-tooltip="true"
+ :sort-method="sortChineseNumber" />
+ <el-table-column label="绉戝" align="center" key="deptname" prop="deptname"
+ :show-overflow-tooltip="true" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount">
+ </el-table-column>
+
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp">
+ </el-table-column>
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded"
+ prop="followUpNeeded">
+ </el-table-column>
+ <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUp" prop="needFollowUp">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.needFollowUpInfo,
+ scope.row.leavehospitaldistrictname +
+ '闇�闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.needFollowUp
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUp" prop="pendingFollowUp">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.pendingFollowUpInfo,
+ scope.row.leavehospitaldistrictname +
+ '寰呴殢璁垮垪琛�'
+ )
+ "><span class="button-zx">{{
+ scope.row.pendingFollowUp
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccess" prop="followUpSuccess">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.followUpSuccessInfo,
+ scope.row.leavehospitaldistrictname +
+ '闅忚鎴愬姛鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.followUpSuccess
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFail" prop="followUpFail">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.followUpFailInfo,
+ scope.row.leavehospitaldistrictname +
+ '闅忚澶辫触鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.followUpFail
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRate" prop="followUpRate">
+ </el-table-column>
+ <el-table-column v-if="orgname != '涓芥按甯備腑鍖婚櫌'" label="鍙婃椂鐜�" align="center" width="120" key="rate"
+ prop="rate">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="Seedetails(scope.row)"><span class="button-zx">{{
+ (Number(scope.row.rate) * 100).toFixed(2)
+ }}%</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manual" prop="manual">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.manualInfo,
+ scope.row.leavehospitaldistrictname +
+ '浜哄伐闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.manual
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="sms" prop="sms">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.smsInfo,
+ scope.row.leavehospitaldistrictname +
+ '鐭俊闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.sms
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChat" prop="weChat">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.weChatInfo,
+ scope.row.leavehospitaldistrictname +
+ '寰俊闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.weChat
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table-column>
+
+ <!-- 闅忚鎯呭喌鍒楋紙浠呬附姘村競涓尰闄㈡樉绀猴級 -->
+ <el-table-column v-if="orgname == '涓芥按甯備腑鍖婚櫌'" align="center" label="闅忚鎯呭喌">
+ <el-table-column label="姝e父璇煶" align="center" width="100" key="taskSituation1"
+ prop="taskSituation1">
+ </el-table-column><el-table-column label="鎮h�呮嫆鎺ユ垨鎷掕" align="center" width="100" key="taskSituation2"
+ prop="taskSituation2">
+ </el-table-column><el-table-column label="闈㈣鎴栬�呮帴璇�" align="center" width="100" key="taskSituation3"
+ prop="taskSituation3">
+ </el-table-column><el-table-column label="寰俊闅忚" align="center" width="100" key="taskSituation4"
+ prop="taskSituation4">
+ </el-table-column><el-table-column label="闅忚鐢佃瘽涓嶆纭�" align="center" width="100" key="taskSituation5"
+ prop="taskSituation5">
+ </el-table-column><el-table-column label="鍏朵粬鎯呭喌涓嶅疁闅忚" align="center" width="100"
+ key="taskSituation6" prop="taskSituation6">
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="鍐嶆闅忚" name="second">
+ <div class="your-table-container">
+ <el-table ref="exportTableSecond" id="exportTableidSecond" v-loading="loadingSecond"
+ :data="secondFollowUpList" :border="true" @selection-change="handleSelectionChangeSecond"
+ @expand-change="handleRowClickSecond" :row-key="getRowKey" show-summary
+ :summary-method="getSummariesSecond" :expand-row-keys="expandsSecond">
+ <!-- 灞曞紑琛岀澶村垪 -->
+ <el-table-column type="expand">
+ <template slot-scope="props">
+ <el-table :data="props.row.doctorStats" border style="width: 95%; margin: 0 auto"
+ class="inner-table" show-summary :summary-method="getInnerSummariesSecond">
+ <el-table-column label="鍖荤敓濮撳悕" prop="drname" align="center" />
+ <el-table-column label="绉戝" width="120" prop="deptname" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" prop="dischargeCount" align="center" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount">
+ </el-table-column>
+
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp"
+ prop="nonFollowUp">
+ </el-table-column>
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded"
+ prop="followUpNeeded">
+ </el-table-column>
+ <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUpAgain"
+ prop="needFollowUpAgain">
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUpAgain"
+ prop="pendingFollowUpAgain">
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccessAgain"
+ prop="followUpSuccessAgain">
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFailAgain"
+ prop="followUpFailAgain">
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRateAgain"
+ prop="followUpRateAgain">
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manualAgain" prop="manualAgain">
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="smsAgain" prop="smsAgain">
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChatAgain" prop="weChatAgain">
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍑洪櫌鐥呭尯" align="center" sortable key="leavehospitaldistrictname"
+ prop="leavehospitaldistrictname" width="150" :show-overflow-tooltip="true"
+ :sort-method="sortChineseNumber" />
+ <el-table-column label="绉戝" align="center" key="deptname" prop="deptname"
+ :show-overflow-tooltip="true" />
+ <el-table-column label="鍑洪櫌浜烘" align="center" key="dischargeCount" prop="dischargeCount">
+ </el-table-column>
+
+ <el-table-column label="鏃犻渶闅忚浜烘" align="center" width="100" key="nonFollowUp" prop="nonFollowUp">
+ </el-table-column>
+ <el-table-column label="搴旈殢璁夸汉娆�" align="center" width="100" key="followUpNeeded"
+ prop="followUpNeeded">
+ </el-table-column>
+ <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
+ <el-table-column label="闇�闅忚" align="center" key="needFollowUpAgain" prop="needFollowUpAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.needFollowUpAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚闇�闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.needFollowUpAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰呴殢璁�" align="center" key="pendingFollowUpAgain"
+ prop="pendingFollowUpAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.pendingFollowUpAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚寰呴殢璁垮垪琛�'
+ )
+ "><span class="button-zx">{{
+ scope.row.pendingFollowUpAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鎴愬姛" align="center" key="followUpSuccessAgain"
+ prop="followUpSuccessAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.followUpSuccessAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚闅忚鎴愬姛鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.followUpSuccessAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚澶辫触" align="center" key="followUpFailAgain" prop="followUpFailAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.followUpFailAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚闅忚澶辫触鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.followUpFailAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="闅忚鐜�" align="center" width="120" key="followUpRateAgain"
+ prop="followUpRateAgain">
+ </el-table-column>
+ <el-table-column label="浜哄伐" align="center" key="manualAgain" prop="manualAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.manualAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚浜哄伐闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.manualAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐭俊" align="center" key="smsAgain" prop="smsAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.smsAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚鐭俊闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.smsAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="寰俊" align="center" key="weChatAgain" prop="weChatAgain">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="
+ viewDetails(
+ scope.row.weChatAgainInfo,
+ scope.row.leavehospitaldistrictname +
+ '鍐嶆闅忚寰俊闅忚鍒楄〃'
+ )
+ "><span class="button-zx">{{
+ scope.row.weChatAgain
+ }}</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+ </el-col>
+ </el-row>
+ </div>
+ </div>
+ <!-- 缁熻瓒嬪娍鍥惧脊绐� -->
+ <el-dialog title="闅忚缁熻瓒嬪娍鍥�" :visible.sync="chartDialogVisible" width="80%" :close-on-click-modal="false">
+ <div class="chart-container">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <div class="chart-title">闅忚鐘舵�佸垎甯�</div>
+ <div id="pieChart" style="width: 100%; height: 400px"></div>
+ </el-col>
+ <el-col :span="12">
+ <div class="chart-title">闅忚瓒嬪娍鍒嗘瀽</div>
+ <div id="barLineChart" style="width: 100%; height: 400px"></div>
+ </el-col>
+ </el-row>
+ </div>
+ </el-dialog>
+ <el-dialog title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�" :visible.sync="SeedetailsVisible" v-loading="Seedloading" width="70%"
+ :close-on-click-modal="false">
+ <div class="examine-jic">
+ <div class="jic-value">
+ <el-row :gutter="20">
+ <!--鐢ㄦ埛鏁版嵁-->
+ <el-form :model="patientqueryParams" ref="queryForm" size="small" :inline="true" label-width="98px">
+ <el-form-item label="鎮h�咃細">
+ <el-input v-model="patientqueryParams.name" @keyup.enter.native="handleQuery"></el-input>
+ </el-form-item>
+ <el-form-item label="鎮h�呰瘖鏂細">
+ <el-input v-model="patientqueryParams.leavediagname" @keyup.enter.native="handleQuery"></el-input>
+ </el-form-item>
+
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="medium" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="medium" @click="resetQuery">鍙栨秷鍒涘缓</el-button>
+ </el-form-item>
+ </el-form>
+ <!-- 閫夋嫨鎮h�呭垪琛� -->
+ <el-table :data="logsheetlist" style="width: 100%">
+ <el-table-column prop="sendname" align="center" label="濮撳悕" width="100">
+ </el-table-column>
+ <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="浠诲姟鍚嶇О">
+ </el-table-column>
+ <el-table-column prop="sendstate" align="center" width="200" label="浠诲姟鐘舵��">
+ <template slot-scope="scope">
+ <div v-if="scope.row.sendstate == 1">
+ <el-tag type="primary" :disable-transitions="false">琛ㄥ崟宸查鍙�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 2">
+ <el-tag type="primary" :disable-transitions="false">寰呴殢璁�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 3">
+ <el-tag type="success" :disable-transitions="false">琛ㄥ崟宸插彂閫�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 4">
+ <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 5">
+ <el-tag type="danger" :disable-transitions="false">鍙戦�佸け璐�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 6">
+ <el-tag type="success" :disable-transitions="false">宸插畬鎴�</el-tag>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column prop="visitTime" align="center" label="搴旈殢璁挎椂闂�" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column prop="finishtime" align="center" label="闅忚瀹屾垚鏃堕棿" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column label="鍑洪櫌鏃ユ湡" width="200" align="center" key="endtime" prop="endtime">
+ <template slot-scope="scope">
+ <span>{{ formatTime(scope.row.endtime) }}</span>
+ </template></el-table-column>
+ <el-table-column label="璐d换鎶ゅ+" width="120" align="center" key="nurseName" prop="nurseName" />
+ <el-table-column label="涓绘不鍖荤敓" width="120" align="center" key="drname" prop="drname" />
+
+ <el-table-column label="缁撴灉鐘舵��" align="center" key="excep" prop="excep" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
+ </template>
+ </el-table-column>
+ <el-table-column label="澶勭悊鎰忚" align="center" key="suggest" prop="suggest" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="templatename" align="center" label="鏈嶅姟妯℃澘" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column prop="remark" align="center" label="鏈嶅姟璁板綍" width="200" show-overflow-tooltip>
+ </el-table-column>
+
+ <el-table-column prop="bankcardno" align="center" label="鍛煎彨鐘舵��" width="210">
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" fixed="right" align="center" width="200"
+ class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="SeedetailsgGo(scope.row)"><span class="button-zx"><i
+ class="el-icon-s-order"></i>鏌ョ湅</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-row>
+ <pagination v-show="patienttotal > 0 && this.patientqueryParams.allhosp != 6" :total="patienttotal"
+ :page.sync="patientqueryParams.pn" :limit.sync="patientqueryParams.ps" @pagination="Seedetailstion" />
+ </div>
+ </div>
+ </el-dialog>
+ <!-- 鍚勭被璇︽儏 -->
+ <el-dialog :title="infotitle" :visible.sync="infotitleVisible" v-loading="infotitloading" width="70%"
+ :close-on-click-modal="false">
+ <div style="margin-bottom: 16px; display: flex; align-items: center">
+ <span style="margin-right: 10px; font-weight: bold">鎮h�呭鍚嶆煡璇�:</span>
+ <el-input v-model="searchName" placeholder="璇疯緭鍏ユ偅鑰呭鍚嶈繘琛岀瓫閫�" clearable style="width: 300px" @input="handleSearch"
+ @clear="handleSearch">
+ </el-input>
+ <span style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px">
+ 鍏� {{ infotitlelist.length }} 鏉¤褰�
+ </span>
+ </div>
+ <div class="examine-jic">
+ <div class="jic-value">
+ <el-row :gutter="20">
+ <!-- 閫夋嫨鎮h�呭垪琛� -->
+ <div class="data-list" ref="dataList" @scroll="handleScroll" v-loading="infotitloading">
+ <el-table :data="currentDisplayList" height="660" style="width: 100%">
+ <el-table-column prop="sendname" align="center" label="濮撳悕" width="100">
+ </el-table-column>
+ <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="浠诲姟鍚嶇О">
+ </el-table-column>
+ <el-table-column prop="sendstate" align="center" width="200" label="浠诲姟鐘舵��">
+ <template slot-scope="scope">
+ <div v-if="scope.row.sendstate == 1">
+ <el-tag type="primary" :disable-transitions="false">琛ㄥ崟宸查鍙�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 2">
+ <el-tag type="primary" :disable-transitions="false">寰呴殢璁�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 3">
+ <el-tag type="success" :disable-transitions="false">琛ㄥ崟宸插彂閫�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 4">
+ <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 5">
+ <el-tag type="danger" :disable-transitions="false">鍙戦�佸け璐�</el-tag>
+ </div>
+ <div v-if="scope.row.sendstate == 6">
+ <el-tag type="success" :disable-transitions="false">宸插畬鎴�</el-tag>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="浠诲姟鎵ц鏂瑰紡" align="center" key="preachform" prop="preachform" width="160"
+ :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <span v-for="item in scope.row.preachform">{{ item }}銆�
+ </span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="visitTime" align="center" label="搴旈殢璁挎椂闂�" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column prop="finishtime" align="center" label="闅忚瀹屾垚鏃堕棿" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column label="鍑洪櫌鏃ユ湡" width="200" align="center" key="endtime" prop="endtime">
+ <template slot-scope="scope">
+ <span>{{ formatTime(scope.row.endtime) }}</span>
+ </template></el-table-column>
+ <el-table-column label="璐d换鎶ゅ+" width="120" align="center" key="nurseName" prop="nurseName" />
+ <el-table-column label="涓绘不鍖荤敓" width="120" align="center" key="drname" prop="drname" />
+
+ <el-table-column label="缁撴灉鐘舵��" align="center" key="excep" prop="excep" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
+ </template>
+ </el-table-column>
+ <el-table-column label="澶勭悊鎰忚" align="center" key="suggest" prop="suggest" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="templatename" align="center" label="鏈嶅姟妯℃澘" width="200" show-overflow-tooltip>
+ </el-table-column>
+ <el-table-column prop="remark" align="center" label="鏈嶅姟璁板綍" width="200" show-overflow-tooltip>
+ </el-table-column>
+
+ <el-table-column prop="bankcardno" align="center" label="鍛煎彨鐘舵��" width="210">
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" fixed="right" align="center" width="200"
+ class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button size="medium" type="text" @click="SeedetailsgGo(scope.row)"><span class="button-zx"><i
+ class="el-icon-s-order"></i>鏌ョ湅</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-row>
+ </div>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import {
+ toamendtag,
+ addapitag,
+ deletetag,
+ changetagcategory,
+} from "@/api/system/label";
+import store from "@/store";
+import { getSfStatistics, selectTimelyRate } from "@/api/system/user";
+import * as XLSX from "xlsx";
+import FileSaver from "file-saver";
+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 = [
+ {
+ text: "浠婂ぉ",
+ onClick(picker) {
+ picker.$emit("pick", new Date());
+ },
+ },
+ {
+ text: "鏄ㄥぉ",
+ onClick(picker) {
+ const date = new Date();
+ date.setTime(date.getTime() - 3600 * 1000 * 24);
+ picker.$emit("pick", date);
+ },
+ },
+ {
+ text: "涓�鍛ㄥ墠",
+ onClick(picker) {
+ const date = new Date();
+ date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+ picker.$emit("pick", date);
+ },
+ },
+];
+
+export default {
+ name: "Percentage",
+ dicts: ["sys_normal_disable", "sys_user_sex"],
+ components: { Treeselect },
+ data() {
+ return {
+ // 鏂板锛歍ab鏍囩椤垫帶鍒�
+ activeTab: "first", // 褰撳墠婵�娲荤殑tab锛宖irst-棣栨闅忚锛宻econd-鍐嶆闅忚
+
+ // 鍒嗙鐨勬暟鎹垪琛�
+ firstFollowUpList: [], // 棣栨闅忚鏁版嵁
+ secondFollowUpList: [], // 鍐嶆闅忚鏁版嵁
+
+ // 鍒嗙鐨勫姞杞界姸鎬�
+ loading: false, // 棣栨闅忚琛ㄦ牸鍔犺浇鐘舵��
+ loadingSecond: false, // 鍐嶆闅忚琛ㄦ牸鍔犺浇鐘舵��
+
+ // 鍒嗙鐨勫睍寮�鐘舵��
+ expands: [], // 棣栨闅忚琛ㄦ牸灞曞紑琛�
+ expandsSecond: [], // 鍐嶆闅忚琛ㄦ牸灞曞紑琛�
+
+ // 鍒嗙鐨勯�夋嫨鐘舵��
+ ids: [], // 棣栨闅忚閫変腑椤�
+ idsSecond: [], // 鍐嶆闅忚閫変腑椤�
+
+ orgname: "",
+ infotitlelist: [],
+ currentDisplayList: [],
+ loadIndex: 0,
+ pageSize: 100,
+ isLoading: false,
+
+ Seedloading: false,
+ chartDialogVisible: false,
+ infotitleVisible: false,
+ searchName: "",
+ infotitloading: false,
+ infotitle: "",
+ pieChart: null,
+ barLineChart: null,
+
+ single: true,
+ multiple: true,
+ showSearch: true,
+ idds: "",
+ total: 0,
+ flatArrayhospit: [],
+ flatArraydept: [],
+ patienttotal: 0,
+ logsheetlist: [],
+ Statisticallist: [
+ {
+ label: "鐥呭尯缁熻",
+ value: 1,
+ },
+ {
+ label: "绉戝缁熻",
+ value: 2,
+ },
+ ],
+ patientqueryParams: {
+ pn: 1,
+ ps: 10,
+ },
+ amendtag: false,
+ lstamendtag: false,
+ scavisible: false,
+ deleteVisible: false,
+ deletefenl: "楂樿鍘�",
+ tagform: {
+ isupload: "",
+ tagname: "",
+ tagcategoryid: "",
+ tagdescription: "",
+ },
+ classifyform: {
+ categoryname: "",
+ },
+ title: "",
+ open: false,
+ dateRange: [],
+ postOptions: [],
+ roleOptions: [],
+ allDeptCodes: [],
+ allWardCodes: [],
+ checkboxlist: [],
+ form: {},
+ forms: {
+ name: "",
+ },
+ numberlb: 22,
+ dialogFormVisible: false,
+ lstamendtagVisible: false,
+ goQRCodeVisible: false,
+ sidecolumnval: "",
+ propss: { multiple: true },
+ SeedetailsVisible: false,
+ options: store.getters.tasktypes,
+ pickerOptions: {
+ disabledDate(time) {
+ return time.getTime() < Date.now() - 3600 * 1000 * 24;
+ },
+ shortcuts: shortcuts,
+ },
+ pickerOptionsa: {
+ disabledDate(time) {
+ return time.getTime() > Date.now();
+ },
+ shortcuts: shortcuts,
+ },
+ queryParams: {
+ serviceType: [2],
+ dateRange: [],
+ statisticaltype: 1,
+ leavehospitaldistrictcodes: ["all"],
+ deptcodes: [],
+ visitCount: 1, // 鏂板锛氶殢璁挎鏁板弬鏁帮紝1-棣栨锛�2-鍐嶆
+ },
+ columns: [
+ { key: 0, label: `鏍囩缂栧彿`, visible: true },
+ { key: 1, label: `鏍囩鍚嶇О`, visible: true },
+ { key: 2, label: `鏍囩鏄电О`, visible: true },
+ { key: 3, label: `閮ㄩ棬`, visible: true },
+ { key: 4, label: `鎵嬫満鍙风爜`, visible: true },
+ { key: 5, label: `鐘舵�乣, visible: true },
+ { key: 6, label: `鍒涘缓鏃堕棿`, visible: true },
+ ],
+ };
+ },
+ watch: {},
+ created() {
+ this.getDeptTree();
+ this.getFirstFollowUpList(); // 榛樿鍔犺浇棣栨闅忚鏁版嵁
+ this.checkboxlist = store.getters.checkboxlist;
+ this.orgname = localStorage.getItem("orgname");
+ },
+
+ methods: {
+ /** 鏌ヨ棣栨闅忚鍒楄〃 */
+ async getFirstFollowUpList() {
+ this.loading = true;
+ this.queryParams.visitCount = 1; // 璁剧疆闅忚娆℃暟涓洪娆�
+
+ const params = {
+ ...this.queryParams,
+ leavehospitaldistrictcodes:
+ this.queryParams.leavehospitaldistrictcodes.includes("all")
+ ? this.allWardCodes
+ : this.queryParams.leavehospitaldistrictcodes,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.allDeptCodes
+ : this.queryParams.deptcodes,
+ };
+
+ delete params.leavehospitaldistrictcodes.all;
+ delete params.deptcodes.all;
+
+ try {
+ const response = await getSfStatistics(params);
+ this.firstFollowUpList = this.customSort(response.data);
+ this.total = response.total;
+ } catch (error) {
+ console.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触:", error);
+ this.$message.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触");
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ /** 鏌ヨ鍐嶆闅忚鍒楄〃 */
+ async getSecondFollowUpList() {
+ this.loadingSecond = true;
+ this.queryParams.visitCount = 2; // 璁剧疆闅忚娆℃暟涓哄啀娆�
+
+ const params = {
+ ...this.queryParams,
+ leavehospitaldistrictcodes:
+ this.queryParams.leavehospitaldistrictcodes.includes("all")
+ ? this.allWardCodes
+ : this.queryParams.leavehospitaldistrictcodes,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.allDeptCodes
+ : this.queryParams.deptcodes,
+ };
+
+ delete params.leavehospitaldistrictcodes.all;
+ delete params.deptcodes.all;
+
+ try {
+ const response = await getSfStatistics(params);
+ this.secondFollowUpList = this.customSort(response.data);
+ this.total = response.total;
+ } catch (error) {
+ console.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触:", error);
+ this.$message.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触");
+ } finally {
+ this.loadingSecond = false;
+ }
+ },
+
+ /** Tab鍒囨崲浜嬩欢 */
+ handleTabClick(tab) {
+ if (tab.name === "first") {
+ if (this.firstFollowUpList.length === 0) {
+ this.getFirstFollowUpList();
+ }
+ } else if (tab.name === "second") {
+ if (this.secondFollowUpList.length === 0) {
+ this.getSecondFollowUpList();
+ }
+ }
+ },
+ sortChineseNumber(aRow, bRow) {
+ const a = aRow.leavehospitaldistrictname;
+ const b = bRow.leavehospitaldistrictname;
+
+ // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
+ const chineseNumMap = {
+ 涓�: 1,
+ 浜�: 2,
+ 涓�: 3,
+ 鍥�: 4,
+ 浜�: 5,
+ 鍏�: 6,
+ 涓�: 7,
+ 鍏�: 8,
+ 涔�: 9,
+ 鍗�: 10,
+ 鍗佷竴: 11,
+ 鍗佷簩: 12,
+ 鍗佷笁: 13,
+ 鍗佸洓: 14,
+ 鍗佷簲: 15,
+ 鍗佸叚: 16,
+ 鍗佷竷: 17,
+ 鍗佸叓: 18,
+ 鍗佷節: 19,
+ 浜屽崄: 20,
+ 浜屽崄涓�: 21,
+ 浜屽崄浜�: 22,
+ 浜屽崄涓�: 23,
+ 浜屽崄鍥�: 24,
+ 浜屽崄浜�: 25,
+ 浜屽崄鍏�: 26,
+ 浜屽崄涓�: 27,
+ 浜屽崄鍏�: 28,
+ 浜屽崄涔�: 29,
+ 涓夊崄: 30,
+ 涓夊崄涓�: 31,
+ 涓夊崄浜�: 32,
+ 涓夊崄涓�: 33,
+ 涓夊崄鍥�: 34,
+ 涓夊崄浜�: 35,
+ 涓夊崄鍏�: 36,
+ 涓夊崄涓�: 37,
+ 涓夊崄鍏�: 38,
+ 涓夊崄涔�: 39,
+ 鍥涘崄: 40,
+ 鍥涘崄涓�: 41,
+ 鍥涘崄浜�: 42,
+ 鍥涘崄涓�: 43,
+ 鍥涘崄鍥�: 44,
+ 鍥涘崄浜�: 45,
+ };
+
+ // 鎻愬彇涓枃鏁板瓧
+ const getNumberFromText = (text) => {
+ if (!text || typeof text !== "string") return -1;
+
+ // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
+ const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+
+ if (match && match[1]) {
+ const chineseNum = match[1];
+ return chineseNumMap[chineseNum] !== undefined
+ ? chineseNumMap[chineseNum]
+ : -1;
+ }
+
+ // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
+ const arabicMatch = text.match(/^(\d+)/);
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10);
+ return num >= 1 && num <= 45 ? num : -1;
+ }
+
+ return -1;
+ };
+
+ const numA = getNumberFromText(a);
+ const numB = getNumberFromText(b);
+
+ // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+ if (numA === -1 && numB === -1) {
+ return (a || "").localeCompare(b || "");
+ }
+ if (numA === -1) return 1;
+ if (numB === -1) return -1;
+
+ return numA - numB;
+ },
+ // 鎼滅储澶勭悊鍑芥暟
+ handleSearch() {
+ if (!this.searchName.trim()) {
+ // 濡傛灉鎼滅储妗嗕负绌猴紝鏄剧ず鎵�鏈夋暟鎹�
+ this.currentDisplayList = [...this.infotitlelist];
+ } else {
+ // 鏍规嵁鎮h�呭鍚嶈繘琛岀瓫閫夛紙涓嶅尯鍒嗗ぇ灏忓啓锛�
+ const keyword = this.searchName.toLowerCase();
+ this.currentDisplayList = this.infotitlelist.filter((item) => {
+ return item.sendname && item.sendname.toLowerCase().includes(keyword);
+ });
+ }
+ },
+ customSort(data) {
+ // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
+ const order = [
+ "涓�",
+ "浜�",
+ "涓�",
+ "鍥�",
+ "浜�",
+ "鍏�",
+ "涓�",
+ "鍏�",
+ "涔�",
+ "鍗�",
+ "鍗佷竴",
+ "鍗佷簩",
+ "鍗佷笁",
+ "鍗佸洓",
+ "鍗佷簲",
+ "鍗佸叚",
+ "鍗佷竷",
+ "鍗佸叓",
+ "鍗佷節",
+ "浜屽崄",
+ "浜屽崄涓�",
+ "浜屽崄浜�",
+ "浜屽崄涓�",
+ "浜屽崄鍥�",
+ "浜屽崄浜�",
+ "浜屽崄鍏�",
+ "浜屽崄涓�",
+ "浜屽崄鍏�",
+ "浜屽崄涔�",
+ "涓夊崄",
+ "涓夊崄涓�",
+ "涓夊崄浜�",
+ "涓夊崄涓�",
+ "涓夊崄鍥�",
+ "涓夊崄浜�",
+ "涓夊崄鍏�",
+ "涓夊崄涓�",
+ "涓夊崄鍏�",
+ "涓夊崄涔�",
+ "鍥涘崄",
+ "鍥涘崄涓�",
+ "鍥涘崄浜�",
+ "鍥涘崄涓�",
+ "鍥涘崄鍥�",
+ "鍥涘崄浜�",
+ ];
+
+ return data.sort((a, b) => {
+ // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
+ const getIndex = (name) => {
+ if (!name || typeof name !== "string") return -1;
+
+ // 鍖归厤涓枃鏁板瓧
+ const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+ if (chineseMatch && chineseMatch[1]) {
+ return order.indexOf(chineseMatch[1]);
+ }
+
+ // 鍖归厤闃挎媺浼暟瀛�
+ const arabicMatch = name.match(/^(\d+)/);
+ if (arabicMatch && arabicMatch[1]) {
+ const num = parseInt(arabicMatch[1], 10);
+ if (num >= 1 && num <= 45) {
+ return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
+ }
+ }
+
+ return -1;
+ };
+
+ const indexA = getIndex(a.leavehospitaldistrictname);
+ const indexB = getIndex(b.leavehospitaldistrictname);
+
+ // 鎺掑簭閫昏緫
+ if (indexA === -1 && indexB === -1) {
+ return (a.leavehospitaldistrictname || "").localeCompare(
+ b.leavehospitaldistrictname || ""
+ );
+ }
+ if (indexA === -1) return 1;
+ if (indexB === -1) return -1;
+ return indexA - indexB;
+ });
+ },
+ getRowKey(row) {
+ 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,
+ // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.allDeptCodes
+ : this.queryParams.deptcodes,
+ leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
+ drcode: "1",
+ visitCount: 1, // 璁剧疆涓洪娆¢殢璁�
+ };
+
+ // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
+ delete params.leavehospitaldistrictcodes.all;
+ delete params.deptcodes.all;
+ // 濡傛灉璇ヨ杩樻病鏈夊姞杞藉尰鐢熸暟鎹紝鍒欏姞杞�
+ 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)];
+ }
+ },
+ getSummaries(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣";
+ return;
+ }
+ if (index === 1 || index === 2) {
+ sums[index] = "/";
+ return;
+ }
+
+ // 瀵圭櫨鍒嗘瘮瀛楁鐗规畩澶勭悊 - 鍙栧钩鍧囧��
+ if (
+ column.property === "followUpRate" ||
+ column.property === "rate" ||
+ column.property === "followUpRateAgain"
+ ) {
+ // 鎻愬彇鎵�鏈夋湁鏁堢櫨鍒嗘瘮鍊煎苟杞崲涓哄皬鏁�
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property];
+ if (!value || value === "-" || value === "0%") return null;
+
+ // 澶勭悊甯︾櫨鍒嗗彿鐨勬暟鎹�
+ if (typeof value === "string" && value.includes("%")) {
+ // 鍘婚櫎鐧惧垎鍙峰苟杞崲涓哄皬鏁�
+ const numValue = parseFloat(value.replace("%", "")) / 100;
+ return isNaN(numValue) ? null : numValue;
+ } else {
+ // 澶勭悊宸茬粡鏄皬鏁扮殑鏁版嵁
+ const numValue = parseFloat(value);
+ return isNaN(numValue) ? null : numValue;
+ }
+ })
+ .filter((value) => value !== null && value !== 0); // 杩囨护鎺塶ull鍜�0鍊�
+
+ if (percentageValues.length > 0) {
+ const average =
+ percentageValues.reduce((sum, value) => sum + value, 0) /
+ percentageValues.length;
+ sums[index] = (average * 100).toFixed(2) + "%";
+ } else {
+ sums[index] = "0.00%";
+ }
+ } else {
+ // 鏅�氭暟瀛楀瓧娈� - 姹傚拰
+ const values = data.map((item) => {
+ const value = item[column.property];
+ if (value === "-" || value === "" || value === null) return 0;
+ return Number(value) || 0;
+ });
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0);
+ sums[index] = this.formatNumber(sums[index]);
+ } else {
+ sums[index] = "-";
+ }
+ }
+ });
+
+ return sums;
+ },
+
+ // 鍐呴儴琛ㄦ牸鍚堣琛岃绠楁柟娉�
+ getInnerSummaries(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "灏忚";
+ return;
+ }
+
+ if (column.property === "drname" || column.property === "deptname") {
+ sums[index] = "-";
+ return;
+ }
+
+ // 瀵圭櫨鍒嗘瘮瀛楁鐗规畩澶勭悊 - 鍙栧钩鍧囧��
+ if (column.property === "followUpRate" || column.property === "rate") {
+ // 鎻愬彇鎵�鏈夋湁鏁堢櫨鍒嗘瘮鍊煎苟杞崲涓哄皬鏁�
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property];
+ if (!value || value === "-" || value === "0%") return null;
+
+ // 澶勭悊甯︾櫨鍒嗗彿鐨勬暟鎹�
+ if (typeof value === "string" && value.includes("%")) {
+ // 鍘婚櫎鐧惧垎鍙峰苟杞崲涓哄皬鏁�
+ const numValue = parseFloat(value.replace("%", "")) / 100;
+ return isNaN(numValue) ? null : numValue;
+ } else {
+ // 澶勭悊宸茬粡鏄皬鏁扮殑鏁版嵁
+ const numValue = parseFloat(value);
+ return isNaN(numValue) ? null : numValue;
+ }
+ })
+ .filter((value) => value !== null && value !== 0);
+
+ if (percentageValues.length > 0) {
+ const average =
+ percentageValues.reduce((sum, value) => sum + value, 0) /
+ percentageValues.length;
+ sums[index] = (average * 100).toFixed(2) + "%";
+ } else {
+ sums[index] = "0.00%";
+ }
+ } else {
+ // 鏅�氭暟瀛楀瓧娈� - 姹傚拰
+ const values = data.map((item) => {
+ const value = item[column.property];
+ if (value === "-" || value === "" || value === null) return 0;
+ return Number(value) || 0;
+ });
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0);
+ sums[index] = this.formatNumber(sums[index]);
+ } else {
+ sums[index] = "-";
+ }
+ }
+ });
+
+ return sums;
+ },
+
+ // 杈呭姪鏂规硶锛氭彁鍙栫櫨鍒嗘瘮鏁板��
+ extractPercentageValue(value) {
+ if (!value) return null;
+
+ if (typeof value === "string") {
+ // 澶勭悊甯︾櫨鍒嗗彿鐨勫瓧绗︿覆
+ if (value.includes("%")) {
+ const num = parseFloat(value.replace("%", ""));
+ return isNaN(num) ? null : num / 100;
+ }
+ // 澶勭悊绾暟瀛楀瓧绗︿覆
+ const num = parseFloat(value);
+ return isNaN(num) ? null : num;
+ }
+
+ // 澶勭悊鏁板瓧绫诲瀷
+ return typeof value === "number" ? value : null;
+ },
+
+ // 鏁板瓧鏍煎紡鍖栨柟娉�
+ formatNumber(num) {
+ if (isNaN(num)) return "-";
+ return Number.isInteger(num) ? num.toString() : num.toFixed(0);
+ },
+ /** 淇敼鏍囩 */
+ handleUpdate(row) {
+ console.log(row, "淇敼鏍囩");
+ this.lstamendtagVisible = true;
+ this.lstamendtag = true;
+ this.tagform = {
+ isupload: row.isupload,
+ tagname: row.tagname,
+ tagcategoryid: row.tagcategoryid,
+ tagdescription: row.tagdescription,
+ tagid: row.tagid,
+ };
+ },
+ // 鑾峰彇绉戝鏍�
+ getDeptTree() {
+ // 绉戝鍒楄〃
+ this.flatArraydept = store.getters.belongDepts.map((dept) => {
+ return {
+ label: dept.deptName,
+ value: dept.deptCode,
+ };
+ });
+ // 瀛樺偍鎵�鏈夌瀹や唬鐮�
+ this.allDeptCodes = store.getters.belongDepts.map(
+ (dept) => dept.deptCode
+ );
+
+ // 鐥呭尯鍒楄〃
+ this.flatArrayhospit = store.getters.belongWards.map((ward) => {
+ return {
+ label: ward.districtName,
+ value: ward.districtCode,
+ };
+ });
+
+ // 瀛樺偍鎵�鏈夌梾鍖轰唬鐮�
+ this.allWardCodes = store.getters.belongWards.map(
+ (ward) => ward.districtCode
+ );
+ this.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
+ this.flatArrayhospit.push({ label: "鍏ㄩ儴", value: "all" });
+ },
+ flattenArray(multiArray) {
+ let result = [];
+
+ // 閫掑綊鍑芥暟锛岀敤浜庡皢澶氱骇鏁扮粍杞崲涓轰竴缁存暟缁勶紝鍙寘鍚渶搴曞眰鐨勫厓绱�
+ function flatten(element) {
+ // 濡傛灉褰撳墠鍏冪礌鏈夊瓙鍏冪礌锛岀户缁�掑綊
+ if (element.children && element.children.length > 0) {
+ element.children.forEach((child) => flatten(child));
+ } else {
+ // 鍏嬮殕鍏冪礌浠ラ伩鍏嶄慨鏀瑰師濮嬫暟鎹�
+ let item = JSON.parse(JSON.stringify(element));
+ result.push(item); // 灏嗘渶搴曞眰鐨勫厓绱犳坊鍔犲埌缁撴灉鏁扮粍
+ }
+ }
+
+ // 浠庨《灞傚厓绱犲紑濮嬮�掑綊
+ multiArray.forEach((element) => flatten(element));
+ return result; // 杩斿洖鍙寘鍚渶搴曞眰鍏冪礌鐨勪竴缁存暟缁�
+ },
+ addladeltag() {
+ this.lstamendtagVisible = true;
+ this.lstamendtag = false;
+ this.tagform = {
+ isupload: "",
+ tagname: "",
+ tagcategoryid: "",
+ tagdescription: "",
+ tagid: "",
+ };
+ },
+ Seedetails(row) {
+ this.SeedetailsVisible = true;
+ this.Seedloading = true;
+ this.patientqueryParams.starttime = this.parseTime(
+ this.queryParams.dateRange[0]
+ );
+ this.patientqueryParams.endtime = this.parseTime(
+ this.queryParams.dateRange[1]
+ );
+ this.patientqueryParams.deptcode = row.deptcode;
+ selectTimelyRate(this.patientqueryParams).then((response) => {
+ this.logsheetlist = response.data.detail;
+ this.patienttotal = response.data.total;
+ this.Seedloading = false;
+ });
+ },
+ Seedetailstion() {
+ selectTimelyRate(this.patientqueryParams).then((response) => {
+ this.logsheetlist = response.data.detail;
+ this.patienttotal = response.data.total;
+ this.Seedloading = false;
+ });
+ },
+ viewDetails(row, title) {
+ this.infotitleVisible = true;
+ this.infotitle = title;
+ this.infotitlelist = row; // 鍋囪row灏辨槸闇�瑕佸睍绀虹殑璇︾粏鏁扮粍
+ console.log(this.infotitlelist, "this.infotitlelist");
+
+ this.infotitlelist.forEach((item) => {
+ let idArray = null;
+
+ if (item.preachform) {
+ if (item.endtime) {
+ item.preachformson = item.preachform;
+ idArray = item.preachform.split(",");
+ }
+
+ item.preachform = idArray.map((value) => {
+ // 鏌ユ壘id瀵瑰簲鐨勫璞�
+ const item = this.checkboxlist.find((item) => item.value == value);
+ // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+ return item ? item.label : null;
+ });
+ }
+ });
+ // 鍒濆鍖栧姞杞�
+ this.loadIndex = 0;
+ this.currentDisplayList = [];
+ this.$nextTick(() => {
+ this.loadMoreData();
+ });
+ },
+ loadMoreData() {
+ if (this.isLoading) return;
+ this.isLoading = true;
+
+ // 妯℃嫙寮傛鍔犺浇锛屽疄闄呭彲鑳芥槸鐩存帴鍒囩墖鏈湴鏁版嵁
+ setTimeout(() => {
+ console.log(this.infotitlelist, "this.infotitlelist");
+
+ const nextChunk = this.infotitlelist.slice(
+ this.loadIndex,
+ this.loadIndex + this.pageSize
+ );
+ this.currentDisplayList = this.currentDisplayList.concat(nextChunk);
+ this.loadIndex += this.pageSize;
+ this.isLoading = false;
+ }, 200);
+ },
+ handleScroll(event) {
+ const scrollContainer = event.target;
+ // 鍒ゆ柇鏄惁婊氬姩鍒板簳閮�
+ const isAtBottom =
+ scrollContainer.scrollTop + scrollContainer.clientHeight >=
+ scrollContainer.scrollHeight - 10;
+
+ if (
+ isAtBottom &&
+ !this.isLoading &&
+ this.loadIndex < this.infotitlelist.length
+ ) {
+ this.loadMoreData();
+ }
+ },
+ SeedetailsgGo(row) {
+ this.SeedetailsVisible = false;
+ let type = "";
+ if (row.preachformson && row.preachformson.includes("3")) {
+ type = 1;
+ }
+ setTimeout(() => {
+ this.$router.push({
+ path: "/followvisit/record/detailpage/",
+ query: {
+ taskid: row.taskid,
+ patid: row.patid,
+ id: row.id,
+ Voicetype: type,
+ // visitCount: this.topqueryParams.visitCount,
+ },
+ });
+ }, 300);
+ },
+ // 娣诲姞/淇敼鏍囩
+ Maintenancetag() {
+ if (this.lstamendtag) {
+ toamendtag(this.addDateRange(this.tagform)).then((response) => {
+ console.log(response);
+ this.getList();
+ });
+ } else {
+ addapitag(this.addDateRange(this.tagform)).then((response) => {
+ console.log(response);
+ this.getList();
+ });
+ }
+ this.tagform = {
+ isupload: "",
+ tagname: "",
+ tagcategoryid: "",
+ tagdescription: "",
+ tagid: "",
+ };
+ },
+ routerErr(row) {
+ console.log(row, "璺宠浆寮傚父");
+ this.$router.push({
+ path: "/followvisit/discharge",
+ query: {
+ errtype: 1,
+ leavehospitaldistrictcode: row.leavehospitaldistrictcode,
+ },
+ });
+ },
+
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.form = {
+ userId: undefined,
+ deptId: undefined,
+ userName: undefined,
+ nickName: undefined,
+ password: undefined,
+ phonenumber: undefined,
+ email: undefined,
+ sex: undefined,
+ status: "0",
+ remark: undefined,
+ postIds: [],
+ roleIds: [],
+ };
+ this.resetForm("form");
+ },
+ // 鏍囩鐘舵�佷慨鏀�
+ handleStatusChange(row) {
+ console.log(row.isupload);
+ let text = row.isupload === "0" ? "鍚敤" : "鍋滅敤";
+ this.$modal
+ .confirm('纭瑕�"' + text + '""' + row.tagname + '"鏍囩鍚楋紵')
+ .then(function () {
+ return changetagcategory(row.tagid, row.isupload);
+ })
+ .then(() => {
+ this.$modal.msgSuccess(text + "鎴愬姛");
+ })
+ .catch(function () {
+ row.isupload = row.isupload === "0" ? "1" : "0";
+ });
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 - 淇敼涓烘悳绱㈠綋鍓嶆縺娲荤殑tab鏁版嵁 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ if (!this.queryParams.dateRange) this.queryParams.dateRange = [];
+ if (this.queryParams.statisticaltype == 1) {
+ this.queryParams.deptcodes = [];
+ } else if (this.queryParams.statisticaltype == 2) {
+ this.queryParams.leavehospitaldistrictcodes = [];
+ }
+
+ this.queryParams.startTime = this.parseTime(
+ this.queryParams.dateRange[0]
+ );
+ this.queryParams.endTime = this.parseTime(this.queryParams.dateRange[1]);
+
+ // 鏍规嵁褰撳墠婵�娲荤殑tab鍔犺浇瀵瑰簲鏁版嵁
+ if (this.activeTab === "first") {
+ this.getFirstFollowUpList();
+ } else {
+ this.getSecondFollowUpList();
+ }
+ },
+
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.queryParams.dateRange = [];
+ this.queryParams.leavehospitaldistrictcodes = [];
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map((item) => item.tagid);
+ this.single = selection.length != 1;
+ this.multiple = !selection.length;
+ },
+
+ /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+ handleDelete(row) {
+ console.log(row, "鍒犻櫎寮圭獥");
+ const tagids = row.tagid || this.ids;
+ console.log(tagids);
+ const tagname = row.tagname;
+ this.$modal
+ .confirm(
+ tagname
+ ? '鏄惁纭鍒犻櫎鏍囩鍚嶇О涓�"' + tagname + '"鐨勬暟鎹」锛�'
+ : "鏄惁纭鍒犻櫎閫変腑鐨勬暟鎹」锛�"
+ )
+ .then(function () {
+ return deletetag(tagids);
+ })
+ .then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ })
+ .catch(() => { });
+ },
+ // 瀵煎嚭鏂规硶
+
+ async exportTable() {
+ try {
+ // 1. 鑾峰彇骞舵牸寮忓寲鏃ユ湡鑼冨洿
+ let dateRangeString = "";
+ let sheetNameSuffix = "";
+
+ if (
+ this.queryParams.dateRange &&
+ this.queryParams.dateRange.length === 2
+ ) {
+ const startDateStr = this.queryParams.dateRange[0];
+ const endDateStr = this.queryParams.dateRange[1];
+ const formatDateForDisplay = (dateTimeStr) => {
+ return dateTimeStr.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;
+ dateRangeString = `${currentMonth}鏈坄;
+ sheetNameSuffix = `${currentMonth}鏈坄;
+ }
+
+ // 2. 鏍规嵁褰撳墠婵�娲荤殑tab纭畾瀵煎嚭鐨勬暟鎹�
+ const isFirstFollowUp = this.activeTab === "first";
+ let excelName, worksheetName, dataToExport;
+
+ if (isFirstFollowUp) {
+ excelName = `棣栨鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
+ worksheetName = `棣栨闅忚缁熻_${sheetNameSuffix}`;
+ dataToExport = this.firstFollowUpList;
+
+ if (!dataToExport || dataToExport.length === 0) {
+ this.$message.warning("鏆傛棤棣栨闅忚鏁版嵁鍙鍑�");
+ return false;
+ }
+ } else {
+ excelName = `鍐嶆鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
+ worksheetName = `鍐嶆闅忚缁熻_${sheetNameSuffix}`;
+ dataToExport = this.secondFollowUpList;
+
+ if (!dataToExport || dataToExport.length === 0) {
+ this.$message.warning("鏆傛棤鍐嶆闅忚鏁版嵁鍙鍑�");
+ return false;
+ }
+ }
+
+ // 3. 鍒涘缓宸ヤ綔绨垮拰宸ヤ綔琛�
+ const workbook = new ExcelJS.Workbook();
+ const worksheet = workbook.addWorksheet(worksheetName);
+
+ // 4. 鏋勫缓琛ㄦ牸
+ if (isFirstFollowUp) {
+ this.buildFirstFollowUpExportSheet(
+ worksheet,
+ dataToExport,
+ sheetNameSuffix
+ );
+ } else {
+ this.buildSecondFollowUpExportSheet(
+ worksheet,
+ dataToExport,
+ sheetNameSuffix
+ );
+ }
+
+ // 5. 鐢熸垚骞朵笅杞芥枃浠�
+ const buffer = await workbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ saveAs(blob, excelName);
+
+ this.$message.success("瀵煎嚭鎴愬姛");
+ return true;
+ } catch (error) {
+ console.error("瀵煎嚭澶辫触:", error);
+ this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+ return false;
+ }
+ },
+ /** 鏋勫缓棣栨闅忚瀵煎嚭琛ㄦ牸 */
+ buildFirstFollowUpExportSheet(worksheet, data, sheetNameSuffix) {
+ 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" } },
+ },
+ };
+
+ const summaryStyle = {
+ font: {
+ name: "瀹嬩綋",
+ size: 10,
+ bold: true,
+ color: { argb: "FF409EFF" },
+ },
+ fill: {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "FFF5F7FA" },
+ },
+ 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" } },
+ },
+ };
+
+ // 1. 娣诲姞鎬绘爣棰樿
+ worksheet.mergeCells(1, 1, 1, 16); // 鍚堝苟A1鍒癙1
+ const titleCell = worksheet.getCell(1, 1);
+ titleCell.value = `棣栨鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`;
+ titleCell.style = titleStyle;
+ worksheet.getRow(1).height = 35;
+
+ // 2. 鍒涘缓琛ㄥご
+ const secondRowHeaders = [
+ "", // A2 灞曞紑鍒楀崰浣�
+ "鍑洪櫌鐥呭尯",
+ "绉戝",
+ "鍑洪櫌浜烘",
+ "鏃犻渶闅忚浜烘",
+ "搴旈殢璁夸汉娆�", // B2 to F2
+ // 棣栨鍑洪櫌闅忚瀛愯〃澶�
+ "闇�闅忚",
+ "寰呴殢璁�",
+ "闅忚鎴愬姛",
+ "闅忚澶辫触",
+ "闅忚鐜�",
+ "鍙婃椂鐜�",
+ "浜哄伐",
+ "鐭俊",
+ "寰俊",
+ ];
+
+ // 娣诲姞绗簩琛�
+ secondRowHeaders.forEach((header, index) => {
+ const cell = worksheet.getCell(3, index + 1);
+ cell.value = header;
+ cell.style = headerStyle;
+ });
+
+ // 3. 鍚堝苟鍗曞厓鏍�
+ // 鍚堝苟 A2:A3, B2:B3, C2:C3, D2:D3, E2:E3, F2:F3
+ for (let i = 1; i <= 6; i++) {
+ worksheet.mergeCells(2, i, 3, i);
+ const cell = worksheet.getCell(2, i);
+ cell.style = headerStyle;
+ }
+
+ // 璁剧疆绗竴琛屽悎骞跺崟鍏冩牸鐨勫��
+ worksheet.getCell(2, 1).value = "";
+ worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
+ worksheet.getCell(2, 3).value = "绉戝";
+ worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
+ worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
+ worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
+
+ // 4. 鍚堝苟"棣栨鍑洪櫌闅忚"鏍囬
+ worksheet.mergeCells(2, 7, 2, 15); // G2:O2
+ worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚";
+ worksheet.getCell(2, 7).style = headerStyle;
+
+ // 5. 璁剧疆琛岄珮
+ worksheet.getRow(2).height = 28;
+ worksheet.getRow(3).height = 25;
+
+ // 6. 娣诲姞鏁版嵁琛�
+ data.forEach((item, rowIndex) => {
+ const dataRow = worksheet.addRow(
+ [
+ "", // 灞曞紑鍒�
+ item.leavehospitaldistrictname || "",
+ item.deptname || "",
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ // 棣栨鍑洪櫌闅忚鏁版嵁
+ item.needFollowUp || 0,
+ item.pendingFollowUp || 0,
+ item.followUpSuccess || 0,
+ item.followUpFail || 0,
+ item.followUpRate || "0%",
+ item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
+ item.manual || 0,
+ item.sms || 0,
+ item.weChat || 0,
+ ],
+ rowIndex + 4
+ );
+
+ // 搴旂敤鏁版嵁琛屾牱寮�
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle;
+ });
+ dataRow.height = 24;
+ });
+
+ // 7. 娣诲姞鍚堣琛�
+ const summaries = this.getFirstFollowUpSummaries(data);
+ const summaryRow = worksheet.addRow(summaries);
+ summaryRow.eachCell((cell, colNumber) => {
+ cell.style = summaryStyle;
+ if (colNumber === 1) {
+ cell.value = "鍚堣";
+ }
+ });
+ summaryRow.height = 28;
+
+ // 8. 璁剧疆鍒楀
+ worksheet.columns = [
+ { width: 8 }, // 灞曞紑鍒�
+ { width: 20 }, // 鍑洪櫌鐥呭尯
+ { width: 15 }, // 绉戝
+ { width: 12 }, // 鍑洪櫌浜烘
+ { width: 12 }, // 鏃犻渶闅忚浜烘
+ { width: 12 }, // 搴旈殢璁夸汉娆�
+ // 棣栨鍑洪櫌闅忚鍒�
+ { width: 10 }, // 闇�闅忚
+ { width: 10 }, // 寰呴殢璁�
+ { width: 10 }, // 闅忚鎴愬姛
+ { width: 10 }, // 闅忚澶辫触
+ { width: 12 }, // 闅忚鐜�
+ { width: 12 }, // 鍙婃椂鐜�
+ { width: 8 }, // 浜哄伐
+ { width: 8 }, // 鐭俊
+ { width: 8 }, // 寰俊
+ ];
+ },
+
+ /** 棣栨闅忚鏁版嵁鍚堣琛岃绠� */
+ getFirstFollowUpSummaries(data) {
+ const summaries = [
+ "鍚堣",
+ "/",
+ "/",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "0%",
+ "0%",
+ 0,
+ 0,
+ 0,
+ ];
+
+ data.forEach((item) => {
+ // 鏁板�煎瓧娈垫眰鍜�
+ summaries[3] += Number(item.dischargeCount) || 0;
+ summaries[4] += Number(item.nonFollowUp) || 0;
+ summaries[5] += Number(item.followUpNeeded) || 0;
+ summaries[6] += Number(item.needFollowUp) || 0;
+ summaries[7] += Number(item.pendingFollowUp) || 0;
+ summaries[8] += Number(item.followUpSuccess) || 0;
+ summaries[9] += Number(item.followUpFail) || 0;
+ summaries[12] += Number(item.manual) || 0;
+ summaries[13] += Number(item.sms) || 0;
+ summaries[14] += Number(item.weChat) || 0;
+ });
+
+ // 璁$畻鐧惧垎姣斿瓧娈电殑骞冲潎鍊�
+ const followUpRateValues = data
+ .map((item) => this.extractPercentageValue(item.followUpRate))
+ .filter((value) => value !== null);
+
+ const rateValues = data
+ .map((item) => this.extractPercentageValue(item.rate))
+ .filter((value) => value !== null);
+
+ if (followUpRateValues.length > 0) {
+ const avgFollowUpRate =
+ followUpRateValues.reduce((sum, val) => sum + val, 0) /
+ followUpRateValues.length;
+ summaries[10] = (avgFollowUpRate * 100).toFixed(2) + "%";
+ }
+
+ if (rateValues.length > 0) {
+ const avgRate =
+ rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length;
+ summaries[11] = (avgRate * 100).toFixed(2) + "%";
+ }
+
+ // 鏍煎紡鍖栨暟瀛�
+ summaries[3] = this.formatNumber(summaries[3]);
+ summaries[4] = this.formatNumber(summaries[4]);
+ summaries[5] = this.formatNumber(summaries[5]);
+ summaries[6] = this.formatNumber(summaries[6]);
+ summaries[7] = this.formatNumber(summaries[7]);
+ summaries[8] = this.formatNumber(summaries[8]);
+ summaries[9] = this.formatNumber(summaries[9]);
+ summaries[12] = this.formatNumber(summaries[12]);
+ summaries[13] = this.formatNumber(summaries[13]);
+ summaries[14] = this.formatNumber(summaries[14]);
+
+ return summaries;
+ },
+
+ /** 鏋勫缓鍐嶆闅忚瀵煎嚭琛ㄦ牸 */
+ buildSecondFollowUpExportSheet(worksheet, data, sheetNameSuffix) {
+ 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" } },
+ },
+ };
+
+ const summaryStyle = {
+ font: {
+ name: "瀹嬩綋",
+ size: 10,
+ bold: true,
+ color: { argb: "FF409EFF" },
+ },
+ fill: {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "FFF5F7FA" },
+ },
+ 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" } },
+ },
+ };
+
+ // 1. 娣诲姞鎬绘爣棰樿
+ worksheet.mergeCells(1, 1, 1, 15); // 鍚堝苟A1鍒癘1
+ const titleCell = worksheet.getCell(1, 1);
+ titleCell.value = `鍐嶆鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`;
+ titleCell.style = titleStyle;
+ worksheet.getRow(1).height = 35;
+
+ // 2. 鍒涘缓琛ㄥご
+ const secondRowHeaders = [
+ "", // A2 灞曞紑鍒楀崰浣�
+ "鍑洪櫌鐥呭尯",
+ "绉戝",
+ "鍑洪櫌浜烘",
+ "鏃犻渶闅忚浜烘",
+ "搴旈殢璁夸汉娆�", // B2 to F2
+ // 鍐嶆鍑洪櫌闅忚瀛愯〃澶�
+ "闇�闅忚",
+ "寰呴殢璁�",
+ "闅忚鎴愬姛",
+ "闅忚澶辫触",
+ "闅忚鐜�",
+ "浜哄伐",
+ "鐭俊",
+ "寰俊",
+ ];
+
+ // 娣诲姞绗簩琛�
+ secondRowHeaders.forEach((header, index) => {
+ const cell = worksheet.getCell(3, index + 1);
+ cell.value = header;
+ cell.style = headerStyle;
+ });
+
+ // 3. 鍚堝苟鍗曞厓鏍�
+ // 鍚堝苟 A2:A3, B2:B3, C2:C3, D2:D3, E2:E3, F2:F3
+ for (let i = 1; i <= 6; i++) {
+ worksheet.mergeCells(2, i, 3, i);
+ const cell = worksheet.getCell(2, i);
+ cell.style = headerStyle;
+ }
+
+ // 璁剧疆绗竴琛屽悎骞跺崟鍏冩牸鐨勫��
+ worksheet.getCell(2, 1).value = "";
+ worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
+ worksheet.getCell(2, 3).value = "绉戝";
+ worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
+ worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
+ worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
+
+ // 4. 鍚堝苟"鍐嶆鍑洪櫌闅忚"鏍囬
+ worksheet.mergeCells(2, 7, 2, 14); // G2:N2
+ worksheet.getCell(2, 7).value = "鍐嶆鍑洪櫌闅忚";
+ worksheet.getCell(2, 7).style = headerStyle;
+
+ // 5. 璁剧疆琛岄珮
+ worksheet.getRow(2).height = 28;
+ worksheet.getRow(3).height = 25;
+
+ // 6. 娣诲姞鏁版嵁琛�
+ data.forEach((item, rowIndex) => {
+ const dataRow = worksheet.addRow(
+ [
+ "", // 灞曞紑鍒�
+ item.leavehospitaldistrictname || "",
+ item.deptname || "",
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ // 鍐嶆鍑洪櫌闅忚鏁版嵁
+ item.needFollowUpAgain || 0,
+ item.pendingFollowUpAgain || 0,
+ item.followUpSuccessAgain || 0,
+ item.followUpFailAgain || 0,
+ item.followUpRateAgain || "0%",
+ item.manualAgain || 0,
+ item.smsAgain || 0,
+ item.weChatAgain || 0,
+ ],
+ rowIndex + 4
+ );
+
+ // 搴旂敤鏁版嵁琛屾牱寮�
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle;
+ });
+ dataRow.height = 24;
+ });
+
+ // 7. 娣诲姞鍚堣琛�
+ const summaries = this.getSecondFollowUpSummaries(data);
+ const summaryRow = worksheet.addRow(summaries);
+ summaryRow.eachCell((cell, colNumber) => {
+ cell.style = summaryStyle;
+ if (colNumber === 1) {
+ cell.value = "鍚堣";
+ }
+ });
+ summaryRow.height = 28;
+
+ // 8. 璁剧疆鍒楀
+ worksheet.columns = [
+ { width: 8 }, // 灞曞紑鍒�
+ { width: 20 }, // 鍑洪櫌鐥呭尯
+ { width: 15 }, // 绉戝
+ { width: 12 }, // 鍑洪櫌浜烘
+ { width: 12 }, // 鏃犻渶闅忚浜烘
+ { width: 12 }, // 搴旈殢璁夸汉娆�
+ // 鍐嶆鍑洪櫌闅忚鍒�
+ { width: 10 }, // 闇�闅忚
+ { width: 10 }, // 寰呴殢璁�
+ { width: 10 }, // 闅忚鎴愬姛
+ { width: 10 }, // 闅忚澶辫触
+ { width: 12 }, // 闅忚鐜�
+ { width: 8 }, // 浜哄伐
+ { width: 8 }, // 鐭俊
+ { width: 8 }, // 寰俊
+ ];
+ },
+
+ /** 鍐嶆闅忚鏁版嵁鍚堣琛岃绠� */
+ getSecondFollowUpSummaries(data) {
+ const summaries = ["鍚堣", "/", "/", 0, 0, 0, 0, 0, 0, 0, "0%", 0, 0, 0];
+
+ data.forEach((item) => {
+ // 鏁板�煎瓧娈垫眰鍜�
+ summaries[3] += Number(item.dischargeCount) || 0;
+ summaries[4] += Number(item.nonFollowUp) || 0;
+ summaries[5] += Number(item.followUpNeeded) || 0;
+ summaries[6] += Number(item.needFollowUpAgain) || 0;
+ summaries[7] += Number(item.pendingFollowUpAgain) || 0;
+ summaries[8] += Number(item.followUpSuccessAgain) || 0;
+ summaries[9] += Number(item.followUpFailAgain) || 0;
+ summaries[11] += Number(item.manualAgain) || 0;
+ summaries[12] += Number(item.smsAgain) || 0;
+ summaries[13] += Number(item.weChatAgain) || 0;
+ });
+
+ // 璁$畻闅忚鐜囩櫨鍒嗘瘮瀛楁鐨勫钩鍧囧��
+ const followUpRateAgainValues = data
+ .map((item) => this.extractPercentageValue(item.followUpRateAgain))
+ .filter((value) => value !== null);
+
+ if (followUpRateAgainValues.length > 0) {
+ const avgFollowUpRateAgain =
+ followUpRateAgainValues.reduce((sum, val) => sum + val, 0) /
+ followUpRateAgainValues.length;
+ summaries[10] = (avgFollowUpRateAgain * 100).toFixed(2) + "%";
+ }
+
+ // 鏍煎紡鍖栨暟瀛�
+ summaries[3] = this.formatNumber(summaries[3]);
+ summaries[4] = this.formatNumber(summaries[4]);
+ summaries[5] = this.formatNumber(summaries[5]);
+ summaries[6] = this.formatNumber(summaries[6]);
+ summaries[7] = this.formatNumber(summaries[7]);
+ summaries[8] = this.formatNumber(summaries[8]);
+ summaries[9] = this.formatNumber(summaries[9]);
+ summaries[11] = this.formatNumber(summaries[11]);
+ summaries[12] = this.formatNumber(summaries[12]);
+ summaries[13] = this.formatNumber(summaries[13]);
+
+ return summaries;
+ },
+
+ /** 鍐嶆闅忚琛ㄦ牸鐨勫悎璁¤璁$畻鏂规硶 */
+ getSummariesSecond(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣";
+ return;
+ }
+ if (index === 1 || index === 2) {
+ sums[index] = "/";
+ return;
+ }
+
+ if (column.property === "followUpRateAgain") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property];
+ if (!value || value === "-" || value === "0%") return null;
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100;
+ return isNaN(numValue) ? null : numValue;
+ } else {
+ const numValue = parseFloat(value);
+ return isNaN(numValue) ? null : numValue;
+ }
+ })
+ .filter((value) => value !== null && value !== 0);
+
+ if (percentageValues.length > 0) {
+ const average =
+ percentageValues.reduce((sum, value) => sum + value, 0) /
+ percentageValues.length;
+ sums[index] = (average * 100).toFixed(2) + "%";
+ } else {
+ sums[index] = "0.00%";
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property];
+ if (value === "-" || value === "" || value === null) return 0;
+ return Number(value) || 0;
+ });
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0);
+ sums[index] = this.formatNumber(sums[index]);
+ } else {
+ sums[index] = "-";
+ }
+ }
+ });
+
+ return sums;
+ },
+ /** 鍐嶆闅忚鍐呴儴琛ㄦ牸鍚堣琛岃绠楁柟娉� */
+ getInnerSummariesSecond(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "灏忚";
+ return;
+ }
+
+ if (column.property === "drname" || column.property === "deptname") {
+ sums[index] = "-";
+ return;
+ }
+
+ if (column.property === "followUpRateAgain") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[column.property];
+ if (!value || value === "-" || value === "0%") return null;
+ if (typeof value === "string" && value.includes("%")) {
+ const numValue = parseFloat(value.replace("%", "")) / 100;
+ return isNaN(numValue) ? null : numValue;
+ } else {
+ const numValue = parseFloat(value);
+ return isNaN(numValue) ? null : numValue;
+ }
+ })
+ .filter((value) => value !== null && value !== 0);
+
+ if (percentageValues.length > 0) {
+ const average =
+ percentageValues.reduce((sum, value) => sum + value, 0) /
+ percentageValues.length;
+ sums[index] = (average * 100).toFixed(2) + "%";
+ } else {
+ sums[index] = "0.00%";
+ }
+ } else {
+ const values = data.map((item) => {
+ const value = item[column.property];
+ if (value === "-" || value === "" || value === null) return 0;
+ return Number(value) || 0;
+ });
+
+ if (!values.every((value) => isNaN(value))) {
+ sums[index] = values.reduce((prev, curr) => prev + curr, 0);
+ sums[index] = this.formatNumber(sums[index]);
+ } else {
+ sums[index] = "-";
+ }
+ }
+ });
+
+ return sums;
+ },
+ /** 鍐嶆闅忚琛ㄦ牸鐨勮鐐瑰嚮灞曞紑 */
+ handleRowClickSecond(row) {
+ if (this.expandsSecond.includes(this.getRowKey(row))) {
+ this.expandsSecond = [];
+ return;
+ }
+
+ const params = {
+ ...this.queryParams,
+ deptcodes: this.queryParams.deptcodes.includes("all")
+ ? this.allDeptCodes
+ : this.queryParams.deptcodes,
+ leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
+ drcode: "1",
+ visitCount: 2, // 璁剧疆涓哄啀娆¢殢璁�
+ };
+
+ delete params.leavehospitaldistrictcodes.all;
+ delete params.deptcodes.all;
+
+ if (!row.doctorStats) {
+ this.loadingSecond = true;
+ getSfStatistics(params).then((res) => {
+ this.$set(row, "doctorStats", res.data);
+ this.expandsSecond = [this.getRowKey(row)];
+ this.loadingSecond = false;
+ });
+ } else {
+ this.expandsSecond = [this.getRowKey(row)];
+ }
+ },
+
+ /** 鍐嶆闅忚琛ㄦ牸鐨勫閫夋閫変腑鏁版嵁 */
+ handleSelectionChangeSecond(selection) {
+ this.idsSecond = selection.map((item) => item.tagid);
+ this.single = selection.length != 1;
+ this.multiple = !selection.length;
+ },
+ // 鏄剧ず鍥捐〃寮圭獥
+
+ showChartDialog() {
+ this.chartDialogVisible = true;
+ this.$nextTick(() => {
+ this.initPieChart();
+ this.initBarLineChart();
+ });
+ },
+ // 鍦╩ethods涓慨鏀圭粺璁℃柟娉�
+ showChartDialog() {
+ this.chartDialogVisible = true;
+ this.$nextTick(() => {
+ console.log(this.userList, "this.userList");
+
+ this.initCharts();
+ });
+ },
+
+ // 鏂板鍒濆鍖栧浘琛ㄦ柟娉�
+ initCharts() {
+ this.initPieChart();
+ this.initBarLineChart();
+ },
+
+ // 鍒濆鍖栭ゼ鍥�
+ initPieChart() {
+ const echarts = require("echarts");
+ const pieDom = document.getElementById("pieChart");
+ if (!pieDom) return;
+
+ if (this.pieChart) {
+ this.pieChart.dispose();
+ }
+
+ this.pieChart = echarts.init(pieDom);
+
+ // 璁$畻楗煎浘鏁版嵁
+ const followUpData = {
+ pending: 0,
+ success: 0,
+ fail: 0,
+ };
+
+ this.userList.forEach((item) => {
+ followUpData.pending += item.pendingFollowUp || 0;
+ followUpData.success += item.followUpSuccess || 0;
+ followUpData.fail += item.followUpFail || 0;
+ });
+
+ // 浣跨敤鏇寸編瑙傜殑棰滆壊鏂规
+ const pieOption = {
+ title: {
+ text: "闅忚鐘舵�佸垎甯�",
+ left: "center",
+ textStyle: {
+ color: "#333",
+ fontSize: 16,
+ },
+ },
+ tooltip: {
+ trigger: "item",
+ formatter: "{a} <br/>{b}: {c} ({d}%)",
+ },
+ legend: {
+ orient: "vertical",
+ left: "left",
+ data: ["寰呴殢璁�", "闅忚鎴愬姛", "闅忚澶辫触"],
+ textStyle: {
+ color: "#666",
+ },
+ },
+ color: ["#FF9D4D", "#36B37E", "#FF5C5C"], // 鏂扮殑閰嶈壊鏂规
+ series: [
+ {
+ name: "闅忚鐘舵��",
+ type: "pie",
+ radius: ["40%", "70%"],
+ avoidLabelOverlap: true,
+ itemStyle: {
+ borderRadius: 10,
+ borderColor: "#fff",
+ borderWidth: 2,
+ },
+ label: {
+ show: true,
+ formatter: "{b}: {c} ({d}%)",
+ color: "#333",
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: "18",
+ fontWeight: "bold",
+ },
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ data: [
+ {
+ value: followUpData.pending,
+ name: "寰呴殢璁�",
+ },
+ {
+ value: followUpData.success,
+ name: "闅忚鎴愬姛",
+ },
+ {
+ value: followUpData.fail,
+ name: "闅忚澶辫触",
+ },
+ ],
+ },
+ ],
+ };
+
+ this.pieChart.setOption(pieOption);
+ window.addEventListener("resize", this.resizePieChart);
+ },
+
+ // 鍒濆鍖栨煴鐘舵姌绾垮浘
+ initBarLineChart() {
+ const echarts = require("echarts");
+ const barDom = document.getElementById("barLineChart");
+ if (!barDom) return;
+
+ if (this.barLineChart) {
+ this.barLineChart.dispose();
+ }
+
+ this.barLineChart = echarts.init(barDom);
+
+ // 鍑嗗鏁版嵁
+ const categories = this.userList.map(
+ (item) => item.leavehospitaldistrictname || item.deptname
+ );
+
+ const dischargeData = this.userList.map(
+ (item) => item.dischargeCount || 0
+ );
+ const followUpData = this.userList.map(
+ (item) => item.followUpNeeded || 0
+ );
+
+ // 鏂板涓ゆ潯鎶樼嚎鏁版嵁
+ const followUpRateData = this.userList.map((item) => {
+ if (!item.followUpRate) return 0;
+ // 鍘绘帀鐧惧垎鍙峰苟杞负鏁板瓧
+ const rateStr = String(item.followUpRate).replace("%", "");
+ return parseFloat(rateStr) || 0;
+ });
+
+ const timelyRateData = this.userList.map((item) =>
+ item.rate ? (Number(item.rate) * 100).toFixed(2) : 0
+ );
+
+ const option = {
+ title: {
+ text: "绉戝/鐥呭尯闅忚瓒嬪娍",
+ left: "center",
+ textStyle: {
+ color: "#333",
+ fontSize: 16,
+ },
+ },
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "cross",
+ crossStyle: {
+ color: "#999",
+ },
+ },
+ },
+ legend: {
+ data: ["鍑洪櫌浜烘", "搴旈殢璁夸汉娆�", "闅忚鐜�(%)", "鍙婃椂鐜�(%)"],
+ top: "bottom",
+ textStyle: {
+ color: "#666",
+ },
+ },
+ color: ["#5470C6", "#91CC75", "#EE6666", "#9A60B4"], // 鏂板绱壊鐢ㄤ簬鍙婃椂鐜�
+ xAxis: {
+ type: "category",
+ data: categories,
+ axisLabel: {
+ interval: 0,
+ rotate: 30,
+ color: "#666",
+ },
+ axisLine: {
+ lineStyle: {
+ color: "#ddd",
+ },
+ },
+ },
+ yAxis: [
+ {
+ type: "value",
+ name: "浜烘",
+ min: 0,
+ axisLabel: {
+ color: "#666",
+ },
+ axisLine: {
+ lineStyle: {
+ color: "#ddd",
+ },
+ },
+ splitLine: {
+ lineStyle: {
+ color: "#f0f0f0",
+ },
+ },
+ },
+ {
+ type: "value",
+ name: "鐧惧垎姣�(%)",
+ min: 0,
+ max: 100,
+ axisLabel: {
+ color: "#666",
+ formatter: "{value}%",
+ },
+ axisLine: {
+ lineStyle: {
+ color: "#ddd",
+ },
+ },
+ splitLine: {
+ show: false,
+ },
+ },
+ ],
+ series: [
+ {
+ name: "鍑洪櫌浜烘",
+ type: "bar",
+ barWidth: "25%",
+ data: dischargeData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0],
+ },
+ },
+ {
+ name: "搴旈殢璁夸汉娆�",
+ type: "bar",
+ barWidth: "25%",
+ data: followUpData,
+ itemStyle: {
+ borderRadius: [4, 4, 0, 0],
+ },
+ },
+ {
+ name: "闅忚鐜�(%)",
+ type: "line",
+ yAxisIndex: 1,
+ data: followUpRateData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3,
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 80,
+ lineStyle: {
+ color: "#EE6666",
+ type: "dashed",
+ },
+ // label: {
+ // position: 'end',
+ // formatter: '鐩爣80%'
+ // }
+ },
+ ],
+ },
+ },
+ {
+ name: "鍙婃椂鐜�(%)",
+ type: "line",
+ yAxisIndex: 1,
+ data: timelyRateData,
+ symbolSize: 8,
+ lineStyle: {
+ width: 3,
+ type: "dotted", // 浣跨敤铏氱嚎鍖哄垎
+ },
+ markLine: {
+ silent: true,
+ data: [
+ {
+ yAxis: 90,
+ lineStyle: {
+ color: "#9A60B4",
+ type: "dashed",
+ },
+ // label: {
+ // position: 'end',
+ // formatter: '鐩爣90%'
+ // }
+ },
+ ],
+ },
+ },
+ ],
+ grid: {
+ top: "15%",
+ left: "3%",
+ right: "4%",
+ bottom: "15%",
+ containLabel: true,
+ },
+ };
+
+ this.barLineChart.setOption(option);
+ window.addEventListener("resize", this.resizeBarLineChart);
+ },
+
+ // 鍥捐〃鍝嶅簲寮忚皟鏁存柟娉�
+ resizePieChart() {
+ if (this.pieChart) {
+ this.pieChart.resize();
+ }
+ },
+
+ resizeBarLineChart() {
+ if (this.barLineChart) {
+ this.barLineChart.resize();
+ }
+ },
+
+ // 鍦ㄧ粍浠堕攢姣佹椂娓呯悊
+ beforeDestroy() {
+ // 绉婚櫎浜嬩欢鐩戝惉
+ window.removeEventListener("resize", this.resizePieChart);
+ window.removeEventListener("resize", this.resizeBarLineChart);
+
+ // 閿�姣佸浘琛ㄥ疄渚�
+ if (this.pieChart) {
+ this.pieChart.dispose();
+ this.pieChart = null;
+ }
+ if (this.barLineChart) {
+ this.barLineChart.dispose();
+ this.barLineChart = null;
+ }
+ },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+::v-deep .el-tabs__header {
+ margin-bottom: 20px;
+}
+
+::v-deep .el-tabs__item {
+ font-size: 16px;
+ padding: 0 20px;
+ height: 40px;
+ line-height: 40px;
+}
+
+::v-deep .el-tabs__active-bar {
+ height: 3px;
+}
+
+/* Tab鍐呭鍖哄煙鏍峰紡 */
+.el-tab-pane {
+ .your-table-container {
+ margin-top: 10px;
+ }
+}
+
+.sidecolumn {
+ width: 180px;
+ min-height: 100vh;
+ text-align: center;
+ // display: flex;
+ margin-top: 20px;
+ margin: 20px;
+ padding: 30px;
+ background: #edf1f7;
+ 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);
+
+ .sidecolumn-top {
+ display: flex;
+ justify-content: space-between;
+
+ .top-wj {
+ font-size: 20px;
+ }
+
+ .top-tj {
+ font-size: 18px;
+
+ color: rgb(0, 89, 255);
+ cursor: pointer;
+ }
+ }
+
+ .center-ss {
+ margin-top: 30px;
+
+ .input-with-select {
+ height: 40px !important;
+ }
+ }
+
+ .bottom-fl {
+ margin-top: 30px;
+ display: center !important;
+ }
+}
+
+.qrcode-dialo {
+ text-align: center;
+ // display: flex;
+ margin: 20px;
+ padding: 30px;
+ background: #edf1f7;
+ 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);
+
+ .qrcode-text {
+ font-size: 20px;
+
+ span {
+ margin-left: 20px;
+ }
+ }
+
+ .qrcode-img {
+ width: 300px;
+ height: 400px;
+ }
+}
+
+::v-deep.el-tabs--left,
+.el-tabs--right {
+ overflow: hidden;
+ align-items: center;
+ display: flex;
+}
+
+::v-deep.el-input--medium .el-input__inner {
+ height: 40px !important;
+}
+
+::v-deep.el-tabs--right .el-tabs__active-bar.is-right {
+ height: 40px;
+ width: 5px;
+ left: 0;
+}
+
+::v-deep.el-tabs--right .el-tabs__item.is-right {
+ display: block;
+ text-align: left;
+ font-size: 20px;
+}
+
+// 缇庡寲鍚堣琛屾牱寮�
+::v-deep .el-table__footer {
+ .el-table__cell {
+ background-color: #f5f7fa;
+ font-weight: 600;
+ color: #409eff;
+
+ .cell {
+ font-weight: 600;
+ color: #409eff;
+ }
+ }
+}
+
+// 鍐呴儴琛ㄦ牸鍚堣琛屾牱寮�
+::v-deep .inner-table .el-table__footer {
+ .el-table__cell {
+ background-color: #ecf5ff;
+ font-weight: 500;
+ color: #67c23a;
+
+ .cell {
+ font-weight: 500;
+ color: #67c23a;
+ }
+ }
+}
+
+// 鐧惧垎姣斿瓧娈电壒娈婃牱寮�
+.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRate"] .cell,
+.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="rate"] .cell,
+.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRateAgain"] .cell {
+ color: #e6a23c !important;
+ font-weight: 700 !important;
+}
+
+.leftvlue {
+ // display: flex;
+ // flex: 1;
+ // width: 80%;
+ // margin-top: 20px;
+ margin: 20px;
+ padding: 30px;
+ background: #ffff;
+ 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);
+
+ .mulsz {
+ font-size: 20px;
+ }
+}
+
+/* 浣胯鏈夋墜鍨嬫寚閽� */
+.el-table__row {
+ cursor: pointer;
+}
+
+/* 鍐呭眰鍖荤敓琛ㄦ牸鏍峰紡 */
+.inner-table {
+
+ // 琛ㄥご鑳屾櫙鑹�
+ ::v-deep .el-table__header-wrapper {
+ background-color: #f0f7ff !important;
+
+ th {
+ background-color: #f0f7ff !important;
+ }
+ }
+
+ // 琛ㄦ牸琛岃儗鏅壊
+ ::v-deep .el-table__body-wrapper {
+ tr {
+ background-color: #f9fbfe !important;
+
+ &:hover {
+ background-color: #e6f1ff !important;
+ }
+ }
+ }
+
+ // 杈规棰滆壊
+ ::v-deep .el-table--border {
+ border-color: #d9e8ff !important;
+
+ td,
+ th {
+ border-color: #d9e8ff !important;
+ }
+ }
+
+ // 鏂戦┈绾规晥鏋�
+ ::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td {
+ background-color: #f5f9ff !important;
+ }
+}
+
+/* 灞曞紑琛屾牱寮� */
+.el-table__expanded-cell {
+ padding: 10px 0 !important;
+ background: #f8f8f8;
+}
+
+.document {
+ width: 100px;
+ height: 50px;
+}
+
+.data-list {
+ max-height: 800px;
+ overflow-y: auto;
+}
+
+.documentf {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.button-text {
+ color: rgb(70, 204, 238);
+}
+
+.button-textck {
+ color: rgb(39, 167, 67);
+}
+
+.button-textxg {
+ color: rgb(35, 81, 233);
+}
+
+.button-textsc {
+ color: rgb(235, 23, 23);
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/index.vue b/src/views/sfstatistics/percentage/index.vue
index 9483d21..911156a 100644
--- a/src/views/sfstatistics/percentage/index.vue
+++ b/src/views/sfstatistics/percentage/index.vue
@@ -1,3679 +1,369 @@
<template>
- <div class="Questionnairemanagement">
- <div class="leftvlue">
- <div class="leftvlue-bg">
- <el-row :gutter="20">
- <!--鏍囩鏁版嵁-->
- <el-col :span="24" :xs="24">
- <el-form
- :model="queryParams"
- ref="queryForm"
- size="small"
- :inline="true"
- v-show="showSearch"
- label-width="98px"
- >
- <el-form-item label="缁熻绫诲瀷" prop="userName">
- <el-select
- v-model="queryParams.statisticaltype"
- placeholder="璇烽�夋嫨缁熻绫诲瀷"
- >
- <el-option
- v-for="item in Statisticallist"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- >
- </el-option>
- </el-select>
- <el-select
- style="margin-left: 10px"
- v-if="queryParams.statisticaltype == 1"
- v-model="queryParams.leavehospitaldistrictcodes"
- size="medium"
- multiple
- filterable
- placeholder="璇烽�夋嫨鐥呭尯"
- >
- <el-option
- v-for="item in flatArrayhospit"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- >
- </el-option>
- </el-select>
- <el-select
- v-else-if="queryParams.statisticaltype == 2"
- v-model="queryParams.deptcodes"
- size="medium"
- multiple
- filterable
- placeholder="璇烽�夋嫨绉戝"
- >
- <el-option
- v-for="item in flatArraydept"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- >
- </el-option>
- </el-select>
- </el-form-item>
+ <div class="follow-up-statistics">
+ <!-- 鎼滅储琛ㄥ崟鍖哄煙 -->
+ <div class="search-section">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="98px">
+ <el-form-item label="缁熻绫诲瀷" prop="userName">
+ <el-select v-model="queryParams.statisticaltype" placeholder="璇烽�夋嫨缁熻绫诲瀷">
+ <el-option v-for="item in Statisticallist" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ <el-select
+ style="margin-left: 10px"
+ v-if="queryParams.statisticaltype == 1"
+ v-model="queryParams.leavehospitaldistrictcodes"
+ size="medium"
+ multiple
+ filterable
+ placeholder="璇烽�夋嫨鐥呭尯"
+ >
+ <el-option v-for="item in flatArrayhospit" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ <el-select
+ v-else-if="queryParams.statisticaltype == 2"
+ v-model="queryParams.deptcodes"
+ size="medium"
+ multiple
+ filterable
+ placeholder="璇烽�夋嫨绉戝"
+ >
+ <el-option v-for="item in flatArraydept" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
- <el-form-item label="鏈嶅姟绫诲瀷" prop="userName">
- <el-select
- v-model="queryParams.serviceType"
- multiple
- placeholder="璇烽�夋嫨"
- >
- <el-option
- v-for="item in options"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- >
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item
- label-width="200"
- label="搴旈殢璁挎椂闂磋寖鍥�"
- prop="userName"
- >
- <el-date-picker
- v-model="queryParams.dateRange"
- value-format="yyyy-MM-dd HH:mm:ss"
- type="daterange"
- range-separator="鑷�"
- start-placeholder="寮�濮嬫棩鏈�"
- end-placeholder="缁撴潫鏃ユ湡"
- :default-time="['00:00:00', '23:59:59']"
- >
- </el-date-picker>
- </el-form-item>
+ <el-form-item label="鏈嶅姟绫诲瀷" prop="userName">
+ <el-select v-model="queryParams.serviceType" multiple placeholder="璇烽�夋嫨">
+ <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </el-form-item>
- <el-form-item>
- <el-button
- type="primary"
- icon="el-icon-search"
- size="medium"
- @click="handleQuery"
- >鎼滅储</el-button
- >
- <el-button
- icon="el-icon-refresh"
- size="medium"
- @click="resetQuery"
- >閲嶇疆</el-button
- >
- </el-form-item>
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="medium"
- @click="exportTable"
- >瀵煎嚭</el-button
- >
- <el-button
- type="primary"
- plain
- icon="el-icon-data-line"
- size="medium"
- @click="showChartDialog"
- >缁熻瓒嬪娍鍥�</el-button
- >
- </el-form>
-
- <!-- 鏂板锛歍ab鏍囩椤� -->
- <el-tabs v-model="activeTab" @tab-click="handleTabClick">
- <el-tab-pane label="棣栨闅忚" name="first">
- <div class="your-table-container">
- <el-table
- ref="exportTable"
- id="exportTableid"
- v-loading="loading"
- :data="firstFollowUpList"
- :border="true"
- @selection-change="handleSelectionChange"
- @expand-change="handleRowClick"
- :row-key="getRowKey"
- show-summary
- :summary-method="getSummaries"
- :expand-row-keys="expands"
- >
- <!-- 灞曞紑琛岀澶村垪 -->
- <el-table-column type="expand">
- <template slot-scope="props">
- <el-table
- :data="props.row.doctorStats"
- border
- style="width: 95%; margin: 0 auto"
- class="inner-table"
- show-summary
- :summary-method="getInnerSummaries"
- >
- <el-table-column
- label="鍖荤敓濮撳悕"
- prop="drname"
- align="center"
- />
- <el-table-column
- label="绉戝"
- width="120"
- prop="deptname"
- align="center"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- prop="dischargeCount"
- align="center"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- align="center"
- key="dischargeCount"
- prop="dischargeCount"
- >
- </el-table-column>
-
- <el-table-column
- label="鏃犻渶闅忚浜烘"
- align="center"
- width="100"
- key="nonFollowUp"
- prop="nonFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="搴旈殢璁夸汉娆�"
- align="center"
- width="100"
- key="followUpNeeded"
- prop="followUpNeeded"
- >
- </el-table-column>
- <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
- <el-table-column
- label="闇�闅忚"
- align="center"
- key="needFollowUp"
- prop="needFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="寰呴殢璁�"
- align="center"
- key="pendingFollowUp"
- prop="pendingFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="闅忚鎴愬姛"
- align="center"
- key="followUpSuccess"
- prop="followUpSuccess"
- >
- </el-table-column>
- <el-table-column
- label="闅忚澶辫触"
- align="center"
- key="followUpFail"
- prop="followUpFail"
- >
- </el-table-column>
- <el-table-column
- label="闅忚鐜�"
- align="center"
- width="120"
- key="followUpRate"
- prop="followUpRate"
- >
- </el-table-column>
- <el-table-column
- v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
- label="鍙婃椂鐜�"
- align="center"
- width="120"
- key="rate"
- prop="rate"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="Seedetails(scope.row)"
- ><span class="button-zx"
- >{{
- (Number(scope.row.rate) * 100).toFixed(2)
- }}%</span
- ></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="浜哄伐"
- align="center"
- key="manual"
- prop="manual"
- >
- </el-table-column>
- <el-table-column
- label="鐭俊"
- align="center"
- key="sms"
- prop="sms"
- >
- </el-table-column>
- <el-table-column
- label="寰俊"
- align="center"
- key="weChat"
- prop="weChat"
- >
- </el-table-column>
- </el-table-column>
- </el-table>
- </template>
- </el-table-column>
- <el-table-column
- label="鍑洪櫌鐥呭尯"
- align="center"
- sortable
- key="leavehospitaldistrictname"
- prop="leavehospitaldistrictname"
- width="150"
- :show-overflow-tooltip="true"
- :sort-method="sortChineseNumber"
- />
- <el-table-column
- label="绉戝"
- align="center"
- key="deptname"
- prop="deptname"
- :show-overflow-tooltip="true"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- align="center"
- key="dischargeCount"
- prop="dischargeCount"
- >
- </el-table-column>
-
- <el-table-column
- label="鏃犻渶闅忚浜烘"
- align="center"
- width="100"
- key="nonFollowUp"
- prop="nonFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="搴旈殢璁夸汉娆�"
- align="center"
- width="100"
- key="followUpNeeded"
- prop="followUpNeeded"
- >
- </el-table-column>
- <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
- <el-table-column
- label="闇�闅忚"
- align="center"
- key="needFollowUp"
- prop="needFollowUp"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.needFollowUpInfo,
- scope.row.leavehospitaldistrictname +
- '闇�闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.needFollowUp
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="寰呴殢璁�"
- align="center"
- key="pendingFollowUp"
- prop="pendingFollowUp"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.pendingFollowUpInfo,
- scope.row.leavehospitaldistrictname +
- '寰呴殢璁垮垪琛�'
- )
- "
- ><span class="button-zx">{{
- scope.row.pendingFollowUp
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚鎴愬姛"
- align="center"
- key="followUpSuccess"
- prop="followUpSuccess"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.followUpSuccessInfo,
- scope.row.leavehospitaldistrictname +
- '闅忚鎴愬姛鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.followUpSuccess
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚澶辫触"
- align="center"
- key="followUpFail"
- prop="followUpFail"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.followUpFailInfo,
- scope.row.leavehospitaldistrictname +
- '闅忚澶辫触鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.followUpFail
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚鐜�"
- align="center"
- width="120"
- key="followUpRate"
- prop="followUpRate"
- >
- </el-table-column>
- <el-table-column
- v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
- label="鍙婃椂鐜�"
- align="center"
- width="120"
- key="rate"
- prop="rate"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="Seedetails(scope.row)"
- ><span class="button-zx"
- >{{
- (Number(scope.row.rate) * 100).toFixed(2)
- }}%</span
- ></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="浜哄伐"
- align="center"
- key="manual"
- prop="manual"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.manualInfo,
- scope.row.leavehospitaldistrictname +
- '浜哄伐闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.manual
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="鐭俊"
- align="center"
- key="sms"
- prop="sms"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.smsInfo,
- scope.row.leavehospitaldistrictname +
- '鐭俊闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.sms
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="寰俊"
- align="center"
- key="weChat"
- prop="weChat"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.weChatInfo,
- scope.row.leavehospitaldistrictname +
- '寰俊闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.weChat
- }}</span></el-button
- >
- </template>
- </el-table-column>
- </el-table-column>
-
- <!-- 闅忚鎯呭喌鍒楋紙浠呬附姘村競涓尰闄㈡樉绀猴級 -->
- <el-table-column
- v-if="orgname == '涓芥按甯備腑鍖婚櫌'"
- align="center"
- label="闅忚鎯呭喌"
- >
- <el-table-column
- label="姝e父璇煶"
- align="center"
- width="100"
- key="taskSituation1"
- prop="taskSituation1"
- >
- </el-table-column
- ><el-table-column
- label="鎮h�呮嫆鎺ユ垨鎷掕"
- align="center"
- width="100"
- key="taskSituation2"
- prop="taskSituation2"
- >
- </el-table-column
- ><el-table-column
- label="闈㈣鎴栬�呮帴璇�"
- align="center"
- width="100"
- key="taskSituation3"
- prop="taskSituation3"
- >
- </el-table-column
- ><el-table-column
- label="寰俊闅忚"
- align="center"
- width="100"
- key="taskSituation4"
- prop="taskSituation4"
- >
- </el-table-column
- ><el-table-column
- label="闅忚鐢佃瘽涓嶆纭�"
- align="center"
- width="100"
- key="taskSituation5"
- prop="taskSituation5"
- >
- </el-table-column
- ><el-table-column
- label="鍏朵粬鎯呭喌涓嶅疁闅忚"
- align="center"
- width="100"
- key="taskSituation6"
- prop="taskSituation6"
- >
- </el-table-column>
- </el-table-column>
- </el-table>
- </div>
- </el-tab-pane>
-
- <el-tab-pane label="鍐嶆闅忚" name="second">
- <div class="your-table-container">
- <el-table
- ref="exportTableSecond"
- id="exportTableidSecond"
- v-loading="loadingSecond"
- :data="secondFollowUpList"
- :border="true"
- @selection-change="handleSelectionChangeSecond"
- @expand-change="handleRowClickSecond"
- :row-key="getRowKey"
- show-summary
- :summary-method="getSummariesSecond"
- :expand-row-keys="expandsSecond"
- >
- <!-- 灞曞紑琛岀澶村垪 -->
- <el-table-column type="expand">
- <template slot-scope="props">
- <el-table
- :data="props.row.doctorStats"
- border
- style="width: 95%; margin: 0 auto"
- class="inner-table"
- show-summary
- :summary-method="getInnerSummariesSecond"
- >
- <el-table-column
- label="鍖荤敓濮撳悕"
- prop="drname"
- align="center"
- />
- <el-table-column
- label="绉戝"
- width="120"
- prop="deptname"
- align="center"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- prop="dischargeCount"
- align="center"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- align="center"
- key="dischargeCount"
- prop="dischargeCount"
- >
- </el-table-column>
-
- <el-table-column
- label="鏃犻渶闅忚浜烘"
- align="center"
- width="100"
- key="nonFollowUp"
- prop="nonFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="搴旈殢璁夸汉娆�"
- align="center"
- width="100"
- key="followUpNeeded"
- prop="followUpNeeded"
- >
- </el-table-column>
- <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
- <el-table-column
- label="闇�闅忚"
- align="center"
- key="needFollowUpAgain"
- prop="needFollowUpAgain"
- >
- </el-table-column>
- <el-table-column
- label="寰呴殢璁�"
- align="center"
- key="pendingFollowUpAgain"
- prop="pendingFollowUpAgain"
- >
- </el-table-column>
- <el-table-column
- label="闅忚鎴愬姛"
- align="center"
- key="followUpSuccessAgain"
- prop="followUpSuccessAgain"
- >
- </el-table-column>
- <el-table-column
- label="闅忚澶辫触"
- align="center"
- key="followUpFailAgain"
- prop="followUpFailAgain"
- >
- </el-table-column>
- <el-table-column
- label="闅忚鐜�"
- align="center"
- width="120"
- key="followUpRateAgain"
- prop="followUpRateAgain"
- >
- </el-table-column>
- <el-table-column
- label="浜哄伐"
- align="center"
- key="manualAgain"
- prop="manualAgain"
- >
- </el-table-column>
- <el-table-column
- label="鐭俊"
- align="center"
- key="smsAgain"
- prop="smsAgain"
- >
- </el-table-column>
- <el-table-column
- label="寰俊"
- align="center"
- key="weChatAgain"
- prop="weChatAgain"
- >
- </el-table-column>
- </el-table-column>
- </el-table>
- </template>
- </el-table-column>
- <el-table-column
- label="鍑洪櫌鐥呭尯"
- align="center"
- sortable
- key="leavehospitaldistrictname"
- prop="leavehospitaldistrictname"
- width="150"
- :show-overflow-tooltip="true"
- :sort-method="sortChineseNumber"
- />
- <el-table-column
- label="绉戝"
- align="center"
- key="deptname"
- prop="deptname"
- :show-overflow-tooltip="true"
- />
- <el-table-column
- label="鍑洪櫌浜烘"
- align="center"
- key="dischargeCount"
- prop="dischargeCount"
- >
- </el-table-column>
-
- <el-table-column
- label="鏃犻渶闅忚浜烘"
- align="center"
- width="100"
- key="nonFollowUp"
- prop="nonFollowUp"
- >
- </el-table-column>
- <el-table-column
- label="搴旈殢璁夸汉娆�"
- align="center"
- width="100"
- key="followUpNeeded"
- prop="followUpNeeded"
- >
- </el-table-column>
- <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
- <el-table-column
- label="闇�闅忚"
- align="center"
- key="needFollowUpAgain"
- prop="needFollowUpAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.needFollowUpAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚闇�闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.needFollowUpAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="寰呴殢璁�"
- align="center"
- key="pendingFollowUpAgain"
- prop="pendingFollowUpAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.pendingFollowUpAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚寰呴殢璁垮垪琛�'
- )
- "
- ><span class="button-zx">{{
- scope.row.pendingFollowUpAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚鎴愬姛"
- align="center"
- key="followUpSuccessAgain"
- prop="followUpSuccessAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.followUpSuccessAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚闅忚鎴愬姛鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.followUpSuccessAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚澶辫触"
- align="center"
- key="followUpFailAgain"
- prop="followUpFailAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.followUpFailAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚闅忚澶辫触鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.followUpFailAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="闅忚鐜�"
- align="center"
- width="120"
- key="followUpRateAgain"
- prop="followUpRateAgain"
- >
- </el-table-column>
- <el-table-column
- label="浜哄伐"
- align="center"
- key="manualAgain"
- prop="manualAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.manualAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚浜哄伐闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.manualAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="鐭俊"
- align="center"
- key="smsAgain"
- prop="smsAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.smsAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚鐭俊闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.smsAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- <el-table-column
- label="寰俊"
- align="center"
- key="weChatAgain"
- prop="weChatAgain"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="
- viewDetails(
- scope.row.weChatAgainInfo,
- scope.row.leavehospitaldistrictname +
- '鍐嶆闅忚寰俊闅忚鍒楄〃'
- )
- "
- ><span class="button-zx">{{
- scope.row.weChatAgain
- }}</span></el-button
- >
- </template>
- </el-table-column>
- </el-table-column>
- </el-table>
- </div>
- </el-tab-pane>
- </el-tabs>
-
- <!-- 鍘熸潵鐨勫垎椤电粍浠朵繚鐣欙紙濡傛灉闇�瑕侊級 -->
- <!-- <pagination
- v-show="total > 0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- /> -->
- </el-col>
- </el-row>
- </div>
- </div>
- <!-- 缁熻瓒嬪娍鍥惧脊绐� -->
- <el-dialog
- title="闅忚缁熻瓒嬪娍鍥�"
- :visible.sync="chartDialogVisible"
- width="80%"
- :close-on-click-modal="false"
- >
- <div class="chart-container">
- <el-row :gutter="20">
- <el-col :span="12">
- <div class="chart-title">闅忚鐘舵�佸垎甯�</div>
- <div id="pieChart" style="width: 100%; height: 400px"></div>
- </el-col>
- <el-col :span="12">
- <div class="chart-title">闅忚瓒嬪娍鍒嗘瀽</div>
- <div id="barLineChart" style="width: 100%; height: 400px"></div>
- </el-col>
- </el-row>
- </div>
- </el-dialog>
- <el-dialog
- title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�"
- :visible.sync="SeedetailsVisible"
- v-loading="Seedloading"
- width="70%"
- :close-on-click-modal="false"
- >
- <div class="examine-jic">
- <div class="jic-value">
- <el-row :gutter="20">
- <!--鐢ㄦ埛鏁版嵁-->
- <el-form
- :model="patientqueryParams"
- ref="queryForm"
- size="small"
- :inline="true"
- label-width="98px"
- >
- <el-form-item label="鎮h�咃細">
- <el-input
- v-model="patientqueryParams.name"
- @keyup.enter.native="handleQuery"
- ></el-input>
- </el-form-item>
- <el-form-item label="鎮h�呰瘖鏂細">
- <el-input
- v-model="patientqueryParams.leavediagname"
- @keyup.enter.native="handleQuery"
- ></el-input>
- </el-form-item>
-
- <el-form-item>
- <el-button
- type="primary"
- icon="el-icon-search"
- size="medium"
- @click="handleQuery"
- >鎼滅储</el-button
- >
- <el-button
- icon="el-icon-refresh"
- size="medium"
- @click="resetQuery"
- >鍙栨秷鍒涘缓</el-button
- >
- </el-form-item>
- </el-form>
- <!-- 閫夋嫨鎮h�呭垪琛� -->
- <el-table :data="logsheetlist" style="width: 100%">
- <el-table-column
- prop="sendname"
- align="center"
- label="濮撳悕"
- width="100"
- >
- </el-table-column>
- <el-table-column
- prop="taskName"
- align="center"
- width="200"
- show-overflow-tooltip
- label="浠诲姟鍚嶇О"
- >
- </el-table-column>
- <el-table-column
- prop="sendstate"
- align="center"
- width="200"
- label="浠诲姟鐘舵��"
- >
- <template slot-scope="scope">
- <div v-if="scope.row.sendstate == 1">
- <el-tag type="primary" :disable-transitions="false"
- >琛ㄥ崟宸查鍙�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 2">
- <el-tag type="primary" :disable-transitions="false"
- >寰呴殢璁�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 3">
- <el-tag type="success" :disable-transitions="false"
- >琛ㄥ崟宸插彂閫�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 4">
- <el-tag type="info" :disable-transitions="false"
- >涓嶆墽琛�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 5">
- <el-tag type="danger" :disable-transitions="false"
- >鍙戦�佸け璐�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 6">
- <el-tag type="success" :disable-transitions="false"
- >宸插畬鎴�</el-tag
- >
- </div>
- </template>
- </el-table-column>
- <el-table-column
- prop="visitTime"
- align="center"
- label="搴旈殢璁挎椂闂�"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- prop="finishtime"
- align="center"
- label="闅忚瀹屾垚鏃堕棿"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- label="鍑洪櫌鏃ユ湡"
- width="200"
- align="center"
- key="endtime"
- prop="endtime"
- >
- <template slot-scope="scope">
- <span>{{ formatTime(scope.row.endtime) }}</span>
- </template></el-table-column
- >
- <el-table-column
- label="璐d换鎶ゅ+"
- width="120"
- align="center"
- key="nurseName"
- prop="nurseName"
- />
- <el-table-column
- label="涓绘不鍖荤敓"
- width="120"
- align="center"
- key="drname"
- prop="drname"
- />
-
- <el-table-column
- label="缁撴灉鐘舵��"
- align="center"
- key="excep"
- prop="excep"
- width="120"
- >
- <template slot-scope="scope">
- <dict-tag
- :options="dict.type.sys_yujing"
- :value="scope.row.excep"
- />
- </template>
- </el-table-column>
- <el-table-column
- label="澶勭悊鎰忚"
- align="center"
- key="suggest"
- prop="suggest"
- width="120"
- >
- <template slot-scope="scope">
- <dict-tag
- :options="dict.type.sys_suggest"
- :value="scope.row.suggest"
- />
- </template>
- </el-table-column>
-
- <el-table-column
- prop="templatename"
- align="center"
- label="鏈嶅姟妯℃澘"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- prop="remark"
- align="center"
- label="鏈嶅姟璁板綍"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
-
- <el-table-column
- prop="bankcardno"
- align="center"
- label="鍛煎彨鐘舵��"
- width="210"
- >
- </el-table-column>
- <el-table-column
- label="鎿嶄綔"
- fixed="right"
- align="center"
- width="200"
- class-name="small-padding fixed-width"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="SeedetailsgGo(scope.row)"
- ><span class="button-zx"
- ><i class="el-icon-s-order"></i>鏌ョ湅</span
- ></el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </el-row>
- <pagination
- v-show="patienttotal > 0 && this.patientqueryParams.allhosp != 6"
- :total="patienttotal"
- :page.sync="patientqueryParams.pn"
- :limit.sync="patientqueryParams.ps"
- @pagination="Seedetailstion"
+ <el-form-item label-width="200" label="搴旈殢璁挎椂闂磋寖鍥�" prop="userName">
+ <el-date-picker
+ v-model="queryParams.dateRange"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ :default-time="['00:00:00', '23:59:59']"
/>
- </div>
- </div>
- </el-dialog>
- <!-- 鍚勭被璇︽儏 -->
- <el-dialog
+ </el-form-item>
+
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="medium" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="medium" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+
+ <el-button type="warning" plain icon="el-icon-download" size="medium" @click="handleExport">瀵煎嚭</el-button>
+ <el-button type="primary" plain icon="el-icon-data-line" size="medium" @click="showChartDialog">缁熻瓒嬪娍鍥�</el-button>
+ </el-form>
+ </div>
+
+ <!-- Tab鍒囨崲鍖哄煙 -->
+ <div class="tab-section">
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+ <el-tab-pane label="棣栨闅忚" name="first">
+ <FirstFollowUp
+ ref="firstFollowUp"
+ :query-params="queryParams"
+ :flat-array-hospit="flatArrayhospit"
+ :flat-array-dept="flatArraydept"
+ :options="options"
+ :orgname="orgname"
+ @view-details="viewDetails"
+ @see-details="Seedetails"
+ />
+ </el-tab-pane>
+
+ <el-tab-pane label="鍐嶆闅忚" name="second">
+ <SecondFollowUp
+ ref="secondFollowUp"
+ :query-params="queryParams"
+ :flat-array-hospit="flatArrayhospit"
+ :flat-array-dept="flatArraydept"
+ :options="options"
+ :orgname="orgname"
+ @view-details="viewDetails"
+ />
+ </el-tab-pane>
+
+ <el-tab-pane label="寤剁画鎶ょ悊缁熻" name="continued" v-if="orgname == '鐪佺珛鍚屽痉缈犺嫅闄㈠尯'">
+ <ContinuedCare
+ ref="continuedCare"
+ :query-params="queryParams"
+ :flat-array-hospit="flatArrayhospit"
+ :flat-array-dept="flatArraydept"
+ :options="options"
+ :orgname="orgname"
+ @view-details="viewDetails"
+ />
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+
+ <!-- 寮圭獥鍖哄煙 -->
+ <ChartDialog
+ :visible="chartDialogVisible"
+ :data="chartData"
+ :active-tab="activeTab"
+ @close="chartDialogVisible = false"
+ />
+
+ <DetailDialog
+ :visible="infotitleVisible"
:title="infotitle"
- :visible.sync="infotitleVisible"
- v-loading="infotitloading"
- width="70%"
- :close-on-click-modal="false"
- >
- <div style="margin-bottom: 16px; display: flex; align-items: center">
- <span style="margin-right: 10px; font-weight: bold">鎮h�呭鍚嶆煡璇�:</span>
- <el-input
- v-model="searchName"
- placeholder="璇疯緭鍏ユ偅鑰呭鍚嶈繘琛岀瓫閫�"
- clearable
- style="width: 300px"
- @input="handleSearch"
- @clear="handleSearch"
- >
- </el-input>
- <span
- style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px"
- >
- 鍏� {{ infotitlelist.length }} 鏉¤褰�
- </span>
- </div>
- <div class="examine-jic">
- <div class="jic-value">
- <el-row :gutter="20">
- <!-- 閫夋嫨鎮h�呭垪琛� -->
- <div
- class="data-list"
- ref="dataList"
- @scroll="handleScroll"
- v-loading="infotitloading"
- >
- <el-table
- :data="currentDisplayList"
- height="660"
- style="width: 100%"
- >
- <el-table-column
- prop="sendname"
- align="center"
- label="濮撳悕"
- width="100"
- >
- </el-table-column>
- <el-table-column
- prop="taskName"
- align="center"
- width="200"
- show-overflow-tooltip
- label="浠诲姟鍚嶇О"
- >
- </el-table-column>
- <el-table-column
- prop="sendstate"
- align="center"
- width="200"
- label="浠诲姟鐘舵��"
- >
- <template slot-scope="scope">
- <div v-if="scope.row.sendstate == 1">
- <el-tag type="primary" :disable-transitions="false"
- >琛ㄥ崟宸查鍙�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 2">
- <el-tag type="primary" :disable-transitions="false"
- >寰呴殢璁�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 3">
- <el-tag type="success" :disable-transitions="false"
- >琛ㄥ崟宸插彂閫�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 4">
- <el-tag type="info" :disable-transitions="false"
- >涓嶆墽琛�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 5">
- <el-tag type="danger" :disable-transitions="false"
- >鍙戦�佸け璐�</el-tag
- >
- </div>
- <div v-if="scope.row.sendstate == 6">
- <el-tag type="success" :disable-transitions="false"
- >宸插畬鎴�</el-tag
- >
- </div>
- </template>
- </el-table-column>
- <el-table-column
- label="浠诲姟鎵ц鏂瑰紡"
- align="center"
- key="preachform"
- prop="preachform"
- width="160"
- :show-overflow-tooltip="true"
- >
- <template slot-scope="scope">
- <span v-for="item in scope.row.preachform"
- >{{ item }}銆�
- </span>
- </template>
- </el-table-column>
- <el-table-column
- prop="visitTime"
- align="center"
- label="搴旈殢璁挎椂闂�"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- prop="finishtime"
- align="center"
- label="闅忚瀹屾垚鏃堕棿"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- label="鍑洪櫌鏃ユ湡"
- width="200"
- align="center"
- key="endtime"
- prop="endtime"
- >
- <template slot-scope="scope">
- <span>{{ formatTime(scope.row.endtime) }}</span>
- </template></el-table-column
- >
- <el-table-column
- label="璐d换鎶ゅ+"
- width="120"
- align="center"
- key="nurseName"
- prop="nurseName"
- />
- <el-table-column
- label="涓绘不鍖荤敓"
- width="120"
- align="center"
- key="drname"
- prop="drname"
- />
+ :data="infotitlelist"
+ :search-name="searchName"
+ @close="infotitleVisible = false"
+ @search="handleSearch"
+ @details-go="SeedetailsgGo"
+ />
- <el-table-column
- label="缁撴灉鐘舵��"
- align="center"
- key="excep"
- prop="excep"
- width="120"
- >
- <template slot-scope="scope">
- <dict-tag
- :options="dict.type.sys_yujing"
- :value="scope.row.excep"
- />
- </template>
- </el-table-column>
- <el-table-column
- label="澶勭悊鎰忚"
- align="center"
- key="suggest"
- prop="suggest"
- width="120"
- >
- <template slot-scope="scope">
- <dict-tag
- :options="dict.type.sys_suggest"
- :value="scope.row.suggest"
- />
- </template>
- </el-table-column>
-
- <el-table-column
- prop="templatename"
- align="center"
- label="鏈嶅姟妯℃澘"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- prop="remark"
- align="center"
- label="鏈嶅姟璁板綍"
- width="200"
- show-overflow-tooltip
- >
- </el-table-column>
-
- <el-table-column
- prop="bankcardno"
- align="center"
- label="鍛煎彨鐘舵��"
- width="210"
- >
- </el-table-column>
- <el-table-column
- label="鎿嶄綔"
- fixed="right"
- align="center"
- width="200"
- class-name="small-padding fixed-width"
- >
- <template slot-scope="scope">
- <el-button
- size="medium"
- type="text"
- @click="SeedetailsgGo(scope.row)"
- ><span class="button-zx"
- ><i class="el-icon-s-order"></i>鏌ョ湅</span
- ></el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </div>
- </el-row>
- </div>
- </div>
- </el-dialog>
+ <TimelyRateDialog
+ :visible="SeedetailsVisible"
+ :loading="Seedloading"
+ :data="logsheetlist"
+ :total="patienttotal"
+ :query-params="patientqueryParams"
+ @close="SeedetailsVisible = false"
+ @search="Seedetailstion"
+ @details-go="SeedetailsgGo"
+ />
</div>
</template>
<script>
-import {
- toamendtag,
- addapitag,
- deletetag,
- changetagcategory,
-} from "@/api/system/label";
-import store from "@/store";
-import { getSfStatistics, selectTimelyRate } from "@/api/system/user";
-import * as XLSX from "xlsx";
-import FileSaver from "file-saver";
-import ExcelJS from "exceljs";
-import { saveAs } from "file-saver";
-import Treeselect from "@riophae/vue-treeselect";
-import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import FirstFollowUp from './components/FirstFollowUp.vue'
+import SecondFollowUp from './components/SecondFollowUp.vue'
+import ContinuedCare from './components/ContinuedCare.vue'
+import ChartDialog from './components/ChartDialog.vue'
+import DetailDialog from './components/DetailDialog.vue'
+import TimelyRateDialog from './components/TimelyRateDialog.vue'
-const shortcuts = [
- {
- text: "浠婂ぉ",
- onClick(picker) {
- picker.$emit("pick", new Date());
- },
- },
- {
- text: "鏄ㄥぉ",
- onClick(picker) {
- const date = new Date();
- date.setTime(date.getTime() - 3600 * 1000 * 24);
- picker.$emit("pick", date);
- },
- },
- {
- text: "涓�鍛ㄥ墠",
- onClick(picker) {
- const date = new Date();
- date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
- picker.$emit("pick", date);
- },
- },
-];
export default {
- name: "Percentage",
- dicts: ["sys_normal_disable", "sys_user_sex"],
- components: { Treeselect },
+ name: 'FollowUpStatistics',
+ components: {
+ FirstFollowUp,
+ SecondFollowUp,
+ ContinuedCare,
+ ChartDialog,
+ DetailDialog,
+ TimelyRateDialog
+ },
data() {
return {
- // 鏂板锛歍ab鏍囩椤垫帶鍒�
- activeTab: "first", // 褰撳墠婵�娲荤殑tab锛宖irst-棣栨闅忚锛宻econd-鍐嶆闅忚
-
- // 鍒嗙鐨勬暟鎹垪琛�
- firstFollowUpList: [], // 棣栨闅忚鏁版嵁
- secondFollowUpList: [], // 鍐嶆闅忚鏁版嵁
-
- // 鍒嗙鐨勫姞杞界姸鎬�
- loading: false, // 棣栨闅忚琛ㄦ牸鍔犺浇鐘舵��
- loadingSecond: false, // 鍐嶆闅忚琛ㄦ牸鍔犺浇鐘舵��
-
- // 鍒嗙鐨勫睍寮�鐘舵��
- expands: [], // 棣栨闅忚琛ㄦ牸灞曞紑琛�
- expandsSecond: [], // 鍐嶆闅忚琛ㄦ牸灞曞紑琛�
-
- // 鍒嗙鐨勯�夋嫨鐘舵��
- ids: [], // 棣栨闅忚閫変腑椤�
- idsSecond: [], // 鍐嶆闅忚閫変腑椤�
-
- orgname: "",
- infotitlelist: [],
- currentDisplayList: [],
- loadIndex: 0,
- pageSize: 100,
- isLoading: false,
-
- Seedloading: false,
- chartDialogVisible: false,
- infotitleVisible: false,
- searchName: "",
- infotitloading: false,
- infotitle: "",
- pieChart: null,
- barLineChart: null,
-
- single: true,
- multiple: true,
- showSearch: true,
- idds: "",
- total: 0,
- flatArrayhospit: [],
- flatArraydept: [],
- patienttotal: 0,
- logsheetlist: [],
+ activeTab: 'first',
+ orgname: localStorage.getItem('orgname') || '',
Statisticallist: [
- {
- label: "鐥呭尯缁熻",
- value: 1,
- },
- {
- label: "绉戝缁熻",
- value: 2,
- },
+ { label: '鐥呭尯缁熻', value: 1 },
+ { label: '绉戝缁熻', value: 2 }
],
- patientqueryParams: {
- pn: 1,
- ps: 10,
- },
- amendtag: false,
- lstamendtag: false,
- scavisible: false,
- deleteVisible: false,
- deletefenl: "楂樿鍘�",
- tagform: {
- isupload: "",
- tagname: "",
- tagcategoryid: "",
- tagdescription: "",
- },
- classifyform: {
- categoryname: "",
- },
- title: "",
- open: false,
- dateRange: [],
- postOptions: [],
- roleOptions: [],
- allDeptCodes: [],
- allWardCodes: [],
- checkboxlist: [],
- form: {},
- forms: {
- name: "",
- },
- numberlb: 22,
- dialogFormVisible: false,
- lstamendtagVisible: false,
- goQRCodeVisible: false,
- sidecolumnval: "",
- propss: { multiple: true },
- SeedetailsVisible: false,
- options: store.getters.tasktypes,
- pickerOptions: {
- disabledDate(time) {
- return time.getTime() < Date.now() - 3600 * 1000 * 24;
- },
- shortcuts: shortcuts,
- },
- pickerOptionsa: {
- disabledDate(time) {
- return time.getTime() > Date.now();
- },
- shortcuts: shortcuts,
- },
+ options: this.$store.getters.tasktypes,
queryParams: {
serviceType: [2],
dateRange: [],
statisticaltype: 1,
- leavehospitaldistrictcodes: ["all"],
- deptcodes: [],
- visitCount: 1, // 鏂板锛氶殢璁挎鏁板弬鏁帮紝1-棣栨锛�2-鍐嶆
+ leavehospitaldistrictcodes: ['all'],
+ deptcodes: []
},
- columns: [
- { key: 0, label: `鏍囩缂栧彿`, visible: true },
- { key: 1, label: `鏍囩鍚嶇О`, visible: true },
- { key: 2, label: `鏍囩鏄电О`, visible: true },
- { key: 3, label: `閮ㄩ棬`, visible: true },
- { key: 4, label: `鎵嬫満鍙风爜`, visible: true },
- { key: 5, label: `鐘舵�乣, visible: true },
- { key: 6, label: `鍒涘缓鏃堕棿`, visible: true },
- ],
- };
+ flatArrayhospit: [],
+ flatArraydept: [],
+ allDeptCodes: [],
+ allWardCodes: [],
+ showSearch: true,
+
+ // 寮圭獥鐩稿叧鐘舵��
+ chartDialogVisible: false,
+ chartData: [],
+ infotitleVisible: false,
+ SeedetailsVisible: false,
+ searchName: '',
+ infotitle: '',
+ infotitlelist: [],
+ patienttotal: 0,
+ logsheetlist: [],
+ Seedloading: false,
+ patientqueryParams: {
+ pn: 1,
+ ps: 10
+ }
+ }
},
- watch: {},
created() {
- this.getDeptTree();
- this.getFirstFollowUpList(); // 榛樿鍔犺浇棣栨闅忚鏁版嵁
- this.checkboxlist = store.getters.checkboxlist;
- this.orgname = localStorage.getItem("orgname");
+ this.getDeptTree()
},
-
methods: {
- /** 鏌ヨ棣栨闅忚鍒楄〃 */
- async getFirstFollowUpList() {
- this.loading = true;
- this.queryParams.visitCount = 1; // 璁剧疆闅忚娆℃暟涓洪娆�
-
- const params = {
- ...this.queryParams,
- leavehospitaldistrictcodes:
- this.queryParams.leavehospitaldistrictcodes.includes("all")
- ? this.allWardCodes
- : this.queryParams.leavehospitaldistrictcodes,
- deptcodes: this.queryParams.deptcodes.includes("all")
- ? this.allDeptCodes
- : this.queryParams.deptcodes,
- };
-
- delete params.leavehospitaldistrictcodes.all;
- delete params.deptcodes.all;
-
- try {
- const response = await getSfStatistics(params);
- this.firstFollowUpList = this.customSort(response.data);
- this.total = response.total;
- } catch (error) {
- console.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触:", error);
- this.$message.error("鑾峰彇棣栨闅忚鏁版嵁澶辫触");
- } finally {
- this.loading = false;
- }
- },
-
- /** 鏌ヨ鍐嶆闅忚鍒楄〃 */
- async getSecondFollowUpList() {
- this.loadingSecond = true;
- this.queryParams.visitCount = 2; // 璁剧疆闅忚娆℃暟涓哄啀娆�
-
- const params = {
- ...this.queryParams,
- leavehospitaldistrictcodes:
- this.queryParams.leavehospitaldistrictcodes.includes("all")
- ? this.allWardCodes
- : this.queryParams.leavehospitaldistrictcodes,
- deptcodes: this.queryParams.deptcodes.includes("all")
- ? this.allDeptCodes
- : this.queryParams.deptcodes,
- };
-
- delete params.leavehospitaldistrictcodes.all;
- delete params.deptcodes.all;
-
- try {
- const response = await getSfStatistics(params);
- this.secondFollowUpList = this.customSort(response.data);
- this.total = response.total;
- } catch (error) {
- console.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触:", error);
- this.$message.error("鑾峰彇鍐嶆闅忚鏁版嵁澶辫触");
- } finally {
- this.loadingSecond = false;
- }
- },
-
- /** Tab鍒囨崲浜嬩欢 */
- handleTabClick(tab) {
- if (tab.name === "first") {
- if (this.firstFollowUpList.length === 0) {
- this.getFirstFollowUpList();
- }
- } else if (tab.name === "second") {
- if (this.secondFollowUpList.length === 0) {
- this.getSecondFollowUpList();
- }
- }
- },
- sortChineseNumber(aRow, bRow) {
- const a = aRow.leavehospitaldistrictname;
- const b = bRow.leavehospitaldistrictname;
-
- // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
- const chineseNumMap = {
- 涓�: 1,
- 浜�: 2,
- 涓�: 3,
- 鍥�: 4,
- 浜�: 5,
- 鍏�: 6,
- 涓�: 7,
- 鍏�: 8,
- 涔�: 9,
- 鍗�: 10,
- 鍗佷竴: 11,
- 鍗佷簩: 12,
- 鍗佷笁: 13,
- 鍗佸洓: 14,
- 鍗佷簲: 15,
- 鍗佸叚: 16,
- 鍗佷竷: 17,
- 鍗佸叓: 18,
- 鍗佷節: 19,
- 浜屽崄: 20,
- 浜屽崄涓�: 21,
- 浜屽崄浜�: 22,
- 浜屽崄涓�: 23,
- 浜屽崄鍥�: 24,
- 浜屽崄浜�: 25,
- 浜屽崄鍏�: 26,
- 浜屽崄涓�: 27,
- 浜屽崄鍏�: 28,
- 浜屽崄涔�: 29,
- 涓夊崄: 30,
- 涓夊崄涓�: 31,
- 涓夊崄浜�: 32,
- 涓夊崄涓�: 33,
- 涓夊崄鍥�: 34,
- 涓夊崄浜�: 35,
- 涓夊崄鍏�: 36,
- 涓夊崄涓�: 37,
- 涓夊崄鍏�: 38,
- 涓夊崄涔�: 39,
- 鍥涘崄: 40,
- 鍥涘崄涓�: 41,
- 鍥涘崄浜�: 42,
- 鍥涘崄涓�: 43,
- 鍥涘崄鍥�: 44,
- 鍥涘崄浜�: 45,
- };
-
- // 鎻愬彇涓枃鏁板瓧
- const getNumberFromText = (text) => {
- if (!text || typeof text !== "string") return -1;
-
- // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
- const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
-
- if (match && match[1]) {
- const chineseNum = match[1];
- return chineseNumMap[chineseNum] !== undefined
- ? chineseNumMap[chineseNum]
- : -1;
- }
-
- // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
- const arabicMatch = text.match(/^(\d+)/);
- if (arabicMatch && arabicMatch[1]) {
- const num = parseInt(arabicMatch[1], 10);
- return num >= 1 && num <= 45 ? num : -1;
- }
-
- return -1;
- };
-
- const numA = getNumberFromText(a);
- const numB = getNumberFromText(b);
-
- // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
- if (numA === -1 && numB === -1) {
- return (a || "").localeCompare(b || "");
- }
- if (numA === -1) return 1;
- if (numB === -1) return -1;
-
- return numA - numB;
- },
- // 鎼滅储澶勭悊鍑芥暟
- handleSearch() {
- if (!this.searchName.trim()) {
- // 濡傛灉鎼滅储妗嗕负绌猴紝鏄剧ず鎵�鏈夋暟鎹�
- this.currentDisplayList = [...this.infotitlelist];
- } else {
- // 鏍规嵁鎮h�呭鍚嶈繘琛岀瓫閫夛紙涓嶅尯鍒嗗ぇ灏忓啓锛�
- const keyword = this.searchName.toLowerCase();
- this.currentDisplayList = this.infotitlelist.filter((item) => {
- return item.sendname && item.sendname.toLowerCase().includes(keyword);
- });
- }
- },
- customSort(data) {
- // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
- const order = [
- "涓�",
- "浜�",
- "涓�",
- "鍥�",
- "浜�",
- "鍏�",
- "涓�",
- "鍏�",
- "涔�",
- "鍗�",
- "鍗佷竴",
- "鍗佷簩",
- "鍗佷笁",
- "鍗佸洓",
- "鍗佷簲",
- "鍗佸叚",
- "鍗佷竷",
- "鍗佸叓",
- "鍗佷節",
- "浜屽崄",
- "浜屽崄涓�",
- "浜屽崄浜�",
- "浜屽崄涓�",
- "浜屽崄鍥�",
- "浜屽崄浜�",
- "浜屽崄鍏�",
- "浜屽崄涓�",
- "浜屽崄鍏�",
- "浜屽崄涔�",
- "涓夊崄",
- "涓夊崄涓�",
- "涓夊崄浜�",
- "涓夊崄涓�",
- "涓夊崄鍥�",
- "涓夊崄浜�",
- "涓夊崄鍏�",
- "涓夊崄涓�",
- "涓夊崄鍏�",
- "涓夊崄涔�",
- "鍥涘崄",
- "鍥涘崄涓�",
- "鍥涘崄浜�",
- "鍥涘崄涓�",
- "鍥涘崄鍥�",
- "鍥涘崄浜�",
- ];
-
- return data.sort((a, b) => {
- // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
- const getIndex = (name) => {
- if (!name || typeof name !== "string") return -1;
-
- // 鍖归厤涓枃鏁板瓧
- const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
- if (chineseMatch && chineseMatch[1]) {
- return order.indexOf(chineseMatch[1]);
- }
-
- // 鍖归厤闃挎媺浼暟瀛�
- const arabicMatch = name.match(/^(\d+)/);
- if (arabicMatch && arabicMatch[1]) {
- const num = parseInt(arabicMatch[1], 10);
- if (num >= 1 && num <= 45) {
- return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
- }
- }
-
- return -1;
- };
-
- const indexA = getIndex(a.leavehospitaldistrictname);
- const indexB = getIndex(b.leavehospitaldistrictname);
-
- // 鎺掑簭閫昏緫
- if (indexA === -1 && indexB === -1) {
- return (a.leavehospitaldistrictname || "").localeCompare(
- b.leavehospitaldistrictname || ""
- );
- }
- if (indexA === -1) return 1;
- if (indexB === -1) return -1;
- return indexA - indexB;
- });
- },
- getRowKey(row) {
- 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,
- // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
- deptcodes: this.queryParams.deptcodes.includes("all")
- ? this.allDeptCodes
- : this.queryParams.deptcodes,
- leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
- drcode: "1",
- visitCount: 1, // 璁剧疆涓洪娆¢殢璁�
- };
-
- // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
- delete params.leavehospitaldistrictcodes.all;
- delete params.deptcodes.all;
- // 濡傛灉璇ヨ杩樻病鏈夊姞杞藉尰鐢熸暟鎹紝鍒欏姞杞�
- 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)];
- }
- },
- getSummaries(param) {
- const { columns, data } = param;
- const sums = [];
-
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "鍚堣";
- return;
- }
- if (index === 1 || index === 2) {
- sums[index] = "/";
- return;
- }
-
- // 瀵圭櫨鍒嗘瘮瀛楁鐗规畩澶勭悊 - 鍙栧钩鍧囧��
- if (
- column.property === "followUpRate" ||
- column.property === "rate" ||
- column.property === "followUpRateAgain"
- ) {
- // 鎻愬彇鎵�鏈夋湁鏁堢櫨鍒嗘瘮鍊煎苟杞崲涓哄皬鏁�
- const percentageValues = data
- .map((item) => {
- const value = item[column.property];
- if (!value || value === "-" || value === "0%") return null;
-
- // 澶勭悊甯︾櫨鍒嗗彿鐨勬暟鎹�
- if (typeof value === "string" && value.includes("%")) {
- // 鍘婚櫎鐧惧垎鍙峰苟杞崲涓哄皬鏁�
- const numValue = parseFloat(value.replace("%", "")) / 100;
- return isNaN(numValue) ? null : numValue;
- } else {
- // 澶勭悊宸茬粡鏄皬鏁扮殑鏁版嵁
- const numValue = parseFloat(value);
- return isNaN(numValue) ? null : numValue;
- }
- })
- .filter((value) => value !== null && value !== 0); // 杩囨护鎺塶ull鍜�0鍊�
-
- if (percentageValues.length > 0) {
- const average =
- percentageValues.reduce((sum, value) => sum + value, 0) /
- percentageValues.length;
- sums[index] = (average * 100).toFixed(2) + "%";
- } else {
- sums[index] = "0.00%";
- }
- } else {
- // 鏅�氭暟瀛楀瓧娈� - 姹傚拰
- const values = data.map((item) => {
- const value = item[column.property];
- if (value === "-" || value === "" || value === null) return 0;
- return Number(value) || 0;
- });
-
- if (!values.every((value) => isNaN(value))) {
- sums[index] = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = this.formatNumber(sums[index]);
- } else {
- sums[index] = "-";
- }
- }
- });
-
- return sums;
- },
-
- // 鍐呴儴琛ㄦ牸鍚堣琛岃绠楁柟娉�
- getInnerSummaries(param) {
- const { columns, data } = param;
- const sums = [];
-
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "灏忚";
- return;
- }
-
- if (column.property === "drname" || column.property === "deptname") {
- sums[index] = "-";
- return;
- }
-
- // 瀵圭櫨鍒嗘瘮瀛楁鐗规畩澶勭悊 - 鍙栧钩鍧囧��
- if (column.property === "followUpRate" || column.property === "rate") {
- // 鎻愬彇鎵�鏈夋湁鏁堢櫨鍒嗘瘮鍊煎苟杞崲涓哄皬鏁�
- const percentageValues = data
- .map((item) => {
- const value = item[column.property];
- if (!value || value === "-" || value === "0%") return null;
-
- // 澶勭悊甯︾櫨鍒嗗彿鐨勬暟鎹�
- if (typeof value === "string" && value.includes("%")) {
- // 鍘婚櫎鐧惧垎鍙峰苟杞崲涓哄皬鏁�
- const numValue = parseFloat(value.replace("%", "")) / 100;
- return isNaN(numValue) ? null : numValue;
- } else {
- // 澶勭悊宸茬粡鏄皬鏁扮殑鏁版嵁
- const numValue = parseFloat(value);
- return isNaN(numValue) ? null : numValue;
- }
- })
- .filter((value) => value !== null && value !== 0);
-
- if (percentageValues.length > 0) {
- const average =
- percentageValues.reduce((sum, value) => sum + value, 0) /
- percentageValues.length;
- sums[index] = (average * 100).toFixed(2) + "%";
- } else {
- sums[index] = "0.00%";
- }
- } else {
- // 鏅�氭暟瀛楀瓧娈� - 姹傚拰
- const values = data.map((item) => {
- const value = item[column.property];
- if (value === "-" || value === "" || value === null) return 0;
- return Number(value) || 0;
- });
-
- if (!values.every((value) => isNaN(value))) {
- sums[index] = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = this.formatNumber(sums[index]);
- } else {
- sums[index] = "-";
- }
- }
- });
-
- return sums;
- },
-
- // 杈呭姪鏂规硶锛氭彁鍙栫櫨鍒嗘瘮鏁板��
- extractPercentageValue(value) {
- if (!value) return null;
-
- if (typeof value === "string") {
- // 澶勭悊甯︾櫨鍒嗗彿鐨勫瓧绗︿覆
- if (value.includes("%")) {
- const num = parseFloat(value.replace("%", ""));
- return isNaN(num) ? null : num / 100;
- }
- // 澶勭悊绾暟瀛楀瓧绗︿覆
- const num = parseFloat(value);
- return isNaN(num) ? null : num;
- }
-
- // 澶勭悊鏁板瓧绫诲瀷
- return typeof value === "number" ? value : null;
- },
-
- // 鏁板瓧鏍煎紡鍖栨柟娉�
- formatNumber(num) {
- if (isNaN(num)) return "-";
- return Number.isInteger(num) ? num.toString() : num.toFixed(0);
- },
- /** 淇敼鏍囩 */
- handleUpdate(row) {
- console.log(row, "淇敼鏍囩");
- this.lstamendtagVisible = true;
- this.lstamendtag = true;
- this.tagform = {
- isupload: row.isupload,
- tagname: row.tagname,
- tagcategoryid: row.tagcategoryid,
- tagdescription: row.tagdescription,
- tagid: row.tagid,
- };
- },
- // 鑾峰彇绉戝鏍�
getDeptTree() {
// 绉戝鍒楄〃
- this.flatArraydept = store.getters.belongDepts.map((dept) => {
+ this.flatArraydept = this.$store.getters.belongDepts.map((dept) => {
return {
label: dept.deptName,
- value: dept.deptCode,
- };
- });
- // 瀛樺偍鎵�鏈夌瀹や唬鐮�
- this.allDeptCodes = store.getters.belongDepts.map(
- (dept) => dept.deptCode
- );
+ value: dept.deptCode
+ }
+ })
+ this.allDeptCodes = this.$store.getters.belongDepts.map((dept) => dept.deptCode)
// 鐥呭尯鍒楄〃
- this.flatArrayhospit = store.getters.belongWards.map((ward) => {
+ this.flatArrayhospit = this.$store.getters.belongWards.map((ward) => {
return {
label: ward.districtName,
- value: ward.districtCode,
- };
- });
-
- // 瀛樺偍鎵�鏈夌梾鍖轰唬鐮�
- this.allWardCodes = store.getters.belongWards.map(
- (ward) => ward.districtCode
- );
- this.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
- this.flatArrayhospit.push({ label: "鍏ㄩ儴", value: "all" });
- },
- flattenArray(multiArray) {
- let result = [];
-
- // 閫掑綊鍑芥暟锛岀敤浜庡皢澶氱骇鏁扮粍杞崲涓轰竴缁存暟缁勶紝鍙寘鍚渶搴曞眰鐨勫厓绱�
- function flatten(element) {
- // 濡傛灉褰撳墠鍏冪礌鏈夊瓙鍏冪礌锛岀户缁�掑綊
- if (element.children && element.children.length > 0) {
- element.children.forEach((child) => flatten(child));
- } else {
- // 鍏嬮殕鍏冪礌浠ラ伩鍏嶄慨鏀瑰師濮嬫暟鎹�
- let item = JSON.parse(JSON.stringify(element));
- result.push(item); // 灏嗘渶搴曞眰鐨勫厓绱犳坊鍔犲埌缁撴灉鏁扮粍
+ value: ward.districtCode
}
+ })
+ this.allWardCodes = this.$store.getters.belongWards.map((ward) => ward.districtCode)
+
+ this.flatArraydept.push({ label: '鍏ㄩ儴', value: 'all' })
+ this.flatArrayhospit.push({ label: '鍏ㄩ儴', value: 'all' })
+ },
+
+ handleTabClick(tab) {
+ this.activeTab = tab.name
+ this.loadCurrentTabData()
+ },
+
+ loadCurrentTabData() {
+ switch (this.activeTab) {
+ case 'first':
+ this.$refs.firstFollowUp.loadData()
+ break
+ case 'second':
+ this.$refs.secondFollowUp.loadData()
+ break
+ case 'continued':
+ this.$refs.continuedCare.loadData()
+ break
+ }
+ },
+
+ handleQuery() {
+ this.queryParams.startTime = this.parseTime(this.queryParams.dateRange[0])
+ this.queryParams.endTime = this.parseTime(this.queryParams.dateRange[1])
+
+ if (this.queryParams.statisticaltype == 1) {
+ this.queryParams.deptcodes = []
+ } else if (this.queryParams.statisticaltype == 2) {
+ this.queryParams.leavehospitaldistrictcodes = []
}
- // 浠庨《灞傚厓绱犲紑濮嬮�掑綊
- multiArray.forEach((element) => flatten(element));
- return result; // 杩斿洖鍙寘鍚渶搴曞眰鍏冪礌鐨勪竴缁存暟缁�
+ this.loadCurrentTabData()
},
- addladeltag() {
- this.lstamendtagVisible = true;
- this.lstamendtag = false;
- this.tagform = {
- isupload: "",
- tagname: "",
- tagcategoryid: "",
- tagdescription: "",
- tagid: "",
- };
+
+ resetQuery() {
+ this.queryParams.dateRange = []
+ this.queryParams.leavehospitaldistrictcodes = []
+ this.handleQuery()
},
- Seedetails(row) {
- this.SeedetailsVisible = true;
- this.Seedloading = true;
- this.patientqueryParams.starttime = this.parseTime(
- this.queryParams.dateRange[0]
- );
- this.patientqueryParams.endtime = this.parseTime(
- this.queryParams.dateRange[1]
- );
- this.patientqueryParams.deptcode = row.deptcode;
- selectTimelyRate(this.patientqueryParams).then((response) => {
- this.logsheetlist = response.data.detail;
- this.patienttotal = response.data.total;
- this.Seedloading = false;
- });
+
+ async handleExport() {
+ switch (this.activeTab) {
+ case 'first':
+ await this.$refs.firstFollowUp.exportTable()
+ break
+ case 'second':
+ await this.$refs.secondFollowUp.exportTable()
+ break
+ case 'continued':
+ await this.$refs.continuedCare.exportTable()
+ break
+ }
},
- Seedetailstion() {
- selectTimelyRate(this.patientqueryParams).then((response) => {
- this.logsheetlist = response.data.detail;
- this.patienttotal = response.data.total;
- this.Seedloading = false;
- });
+
+ showChartDialog() {
+ this.chartData = this.getCurrentTabData()
+ this.chartDialogVisible = true
},
+
+ getCurrentTabData() {
+ switch (this.activeTab) {
+ case 'first':
+ return this.$refs.firstFollowUp.tableData
+ case 'second':
+ return this.$refs.secondFollowUp.tableData
+ case 'continued':
+ return this.$refs.continuedCare.tableData
+ default:
+ return []
+ }
+ },
+
viewDetails(row, title) {
- this.infotitleVisible = true;
- this.infotitle = title;
- this.infotitlelist = row; // 鍋囪row灏辨槸闇�瑕佸睍绀虹殑璇︾粏鏁扮粍
- console.log(this.infotitlelist, "this.infotitlelist");
-
- this.infotitlelist.forEach((item) => {
- let idArray = null;
-
- if (item.preachform) {
- if (item.endtime) {
- item.preachformson = item.preachform;
- idArray = item.preachform.split(",");
- }
-
- item.preachform = idArray.map((value) => {
- // 鏌ユ壘id瀵瑰簲鐨勫璞�
- const item = this.checkboxlist.find((item) => item.value == value);
- // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
- return item ? item.label : null;
- });
- }
- });
- // 鍒濆鍖栧姞杞�
- this.loadIndex = 0;
- this.currentDisplayList = [];
- this.$nextTick(() => {
- this.loadMoreData();
- });
+ this.infotitle = title
+ this.infotitlelist = row
+ this.infotitleVisible = true
},
- loadMoreData() {
- if (this.isLoading) return;
- this.isLoading = true;
- // 妯℃嫙寮傛鍔犺浇锛屽疄闄呭彲鑳芥槸鐩存帴鍒囩墖鏈湴鏁版嵁
- setTimeout(() => {
- console.log(this.infotitlelist, "this.infotitlelist");
+ Seedetails(row) {
+ this.SeedetailsVisible = true
+ this.Seedloading = true
- const nextChunk = this.infotitlelist.slice(
- this.loadIndex,
- this.loadIndex + this.pageSize
- );
- this.currentDisplayList = this.currentDisplayList.concat(nextChunk);
- this.loadIndex += this.pageSize;
- this.isLoading = false;
- }, 200);
+ this.$refs.firstFollowUp.selectTimelyRate(row, this.queryParams.dateRange)
+ .then(response => {
+ this.logsheetlist = response.data.detail
+ this.patienttotal = response.data.total
+ this.Seedloading = false
+ })
},
- handleScroll(event) {
- const scrollContainer = event.target;
- // 鍒ゆ柇鏄惁婊氬姩鍒板簳閮�
- const isAtBottom =
- scrollContainer.scrollTop + scrollContainer.clientHeight >=
- scrollContainer.scrollHeight - 10;
- if (
- isAtBottom &&
- !this.isLoading &&
- this.loadIndex < this.infotitlelist.length
- ) {
- this.loadMoreData();
- }
+ Seedetailstion() {
+ this.$refs.firstFollowUp.selectTimelyRate(this.patientqueryParams)
+ .then(response => {
+ this.logsheetlist = response.data.detail
+ this.patienttotal = response.data.total
+ })
},
+
SeedetailsgGo(row) {
- this.SeedetailsVisible = false;
- let type = "";
- if (row.preachformson && row.preachformson.includes("3")) {
- type = 1;
+ this.SeedetailsVisible = false
+ let type = ''
+ if (row.preachformson && row.preachformson.includes('3')) {
+ type = 1
}
setTimeout(() => {
this.$router.push({
- path: "/followvisit/record/detailpage/",
+ path: '/followvisit/record/detailpage/',
query: {
taskid: row.taskid,
patid: row.patid,
id: row.id,
- Voicetype: type,
- // visitCount: this.topqueryParams.visitCount,
- },
- });
- }, 300);
- },
- // 娣诲姞/淇敼鏍囩
- Maintenancetag() {
- if (this.lstamendtag) {
- toamendtag(this.addDateRange(this.tagform)).then((response) => {
- console.log(response);
- this.getList();
- });
- } else {
- addapitag(this.addDateRange(this.tagform)).then((response) => {
- console.log(response);
- this.getList();
- });
- }
- this.tagform = {
- isupload: "",
- tagname: "",
- tagcategoryid: "",
- tagdescription: "",
- tagid: "",
- };
- },
- routerErr(row) {
- console.log(row, "璺宠浆寮傚父");
- this.$router.push({
- path: "/followvisit/discharge",
- query: {
- errtype: 1,
- leavehospitaldistrictcode: row.leavehospitaldistrictcode,
- },
- });
- },
-
- // 琛ㄥ崟閲嶇疆
- reset() {
- this.form = {
- userId: undefined,
- deptId: undefined,
- userName: undefined,
- nickName: undefined,
- password: undefined,
- phonenumber: undefined,
- email: undefined,
- sex: undefined,
- status: "0",
- remark: undefined,
- postIds: [],
- roleIds: [],
- };
- this.resetForm("form");
- },
- // 鏍囩鐘舵�佷慨鏀�
- handleStatusChange(row) {
- console.log(row.isupload);
- let text = row.isupload === "0" ? "鍚敤" : "鍋滅敤";
- this.$modal
- .confirm('纭瑕�"' + text + '""' + row.tagname + '"鏍囩鍚楋紵')
- .then(function () {
- return changetagcategory(row.tagid, row.isupload);
+ Voicetype: type
+ }
})
- .then(() => {
- this.$modal.msgSuccess(text + "鎴愬姛");
- })
- .catch(function () {
- row.isupload = row.isupload === "0" ? "1" : "0";
- });
- },
- /** 鎼滅储鎸夐挳鎿嶄綔 - 淇敼涓烘悳绱㈠綋鍓嶆縺娲荤殑tab鏁版嵁 */
- handleQuery() {
- this.queryParams.pageNum = 1;
- if (!this.queryParams.dateRange) this.queryParams.dateRange = [];
- if (this.queryParams.statisticaltype == 1) {
- this.queryParams.deptcodes = [];
- } else if (this.queryParams.statisticaltype == 2) {
- this.queryParams.leavehospitaldistrictcodes = [];
- }
-
- this.queryParams.startTime = this.parseTime(
- this.queryParams.dateRange[0]
- );
- this.queryParams.endTime = this.parseTime(this.queryParams.dateRange[1]);
-
- // 鏍规嵁褰撳墠婵�娲荤殑tab鍔犺浇瀵瑰簲鏁版嵁
- if (this.activeTab === "first") {
- this.getFirstFollowUpList();
- } else {
- this.getSecondFollowUpList();
- }
+ }, 300)
},
- /** 閲嶇疆鎸夐挳鎿嶄綔 */
- resetQuery() {
- this.queryParams.dateRange = [];
- this.queryParams.leavehospitaldistrictcodes = [];
- this.handleQuery();
- },
- // 澶氶�夋閫変腑鏁版嵁
- handleSelectionChange(selection) {
- this.ids = selection.map((item) => item.tagid);
- this.single = selection.length != 1;
- this.multiple = !selection.length;
- },
-
- /** 鍒犻櫎鎸夐挳鎿嶄綔 */
- handleDelete(row) {
- console.log(row, "鍒犻櫎寮圭獥");
- const tagids = row.tagid || this.ids;
- console.log(tagids);
- const tagname = row.tagname;
- this.$modal
- .confirm(
- tagname
- ? '鏄惁纭鍒犻櫎鏍囩鍚嶇О涓�"' + tagname + '"鐨勬暟鎹」锛�'
- : "鏄惁纭鍒犻櫎閫変腑鐨勬暟鎹」锛�"
- )
- .then(function () {
- return deletetag(tagids);
- })
- .then(() => {
- this.getList();
- this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
- })
- .catch(() => {});
- },
- // 瀵煎嚭鏂规硶
-
- async exportTable() {
- try {
- // 1. 鑾峰彇骞舵牸寮忓寲鏃ユ湡鑼冨洿
- let dateRangeString = "";
- let sheetNameSuffix = "";
-
- if (
- this.queryParams.dateRange &&
- this.queryParams.dateRange.length === 2
- ) {
- const startDateStr = this.queryParams.dateRange[0];
- const endDateStr = this.queryParams.dateRange[1];
- const formatDateForDisplay = (dateTimeStr) => {
- return dateTimeStr.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;
- dateRangeString = `${currentMonth}鏈坄;
- sheetNameSuffix = `${currentMonth}鏈坄;
- }
-
- // 2. 鏍规嵁褰撳墠婵�娲荤殑tab纭畾瀵煎嚭鐨勬暟鎹�
- const isFirstFollowUp = this.activeTab === "first";
- let excelName, worksheetName, dataToExport;
-
- if (isFirstFollowUp) {
- excelName = `棣栨鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
- worksheetName = `棣栨闅忚缁熻_${sheetNameSuffix}`;
- dataToExport = this.firstFollowUpList;
-
- if (!dataToExport || dataToExport.length === 0) {
- this.$message.warning("鏆傛棤棣栨闅忚鏁版嵁鍙鍑�");
- return false;
- }
- } else {
- excelName = `鍐嶆鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
- worksheetName = `鍐嶆闅忚缁熻_${sheetNameSuffix}`;
- dataToExport = this.secondFollowUpList;
-
- if (!dataToExport || dataToExport.length === 0) {
- this.$message.warning("鏆傛棤鍐嶆闅忚鏁版嵁鍙鍑�");
- return false;
- }
- }
-
- // 3. 鍒涘缓宸ヤ綔绨垮拰宸ヤ綔琛�
- const workbook = new ExcelJS.Workbook();
- const worksheet = workbook.addWorksheet(worksheetName);
-
- // 4. 鏋勫缓琛ㄦ牸
- if (isFirstFollowUp) {
- this.buildFirstFollowUpExportSheet(
- worksheet,
- dataToExport,
- sheetNameSuffix
- );
- } else {
- this.buildSecondFollowUpExportSheet(
- worksheet,
- dataToExport,
- sheetNameSuffix
- );
- }
-
- // 5. 鐢熸垚骞朵笅杞芥枃浠�
- const buffer = await workbook.xlsx.writeBuffer();
- const blob = new Blob([buffer], {
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
- saveAs(blob, excelName);
-
- this.$message.success("瀵煎嚭鎴愬姛");
- return true;
- } catch (error) {
- console.error("瀵煎嚭澶辫触:", error);
- this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
- return false;
- }
- },
- /** 鏋勫缓棣栨闅忚瀵煎嚭琛ㄦ牸 */
- buildFirstFollowUpExportSheet(worksheet, data, sheetNameSuffix) {
- 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" } },
- },
- };
-
- const summaryStyle = {
- font: {
- name: "瀹嬩綋",
- size: 10,
- bold: true,
- color: { argb: "FF409EFF" },
- },
- fill: {
- type: "pattern",
- pattern: "solid",
- fgColor: { argb: "FFF5F7FA" },
- },
- 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" } },
- },
- };
-
- // 1. 娣诲姞鎬绘爣棰樿
- worksheet.mergeCells(1, 1, 1, 16); // 鍚堝苟A1鍒癙1
- const titleCell = worksheet.getCell(1, 1);
- titleCell.value = `棣栨鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`;
- titleCell.style = titleStyle;
- worksheet.getRow(1).height = 35;
-
- // 2. 鍒涘缓琛ㄥご
- const secondRowHeaders = [
- "", // A2 灞曞紑鍒楀崰浣�
- "鍑洪櫌鐥呭尯",
- "绉戝",
- "鍑洪櫌浜烘",
- "鏃犻渶闅忚浜烘",
- "搴旈殢璁夸汉娆�", // B2 to F2
- // 棣栨鍑洪櫌闅忚瀛愯〃澶�
- "闇�闅忚",
- "寰呴殢璁�",
- "闅忚鎴愬姛",
- "闅忚澶辫触",
- "闅忚鐜�",
- "鍙婃椂鐜�",
- "浜哄伐",
- "鐭俊",
- "寰俊",
- ];
-
- // 娣诲姞绗簩琛�
- secondRowHeaders.forEach((header, index) => {
- const cell = worksheet.getCell(3, index + 1);
- cell.value = header;
- cell.style = headerStyle;
- });
-
- // 3. 鍚堝苟鍗曞厓鏍�
- // 鍚堝苟 A2:A3, B2:B3, C2:C3, D2:D3, E2:E3, F2:F3
- for (let i = 1; i <= 6; i++) {
- worksheet.mergeCells(2, i, 3, i);
- const cell = worksheet.getCell(2, i);
- cell.style = headerStyle;
- }
-
- // 璁剧疆绗竴琛屽悎骞跺崟鍏冩牸鐨勫��
- worksheet.getCell(2, 1).value = "";
- worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
- worksheet.getCell(2, 3).value = "绉戝";
- worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
- worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
- worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
-
- // 4. 鍚堝苟"棣栨鍑洪櫌闅忚"鏍囬
- worksheet.mergeCells(2, 7, 2, 15); // G2:O2
- worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚";
- worksheet.getCell(2, 7).style = headerStyle;
-
- // 5. 璁剧疆琛岄珮
- worksheet.getRow(2).height = 28;
- worksheet.getRow(3).height = 25;
-
- // 6. 娣诲姞鏁版嵁琛�
- data.forEach((item, rowIndex) => {
- const dataRow = worksheet.addRow(
- [
- "", // 灞曞紑鍒�
- item.leavehospitaldistrictname || "",
- item.deptname || "",
- item.dischargeCount || 0,
- item.nonFollowUp || 0,
- item.followUpNeeded || 0,
- // 棣栨鍑洪櫌闅忚鏁版嵁
- item.needFollowUp || 0,
- item.pendingFollowUp || 0,
- item.followUpSuccess || 0,
- item.followUpFail || 0,
- item.followUpRate || "0%",
- item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
- item.manual || 0,
- item.sms || 0,
- item.weChat || 0,
- ],
- rowIndex + 4
- );
-
- // 搴旂敤鏁版嵁琛屾牱寮�
- dataRow.eachCell((cell) => {
- cell.style = cellStyle;
- });
- dataRow.height = 24;
- });
-
- // 7. 娣诲姞鍚堣琛�
- const summaries = this.getFirstFollowUpSummaries(data);
- const summaryRow = worksheet.addRow(summaries);
- summaryRow.eachCell((cell, colNumber) => {
- cell.style = summaryStyle;
- if (colNumber === 1) {
- cell.value = "鍚堣";
- }
- });
- summaryRow.height = 28;
-
- // 8. 璁剧疆鍒楀
- worksheet.columns = [
- { width: 8 }, // 灞曞紑鍒�
- { width: 20 }, // 鍑洪櫌鐥呭尯
- { width: 15 }, // 绉戝
- { width: 12 }, // 鍑洪櫌浜烘
- { width: 12 }, // 鏃犻渶闅忚浜烘
- { width: 12 }, // 搴旈殢璁夸汉娆�
- // 棣栨鍑洪櫌闅忚鍒�
- { width: 10 }, // 闇�闅忚
- { width: 10 }, // 寰呴殢璁�
- { width: 10 }, // 闅忚鎴愬姛
- { width: 10 }, // 闅忚澶辫触
- { width: 12 }, // 闅忚鐜�
- { width: 12 }, // 鍙婃椂鐜�
- { width: 8 }, // 浜哄伐
- { width: 8 }, // 鐭俊
- { width: 8 }, // 寰俊
- ];
- },
-
- /** 棣栨闅忚鏁版嵁鍚堣琛岃绠� */
- getFirstFollowUpSummaries(data) {
- const summaries = [
- "鍚堣",
- "/",
- "/",
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- "0%",
- "0%",
- 0,
- 0,
- 0,
- ];
-
- data.forEach((item) => {
- // 鏁板�煎瓧娈垫眰鍜�
- summaries[3] += Number(item.dischargeCount) || 0;
- summaries[4] += Number(item.nonFollowUp) || 0;
- summaries[5] += Number(item.followUpNeeded) || 0;
- summaries[6] += Number(item.needFollowUp) || 0;
- summaries[7] += Number(item.pendingFollowUp) || 0;
- summaries[8] += Number(item.followUpSuccess) || 0;
- summaries[9] += Number(item.followUpFail) || 0;
- summaries[12] += Number(item.manual) || 0;
- summaries[13] += Number(item.sms) || 0;
- summaries[14] += Number(item.weChat) || 0;
- });
-
- // 璁$畻鐧惧垎姣斿瓧娈电殑骞冲潎鍊�
- const followUpRateValues = data
- .map((item) => this.extractPercentageValue(item.followUpRate))
- .filter((value) => value !== null);
-
- const rateValues = data
- .map((item) => this.extractPercentageValue(item.rate))
- .filter((value) => value !== null);
-
- if (followUpRateValues.length > 0) {
- const avgFollowUpRate =
- followUpRateValues.reduce((sum, val) => sum + val, 0) /
- followUpRateValues.length;
- summaries[10] = (avgFollowUpRate * 100).toFixed(2) + "%";
- }
-
- if (rateValues.length > 0) {
- const avgRate =
- rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length;
- summaries[11] = (avgRate * 100).toFixed(2) + "%";
- }
-
- // 鏍煎紡鍖栨暟瀛�
- summaries[3] = this.formatNumber(summaries[3]);
- summaries[4] = this.formatNumber(summaries[4]);
- summaries[5] = this.formatNumber(summaries[5]);
- summaries[6] = this.formatNumber(summaries[6]);
- summaries[7] = this.formatNumber(summaries[7]);
- summaries[8] = this.formatNumber(summaries[8]);
- summaries[9] = this.formatNumber(summaries[9]);
- summaries[12] = this.formatNumber(summaries[12]);
- summaries[13] = this.formatNumber(summaries[13]);
- summaries[14] = this.formatNumber(summaries[14]);
-
- return summaries;
- },
-
- /** 鏋勫缓鍐嶆闅忚瀵煎嚭琛ㄦ牸 */
- buildSecondFollowUpExportSheet(worksheet, data, sheetNameSuffix) {
- 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" } },
- },
- };
-
- const summaryStyle = {
- font: {
- name: "瀹嬩綋",
- size: 10,
- bold: true,
- color: { argb: "FF409EFF" },
- },
- fill: {
- type: "pattern",
- pattern: "solid",
- fgColor: { argb: "FFF5F7FA" },
- },
- 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" } },
- },
- };
-
- // 1. 娣诲姞鎬绘爣棰樿
- worksheet.mergeCells(1, 1, 1, 15); // 鍚堝苟A1鍒癘1
- const titleCell = worksheet.getCell(1, 1);
- titleCell.value = `鍐嶆鍑洪櫌闅忚缁熻琛╛${sheetNameSuffix}`;
- titleCell.style = titleStyle;
- worksheet.getRow(1).height = 35;
-
- // 2. 鍒涘缓琛ㄥご
- const secondRowHeaders = [
- "", // A2 灞曞紑鍒楀崰浣�
- "鍑洪櫌鐥呭尯",
- "绉戝",
- "鍑洪櫌浜烘",
- "鏃犻渶闅忚浜烘",
- "搴旈殢璁夸汉娆�", // B2 to F2
- // 鍐嶆鍑洪櫌闅忚瀛愯〃澶�
- "闇�闅忚",
- "寰呴殢璁�",
- "闅忚鎴愬姛",
- "闅忚澶辫触",
- "闅忚鐜�",
- "浜哄伐",
- "鐭俊",
- "寰俊",
- ];
-
- // 娣诲姞绗簩琛�
- secondRowHeaders.forEach((header, index) => {
- const cell = worksheet.getCell(3, index + 1);
- cell.value = header;
- cell.style = headerStyle;
- });
-
- // 3. 鍚堝苟鍗曞厓鏍�
- // 鍚堝苟 A2:A3, B2:B3, C2:C3, D2:D3, E2:E3, F2:F3
- for (let i = 1; i <= 6; i++) {
- worksheet.mergeCells(2, i, 3, i);
- const cell = worksheet.getCell(2, i);
- cell.style = headerStyle;
- }
-
- // 璁剧疆绗竴琛屽悎骞跺崟鍏冩牸鐨勫��
- worksheet.getCell(2, 1).value = "";
- worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
- worksheet.getCell(2, 3).value = "绉戝";
- worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
- worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
- worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
-
- // 4. 鍚堝苟"鍐嶆鍑洪櫌闅忚"鏍囬
- worksheet.mergeCells(2, 7, 2, 14); // G2:N2
- worksheet.getCell(2, 7).value = "鍐嶆鍑洪櫌闅忚";
- worksheet.getCell(2, 7).style = headerStyle;
-
- // 5. 璁剧疆琛岄珮
- worksheet.getRow(2).height = 28;
- worksheet.getRow(3).height = 25;
-
- // 6. 娣诲姞鏁版嵁琛�
- data.forEach((item, rowIndex) => {
- const dataRow = worksheet.addRow(
- [
- "", // 灞曞紑鍒�
- item.leavehospitaldistrictname || "",
- item.deptname || "",
- item.dischargeCount || 0,
- item.nonFollowUp || 0,
- item.followUpNeeded || 0,
- // 鍐嶆鍑洪櫌闅忚鏁版嵁
- item.needFollowUpAgain || 0,
- item.pendingFollowUpAgain || 0,
- item.followUpSuccessAgain || 0,
- item.followUpFailAgain || 0,
- item.followUpRateAgain || "0%",
- item.manualAgain || 0,
- item.smsAgain || 0,
- item.weChatAgain || 0,
- ],
- rowIndex + 4
- );
-
- // 搴旂敤鏁版嵁琛屾牱寮�
- dataRow.eachCell((cell) => {
- cell.style = cellStyle;
- });
- dataRow.height = 24;
- });
-
- // 7. 娣诲姞鍚堣琛�
- const summaries = this.getSecondFollowUpSummaries(data);
- const summaryRow = worksheet.addRow(summaries);
- summaryRow.eachCell((cell, colNumber) => {
- cell.style = summaryStyle;
- if (colNumber === 1) {
- cell.value = "鍚堣";
- }
- });
- summaryRow.height = 28;
-
- // 8. 璁剧疆鍒楀
- worksheet.columns = [
- { width: 8 }, // 灞曞紑鍒�
- { width: 20 }, // 鍑洪櫌鐥呭尯
- { width: 15 }, // 绉戝
- { width: 12 }, // 鍑洪櫌浜烘
- { width: 12 }, // 鏃犻渶闅忚浜烘
- { width: 12 }, // 搴旈殢璁夸汉娆�
- // 鍐嶆鍑洪櫌闅忚鍒�
- { width: 10 }, // 闇�闅忚
- { width: 10 }, // 寰呴殢璁�
- { width: 10 }, // 闅忚鎴愬姛
- { width: 10 }, // 闅忚澶辫触
- { width: 12 }, // 闅忚鐜�
- { width: 8 }, // 浜哄伐
- { width: 8 }, // 鐭俊
- { width: 8 }, // 寰俊
- ];
- },
-
- /** 鍐嶆闅忚鏁版嵁鍚堣琛岃绠� */
- getSecondFollowUpSummaries(data) {
- const summaries = ["鍚堣", "/", "/", 0, 0, 0, 0, 0, 0, 0, "0%", 0, 0, 0];
-
- data.forEach((item) => {
- // 鏁板�煎瓧娈垫眰鍜�
- summaries[3] += Number(item.dischargeCount) || 0;
- summaries[4] += Number(item.nonFollowUp) || 0;
- summaries[5] += Number(item.followUpNeeded) || 0;
- summaries[6] += Number(item.needFollowUpAgain) || 0;
- summaries[7] += Number(item.pendingFollowUpAgain) || 0;
- summaries[8] += Number(item.followUpSuccessAgain) || 0;
- summaries[9] += Number(item.followUpFailAgain) || 0;
- summaries[11] += Number(item.manualAgain) || 0;
- summaries[12] += Number(item.smsAgain) || 0;
- summaries[13] += Number(item.weChatAgain) || 0;
- });
-
- // 璁$畻闅忚鐜囩櫨鍒嗘瘮瀛楁鐨勫钩鍧囧��
- const followUpRateAgainValues = data
- .map((item) => this.extractPercentageValue(item.followUpRateAgain))
- .filter((value) => value !== null);
-
- if (followUpRateAgainValues.length > 0) {
- const avgFollowUpRateAgain =
- followUpRateAgainValues.reduce((sum, val) => sum + val, 0) /
- followUpRateAgainValues.length;
- summaries[10] = (avgFollowUpRateAgain * 100).toFixed(2) + "%";
- }
-
- // 鏍煎紡鍖栨暟瀛�
- summaries[3] = this.formatNumber(summaries[3]);
- summaries[4] = this.formatNumber(summaries[4]);
- summaries[5] = this.formatNumber(summaries[5]);
- summaries[6] = this.formatNumber(summaries[6]);
- summaries[7] = this.formatNumber(summaries[7]);
- summaries[8] = this.formatNumber(summaries[8]);
- summaries[9] = this.formatNumber(summaries[9]);
- summaries[11] = this.formatNumber(summaries[11]);
- summaries[12] = this.formatNumber(summaries[12]);
- summaries[13] = this.formatNumber(summaries[13]);
-
- return summaries;
- },
-
- /** 鍐嶆闅忚琛ㄦ牸鐨勫悎璁¤璁$畻鏂规硶 */
- getSummariesSecond(param) {
- const { columns, data } = param;
- const sums = [];
-
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "鍚堣";
- return;
- }
- if (index === 1 || index === 2) {
- sums[index] = "/";
- return;
- }
-
- if (column.property === "followUpRateAgain") {
- const percentageValues = data
- .map((item) => {
- const value = item[column.property];
- if (!value || value === "-" || value === "0%") return null;
- if (typeof value === "string" && value.includes("%")) {
- const numValue = parseFloat(value.replace("%", "")) / 100;
- return isNaN(numValue) ? null : numValue;
- } else {
- const numValue = parseFloat(value);
- return isNaN(numValue) ? null : numValue;
- }
- })
- .filter((value) => value !== null && value !== 0);
-
- if (percentageValues.length > 0) {
- const average =
- percentageValues.reduce((sum, value) => sum + value, 0) /
- percentageValues.length;
- sums[index] = (average * 100).toFixed(2) + "%";
- } else {
- sums[index] = "0.00%";
- }
- } else {
- const values = data.map((item) => {
- const value = item[column.property];
- if (value === "-" || value === "" || value === null) return 0;
- return Number(value) || 0;
- });
-
- if (!values.every((value) => isNaN(value))) {
- sums[index] = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = this.formatNumber(sums[index]);
- } else {
- sums[index] = "-";
- }
- }
- });
-
- return sums;
- },
- /** 鍐嶆闅忚鍐呴儴琛ㄦ牸鍚堣琛岃绠楁柟娉� */
- getInnerSummariesSecond(param) {
- const { columns, data } = param;
- const sums = [];
-
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "灏忚";
- return;
- }
-
- if (column.property === "drname" || column.property === "deptname") {
- sums[index] = "-";
- return;
- }
-
- if (column.property === "followUpRateAgain") {
- const percentageValues = data
- .map((item) => {
- const value = item[column.property];
- if (!value || value === "-" || value === "0%") return null;
- if (typeof value === "string" && value.includes("%")) {
- const numValue = parseFloat(value.replace("%", "")) / 100;
- return isNaN(numValue) ? null : numValue;
- } else {
- const numValue = parseFloat(value);
- return isNaN(numValue) ? null : numValue;
- }
- })
- .filter((value) => value !== null && value !== 0);
-
- if (percentageValues.length > 0) {
- const average =
- percentageValues.reduce((sum, value) => sum + value, 0) /
- percentageValues.length;
- sums[index] = (average * 100).toFixed(2) + "%";
- } else {
- sums[index] = "0.00%";
- }
- } else {
- const values = data.map((item) => {
- const value = item[column.property];
- if (value === "-" || value === "" || value === null) return 0;
- return Number(value) || 0;
- });
-
- if (!values.every((value) => isNaN(value))) {
- sums[index] = values.reduce((prev, curr) => prev + curr, 0);
- sums[index] = this.formatNumber(sums[index]);
- } else {
- sums[index] = "-";
- }
- }
- });
-
- return sums;
- },
- /** 鍐嶆闅忚琛ㄦ牸鐨勮鐐瑰嚮灞曞紑 */
- handleRowClickSecond(row) {
- if (this.expandsSecond.includes(this.getRowKey(row))) {
- this.expandsSecond = [];
- return;
- }
-
- const params = {
- ...this.queryParams,
- deptcodes: this.queryParams.deptcodes.includes("all")
- ? this.allDeptCodes
- : this.queryParams.deptcodes,
- leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
- drcode: "1",
- visitCount: 2, // 璁剧疆涓哄啀娆¢殢璁�
- };
-
- delete params.leavehospitaldistrictcodes.all;
- delete params.deptcodes.all;
-
- if (!row.doctorStats) {
- this.loadingSecond = true;
- getSfStatistics(params).then((res) => {
- this.$set(row, "doctorStats", res.data);
- this.expandsSecond = [this.getRowKey(row)];
- this.loadingSecond = false;
- });
- } else {
- this.expandsSecond = [this.getRowKey(row)];
- }
- },
-
- /** 鍐嶆闅忚琛ㄦ牸鐨勫閫夋閫変腑鏁版嵁 */
- handleSelectionChangeSecond(selection) {
- this.idsSecond = selection.map((item) => item.tagid);
- this.single = selection.length != 1;
- this.multiple = !selection.length;
- },
- // 鏄剧ず鍥捐〃寮圭獥
-
- showChartDialog() {
- this.chartDialogVisible = true;
- this.$nextTick(() => {
- this.initPieChart();
- this.initBarLineChart();
- });
- },
- // 鍦╩ethods涓慨鏀圭粺璁℃柟娉�
- showChartDialog() {
- this.chartDialogVisible = true;
- this.$nextTick(() => {
- console.log(this.userList, "this.userList");
-
- this.initCharts();
- });
- },
-
- // 鏂板鍒濆鍖栧浘琛ㄦ柟娉�
- initCharts() {
- this.initPieChart();
- this.initBarLineChart();
- },
-
- // 鍒濆鍖栭ゼ鍥�
- initPieChart() {
- const echarts = require("echarts");
- const pieDom = document.getElementById("pieChart");
- if (!pieDom) return;
-
- if (this.pieChart) {
- this.pieChart.dispose();
- }
-
- this.pieChart = echarts.init(pieDom);
-
- // 璁$畻楗煎浘鏁版嵁
- const followUpData = {
- pending: 0,
- success: 0,
- fail: 0,
- };
-
- this.userList.forEach((item) => {
- followUpData.pending += item.pendingFollowUp || 0;
- followUpData.success += item.followUpSuccess || 0;
- followUpData.fail += item.followUpFail || 0;
- });
-
- // 浣跨敤鏇寸編瑙傜殑棰滆壊鏂规
- const pieOption = {
- title: {
- text: "闅忚鐘舵�佸垎甯�",
- left: "center",
- textStyle: {
- color: "#333",
- fontSize: 16,
- },
- },
- tooltip: {
- trigger: "item",
- formatter: "{a} <br/>{b}: {c} ({d}%)",
- },
- legend: {
- orient: "vertical",
- left: "left",
- data: ["寰呴殢璁�", "闅忚鎴愬姛", "闅忚澶辫触"],
- textStyle: {
- color: "#666",
- },
- },
- color: ["#FF9D4D", "#36B37E", "#FF5C5C"], // 鏂扮殑閰嶈壊鏂规
- series: [
- {
- name: "闅忚鐘舵��",
- type: "pie",
- radius: ["40%", "70%"],
- avoidLabelOverlap: true,
- itemStyle: {
- borderRadius: 10,
- borderColor: "#fff",
- borderWidth: 2,
- },
- label: {
- show: true,
- formatter: "{b}: {c} ({d}%)",
- color: "#333",
- },
- emphasis: {
- label: {
- show: true,
- fontSize: "18",
- fontWeight: "bold",
- },
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: "rgba(0, 0, 0, 0.5)",
- },
- },
- data: [
- {
- value: followUpData.pending,
- name: "寰呴殢璁�",
- },
- {
- value: followUpData.success,
- name: "闅忚鎴愬姛",
- },
- {
- value: followUpData.fail,
- name: "闅忚澶辫触",
- },
- ],
- },
- ],
- };
-
- this.pieChart.setOption(pieOption);
- window.addEventListener("resize", this.resizePieChart);
- },
-
- // 鍒濆鍖栨煴鐘舵姌绾垮浘
- initBarLineChart() {
- const echarts = require("echarts");
- const barDom = document.getElementById("barLineChart");
- if (!barDom) return;
-
- if (this.barLineChart) {
- this.barLineChart.dispose();
- }
-
- this.barLineChart = echarts.init(barDom);
-
- // 鍑嗗鏁版嵁
- const categories = this.userList.map(
- (item) => item.leavehospitaldistrictname || item.deptname
- );
-
- const dischargeData = this.userList.map(
- (item) => item.dischargeCount || 0
- );
- const followUpData = this.userList.map(
- (item) => item.followUpNeeded || 0
- );
-
- // 鏂板涓ゆ潯鎶樼嚎鏁版嵁
- const followUpRateData = this.userList.map((item) => {
- if (!item.followUpRate) return 0;
- // 鍘绘帀鐧惧垎鍙峰苟杞负鏁板瓧
- const rateStr = String(item.followUpRate).replace("%", "");
- return parseFloat(rateStr) || 0;
- });
-
- const timelyRateData = this.userList.map((item) =>
- item.rate ? (Number(item.rate) * 100).toFixed(2) : 0
- );
-
- const option = {
- title: {
- text: "绉戝/鐥呭尯闅忚瓒嬪娍",
- left: "center",
- textStyle: {
- color: "#333",
- fontSize: 16,
- },
- },
- tooltip: {
- trigger: "axis",
- axisPointer: {
- type: "cross",
- crossStyle: {
- color: "#999",
- },
- },
- },
- legend: {
- data: ["鍑洪櫌浜烘", "搴旈殢璁夸汉娆�", "闅忚鐜�(%)", "鍙婃椂鐜�(%)"],
- top: "bottom",
- textStyle: {
- color: "#666",
- },
- },
- color: ["#5470C6", "#91CC75", "#EE6666", "#9A60B4"], // 鏂板绱壊鐢ㄤ簬鍙婃椂鐜�
- xAxis: {
- type: "category",
- data: categories,
- axisLabel: {
- interval: 0,
- rotate: 30,
- color: "#666",
- },
- axisLine: {
- lineStyle: {
- color: "#ddd",
- },
- },
- },
- yAxis: [
- {
- type: "value",
- name: "浜烘",
- min: 0,
- axisLabel: {
- color: "#666",
- },
- axisLine: {
- lineStyle: {
- color: "#ddd",
- },
- },
- splitLine: {
- lineStyle: {
- color: "#f0f0f0",
- },
- },
- },
- {
- type: "value",
- name: "鐧惧垎姣�(%)",
- min: 0,
- max: 100,
- axisLabel: {
- color: "#666",
- formatter: "{value}%",
- },
- axisLine: {
- lineStyle: {
- color: "#ddd",
- },
- },
- splitLine: {
- show: false,
- },
- },
- ],
- series: [
- {
- name: "鍑洪櫌浜烘",
- type: "bar",
- barWidth: "25%",
- data: dischargeData,
- itemStyle: {
- borderRadius: [4, 4, 0, 0],
- },
- },
- {
- name: "搴旈殢璁夸汉娆�",
- type: "bar",
- barWidth: "25%",
- data: followUpData,
- itemStyle: {
- borderRadius: [4, 4, 0, 0],
- },
- },
- {
- name: "闅忚鐜�(%)",
- type: "line",
- yAxisIndex: 1,
- data: followUpRateData,
- symbolSize: 8,
- lineStyle: {
- width: 3,
- },
- markLine: {
- silent: true,
- data: [
- {
- yAxis: 80,
- lineStyle: {
- color: "#EE6666",
- type: "dashed",
- },
- // label: {
- // position: 'end',
- // formatter: '鐩爣80%'
- // }
- },
- ],
- },
- },
- {
- name: "鍙婃椂鐜�(%)",
- type: "line",
- yAxisIndex: 1,
- data: timelyRateData,
- symbolSize: 8,
- lineStyle: {
- width: 3,
- type: "dotted", // 浣跨敤铏氱嚎鍖哄垎
- },
- markLine: {
- silent: true,
- data: [
- {
- yAxis: 90,
- lineStyle: {
- color: "#9A60B4",
- type: "dashed",
- },
- // label: {
- // position: 'end',
- // formatter: '鐩爣90%'
- // }
- },
- ],
- },
- },
- ],
- grid: {
- top: "15%",
- left: "3%",
- right: "4%",
- bottom: "15%",
- containLabel: true,
- },
- };
-
- this.barLineChart.setOption(option);
- window.addEventListener("resize", this.resizeBarLineChart);
- },
-
- // 鍥捐〃鍝嶅簲寮忚皟鏁存柟娉�
- resizePieChart() {
- if (this.pieChart) {
- this.pieChart.resize();
- }
- },
-
- resizeBarLineChart() {
- if (this.barLineChart) {
- this.barLineChart.resize();
- }
- },
-
- // 鍦ㄧ粍浠堕攢姣佹椂娓呯悊
- beforeDestroy() {
- // 绉婚櫎浜嬩欢鐩戝惉
- window.removeEventListener("resize", this.resizePieChart);
- window.removeEventListener("resize", this.resizeBarLineChart);
-
- // 閿�姣佸浘琛ㄥ疄渚�
- if (this.pieChart) {
- this.pieChart.dispose();
- this.pieChart = null;
- }
- if (this.barLineChart) {
- this.barLineChart.dispose();
- this.barLineChart = null;
- }
- },
- },
-};
+ handleSearch() {
+ // 鎼滅储閫昏緫
+ }
+ }
+}
</script>
<style lang="scss" scoped>
-::v-deep .el-tabs__header {
- margin-bottom: 20px;
-}
-
-::v-deep .el-tabs__item {
- font-size: 16px;
- padding: 0 20px;
- height: 40px;
- line-height: 40px;
-}
-
-::v-deep .el-tabs__active-bar {
- height: 3px;
-}
-
-/* Tab鍐呭鍖哄煙鏍峰紡 */
-.el-tab-pane {
- .your-table-container {
- margin-top: 10px;
- }
-}
-.sidecolumn {
- width: 180px;
- min-height: 100vh;
- text-align: center;
- // display: flex;
- margin-top: 20px;
- margin: 20px;
- padding: 30px;
- background: #edf1f7;
- 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);
- .sidecolumn-top {
- display: flex;
- justify-content: space-between;
- .top-wj {
- font-size: 20px;
- }
- .top-tj {
- font-size: 18px;
-
- color: rgb(0, 89, 255);
- cursor: pointer;
- }
- }
- .center-ss {
- margin-top: 30px;
- .input-with-select {
- height: 40px !important;
- }
- }
- .bottom-fl {
- margin-top: 30px;
- display: center !important;
- }
-}
-.qrcode-dialo {
- text-align: center;
- // display: flex;
- margin: 20px;
- padding: 30px;
- background: #edf1f7;
- 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);
- .qrcode-text {
- font-size: 20px;
- span {
- margin-left: 20px;
- }
- }
- .qrcode-img {
- width: 300px;
- height: 400px;
- }
-}
-::v-deep.el-tabs--left,
-.el-tabs--right {
- overflow: hidden;
- align-items: center;
- display: flex;
-}
-::v-deep.el-input--medium .el-input__inner {
- height: 40px !important;
-}
-::v-deep.el-tabs--right .el-tabs__active-bar.is-right {
- height: 40px;
- width: 5px;
- left: 0;
-}
-::v-deep.el-tabs--right .el-tabs__item.is-right {
- display: block;
- text-align: left;
- font-size: 20px;
-}
-// 缇庡寲鍚堣琛屾牱寮�
-::v-deep .el-table__footer {
- .el-table__cell {
- background-color: #f5f7fa;
- font-weight: 600;
- color: #409eff;
-
- .cell {
- font-weight: 600;
- color: #409eff;
- }
- }
-}
-
-// 鍐呴儴琛ㄦ牸鍚堣琛屾牱寮�
-::v-deep .inner-table .el-table__footer {
- .el-table__cell {
- background-color: #ecf5ff;
- font-weight: 500;
- color: #67c23a;
-
- .cell {
- font-weight: 500;
- color: #67c23a;
- }
- }
-}
-
-// 鐧惧垎姣斿瓧娈电壒娈婃牱寮�
-.your-table-container
- ::v-deep
- .el-table__footer
- .el-table__cell[data-field="followUpRate"]
- .cell,
-.your-table-container
- ::v-deep
- .el-table__footer
- .el-table__cell[data-field="rate"]
- .cell,
-.your-table-container
- ::v-deep
- .el-table__footer
- .el-table__cell[data-field="followUpRateAgain"]
- .cell {
- color: #e6a23c !important;
- font-weight: 700 !important;
-}
-
-.leftvlue {
- // display: flex;
- // flex: 1;
- // width: 80%;
- // margin-top: 20px;
- margin: 20px;
- padding: 30px;
+.follow-up-statistics {
+ padding: 20px;
background: #ffff;
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);
- .mulsz {
- font-size: 20px;
- }
-}
-/* 浣胯鏈夋墜鍨嬫寚閽� */
-.el-table__row {
- cursor: pointer;
-}
-/* 鍐呭眰鍖荤敓琛ㄦ牸鏍峰紡 */
-.inner-table {
- // 琛ㄥご鑳屾櫙鑹�
- ::v-deep .el-table__header-wrapper {
- background-color: #f0f7ff !important;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
- th {
- background-color: #f0f7ff !important;
+ .search-section {
+ margin-bottom: 20px;
+ }
+
+ .tab-section {
+ ::v-deep .el-tabs__header {
+ margin-bottom: 20px;
+ }
+
+ ::v-deep .el-tabs__item {
+ font-size: 16px;
+ padding: 0 20px;
+ height: 40px;
+ line-height: 40px;
+ }
+
+ ::v-deep .el-tabs__active-bar {
+ height: 3px;
}
}
-
- // 琛ㄦ牸琛岃儗鏅壊
- ::v-deep .el-table__body-wrapper {
- tr {
- background-color: #f9fbfe !important;
-
- &:hover {
- background-color: #e6f1ff !important;
- }
- }
- }
-
- // 杈规棰滆壊
- ::v-deep .el-table--border {
- border-color: #d9e8ff !important;
-
- td,
- th {
- border-color: #d9e8ff !important;
- }
- }
-
- // 鏂戦┈绾规晥鏋�
- ::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td {
- background-color: #f5f9ff !important;
- }
-}
-/* 灞曞紑琛屾牱寮� */
-.el-table__expanded-cell {
- padding: 10px 0 !important;
- background: #f8f8f8;
-}
-.document {
- width: 100px;
- height: 50px;
-}
-.data-list {
- max-height: 800px;
- overflow-y: auto;
-}
-.documentf {
- display: flex;
- justify-content: flex-end;
-}
-.button-text {
- color: rgb(70, 204, 238);
-}
-.button-textck {
- color: rgb(39, 167, 67);
-}
-.button-textxg {
- color: rgb(35, 81, 233);
-}
-.button-textsc {
- color: rgb(235, 23, 23);
}
</style>
diff --git a/vue.config.js b/vue.config.js
index 5a49e1f..9099947 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -36,9 +36,10 @@
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
// target: `https://www.health-y.cn/lssf`,
- target: `http://192.168.100.10:8096`,
- // target: `http://192.168.100.10:8094`,//鐪佺珛鍚屽痉
+ // target: `http://192.168.100.10:8096`,
+ target: `http://192.168.100.10:8094`,//鐪佺珛鍚屽痉
// target: `http://192.168.100.10:8095`,//鏂板崕
+ // target: `http://192.168.100.10:8098`,//甯備竴
// target:`http://localhost:8095`,
// target:`http://35z1t16164.qicp.vip`,
// target: `http://192.168.100.172:8095`,
diff --git "a/\345\270\202\344\270\200.zip" "b/\345\270\202\344\270\200.zip"
new file mode 100644
index 0000000..78b3603
--- /dev/null
+++ "b/\345\270\202\344\270\200.zip"
Binary files differ
--
Gitblit v1.9.3