| | |
| | | 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, |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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; |
| | | }, |
| | | |
| | | // ä»URLè·åæä»¶å |
| | | 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> |
| | |
| | | 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"> |
| | | è¿åå¼å¸¸å表 |
| | |
| | | > |
| | | <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> |
| | |
| | | :border="true" |
| | | style="width: 100%" |
| | | @selection-change="handleSelectionChange" |
| | | row-key="id" |
| | | class="exception-table" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | |
| | | |
| | | <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>è§£æå¼ï¼</strong>{{ row.matchedtext }} |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | <el-table-column label="æ£è
ä¿¡æ¯" 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.patientName }}</span> |
| | | </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> |
| | | <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.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> |
| | |
| | | |
| | | <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> |
| | | |
| | |
| | | size="small" |
| | | icon="el-icon-edit" |
| | | @click="handleProcess(row)" |
| | | :disabled="row.processStatus === 2" |
| | | :disabled="row.handleFlag === '1'" |
| | | > |
| | | å¤ç |
| | | </el-button> |
| | |
| | | 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"> |
| | | æ¯æä¸ä¼ å¾çãææ¡£çéä»¶ï¼å个æä»¶ä¸è¶
è¿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"> |
| | |
| | | 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> |
| | |
| | | @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 { deptTreeSelect } from "@/api/system/user"; |
| | | |
| | | export default { |
| | | name: "BatchProcess", |
| | | components: { |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | // æ·»å 以䏿°æ® |
| | | // 详æ
å¼¹æ¡ç¸å
³ |
| | | detailDialogVisible: false, |
| | | selectedRecordId: null, |
| | | selectedRecordData: null, |
| | | detailDialogTitle: "å¼å¸¸åé¦è¯¦æ
", |
| | | |
| | | // é³é¢ææ¾ |
| | | audioUrl: "", |
| | | |
| | | // å½åå¤ççå¼å¸¸ID |
| | | currentExceptionId: null, |
| | | |
| | |
| | | |
| | | // è¿æ»¤åæ° |
| | | filterParams: { |
| | | deptId: "", |
| | | status: "", |
| | | todeptcode: "", |
| | | handleFlag: "", |
| | | templateType: "", |
| | | scriptid: null, |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }, |
| | |
| | | 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: [], |
| | |
| | | // å¤çå¯¹è¯æ¡ |
| | | 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() { |
| | | // ä»è·¯ç±åæ°è·åé®é¢ID |
| | | if (this.$route.query.questionId) { |
| | | this.filterParams.scriptid = this.$route.query.questionId || null; |
| | | this.filterParams.scriptids = null; |
| | | } else if (this.$route.query.questionIds) { |
| | | this.filterParams.scriptids = this.$route.query.questionIds; |
| | | 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; |
| | | }, |
| | | // è§£ææ£è
æè¿°ä¿¡æ¯ |
| | | 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("è§£ææ£è
ä¿¡æ¯å¤±è´¥:", 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"; |
| | |
| | | }, |
| | | |
| | | // è·åç¶æææ¬ |
| | | 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; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | }, |
| | | |
| | |
| | | // éç½®çé |
| | | handleResetFilter() { |
| | | this.filterParams = { |
| | | deptId: "", |
| | | status: "", |
| | | todeptcode: "", |
| | | handleFlag: "", |
| | | templateType: "", |
| | | scriptid: null, // ä¿çé®é¢ID |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }; |
| | | this.selectedExceptionIds = []; |
| | | this.loadExceptionList(); |
| | | }, |
| | | |
| | |
| | | this.$message.warning("请å
éæ©è¦å¤ççå¼å¸¸åé¦"); |
| | | return; |
| | | } |
| | | |
| | | // éç½®æ¹éå¤ç表å |
| | | this.batchProcessForm = { |
| | | handleFlag: "", |
| | | ccdepts: [], |
| | | handleresult: "", |
| | | handledesc: "", |
| | | }; |
| | | |
| | | this.batchDialogVisible = true; |
| | | }, |
| | | |
| | |
| | | // æ¥ç详æ
|
| | | handleViewDetail(row) { |
| | | this.selectedRecordId = row.id; |
| | | this.detailDialogTitle = `${row.patientName} - å¼å¸¸åé¦è¯¦æ
`; |
| | | this.selectedRecordData = row; |
| | | |
| | | // çæå¼¹æ¡æ é¢ |
| | | let title = "å¼å¸¸åé¦è¯¦æ
"; |
| | | if (row.patdesc) { |
| | | const patientName = row.patdesc.split("|")[0]; |
| | | 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, |
| | | // å°æ°ç»è½¬æ¢ä¸ºéå·åéçå符串 |
| | | 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; |
| | | } |
| | | }); |
| | | }, |
| | |
| | | // æäº¤æ¹éå¤ç |
| | | 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; |
| | | } |
| | | }); |
| | | }, |
| | |
| | | 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 |
| | | } 个æä»¶` |
| | | ); |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | } |
| | | |
| | | .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: space-between; |
| | | 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; |
| | |
| | | padding: 2px 0; |
| | | |
| | | .label { |
| | | font-size: 12px; |
| | | color: #606266; |
| | | min-width: 50px; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 13px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | 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 { |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <div class="info-item"> |
| | | <span class="label">æ£è
å§åï¼</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">è§£æå¼ï¼</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="24" v-if="currentRecord.patdesc"> |
| | | <div class="info-item"> |
| | | <span class="label">æ£è
ä¿¡æ¯ï¼</span> |
| | | <span class="value">{{ currentRecord.patdesc }}</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" |
| | |
| | | {{ 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> |
| | | |
| | |
| | | type="primary" |
| | | icon="el-icon-edit" |
| | | @click="handleProcess" |
| | | v-if="currentRecord.processStatus !== 2" |
| | | v-if="currentRecord.handleFlag !== '1'" |
| | | > |
| | | å¤çå¼å¸¸ |
| | | </el-button> |
| | |
| | | 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">æ¯æä¸ä¼ å¾çãææ¡£çéä»¶ï¼å个æä»¶ä¸è¶
è¿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"> |
| | |
| | | </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: 'å¼å¸¸åé¦è¯¦æ
' |
| | |
| | | // å½åè®°å½ |
| | | 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 |
| | | }; |
| | | }, |
| | | |
| | |
| | | set(val) { |
| | | this.$emit('update:visible', val); |
| | | } |
| | | }, |
| | | |
| | | isVoiceTemplate() { |
| | | return this.currentRecord.templateType === 1; |
| | | } |
| | | }, |
| | | |
| | |
| | | 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(() => { |
| | | // æ ¹æ®ä¸åçrecordIdè¿åä¸åçmockæ°æ® |
| | | 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: 'å·²æ¶å°åé¦ï¼æ£å¨å®æç¸å
³äººåæ ¸æ¥æ
åµ', |
| | | attachments: [ |
| | | { id: 1, name: 'åæ¥è°æ¥è®°å½.docx' }, |
| | | { id: 2, name: 'æ£è
æ²éè®°å½.jpg' } |
| | | ] |
| | | }, |
| | | { |
| | | id: 2, |
| | | time: '2024-01-15 10:45:12', |
| | | user: 'ç³»ç»', |
| | | status: 0, // å¾
å¤ç |
| | | remark: 'ç³»ç»èªå¨è¯å«ä¸ºå¼å¸¸åé¦ï¼å·²åé
å°è´£ä»»ç§å®¤', |
| | | 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 { |
| | | // è¿ééè¦æ ¹æ®å®é
æ
åµè°ç¨æ¥å£è·åé®å·æ°æ® |
| | | // 妿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; |
| | | }, |
| | |
| | | // æäº¤å¤ç |
| | | 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} 个æä»¶`); |
| | | } |
| | | } |
| | | }; |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | |
| | | gap: 10px; |
| | | } |
| | | } |
| | | |
| | | // å¼å¸¸æ ·å¼ |
| | | .scriptTopic-isabnormal { |
| | | border-color: #f56c6c !important; |
| | | background: #fef0f0 !important; |
| | | } |
| | | |
| | | .scriptTopic-warning { |
| | | border-color: #e6a23c !important; |
| | | background: #fdf6ec !important; |
| | | } |
| | | </style> |
| | |
| | | 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.templateid" |
| | | placeholder="è¯·éæ©æ¨¡æ¿" |
| | | clearable |
| | | style="width: 200px" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="责任ç§å®¤" prop="deptIds"> |
| | | <el-form-item label="责任ç§å®¤" prop="todeptcode"> |
| | | <el-select |
| | | v-model="queryParams.deptIds" |
| | | v-model="queryParams.todeptcode" |
| | | placeholder="è¯·éæ©è´£ä»»ç§å®¤" |
| | | clearable |
| | | filterable |
| | |
| | | > |
| | | <el-option |
| | | v-for="dept in deptList" |
| | | :key="dept.id" |
| | | :label="dept.name" |
| | | :value="dept.id" |
| | | :key="dept.deptCode" |
| | | :label="dept.deptName" |
| | | :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" |
| | | /> |
| | |
| | | <!-- å¼å¸¸ç»è®¡æ¦è§ --> |
| | | <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;"> |
| | |
| | | </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;"> |
| | |
| | | </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;"> |
| | |
| | | <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> |
| | |
| | | |
| | | <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> |
| | |
| | | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | |
| | | <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> |
| | |
| | | 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" |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { tracedeallist } from "@/api/AiCentre/index"; |
| | | |
| | | export default { |
| | | name: 'ExceptionList', |
| | | data() { |
| | | return { |
| | | // æ¥è¯¢åæ° |
| | | queryParams: { |
| | | templateId: '', |
| | | deptIds: [], |
| | | dateRange: [], |
| | | todeptcode: [], // å¤çç§å®¤ç¼å·æ°ç» |
| | | todeptname: '', // å¤çç§å®¤åç§° |
| | | templateid: '', // 任塿¨¡æ¿ID |
| | | handleStartTime: '', // å¤çå¼å§æ¶é´ |
| | | handleEndTime: '', // å¤çç»ææ¶é´ |
| | | handleTimeRange: [], // æ¶é´èå´ï¼ç¨äºçé¢å±ç¤º |
| | | pageNum: 1, |
| | | pageSize: 10 |
| | | }, |
| | |
| | | |
| | | // 模æ¿å表 |
| | | 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: 'è¿ç¤ç§' } |
| | | // ä½ å¯ä»¥ä»æ¥å£è·åç§å®¤å表ï¼è¿éå
ç¨éææ°æ® |
| | | { deptCode: '001', deptName: 'å¿è¡ç®¡å
ç§' }, |
| | | { deptCode: '002', deptName: 'ç¥ç»å
ç§' }, |
| | | { deptCode: '003', deptName: 'æ®å¤ç§' }, |
| | | { deptCode: '004', deptName: '骨ç§' }, |
| | | { deptCode: '005', deptName: 'å¦äº§ç§' }, |
| | | { deptCode: '006', deptName: 'å¿ç§' }, |
| | | { deptCode: '007', deptName: 'æ¥è¯ç§' }, |
| | | { deptCode: '008', deptName: 'å¼å¸å
ç§' }, |
| | | { deptCode: '009', deptName: 'æ¶åå
ç§' }, |
| | | { deptCode: '010', deptName: 'å
åæ³ç§' }, |
| | | { deptCode: '011', deptName: 'è¾å
ç§' }, |
| | | { deptCode: '012', deptName: 'è¿ç¤ç§' } |
| | | ], |
| | | |
| | | // å¼å¸¸åè¡¨æ°æ® |
| | |
| | | }, |
| | | |
| | | 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.templateid) { |
| | | params.templateid = this.queryParams.templateid; |
| | | } |
| | | |
| | | // å¤çæ¶é´èå´ |
| | | if (this.queryParams.handleTimeRange && this.queryParams.handleTimeRange.length === 2) { |
| | | params.handleStartTime = this.queryParams.handleTimeRange[0]; |
| | | params.handleEndTime = this.queryParams.handleTimeRange[1]; |
| | | } |
| | | |
| | | return params; |
| | | }, |
| | | |
| | | // å è½½æ°æ® |
| | | async loadData() { |
| | | this.loading = true; |
| | |
| | | |
| | | // å è½½å¼å¸¸å表 |
| | | 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 { |
| | | // 仿¥å£æ°æ®è®¡ç®ç»è®¡æ°æ® |
| | | 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 |
| | | }; |
| | | } |
| | | }, |
| | | |
| | | // å¤çæ¥è¯¢ |
| | |
| | | // å¤çéç½® |
| | | handleReset() { |
| | | this.$refs.queryForm.resetFields(); |
| | | this.queryParams.dateRange = []; |
| | | this.queryParams.handleTimeRange = []; |
| | | this.queryParams.pageNum = 1; |
| | | this.queryParams.todeptcode = []; // éç½®ç§å®¤éæ© |
| | | this.loadData(); |
| | | }, |
| | | |
| | |
| | | |
| | | // è·³è½¬å°æ¹éå¤çé¡µé¢ |
| | | this.$router.push({ |
| | | path: '/satisfaction/exception/batch-process', |
| | | path: '/Intelligentcenter/batch', |
| | | query: { |
| | | questionIds: this.selectedIds.join(',') |
| | | } |
| | |
| | | |
| | | // å¤çéæ©åå |
| | | 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); |
| | | }, |
| | | |
| | | // å¤çå个é¢ç®æ¹éå¤ç |
| | |
| | | this.$router.push({ |
| | | path: '/Intelligentcenter/batch', |
| | | query: { |
| | | questionId: row.questionId |
| | | questionId: row.scriptid, |
| | | questionText: encodeURIComponent(row.questiontext) |
| | | } |
| | | }); |
| | | }, |
| | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column |
| | | <!-- <el-table-column |
| | | label="è¶å¿" |
| | | prop="trend" |
| | | align="center" |
| | |
| | | }}</span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> --> |
| | | |
| | | <el-table-column |
| | | label="æä½" |
| | |
| | | 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, |
| | |
| | | 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(); |
| | |
| | | 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({ |
| | |
| | | }); |
| | | |
| | | this.typeDetailData = typeDetail; |
| | | console.log(this.typeDetailData,'this.typeDetailData'); |
| | | |
| | | this.calculateTypeSummary(typeDetail); |
| | | }, |
| | | |
| | |
| | | if (score >= 4.0) return "è¯å¥½"; |
| | | if (score >= 3.0) return "ä¸è¬"; |
| | | if (score >= 2.0) return "è¾å·®"; |
| | | return "å·®"; |
| | | return "æªç¥"; |
| | | }, |
| | | |
| | | // è·åè¶å¿ |
| | |
| | | // 渲æå¾è¡¨ |
| | | 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: "", |
| | |
| | | <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> |
| | |
| | | |
| | | // æ ¼å¼åç¾åæ¯ |
| | | 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)}%`; |
| | | }, |
| | | |
| | | // è·ååæ¶çæ ·å¼ç±» |
| | |
| | | è¯å¥½: "primary", |
| | | ä¸è¬: "warning", |
| | | è¾å·®: "danger", |
| | | å·®: "info", |
| | | æªç¥: "info", |
| | | }; |
| | | return levelMap[level] || "info"; |
| | | }, |
| | |
| | | value: 4, |
| | | label: "䏿§è¡", |
| | | }, |
| | | { |
| | | { |
| | | value: 5, |
| | | label: "åé失败", |
| | | }, |
| | |
| | | value: 6, |
| | | label: "已宿", |
| | | }, |
| | | { |
| | | { |
| | | value: 7, |
| | | label: "è¶
æ¶", |
| | | }, |
| | |
| | | /** å¯¼åºæé®æä½ */ |
| | | handleExport() { |
| | | console.log(this.topqueryParams); |
| | | |
| | | this.topqueryParams.pageSize = null; |
| | | this.download( |
| | | // "smartor/serviceSubtask/export", |
| | | "smartor/serviceSubtask/getSubtaskByDiagnameExport", |
| | |
| | | [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://localhost:8095`, |
| | | // target:`http://35z1t16164.qicp.vip`, |
| | | // target: `http://192.168.100.172:8095`, |
| | | // target: `http://192.168.101.166:8093`, |