| | |
| | | <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="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> |