<template>
|
<el-dialog
|
:title="title"
|
:visible.sync="dialogVisible"
|
width="900px"
|
top="5vh"
|
class="exception-detail-dialog"
|
@close="handleClose"
|
>
|
<!-- 基本信息 -->
|
<div class="info-section">
|
<div class="section-title">基本信息</div>
|
<el-row :gutter="20">
|
<el-col :span="8">
|
<div class="info-item">
|
<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.asrtext || '无回答' }}</span>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="info-item">
|
<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 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.handleFlag)"
|
effect="dark"
|
>
|
{{ getStatusText(currentRecord.handleFlag) }}
|
</el-tag>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="info-item">
|
<span class="label">模板类型:</span>
|
<el-tag :type="currentRecord.templateType === 1 ? 'primary' : 'success'">
|
{{ currentRecord.templateType === 1 ? '语音模板' : '问卷模板' }}
|
</el-tag>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="info-item">
|
<span class="label">创建时间:</span>
|
<span class="value">{{ formatDateTime(currentRecord.createTime) }}</span>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="info-item">
|
<span class="label">处理时间:</span>
|
<span class="value">{{ currentRecord.handleTime ? formatDateTime(currentRecord.handleTime) : '未处理' }}</span>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="info-item">
|
<span class="label">处理人:</span>
|
<span class="value">{{ currentRecord.handleBy || '未处理' }}</span>
|
</div>
|
</el-col>
|
<el-col :span="8" v-if="currentRecord.handleresult">
|
<div class="info-item">
|
<span class="label">处理结果:</span>
|
<span class="value">{{ getHandleresultText(currentRecord.handleresult) }}</span>
|
</div>
|
</el-col>
|
<el-col :span="16" v-if="currentRecord.handledesc">
|
<div class="info-item">
|
<span class="label">处理说明:</span>
|
<span class="value">{{ currentRecord.handledesc }}</span>
|
</div>
|
</el-col>
|
<el-col :span="24" v-if="currentRecord.finaloption">
|
<div class="info-item">
|
<span class="label">最终意见:</span>
|
<span class="value">{{ currentRecord.finaloption }}</span>
|
</div>
|
</el-col>
|
<el-col :span="8" v-if="currentRecord.recordurl">
|
<div class="info-item">
|
<span class="label">录音地址:</span>
|
<el-button
|
type="text"
|
size="small"
|
icon="el-icon-headset"
|
@click="handlePlayAudio(currentRecord.recordurl)"
|
>
|
播放录音
|
</el-button>
|
</div>
|
</el-col>
|
<el-col :span="8" v-if="currentRecord.ccdepts">
|
<div class="info-item">
|
<span class="label">抄送科室:</span>
|
<span class="value">{{ currentRecord.ccdepts }}</span>
|
</div>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 问卷/语音详情 -->
|
<div class="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"
|
>
|
<!-- 单选 -->
|
<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>
|
</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>
|
</el-tab-pane>
|
</el-tabs>
|
</div>
|
|
<!-- 处理记录 -->
|
<div class="process-section" v-if="processRecords.length > 0">
|
<div class="section-title">处理记录</div>
|
<div class="process-timeline">
|
<el-timeline>
|
<el-timeline-item
|
v-for="(record, index) in processRecords"
|
:key="index"
|
:timestamp="formatDateTime(record.handleTime || record.createTime)"
|
placement="top"
|
>
|
<el-card>
|
<div class="process-item">
|
<div class="process-header">
|
<span class="process-user">{{ record.handleBy || '系统' }}</span>
|
<el-tag
|
size="small"
|
:type="getStatusTagType(record.handleFlag)"
|
>
|
{{ getStatusText(record.handleFlag) }}
|
</el-tag>
|
</div>
|
<div class="process-content">
|
<div v-if="record.ccdepts" class="process-depts">
|
<span class="label">抄送科室:</span>
|
<el-tag
|
v-for="dept in getDeptArray(record.ccdepts)"
|
:key="dept"
|
size="small"
|
type="info"
|
class="dept-tag"
|
>
|
{{ dept }}
|
</el-tag>
|
</div>
|
<div v-if="record.handleresult" class="process-remark">
|
<span class="label">处理结果:</span>
|
<span class="content">{{ getHandleresultText(record.handleresult) }}</span>
|
</div>
|
<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>
|
|
<span slot="footer" class="dialog-footer">
|
<el-button
|
type="primary"
|
icon="el-icon-edit"
|
@click="handleProcess"
|
v-if="currentRecord.handleFlag !== '1'"
|
>
|
处理异常
|
</el-button>
|
<el-button @click="dialogVisible = false">关闭</el-button>
|
</span>
|
|
<!-- 处理对话框 -->
|
<el-dialog
|
title="处理异常反馈"
|
:visible.sync="processDialogVisible"
|
width="600px"
|
center
|
append-to-body
|
>
|
<el-form
|
:model="processForm"
|
:rules="processRules"
|
ref="processForm"
|
label-width="100px"
|
size="medium"
|
>
|
<el-form-item label="处理状态" prop="handleFlag">
|
<el-select
|
v-model="processForm.handleFlag"
|
placeholder="请选择处理状态"
|
style="width: 100%"
|
>
|
<el-option label="已处理" :value="'1'" />
|
<el-option label="取消处理" :value="'0'" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="抄送科室" prop="ccdepts">
|
<el-select
|
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.deptCode"
|
:label="dept.label"
|
:value="dept.deptCode"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<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.handledesc"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入处理说明(最多500字)"
|
maxlength="500"
|
show-word-limit
|
:disabled="processForm.handleFlag !== '1'"
|
/>
|
</el-form-item>
|
|
<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 @click="processDialogVisible = false">取消</el-button>
|
<el-button
|
type="primary"
|
@click="submitProcess"
|
:loading="processing"
|
>
|
提交处理
|
</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
|
},
|
recordId: {
|
type: [Number, String],
|
default: null
|
},
|
recordData: {
|
type: Object,
|
default: () => ({})
|
},
|
title: {
|
type: String,
|
default: '异常反馈详情'
|
}
|
},
|
data() {
|
return {
|
// 当前记录
|
currentRecord: {},
|
|
// 问卷/语音数据
|
activeName: 'wj',
|
taskName: '',
|
templateData: [],
|
voiceData: [],
|
voiceAudioUrl: '',
|
|
// 处理记录
|
processRecords: [],
|
|
// 科室列表
|
deptList: [],
|
|
// 处理对话框
|
processDialogVisible: false,
|
processing: false,
|
processForm: {
|
handleFlag: '',
|
ccdepts: [],
|
handleresult: '',
|
handledesc: '',
|
finaloption: ''
|
},
|
processRules: {
|
handleFlag: [
|
{ required: true, message: '请选择处理状态', trigger: 'change' }
|
],
|
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();
|
}
|
}
|
}
|
]
|
},
|
|
// 音频播放
|
audioUrl: '',
|
|
// 加载状态
|
loading: false,
|
|
// 权限控制
|
hasQualityPermission: false
|
};
|
},
|
|
computed: {
|
dialogVisible: {
|
get() {
|
return this.visible;
|
},
|
set(val) {
|
this.$emit('update:visible', val);
|
}
|
},
|
|
isVoiceTemplate() {
|
return this.currentRecord.templateType === 1;
|
}
|
},
|
|
watch: {
|
visible: {
|
immediate: true,
|
handler(val) {
|
if (val) {
|
this.loadData();
|
} else {
|
this.resetData();
|
}
|
}
|
},
|
|
recordData: {
|
immediate: true,
|
handler(val) {
|
if (val && Object.keys(val).length > 0) {
|
this.currentRecord = { ...val };
|
}
|
}
|
}
|
},
|
|
methods: {
|
// 格式化日期时间
|
formatDateTime(dateTime) {
|
if (!dateTime) return '';
|
try {
|
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;
|
}
|
},
|
|
// 检查质管权限
|
checkQualityPermission() {
|
const userRoles = this.$store.getters.roles || [];
|
return userRoles.includes('quality_manager') || userRoles.includes('admin');
|
},
|
|
// 获取科室列表
|
async getDeptOptions() {
|
try {
|
const res = await deptTreeSelect();
|
if (res.code == 200) {
|
this.deptList = this.flattenArray(res.data) || [];
|
}
|
} catch (error) {
|
console.error('获取科室列表失败:', error);
|
}
|
},
|
|
// 展平数组
|
flattenArray(multiArray) {
|
let result = [];
|
|
function flatten(element) {
|
if (element.children && element.children.length > 0) {
|
element.children.forEach((child) => flatten(child));
|
} else {
|
let item = JSON.parse(JSON.stringify(element));
|
result.push(item);
|
}
|
}
|
|
multiArray.forEach((element) => flatten(element));
|
return result;
|
},
|
|
// 获取状态标签类型
|
getStatusTagType(handleFlag) {
|
switch (handleFlag) {
|
case '0': return 'warning'; // 未处理
|
case '1': return 'success'; // 已处理
|
default: return 'info';
|
}
|
},
|
|
// 获取状态文本
|
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 = {
|
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) {
|
return;
|
}
|
|
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;
|
|
// 更新当前记录
|
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');
|
} else {
|
this.$message.error(res.msg || "处理提交失败");
|
}
|
} catch (error) {
|
console.error("处理提交失败:", error);
|
this.$message.error("处理提交失败,请稍后重试");
|
} finally {
|
this.processing = false;
|
}
|
});
|
},
|
|
// 处理对话框关闭
|
handleClose() {
|
this.$emit('close');
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.exception-detail-dialog {
|
::v-deep .el-dialog {
|
max-height: 85vh;
|
display: flex;
|
flex-direction: column;
|
|
.el-dialog__body {
|
flex: 1;
|
overflow-y: auto;
|
padding: 20px;
|
}
|
}
|
|
.info-section {
|
margin-bottom: 20px;
|
padding: 20px;
|
background: #f8f9fa;
|
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;
|
}
|
|
.info-item {
|
margin-bottom: 12px;
|
display: flex;
|
align-items: center;
|
|
.label {
|
font-size: 14px;
|
color: #606266;
|
min-width: 80px;
|
font-weight: 500;
|
}
|
|
.value {
|
font-size: 14px;
|
color: #303133;
|
font-weight: 500;
|
flex: 1;
|
}
|
}
|
}
|
|
.content-container {
|
margin-bottom: 20px;
|
|
::v-deep .el-tabs__content {
|
padding: 20px;
|
background: #fff;
|
border-radius: 0 0 4px 4px;
|
}
|
|
.CONTENT, .borderdiv {
|
padding: 20px;
|
background: #fff;
|
border-radius: 6px;
|
|
.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;
|
}
|
}
|
|
.leftside {
|
display: flex;
|
align-items: center;
|
gap: 10px;
|
margin-bottom: 10px;
|
font-size: 15px;
|
font-weight: 500;
|
color: #303133;
|
|
i {
|
color: #409EFF;
|
}
|
}
|
|
.offside {
|
display: flex;
|
align-items: flex-start;
|
gap: 10px;
|
margin-bottom: 20px;
|
|
i {
|
color: #67C23A;
|
margin-top: 8px;
|
}
|
|
.offside-value {
|
flex: 1;
|
|
.el-textarea {
|
margin-bottom: 10px;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
.process-section {
|
.section-title {
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 15px;
|
padding-bottom: 10px;
|
border-bottom: 2px solid #409EFF;
|
}
|
|
.process-timeline {
|
::v-deep .el-timeline-item {
|
padding-bottom: 20px;
|
|
.el-timeline-item__timestamp {
|
font-size: 13px;
|
color: #909399;
|
}
|
}
|
|
.process-item {
|
.process-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 10px;
|
|
.process-user {
|
font-size: 14px;
|
font-weight: 600;
|
color: #409EFF;
|
}
|
}
|
|
.process-content {
|
.process-depts {
|
margin-bottom: 8px;
|
|
.label {
|
font-size: 13px;
|
color: #606266;
|
margin-right: 5px;
|
}
|
|
.dept-tag {
|
margin-right: 5px;
|
margin-bottom: 5px;
|
}
|
}
|
|
.process-remark {
|
margin-bottom: 8px;
|
|
.label {
|
font-size: 13px;
|
color: #606266;
|
margin-right: 5px;
|
}
|
|
.content {
|
font-size: 13px;
|
color: #303133;
|
line-height: 1.5;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
.dialog-footer {
|
display: flex;
|
justify-content: flex-end;
|
align-items: center;
|
gap: 10px;
|
}
|
}
|
|
// 异常样式
|
.scriptTopic-isabnormal {
|
border-color: #f56c6c !important;
|
background: #fef0f0 !important;
|
}
|
|
.scriptTopic-warning {
|
border-color: #e6a23c !important;
|
background: #fdf6ec !important;
|
}
|
</style>
|