From 15371b329484632c987e349e50f41cab90d3ae8c Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 15 四月 2026 09:28:25 +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 ++++++++++++
src/views/followvisit/again/index.vue | 50
src/views/sfstatistics/percentage/components/TimelyRateDialog.vue | 249 +
vue.config.js | 5
src/components/AudioPlayer/index.vue | 964 ++++
src/views/sfstatistics/percentage/components/FirstFollowUp.vue | 728 +++
src/views/Satisfaction/configurationmyd/batch.vue | 1004 ++-
src/views/sfstatistics/percentage/components/styles.scss | 90
src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue | 1266 +++--
src/views/sfstatistics/percentage/components/ChartDialog.vue | 579 ++
/dev/null | 0
src/api/AiCentre/satisfactionse.js | 25
src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue | 70
src/views/followvisit/HistoricalFollow/index.vue | 6
src/views/followvisit/record/detailpage/index.vue | 39
src/views/sfstatistics/percentage/index.vue | 3338 +------------
src/views/sfstatistics/percentage/components/ContinuedCare.vue | 633 ++
src/views/sfstatistics/percentage/components/DetailDialog.vue | 302 +
src/views/Satisfaction/configurationmyd/index.vue | 554 +-
src/views/Satisfaction/configurationmyd/dispose.vue | 570 +-
src/views/followvisit/discharge/index.vue | 6
23 files changed, 9,497 insertions(+), 4,566 deletions(-)
diff --git a/src/api/AiCentre/satisfactionse.js b/src/api/AiCentre/satisfactionse.js
index e9901b0..fef0537 100644
--- a/src/api/AiCentre/satisfactionse.js
+++ b/src/api/AiCentre/satisfactionse.js
@@ -35,6 +35,31 @@
method: "get",
});
}
+// 寮傚父澶勭悊鍒楄〃
+export function tracedeallist(data) {
+ return request({
+ url: "/smartor/trace/tracedeallist",
+ method: "post",
+ data: data,
+ });
+}
+// 鎵归噺澶勭悊鍒楄〃
+export function tracelist(data) {
+ return request({
+ url: "/smartor/trace/list",
+ method: "post",
+ data: data,
+ });
+}
+// 浠诲姟鍒楄〃淇敼澶勭悊
+export function traceedit(data) {
+ return request({
+ url: "/smartor/trace/edit",
+ method: "post",
+ data: data,
+ });
+}
+
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/components/AudioPlayer/index.vue b/src/components/AudioPlayer/index.vue
new file mode 100644
index 0000000..0524c1f
--- /dev/null
+++ b/src/components/AudioPlayer/index.vue
@@ -0,0 +1,964 @@
+<template>
+ <div class="audio-player">
+ <!-- 涓绘挱鏀惧櫒 -->
+ <div class="audio-container" v-if="showDefaultPlayer">
+ <audio
+ ref="audioElement"
+ :src="audioSource"
+ preload="metadata"
+ @timeupdate="updateTime"
+ @loadedmetadata="updateDuration"
+ @play="handlePlay"
+ @pause="handlePause"
+ @ended="handleEnded"
+ @error="handleError"
+ style="display: none"
+ ></audio>
+
+ <!-- 鎾斁鎺у埗 -->
+ <div class="audio-controls">
+ <el-button
+ v-if="!isPlaying"
+ type="text"
+ icon="el-icon-video-play"
+ class="play-btn"
+ @click="playAudio"
+ :loading="loading"
+ ></el-button>
+ <el-button
+ v-else
+ type="text"
+ icon="el-icon-video-pause"
+ class="pause-btn"
+ @click="pauseAudio"
+ ></el-button>
+
+ <!-- 杩涘害鏉� -->
+ <div class="progress-container" @click="seekAudio" @mousemove="updateHoverTime">
+ <div class="progress-background">
+ <!-- 缂撳啿杩涘害 -->
+ <div
+ v-if="buffered.length > 0"
+ class="buffered-progress"
+ :style="{ width: `${bufferedPercent}%` }"
+ ></div>
+
+ <!-- 鎾斁杩涘害 -->
+ <div
+ class="played-progress"
+ :style="{ width: `${progressPercent}%` }"
+ ></div>
+
+ <!-- 鎮仠棰勮 -->
+ <div
+ v-if="showHoverPreview"
+ class="hover-preview"
+ :style="{ left: `${hoverPercent}%` }"
+ >
+ <span class="hover-time">{{ formatTime(hoverTime) }}</span>
+ </div>
+
+ <!-- 鎾斁鐐� -->
+ <div
+ class="playhead"
+ :style="{ left: `${progressPercent}%` }"
+ ></div>
+ </div>
+ </div>
+
+ <!-- 鏃堕棿鏄剧ず -->
+ <div class="time-display">
+ <span class="current-time">{{ formatTime(currentTime) }}</span>
+ <span class="time-separator">/</span>
+ <span class="duration">{{ formatTime(duration) }}</span>
+ </div>
+
+ <!-- 闊抽噺鎺у埗 -->
+ <div class="volume-control" v-if="showVolumeControl">
+ <el-popover
+ placement="top"
+ width="40"
+ trigger="hover"
+ popper-class="volume-popover"
+ >
+ <div class="volume-slider-container" @click.stop>
+ <el-slider
+ v-model="volume"
+ vertical
+ height="100px"
+ :show-tooltip="false"
+ @input="changeVolume"
+ ></el-slider>
+ </div>
+
+ <el-button
+ slot="reference"
+ type="text"
+ :icon="volumeIcon"
+ class="volume-btn"
+ @click.stop
+ ></el-button>
+ </el-popover>
+ </div>
+
+ <!-- 鎾斁閫熷害 -->
+ <el-select
+ v-if="showPlaybackRate"
+ v-model="playbackRate"
+ size="mini"
+ class="playback-rate"
+ @change="changePlaybackRate"
+ >
+ <el-option
+ v-for="rate in playbackRates"
+ :key="rate"
+ :label="`${rate}x`"
+ :value="rate"
+ ></el-option>
+ </el-select>
+
+ <!-- 涓嬭浇鎸夐挳 -->
+ <el-button
+ v-if="showDownload"
+ type="text"
+ icon="el-icon-download"
+ class="download-btn"
+ @click="downloadAudio"
+ title="涓嬭浇闊抽"
+ ></el-button>
+
+ <!-- 鏇村鍔熻兘鎸夐挳 -->
+ <el-dropdown
+ v-if="showMoreOptions"
+ trigger="click"
+ class="more-options"
+ >
+ <el-button type="text" icon="el-icon-more" class="more-btn"></el-button>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item @click.native="loopAudio = !loopAudio">
+ <i :class="loopAudio ? 'el-icon-refresh' : 'el-icon-refresh-left'"></i>
+ {{ loopAudio ? '鍏抽棴寰幆' : '寮�鍚惊鐜�' }}
+ </el-dropdown-item>
+ <el-dropdown-item @click.native="resetAudio">
+ <i class="el-icon-refresh-right"></i>
+ 閲嶇疆
+ </el-dropdown-item>
+ <el-dropdown-item v-if="showDetails" @click.native="showAudioInfo">
+ <i class="el-icon-info"></i>
+ 闊抽淇℃伅
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </div>
+ </div>
+
+ <!-- 闊抽淇℃伅瀵硅瘽妗� -->
+ <el-dialog
+ v-if="showDetailsDialog"
+ title="闊抽淇℃伅"
+ :visible.sync="showDetailsDialog"
+ width="400px"
+ >
+ <div class="audio-info">
+ <div class="info-item">
+ <span class="label">鏂囦欢澶у皬锛�</span>
+ <span class="value">{{ fileSize }}</span>
+ </div>
+ <div class="info-item">
+ <span class="label">闊抽鏃堕暱锛�</span>
+ <span class="value">{{ formatTime(duration) }}</span>
+ </div>
+ <div class="info-item">
+ <span class="label">鏂囦欢鏍煎紡锛�</span>
+ <span class="value">{{ audioFormat }}</span>
+ </div>
+ <div class="info-item">
+ <span class="label">闊抽鍦板潃锛�</span>
+ <a :href="audioSource" target="_blank" class="audio-url">{{ truncateUrl(audioSource) }}</a>
+ </div>
+ </div>
+ </el-dialog>
+
+ <!-- 绠�鏄撴挱鏀惧櫒锛堜粎鏄剧ず鎾斁鎸夐挳锛� -->
+ <div v-else class="simple-player">
+ <el-button
+ v-if="!isPlaying"
+ type="text"
+ icon="el-icon-video-play"
+ size="small"
+ class="simple-play-btn"
+ @click="playAudio"
+ :loading="loading"
+ >
+ 鎾斁褰曢煶
+ </el-button>
+ <el-button
+ v-else
+ type="text"
+ icon="el-icon-video-pause"
+ size="small"
+ class="simple-pause-btn"
+ @click="pauseAudio"
+ >
+ 鏆傚仠鎾斁
+ </el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'AudioPlayer',
+ props: {
+ // 闊抽婧愬湴鍧�
+ audioSource: {
+ type: String,
+ default: ''
+ },
+
+ // 鏄惁鏄剧ず瀹屾暣鎾斁鍣�
+ showDefaultPlayer: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鏄惁鏄剧ず闊抽噺鎺у埗
+ showVolumeControl: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鏄惁鏄剧ず鎾斁閫熷害鎺у埗
+ showPlaybackRate: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鏄惁鏄剧ず涓嬭浇鎸夐挳
+ showDownload: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鏄惁鏄剧ず鏇村閫夐」
+ showMoreOptions: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鏄惁鏄剧ず闊抽淇℃伅
+ showDetails: {
+ type: Boolean,
+ default: true
+ },
+
+ // 鍒濆闊抽噺锛�0-100锛�
+ initialVolume: {
+ type: Number,
+ default: 80,
+ validator: (value) => value >= 0 && value <= 100
+ },
+
+ // 鍒濆鎾斁閫熷害
+ initialPlaybackRate: {
+ type: Number,
+ default: 1.0
+ },
+
+ // 鑷姩鎾斁
+ autoplay: {
+ type: Boolean,
+ default: false
+ },
+
+ // 寰幆鎾斁
+ loop: {
+ type: Boolean,
+ default: false
+ }
+ },
+
+ data() {
+ return {
+ // 鎾斁鐘舵��
+ isPlaying: false,
+ isLoading: false,
+ loading: false,
+ error: false,
+
+ // 鏃堕棿鐩稿叧
+ currentTime: 0,
+ duration: 0,
+ buffered: [],
+
+ // 闊抽噺
+ volume: this.initialVolume,
+ isMuted: false,
+
+ // 鎾斁閫熷害
+ playbackRate: this.initialPlaybackRate,
+ playbackRates: [0.5, 0.75, 1.0, 1.25, 1.5, 2.0],
+
+ // 寰幆鎾斁
+ loopAudio: this.loop,
+
+ // 杩涘害鏉℃偓鍋�
+ hoverTime: 0,
+ hoverPercent: 0,
+ showHoverPreview: false,
+
+ // 闊抽淇℃伅
+ showDetailsDialog: false,
+ fileSize: '鏈煡',
+ audioFormat: '鏈煡',
+
+ // 鐩戝惉鍣ㄥ紩鐢�
+ resizeObserver: null
+ };
+ },
+
+ computed: {
+ // 鎾斁杩涘害鐧惧垎姣�
+ progressPercent() {
+ if (this.duration <= 0) return 0;
+ return (this.currentTime / this.duration) * 100;
+ },
+
+ // 缂撳啿杩涘害鐧惧垎姣�
+ bufferedPercent() {
+ if (this.duration <= 0) return 0;
+ if (this.buffered.length === 0) return 0;
+
+ const bufferedEnd = this.buffered.end(this.buffered.length - 1);
+ return (bufferedEnd / this.duration) * 100;
+ },
+
+ // 闊抽噺鍥炬爣
+ volumeIcon() {
+ if (this.isMuted || this.volume === 0) {
+ return 'el-icon-turn-off-microphone';
+ } else if (this.volume <= 30) {
+ return 'el-icon-microphone';
+ } else if (this.volume <= 70) {
+ return 'el-icon-microphone';
+ } else {
+ return 'el-icon-microphone';
+ }
+ }
+ },
+
+ watch: {
+ // 鐩戝惉闊抽婧愬彉鍖�
+ audioSource(newSource) {
+ if (newSource) {
+ this.resetAudio();
+ this.loadAudio();
+ }
+ },
+
+ // 鐩戝惉鑷姩鎾斁
+ autoplay(newVal) {
+ if (newVal && this.audioSource) {
+ this.playAudio();
+ }
+ },
+
+ // 鐩戝惉寰幆鎾斁
+ loopAudio(newVal) {
+ this.$emit('loop-change', newVal);
+ }
+ },
+
+ mounted() {
+ if (this.audioSource) {
+ this.loadAudio();
+ }
+
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲
+ this.resizeObserver = new ResizeObserver(() => {
+ this.updateBuffered();
+ });
+
+ if (this.$refs.audioElement) {
+ this.resizeObserver.observe(this.$refs.audioElement);
+ }
+ },
+
+ beforeDestroy() {
+ if (this.resizeObserver) {
+ this.resizeObserver.disconnect();
+ }
+
+ // 鍋滄闊抽鎾斁
+ this.pauseAudio();
+ },
+
+ methods: {
+ // 鍔犺浇闊抽
+ async loadAudio() {
+ this.loading = true;
+ this.error = false;
+
+ try {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ // 璁剧疆闊抽噺
+ audio.volume = this.volume / 100;
+ audio.playbackRate = this.playbackRate;
+ audio.loop = this.loopAudio;
+
+ // 灏濊瘯鑾峰彇鏂囦欢淇℃伅
+ this.getAudioInfo();
+
+ // 濡傛灉璁剧疆浜嗚嚜鍔ㄦ挱鏀撅紝寮�濮嬫挱鏀�
+ if (this.autoplay) {
+ await this.playAudio();
+ }
+ } catch (error) {
+ console.error('鍔犺浇闊抽澶辫触:', error);
+ this.error = true;
+ this.$emit('error', error);
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ // 鎾斁闊抽
+ async playAudio() {
+ try {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ await audio.play();
+ this.isPlaying = true;
+ this.$emit('play');
+ } catch (error) {
+ console.error('鎾斁澶辫触:', error);
+ this.error = true;
+ this.isPlaying = false;
+ this.$emit('error', error);
+
+ // 濡傛灉鏄敤鎴蜂氦浜掑紩璧风殑閿欒锛屾彁绀虹敤鎴�
+ if (error.name === 'NotAllowedError') {
+ this.$message.warning('璇锋墜鍔ㄧ偣鍑绘挱鏀炬寜閽紑濮嬫挱鏀�');
+ }
+ }
+ },
+
+ // 鏆傚仠闊抽
+ pauseAudio() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ audio.pause();
+ this.isPlaying = false;
+ this.$emit('pause');
+ },
+
+ // 璺宠浆鍒版寚瀹氭椂闂�
+ seekAudio(event) {
+ const audio = this.$refs.audioElement;
+ if (!audio || this.duration <= 0) return;
+
+ const progressContainer = event.currentTarget;
+ const rect = progressContainer.getBoundingClientRect();
+ const x = event.clientX - rect.left;
+ const width = rect.width;
+
+ const percent = Math.max(0, Math.min(1, x / width));
+ const time = percent * this.duration;
+
+ audio.currentTime = time;
+ this.currentTime = time;
+ this.$emit('seek', time);
+ },
+
+ // 鏇存柊鎮仠鏃堕棿
+ updateHoverTime(event) {
+ const progressContainer = event.currentTarget;
+ const rect = progressContainer.getBoundingClientRect();
+ const x = event.clientX - rect.left;
+ const width = rect.width;
+
+ const percent = Math.max(0, Math.min(1, x / width));
+ this.hoverPercent = percent * 100;
+ this.hoverTime = percent * this.duration;
+ this.showHoverPreview = true;
+ },
+
+ // 闅愯棌鎮仠棰勮
+ hideHoverPreview() {
+ this.showHoverPreview = false;
+ },
+
+ // 鏇存柊鏃堕棿
+ updateTime() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ this.currentTime = audio.currentTime;
+ this.$emit('timeupdate', this.currentTime);
+ },
+
+ // 鏇存柊鎬绘椂闀�
+ updateDuration() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ this.duration = audio.duration;
+ this.updateBuffered();
+ this.$emit('loadedmetadata', this.duration);
+ },
+
+ // 鏇存柊缂撳啿鏁版嵁
+ updateBuffered() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ this.buffered = audio.buffered;
+ },
+
+ // 澶勭悊鎾斁
+ handlePlay() {
+ this.isPlaying = true;
+ this.$emit('play');
+ },
+
+ // 澶勭悊鏆傚仠
+ handlePause() {
+ this.isPlaying = false;
+ this.$emit('pause');
+ },
+
+ // 澶勭悊鎾斁缁撴潫
+ handleEnded() {
+ this.isPlaying = false;
+ this.currentTime = 0;
+ this.$emit('ended');
+ },
+
+ // 澶勭悊閿欒
+ handleError(event) {
+ console.error('闊抽鎾斁閿欒:', event);
+ this.error = true;
+ this.isPlaying = false;
+ this.$emit('error', event);
+ },
+
+ // 鏀瑰彉闊抽噺
+ changeVolume(value) {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ audio.volume = value / 100;
+ this.volume = value;
+ this.isMuted = value === 0;
+ this.$emit('volume-change', value);
+ },
+
+ // 闈欓煶/鍙栨秷闈欓煶
+ toggleMute() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ this.isMuted = !this.isMuted;
+ audio.muted = this.isMuted;
+ this.$emit('mute-change', this.isMuted);
+ },
+
+ // 鏀瑰彉鎾斁閫熷害
+ changePlaybackRate(rate) {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ audio.playbackRate = rate;
+ this.playbackRate = rate;
+ this.$emit('playbackrate-change', rate);
+ },
+
+ // 閲嶇疆闊抽
+ resetAudio() {
+ const audio = this.$refs.audioElement;
+ if (!audio) return;
+
+ audio.currentTime = 0;
+ this.currentTime = 0;
+ this.pauseAudio();
+ this.$emit('reset');
+ },
+
+ // 涓嬭浇闊抽
+ downloadAudio() {
+ if (!this.audioSource) {
+ this.$message.warning('闊抽鍦板潃鏃犳晥');
+ return;
+ }
+
+ const link = document.createElement('a');
+ link.href = this.audioSource;
+ link.download = this.getFileNameFromUrl(this.audioSource);
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+
+ this.$emit('download');
+ },
+
+ // 鏄剧ず闊抽淇℃伅
+ async showAudioInfo() {
+ this.showDetailsDialog = true;
+ await this.getAudioInfo();
+ },
+
+ // 鑾峰彇闊抽淇℃伅
+ async getAudioInfo() {
+ if (!this.audioSource) return;
+
+ try {
+ // 鑾峰彇鏂囦欢澶у皬
+ const response = await fetch(this.audioSource, { method: 'HEAD' });
+ const contentLength = response.headers.get('content-length');
+
+ if (contentLength) {
+ this.fileSize = this.formatFileSize(contentLength);
+ }
+
+ // 鑾峰彇鏂囦欢鏍煎紡
+ const url = this.audioSource.toLowerCase();
+ if (url.endsWith('.mp3')) this.audioFormat = 'MP3';
+ else if (url.endsWith('.wav')) this.audioFormat = 'WAV';
+ else if (url.endsWith('.ogg')) this.audioFormat = 'OGG';
+ else if (url.endsWith('.m4a')) this.audioFormat = 'M4A';
+ else if (url.endsWith('.aac')) this.audioFormat = 'AAC';
+ else this.audioFormat = '鏈煡鏍煎紡';
+
+ } catch (error) {
+ console.error('鑾峰彇闊抽淇℃伅澶辫触:', error);
+ this.fileSize = '鏈煡';
+ this.audioFormat = '鏈煡';
+ }
+ },
+
+ // 鏍煎紡鍖栨椂闂�
+ formatTime(time) {
+ if (isNaN(time) || time < 0) return '00:00';
+
+ const hours = Math.floor(time / 3600);
+ const minutes = Math.floor((time % 3600) / 60);
+ const seconds = Math.floor(time % 60);
+
+ if (hours > 0) {
+ return `${hours.toString().padStart(2, '0')}:${minutes
+ .toString()
+ .padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
+ } else {
+ return `${minutes.toString().padStart(2, '0')}:${seconds
+ .toString()
+ .padStart(2, '0')}`;
+ }
+ },
+
+ // 鏍煎紡鍖栨枃浠跺ぇ灏�
+ formatFileSize(bytes) {
+ if (bytes === 0) return '0 B';
+
+ const k = 1024;
+ const sizes = ['B', 'KB', 'MB', 'GB'];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+ },
+
+ // 鎴柇URL鏄剧ず
+ truncateUrl(url, maxLength = 40) {
+ if (!url) return '';
+ if (url.length <= maxLength) return url;
+
+ const start = url.substring(0, maxLength / 2 - 3);
+ const end = url.substring(url.length - maxLength / 2 + 3);
+ return start + '...' + end;
+ },
+
+ // 浠嶶RL鑾峰彇鏂囦欢鍚�
+ getFileNameFromUrl(url) {
+ if (!url) return 'audio';
+
+ const fileName = url.split('/').pop();
+ return fileName || 'audio';
+ }
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+.audio-player {
+ width: 100%;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+
+ .audio-container {
+ background: #fff;
+ border-radius: 8px;
+ padding: 12px 16px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+ border: 1px solid #ebeef5;
+
+ .audio-controls {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .play-btn,
+ .pause-btn {
+ width: 36px;
+ height: 36px;
+ padding: 0;
+ font-size: 20px;
+ color: #409EFF;
+
+ &:hover {
+ color: #66b1ff;
+ }
+
+ &:active {
+ color: #3a8ee6;
+ }
+ }
+
+ .progress-container {
+ flex: 1;
+ height: 36px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+
+ .progress-background {
+ position: relative;
+ width: 100%;
+ height: 6px;
+ background: #e4e7ed;
+ border-radius: 3px;
+ overflow: visible;
+
+ .buffered-progress {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background: #c0c4cc;
+ border-radius: 3px;
+ transition: width 0.2s ease;
+ }
+
+ .played-progress {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background: #409EFF;
+ border-radius: 3px;
+ transition: width 0.2s ease;
+ z-index: 2;
+ }
+
+ .hover-preview {
+ position: absolute;
+ top: -30px;
+ width: 1px;
+ height: 20px;
+ background: #909399;
+ transform: translateX(-50%);
+ z-index: 3;
+ pointer-events: none;
+
+ .hover-time {
+ position: absolute;
+ bottom: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ background: rgba(0, 0, 0, 0.8);
+ color: white;
+ padding: 2px 6px;
+ border-radius: 3px;
+ font-size: 12px;
+ white-space: nowrap;
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 0;
+ height: 0;
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid rgba(0, 0, 0, 0.8);
+ }
+ }
+
+ .playhead {
+ position: absolute;
+ top: 50%;
+ width: 12px;
+ height: 12px;
+ background: #fff;
+ border: 2px solid #409EFF;
+ border-radius: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 4;
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ transform: translate(-50%, -50%) scale(1.2);
+ box-shadow: 0 0 8px rgba(64, 158, 255, 0.5);
+ }
+ }
+ }
+
+ &:hover {
+ .progress-background {
+ height: 8px;
+
+ .playhead {
+ transform: translate(-50%, -50%) scale(1.1);
+ }
+ }
+ }
+ }
+
+ .time-display {
+ min-width: 100px;
+ font-size: 12px;
+ color: #606266;
+ display: flex;
+ align-items: center;
+ gap: 2px;
+
+ .current-time {
+ color: #303133;
+ font-weight: 500;
+ }
+
+ .time-separator {
+ opacity: 0.6;
+ }
+
+ .duration {
+ opacity: 0.8;
+ }
+ }
+
+ .volume-control {
+ .volume-btn {
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ font-size: 16px;
+ color: #606266;
+
+ &:hover {
+ color: #409EFF;
+ }
+ }
+ }
+
+ .playback-rate {
+ width: 60px;
+
+ ::v-deep .el-input__inner {
+ height: 24px;
+ line-height: 24px;
+ padding: 0 5px;
+ font-size: 12px;
+ }
+ }
+
+ .download-btn,
+ .more-btn {
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ font-size: 16px;
+ color: #606266;
+
+ &:hover {
+ color: #409EFF;
+ }
+ }
+ }
+ }
+
+ .simple-player {
+ .simple-play-btn,
+ .simple-pause-btn {
+ padding: 4px 8px;
+ font-size: 12px;
+ color: #409EFF;
+
+ &:hover {
+ color: #66b1ff;
+ }
+ }
+ }
+
+ .audio-info {
+ .info-item {
+ margin-bottom: 12px;
+ display: flex;
+
+ .label {
+ width: 80px;
+ font-weight: 500;
+ color: #303133;
+ }
+
+ .value {
+ flex: 1;
+ color: #606266;
+ }
+
+ .audio-url {
+ color: #409EFF;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+ }
+}
+
+// 闊抽噺寮圭獥鏍峰紡
+::v-deep .volume-popover {
+ padding: 10px;
+ min-width: 40px;
+
+ .volume-slider-container {
+ height: 100px;
+ display: flex;
+ justify-content: center;
+
+ .el-slider {
+ height: 100%;
+
+ .el-slider__runway {
+ background: #e4e7ed;
+ }
+
+ .el-slider__bar {
+ background: #409EFF;
+ }
+
+ .el-slider__button {
+ border-color: #409EFF;
+ width: 12px;
+ height: 12px;
+ }
+ }
+ }
+}
+</style>
diff --git a/src/views/Satisfaction/configurationmyd/batch.vue b/src/views/Satisfaction/configurationmyd/batch.vue
index 10d6619..bd73abe 100644
--- a/src/views/Satisfaction/configurationmyd/batch.vue
+++ b/src/views/Satisfaction/configurationmyd/batch.vue
@@ -11,8 +11,9 @@
icon="el-icon-check"
@click="handleBatchSubmit"
:loading="batchProcessing"
+ :disabled="selectedExceptionIds.length === 0"
>
- 鎵归噺鎻愪氦澶勭悊
+ 鎵归噺鎻愪氦澶勭悊 ({{ selectedExceptionIds.length }})
</el-button>
<el-button type="warning" icon="el-icon-back" @click="handleGoBack">
杩斿洖寮傚父鍒楄〃
@@ -33,29 +34,40 @@
>
<el-form-item label="璐熻矗绉戝">
<el-select
- v-model="filterParams.deptId"
+ v-model="filterParams.todeptcode"
placeholder="璇烽�夋嫨绉戝"
clearable
+ filterable
style="width: 200px"
>
<el-option
v-for="dept in deptList"
- :key="dept.id"
- :label="dept.name"
- :value="dept.id"
+ :key="dept.deptCode"
+ :label="dept.label"
+ :value="dept.deptCode"
/>
</el-select>
</el-form-item>
<el-form-item label="澶勭悊鐘舵��">
<el-select
- v-model="filterParams.status"
+ v-model="filterParams.handleFlag"
placeholder="璇烽�夋嫨鐘舵��"
clearable
style="width: 200px"
>
- <el-option label="寰呭鐞�" :value="0" />
- <el-option label="澶勭悊涓�" :value="1" />
- <el-option label="宸插鐞�" :value="2" />
+ <el-option label="鏈鐞�" :value="'0'" />
+ <el-option label="宸插鐞�" :value="'1'" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="婊℃剰搴︾被鍨�">
+ <el-select
+ v-model="filterParams.templateType"
+ placeholder="璇烽�夋嫨妯℃澘绫诲瀷"
+ clearable
+ style="width: 200px"
+ >
+ <el-option label="璇煶妯℃澘" :value="1" />
+ <el-option label="闂嵎妯℃澘" :value="2" />
</el-select>
</el-form-item>
<el-form-item>
@@ -79,6 +91,7 @@
:border="true"
style="width: 100%"
@selection-change="handleSelectionChange"
+ row-key="id"
class="exception-table"
>
<el-table-column type="selection" width="55" align="center" />
@@ -92,24 +105,30 @@
<el-table-column
label="璐熻矗绉戝"
- prop="responsibilityDept"
- width="120"
+ prop="todeptname"
+ width="200"
align="center"
>
<template slot-scope="{ row }">
- <el-tag type="primary">{{ row.responsibilityDept }}</el-tag>
+ <el-tag type="primary" v-if="row.todeptname">{{
+ row.todeptname
+ }}</el-tag>
+ <span v-else class="no-data">鏈垎閰�</span>
</template>
</el-table-column>
- <el-table-column
- label="涓嶆弧鎰忚鎯�"
- prop="unsatisfactoryDetail"
- min-width="200"
- align="center"
- >
+ <el-table-column label="涓嶆弧鎰忚鎯�" min-width="250" align="center">
<template slot-scope="{ row }">
<div class="detail-content">
- {{ row.unsatisfactoryDetail }}
+ <div class="question-text">
+ <strong>闂锛�</strong>{{ row.questiontext }}
+ </div>
+ <div class="answer-text">
+ <strong>鍥炵瓟锛�</strong>{{ row.asrtext || "鏃犲洖绛�" }}
+ </div>
+ <div class="matched-text" v-if="row.matchedtext">
+ <strong>瑙f瀽鍊硷細</strong>{{ row.matchedtext }}
+ </div>
</div>
</template>
</el-table-column>
@@ -117,42 +136,50 @@
<el-table-column label="鎮h�呬俊鎭�" width="300" align="center">
<template slot-scope="{ row }">
<div class="patient-info">
- <div class="patient-item">
- <span class="label">濮撳悕锛�</span>
- <span class="value">{{ row.patientName }}</span>
+ <div class="patient-row">
+ <div class="patient-item">
+ <span class="label">濮撳悕锛�</span>
+ <span class="value">{{ row.patdescJson.sendname }}</span>
+ </div>
+ <div class="patient-item">
+ <span class="label">鎬у埆锛�</span>
+ <span class="value">{{
+ row.patdescJson.sex
+ }}</span>
+ </div>
+ <div class="patient-item">
+ <span class="label">骞撮緞锛�</span>
+ <span class="value">{{ row.patdescJson.age }}宀�</span>
+ </div>
</div>
- <div class="patient-item">
- <span class="label">鎬у埆锛�</span>
- <span class="value">{{
- row.gender === 1 ? "鐢�" : "濂�"
- }}</span>
- </div>
- <div class="patient-item">
- <span class="label">骞撮緞锛�</span>
- <span class="value">{{ row.age }}宀�</span>
- </div>
- <div class="patient-item">
- <span class="label">鐢佃瘽锛�</span>
- <span class="value">{{ row.phone }}</span>
+ <div class="patient-row">
+ <div class="patient-item full-width">
+ <span class="label">鐢佃瘽锛�</span>
+ <span class="value">{{ row.patdescJson.phone }}</span>
+ </div>
</div>
</div>
</template>
</el-table-column>
- <el-table-column label="鍑洪櫌淇℃伅" width="250" align="center">
+ <el-table-column label="濉啓淇℃伅" width="180" align="center">
<template slot-scope="{ row }">
- <div class="discharge-info">
+ <div class="fill-info">
<div class="info-item">
- <span class="label">绉戝锛�</span>
- <span class="value">{{ row.dischargeDept }}</span>
+ <span class="label">濉姤鏃堕棿锛�</span>
+ <span class="value time">{{
+ formatDateTime(row.createTime)
+ }}</span>
</div>
- <div class="info-item">
- <span class="label">鐥呭尯锛�</span>
- <span class="value">{{ row.dischargeWard }}</span>
- </div>
- <div class="info-item">
- <span class="label">濉啓鏃堕棿锛�</span>
- <span class="value time">{{ row.fillTime }}</span>
+ <div v-if="row.recordurl" class="info-item">
+ <el-button
+ type="text"
+ size="small"
+ @click="handlePlayAudio(row.recordurl)"
+ icon="el-icon-headset"
+ >
+ 鎾斁褰曢煶
+ </el-button>
</div>
</div>
</template>
@@ -160,14 +187,36 @@
<el-table-column
label="澶勭悊鐘舵��"
- prop="processStatus"
+ prop="handleFlag"
width="100"
align="center"
>
<template slot-scope="{ row }">
- <el-tag :type="getStatusTagType(row.processStatus)" effect="dark">
- {{ getStatusText(row.processStatus) }}
+ <el-tag :type="getStatusTagType(row.handleFlag)" effect="dark">
+ {{ getStatusText(row.handleFlag) }}
</el-tag>
+ </template>
+ </el-table-column>
+
+ <el-table-column label="鏈�鏂板鐞嗕俊鎭�" width="180" align="center">
+ <template slot-scope="{ row }">
+ <div v-if="row.handleTime" class="handle-info">
+ <div class="info-item">
+ <span class="label">澶勭悊浜猴細</span>
+ <span class="value">{{ row.handleBy || "绯荤粺" }}</span>
+ </div>
+ <div class="info-item">
+ <span class="label">澶勭悊鏃堕棿锛�</span>
+ <span class="value time">{{
+ formatDateTime(row.handleTime)
+ }}</span>
+ </div>
+ <div class="info-item">
+ <span class="label">澶勭悊璇存槑锛�</span>
+ <span class="value">{{ row.handledesc }}</span>
+ </div>
+ </div>
+ <span v-else class="no-data">鏈鐞�</span>
</template>
</el-table-column>
@@ -191,7 +240,7 @@
size="small"
icon="el-icon-edit"
@click="handleProcess(row)"
- :disabled="row.processStatus === 2"
+ :disabled="row.handleFlag === '1'"
>
澶勭悊
</el-button>
@@ -229,63 +278,76 @@
label-width="100px"
size="medium"
>
- <el-form-item label="澶勭悊鐘舵��" prop="status">
+ <el-form-item label="澶勭悊鐘舵��" prop="handleFlag">
<el-select
- v-model="processForm.status"
+ v-model="processForm.handleFlag"
placeholder="璇烽�夋嫨澶勭悊鐘舵��"
style="width: 100%"
>
- <el-option label="澶勭悊涓�" :value="1" />
- <el-option label="宸插鐞�" :value="2" />
- <el-option label="宸查┏鍥�" :value="3" />
+ <el-option label="宸插鐞�" :value="'1'" />
+ <el-option label="鍙栨秷澶勭悊" :value="'0'" />
</el-select>
</el-form-item>
- <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+ <el-form-item label="鎶ュ绉戝" prop="ccdepts">
<el-select
- v-model="processForm.reportDepts"
+ v-model="processForm.ccdepts"
placeholder="璇烽�夋嫨鎶ュ绉戝"
multiple
filterable
collapse-tags
style="width: 100%"
+ :disabled="processForm.handleFlag !== '1'"
>
<el-option
v-for="dept in deptList"
- :key="dept.id"
- :label="dept.name"
- :value="dept.id"
+ :key="dept.deptCode"
+ :label="dept.label"
+ :value="dept.deptCode"
/>
</el-select>
</el-form-item>
- <el-form-item label="澶勭悊澶囨敞" prop="remark">
+ <el-form-item label="澶勭悊缁撴灉" prop="handleresult">
+ <el-select
+ v-model="processForm.handleresult"
+ placeholder="璇烽�夋嫨澶勭悊缁撴灉"
+ style="width: 100%"
+ :disabled="processForm.handleFlag !== '1'"
+ >
+ <el-option label="宸茶В鍐�" value="resolved" />
+ <el-option label="宸茶В閲�" value="explained" />
+ <el-option label="宸茶浆浜�" value="transferred" />
+ <el-option label="闇�鏀硅繘" value="improvement" />
+ <el-option label="宸查┏鍥�" value="rejected" />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="澶勭悊璇存槑" prop="handledesc">
<el-input
- v-model="processForm.remark"
+ v-model="processForm.handledesc"
type="textarea"
:rows="4"
- placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+ placeholder="璇疯緭鍏ュ鐞嗚鏄庯紙鏈�澶�500瀛楋級"
maxlength="500"
show-word-limit
+ :disabled="processForm.handleFlag !== '1'"
/>
</el-form-item>
- <el-form-item label="闄勪欢涓婁紶">
- <el-upload
- class="upload-demo"
- action="#"
- :on-preview="handlePreview"
- :on-remove="handleRemove"
- :before-remove="beforeRemove"
- :limit="3"
- :on-exceed="handleExceed"
- :file-list="fileList"
- >
- <el-button size="small" type="primary">鐐瑰嚮涓婁紶</el-button>
- <div slot="tip" class="el-upload__tip">
- 鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑闄勪欢锛屽崟涓枃浠朵笉瓒呰繃10MB
- </div>
- </el-upload>
+ <el-form-item
+ label="鏈�缁堟剰瑙�"
+ prop="finaloption"
+ v-if="hasQualityPermission"
+ >
+ <el-input
+ v-model="processForm.finaloption"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ユ渶缁堝鐞嗘剰瑙侊紙鏈�澶�300瀛楋級"
+ maxlength="300"
+ show-word-limit
+ />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
@@ -310,44 +372,60 @@
label-width="100px"
size="medium"
>
- <el-form-item label="澶勭悊鐘舵��" prop="status">
+ <el-form-item label="澶勭悊鐘舵��" prop="handleFlag">
<el-select
- v-model="batchProcessForm.status"
+ v-model="batchProcessForm.handleFlag"
placeholder="璇烽�夋嫨澶勭悊鐘舵��"
style="width: 100%"
>
- <el-option label="澶勭悊涓�" :value="1" />
- <el-option label="宸插鐞�" :value="2" />
- <el-option label="宸查┏鍥�" :value="3" />
+ <el-option label="宸插鐞�" :value="'1'" />
+ <el-option label="鍙栨秷澶勭悊" :value="'0'" />
</el-select>
</el-form-item>
- <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+ <el-form-item label="鎶ュ绉戝" prop="ccdepts">
<el-select
- v-model="batchProcessForm.reportDepts"
+ v-model="batchProcessForm.ccdepts"
placeholder="璇烽�夋嫨鎶ュ绉戝"
multiple
filterable
collapse-tags
style="width: 100%"
+ :disabled="batchProcessForm.handleFlag !== '1'"
>
<el-option
v-for="dept in deptList"
- :key="dept.id"
- :label="dept.name"
- :value="dept.id"
+ :key="dept.deptCode"
+ :label="dept.label"
+ :value="dept.deptCode"
/>
</el-select>
</el-form-item>
- <el-form-item label="澶勭悊澶囨敞" prop="remark">
+ <el-form-item label="澶勭悊缁撴灉" prop="handleresult">
+ <el-select
+ v-model="batchProcessForm.handleresult"
+ placeholder="璇烽�夋嫨澶勭悊缁撴灉"
+ style="width: 100%"
+ :disabled="batchProcessForm.handleFlag !== '1'"
+ >
+ <el-option label="宸茶В鍐�" value="resolved" />
+ <el-option label="宸茶В閲�" value="explained" />
+ <el-option label="宸茶浆浜�" value="transferred" />
+ <el-option label="闇�鏀硅繘" value="improvement" />
+ <el-option label="宸查┏鍥�" value="rejected" />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="澶勭悊璇存槑" prop="handledesc">
<el-input
- v-model="batchProcessForm.remark"
+ v-model="batchProcessForm.handledesc"
type="textarea"
:rows="4"
- placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+ placeholder="璇疯緭鍏ュ鐞嗚鏄庯紙鏈�澶�500瀛楋級"
maxlength="500"
show-word-limit
+ :disabled="batchProcessForm.handleFlag !== '1'"
/>
</el-form-item>
</el-form>
@@ -358,24 +436,57 @@
@click="submitBatchProcess"
:loading="batchProcessing"
>
- 鎵归噺鎻愪氦
+ 鎵归噺鎻愪氦 ({{ selectedExceptionIds.length }})
</el-button>
</span>
+ </el-dialog>
+ <!-- 杩涘害瀵硅瘽妗� -->
+ <el-dialog
+ title="鎵归噺澶勭悊杩涘害"
+ :visible.sync="batchProgress.visible"
+ width="400px"
+ :close-on-click-modal="false"
+ :show-close="false"
+ :close-on-press-escape="false"
+ >
+ <div class="progress-content">
+ <el-progress
+ :percentage="batchProgress.percentage"
+ :status="batchProgress.percentage === 100 ? 'success' : ''"
+ />
+ <div class="progress-info">
+ 宸插鐞� {{ batchProgress.processed }}/{{ batchProgress.total }} 鏉¤褰�
+ </div>
+ </div>
</el-dialog>
<!-- 寮傚父璇︽儏寮规 -->
<Details-anomaly
:visible="detailDialogVisible"
:record-id="selectedRecordId"
:title="detailDialogTitle"
+ :record-data="selectedRecordData"
@update:visible="handleDetailDialogClose"
@processed="handleProcessed"
@close="handleDetailDialogClose"
+ />
+
+ <!-- 褰曢煶鎾斁鍣� -->
+ <audio
+ v-if="audioUrl"
+ :src="audioUrl"
+ ref="audioPlayer"
+ controls
+ style="display: none"
/>
</div>
</template>
<script>
import DetailsAnomaly from "./components/DetailsAnomaly.vue";
+import { tracelist, traceedit } from "@/api/AiCentre/index";
+import dayjs from "dayjs";
+import { deptTreeSelect } from "@/api/system/user";
+
export default {
name: "BatchProcess",
components: {
@@ -383,10 +494,15 @@
},
data() {
return {
- // 娣诲姞浠ヤ笅鏁版嵁
+ // 璇︽儏寮规鐩稿叧
detailDialogVisible: false,
selectedRecordId: null,
+ selectedRecordData: null,
detailDialogTitle: "寮傚父鍙嶉璇︽儏",
+
+ // 闊抽鎾斁
+ audioUrl: "",
+
// 褰撳墠澶勭悊鐨勫紓甯窱D
currentExceptionId: null,
@@ -395,8 +511,10 @@
// 杩囨护鍙傛暟
filterParams: {
- deptId: "",
- status: "",
+ todeptcode: "",
+ handleFlag: "",
+ templateType: null,
+ scriptids: null,
pageNum: 1,
pageSize: 10,
},
@@ -406,19 +524,11 @@
processing: false,
batchProcessing: false,
+ // 鏉冮檺鎺у埗
+ hasQualityPermission: false, // 鏄惁鍏锋湁璐ㄧ鏉冮檺
+
// 绉戝鍒楄〃
- deptList: [
- { id: 1, name: "蹇冭绠″唴绉�" },
- { id: 2, name: "绁炵粡鍐呯" },
- { id: 3, name: "鏅绉�" },
- { id: 4, name: "楠ㄧ" },
- { id: 5, name: "濡囦骇绉�" },
- { id: 6, name: "鍎跨" },
- { id: 7, name: "鎬ヨ瘖绉�" },
- { id: 8, name: "鍛煎惛鍐呯" },
- { id: 9, name: "娑堝寲鍐呯" },
- { id: 10, name: "鍐呭垎娉岀" },
- ],
+ deptList: [],
// 寮傚父鍒楄〃鏁版嵁
exceptionList: [],
@@ -427,183 +537,169 @@
// 澶勭悊瀵硅瘽妗�
processDialogVisible: false,
processForm: {
- status: "",
- reportDepts: [],
- remark: "",
+ handleFlag: "",
+ ccdepts: [],
+ handleresult: "",
+ handledesc: "",
+ finaloption: "",
+ },
+ batchProgress: {
+ visible: false,
+ percentage: 0,
+ processed: 0,
+ total: 0,
},
processRules: {
- status: [
+ handleFlag: [
{ required: true, message: "璇烽�夋嫨澶勭悊鐘舵��", trigger: "change" },
],
- remark: [
- { required: true, message: "璇疯緭鍏ュ鐞嗗娉�", trigger: "blur" },
+ handleresult: [
{
- min: 5,
- max: 500,
- message: "澶囨敞闀垮害鍦� 5 鍒� 500 涓瓧绗�",
+ required: true,
+ message: "璇烽�夋嫨澶勭悊缁撴灉",
+ trigger: "change",
+ validator: (rule, value, callback) => {
+ if (this.processForm.handleFlag === "1" && !value) {
+ callback(new Error("璇烽�夋嫨澶勭悊缁撴灉"));
+ } else {
+ callback();
+ }
+ },
+ },
+ ],
+ handledesc: [
+ {
+ required: true,
+ message: "璇疯緭鍏ュ鐞嗚鏄�",
trigger: "blur",
+ validator: (rule, value, callback) => {
+ if (
+ this.processForm.handleFlag === "1" &&
+ (!value || value.trim().length < 3)
+ ) {
+ callback(new Error("澶勭悊璇存槑鑷冲皯3涓瓧绗�"));
+ } else {
+ callback();
+ }
+ },
},
],
},
- fileList: [],
// 鎵归噺澶勭悊瀵硅瘽妗�
batchDialogVisible: false,
batchProcessForm: {
- status: "",
- reportDepts: [],
- remark: "",
+ handleFlag: "",
+ ccdepts: [],
+ handleresult: "",
+ handledesc: "",
},
};
},
+ created() {
+ // 浠庤矾鐢卞弬鏁拌幏鍙栭棶棰業D
+ this.filterParams.scriptids = this.$route.query.questionId || this.$route.query.questionIds||null;
+ // if (this.$route.query.questionId) {
+ // } else if (this.$route.query.questionIds) {
+ // console.log(
+ // this.$route.query.questionIds,
+ // "this.$route.query.questionIds"
+ // );
+
+ this.filterParams.templateType = Number(this.$route.query.type)||null;
+
+ // this.filterParams.scriptid = null;
+ // }
+ this.hasQualityPermission = this.checkQualityPermission();
+ },
+
mounted() {
this.loadExceptionList();
+ this.getDeptOptions();
},
methods: {
- // 鍔犺浇寮傚父鍒楄〃
- async loadExceptionList() {
- this.loading = true;
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return "";
try {
- // Mock 鏁版嵁
- await new Promise((resolve) => {
- setTimeout(() => {
- this.exceptionList = [
- {
- id: 1,
- responsibilityDept: "蹇冭绠″唴绉�",
- unsatisfactoryDetail:
- "鍖荤敓鏌ユ埧鏃堕棿澶煭锛屾矡閫氫笉澶熷厖鍒嗭紝瀵圭梾鎯呰В閲婁笉澶熻缁�",
- patientName: "寮犲厛鐢�",
- gender: 1,
- age: 45,
- phone: "138****1234",
- dischargeDept: "蹇冭绠″唴绉�",
- dischargeWard: "鍐呯涓�鐥呭尯",
- fillTime: "2024-01-15 10:30:25",
- processStatus: 0,
- questionnaireId: 1001,
- },
- {
- id: 2,
- responsibilityDept: "绁炵粡鍐呯",
- unsatisfactoryDetail:
- "鎶ゅ+鎵撻拡鎶�鏈笉浣筹紝鎵庝簡涓夋鎵嶆垚鍔燂紝涓旀�佸害涓嶅鑰愬績",
- patientName: "鏉庡コ澹�",
- gender: 0,
- age: 38,
- phone: "139****5678",
- dischargeDept: "绁炵粡鍐呯",
- dischargeWard: "鍐呯浜岀梾鍖�",
- fillTime: "2024-01-14 16:20:10",
- processStatus: 0,
- questionnaireId: 1002,
- },
- {
- id: 3,
- responsibilityDept: "鏅绉�",
- unsatisfactoryDetail: "鏈悗鎹㈣嵂涓嶅強鏃讹紝浼ゅ彛鐤肩棝鏃舵病鏈夊強鏃跺鐞�",
- patientName: "鐜嬪厛鐢�",
- gender: 1,
- age: 52,
- phone: "137****9012",
- dischargeDept: "鏅绉�",
- dischargeWard: "澶栫涓�鐥呭尯",
- fillTime: "2024-01-13 09:15:45",
- processStatus: 1,
- questionnaireId: 1003,
- },
- {
- id: 4,
- responsibilityDept: "楠ㄧ",
- unsatisfactoryDetail: "搴峰鎸囧涓嶅涓撲笟锛屽鎭㈠杩囩▼鎻忚堪涓嶆竻妤�",
- patientName: "鍒樺コ澹�",
- gender: 0,
- age: 65,
- phone: "136****3456",
- dischargeDept: "楠ㄧ",
- dischargeWard: "澶栫浜岀梾鍖�",
- fillTime: "2024-01-12 14:40:30",
- processStatus: 0,
- questionnaireId: 1004,
- },
- {
- id: 5,
- responsibilityDept: "濡囦骇绉�",
- unsatisfactoryDetail:
- "浜у墠妫�鏌ユ帓闃熸椂闂磋繃闀匡紝绛夊緟鏈熼棿娌℃湁浼戞伅搴т綅",
- patientName: "闄堝コ澹�",
- gender: 0,
- age: 28,
- phone: "135****7890",
- dischargeDept: "濡囦骇绉�",
- dischargeWard: "濡囦骇绉戠梾鍖�",
- fillTime: "2024-01-11 11:25:15",
- processStatus: 2,
- questionnaireId: 1005,
- },
- {
- id: 6,
- responsibilityDept: "鍎跨",
- unsatisfactoryDetail:
- "鍎跨鐢ㄨ嵂鍓傞噺浜や唬涓嶆竻鏅帮紝鐢ㄨ嵂娉ㄦ剰浜嬮」娌℃湁璇存槑",
- patientName: "璧靛疂瀹�",
- gender: 1,
- age: 5,
- phone: "134****1234",
- dischargeDept: "鍎跨",
- dischargeWard: "鍎跨鐥呭尯",
- fillTime: "2024-01-10 15:50:20",
- processStatus: 0,
- questionnaireId: 1006,
- },
- {
- id: 7,
- responsibilityDept: "鎬ヨ瘖绉�",
- unsatisfactoryDetail: "鎬ヨ瘖绛夊緟鏃堕棿杩囬暱锛岀梾鎯呮病鏈夊緱鍒板強鏃惰瘎浼�",
- patientName: "瀛欏厛鐢�",
- gender: 1,
- age: 40,
- phone: "133****5678",
- dischargeDept: "鎬ヨ瘖绉�",
- dischargeWard: "鎬ヨ瘖鐥呭尯",
- fillTime: "2024-01-09 10:15:40",
- processStatus: 0,
- questionnaireId: 1007,
- },
- {
- id: 8,
- responsibilityDept: "鍛煎惛鍐呯",
- unsatisfactoryDetail: "鍖荤敓寮�鑽緝澶氾紝璐圭敤杈冮珮锛屾病鏈夎鏄庡繀瑕佹��",
- patientName: "鍛ㄥコ澹�",
- gender: 0,
- age: 55,
- phone: "132****9012",
- dischargeDept: "鍛煎惛鍐呯",
- dischargeWard: "鍐呯涓�鐥呭尯",
- fillTime: "2024-01-08 13:30:55",
- processStatus: 1,
- questionnaireId: 1008,
- },
- ];
- this.total = this.exceptionList.length;
- resolve();
- }, 500);
+ const date = new Date(dateTime);
+ if (isNaN(date.getTime())) {
+ return dateTime;
+ }
+ return (
+ date.toLocaleDateString().replace(/\//g, "-") +
+ " " +
+ date.toTimeString().split(" ")[0]
+ );
+ } catch (error) {
+ console.error("鏃ユ湡鏍煎紡鍖栭敊璇�:", error);
+ return dateTime;
+ }
+ },
+ /** 鏌ヨ绉戝鍒楄〃 */
+ getDeptOptions() {
+ deptTreeSelect()
+ .then((res) => {
+ if (res.code == 200) {
+ this.deptList = this.flattenArray(res.data) || [];
+ }
+ })
+ .catch((error) => {
+ console.error("鑾峰彇绉戝鍒楄〃澶辫触:", error);
+ this.$message.error("鑾峰彇绉戝鍒楄〃澶辫触");
});
- } finally {
- this.loading = false;
+ },
+ 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;
+ },
+ // 瑙f瀽鎮h�呮弿杩颁俊鎭�
+ parsePatDesc(patdesc) {
+ if (!patdesc) return [];
+
+ try {
+ const parts = patdesc.split("|");
+ const items = [];
+
+ if (parts[0]) items.push({ label: "濮撳悕", value: parts[0] });
+ if (parts[1]) items.push({ label: "鐢佃瘽", value: parts[1] });
+ if (parts[2]) items.push({ label: "绉戝", value: parts[2] });
+
+ return items;
+ } catch (error) {
+ console.error("瑙f瀽鎮h�呬俊鎭け璐�:", error);
+ return [];
}
},
+ // 妫�鏌ヨ川绠℃潈闄�
+ checkQualityPermission() {
+ // 杩欓噷鍙互鏍规嵁瀹為檯鏉冮檺绯荤粺瀹炵幇
+ const userRoles = this.$store.getters.roles || [];
+ return (
+ userRoles.includes("quality_manager") || userRoles.includes("admin")
+ );
+ },
+
// 鑾峰彇鐘舵�佹爣绛剧被鍨�
- getStatusTagType(status) {
- switch (status) {
- case 0:
- return "warning"; // 寰呭鐞�
- case 1:
- return "primary"; // 澶勭悊涓�
- case 2:
+ getStatusTagType(handleFlag) {
+ switch (handleFlag) {
+ case "0":
+ return "warning"; // 鏈鐞�
+ case "1":
return "success"; // 宸插鐞�
default:
return "info";
@@ -611,16 +707,82 @@
},
// 鑾峰彇鐘舵�佹枃鏈�
- getStatusText(status) {
- switch (status) {
- case 0:
- return "寰呭鐞�";
- case 1:
- return "澶勭悊涓�";
- case 2:
+ getStatusText(handleFlag) {
+ switch (handleFlag) {
+ case "0":
+ return "鏈鐞�";
+ case "1":
return "宸插鐞�";
default:
return "鏈煡";
+ }
+ },
+
+ // 鎾斁褰曢煶
+ handlePlayAudio(url) {
+ this.audioUrl = url;
+ this.$nextTick(() => {
+ const audioPlayer = this.$refs.audioPlayer;
+ if (audioPlayer) {
+ audioPlayer.play().catch((error) => {
+ console.error("鎾斁澶辫触:", error);
+ this.$message.error("闊抽鎾斁澶辫触");
+ });
+ }
+ });
+ },
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ buildQueryParams() {
+ const params = {
+ pageNum: this.filterParams.pageNum,
+ pageSize: this.filterParams.pageSize,
+ };
+
+ if (this.filterParams.todeptcode) {
+ params.todeptcode = this.filterParams.todeptcode;
+ }
+
+ if (this.filterParams.handleFlag !== "") {
+ params.handleFlag = this.filterParams.handleFlag;
+ }
+
+ if (this.filterParams.templateType) {
+ params.templateType = this.filterParams.templateType;
+ }
+
+ // if (this.filterParams.scriptid) {
+ // params.scriptid = this.filterParams.scriptid;
+ // }
+ if (this.filterParams.scriptids) {
+ params.scriptids = this.filterParams.scriptids.split(",");
+ }
+
+ return params;
+ },
+
+ // 鍔犺浇寮傚父鍒楄〃
+ async loadExceptionList() {
+ this.loading = true;
+ try {
+ const params = this.buildQueryParams();
+ const response = await tracelist(params);
+
+ if (response && response.code === 200) {
+ this.exceptionList = response.rows || [];
+ this.total = response.total || 0;
+ } else {
+ this.exceptionList = [];
+ this.total = 0;
+ this.$message.error(response?.msg || "鍔犺浇寮傚父鍒楄〃澶辫触");
+ }
+ } catch (error) {
+ console.error("鍔犺浇寮傚父鍒楄〃澶辫触:", error);
+ this.$message.error("鍔犺浇寮傚父鍒楄〃澶辫触锛岃绋嶅悗閲嶈瘯");
+ this.exceptionList = [];
+ this.total = 0;
+ } finally {
+ this.loading = false;
}
},
@@ -633,11 +795,14 @@
// 閲嶇疆绛涢��
handleResetFilter() {
this.filterParams = {
- deptId: "",
- status: "",
+ todeptcode: "",
+ handleFlag: "",
+ templateType: "",
+ scriptids: null, // 淇濈暀闂ID
pageNum: 1,
pageSize: 10,
};
+ this.selectedExceptionIds = [];
this.loadExceptionList();
},
@@ -652,6 +817,15 @@
this.$message.warning("璇峰厛閫夋嫨瑕佸鐞嗙殑寮傚父鍙嶉");
return;
}
+
+ // 閲嶇疆鎵归噺澶勭悊琛ㄥ崟
+ this.batchProcessForm = {
+ handleFlag: "",
+ ccdepts: [],
+ handleresult: "",
+ handledesc: "",
+ };
+
this.batchDialogVisible = true;
},
@@ -663,44 +837,86 @@
// 鏌ョ湅璇︽儏
handleViewDetail(row) {
this.selectedRecordId = row.id;
- this.detailDialogTitle = `${row.patientName} - 寮傚父鍙嶉璇︽儏`;
+ this.selectedRecordData = row;
+
+ // 鐢熸垚寮规鏍囬
+ let title = "寮傚父鍙嶉璇︽儏";
+ if (row.patdesc) {
+ const patientName = row.patdescJson.sendname;
+ if (patientName) {
+ title = `${patientName} - ${title}`;
+ }
+ }
+ this.detailDialogTitle = title;
+
this.detailDialogVisible = true;
},
+
// 澶勭悊璇︽儏寮规鍏抽棴
handleDetailDialogClose() {
this.detailDialogVisible = false;
this.selectedRecordId = null;
- }, // 澶勭悊瀹屾垚鍚庣殑鍥炶皟
+ this.selectedRecordData = null;
+ },
+
+ // 澶勭悊瀹屾垚鍚庣殑鍥炶皟
handleProcessed() {
- // 閲嶆柊鍔犺浇鏁版嵁
this.loadExceptionList();
},
+
// 澶勭悊鍗曚釜寮傚父
handleProcess(row) {
this.currentExceptionId = row.id;
+
+ // 鍒濆鍖栬〃鍗曟暟鎹�
this.processForm = {
- status: row.processStatus === 0 ? 1 : row.processStatus,
- reportDepts: [],
- remark: "",
+ handleFlag: row.handleFlag === "0" ? "1" : "0",
+ ccdepts: row.ccdepts ? row.ccdepts.split(",") : [],
+ handleresult: row.handleresult || "",
+ handledesc: row.handledesc || "",
+ finaloption: row.finaloption || "",
};
+
this.processDialogVisible = true;
},
// 鎻愪氦澶勭悊
async submitProcess() {
this.$refs.processForm.validate(async (valid) => {
- if (valid) {
- this.processing = true;
- try {
- // Mock API璋冪敤
- await new Promise((resolve) => setTimeout(resolve, 1000));
+ if (!valid) {
+ return;
+ }
- this.$message.success("澶勭悊鎻愪氦鎴愬姛");
- this.processDialogVisible = false;
- this.loadExceptionList();
- } finally {
- this.processing = false;
- }
+ this.processing = true;
+
+ try {
+ // 鍑嗗鎻愪氦鏁版嵁
+ const submitData = {
+ id: this.currentExceptionId,
+ handleFlag: this.processForm.handleFlag,
+ handleresult: this.processForm.handleresult,
+ handledesc: this.processForm.handledesc,
+ finaloption: this.processForm.finaloption,
+ handleBy: this.$store.state.user.nickName,
+ handleTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ // 灏嗘暟缁勮浆鎹负閫楀彿鍒嗛殧鐨勫瓧绗︿覆
+ ccdepts: Array.isArray(this.processForm.ccdepts)
+ ? this.processForm.ccdepts.join(",")
+ : this.processForm.ccdepts,
+ };
+ // TODO: 杩欓噷闇�瑕佽皟鐢ㄥ疄闄呯殑澶勭悊鎺ュ彛
+ await traceedit(submitData);
+
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ this.$message.success("澶勭悊鎻愪氦鎴愬姛");
+ this.processDialogVisible = false;
+ this.loadExceptionList();
+ } catch (error) {
+ console.error("澶勭悊鎻愪氦澶辫触:", error);
+ this.$message.error("澶勭悊鎻愪氦澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ this.processing = false;
}
});
},
@@ -708,21 +924,111 @@
// 鎻愪氦鎵归噺澶勭悊
async submitBatchProcess() {
this.$refs.batchProcessForm.validate(async (valid) => {
- if (valid) {
- this.batchProcessing = true;
- try {
- // Mock API璋冪敤
- await new Promise((resolve) => setTimeout(resolve, 1500));
+ if (!valid) {
+ return;
+ }
- this.$message.success(
- `宸叉壒閲忓鐞� ${this.selectedExceptionIds.length} 鏉″紓甯稿弽棣坄
+ this.batchProcessing = true;
+ // 鏄剧ず杩涘害鏉�
+ this.batchProgress = {
+ visible: true,
+ percentage: 0,
+ processed: 0,
+ total: this.selectedExceptionIds.length,
+ };
+ try {
+ // 鍑嗗鎵归噺鎻愪氦鏁版嵁
+ const processData = {
+ handleFlag: this.batchProcessForm.handleFlag,
+ handleresult: this.batchProcessForm.handleresult,
+ handledesc: this.batchProcessForm.handledesc,
+ ccdepts: Array.isArray(this.batchProcessForm.ccdepts)
+ ? this.batchProcessForm.ccdepts.join(",")
+ : this.batchProcessForm.ccdepts,
+ };
+
+ // 鎺у埗骞跺彂鏁�
+ const CONCURRENT_LIMIT = 10; // 鍚屾椂鏈�澶�3涓姹�
+ const totalCount = this.selectedExceptionIds.length;
+ const results = [];
+ let successCount = 0;
+ let failCount = 0;
+
+ this.$message.info(`寮�濮嬫壒閲忓鐞� ${totalCount} 鏉¤褰�...`);
+
+ // 鍒嗙粍澶勭悊
+ for (
+ let i = 0;
+ i < this.selectedExceptionIds.length;
+ i += CONCURRENT_LIMIT
+ ) {
+ const batchIds = this.selectedExceptionIds.slice(
+ i,
+ i + CONCURRENT_LIMIT
);
- this.batchDialogVisible = false;
- this.selectedExceptionIds = [];
- this.loadExceptionList();
- } finally {
- this.batchProcessing = false;
+
+ // 骞跺彂澶勭悊褰撳墠鎵规
+ const batchPromises = batchIds.map((id) =>
+ traceedit({
+ id: id,
+ ...processData,
+ })
+ .then((result) => ({
+ id,
+ success: result && result.code === 200,
+ error: result?.msg,
+ }))
+ .catch((error) => ({
+ id,
+ success: false,
+ error: error.message,
+ }))
+ );
+
+ const batchResults = await Promise.all(batchPromises);
+ results.push(...batchResults);
+
+ // 鏇存柊缁熻
+ batchResults.forEach((result) => {
+ if (result.success) {
+ successCount++;
+ } else {
+ failCount++;
+ console.error(`澶勭悊璁板綍 ${result.id} 澶辫触:`, result.error);
+ }
+ });
+ // 鏇存柊杩涘害
+ this.batchProgress.processed = i + 1;
+ this.batchProgress.percentage = Math.round(
+ ((i + 1) / totalCount) * 100
+ );
+ // 鏄剧ず杩涘害
+ console.log(
+ `杩涘害: ${Math.min(
+ i + CONCURRENT_LIMIT,
+ totalCount
+ )}/${totalCount}`
+ );
}
+
+ // 澶勭悊缁撴灉鎻愮ず
+ if (successCount === totalCount) {
+ this.$message.success(`宸叉垚鍔熷鐞嗗叏閮� ${totalCount} 鏉″紓甯稿弽棣坄);
+ } else {
+ this.$message.warning(
+ `宸插鐞� ${successCount} 鏉★紝澶辫触 ${failCount} 鏉″紓甯稿弽棣坄
+ );
+ }
+
+ this.batchDialogVisible = false;
+ this.selectedExceptionIds = [];
+ this.loadExceptionList();
+ } catch (error) {
+ console.error("鎵归噺澶勭悊澶辫触:", error);
+ this.$message.error("鎵归噺澶勭悊澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ this.batchProcessing = false;
+ this.batchProgress.visible = false;
}
});
},
@@ -738,27 +1044,6 @@
handlePageChange(page) {
this.filterParams.pageNum = page;
this.loadExceptionList();
- },
-
- // 鏂囦欢涓婁紶鐩稿叧鏂规硶
- handlePreview(file) {
- console.log("棰勮鏂囦欢:", file);
- },
-
- handleRemove(file, fileList) {
- console.log("绉婚櫎鏂囦欢:", file, fileList);
- },
-
- beforeRemove(file) {
- return this.$confirm(`纭畾绉婚櫎 ${file.name}锛焋);
- },
-
- handleExceed(files, fileList) {
- this.$message.warning(
- `褰撳墠闄愬埗閫夋嫨 3 涓枃浠讹紝鏈閫夋嫨浜� ${files.length} 涓枃浠讹紝鍏遍�夋嫨浜� ${
- files.length + fileList.length
- } 涓枃浠禶
- );
},
},
};
@@ -827,64 +1112,109 @@
}
.detail-content {
- font-size: 13px;
- color: #606266;
- line-height: 1.5;
text-align: left;
+ font-size: 12px;
+ line-height: 1.5;
+
+ .question-text {
+ color: #303133;
+ margin-bottom: 5px;
+ font-weight: 500;
+ }
+
+ .answer-text {
+ color: #f56c6c;
+ margin-bottom: 5px;
+ }
+
+ .matched-text {
+ color: #e6a23c;
+ font-style: italic;
+ }
+
+ strong {
+ color: #606266;
+ font-weight: 600;
+ }
}
.patient-info {
- .patient-item {
+ .patient-row {
display: flex;
justify-content: space-between;
align-items: center;
- margin-bottom: 5px;
- padding: 2px 0;
+ margin-bottom: 8px;
- .label {
- font-size: 12px;
- color: #606266;
- min-width: 40px;
+ &:last-child {
+ margin-bottom: 0;
}
- .value {
- font-size: 13px;
- color: #333;
- font-weight: 500;
- text-align: right;
+ .patient-item {
flex: 1;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ padding: 0 5px;
+
+ &.full-width {
+ flex: 1 0 100%;
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .label {
+ font-size: 12px;
+ color: #606266;
+ margin-right: 5px;
+ white-space: nowrap;
+ }
+
+ .value {
+ font-size: 12px;
+ color: #333;
+ font-weight: 500;
+ text-align: right;
+ word-break: break-all;
+ }
}
}
}
- .discharge-info {
+ .fill-info,
+ .handle-info {
+ font-size: 12px;
+
.info-item {
display: flex;
- justify-content: space-between;
+ justify-content: flex-start;
align-items: center;
margin-bottom: 5px;
padding: 2px 0;
.label {
- font-size: 12px;
color: #606266;
min-width: 50px;
}
.value {
- font-size: 13px;
color: #333;
font-weight: 500;
- text-align: right;
+ // text-align: right;
flex: 1;
&.time {
- font-size: 12px;
color: #909399;
+ font-size: 11px;
}
}
}
}
+
+ .no-data {
+ color: #909399;
+ font-style: italic;
+ font-size: 12px;
+ }
}
.pagination-section {
diff --git a/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue b/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
index 57b4dff..1219d47 100644
--- a/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
+++ b/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
@@ -13,147 +13,280 @@
<el-row :gutter="20">
<el-col :span="8">
<div class="info-item">
- <span class="label">鎮h�呭鍚嶏細</span>
- <span class="value">{{ currentRecord.patientName }}</span>
+ <span class="label">闂鍐呭锛�</span>
+ <span class="value">{{ currentRecord.questiontext || '鏃�' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
- <span class="label">鎬у埆锛�</span>
- <span class="value">{{ currentRecord.gender === 1 ? '鐢�' : '濂�' }}</span>
+ <span class="label">鍥炵瓟鍐呭锛�</span>
+ <span class="value">{{ currentRecord.asrtext || '鏃犲洖绛�' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
- <span class="label">骞撮緞锛�</span>
- <span class="value">{{ currentRecord.age }}宀�</span>
- </div>
- </el-col>
- <el-col :span="8">
- <div class="info-item">
- <span class="label">鑱旂郴鏂瑰紡锛�</span>
- <span class="value">{{ currentRecord.phone }}</span>
- </div>
- </el-col>
- <el-col :span="8">
- <div class="info-item">
- <span class="label">鍑洪櫌绉戝锛�</span>
- <span class="value">{{ currentRecord.dischargeDept }}</span>
- </div>
- </el-col>
- <el-col :span="8">
- <div class="info-item">
- <span class="label">鍑洪櫌鐥呭尯锛�</span>
- <span class="value">{{ currentRecord.dischargeWard }}</span>
- </div>
- </el-col>
- <el-col :span="8">
- <div class="info-item">
- <span class="label">濉啓鏃堕棿锛�</span>
- <span class="value">{{ currentRecord.fillTime }}</span>
+ <span class="label">瑙f瀽鍊硷細</span>
+ <span class="value">{{ currentRecord.matchedtext || '鏃�' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="label">璐熻矗绉戝锛�</span>
- <el-tag type="primary">{{ currentRecord.responsibilityDept }}</el-tag>
+ <el-tag v-if="currentRecord.todeptname" type="primary">{{ currentRecord.todeptname }}</el-tag>
+ <span v-else class="value">鏈垎閰�</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="label">澶勭悊鐘舵�侊細</span>
<el-tag
- :type="getStatusTagType(currentRecord.processStatus)"
+ :type="getStatusTagType(currentRecord.handleFlag)"
effect="dark"
>
- {{ getStatusText(currentRecord.processStatus) }}
+ {{ getStatusText(currentRecord.handleFlag) }}
</el-tag>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="info-item">
+ <span class="label">妯℃澘绫诲瀷锛�</span>
+ <el-tag :type="currentRecord.templateType === 1 ? 'primary' : 'success'">
+ {{ currentRecord.templateType === 1 ? '璇煶妯℃澘' : '闂嵎妯℃澘' }}
+ </el-tag>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="info-item">
+ <span class="label">鍒涘缓鏃堕棿锛�</span>
+ <span class="value">{{ formatDateTime(currentRecord.createTime) }}</span>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="info-item">
+ <span class="label">澶勭悊鏃堕棿锛�</span>
+ <span class="value">{{ currentRecord.handleTime ? formatDateTime(currentRecord.handleTime) : '鏈鐞�' }}</span>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="info-item">
+ <span class="label">澶勭悊浜猴細</span>
+ <span class="value">{{ currentRecord.handleBy || '鏈鐞�' }}</span>
+ </div>
+ </el-col>
+ <el-col :span="8" v-if="currentRecord.handleresult">
+ <div class="info-item">
+ <span class="label">澶勭悊缁撴灉锛�</span>
+ <span class="value">{{ getHandleresultText(currentRecord.handleresult) }}</span>
+ </div>
+ </el-col>
+ <el-col :span="16" v-if="currentRecord.handledesc">
+ <div class="info-item">
+ <span class="label">澶勭悊璇存槑锛�</span>
+ <span class="value">{{ currentRecord.handledesc }}</span>
+ </div>
+ </el-col>
+ <el-col :span="24" v-if="currentRecord.finaloption">
+ <div class="info-item">
+ <span class="label">鏈�缁堟剰瑙侊細</span>
+ <span class="value">{{ currentRecord.finaloption }}</span>
+ </div>
+ </el-col>
+ <el-col :span="8" v-if="currentRecord.recordurl">
+ <div class="info-item">
+ <span class="label">褰曢煶鍦板潃锛�</span>
+ <el-button
+ type="text"
+ size="small"
+ icon="el-icon-headset"
+ @click="handlePlayAudio(currentRecord.recordurl)"
+ >
+ 鎾斁褰曢煶
+ </el-button>
+ </div>
+ </el-col>
+ <el-col :span="8" v-if="currentRecord.ccdepts">
+ <div class="info-item">
+ <span class="label">鎶勯�佺瀹わ細</span>
+ <span class="value">{{ currentRecord.ccdepts }}</span>
</div>
</el-col>
</el-row>
</div>
- <!-- 闂嵎璇︽儏 -->
- <div class="questionnaire-section">
- <div class="section-title">闂嵎濉啓璇︽儏</div>
- <div class="questionnaire-content">
- <div class="question-item" v-for="(question, index) in questionnaireData" :key="index">
- <div class="question-header">
- <span class="question-index">{{ index + 1 }}.</span>
- <span class="question-text">{{ question.question }}</span>
- <el-tag
- size="mini"
- :type="question.type === 1 ? 'primary' : 'success'"
- class="question-type"
- >
- {{ question.type === 1 ? '鍗曢�夐' : '澶氶�夐' }}
- </el-tag>
- </div>
- <div class="question-options">
- <el-radio-group
- v-model="question.answer"
- v-if="question.type === 1"
- disabled
- >
- <el-radio
- v-for="option in question.options"
- :key="option.value"
- :label="option.value"
- :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
+ <!-- 闂嵎/璇煶璇︽儏 -->
+ <div class="content-container" v-if="templateData.length > 0">
+ <el-tabs v-model="activeName" type="border-card">
+ <!-- 闂嵎闅忚璇︽儏 -->
+ <el-tab-pane name="wj" v-if="currentRecord.templateType === 2">
+ <span slot="label"><i class="el-icon-notebook-1"></i> 闂嵎闅忚璇︽儏</span>
+ <div class="CONTENT">
+ <div class="title">{{ currentRecord.questiontext || '闂嵎璇︽儏' }}</div>
+ <div class="preview-left" v-if="!isVoiceTemplate">
+ <div
+ class="topic-dev"
+ v-for="(item, index) in templateData"
+ :key="item.id"
>
- {{ option.text }}
- </el-radio>
- </el-radio-group>
- <el-checkbox-group
- v-model="question.answer"
- v-else
- disabled
- >
- <el-checkbox
- v-for="option in question.options"
- :key="option.value"
- :label="option.value"
- :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
- >
- {{ option.text }}
- </el-checkbox>
- </el-checkbox-group>
+ <!-- 鍗曢�� -->
+ <div
+ :class="getTopicClass(item)"
+ :key="index"
+ v-if="item.scriptType == 1 && !item.astrict"
+ >
+ <div class="dev-text">
+ {{ index + 1 }}銆乕鍗曢�塢<span>{{ item.scriptContent }}</span>
+ </div>
+ <div class="dev-xx">
+ <el-radio-group v-model="item.scriptResult" disabled>
+ <el-radio
+ v-for="(option, optionIndex) in item.svyTaskTemplateTargetoptions"
+ :class="getOptionClass(option)"
+ :key="optionIndex"
+ :label="option.optioncontent"
+ >{{ option.optioncontent }}</el-radio>
+ </el-radio-group>
+ </div>
+ <div
+ v-if="item.showAppendInput || item.answerps"
+ class="append-input-container"
+ >
+ <el-input
+ type="textarea"
+ :rows="2"
+ placeholder="璇疯緭鍏ュ叿浣撲俊鎭�"
+ v-model="item.answerps"
+ readonly
+ ></el-input>
+ </div>
+ <div v-show="item.prompt">
+ <el-alert :title="item.prompt" type="warning"></el-alert>
+ </div>
+ </div>
+ <!-- 澶氶�� -->
+ <div
+ :class="item.isabnormal ? 'scriptTopic-isabnormal' : 'scriptTopic-dev'"
+ :key="index"
+ v-if="item.scriptType == 2 && !item.astrict"
+ >
+ <div class="dev-text">
+ {{ index + 1 }}銆乕澶氶�塢<span>{{ item.scriptContent }}</span>
+ </div>
+ <div class="dev-xx">
+ <el-checkbox-group v-model="item.scriptResult" disabled>
+ <el-checkbox
+ :class="option.isabnormal ? 'red-star' : ''"
+ v-for="(option, optionIndex) in item.svyTaskTemplateTargetoptions"
+ :key="optionIndex"
+ :label="option.optioncontent"
+ >
+ {{ option.optioncontent }}
+ </el-checkbox>
+ </el-checkbox-group>
+ </div>
+ <div v-show="item.prompt && item.scriptResult[0]">
+ <el-alert :title="item.prompt" type="warning"></el-alert>
+ </div>
+ </div>
+ <!-- 濉┖ -->
+ <div
+ class="scriptTopic-dev"
+ :key="index"
+ v-if="item.scriptType == 4 && !item.astrict"
+ >
+ <div class="dev-text">
+ {{ index + 1 }}銆乕闂瓟]<span>{{ item.scriptContent }}</span>
+ <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+ </div>
+ <div class="dev-xx" v-if="item.valueType == 3">
+ <el-input
+ type="text"
+ placeholder="璇疯緭鍏ョ瓟妗�"
+ v-model="item.scriptResult"
+ readonly
+ ></el-input>
+ </div>
+ <div class="dev-xx" v-else>
+ <el-input
+ type="textarea"
+ :rows="2"
+ placeholder="璇疯緭鍏ョ瓟妗�"
+ v-model="item.scriptResult"
+ readonly
+ ></el-input>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
- <div v-if="question.additional" class="additional-remark">
- <div class="remark-label">琛ュ厖璇存槑锛�</div>
- <div class="remark-content">{{ question.additional }}</div>
+ </el-tab-pane>
+
+ <!-- 璇煶闅忚璇︽儏 -->
+ <el-tab-pane name="yy" v-if="currentRecord.templateType === 1">
+ <span slot="label"><i class="el-icon-headset"></i> 璇煶闅忚璇︽儏</span>
+ <div class="borderdiv">
+ <div class="title">{{ taskName }}</div>
+ <div class="voice-audio" v-if="voiceAudioUrl">
+ 瀹屾暣璇煶锛�
+ <audio-player
+ :audio-source="voiceAudioUrl"
+ ></audio-player>
+ </div>
+ <div class="preview-left" v-if="voiceData.length > 0">
+ <div v-for="(item, index) in voiceData" :key="index">
+ <div class="leftside">
+ <i class="el-icon-phone-outline"></i>
+ <span>{{ item.questiontext || '闂鍐呭' }}</span>
+ </div>
+ <div class="offside">
+ <i class="el-icon-user"></i>
+ <div class="offside-value">
+ <el-input
+ type="textarea"
+ :autosize="{ minRows: 1 }"
+ v-model="item.asrtext"
+ readonly
+ ></el-input>
+ <div v-if="item.questionvoice">
+ <audio-player
+ :audio-source="item.questionvoice"
+ ></audio-player>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
- </div>
- </div>
+ </el-tab-pane>
+ </el-tabs>
</div>
<!-- 澶勭悊璁板綍 -->
- <div class="process-section">
+ <div class="process-section" v-if="processRecords.length > 0">
<div class="section-title">澶勭悊璁板綍</div>
- <div class="process-timeline" v-if="processRecords.length > 0">
+ <div class="process-timeline">
<el-timeline>
<el-timeline-item
v-for="(record, index) in processRecords"
:key="index"
- :timestamp="record.time"
+ :timestamp="formatDateTime(record.handleTime || record.createTime)"
placement="top"
>
<el-card>
<div class="process-item">
<div class="process-header">
- <span class="process-user">{{ record.user }}</span>
+ <span class="process-user">{{ record.handleBy || '绯荤粺' }}</span>
<el-tag
size="small"
- :type="getStatusTagType(record.status)"
+ :type="getStatusTagType(record.handleFlag)"
>
- {{ getStatusText(record.status) }}
+ {{ getStatusText(record.handleFlag) }}
</el-tag>
</div>
<div class="process-content">
- <div v-if="record.reportDepts && record.reportDepts.length > 0" class="process-depts">
- <span class="label">鎶ュ绉戝锛�</span>
+ <div v-if="record.ccdepts" class="process-depts">
+ <span class="label">鎶勯�佺瀹わ細</span>
<el-tag
- v-for="dept in record.reportDepts"
+ v-for="dept in getDeptArray(record.ccdepts)"
:key="dept"
size="small"
type="info"
@@ -162,31 +295,23 @@
{{ dept }}
</el-tag>
</div>
- <div v-if="record.remark" class="process-remark">
- <span class="label">澶勭悊澶囨敞锛�</span>
- <span class="content">{{ record.remark }}</span>
+ <div v-if="record.handleresult" class="process-remark">
+ <span class="label">澶勭悊缁撴灉锛�</span>
+ <span class="content">{{ getHandleresultText(record.handleresult) }}</span>
</div>
- <div v-if="record.attachments && record.attachments.length > 0" class="process-attachments">
- <span class="label">闄勪欢锛�</span>
- <el-button
- v-for="file in record.attachments"
- :key="file.id"
- type="text"
- size="small"
- icon="el-icon-document"
- @click="handlePreviewFile(file)"
- >
- {{ file.name }}
- </el-button>
+ <div v-if="record.handledesc" class="process-remark">
+ <span class="label">澶勭悊璇存槑锛�</span>
+ <span class="content">{{ record.handledesc }}</span>
+ </div>
+ <div v-if="record.finaloption" class="process-remark">
+ <span class="label">鏈�缁堟剰瑙侊細</span>
+ <span class="content">{{ record.finaloption }}</span>
</div>
</div>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
- </div>
- <div v-else class="no-record">
- 鏆傛棤澶勭悊璁板綍
</div>
</div>
@@ -195,7 +320,7 @@
type="primary"
icon="el-icon-edit"
@click="handleProcess"
- v-if="currentRecord.processStatus !== 2"
+ v-if="currentRecord.handleFlag !== '1'"
>
澶勭悊寮傚父
</el-button>
@@ -217,61 +342,72 @@
label-width="100px"
size="medium"
>
- <el-form-item label="澶勭悊鐘舵��" prop="status">
+ <el-form-item label="澶勭悊鐘舵��" prop="handleFlag">
<el-select
- v-model="processForm.status"
+ v-model="processForm.handleFlag"
placeholder="璇烽�夋嫨澶勭悊鐘舵��"
style="width: 100%"
>
- <el-option label="澶勭悊涓�" :value="1" />
- <el-option label="宸插鐞�" :value="2" />
- <el-option label="宸查┏鍥�" :value="3" />
+ <el-option label="宸插鐞�" :value="'1'" />
+ <el-option label="鍙栨秷澶勭悊" :value="'0'" />
</el-select>
</el-form-item>
- <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+ <el-form-item label="鎶勯�佺瀹�" prop="ccdepts">
<el-select
- v-model="processForm.reportDepts"
- placeholder="璇烽�夋嫨鎶ュ绉戝"
+ v-model="processForm.ccdepts"
+ placeholder="璇烽�夋嫨鎶勯�佺瀹�"
multiple
filterable
collapse-tags
style="width: 100%"
+ :disabled="processForm.handleFlag !== '1'"
>
<el-option
v-for="dept in deptList"
- :key="dept.id"
- :label="dept.name"
- :value="dept.id"
+ :key="dept.deptCode"
+ :label="dept.label"
+ :value="dept.deptCode"
/>
</el-select>
</el-form-item>
- <el-form-item label="澶勭悊澶囨敞" prop="remark">
+ <el-form-item label="澶勭悊缁撴灉" prop="handleresult">
+ <el-select
+ v-model="processForm.handleresult"
+ placeholder="璇烽�夋嫨澶勭悊缁撴灉"
+ style="width: 100%"
+ :disabled="processForm.handleFlag !== '1'"
+ >
+ <el-option label="宸茶В鍐�" value="resolved" />
+ <el-option label="宸茶В閲�" value="explained" />
+ <el-option label="宸茶浆浜�" value="transferred" />
+ <el-option label="闇�鏀硅繘" value="improvement" />
+ <el-option label="宸查┏鍥�" value="rejected" />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="澶勭悊璇存槑" prop="handledesc">
<el-input
- v-model="processForm.remark"
+ v-model="processForm.handledesc"
type="textarea"
:rows="4"
- placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+ placeholder="璇疯緭鍏ュ鐞嗚鏄庯紙鏈�澶�500瀛楋級"
maxlength="500"
show-word-limit
+ :disabled="processForm.handleFlag !== '1'"
/>
</el-form-item>
- <el-form-item label="闄勪欢涓婁紶">
- <el-upload
- class="upload-demo"
- action="#"
- :on-preview="handleFilePreview"
- :on-remove="handleFileRemove"
- :before-remove="beforeFileRemove"
- :limit="3"
- :on-exceed="handleFileExceed"
- :file-list="fileList"
- >
- <el-button size="small" type="primary">鐐瑰嚮涓婁紶</el-button>
- <div slot="tip" class="el-upload__tip">鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑闄勪欢锛屽崟涓枃浠朵笉瓒呰繃10MB</div>
- </el-upload>
+ <el-form-item label="鏈�缁堟剰瑙�" prop="finaloption" v-if="hasQualityPermission">
+ <el-input
+ v-model="processForm.finaloption"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ユ渶缁堝鐞嗘剰瑙侊紙鏈�澶�300瀛楋級"
+ maxlength="300"
+ show-word-limit
+ />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
@@ -285,24 +421,42 @@
</el-button>
</span>
</el-dialog>
+
+ <!-- 褰曢煶鎾斁鍣� -->
+ <audio
+ v-if="audioUrl"
+ :src="audioUrl"
+ ref="audioPlayer"
+ controls
+ style="display: none"
+ />
</el-dialog>
</template>
<script>
+import { traceedit } from "@/api/AiCentre/index";
+import { getsearchrResults, getPersonVoices, getTaskservelist } from "@/api/AiCentre/index";
+import { deptTreeSelect } from "@/api/system/user";
+import AudioPlayer from "@/components/AudioPlayer"; // 闇�瑕佸垱寤鸿繖涓煶棰戞挱鏀剧粍浠�
+
export default {
name: 'ExceptionDetailDialog',
+ components: {
+ AudioPlayer
+ },
props: {
- // 鏄惁鏄剧ず瀵硅瘽妗�
visible: {
type: Boolean,
default: false
},
- // 璁板綍ID
recordId: {
type: [Number, String],
default: null
},
- // 瀵硅瘽妗嗘爣棰�
+ recordData: {
+ type: Object,
+ default: () => ({})
+ },
title: {
type: String,
default: '寮傚父鍙嶉璇︽儏'
@@ -313,45 +467,71 @@
// 褰撳墠璁板綍
currentRecord: {},
- // 闂嵎鏁版嵁
- questionnaireData: [],
+ // 闂嵎/璇煶鏁版嵁
+ activeName: 'wj',
+ taskName: '',
+ templateData: [],
+ voiceData: [],
+ voiceAudioUrl: '',
// 澶勭悊璁板綍
processRecords: [],
// 绉戝鍒楄〃
- deptList: [
- { id: 1, name: '蹇冭绠″唴绉�' },
- { id: 2, name: '绁炵粡鍐呯' },
- { id: 3, name: '鏅绉�' },
- { id: 4, name: '楠ㄧ' },
- { id: 5, name: '濡囦骇绉�' },
- { id: 6, name: '鍎跨' },
- { id: 7, name: '鎬ヨ瘖绉�' },
- { id: 8, name: '鍛煎惛鍐呯' }
- ],
+ deptList: [],
// 澶勭悊瀵硅瘽妗�
processDialogVisible: false,
processing: false,
processForm: {
- status: '',
- reportDepts: [],
- remark: ''
+ handleFlag: '',
+ ccdepts: [],
+ handleresult: '',
+ handledesc: '',
+ finaloption: ''
},
processRules: {
- status: [
+ handleFlag: [
{ required: true, message: '璇烽�夋嫨澶勭悊鐘舵��', trigger: 'change' }
],
- remark: [
- { required: true, message: '璇疯緭鍏ュ鐞嗗娉�', trigger: 'blur' },
- { min: 5, max: 500, message: '澶囨敞闀垮害鍦� 5 鍒� 500 涓瓧绗�', trigger: 'blur' }
+ handleresult: [
+ {
+ required: true,
+ message: '璇烽�夋嫨澶勭悊缁撴灉',
+ trigger: 'change',
+ validator: (rule, value, callback) => {
+ if (this.processForm.handleFlag === '1' && !value) {
+ callback(new Error('璇烽�夋嫨澶勭悊缁撴灉'));
+ } else {
+ callback();
+ }
+ }
+ }
+ ],
+ handledesc: [
+ {
+ required: true,
+ message: '璇疯緭鍏ュ鐞嗚鏄�',
+ trigger: 'blur',
+ validator: (rule, value, callback) => {
+ if (this.processForm.handleFlag === '1' && (!value || value.trim().length < 3)) {
+ callback(new Error('澶勭悊璇存槑鑷冲皯3涓瓧绗�'));
+ } else {
+ callback();
+ }
+ }
+ }
]
},
- fileList: [],
+
+ // 闊抽鎾斁
+ audioUrl: '',
// 鍔犺浇鐘舵��
- loading: false
+ loading: false,
+
+ // 鏉冮檺鎺у埗
+ hasQualityPermission: false
};
},
@@ -363,6 +543,10 @@
set(val) {
this.$emit('update:visible', val);
}
+ },
+
+ isVoiceTemplate() {
+ return this.currentRecord.templateType === 1;
}
},
@@ -370,237 +554,293 @@
visible: {
immediate: true,
handler(val) {
- if (val && this.recordId) {
+ if (val) {
this.loadData();
+ } else {
+ this.resetData();
+ }
+ }
+ },
+
+ recordData: {
+ immediate: true,
+ handler(val) {
+ if (val && Object.keys(val).length > 0) {
+ this.currentRecord = { ...val };
}
}
}
},
methods: {
- // 鍔犺浇鏁版嵁
- async loadData() {
- this.loading = true;
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return '';
try {
- await Promise.all([
- this.loadRecordDetail(),
- this.loadQuestionnaireData(),
- this.loadProcessRecords()
- ]);
- } finally {
- this.loading = false;
+ const date = new Date(dateTime);
+ if (isNaN(date.getTime())) {
+ return dateTime;
+ }
+ return date.toLocaleDateString().replace(/\//g, '-') + ' ' +
+ date.toTimeString().split(' ')[0];
+ } catch (error) {
+ console.error('鏃ユ湡鏍煎紡鍖栭敊璇�:', error);
+ return dateTime;
}
},
- // 鍔犺浇璁板綍璇︽儏
- async loadRecordDetail() {
- return new Promise(resolve => {
- setTimeout(() => {
- // 鏍规嵁涓嶅悓鐨剅ecordId杩斿洖涓嶅悓鐨刴ock鏁版嵁
- const mockRecords = {
- 1: {
- id: 1,
- patientName: '寮犲厛鐢�',
- gender: 1,
- age: 45,
- phone: '13800138000',
- dischargeDept: '蹇冭绠″唴绉�',
- dischargeWard: '鍐呯涓�鐥呭尯',
- fillTime: '2024-01-15 10:30:25',
- responsibilityDept: '蹇冭绠″唴绉�',
- processStatus: 0
- },
- 2: {
- id: 2,
- patientName: '鏉庡コ澹�',
- gender: 0,
- age: 38,
- phone: '13900139000',
- dischargeDept: '绁炵粡鍐呯',
- dischargeWard: '鍐呯浜岀梾鍖�',
- fillTime: '2024-01-14 16:20:10',
- responsibilityDept: '绁炵粡鍐呯',
- processStatus: 0
- },
- 3: {
- id: 3,
- patientName: '鐜嬪厛鐢�',
- gender: 1,
- age: 52,
- phone: '13700137000',
- dischargeDept: '鏅绉�',
- dischargeWard: '澶栫涓�鐥呭尯',
- fillTime: '2024-01-13 09:15:45',
- responsibilityDept: '鏅绉�',
- processStatus: 1
- }
- };
-
- this.currentRecord = mockRecords[this.recordId] || {
- id: 1,
- patientName: '寮犲厛鐢�',
- gender: 1,
- age: 45,
- phone: '13800138000',
- dischargeDept: '蹇冭绠″唴绉�',
- dischargeWard: '鍐呯涓�鐥呭尯',
- fillTime: '2024-01-15 10:30:25',
- responsibilityDept: '蹇冭绠″唴绉�',
- processStatus: 0
- };
- resolve();
- }, 300);
- });
+ // 妫�鏌ヨ川绠℃潈闄�
+ checkQualityPermission() {
+ const userRoles = this.$store.getters.roles || [];
+ return userRoles.includes('quality_manager') || userRoles.includes('admin');
},
- // 鍔犺浇闂嵎鏁版嵁
- async loadQuestionnaireData() {
- return new Promise(resolve => {
- setTimeout(() => {
- this.questionnaireData = [
- {
- question: '鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�',
- type: 1,
- options: [
- { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
- { value: '婊℃剰', text: '婊℃剰' },
- { value: '涓�鑸�', text: '涓�鑸�' },
- { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
- { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
- ],
- answer: '涓嶆弧鎰�',
- additional: '鍖荤敓鏌ユ埧鏃堕棿澶煭锛屾矡閫氫笉澶熷厖鍒嗭紝瀵圭梾鎯呰В閲婁笉澶熻缁�'
- },
- {
- question: '鎮ㄥ鍖荤敓鐨勮瘖鐤楁按骞冲拰鎶�鏈兘鍔涜瘎浠峰浣曪紵',
- type: 1,
- options: [
- { value: '闈炲父涓撲笟', text: '闈炲父涓撲笟' },
- { value: '姣旇緝涓撲笟', text: '姣旇緝涓撲笟' },
- { value: '涓�鑸�', text: '涓�鑸�' },
- { value: '涓嶅涓撲笟', text: '涓嶅涓撲笟' },
- { value: '闈炲父涓嶄笓涓�', text: '闈炲父涓嶄笓涓�' }
- ],
- answer: '姣旇緝涓撲笟',
- additional: ''
- },
- {
- question: '鎮ㄥ鍖婚櫌鐨勭幆澧冨拰鍗敓鐘跺喌鏄惁婊℃剰锛�',
- type: 1,
- options: [
- { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
- { value: '婊℃剰', text: '婊℃剰' },
- { value: '涓�鑸�', text: '涓�鑸�' },
- { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
- { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
- ],
- answer: '涓�鑸�',
- additional: ''
- },
- {
- question: '鎮ㄨ涓哄尰鎶や汉鍛樹笌鎮ㄧ殑娌熼�氭槸鍚﹀厖鍒嗭紵',
- type: 1,
- options: [
- { value: '闈炲父鍏呭垎', text: '闈炲父鍏呭垎' },
- { value: '姣旇緝鍏呭垎', text: '姣旇緝鍏呭垎' },
- { value: '涓�鑸�', text: '涓�鑸�' },
- { value: '涓嶅鍏呭垎', text: '涓嶅鍏呭垎' },
- { value: '闈炲父涓嶅厖鍒�', text: '闈炲父涓嶅厖鍒�' }
- ],
- answer: '涓嶅鍏呭垎',
- additional: '鍖荤敓璁茶В鐥呮儏鏃惰閫熷お蹇紝娌℃湁缁欒冻澶熺殑鏃堕棿鎻愰棶'
- },
- {
- question: '鎮ㄥ绛夊緟灏辫瘖鍜屾不鐤楃殑鏃堕棿鏄惁婊℃剰锛�',
- type: 1,
- options: [
- { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
- { value: '婊℃剰', text: '婊℃剰' },
- { value: '涓�鑸�', text: '涓�鑸�' },
- { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
- { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
- ],
- answer: '涓嶆弧鎰�',
- additional: '棰勭害鐨�9鐐癸紝瀹為檯10鐐规墠瑙佸埌鍖荤敓'
- }
- ];
- resolve();
- }, 300);
- });
+ // 鑾峰彇绉戝鍒楄〃
+ async getDeptOptions() {
+ try {
+ const res = await deptTreeSelect();
+ if (res.code == 200) {
+ this.deptList = this.flattenArray(res.data) || [];
+ }
+ } catch (error) {
+ console.error('鑾峰彇绉戝鍒楄〃澶辫触:', error);
+ }
},
- // 鍔犺浇澶勭悊璁板綍
- async loadProcessRecords() {
- return new Promise(resolve => {
- setTimeout(() => {
- this.processRecords = [
- {
- id: 1,
- time: '2024-01-15 14:20:30',
- user: '寮犲尰鐢�',
- status: 1, // 澶勭悊涓�
- reportDepts: ['鍖诲姟绉�', '鎶ょ悊閮�'],
- remark: '宸叉敹鍒板弽棣堬紝姝e湪瀹夋帓鐩稿叧浜哄憳鏍告煡鎯呭喌',
- attachments: [
- { id: 1, name: '鍒濇璋冩煡璁板綍.docx' },
- { id: 2, name: '鎮h�呮矡閫氳褰�.jpg' }
- ]
- },
- {
- id: 2,
- time: '2024-01-15 10:45:12',
- user: '绯荤粺',
- status: 0, // 寰呭鐞�
- remark: '绯荤粺鑷姩璇嗗埆涓哄紓甯稿弽棣堬紝宸插垎閰嶅埌璐d换绉戝',
- attachments: []
- }
- ];
- resolve();
- }, 300);
- });
- },
+ // 灞曞钩鏁扮粍
+ flattenArray(multiArray) {
+ let result = [];
- // 鍒ゆ柇鏄惁涓轰笉婊℃剰閫夐」
- isUnsatisfactoryOption(value) {
- const unsatisfactoryValues = [
- '涓嶆弧鎰�',
- '闈炲父涓嶆弧鎰�',
- '涓嶅涓撲笟',
- '闈炲父涓嶄笓涓�',
- '涓嶅鍏呭垎',
- '闈炲父涓嶅厖鍒�'
- ];
- return unsatisfactoryValues.includes(value);
+ 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;
},
// 鑾峰彇鐘舵�佹爣绛剧被鍨�
- getStatusTagType(status) {
- switch (status) {
- case 0: return 'warning'; // 寰呭鐞�
- case 1: return 'primary'; // 澶勭悊涓�
- case 2: return 'success'; // 宸插鐞�
- case 3: return 'danger'; // 宸查┏鍥�
+ getStatusTagType(handleFlag) {
+ switch (handleFlag) {
+ case '0': return 'warning'; // 鏈鐞�
+ case '1': return 'success'; // 宸插鐞�
default: return 'info';
}
},
// 鑾峰彇鐘舵�佹枃鏈�
- getStatusText(status) {
- switch (status) {
- case 0: return '寰呭鐞�';
- case 1: return '澶勭悊涓�';
- case 2: return '宸插鐞�';
- case 3: return '宸查┏鍥�';
+ getStatusText(handleFlag) {
+ switch (handleFlag) {
+ case '0': return '鏈鐞�';
+ case '1': return '宸插鐞�';
default: return '鏈煡';
+ }
+ },
+
+ // 鑾峰彇澶勭悊缁撴灉鏂囨湰
+ getHandleresultText(handleresult) {
+ const map = {
+ 'resolved': '宸茶В鍐�',
+ 'explained': '宸茶В閲�',
+ 'transferred': '宸茶浆浜�',
+ 'improvement': '闇�鏀硅繘',
+ 'rejected': '宸查┏鍥�'
+ };
+ return map[handleresult] || handleresult;
+ },
+
+ // 鑾峰彇绉戝鏁扮粍
+ getDeptArray(ccdepts) {
+ if (!ccdepts) return [];
+ return ccdepts.split(',');
+ },
+
+ // 鎾斁闊抽
+ handlePlayAudio(url) {
+ this.audioUrl = url;
+ this.$nextTick(() => {
+ const audioPlayer = this.$refs.audioPlayer;
+ if (audioPlayer) {
+ audioPlayer.play().catch(error => {
+ console.error('鎾斁澶辫触:', error);
+ this.$message.error('闊抽鎾斁澶辫触');
+ });
+ }
+ });
+ },
+
+ // 鑾峰彇涓婚鏍峰紡绫�
+ getTopicClass(item) {
+ if (item.isabnormal == 1) {
+ return "scriptTopic-isabnormal";
+ } else if (item.isabnormal == 2) {
+ return "scriptTopic-warning";
+ } else {
+ return "scriptTopic-dev";
+ }
+ },
+
+ // 鑾峰彇閫夐」鏍峰紡绫�
+ getOptionClass(items) {
+ if (items.isabnormal == 1) {
+ return "red-star";
+ } else if (items.isabnormal == 2) {
+ return "yellow-star";
+ }
+ return "";
+ },
+
+ // 鍔犺浇鏁版嵁
+ async loadData() {
+ this.loading = true;
+ try {
+ this.hasQualityPermission = this.checkQualityPermission();
+ await this.getDeptOptions();
+
+ if (Object.keys(this.currentRecord).length === 0) {
+ this.currentRecord = this.recordData || {};
+ }
+
+ // 濡傛灉褰撳墠璁板綍鏄闊虫ā鏉匡紝鍔犺浇璇煶鏁版嵁
+ if (this.currentRecord.templateType === 1) {
+ await this.loadVoiceData();
+ this.activeName = 'yy';
+ } else if (this.currentRecord.templateType === 2) {
+ await this.loadQuestionnaireData();
+ this.activeName = 'wj';
+ }
+
+ await this.loadProcessRecords();
+ } catch (error) {
+ console.error('鍔犺浇璇︽儏鏁版嵁澶辫触:', error);
+ this.$message.error('鍔犺浇鏁版嵁澶辫触');
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ // 閲嶇疆鏁版嵁
+ resetData() {
+ this.currentRecord = {};
+ this.templateData = [];
+ this.voiceData = [];
+ this.processRecords = [];
+ this.voiceAudioUrl = '';
+ this.taskName = '';
+ this.activeName = 'wj';
+ },
+
+ // 鍔犺浇闂嵎鏁版嵁
+ async loadQuestionnaireData() {
+ try {
+ // 杩欓噷闇�瑕佹牴鎹疄闄呮儏鍐佃皟鐢ㄦ帴鍙h幏鍙栭棶鍗锋暟鎹�
+ // 濡傛灉recordData涓凡缁忓寘鍚簡闂嵎鏁版嵁锛屽彲浠ョ洿鎺ヤ娇鐢�
+ if (this.currentRecord.taskid && this.currentRecord.patid) {
+ const params = {
+ taskid: this.currentRecord.taskid,
+ patid: this.currentRecord.patid,
+ subId: this.currentRecord.subId || this.currentRecord.id,
+ isFinish: true
+ };
+
+ const res = await getsearchrResults(params);
+ if (res.code === 200 && res.data) {
+ this.templateData = res.data.scriptResult || [];
+ this.taskName = res.data.taskName || '';
+
+ // 澶勭悊鏁版嵁鏍煎紡
+ this.templateData.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) {
+ item.scriptResult = item.scriptResult.split("&");
+ item.isoption = 3;
+ }
+ });
+
+ this.overdata();
+ }
+ }
+ } catch (error) {
+ console.error('鍔犺浇闂嵎鏁版嵁澶辫触:', error);
+ }
+ },
+
+ // 澶勭悊寮傚父鏁版嵁
+ overdata() {
+ this.templateData.forEach((item, index) => {
+ var obj = item.svyTaskTemplateTargetoptions.find(
+ (items) => items.optioncontent == item.scriptResult
+ );
+ if (obj && obj.isabnormal) {
+ this.templateData[index].isabnormal = obj.isabnormal;
+ }
+ this.$forceUpdate();
+ });
+ },
+
+ // 鍔犺浇璇煶鏁版嵁
+ async loadVoiceData() {
+ try {
+ if (this.currentRecord.taskid && this.currentRecord.patid) {
+ const params = {
+ taskid: this.currentRecord.taskid,
+ patid: this.currentRecord.patid,
+ subId: this.currentRecord.subId || this.currentRecord.id
+ };
+
+ const res = await getPersonVoices(params);
+ if (res.code == 200) {
+ this.voiceData = res.data.serviceSubtaskDetails || [];
+ this.voiceAudioUrl = res.data.voice || '';
+ this.taskName = res.data.taskName || '';
+ this.templateData = res.data.filteredDetails || [];
+
+ this.templateData.forEach((item) => {
+ if (item.targetvalue) {
+ item.scriptResult = item.targetvalue.split("&");
+ } else {
+ item.scriptResult = [];
+ }
+ });
+ }
+ }
+ } catch (error) {
+ console.error('鍔犺浇璇煶鏁版嵁澶辫触:', error);
+ }
+ },
+
+ // 鍔犺浇澶勭悊璁板綍
+ async loadProcessRecords() {
+ try {
+ // 杩欓噷鍙互鏍规嵁recordId鍔犺浇澶勭悊鍘嗗彶
+ // 鏆傛椂浣跨敤褰撳墠璁板綍鐨勫鐞嗕俊鎭�
+ if (this.currentRecord.handleTime) {
+ this.processRecords = [{
+ ...this.currentRecord,
+ time: this.currentRecord.handleTime
+ }];
+ }
+ } catch (error) {
+ console.error('鍔犺浇澶勭悊璁板綍澶辫触:', error);
}
},
// 澶勭悊寮傚父
handleProcess() {
this.processForm = {
- status: this.currentRecord.processStatus === 0 ? 1 : this.currentRecord.processStatus,
- reportDepts: [],
- remark: ''
+ handleFlag: this.currentRecord.handleFlag === '0' ? '1' : '0',
+ ccdepts: this.currentRecord.ccdepts ? this.currentRecord.ccdepts.split(',') : [],
+ handleresult: this.currentRecord.handleresult || '',
+ handledesc: this.currentRecord.handledesc || '',
+ finaloption: this.currentRecord.finaloption || ''
};
this.processDialogVisible = true;
},
@@ -608,52 +848,56 @@
// 鎻愪氦澶勭悊
async submitProcess() {
this.$refs.processForm.validate(async (valid) => {
- if (valid) {
- this.processing = true;
- try {
- // Mock API璋冪敤
- await new Promise(resolve => setTimeout(resolve, 1000));
+ if (!valid) {
+ return;
+ }
- this.$message.success('澶勭悊鎻愪氦鎴愬姛');
+ this.processing = true;
+ try {
+ const submitData = {
+ id: this.currentRecord.id,
+ handleFlag: this.processForm.handleFlag,
+ handleresult: this.processForm.handleresult,
+ handledesc: this.processForm.handledesc,
+ finaloption: this.processForm.finaloption,
+ ccdepts: Array.isArray(this.processForm.ccdepts)
+ ? this.processForm.ccdepts.join(",")
+ : this.processForm.ccdepts
+ };
+
+ const res = await traceedit(submitData);
+ if (res.code === 200) {
+ this.$message.success("澶勭悊鎻愪氦鎴愬姛");
this.processDialogVisible = false;
- // 閲嶆柊鍔犺浇鏁版嵁
- await this.loadData();
+ // 鏇存柊褰撳墠璁板綍
+ this.currentRecord = {
+ ...this.currentRecord,
+ ...submitData,
+ handleBy: this.$store.getters.name, // 褰撳墠鐢ㄦ埛
+ handleTime: new Date().toISOString().replace('T', ' ').substr(0, 19)
+ };
+
+ // 閲嶆柊鍔犺浇澶勭悊璁板綍
+ await this.loadProcessRecords();
// 瑙﹀彂鐖剁粍浠跺埛鏂�
this.$emit('processed');
- } finally {
- this.processing = false;
+ } else {
+ this.$message.error(res.msg || "澶勭悊鎻愪氦澶辫触");
}
+ } catch (error) {
+ console.error("澶勭悊鎻愪氦澶辫触:", error);
+ this.$message.error("澶勭悊鎻愪氦澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ this.processing = false;
}
});
- },
-
- // 棰勮鏂囦欢
- handlePreviewFile(file) {
- this.$message.info(`棰勮鏂囦欢: ${file.name}`);
},
// 澶勭悊瀵硅瘽妗嗗叧闂�
handleClose() {
this.$emit('close');
- },
-
- // 鏂囦欢涓婁紶鐩稿叧鏂规硶
- handleFilePreview(file) {
- console.log('棰勮鏂囦欢:', file);
- },
-
- handleFileRemove(file, fileList) {
- console.log('绉婚櫎鏂囦欢:', file, fileList);
- },
-
- beforeFileRemove(file) {
- return this.$confirm(`纭畾绉婚櫎 ${file.name}锛焋);
- },
-
- handleFileExceed(files, fileList) {
- this.$message.warning(`褰撳墠闄愬埗閫夋嫨 3 涓枃浠讹紝鏈閫夋嫨浜� ${files.length} 涓枃浠讹紝鍏遍�夋嫨浜� ${files.length + fileList.length} 涓枃浠禶);
}
}
};
@@ -705,116 +949,137 @@
font-size: 14px;
color: #303133;
font-weight: 500;
+ flex: 1;
}
}
}
- .questionnaire-section {
+ .content-container {
margin-bottom: 20px;
- padding: 20px;
- background: #fff;
- border-radius: 8px;
- border: 1px solid #ebeef5;
- .section-title {
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- margin-bottom: 15px;
- padding-bottom: 10px;
- border-bottom: 2px solid #409EFF;
+ ::v-deep .el-tabs__content {
+ padding: 20px;
+ background: #fff;
+ border-radius: 0 0 4px 4px;
}
- .questionnaire-content {
- .question-item {
- margin-bottom: 20px;
- padding: 15px;
- border-radius: 6px;
- border: 1px solid #ebeef5;
- transition: all 0.3s;
+ .CONTENT, .borderdiv {
+ padding: 20px;
+ background: #fff;
+ border-radius: 6px;
- &:hover {
- border-color: #409EFF;
- box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
+ .title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 20px;
+ padding-bottom: 10px;
+ border-bottom: 2px solid #409EFF;
+ }
+
+ .voice-audio {
+ margin-bottom: 20px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+
+ .audio-player {
+ flex: 1;
+ }
+ }
+
+ .preview-left {
+ .topic-dev {
+ margin-bottom: 20px;
+ padding: 15px;
+ border-radius: 6px;
+ border: 1px solid #ebeef5;
+ background: #fff;
+
+ .dev-text {
+ font-size: 15px;
+ font-weight: 500;
+ color: #303133;
+ margin-bottom: 15px;
+ line-height: 1.5;
+
+ span {
+ color: #606266;
+ }
+ }
+
+ .dev-xx {
+ ::v-deep .el-radio-group,
+ ::v-deep .el-checkbox-group {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ ::v-deep .el-radio,
+ ::v-deep .el-checkbox {
+ margin: 0;
+ padding: 8px 12px;
+ border-radius: 4px;
+ border: 1px solid #ebeef5;
+ transition: all 0.3s;
+
+ &:hover {
+ background: #f5f7fa;
+ }
+
+ &.red-star {
+ border-color: #f56c6c;
+ background: #fef0f0;
+ }
+
+ &.yellow-star {
+ border-color: #e6a23c;
+ background: #fdf6ec;
+ }
+ }
+ }
+
+ .append-input-container {
+ margin-top: 15px;
+ }
+
+ .el-alert {
+ margin-top: 10px;
+ }
}
- .question-header {
+ .leftside {
display: flex;
align-items: center;
- margin-bottom: 15px;
- padding-bottom: 10px;
- border-bottom: 1px dashed #dcdfe6;
+ gap: 10px;
+ margin-bottom: 10px;
+ font-size: 15px;
+ font-weight: 500;
+ color: #303133;
- .question-index {
- font-weight: 600;
+ i {
color: #409EFF;
- margin-right: 8px;
- font-size: 15px;
+ }
+ }
+
+ .offside {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ margin-bottom: 20px;
+
+ i {
+ color: #67C23A;
+ margin-top: 8px;
}
- .question-text {
+ .offside-value {
flex: 1;
- font-size: 15px;
- color: #303133;
- font-weight: 500;
- line-height: 1.5;
- }
- .question-type {
- margin-left: 10px;
- }
- }
-
- .question-options {
- ::v-deep .el-radio-group {
- display: flex;
- flex-direction: column;
- gap: 10px;
- }
-
- ::v-deep .el-checkbox-group {
- display: flex;
- flex-wrap: wrap;
- gap: 15px;
- }
-
- ::v-deep .el-radio,
- ::v-deep .el-checkbox {
- margin: 0;
- padding: 8px 12px;
- border-radius: 4px;
- border: 1px solid #ebeef5;
- transition: all 0.3s;
-
- &:hover {
- background: #f5f7fa;
+ .el-textarea {
+ margin-bottom: 10px;
}
-
- &.unsatisfactory-option {
- border-color: #e6a23c;
- background: #fdf6ec;
- }
- }
- }
-
- .additional-remark {
- margin-top: 15px;
- padding: 12px;
- background: #f0f9ff;
- border-radius: 6px;
- border-left: 4px solid #409EFF;
-
- .remark-label {
- font-size: 13px;
- color: #606266;
- font-weight: 500;
- margin-bottom: 5px;
- }
-
- .remark-content {
- font-size: 14px;
- color: #303133;
- line-height: 1.6;
}
}
}
@@ -886,30 +1151,8 @@
line-height: 1.5;
}
}
-
- .process-attachments {
- .label {
- font-size: 13px;
- color: #606266;
- margin-right: 5px;
- }
-
- ::v-deep .el-button {
- margin-right: 8px;
- margin-bottom: 5px;
- }
- }
}
}
- }
-
- .no-record {
- text-align: center;
- padding: 40px 0;
- color: #909399;
- font-style: italic;
- background: #f8f9fa;
- border-radius: 6px;
}
}
@@ -920,4 +1163,15 @@
gap: 10px;
}
}
+
+// 寮傚父鏍峰紡
+.scriptTopic-isabnormal {
+ border-color: #f56c6c !important;
+ background: #fef0f0 !important;
+}
+
+.scriptTopic-warning {
+ border-color: #e6a23c !important;
+ background: #fdf6ec !important;
+}
</style>
diff --git a/src/views/Satisfaction/configurationmyd/dispose.vue b/src/views/Satisfaction/configurationmyd/dispose.vue
index 8a59106..4c39707 100644
--- a/src/views/Satisfaction/configurationmyd/dispose.vue
+++ b/src/views/Satisfaction/configurationmyd/dispose.vue
@@ -19,9 +19,9 @@
label-width="120px"
class="search-form"
>
- <el-form-item label="婊℃剰搴︽ā鏉�" prop="templateId">
+ <el-form-item label="婊℃剰搴︾被鍨�" prop="templateid">
<el-select
- v-model="queryParams.templateId"
+ v-model="queryParams.templateType"
placeholder="璇烽�夋嫨妯℃澘"
clearable
style="width: 200px"
@@ -35,9 +35,9 @@
</el-select>
</el-form-item>
- <el-form-item label="璐d换绉戝" prop="deptIds">
+ <el-form-item label="璐d换绉戝" prop="todeptcode">
<el-select
- v-model="queryParams.deptIds"
+ v-model="queryParams.todeptcode"
placeholder="璇烽�夋嫨璐d换绉戝"
clearable
filterable
@@ -47,21 +47,21 @@
>
<el-option
v-for="dept in deptList"
- :key="dept.id"
- :label="dept.name"
- :value="dept.id"
+ :key="dept.deptCode"
+ :label="dept.label"
+ :value="dept.deptCode"
/>
</el-select>
</el-form-item>
- <el-form-item label="缁熻鏃堕棿" prop="dateRange">
+ <el-form-item label="澶勭悊鏃堕棿" prop="handleTimeRange">
<el-date-picker
- v-model="queryParams.dateRange"
- type="daterange"
+ v-model="queryParams.handleTimeRange"
+ type="datetimerange"
range-separator="鑷�"
- start-placeholder="寮�濮嬫棩鏈�"
- end-placeholder="缁撴潫鏃ユ湡"
- value-format="yyyy-MM-dd"
+ start-placeholder="寮�濮嬫椂闂�"
+ end-placeholder="缁撴潫鏃堕棿"
+ value-format="yyyy-MM-dd HH:mm:ss"
:picker-options="pickerOptions"
style="width: 380px"
/>
@@ -96,11 +96,7 @@
>
鎵归噺澶勭悊 ({{ selectedIds.length }})
</el-button>
- <el-button
- type="info"
- icon="el-icon-download"
- @click="handleExport"
- >
+ <el-button type="info" icon="el-icon-download" @click="handleExport">
瀵煎嚭寮傚父鏁版嵁
</el-button>
<el-button
@@ -117,24 +113,26 @@
<!-- 寮傚父缁熻姒傝 -->
<div class="overview-section">
<el-row :gutter="20">
- <el-col :span="6">
+ <el-col :span="8">
<el-card shadow="never" class="stat-card">
<div class="stat-content">
- <div class="stat-icon" style="background: #f0f9ff;">
- <i class="el-icon-s-claim" style="color: #5788FE;"></i>
+ <div class="stat-icon" style="background: #f0f9ff">
+ <i class="el-icon-s-claim" style="color: #5788fe"></i>
</div>
<div class="stat-info">
<div class="stat-title">鎬诲紓甯告暟閲�</div>
- <div class="stat-value">{{ overviewData.totalExceptionCount }}</div>
+ <div class="stat-value">
+ {{ overviewData.totalExceptionCount }}
+ </div>
</div>
</div>
</el-card>
</el-col>
- <el-col :span="6">
+ <el-col :span="8">
<el-card shadow="never" class="stat-card">
<div class="stat-content">
- <div class="stat-icon" style="background: #f0f9ff;">
- <i class="el-icon-s-flag" style="color: #E6A23C;"></i>
+ <div class="stat-icon" style="background: #f0f9ff">
+ <i class="el-icon-s-flag" style="color: #e6a23c"></i>
</div>
<div class="stat-info">
<div class="stat-title">寰呭鐞嗗紓甯�</div>
@@ -143,28 +141,15 @@
</div>
</el-card>
</el-col>
- <el-col :span="6">
+ <el-col :span="8">
<el-card shadow="never" class="stat-card">
<div class="stat-content">
- <div class="stat-icon" style="background: #f0f9ff;">
- <i class="el-icon-check" style="color: #67C23A;"></i>
+ <div class="stat-icon" style="background: #f0f9ff">
+ <i class="el-icon-check" style="color: #67c23a"></i>
</div>
<div class="stat-info">
<div class="stat-title">宸插鐞嗗紓甯�</div>
<div class="stat-value">{{ overviewData.processedCount }}</div>
- </div>
- </div>
- </el-card>
- </el-col>
- <el-col :span="6">
- <el-card shadow="never" class="stat-card">
- <div class="stat-content">
- <div class="stat-icon" style="background: #f0f9ff;">
- <i class="el-icon-s-order" style="color: #909399;"></i>
- </div>
- <div class="stat-info">
- <div class="stat-title">浠婃棩澶勭悊鏁�</div>
- <div class="stat-value">{{ overviewData.todayProcessedCount }}</div>
</div>
</div>
</el-card>
@@ -183,11 +168,7 @@
@selection-change="handleSelectionChange"
class="exception-table"
>
- <el-table-column
- type="selection"
- width="55"
- align="center"
- />
+ <el-table-column type="selection" width="55" align="center" />
<el-table-column
label="搴忓彿"
@@ -198,25 +179,19 @@
<el-table-column
label="棰樼洰鍐呭"
- prop="questionContent"
+ prop="questiontext"
min-width="300"
align="center"
>
<template slot-scope="{ row }">
<div class="question-content">
- <span class="question-text">{{ row.questionContent }}</span>
+ <span class="question-text">{{ row.questiontext }}</span>
<div class="question-tags">
<el-tag
size="mini"
- :type="getQuestionTypeTag(row.questionType)"
+ :type="getTemplateTypeTag(row.templateType)"
>
- {{ row.questionType === 1 ? '鍗曢�夐' : '澶氶�夐' }}
- </el-tag>
- <el-tag
- size="mini"
- type="info"
- >
- {{ row.templateName }}
+ {{ row.templateType === 1 ? "璇煶妯℃澘" : "闂嵎妯℃澘" }}
</el-tag>
</div>
</div>
@@ -225,62 +200,64 @@
<el-table-column
label="璐熻矗绉戝"
- prop="responsibilityDepts"
+ prop="responsibleDept"
width="180"
align="center"
>
<template slot-scope="{ row }">
<div class="dept-list">
<el-tag
- v-for="dept in row.responsibilityDepts"
- :key="dept.id"
+ v-for="dept in row.responsibleDept"
+ :key="dept.deptCode"
size="small"
type="primary"
class="dept-tag"
>
- {{ dept.name }}
+ {{ dept.deptName }}
</el-tag>
</div>
</template>
</el-table-column>
- <el-table-column
- label="濉啓鎯呭喌"
- width="200"
- align="center"
- >
+ <el-table-column label="濉啓鎯呭喌" width="200" align="center">
<template slot-scope="{ row }">
<div class="fill-statistics">
<div class="stat-item">
<span class="stat-label">鏈夋晥濉啓锛�</span>
- <span class="stat-value">{{ row.validFillCount }}</span>
+ <span class="stat-value">{{
+ row.fillSituation.effectiveFillNum
+ }}</span>
</div>
<div class="stat-item">
<span class="stat-label">寮傚父濉啓锛�</span>
- <span class="stat-value exception-count">{{ row.exceptionFillCount }}</span>
+ <span class="stat-value exception-count">{{
+ row.fillSituation.exceptionFillNum
+ }}</span>
</div>
</div>
</template>
</el-table-column>
- <el-table-column
- label="寮傚父浠诲姟"
- width="280"
- align="center"
- >
+ <el-table-column label="寮傚父浠诲姟" width="280" align="center">
<template slot-scope="{ row }">
<div class="exception-tasks">
<div class="task-category">
<div class="task-title">宸插鐞�</div>
- <div class="task-count processed">{{ row.processedCount }}</div>
+ <div class="task-count processed">
+ {{ row.exceptionQuesNum.yesDeal }}
+ </div>
</div>
<div class="task-category">
<div class="task-title">寰呭鐞�</div>
- <div class="task-count pending">{{ row.pendingCount }}</div>
+ <div class="task-count pending">
+ {{ row.exceptionQuesNum.noDeal }}
+ </div>
</div>
<div class="task-category">
<div class="task-title">寮傚父鎬绘暟</div>
- <div class="task-count total">{{ row.totalExceptionCount }}</div>
+ <div class="task-count total">
+ {{ row.exceptionQuesNum.all }}
+ </div>
</div>
</div>
</template>
@@ -288,14 +265,16 @@
<el-table-column
label="鏈�杩戝鐞�"
- prop="lastProcessTime"
+ prop="handleTime"
width="180"
align="center"
>
<template slot-scope="{ row }">
- <div v-if="row.lastProcessTime" class="last-process">
- <div class="process-time">{{ row.lastProcessTime }}</div>
- <div class="process-user">{{ row.lastProcessUser }}</div>
+ <div v-if="row.handleTime" class="last-process">
+ <div class="process-time">
+ {{ formatDateTime(row.handleTime) }}
+ </div>
+ <div class="process-user">{{ row.handleBy || "绯荤粺澶勭悊" }}</div>
</div>
<span v-else class="no-process">鏆傛棤澶勭悊璁板綍</span>
</template>
@@ -308,14 +287,6 @@
fixed="right"
>
<template slot-scope="{ row }">
- <!-- <el-button
- type="primary"
- size="small"
- icon="el-icon-view"
- @click="handleViewDetail(row)"
- >
- 璇︽儏
- </el-button> -->
<el-button
type="warning"
size="small"
@@ -347,17 +318,23 @@
</template>
<script>
+import { tracedeallist } from "@/api/AiCentre/index";
+import { deptTreeSelect } from "@/api/system/user";
+
export default {
- name: 'ExceptionList',
+ name: "ExceptionList",
data() {
return {
// 鏌ヨ鍙傛暟
queryParams: {
- templateId: '',
- deptIds: [],
- dateRange: [],
+ todeptcode: [], // 澶勭悊绉戝缂栧彿鏁扮粍
+ todeptname: "", // 澶勭悊绉戝鍚嶇О
+ templateType: 2, // 浠诲姟妯℃澘ID
+ handleStartTime: "", // 澶勭悊寮�濮嬫椂闂�
+ handleEndTime: "", // 澶勭悊缁撴潫鏃堕棿
+ handleTimeRange: [], // 鏃堕棿鑼冨洿锛岀敤浜庣晫闈㈠睍绀�
pageNum: 1,
- pageSize: 10
+ pageSize: 10,
},
// 鍔犺浇鐘舵��
@@ -368,27 +345,13 @@
// 妯℃澘鍒楄〃
templateList: [
- { id: 1, name: '鍑洪櫌婊℃剰搴﹂棶鍗�' },
- { id: 2, name: '浣忛櫌婊℃剰搴﹂棶鍗�' },
- { id: 3, name: '闂ㄨ瘖婊℃剰搴﹂棶鍗�' },
- { id: 4, name: '甯哥敤婊℃剰搴﹂棶鍗�' }
+ { id: 1, name: "璇煶婊℃剰搴�" },
+ { id: 2, name: "闂嵎婊℃剰搴�" },
+ // 浣犲彲浠ユ牴鎹疄闄呮儏鍐典粠鎺ュ彛鑾峰彇妯℃澘鍒楄〃
],
// 绉戝鍒楄〃
- deptList: [
- { id: 1, name: '蹇冭绠″唴绉�' },
- { id: 2, name: '绁炵粡鍐呯' },
- { id: 3, name: '鏅绉�' },
- { id: 4, name: '楠ㄧ' },
- { id: 5, name: '濡囦骇绉�' },
- { id: 6, name: '鍎跨' },
- { id: 7, name: '鎬ヨ瘖绉�' },
- { id: 8, name: '鍛煎惛鍐呯' },
- { id: 9, name: '娑堝寲鍐呯' },
- { id: 10, name: '鍐呭垎娉岀' },
- { id: 11, name: '鑲惧唴绉�' },
- { id: 12, name: '鑲跨槫绉�' }
- ],
+ deptList: [],
// 寮傚父鍒楄〃鏁版嵁
exceptionList: [],
@@ -399,60 +362,134 @@
totalExceptionCount: 0,
pendingCount: 0,
processedCount: 0,
- todayProcessedCount: 0
+ todayProcessedCount: 0,
},
// 鏃ユ湡閫夋嫨鍣ㄩ�夐」
pickerOptions: {
shortcuts: [
{
- text: '鏈�杩戜竴鍛�',
+ text: "鏈�杩戜竴鍛�",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
- picker.$emit('pick', [start, end]);
- }
+ picker.$emit("pick", [start, end]);
+ },
},
{
- text: '鏈�杩戜竴涓湀',
+ text: "鏈�杩戜竴涓湀",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
- picker.$emit('pick', [start, end]);
- }
+ picker.$emit("pick", [start, end]);
+ },
},
{
- text: '鏈�杩戜笁涓湀',
+ text: "鏈�杩戜笁涓湀",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
- picker.$emit('pick', [start, end]);
- }
- }
+ picker.$emit("pick", [start, end]);
+ },
+ },
],
disabledDate(time) {
return time.getTime() > Date.now();
- }
- }
+ },
+ },
};
},
mounted() {
this.loadData();
+ this.getDeptOptions();
},
methods: {
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return "";
+ const date = new Date(dateTime);
+ return (
+ date.toLocaleDateString().replace(/\//g, "-") +
+ " " +
+ date.toTimeString().split(" ")[0]
+ );
+ },
+
+ // 鑾峰彇妯℃澘绫诲瀷鏍囩鏍峰紡
+ getTemplateTypeTag(type) {
+ return type === 1 ? "primary" : "success";
+ },
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ buildQueryParams() {
+ const params = {
+ pageNum: this.queryParams.pageNum,
+ pageSize: this.queryParams.pageSize,
+ };
+
+ // 澶勭悊绉戝缂栧彿
+ if (
+ this.queryParams.todeptcode &&
+ this.queryParams.todeptcode.length > 0
+ ) {
+ // 鎺ュ彛鍙兘闇�瑕佸瓧绗︿覆鏍煎紡鐨勭瀹ょ紪鍙凤紝鏍规嵁瀹為檯鎯呭喌璋冩暣
+ params.todeptcode = this.queryParams.todeptcode.join(",");
+ }
+
+ // 妯℃澘ID
+ if (this.queryParams.templateType) {
+ params.templateType = this.queryParams.templateType;
+ }
+
+ // 澶勭悊鏃堕棿鑼冨洿
+ if (
+ this.queryParams.handleTimeRange &&
+ this.queryParams.handleTimeRange.length === 2
+ ) {
+ params.handleStartTime = this.queryParams.handleTimeRange[0];
+ params.handleEndTime = this.queryParams.handleTimeRange[1];
+ }
+
+ return params;
+ },
+ /** 鏌ヨ绉戝鍒楄〃 */
+ getDeptOptions() {
+ deptTreeSelect()
+ .then((res) => {
+ if (res.code == 200) {
+ this.deptList = this.flattenArray(res.data) || [];
+ }
+ })
+ .catch((error) => {
+ console.error("鑾峰彇绉戝鍒楄〃澶辫触:", error);
+ this.$message.error("鑾峰彇绉戝鍒楄〃澶辫触");
+ });
+ },
+ 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;
+ },
// 鍔犺浇鏁版嵁
async loadData() {
this.loading = true;
try {
- await Promise.all([
- this.loadExceptionList(),
- this.loadOverviewData()
- ]);
+ await Promise.all([this.loadExceptionList(), this.loadOverviewData()]);
} finally {
this.loading = false;
}
@@ -460,185 +497,70 @@
// 鍔犺浇寮傚父鍒楄〃
async loadExceptionList() {
- return new Promise((resolve) => {
- setTimeout(() => {
- // Mock 鏁版嵁
- this.exceptionList = [
- {
- id: 1,
- questionId: 101,
- questionContent: '鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�',
- questionType: 1, // 1: 鍗曢�夐, 2: 澶氶�夐
- templateName: '鍑洪櫌婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 1, name: '蹇冭绠″唴绉�' },
- { id: 2, name: '绁炵粡鍐呯' }
- ],
- validFillCount: 145,
- exceptionFillCount: 8,
- processedCount: 5,
- pendingCount: 3,
- totalExceptionCount: 8,
- lastProcessTime: '2024-01-15 10:30:25',
- lastProcessUser: '寮犲尰鐢�'
- },
- {
- id: 2,
- questionId: 102,
- questionContent: '鎮ㄥ鍖荤敓鐨勮瘖鐤楁按骞冲拰鎶�鏈兘鍔涜瘎浠峰浣曪紵',
- questionType: 1,
- templateName: '浣忛櫌婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 3, name: '鏅绉�' },
- { id: 4, name: '楠ㄧ' }
- ],
- validFillCount: 120,
- exceptionFillCount: 12,
- processedCount: 8,
- pendingCount: 4,
- totalExceptionCount: 12,
- lastProcessTime: '2024-01-14 16:20:10',
- lastProcessUser: '鏉庢姢澹暱'
- },
- {
- id: 3,
- questionId: 103,
- questionContent: '鎮ㄥ鍖婚櫌鐨勭幆澧冨拰鍗敓鐘跺喌鏄惁婊℃剰锛�',
- questionType: 1,
- templateName: '闂ㄨ瘖婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 5, name: '濡囦骇绉�' },
- { id: 6, name: '鍎跨' },
- { id: 7, name: '鎬ヨ瘖绉�' }
- ],
- validFillCount: 180,
- exceptionFillCount: 15,
- processedCount: 10,
- pendingCount: 5,
- totalExceptionCount: 15,
- lastProcessTime: '2024-01-13 09:15:45',
- lastProcessUser: '鐜嬩富浠�'
- },
- {
- id: 4,
- questionId: 104,
- questionContent: '鎮ㄨ涓哄尰鎶や汉鍛樹笌鎮ㄧ殑娌熼�氭槸鍚﹀厖鍒嗭紵',
- questionType: 1,
- templateName: '甯哥敤婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 8, name: '鍛煎惛鍐呯' },
- { id: 9, name: '娑堝寲鍐呯' }
- ],
- validFillCount: 95,
- exceptionFillCount: 6,
- processedCount: 4,
- pendingCount: 2,
- totalExceptionCount: 6,
- lastProcessTime: '2024-01-12 14:40:30',
- lastProcessUser: '璧靛尰鐢�'
- },
- {
- id: 5,
- questionId: 105,
- questionContent: '鎮ㄥ绛夊緟灏辫瘖鍜屾不鐤楃殑鏃堕棿鏄惁婊℃剰锛�',
- questionType: 1,
- templateName: '浣忛櫌婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 10, name: '鍐呭垎娉岀' },
- { id: 11, name: '鑲惧唴绉�' }
- ],
- validFillCount: 200,
- exceptionFillCount: 25,
- processedCount: 15,
- pendingCount: 10,
- totalExceptionCount: 25,
- lastProcessTime: '2024-01-11 11:25:15',
- lastProcessUser: '瀛欐姢澹�'
- },
- {
- id: 6,
- questionId: 106,
- questionContent: '鎮ㄥ鍖婚櫌鏀惰垂鐨勯�忔槑搴﹀拰鍚堢悊鎬ц瘎浠峰浣曪紵',
- questionType: 1,
- templateName: '闂ㄨ瘖婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 12, name: '鑲跨槫绉�' }
- ],
- validFillCount: 160,
- exceptionFillCount: 18,
- processedCount: 12,
- pendingCount: 6,
- totalExceptionCount: 18,
- lastProcessTime: '2024-01-10 15:50:20',
- lastProcessUser: '鍛ㄥ尰鐢�'
- },
- {
- id: 7,
- questionId: 107,
- questionContent: '鎮ㄤ細鍚戜翰鍙嬫帹鑽愭垜浠尰闄㈠悧锛�',
- questionType: 1,
- templateName: '鍑洪櫌婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 1, name: '蹇冭绠″唴绉�' },
- { id: 8, name: '鍛煎惛鍐呯' }
- ],
- validFillCount: 110,
- exceptionFillCount: 7,
- processedCount: 5,
- pendingCount: 2,
- totalExceptionCount: 7,
- lastProcessTime: '2024-01-09 10:15:40',
- lastProcessUser: '鍚翠富浠�'
- },
- {
- id: 8,
- questionId: 108,
- questionContent: '鎮ㄥ浠ヤ笅鍝簺鏂归潰姣旇緝婊℃剰锛堝閫夛級锛�',
- questionType: 2,
- templateName: '甯哥敤婊℃剰搴﹂棶鍗�',
- responsibilityDepts: [
- { id: 2, name: '绁炵粡鍐呯' },
- { id: 3, name: '鏅绉�' },
- { id: 5, name: '濡囦骇绉�' }
- ],
- validFillCount: 135,
- exceptionFillCount: 9,
- processedCount: 6,
- pendingCount: 3,
- totalExceptionCount: 9,
- lastProcessTime: '2024-01-08 13:30:55',
- lastProcessUser: '閮戝尰鐢�'
- }
- ];
- this.total = this.exceptionList.length;
- resolve();
- }, 500);
- });
+ try {
+ const params = this.buildQueryParams();
+ const response = await tracedeallist(params);
+
+ if (response.code == 200) {
+ this.exceptionList = response.rows.detailTraceDealDTOList || [];
+ this.overviewData.totalExceptionCount = response.rows.totalException;
+ this.overviewData.pendingCount = response.rows.noDealException;
+ this.overviewData.processedCount = response.rows.yesDealException;
+ this.total = response.total || 0;
+ } else {
+ this.exceptionList = [];
+ this.total = 0;
+ }
+ } catch (error) {
+ console.error("鍔犺浇寮傚父鍒楄〃澶辫触:", error);
+ this.$message.error("鍔犺浇寮傚父鍒楄〃澶辫触锛岃绋嶅悗閲嶈瘯");
+ this.exceptionList = [];
+ this.total = 0;
+ }
},
// 鍔犺浇姒傝鏁版嵁
async loadOverviewData() {
- return new Promise((resolve) => {
- setTimeout(() => {
- // 璁$畻缁熻鏁版嵁
- const totalExceptionCount = this.exceptionList.reduce((sum, item) => sum + item.totalExceptionCount, 0);
- const pendingCount = this.exceptionList.reduce((sum, item) => sum + item.pendingCount, 0);
- const processedCount = this.exceptionList.reduce((sum, item) => sum + item.processedCount, 0);
+ try {
+ // 浠庢帴鍙f暟鎹绠楃粺璁℃暟鎹�
+ const totalExceptionCount = this.exceptionList.reduce(
+ (sum, item) => sum + (item.exceptionQuesNum?.all || 0),
+ 0
+ );
+ const pendingCount = this.exceptionList.reduce(
+ (sum, item) => sum + (item.exceptionQuesNum?.noDeal || 0),
+ 0
+ );
+ const processedCount = this.exceptionList.reduce(
+ (sum, item) => sum + (item.exceptionQuesNum?.yesDeal || 0),
+ 0
+ );
- this.overviewData = {
- totalExceptionCount,
- pendingCount,
- processedCount,
- todayProcessedCount: 8 // 浠婃棩澶勭悊鏁� mock
- };
- resolve();
- }, 300);
- });
- },
+ // 璁$畻浠婃棩澶勭悊鏁帮紙杩欓噷鍙互鏍规嵁瀹為檯闇�姹傝皟鏁撮�昏緫锛�
+ const today = new Date().toISOString().split("T")[0];
+ const todayProcessedCount = this.exceptionList.filter((item) => {
+ if (!item.handleTime) return false;
+ const handleDate = new Date(item.handleTime)
+ .toISOString()
+ .split("T")[0];
+ return handleDate === today;
+ }).length;
- // 鑾峰彇棰樼洰绫诲瀷鏍囩鏍峰紡
- getQuestionTypeTag(type) {
- return type === 1 ? 'primary' : 'success';
+ this.overviewData = {
+ totalExceptionCount,
+ pendingCount,
+ processedCount,
+ todayProcessedCount,
+ };
+ } catch (error) {
+ console.error("鍔犺浇姒傝鏁版嵁澶辫触:", error);
+ this.overviewData = {
+ totalExceptionCount: 0,
+ pendingCount: 0,
+ processedCount: 0,
+ todayProcessedCount: 0,
+ };
+ }
},
// 澶勭悊鏌ヨ
@@ -650,60 +572,53 @@
// 澶勭悊閲嶇疆
handleReset() {
this.$refs.queryForm.resetFields();
- this.queryParams.dateRange = [];
+ this.queryParams.handleTimeRange = [];
this.queryParams.pageNum = 1;
+ this.queryParams.todeptcode = []; // 閲嶇疆绉戝閫夋嫨
this.loadData();
},
// 澶勭悊鎵归噺澶勭悊
handleBatchProcess() {
if (this.selectedIds.length === 0) {
- this.$message.warning('璇峰厛閫夋嫨瑕佸鐞嗙殑寮傚父棰樼洰');
+ this.$message.warning("璇峰厛閫夋嫨瑕佸鐞嗙殑寮傚父棰樼洰");
return;
}
// 璺宠浆鍒版壒閲忓鐞嗛〉闈�
this.$router.push({
- path: '/satisfaction/exception/batch-process',
+ path: "/Intelligentcenter/batch",
query: {
- questionIds: this.selectedIds.join(',')
- }
+ questionIds: this.selectedIds.join(","),
+ type: this.queryParams.templateType,
+ },
});
},
// 澶勭悊瀵煎嚭
handleExport() {
- this.$message.success('瀵煎嚭鍔熻兘寮�鍙戜腑...');
+ this.$message.success("瀵煎嚭鍔熻兘寮�鍙戜腑...");
},
// 鍒锋柊鏁版嵁
refreshData() {
this.loadData();
- this.$message.success('鏁版嵁宸插埛鏂�');
+ this.$message.success("鏁版嵁宸插埛鏂�");
},
// 澶勭悊閫夋嫨鍙樺寲
handleSelectionChange(selection) {
- this.selectedIds = selection.map(item => item.questionId);
- },
-
- // 澶勭悊鏌ョ湅璇︽儏
- handleViewDetail(row) {
- this.$router.push({
- path: '/satisfaction/exception/detail',
- query: {
- id: row.questionId
- }
- });
+ this.selectedIds = selection.map((item) => item.scriptid);
},
// 澶勭悊鍗曚釜棰樼洰鎵归噺澶勭悊
handleBatchQuestion(row) {
this.$router.push({
- path: '/Intelligentcenter/batch',
+ path: "/Intelligentcenter/batch",
query: {
- questionId: row.questionId
- }
+ questionId: row.scriptid,
+ type: this.queryParams.templateType,
+ },
});
},
@@ -718,8 +633,8 @@
handlePageChange(page) {
this.queryParams.pageNum = page;
this.loadExceptionList();
- }
- }
+ },
+ },
};
</script>
@@ -732,7 +647,7 @@
.page-header {
margin-bottom: 20px;
padding: 20px;
- background: linear-gradient(135deg, #5788FE 0%, #66b1ff 100%);
+ background: linear-gradient(135deg, #5788fe 0%, #66b1ff 100%);
border-radius: 8px;
color: white;
@@ -838,12 +753,13 @@
color: #303133;
margin-bottom: 8px;
line-height: 1.5;
+ text-align: left;
}
.question-tags {
display: flex;
gap: 5px;
- justify-content: center;
+ justify-content: flex-start;
}
}
@@ -915,7 +831,7 @@
}
&.total {
- color: #5788FE;
+ color: #5788fe;
}
}
}
@@ -930,7 +846,7 @@
.process-user {
font-size: 13px;
- color: #5788FE;
+ color: #5788fe;
font-weight: 500;
}
}
diff --git a/src/views/Satisfaction/configurationmyd/index.vue b/src/views/Satisfaction/configurationmyd/index.vue
index b92dfd9..5029a05 100644
--- a/src/views/Satisfaction/configurationmyd/index.vue
+++ b/src/views/Satisfaction/configurationmyd/index.vue
@@ -481,89 +481,95 @@
</div>
</div>
</div>
-<!-- 閫夐」閰嶇疆瀵硅瘽妗� -->
-<el-dialog
- title="閫夐」寮傚父鐘舵�侀厤缃�"
- :visible.sync="optionDialogVisible"
- width="700px"
- center
- :close-on-click-modal="false"
->
- <div v-if="editingQuestion" class="option-config-wrapper">
- <div class="dialog-header">
- <h4>{{ editingQuestion.scriptTopic || '鏃犱富棰�' }}</h4>
- <p class="dialog-subtitle">{{ editingQuestion.scriptContent }}</p>
- </div>
+ <!-- 閫夐」閰嶇疆瀵硅瘽妗� -->
+ <el-dialog
+ title="閫夐」寮傚父鐘舵�侀厤缃�"
+ :visible.sync="optionDialogVisible"
+ width="700px"
+ center
+ :close-on-click-modal="false"
+ >
+ <div v-if="editingQuestion" class="option-config-wrapper">
+ <div class="dialog-header">
+ <h4>{{ editingQuestion.scriptTopic || "鏃犱富棰�" }}</h4>
+ <p class="dialog-subtitle">{{ editingQuestion.scriptContent }}</p>
+ </div>
- <div class="option-list">
- <el-alert
- v-if="!currentOptions.some(opt => opt.isabnormal === 1)"
- title="璇疯嚦灏戣缃竴涓紓甯搁�夐」锛堟爣璁颁负寮傚父锛�"
- type="warning"
- :closable="false"
- show-icon
- style="margin-bottom: 20px;"
- />
+ <div class="option-list">
+ <el-alert
+ v-if="!currentOptions.some((opt) => opt.isabnormal === 1)"
+ title="璇疯嚦灏戣缃竴涓紓甯搁�夐」锛堟爣璁颁负寮傚父锛�"
+ type="warning"
+ :closable="false"
+ show-icon
+ style="margin-bottom: 20px"
+ />
- <div v-for="(option, index) in currentOptions" :key="index" class="option-item">
- <el-form
- :model="option"
- :rules="optionRules"
- ref="optionForm"
- size="small"
- class="option-form"
- >
- <el-row :gutter="12" align="middle">
- <el-col :span="2">
- <div class="option-index">#{{ index + 1 }}</div>
- </el-col>
+ <div
+ v-for="(option, index) in currentOptions"
+ :key="index"
+ class="option-item"
+ >
+ <el-form
+ :model="option"
+ :rules="optionRules"
+ ref="optionForm"
+ size="small"
+ class="option-form"
+ >
+ <el-row :gutter="12" align="middle">
+ <el-col :span="2">
+ <div class="option-index">#{{ index + 1 }}</div>
+ </el-col>
- <el-col :span="12">
- <el-form-item prop="targetvalue">
- <el-input
- v-model="option.targetvalue"
- placeholder="璇疯緭鍏ラ�夐」鍐呭"
- clearable
- maxlength="200"
- show-word-limit
- />
- </el-form-item>
- </el-col>
+ <el-col :span="12">
+ <el-form-item prop="targetvalue">
+ <el-input
+ v-model="option.targetvalue"
+ placeholder="璇疯緭鍏ラ�夐」鍐呭"
+ clearable
+ maxlength="200"
+ show-word-limit
+ />
+ </el-form-item>
+ </el-col>
- <el-col :span="6">
- <el-form-item prop="isabnormal">
- <el-select
- v-model="option.isabnormal"
- placeholder="閫夋嫨鐘舵��"
- style="width: 100%"
- >
- <el-option
- v-for="status in abnormalOptions"
- :key="status.value"
- :label="status.label"
- :value="status.value"
- >
- <el-tag :type="status.type" size="small">{{ status.label }}</el-tag>
- </el-option>
- </el-select>
- </el-form-item>
- </el-col>
+ <el-col :span="6">
+ <el-form-item prop="isabnormal">
+ <el-select
+ v-model="option.isabnormal"
+ placeholder="閫夋嫨鐘舵��"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="status in abnormalOptions"
+ :key="status.value"
+ :label="status.label"
+ :value="status.value"
+ >
+ <el-tag :type="status.type" size="small">{{
+ status.label
+ }}</el-tag>
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
- <el-col :span="4">
- <el-button
- type="danger"
- icon="el-icon-delete"
- @click="removeOption(index)"
- size="small"
- circle
- plain
- />
- </el-col>
- </el-row>
- </el-form>
- </div>
+ <el-col :span="4">
+ <el-button
+ type="danger"
+ icon="el-icon-delete"
+ @click="removeOption(index)"
+ size="small"
+ circle
+ plain
+ />
+ </el-col>
+ </el-row>
+ </el-form>
+ </div>
- <!-- <el-button
+ <!-- <el-button
type="primary"
icon="el-icon-plus"
@click="addNewOption"
@@ -573,16 +579,16 @@
>
娣诲姞閫夐」
</el-button> -->
- </div>
- </div>
+ </div>
+ </div>
- <span slot="footer" class="dialog-footer">
- <el-button @click="optionDialogVisible = false">鍙栨秷</el-button>
- <el-button type="primary" @click="saveOptions" :loading="savingOptions">
- 淇濆瓨閰嶇疆
- </el-button>
- </span>
-</el-dialog>
+ <span slot="footer" class="dialog-footer">
+ <el-button @click="optionDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveOptions" :loading="savingOptions">
+ 淇濆瓨閰嶇疆
+ </el-button>
+ </span>
+ </el-dialog>
<!-- 棰樼洰棰勮瀵硅瘽妗� -->
<el-dialog
title="棰樼洰棰勮"
@@ -848,30 +854,12 @@
this.voiceCategories.includes(q.scriptAssortid)
).length;
}
+ return 0;
},
- // 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」
- hasAbnormalOption(question) {
- return (question) => {
- if (!question) return false;
- // 闂嵎妯℃澘
- if (this.templateForm.templateType === 1) {
- const options = question.svyLibTemplateTargetoptions || [];
- return options.some((opt) => opt.isabnormal === 1);
- }
- // 璇煶妯℃澘
- else if (this.templateForm.templateType === 2) {
- const options = question.ivrLibaScriptTargetoptionList || [];
- return options.some((opt) => opt.isabnormal === 1);
- }
-
- return false;
- };
- },
// 绛涢�夊悗鐨勯鐩垪琛�
filteredQuestionList() {
let filtered = this.questionList;
- console.log(this.questionnaireCategorys);
// 绛涢�夋弧鎰忓害棰樼洰
if (this.templateForm.templateType === 1) {
@@ -888,7 +876,7 @@
if (this.queryParams.scriptTopic) {
const keyword = this.queryParams.scriptTopic.toLowerCase();
filtered = filtered.filter(
- (q) => q.scriptTopic && q.scriptTopic.toLowerCase().includes(keyword)
+ (q) => q.scriptTopic && q.criptTopic.toLowerCase().includes(keyword)
);
}
@@ -988,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 || "鍔犺浇闂嵎妯℃澘澶辫触");
}
@@ -1012,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 || "鍔犺浇璇煶妯℃澘澶辫触");
}
@@ -1215,6 +1211,8 @@
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];
if (formRef) {
@@ -1261,24 +1259,61 @@
const changedItems = this.questionList.filter((q) => q.hasChanges);
this.changedCount = changedItems.length;
this.hasChanges = changedItems.length > 0;
+
+ // 寮哄埗鏇存柊瑙嗗浘
+ this.$forceUpdate();
+ },
+
+ /** 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」 */
+ checkHasAbnormalOptions(question) {
+ if (this.templateForm.templateType === 1) {
+ return (question.svyLibTemplateTargetoptions || []).some(
+ (opt) => opt.isabnormal === 1
+ );
+ } else if (this.templateForm.templateType === 2) {
+ return (question.ivrLibaScriptTargetoptionList || []).some(
+ (opt) => opt.isabnormal === 1
+ );
+ }
+ return false;
},
/** 淇濆瓨鍗曚釜棰樼洰閰嶇疆 */
- async saveSingleConfig(question) {
- if (!question.hasChanges) return;
+ async saveSingleConfig(question, skipAbnormalCheck = false) {
+ // 妫�鏌ユ槸鍚︽湁鍙樻洿
+ if (!question.hasChanges && !skipAbnormalCheck) {
+ this.$message.info("褰撳墠閰嶇疆鏃犲彉鍖�");
+ return;
+ }
- const index = this.filteredQuestionList.findIndex(
- (q) => q.id === question.id
- );
- console.log(index, "filteredQuestionList");
+ // 妫�鏌ユ槸鍚︽湁寮傚父閫夐」
+ if (!skipAbnormalCheck && !this.checkHasAbnormalOptions(question)) {
+ this.$confirm(
+ "璇ラ鐩病鏈夎缃紓甯搁�夐」锛屽繀椤诲厛閰嶇疆寮傚父閫夐」鎵嶈兘淇濆瓨銆傛槸鍚︾珛鍗抽厤缃紵",
+ "鎻愮ず",
+ {
+ confirmButtonText: "鍘婚厤缃�",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ )
+ .then(() => {
+ this.openOptionDialog(question);
+ })
+ .catch(() => {});
+ return;
+ }
+ const index = this.questionList.findIndex((q) => q.id === question.id);
if (index === -1) return;
const formRef = this.$refs.configForm && this.$refs.configForm[index];
if (!formRef) return;
- const valid = await formRef.validate();
- if (!valid) {
+ // 楠岃瘉琛ㄥ崟
+ try {
+ await formRef.validate();
+ } catch (error) {
this.$message.warning("璇峰厛瀹屾垚蹇呭~椤�");
return;
}
@@ -1339,6 +1374,18 @@
reportDeptName: reportDeptNames.join(","),
};
+ // 濡傛灉闇�瑕侊紝涔熸洿鏂伴�夐」鏁版嵁
+ if (question.hasChanges && this.templateForm.templateType === 1) {
+ questions[questionIndex].svyLibTemplateTargetoptions =
+ question.svyLibTemplateTargetoptions || [];
+ } else if (
+ question.hasChanges &&
+ this.templateForm.templateType === 2
+ ) {
+ questions[questionIndex].ivrLibaScriptTargetoptionList =
+ question.ivrLibaScriptTargetoptionList || [];
+ }
+
// 鏇存柊妯℃澘
updatedTemplateDetail[questionsField] = questions;
@@ -1375,7 +1422,6 @@
}
},
- /** 澶勭悊淇濆瓨鎴愬姛 */
/** 澶勭悊淇濆瓨鎴愬姛 */
handleSaveSuccess(question) {
// 鍚屾椂鏇存柊棰樼洰椤跺眰瀛楁
@@ -1450,6 +1496,36 @@
async handleBatchSave() {
if (!this.hasChanges || this.batchSaving) return;
+ // 鑾峰彇鏈夊彉鏇寸殑棰樼洰
+ const changedQuestions = this.questionList.filter((q) => q.hasChanges);
+ if (changedQuestions.length === 0) {
+ this.$message.info("娌℃湁闇�瑕佷繚瀛樼殑閰嶇疆鍙樻洿");
+ return;
+ }
+
+ // 妫�鏌ユ槸鍚︽湁棰樼洰缂哄皯寮傚父閫夐」
+ const questionsWithoutAbnormal = changedQuestions.filter(
+ (q) => !this.checkHasAbnormalOptions(q)
+ );
+
+ if (questionsWithoutAbnormal.length > 0) {
+ this.$confirm(
+ `鏈� ${questionsWithoutAbnormal.length} 涓鐩病鏈夎缃紓甯搁�夐」锛屽繀椤婚厤缃紓甯搁�夐」鍚庢墠鑳戒繚瀛樸�傛槸鍚﹀厛鍘婚厤缃紵`,
+ "鎻愮ず",
+ {
+ confirmButtonText: "鍘婚厤缃�",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ )
+ .then(() => {
+ // 鎵撳紑绗竴涓病鏈夊紓甯搁�夐」鐨勯鐩殑閰嶇疆瀵硅瘽妗�
+ this.openOptionDialog(questionsWithoutAbnormal[0]);
+ })
+ .catch(() => {});
+ return;
+ }
+
this.$confirm("纭畾瑕佷繚瀛樻墍鏈変慨鏀硅繃鐨勯厤缃悧锛�", "鎵归噺淇濆瓨", {
confirmButtonText: "纭畾",
cancelButtonText: "鍙栨秷",
@@ -1458,24 +1534,20 @@
.then(async () => {
this.batchSaving = true;
- const changedQuestions = this.questionList.filter(
- (q) => q.hasChanges
- );
const results = [];
-
for (const question of changedQuestions) {
try {
- await this.saveSingleConfig(question);
+ // 璺宠繃寮傚父妫�鏌ワ紝鍥犱负鍦ㄤ笂闈㈠凡缁忔鏌ヨ繃浜�
+ await this.saveSingleConfig(question, true);
results.push({
id: question.id,
- success:
- !question.hasChanges &&
- question.saveStatus?.type === "success",
+ success: !question.hasChanges,
});
} catch (error) {
results.push({
id: question.id,
success: false,
+ error: error.message,
});
}
}
@@ -1492,6 +1564,11 @@
this.$message.warning(
`鎴愬姛淇濆瓨 ${successCount} 涓紝澶辫触 ${failCount} 涓猔
);
+ // 鍙互鏄剧ず鍏蜂綋鍝簺澶辫触浜�
+ const failedQuestions = results
+ .filter((r) => !r.success)
+ .map((r) => r.id);
+ console.error("淇濆瓨澶辫触鐨勯鐩甀D:", failedQuestions);
}
})
.catch(() => {
@@ -1505,39 +1582,38 @@
this.previewAnswer = "";
this.previewVisible = true;
},
- /** 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」 */
- checkHasAbnormalOptions(question) {
- if (this.templateForm.templateType === 1) {
- return (question.svyLibTemplateTargetoptions || []).some(
- (opt) => opt.isabnormal === 1
- );
- } else if (this.templateForm.templateType === 2) {
- return (question.ivrLibaScriptTargetoptionList || []).some(
- (opt) => opt.isabnormal === 1
- );
- }
- return false;
- },
- /** 鎵撳紑閫夐」绠$悊瀵硅瘽妗� */
+ /** 淇敼閫夐」绠$悊瀵硅瘽妗嗙殑鎵撳紑鏂规硶锛屼繚瀛樺師濮嬮�夐」 */
openOptionDialog(question) {
this.editingQuestion = question;
+
+ // 淇濆瓨鍘熷閫夐」鐨勫揩鐓�
+ if (this.templateForm.templateType === 1) {
+ this.editingQuestion.originalOptions = JSON.parse(
+ JSON.stringify(question.svyLibTemplateTargetoptions || [])
+ );
+ } else if (this.templateForm.templateType === 2) {
+ this.editingQuestion.originalOptions = JSON.parse(
+ JSON.stringify(question.ivrLibaScriptTargetoptionList || [])
+ );
+ }
// 澶嶅埗閫夐」鏁版嵁
if (this.templateForm.templateType === 1) {
this.currentOptions = JSON.parse(
JSON.stringify(question.svyLibTemplateTargetoptions || [])
- ).map((opt) => ({
+ ).map((opt, index) => ({
...opt,
- id: opt.id,
+ id: opt.id || `temp_${Date.now()}_${index}`,
targetvalue: opt.optioncontent || "",
isabnormal: opt.isabnormal || 0,
}));
} else if (this.templateForm.templateType === 2) {
this.currentOptions = JSON.parse(
JSON.stringify(question.ivrLibaScriptTargetoptionList || [])
- ).map((opt) => ({
+ ).map((opt, index) => ({
...opt,
+ id: opt.id || `temp_${Date.now()}_${index}`,
targetvalue: opt.targetvalue || "",
isabnormal: opt.isabnormal || 0,
}));
@@ -1549,7 +1625,7 @@
/** 娣诲姞鏂伴�夐」 */
addNewOption() {
this.currentOptions.push({
- id: Date.now(), // 涓存椂ID
+ id: `temp_${Date.now()}_${this.currentOptions.length}`,
targetvalue: "",
isabnormal: 0,
isNew: true,
@@ -1558,16 +1634,25 @@
/** 鍒犻櫎閫夐」 */
removeOption(index) {
- this.currentOptions.splice(index, 1);
+ this.$confirm("纭畾瑕佸垹闄よ繖涓�夐」鍚楋紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ this.currentOptions.splice(index, 1);
+ })
+ .catch(() => {});
},
/** 淇濆瓨閫夐」閰嶇疆 */
async saveOptions() {
try {
// 楠岃瘉蹇呭~椤�
- for (const option of this.currentOptions) {
+ for (let i = 0; i < this.currentOptions.length; i++) {
+ const option = this.currentOptions[i];
if (!option.targetvalue || option.targetvalue.trim() === "") {
- this.$message.warning("璇峰~鍐欐墍鏈夐�夐」鍐呭");
+ this.$message.warning(`绗� ${i + 1} 涓�夐」鍐呭涓嶈兘涓虹┖`);
return;
}
}
@@ -1582,6 +1667,27 @@
return;
}
+ // 鍒ゆ柇閫夐」鏄惁鍙戠敓鍙樺寲
+ let isOptionsChanged = false;
+
+ if (this.templateForm.templateType === 1) {
+ const originalOptions =
+ this.editingQuestion.svyLibTemplateTargetoptions || [];
+ isOptionsChanged = this.checkOptionsChanged(
+ originalOptions,
+ this.currentOptions,
+ "questionnaire"
+ );
+ } else if (this.templateForm.templateType === 2) {
+ const originalOptions =
+ this.editingQuestion.ivrLibaScriptTargetoptionList || [];
+ isOptionsChanged = this.checkOptionsChanged(
+ originalOptions,
+ this.currentOptions,
+ "voice"
+ );
+ }
+
// 淇濆瓨閫昏緫 - 鏇存柊棰樼洰瀵硅薄鐨勯�夐」鏁版嵁
if (this.templateForm.templateType === 1) {
this.editingQuestion.svyLibTemplateTargetoptions =
@@ -1589,14 +1695,24 @@
...opt,
optioncontent: opt.targetvalue,
isabnormal: opt.isabnormal,
+ // 娓呴櫎涓存椂瀛楁
+ targetvalue: undefined,
+ isNew: undefined,
}));
} else if (this.templateForm.templateType === 2) {
this.editingQuestion.ivrLibaScriptTargetoptionList =
- this.currentOptions;
+ this.currentOptions.map((opt) => ({
+ ...opt,
+ // 娓呴櫎涓存椂瀛楁
+ isNew: undefined,
+ }));
}
- // 瑙﹀彂閰嶇疆鍙樻洿妫�鏌�
- this.handleConfigChange(this.editingQuestion);
+ // 濡傛灉閫夐」鏈夊彉鍖栵紝鍒欒缃鐩负鏈夊彉鏇寸姸鎬�
+ if (isOptionsChanged) {
+ this.editingQuestion.hasChanges = true;
+ this.updateChangedStatus();
+ }
this.$message.success("閫夐」閰嶇疆淇濆瓨鎴愬姛");
this.optionDialogVisible = false;
@@ -1605,126 +1721,39 @@
this.$message.error("淇濆瓨閫夐」澶辫触");
}
},
-
- /** 淇敼淇濆瓨鍗曚釜棰樼洰閰嶇疆鏂规硶锛屾坊鍔犲紓甯搁�夐」妫�鏌� */
- async saveSingleConfig(question) {
- // 妫�鏌ユ槸鍚︽湁寮傚父閫夐」
- if (!this.checkHasAbnormalOptions(question)) {
- this.$confirm("璇ラ鐩病鏈夎缃紓甯搁�夐」锛屾槸鍚﹀厛閰嶇疆閫夐」锛�", "鎻愮ず", {
- confirmButtonText: "鍘婚厤缃�",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- this.openOptionDialog(question);
- })
- .catch(() => {});
- return;
+ /** 妫�鏌ラ�夐」鏄惁鍙戠敓鍙樺寲 */
+ checkOptionsChanged(originalOptions, newOptions, templateType) {
+ // 濡傛灉鏁伴噺涓嶅悓锛屽垯涓�瀹氬彉鍖栦簡
+ if (originalOptions.length !== newOptions.length) {
+ return true;
}
- // 鍘熸湁鐨勪繚瀛橀�昏緫...
- if (!question.hasChanges) return;
+ // 姣旇緝姣忎釜閫夐」鐨勫唴瀹瑰拰寮傚父鐘舵��
+ for (let i = 0; i < originalOptions.length; i++) {
+ const original = originalOptions[i];
+ const current = newOptions[i];
- const index = this.filteredQuestionList.findIndex(
- (q) => q.id === question.id
- );
-
- if (index === -1) return;
-
- const formRef = this.$refs.configForm && this.$refs.configForm[index];
- if (!formRef) return;
-
- const valid = await formRef.validate();
- if (!valid) {
- this.$message.warning("璇峰厛瀹屾垚蹇呭~椤�");
- return;
- }
-
- // 缁х画鍘熸湁鐨勪繚瀛橀�昏緫...
- question.saving = true;
- question.saveStatus = null;
-
- try {
- // ... 鍘熸湁鐨勪繚瀛橀�昏緫涓嶅彉
- } catch (error) {
- // ... 閿欒澶勭悊涓嶅彉
- } finally {
- question.saving = false;
- }
- },
-
- /** 鎵归噺淇濆瓨鏃朵篃瑕佹鏌� */
- async handleBatchSave() {
- if (!this.hasChanges || this.batchSaving) return;
-
- // 妫�鏌ユ墍鏈夋湁鍙樻洿鐨勯鐩槸鍚﹂兘鏈夊紓甯搁�夐」
- const changedQuestions = this.questionList.filter((q) => q.hasChanges);
- const questionsWithoutAbnormal = changedQuestions.filter(
- (q) => !this.checkHasAbnormalOptions(q)
- );
-
- if (questionsWithoutAbnormal.length > 0) {
- this.$confirm(
- `鏈� ${questionsWithoutAbnormal.length} 涓鐩病鏈夎缃紓甯搁�夐」锛岃鍏堥厤缃�夐」銆傛槸鍚︾户缁紵`,
- "鎻愮ず",
- {
- confirmButtonText: "缁х画",
- cancelButtonText: "鍘婚厤缃�",
- type: "warning",
+ if (templateType === "questionnaire") {
+ // 闂嵎妯℃澘姣旇緝
+ if (
+ original.optioncontent !== current.targetvalue ||
+ original.isabnormal !== current.isabnormal
+ ) {
+ return true;
}
- )
- .then(() => {
- // 缁х画鎵ц鎵归噺淇濆瓨
- this.executeBatchSave(changedQuestions);
- })
- .catch(() => {
- // 鍙互鍦ㄨ繖閲岃烦杞埌绗竴涓病鏈夊紓甯搁�夐」鐨勯鐩�
- if (questionsWithoutAbnormal.length > 0) {
- this.openOptionDialog(questionsWithoutAbnormal[0]);
- }
- });
- } else {
- this.executeBatchSave(changedQuestions);
- }
- },
-
- /** 鎵ц鎵归噺淇濆瓨 */
- async executeBatchSave(changedQuestions) {
- this.$confirm("纭畾瑕佷繚瀛樻墍鏈変慨鏀硅繃鐨勯厤缃悧锛�", "鎵归噺淇濆瓨", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(async () => {
- this.batchSaving = true;
-
- const results = [];
- for (const question of changedQuestions) {
- try {
- // 杩欓噷璋冪敤淇敼鍚庣殑saveSingleConfig鏂规硶
- await this.saveSingleConfig(question);
- results.push({
- id: question.id,
- success:
- !question.hasChanges &&
- question.saveStatus?.type === "success",
- });
- } catch (error) {
- results.push({
- id: question.id,
- success: false,
- });
- }
+ } else if (templateType === "voice") {
+ // 璇煶妯℃澘姣旇緝
+ if (
+ original.targetvalue !== current.targetvalue ||
+ original.isabnormal !== current.isabnormal
+ ) {
+ return true;
}
+ }
+ }
- this.batchSaving = false;
- // ... 鍚庣画澶勭悊涓嶅彉
- })
- .catch(() => {
- this.batchSaving = false;
- });
+ return false;
},
-
/** 鑾峰彇寮傚父閫夐」缁熻 */
getAbnormalStats(question) {
if (this.templateForm.templateType === 1) {
@@ -1746,6 +1775,7 @@
}
return { total: 0, abnormal: 0, warning: 0, normal: 0 };
},
+
/** 鎼滅储 */
handleQuery() {
// 浠呯瓫閫夋樉绀猴紝涓嶉渶瑕侀噸鏂板姞杞�
diff --git a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
index c1d3a0a..2d78fdf 100644
--- a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
+++ b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
@@ -414,7 +414,7 @@
</template>
</el-table-column>
- <el-table-column
+ <!-- <el-table-column
label="瓒嬪娍"
prop="trend"
align="center"
@@ -446,7 +446,7 @@
}}</span>
</div>
</template>
- </el-table-column>
+ </el-table-column> -->
<el-table-column
label="鎿嶄綔"
@@ -790,11 +790,11 @@
Object.entries(apiData.rows).forEach(([typeName, typeStat]) => {
const sendCount = typeStat.subidAll || 0;
const receiveCount = typeStat.fillCountAll || 0;
- const recoveryRate = typeStat.receiveRate || 0;
+ const recoveryRate = typeStat.receiveRate.toFixed(2) || 0;
chartData.push({
name: typeName,
- value: recoveryRate * 100, // 杞崲涓虹櫨鍒嗘瘮
+ value: (recoveryRate * 100).toFixed(2), // 杞崲涓虹櫨鍒嗘瘮
sendCount: sendCount,
receiveCount: receiveCount,
averageScore: typeStat.averageScore || 0,
@@ -914,7 +914,9 @@
const response = await satisfactionGraph(params);
if (response.code === 200) {
- this.processTypeDetailData(response.data);
+ this.processTypeDetailData(response);
+ console.log(11);
+
} else {
this.$message.error(response.msg || "鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
const mockData = await this.generateMockTypeDetail();
@@ -944,7 +946,7 @@
Object.entries(apiData.rows).forEach(([typeName, typeStat], index) => {
const sendCount = typeStat.subidAll || 0;
const receiveCount = typeStat.fillCountAll || 0;
- const recoveryRate = typeStat.receiveRate || 0;
+ const recoveryRate = typeStat.receiveRate.toFixed(2) || 0;
const averageScore = typeStat.averageScore || 0;
typeDetail.push({
@@ -963,6 +965,8 @@
});
this.typeDetailData = typeDetail;
+ console.log(this.typeDetailData,'this.typeDetailData');
+
this.calculateTypeSummary(typeDetail);
},
@@ -972,7 +976,7 @@
if (score >= 4.0) return "鑹ソ";
if (score >= 3.0) return "涓�鑸�";
if (score >= 2.0) return "杈冨樊";
- return "宸�";
+ return "鏈煡";
},
// 鑾峰彇瓒嬪娍
@@ -1041,24 +1045,24 @@
// 娓叉煋鍥捐〃
renderChart(chartData) {
if (!this.barChart) return;
- if (!chartData || chartData.length === 0) {
- const emptyOption = {
- title: {
- text: "鏆傛棤鏁版嵁",
- left: "center",
- top: "center",
- textStyle: {
- color: "#999",
- fontSize: 16,
- fontWeight: "normal"
- }
- },
- xAxis: { show: false },
- yAxis: { show: false }
- };
- this.barChart.setOption(emptyOption);
- return;
- }
+ if (!chartData || chartData.length === 0) {
+ const emptyOption = {
+ title: {
+ text: "鏆傛棤鏁版嵁",
+ left: "center",
+ top: "center",
+ textStyle: {
+ color: "#999",
+ fontSize: 16,
+ fontWeight: "normal",
+ },
+ },
+ xAxis: { show: false },
+ yAxis: { show: false },
+ };
+ this.barChart.setOption(emptyOption);
+ return;
+ }
const option = {
title: {
text: "",
@@ -1079,7 +1083,7 @@
<span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:${
data.color
};margin-right:5px;"></span>
- 濉姤姣斾緥: <strong>${data.value.toFixed(1)}%</strong>
+ 濉姤姣斾緥: <strong>${data.value}%</strong>
</div>
<div style="margin: 2px 0;">
<span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
@@ -1437,12 +1441,12 @@
// 鏍煎紡鍖栫櫨鍒嗘瘮
formatPercent(value) {
- if (value === null || value === undefined) return "-";
- const num = parseFloat(value);
- if (isNaN(num)) return "-";
- // 濡傛灉鍊煎皬浜�1锛岃涓烘槸灏忔暟姣斾緥锛岄渶瑕佷箻浠�100
- const percentValue = num < 1 ? num * 100 : num;
- return `${percentValue.toFixed(2)}%`;
+ if (value === null || value === undefined) return "-";
+ const num = parseFloat(value);
+ if (isNaN(num)) return "-";
+ // 濡傛灉鍊煎皬浜�1锛岃涓烘槸灏忔暟姣斾緥锛岄渶瑕佷箻浠�100
+ const percentValue = num < 1 ? num * 100 : num;
+ return `${percentValue.toFixed(2)}%`;
},
// 鑾峰彇鍥炴敹鐜囨牱寮忕被
@@ -1459,7 +1463,7 @@
鑹ソ: "primary",
涓�鑸�: "warning",
杈冨樊: "danger",
- 宸�: "info",
+ 鏈煡: "info",
};
return levelMap[level] || "info";
},
diff --git a/src/views/followvisit/HistoricalFollow/index.vue b/src/views/followvisit/HistoricalFollow/index.vue
index 4b5b99a..3abdee2 100644
--- a/src/views/followvisit/HistoricalFollow/index.vue
+++ b/src/views/followvisit/HistoricalFollow/index.vue
@@ -662,7 +662,7 @@
value: 4,
label: "涓嶆墽琛�",
},
- {
+ {
value: 5,
label: "鍙戦�佸け璐�",
},
@@ -670,7 +670,7 @@
value: 6,
label: "宸插畬鎴�",
},
- {
+ {
value: 7,
label: "瓒呮椂",
},
@@ -1147,7 +1147,7 @@
/** 瀵煎嚭鎸夐挳鎿嶄綔 */
handleExport() {
console.log(this.topqueryParams);
-
+ this.topqueryParams.pageSize = null;
this.download(
// "smartor/serviceSubtask/export",
"smartor/serviceSubtask/getSubtaskByDiagnameExport",
diff --git a/src/views/followvisit/again/index.vue b/src/views/followvisit/again/index.vue
index 5a959d1..4911da7 100644
--- a/src/views/followvisit/again/index.vue
+++ b/src/views/followvisit/again/index.vue
@@ -180,7 +180,7 @@
<el-col :span="1.5">
<el-button
type="primary"
- icon="el-icon-plus"
+ icon="el-icon-plus"
size="medium"
@click="handleAdd"
>鏂板</el-button
@@ -289,6 +289,15 @@
</template>
</el-table-column>
<el-table-column
+ label="璇婃柇鍚嶇О"
+ align="center"
+ key="leavediagname"
+ prop="leavediagname"
+ width="120"
+ :show-overflow-tooltip="true"
+ >
+ </el-table-column>
+ <el-table-column
label="浠诲姟鐘舵��"
align="center"
key="sendstate"
@@ -325,15 +334,13 @@
>鍙戦�佸け璐�</el-tag
>
</div>
- <div v-if="scope.row.sendstate == 6">
+ <div v-if="scope.row.sendstate == 6">
<el-tag type="success" :disable-transitions="false"
>宸插畬鎴�</el-tag
>
</div>
<div v-if="scope.row.sendstate == 7">
- <el-tag type="danger" :disable-transitions="false"
- >瓒呮椂</el-tag
- >
+ <el-tag type="danger" :disable-transitions="false">瓒呮椂</el-tag>
</div>
</el-tooltip>
</template>
@@ -472,15 +479,6 @@
>
</el-table-column>
- <el-table-column
- label="璇婃柇鍚嶇О"
- align="center"
- key="leavediagname"
- prop="leavediagname"
- width="120"
- :show-overflow-tooltip="true"
- >
- </el-table-column>
<el-table-column
label="闅忚浜哄憳"
align="center"
@@ -649,7 +647,7 @@
</el-form-item>
</el-col>
</el-row>
-<el-row >
+ <el-row>
<el-col :span="8">
<el-form-item label="杩囨护鍖荤敓" width="100" prop="filterDrname">
<el-input
@@ -1035,7 +1033,7 @@
value: 4,
label: "涓嶆墽琛�",
},
- {
+ {
value: 5,
label: "鍙戦�佸け璐�",
},
@@ -1043,7 +1041,7 @@
value: 6,
label: "宸插畬鎴�",
},
- {
+ {
value: 7,
label: "瓒呮椂",
},
@@ -1214,7 +1212,7 @@
});
},
affiliation() {
- this.topqueryParams.managementDoctorCode= store.getters.hisUserId;
+ this.topqueryParams.managementDoctorCode = store.getters.hisUserId;
this.getList(1);
},
@@ -1488,7 +1486,7 @@
.then((response) => {
console.log(response);
})
- .then(() => {
+ .then(() => {
this.getList(1);
this.$modal.msgSuccess("鎮h�呰繃婊ゆ垚鍔�");
});
@@ -1557,11 +1555,11 @@
},
// 璺宠浆璇︽儏椤�
Seedetails(row) {
- let type = "";
+ let type = "";
console.log(row, "rwo");
- if (row.type == 1) {
- type = 1;
- }
+ if (row.type == 1) {
+ type = 1;
+ }
this.$router.push({
path: "/followvisit/record/detailpage/",
query: {
@@ -1787,11 +1785,11 @@
}
}
::v-deep.leftvlue .el-card__body {
- background: #F2F8FF;
- color: #324A9B;
+ background: #f2f8ff;
+ color: #324a9b;
}
::v-deep.leftvlue .el-card__body:hover {
- background: #3664D9;
+ background: #3664d9;
color: #fff;
cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
}
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 955da10..65aeb31 100644
--- a/src/views/followvisit/record/detailpage/index.vue
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -2286,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 == "";
@@ -2373,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 = ""; // 娓呴櫎闄勫姞淇℃伅
// }
@@ -2443,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 5cad6ba..911156a 100644
--- a/src/views/sfstatistics/percentage/index.vue
+++ b/src/views/sfstatistics/percentage/index.vue
@@ -1,3103 +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-col :span="19">
- <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-col>
- </el-form>
- <div class="your-table-container">
- <el-table
- ref="exportTable"
- id="exportTableid"
- v-loading="loading"
- :data="userList"
- :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"
- >
- <!-- <template slot-scope="scope">
- <span
- >{{
- (Number(scope.row.followUpRate) * 100).toFixed(2)
- }}%</span
- >
- </template> -->
- </el-table-column>
- <el-table-column
- 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-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"
- >
- <!-- <template slot-scope="scope">
- <span
- >{{
- (Number(scope.row.FollowUpRateAgain) * 100).toFixed(2)
- }}%</span
- >
- </template> -->
- </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="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"
- >
- <!-- <template slot-scope="scope">
- <span
- >{{
- (Number(scope.row.followUpRate) * 100).toFixed(2)
- }}%</span
- >
- </template> -->
- </el-table-column>
- <el-table-column
- 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 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"
- >
- <!-- <template slot-scope="scope">
- <span
- >{{
- (Number(scope.row.FollowUpRateAgain) * 100).toFixed(2)
- }}%</span
- >
- </template> -->
- </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-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>
-
- <!-- <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";
-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);
- },
- },
-];
+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'
+
+
export default {
- name: "Percentage",
- dicts: ["sys_normal_disable", "sys_user_sex"],
- components: { Treeselect },
+ name: 'FollowUpStatistics',
+ components: {
+ FirstFollowUp,
+ SecondFollowUp,
+ ContinuedCare,
+ ChartDialog,
+ DetailDialog,
+ TimelyRateDialog
+ },
data() {
return {
- topactiveName: "Local", //椤堕儴閫夋嫨
- activeName: "first", //渚ц竟閫夋嫨
- orgname: "",
- expands: [],
- infotitlelist: [],
- currentDisplayList: [], // 褰撳墠鏄剧ず鐨勬暟鎹�
- loadIndex: 0, // 褰撳墠宸插姞杞界殑鏁版嵁绱㈠紩
- pageSize: 100, // 姣忔鍔犺浇鐨勬暟鎹噺
- isLoading: false, // 闃叉婊氬姩鏃堕噸澶嶅姞杞�
- // 閬僵灞�
- loading: false,
- Seedloading: false,
- chartDialogVisible: false,
- infotitleVisible: false,
- searchName: "", // 鎼滅储鍏抽敭璇�
- infotitloading: false,
- infotitle: "",
- pieChart: null,
- barLineChart: null,
- // 閫変腑鏁扮粍
- ids: [],
- // 闈炲崟涓鐢�
- single: true,
- // 闈炲涓鐢�
- multiple: true,
- // 鏄剧ず鎼滅储鏉′欢
- showSearch: true,
- idds: "", //鍒嗙被id
- // 鎬绘潯鏁�
- 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: "",
- },
- // 鏍囩琛ㄦ牸鏁版嵁
- userList: [],
- // 寮瑰嚭灞傛爣棰�
- 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: [], // 榛樿閫変腑鍏ㄩ儴绉戝
+ 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.getList();
- this.checkboxlist = store.getters.checkboxlist;
- this.orgname = localStorage.getItem("orgname");
+ this.getDeptTree()
},
-
methods: {
- /** 鏌ヨ鏍囩鍒楄〃 */
- getList() {
- // 澶勭悊鏌ヨ鍙傛暟
- const params = {
- ...this.queryParams,
- // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
- leavehospitaldistrictcodes:
- this.queryParams.leavehospitaldistrictcodes.includes("all")
- ? this.allWardCodes
- : this.queryParams.leavehospitaldistrictcodes,
- deptcodes: this.queryParams.deptcodes.includes("all")
- ? this.allDeptCodes
- : this.queryParams.deptcodes,
- };
- this.loading = true;
- // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
- delete params.leavehospitaldistrictcodes.all;
- delete params.deptcodes.all;
- getSfStatistics(params).then((response) => {
- this.loading = false;
-
- this.total = response.total;
- // this.userList = response.data;
- this.userList = this.customSort(response.data);
- });
- },
- 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",
- };
-
- // 绉婚櫎鍙兘瀛樺湪鐨�"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);
- })
- .then(() => {
- this.$modal.msgSuccess(text + "鎴愬姛");
- })
- .catch(function () {
- row.isupload = row.isupload === "0" ? "1" : "0";
- });
- },
- /** 鎼滅储鎸夐挳鎿嶄綔 */
- 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 = [];
- }
- console.log(this.queryParams.dateRange);
-
- this.queryParams.startTime = this.parseTime(
- this.queryParams.dateRange[0]
- );
- this.queryParams.endTime = this.parseTime(this.queryParams.dateRange[1]);
- this.getList();
- },
- /** 閲嶇疆鎸夐挳鎿嶄綔 */
- 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(() => {});
- },
- // 瀵煎嚭鏂规硶
- // 鏇挎崲鎮ㄥ師鏉ョ殑 exportTable 鏂规硶
- async exportTable() {
- try {
- // 1. 鑾峰彇骞舵牸寮忓寲鏃ユ湡鑼冨洿
- let dateRangeString = ""; // 鐢ㄤ簬鏂囦欢鍚�
- let sheetNameSuffix = ""; // 鐢ㄤ簬宸ヤ綔琛ㄥ悕
-
- // 妫�鏌ユ槸鍚﹀瓨鍦ㄩ�変腑鐨勬棩鏈熻寖鍥�
- if (
- this.queryParams.dateRange &&
- this.queryParams.dateRange.length === 2
- ) {
- const startDateStr = this.queryParams.dateRange[0]; // 寮�濮嬫棩鏈熷瓧绗︿覆锛屼緥濡� "2026-01-01 00:00:00"
- const endDateStr = this.queryParams.dateRange[1]; // 缁撴潫鏃ユ湡瀛楃涓�
-
- // 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD锛堝幓鎺夋椂闂撮儴鍒嗭級
- const formatDateForDisplay = (dateTimeStr) => {
- return dateTimeStr.split(" ")[0]; // 鍙栫┖鏍煎墠鐨勯儴鍒嗭紝鍗� "YYYY-MM-DD"
- };
-
- 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. 鍔ㄦ�佹瀯寤烘枃浠跺悕鍜屽伐浣滆〃鍚�
- const excelName = `鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
- const worksheetName = `闅忚缁熻_${sheetNameSuffix}`; // 宸ヤ綔琛ㄥ悕涓嶈兘瓒呰繃31涓瓧绗2](@ref)
- // 鍒涘缓鏂扮殑宸ヤ綔绨垮拰宸ヤ綔琛�
- const workbook = new ExcelJS.Workbook();
- const worksheet = workbook.addWorksheet(worksheetName); // 浣跨敤鍔ㄦ�佸伐浣滆〃鍚�
- // 瀹氫箟鏍峰紡锛堟柊澧炴�绘爣棰樻牱寮忥級
- const titleStyle = {
- font: {
- name: "寰蒋闆呴粦",
- size: 16,
- bold: true,
- color: { argb: "FF000000" },
- },
- fill: {
- type: "pattern",
- pattern: "solid",
- fgColor: { argb: "FFE6F3FF" },
- },
- alignment: {
- vertical: "middle",
- horizontal: "center",
- wrapText: true,
- },
- border: {
- top: { style: "thin", color: { argb: "FFD0D0D0" } },
- left: { style: "thin", color: { argb: "FFD0D0D0" } },
- bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
- right: { style: "thin", color: { argb: "FFD0D0D0" } },
- },
- };
- // 瀹氫箟鏍峰紡
- const headerStyle = {
- font: {
- name: "寰蒋闆呴粦",
- size: 11,
- bold: true,
- color: { argb: "FF000000" },
- },
- fill: {
- type: "pattern",
- pattern: "solid",
- fgColor: { argb: "FFF5F7FA" },
- },
- alignment: {
- vertical: "middle",
- horizontal: "center",
- wrapText: true,
- },
- border: {
- top: { style: "thin", color: { argb: "FFD0D0D0" } },
- left: { style: "thin", color: { argb: "FFD0D0D0" } },
- bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
- right: { style: "thin", color: { argb: "FFD0D0D0" } },
- },
- };
-
- const cellStyle = {
- font: {
- name: "瀹嬩綋",
- size: 10,
- color: { argb: "FF000000" },
- },
- alignment: {
- vertical: "middle",
- horizontal: "center",
- },
- border: {
- top: { style: "thin", color: { argb: "FFD0D0D0" } },
- left: { style: "thin", color: { argb: "FFD0D0D0" } },
- bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
- right: { style: "thin", color: { argb: "FFD0D0D0" } },
- },
- };
-
- 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, 23); // 鍚堝苟A1鍒癢1鐨勬墍鏈夊垪[1,4](@ref)
- const titleCell = worksheet.getCell(1, 1);
- titleCell.value = `${sheetNameSuffix}鍑洪櫌闅忚缁熻琛╜; // 浣跨敤鏂囦欢鍚嶄綔涓烘�绘爣棰�
- titleCell.style = titleStyle;
- worksheet.getRow(1).height = 35; // 璁剧疆鎬绘爣棰樿楂�
- // 1. 棣栧厛锛屽垱寤哄苟璁剧疆绗簩琛岋紙瀛愯〃澶达級鐨勬墍鏈夊崟鍏冩牸
- const secondRowHeaders = [
- "", // A2 灞曞紑鍒楀崰浣嶏紙鍏跺�煎皢鐢辩涓�琛屽悎骞跺悗鐨勪富鍗曞厓鏍煎喅瀹氾級
- "鍑洪櫌鐥呭尯",
- "绉戝",
- "鍑洪櫌浜烘",
- "鏃犻渶闅忚浜烘",
- "搴旈殢璁夸汉娆�", // B2 to F2
- // 棣栨鍑洪櫌闅忚瀛愯〃澶�
- "闇�闅忚",
- "寰呴殢璁�",
- "闅忚鎴愬姛",
- "闅忚澶辫触",
- "闅忚鐜�",
- "鍙婃椂鐜�",
- "浜哄伐",
- "鐭俊",
- "寰俊",
- // 鍐嶆鍑洪櫌闅忚瀛愯〃澶�
- "闇�闅忚",
- "寰呴殢璁�",
- "闅忚鎴愬姛",
- "闅忚澶辫触",
- "闅忚鐜�",
- "浜哄伐",
- "鐭俊",
- "寰俊",
- ];
-
- // 娣诲姞绗簩琛岋紙鍘熺涓�琛屼笅绉伙級
- secondRowHeaders.forEach((header, index) => {
- const cell = worksheet.getCell(3, index + 1); // 鏀逛负绗�3琛�
- cell.value = header;
- cell.style = headerStyle;
- });
-
- // 3. 璋冩暣鍘熷悎骞跺崟鍏冩牸浣嶇疆锛堝師绗�1琛屽悎骞跺崟鍏冩牸涓嬬Щ鍒扮2琛岋級
- // 鍚堝苟 A2:A3
- worksheet.mergeCells(2, 1, 3, 1);
- worksheet.getCell(2, 1).value = "";
- worksheet.getCell(2, 1).style = headerStyle;
-
- // 鍚堝苟 B2:B3
- worksheet.mergeCells(2, 2, 3, 2);
- worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
- worksheet.getCell(2, 2).style = headerStyle;
-
- // 鍚堝苟 C2:C3
- worksheet.mergeCells(2, 3, 3, 3);
- worksheet.getCell(2, 3).value = "绉戝";
- worksheet.getCell(2, 3).style = headerStyle;
-
- // 鍚堝苟 D2:D3
- worksheet.mergeCells(2, 4, 3, 4);
- worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
- worksheet.getCell(2, 4).style = headerStyle;
-
- // 鍚堝苟 E2:E3
- worksheet.mergeCells(2, 5, 3, 5);
- worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
- worksheet.getCell(2, 5).style = headerStyle;
-
- // 鍚堝苟 F2:F3
- worksheet.mergeCells(2, 6, 3, 6);
- worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
- worksheet.getCell(2, 6).style = headerStyle;
-
- // 4. 璋冩暣妯悜鍚堝苟鏍囬浣嶇疆锛堜笅绉诲埌绗�2琛岋級
- // 棣栨鍑洪櫌闅忚锛堝悎骞禛2:O2锛�
- worksheet.mergeCells(2, 7, 2, 15); // G2:O2
- worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚";
- worksheet.getCell(2, 7).style = headerStyle;
-
- // 鍐嶆鍑洪櫌闅忚锛堝悎骞禤2:W2锛�
- worksheet.mergeCells(2, 16, 2, 23); // P2:W2
- worksheet.getCell(2, 16).value = "鍐嶆鍑洪櫌闅忚";
- worksheet.getCell(2, 16).style = headerStyle;
-
- // 5. 璁剧疆琛岄珮
- worksheet.getRow(1).height = 35; // 鎬绘爣棰樿楂�
- worksheet.getRow(2).height = 28; // 鍘熺涓�琛屼笅绉�
- worksheet.getRow(3).height = 25; // 鍘熺浜岃涓嬬Щ
-
- // 6. 娣诲姞鏁版嵁琛岋紙娉ㄦ剰琛岀储寮曢渶瑕�+1锛屽洜涓轰笂闈㈡彃鍏ヤ簡涓�琛岋級
- this.userList.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,
- // 鍐嶆鍑洪櫌闅忚鏁版嵁
- 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
- ); // 浠庣4琛屽紑濮嬫坊鍔犳暟鎹紙鍘熺3琛岋級
-
- // 搴旂敤鏁版嵁琛屾牱寮�
- dataRow.eachCell((cell) => {
- cell.style = cellStyle;
- });
- dataRow.height = 24;
- });
-
- // 娣诲姞鍚堣琛�
- const summaries = this.getSummaries({
- columns: [
- { property: "" },
- { property: "leavehospitaldistrictname" },
- { property: "deptname" },
- { property: "dischargeCount" },
- { property: "nonFollowUp" },
- { property: "followUpNeeded" },
- { property: "needFollowUp" },
- { property: "pendingFollowUp" },
- { property: "followUpSuccess" },
- { property: "followUpFail" },
- { property: "followUpRate" },
- { property: "rate" },
- { property: "manual" },
- { property: "sms" },
- { property: "weChat" },
- { property: "needFollowUpAgain" },
- { property: "pendingFollowUpAgain" },
- { property: "followUpSuccessAgain" },
- { property: "followUpFailAgain" },
- { property: "followUpRateAgain" },
- { property: "manualAgain" },
- { property: "smsAgain" },
- { property: "weChatAgain" },
- ],
- data: this.userList,
- });
-
- const summaryRow = worksheet.addRow(summaries);
- summaryRow.eachCell((cell, colNumber) => {
- cell.style = summaryStyle;
- // 绗竴鍒楁樉绀�"鍚堣"
- if (colNumber === 1) {
- cell.value = "鍚堣";
+ Voicetype: type
}
- });
- 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 },
- // 鍐嶆鍑洪櫌闅忚鍒�
- { width: 10 },
- { width: 10 },
- { width: 10 },
- { width: 10 },
- { width: 12 },
- { width: 8 },
- { width: 8 },
- { width: 8 },
- ];
-
- // 鐢熸垚骞朵笅杞芥枃浠�
- 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;
- }
+ })
+ }, 300)
},
- // 鏄剧ず鍥捐〃寮圭獥
-
- 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>
-.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 2542f56..1ce99d9 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -37,9 +37,10 @@
[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:8094`,//鐪佺珛鍚屽痉
// target: `http://192.168.100.10:8095`,//鏂板崕
- target:`http://localhost:8095`,
+ // target: `http://192.168.100.10:8098`,//甯備竴
+ // target:`http://localhost:8095`,
// target:`http://35z1t16164.qicp.vip`,
// target: `http://192.168.100.183:8095`,
// target: `http://192.168.101.166:8093`,
diff --git a/xhyy.zip b/xhyy.zip
deleted file mode 100644
index 98caa1f..0000000
--- a/xhyy.zip
+++ /dev/null
Binary files differ
--
Gitblit v1.9.3