From bc9538a9e071259ca8bbb6de52c60c9d7a55a03b Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 23 九月 2026 14:02:44 +0800
Subject: [PATCH] 测试完成
---
src/views/followvisit/tasklist/index.vue | 127 ++
src/api/smartor/patouthosp.js | 5
src/views/Satisfaction/sfstatistics/components/DataOverview.vue | 30
src/api/AiCentre/SingleTask.js | 8
src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue | 17
src/views/Satisfaction/configurationall/index.vue | 2308 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/views/followvisit/record/detailpage/index.vue | 80 +
src/views/patient/patient/hospital.vue | 13
src/views/patient/patient/behospitalized.vue | 13
src/views/patient/patient/AwaitingAdmission.vue | 13
随访通用922.zip | 0
src/api/patient/record.js | 5
src/components/CallCenterLs/index.vue | 5
src/views/followvisit/discharge/index.vue | 23
14 files changed, 2,622 insertions(+), 25 deletions(-)
diff --git a/src/api/AiCentre/SingleTask.js b/src/api/AiCentre/SingleTask.js
index 0f24aa0..89474da 100644
--- a/src/api/AiCentre/SingleTask.js
+++ b/src/api/AiCentre/SingleTask.js
@@ -86,6 +86,14 @@
data: data,
});
}
+// 鏌ヨ浠诲姟鎵ц鎯呭喌
+export function countByCondition(data) {
+ return request({
+ url: "/smartor/serviceSubtask/countByCondition",
+ method: "post",
+ data: data,
+ });
+}
// 浠诲姟瑙勫垯鍒犻櫎
export function deltaskrule(taskid) {
diff --git a/src/api/patient/record.js b/src/api/patient/record.js
index 522b134..e318faa 100644
--- a/src/api/patient/record.js
+++ b/src/api/patient/record.js
@@ -3,10 +3,13 @@
// 鏌ヨ浣忛櫌璁板綍鍒楄〃
export function listpatient(data) {
+ const params = { ...data };
+ // bedSort 涓嶄紶鍗充笉鎸夊簥鍙锋帓搴�
+ if (params.bedSort == null || params.bedSort === "") delete params.bedSort;
return request({
url: '/smartor/patinhosp/selectPatMedInhospList',
method: 'post',
- data: data
+ data: params
})
};
// 浣忛櫌璁板綍璇︽儏
diff --git a/src/api/smartor/patouthosp.js b/src/api/smartor/patouthosp.js
index 353c440..315c9cc 100644
--- a/src/api/smartor/patouthosp.js
+++ b/src/api/smartor/patouthosp.js
@@ -10,10 +10,13 @@
}
// 鏌ヨ寰呭叆闄㈣褰曞垪琛�
export function listPatMedInhosp(query) {
+ const data = { ...query };
+ // bedSort 涓嶄紶鍗充笉鎸夊簥鍙锋帓搴�
+ if (data.bedSort == null || data.bedSort === "") delete data.bedSort;
return request({
url: '/smartor/patinhosp/selectPatMedInhospList',
method: 'post',
- data: query
+ data: data
})
}
diff --git a/src/components/CallCenterLs/index.vue b/src/components/CallCenterLs/index.vue
index 1ffc805..f5fb0fb 100644
--- a/src/components/CallCenterLs/index.vue
+++ b/src/components/CallCenterLs/index.vue
@@ -267,9 +267,14 @@
},
onCallStatusChange(status) {
+ const wasConnected = this.callStatus === "connected";
this.callStatus = status.status;
if (status.status == "connected") {
this.startCallTimer();
+ // 浠呭湪浠庨潪鎺ラ�氱姸鎬佸垏鎹㈠埌鎺ラ�氭椂閫氱煡鐖剁粍浠讹紙閬垮厤閲嶅璁℃暟锛�
+ if (!wasConnected) {
+ this.$emit("call-connected");
+ }
} else if (status.status == "idle") {
this.stopCallTimer();
}
diff --git a/src/views/Satisfaction/configurationall/index.vue b/src/views/Satisfaction/configurationall/index.vue
new file mode 100644
index 0000000..8208233
--- /dev/null
+++ b/src/views/Satisfaction/configurationall/index.vue
@@ -0,0 +1,2308 @@
+<template>
+ <div class="question-exception-config">
+ <!-- 椤甸潰鏍囬 -->
+ <div class="page-header">
+ <div class="header-content">
+ <h2 class="page-title">棰樼洰寮傚父澶勭悊閰嶇疆</h2>
+ <p class="page-description">
+ 鍩轰簬妯℃澘閰嶇疆鍏ㄩ儴棰樼洰鐨勮矗浠荤瀹ゅ拰鎶ュ绉戝
+ </p>
+ </div>
+ </div>
+
+ <!-- 妯℃澘閫夋嫨鍖哄煙 -->
+ <div class="template-section">
+ <el-card shadow="never">
+ <div class="template-header">
+ <h3 class="template-title">妯℃澘閫夋嫨</h3>
+ <p class="template-tip">璇峰厛閫夋嫨妯℃澘绫诲瀷鍜屽叿浣撴ā鏉�</p>
+ </div>
+
+ <el-form
+ :model="templateForm"
+ :rules="templateRules"
+ ref="templateForm"
+ label-width="120px"
+ size="medium"
+ >
+ <el-row :gutter="20">
+ <el-col :span="8">
+ <el-form-item label="妯℃澘绫诲瀷" prop="templateType">
+ <el-select
+ v-model="templateForm.templateType"
+ placeholder="璇烽�夋嫨妯℃澘绫诲瀷"
+ clearable
+ @change="handleTemplateTypeChange"
+ style="width: 100%"
+ >
+ <el-option label="闂嵎妯℃澘" :value="1" />
+ <el-option label="璇煶妯℃澘" :value="2" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="8">
+ <el-form-item
+ label="閫夋嫨妯℃澘"
+ prop="templateId"
+ :rules="
+ templateForm.templateType
+ ? [
+ {
+ required: true,
+ message: '璇烽�夋嫨妯℃澘',
+ trigger: 'change',
+ },
+ ]
+ : []
+ "
+ >
+ <el-select
+ v-model="templateForm.templateId"
+ placeholder="璇烽�夋嫨妯℃澘"
+ clearable
+ filterable
+ @change="handleTemplateChange"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="template in filteredTemplateOptions"
+ :key="template.id"
+ :label="template.templateName"
+ :value="template.id"
+ />
+ <div
+ v-if="templateOptionsLoading"
+ slot="empty"
+ class="select-loading"
+ >
+ <i class="el-icon-loading"></i>
+ <span>鍔犺浇涓�...</span>
+ </div>
+ </el-select>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="8">
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="el-icon-search"
+ @click="handleLoadTemplate"
+ :loading="templateLoading"
+ :disabled="!templateForm.templateId"
+ >
+ 鍔犺浇妯℃澘棰樼洰
+ </el-button>
+ <el-button icon="el-icon-refresh" @click="handleResetTemplate">
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ </el-card>
+ </div>
+
+ <!-- 妯℃澘淇℃伅 -->
+ <div v-if="currentTemplateInfo" class="template-info-section">
+ <el-card shadow="never">
+ <div class="template-info">
+ <div class="info-left">
+ <h3 class="template-name">
+ {{ currentTemplateInfo.templateName }}
+ </h3>
+ <div class="template-meta">
+ <span class="meta-item">
+ <i class="el-icon-s-order"></i>
+ 妯℃澘绫诲瀷锛歿{
+ templateForm.templateType == 1 ? "闂嵎妯℃澘" : "璇煶妯℃澘"
+ }}
+ </span>
+ <span class="meta-item">
+ <i class="el-icon-s-management"></i>
+ 棰樼洰鎬绘暟锛歿{ currentTemplateInfo.questionCount || 0 }}
+ </span>
+ </div>
+ </div>
+ <div class="info-right">
+ <el-tag
+ :type="
+ currentTemplateInfo.templateStatus == 1 ? 'success' : 'info'
+ "
+ size="medium"
+ >
+ {{ currentTemplateInfo.templateStatus == 1 ? "鍚敤" : "鍋滅敤" }}
+ </el-tag>
+ </div>
+ </div>
+ </el-card>
+ </div>
+
+ <!-- 鎼滅储鍖哄煙锛堥鐩瓫閫夛級 -->
+ <div v-show="questionList.length > 0" class="search-section">
+ <el-card shadow="never" class="search-container">
+ <el-form :model="queryParams" size="medium">
+ <el-form-item label="闂涓婚">
+ <el-input
+ v-model="queryParams.scriptTopic"
+ placeholder="璇疯緭鍏ラ棶棰樹富棰�"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="闂鍐呭">
+ <el-input
+ v-model="queryParams.scriptContent"
+ placeholder="璇疯緭鍏ラ棶棰樺唴瀹�"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="el-icon-search"
+ @click="handleQuery"
+ >
+ 绛涢�夐鐩�
+ </el-button>
+ <el-button icon="el-icon-refresh" @click="resetQuery">
+ 閲嶇疆绛涢��
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </el-card>
+ </div>
+
+ <!-- 閰嶇疆鍒楄〃 -->
+ <div class="config-content">
+ <!-- 鎵归噺鎿嶄綔鏍� -->
+ <div v-if="questionList.length > 0" class="batch-actions-card">
+ <el-card shadow="never">
+ <div class="batch-actions">
+ <el-button
+ type="success"
+ icon="el-icon-check"
+ :loading="batchSaving"
+ :disabled="!hasChanges || batchSaving"
+ @click="handleBatchSave"
+ size="medium"
+ >
+ {{ batchSaving ? "鎵归噺淇濆瓨涓�..." : "鎵归噺淇濆瓨閰嶇疆" }}
+ </el-button>
+ <span v-if="changedCount > 0" class="change-count">
+ 鏈� {{ changedCount }} 椤归厤缃渶瑕佷繚瀛�
+ </span>
+ <div class="total-count">
+ 鍏� {{ filteredQuestionList.length }} 鏉¤褰�
+ </div>
+ </div>
+ </el-card>
+ </div>
+
+ <div v-if="loading" class="loading-wrapper">
+ <div class="loading-spinner">
+ <i class="el-icon-loading"></i>
+ <span>鍔犺浇涓�...</span>
+ </div>
+ </div>
+
+ <div
+ v-else-if="questionList.length == 0 && templateForm.templateId"
+ class="empty-wrapper"
+ >
+ <el-empty description="璇ユā鏉夸腑鏆傛棤棰樼洰">
+ <p class="empty-tip">
+ 璇烽�夋嫨鍏朵粬妯℃澘鎴栨鏌ユā鏉夸腑鏄惁鍖呭惈棰樼洰
+ </p>
+ </el-empty>
+ </div>
+
+ <!-- 涓�琛屼竴琛岀殑鍗$墖鍒楄〃 -->
+ <div v-else-if="filteredQuestionList.length > 0" class="question-list">
+ <div
+ v-for="(question, index) in filteredQuestionList"
+ :key="question.id"
+ class="question-item"
+ >
+ <el-card
+ shadow="hover"
+ class="question-card"
+ :class="{ 'has-changes': question.hasChanges }"
+ >
+ <!-- 鍗$墖澶撮儴 -->
+ <div class="card-header">
+ <div class="header-left">
+ <div class="question-index">
+ <span class="index-number">{{ index + 1 }}</span>
+ <div class="index-line"></div>
+ </div>
+ <div class="question-basic-info">
+ <div class="question-title-section">
+ <h3 class="question-topic" :title="question.scriptTopic">
+ {{ question.scriptTopic || "鏃犱富棰�" }}
+ </h3>
+ <div class="question-tags">
+ <dict-tag
+ :options="askvaluetype"
+ :value="question.scriptType"
+ size="small"
+ />
+ <el-tag
+ v-if="question.targetname"
+ size="small"
+ type="info"
+ >
+ {{ question.targetname }}
+ </el-tag>
+ </div>
+ </div>
+ <div class="question-content-section">
+ <span class="content-label">棰樼洰鍐呭锛�</span>
+ <span class="content-text">{{
+ question.scriptContent
+ }}</span>
+ </div>
+ </div>
+ </div>
+ <div class="header-right">
+ <!-- 寮傚父閫夐」鐘舵�� -->
+ <div
+ class="option-status"
+ v-if="
+ templateForm.templateType != 3 &&
+ templateForm.templateType != 4
+ "
+ >
+ <el-tooltip
+ :content="
+ checkHasAbnormalOptions(question)
+ ? '宸叉湁寮傚父閫夐」'
+ : '鏆傛棤寮傚父閫夐」'
+ "
+ placement="top"
+ >
+ <el-tag
+ :type="
+ checkHasAbnormalOptions(question) ? 'success' : 'danger'
+ "
+ size="small"
+ class="status-tag"
+ >
+ <i
+ :class="
+ checkHasAbnormalOptions(question)
+ ? 'el-icon-success'
+ : 'el-icon-warning'
+ "
+ ></i>
+ {{
+ checkHasAbnormalOptions(question)
+ ? "寮傚父閫夐」宸查厤缃�"
+ : "鏃犲紓甯搁�夐」"
+ }}
+ </el-tag>
+ </el-tooltip>
+ </div>
+
+ <el-button
+ type="text"
+ icon="el-icon-view"
+ @click="previewQuestion(question)"
+ size="small"
+ >
+ 棰勮
+ </el-button>
+
+ <!-- 娣诲姞閰嶇疆閫夐」鎸夐挳 -->
+ <el-button
+ v-if="
+ templateForm.templateType != 3 &&
+ templateForm.templateType != 4
+ "
+ type="text"
+ icon="el-icon-setting"
+ @click="openOptionDialog(question)"
+ size="small"
+ >
+ 閰嶇疆閫夐」
+ </el-button>
+ </div>
+ </div>
+
+ <!-- 寮傚父澶勭悊閰嶇疆 -->
+ <div class="config-section">
+ <div class="config-title">
+ <i class="el-icon-setting"></i>
+ <span>寮傚父澶勭悊閰嶇疆</span>
+ </div>
+
+ <el-form
+ :model="question.exceptionConfig"
+ :rules="configRules"
+ ref="configForm"
+ label-width="100px"
+ size="small"
+ class="config-form"
+ >
+ <div class="config-fields">
+ <!-- 璐d换绉戝锛堝閫夛級 -->
+ <div class="config-field">
+ <el-form-item
+ label="璐d换绉戝"
+ prop="responsibilityDept"
+ class="config-item"
+ >
+ <el-select
+ v-model="question.exceptionConfig.responsibilityDept"
+ placeholder="璇烽�夋嫨璐d换绉戝"
+ filterable
+ clearable
+ multiple
+ style="width: 100%"
+ @change="handleConfigChange(question)"
+ >
+ <el-option
+ v-for="dept in deptOptions"
+ :key="dept.id"
+ :label="dept.label"
+ :value="dept.deptCode"
+ />
+ </el-select>
+ <div class="config-tip">
+ 璐熻矗澶勭悊璇ラ鐩弽棣堢殑绉戝锛屽彲澶氶��
+ </div>
+ </el-form-item>
+ </div>
+ <div class="config-field">
+ <el-form-item label="璐d换浜哄伐鍙�">
+ <el-input
+ v-model="question.exceptionConfig.dutyDeptPersonCode"
+ placeholder="璇疯緭鍏ヨ矗浠讳汉宸ュ彿"
+ @input="handleConfigChange(question)"
+ />
+ </el-form-item>
+ </div>
+ <!-- 鎶ュ绉戝锛堝閫夛級 -->
+ <div class="config-field">
+ <el-form-item
+ label="鎶ュ绉戝"
+ prop="reportDept"
+ class="config-item"
+ >
+ <el-select
+ v-model="question.exceptionConfig.reportDept"
+ placeholder="璇烽�夋嫨鎶ュ绉戝"
+ filterable
+ clearable
+ multiple
+ style="width: 100%"
+ @change="handleConfigChange(question)"
+ >
+ <el-option
+ v-for="dept in deptOptions"
+ :key="dept.id"
+ :label="dept.label"
+ :value="dept.deptCode"
+ />
+ </el-select>
+ <div class="config-tip">
+ 闇�瑕佹帴鏀跺紓甯稿弽棣堢殑绉戝锛屽彲澶氶��
+ </div>
+ </el-form-item>
+ </div>
+ </div>
+
+ <!-- 褰撳墠閰嶇疆淇℃伅 -->
+ <div v-if="question.hasChanges" class="current-config">
+ <div class="config-preview">
+ <div class="preview-item">
+ <span class="preview-label">璐d换绉戝锛�</span>
+ <span class="preview-value">
+ {{
+ getDeptNames(
+ question.exceptionConfig.responsibilityDept || []
+ ).join(", ")
+ }}
+ </span>
+ </div>
+ <div class="preview-item">
+ <span class="preview-label">鎶ュ绉戝锛�</span>
+ <span class="preview-value">
+ {{
+ getDeptNames(
+ question.exceptionConfig.reportDept || []
+ ).join(", ")
+ }}
+ </span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 閰嶇疆鐘舵�佸拰鎿嶄綔鎸夐挳 -->
+ <div class="config-footer">
+ <div v-if="question.saveStatus" class="save-status">
+ <el-alert
+ :type="question.saveStatus.type"
+ :title="question.saveStatus.message"
+ :closable="false"
+ show-icon
+ :effect="
+ question.saveStatus.type == 'success' ? 'dark' : 'light'
+ "
+ size="small"
+ />
+ </div>
+
+ <div class="config-actions">
+ <el-button
+ type="primary"
+ :loading="question.saving"
+ :disabled="!question.hasChanges"
+ @click="saveSingleConfig(question)"
+ size="small"
+ icon="el-icon-check"
+ >
+ {{ question.saving ? "淇濆瓨涓�..." : "淇濆瓨閰嶇疆" }}
+ </el-button>
+ <el-button
+ v-if="question.hasChanges"
+ type="text"
+ @click="resetSingleConfig(question)"
+ size="small"
+ >
+ 閲嶇疆
+ </el-button>
+ </div>
+ </div>
+ </el-form>
+ </div>
+ </el-card>
+ </div>
+ </div>
+ </div>
+ <!-- 閫夐」閰嶇疆瀵硅瘽妗� -->
+ <el-dialog
+ title="閫夐」寮傚父鐘舵�侀厤缃�"
+ :visible.sync="optionDialogVisible"
+ width="700px"
+ center
+ :close-on-click-modal="false"
+ >
+ <div v-if="editingQuestion" class="option-config-wrapper">
+ <div class="dialog-header">
+ <h4>{{ editingQuestion.scriptTopic || "鏃犱富棰�" }}</h4>
+ <p class="dialog-subtitle">{{ editingQuestion.scriptContent }}</p>
+ </div>
+
+ <div class="option-list">
+ <el-alert
+ v-if="!currentOptions.some((opt) => opt.isabnormal == 1)"
+ title="璇疯嚦灏戣缃竴涓紓甯搁�夐」锛堟爣璁颁负寮傚父锛�"
+ type="warning"
+ :closable="false"
+ show-icon
+ style="margin-bottom: 20px"
+ />
+
+ <div
+ v-for="(option, index) in currentOptions"
+ :key="index"
+ class="option-item"
+ >
+ <el-form
+ :model="option"
+ :rules="optionRules"
+ ref="optionForm"
+ size="small"
+ class="option-form"
+ >
+ <el-row :gutter="12" align="middle">
+ <el-col :span="2">
+ <div class="option-index">#{{ index + 1 }}</div>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="targetvalue">
+ <el-input
+ v-model="option.targetvalue"
+ placeholder="璇疯緭鍏ラ�夐」鍐呭"
+ clearable
+ maxlength="200"
+ show-word-limit
+ />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="6">
+ <el-form-item prop="isabnormal">
+ <el-select
+ v-model="option.isabnormal"
+ placeholder="閫夋嫨鐘舵��"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="status in abnormalOptions"
+ :key="status.value"
+ :label="status.label"
+ :value="status.value"
+ >
+ <el-tag :type="status.type" size="small">{{
+ status.label
+ }}</el-tag>
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="4">
+ <el-button
+ type="danger"
+ icon="el-icon-delete"
+ @click="removeOption(index)"
+ size="small"
+ circle
+ plain
+ />
+ </el-col>
+ </el-row>
+ </el-form>
+ </div>
+
+ <!-- <el-button
+ type="primary"
+ icon="el-icon-plus"
+ @click="addNewOption"
+ size="small"
+ plain
+ style="width: 100%; margin-top: 10px;"
+ >
+ 娣诲姞閫夐」
+ </el-button> -->
+ </div>
+ </div>
+
+ <span slot="footer" class="dialog-footer">
+ <el-button @click="optionDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveOptions"> 淇濆瓨閰嶇疆 </el-button>
+ </span>
+ </el-dialog>
+ <!-- 棰樼洰棰勮瀵硅瘽妗� -->
+ <el-dialog
+ title="棰樼洰棰勮"
+ :visible.sync="previewVisible"
+ width="600px"
+ center
+ >
+ <div v-if="currentPreview" class="preview-wrapper">
+ <div class="preview-header">
+ <h4>{{ currentPreview.scriptTopic || "鏃犱富棰�" }}</h4>
+ <div class="preview-tags">
+ <dict-tag
+ :options="askvaluetype"
+ :value="currentPreview.scriptType"
+ size="small"
+ />
+ <el-tag v-if="currentPreview.targetname" size="small" type="info">
+ {{ currentPreview.targetname }}
+ </el-tag>
+ </div>
+ </div>
+ <!-- 妯℃澘棰樼洰灞曠ず -->
+
+ <div class="preview-content" v-if="templateForm.templateType == 1">
+ <p class="preview-question">{{ currentPreview.scriptContent }}</p>
+
+ <div
+ v-if="
+ currentPreview.scriptType != 3 && currentPreview.scriptType != 4
+ "
+ class="preview-options"
+ >
+ <el-radio-group v-model="previewAnswer">
+ <el-radio
+ v-for="(
+ option, idx
+ ) in currentPreview.svyLibTemplateTargetoptions || []"
+ :key="idx"
+ :label="option.optioncontent"
+ class="option-item"
+ >
+ {{ option.optioncontent }}
+ </el-radio>
+ </el-radio-group>
+ </div>
+
+ <div v-else class="preview-textarea">
+ <el-input
+ type="textarea"
+ placeholder="璇疯緭鍏ュ洖绛�"
+ v-model="previewAnswer"
+ :rows="4"
+ />
+ </div>
+ </div>
+ <!-- 璇煶棰樼洰灞曠ず -->
+ <div class="preview-content" v-else>
+ <p class="preview-question">{{ currentPreview.scriptContent }}</p>
+
+ <div
+ v-if="
+ currentPreview.scriptType != 3 && currentPreview.scriptType != 4
+ "
+ class="preview-options"
+ >
+ <el-radio-group v-model="previewAnswer">
+ <el-radio
+ v-for="(
+ option, idx
+ ) in currentPreview.ivrLibaScriptTargetoptionList || []"
+ :key="idx"
+ :label="option.targetvalue"
+ class="option-item"
+ >
+ {{ option.targetvalue }}
+ </el-radio>
+ </el-radio-group>
+ </div>
+
+ <div v-else class="preview-textarea">
+ <el-input
+ type="textarea"
+ placeholder="璇疯緭鍏ュ洖绛�"
+ v-model="previewAnswer"
+ :rows="4"
+ />
+ </div>
+ </div>
+ </div>
+ <span slot="footer" class="dialog-footer">
+ <el-button @click="previewVisible = false">鍏抽棴</el-button>
+ </span>
+ </el-dialog>
+
+ <!-- 淇濆瓨鎴愬姛鎻愮ず -->
+ <el-dialog
+ title="淇濆瓨鎴愬姛"
+ :visible.sync="saveSuccessVisible"
+ width="400px"
+ center
+ >
+ <div class="success-content">
+ <i class="el-icon-success success-icon"></i>
+ <p class="success-text">閰嶇疆宸叉垚鍔熶繚瀛橈紒</p>
+ </div>
+ <span slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="saveSuccessVisible = false"
+ >纭畾</el-button
+ >
+ </span>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import {
+ compileQtemplate,
+ compileFollowup,
+ getQtemplatelist,
+ getFollowuplist,
+ getvFollowup,
+ getQtemplateobj,
+} from "@/api/AiCentre/index";
+import { deptTreeSelect } from "@/api/system/user";
+import store from "@/store";
+import Pagination from "@/components/Pagination";
+
+export default {
+ name: "QuestionExceptionConfig",
+ components: { Pagination },
+ data() {
+ return {
+ // 妯℃澘琛ㄥ崟
+ templateForm: {
+ templateType: "",
+ templateId: "",
+ },
+ templateRules: {
+ templateType: [
+ { required: true, message: "璇烽�夋嫨妯℃澘绫诲瀷", trigger: "change" },
+ ],
+ },
+ // 閫夐」绠$悊鐩稿叧
+ optionDialogVisible: false,
+ currentOptions: [],
+ editingQuestion: null,
+ optionRules: {
+ targetvalue: [
+ { required: true, message: "璇疯緭鍏ラ�夐」鍐呭", trigger: "blur" },
+ ],
+ isabnormal: [
+ { required: true, message: "璇烽�夋嫨寮傚父鐘舵��", trigger: "change" },
+ ],
+ },
+
+ // 寮傚父鐘舵�侀�夐」
+ abnormalOptions: [
+ { label: "姝e父", value: 0, type: "success" },
+ { label: "寮傚父", value: 1, type: "danger" },
+ { label: "璀﹀憡", value: 2, type: "warning" },
+ ],
+ // 妯℃澘閫夐」
+ questionnaireTemplates: [], // 闂嵎妯℃澘鍒楄〃
+ followupTemplates: [], // 璇煶妯℃澘鍒楄〃
+ templateOptionsLoading: false,
+
+ // 褰撳墠妯℃澘淇℃伅
+ currentTemplateInfo: null,
+ templateLoading: false,
+
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ scriptTopic: null,
+ scriptContent: null,
+ },
+
+ // 鏁版嵁鍒楄〃
+ questionList: [],
+ loading: false,
+ batchSaving: false,
+
+ // 瀛楀吀鏁版嵁
+ askvaluetype: store.getters.askvaluetype || [],
+ qyoptions: store.getters.usable || [],
+
+ // 绉戝閫夐」
+ deptOptions: [],
+
+ // 棰勮鐩稿叧
+ previewVisible: false,
+ currentPreview: null,
+ previewAnswer: "",
+
+ // 淇濆瓨鐩稿叧
+ saveSuccessVisible: false,
+ hasChanges: false,
+ changedCount: 0,
+
+ // 琛ㄥ崟楠岃瘉瑙勫垯
+ configRules: {
+ responsibilityDept: [
+ {
+ required: true,
+ message: "璇疯嚦灏戦�夋嫨涓�涓矗浠荤瀹�",
+ trigger: "change",
+ },
+ {
+ validator: (rule, value, callback) => {
+ if (!value || value.length == 0) {
+ callback(new Error("璇疯嚦灏戦�夋嫨涓�涓矗浠荤瀹�"));
+ } else {
+ callback();
+ }
+ },
+ trigger: "change",
+ },
+ ],
+ reportDept: [
+ {
+ required: true,
+ message: "璇疯嚦灏戦�夋嫨涓�涓姤澶囩瀹�",
+ trigger: "change",
+ },
+ {
+ validator: (rule, value, callback) => {
+ if (!value || value.length == 0) {
+ callback(new Error("璇疯嚦灏戦�夋嫨涓�涓姤澶囩瀹�"));
+ } else {
+ callback();
+ }
+ },
+ trigger: "change",
+ },
+ ],
+ },
+ };
+ },
+ computed: {
+ // 鏍规嵁妯℃澘绫诲瀷杩囨护妯℃澘閫夐」
+ filteredTemplateOptions() {
+ if (this.templateForm.templateType == 1) {
+ return this.questionnaireTemplates;
+ } else if (this.templateForm.templateType == 2) {
+ return this.followupTemplates;
+ }
+ return [];
+ },
+
+ // 绛涢�夊悗鐨勯鐩垪琛�
+ filteredQuestionList() {
+ let filtered = this.questionList;
+
+ // 搴旂敤鎼滅储鏉′欢
+ if (this.queryParams.scriptTopic) {
+ const keyword = this.queryParams.scriptTopic.toLowerCase();
+ filtered = filtered.filter(
+ (q) => q.scriptTopic && q.scriptTopic.toLowerCase().includes(keyword)
+ );
+ }
+
+ if (this.queryParams.scriptContent) {
+ const keyword = this.queryParams.scriptContent.toLowerCase();
+ filtered = filtered.filter(
+ (q) =>
+ q.scriptContent && q.scriptContent.toLowerCase().includes(keyword)
+ );
+ }
+
+ return filtered;
+ },
+ },
+ created() {
+ this.getDeptOptions();
+ this.loadAllTemplates();
+ },
+ methods: {
+ /** 鍔犺浇鎵�鏈夋ā鏉垮垪琛� */
+ loadAllTemplates() {
+ this.templateOptionsLoading = true;
+
+ // 骞惰鍔犺浇闂嵎妯℃澘鍜岃闊虫ā鏉�
+ Promise.all([
+ this.loadQuestionnaireTemplates(),
+ this.loadFollowupTemplates(),
+ ]).finally(() => {
+ this.templateOptionsLoading = false;
+ });
+ },
+
+ /** 鏌ヨ绉戝鍒楄〃 */
+ getDeptOptions() {
+ deptTreeSelect()
+ .then((res) => {
+ if (res.code == 200) {
+ this.deptOptions = this.flattenArray(res.data) || [];
+ }
+ })
+ .catch((error) => {
+ console.error("鑾峰彇绉戝鍒楄〃澶辫触:", error);
+ this.$message.error("鑾峰彇绉戝鍒楄〃澶辫触");
+ });
+ },
+
+ flattenArray(multiArray) {
+ let result = [];
+
+ function flatten(element) {
+ if (element.children && element.children.length > 0) {
+ element.children.forEach((child) => flatten(child));
+ } else {
+ let item = JSON.parse(JSON.stringify(element));
+ result.push(item);
+ }
+ }
+
+ multiArray.forEach((element) => flatten(element));
+ return result;
+ },
+
+ /** 鏍规嵁绉戝缂栫爜鑾峰彇绉戝鍚嶇О */
+ getDeptName(deptCode) {
+ if (!deptCode) return "";
+ const dept = this.deptOptions.find((d) => d.deptCode == deptCode);
+ return dept ? dept.label : deptCode;
+ },
+
+ /** 鏍规嵁绉戝缂栫爜鏁扮粍鑾峰彇绉戝鍚嶇О鏁扮粍 */
+ getDeptNames(deptCodes) {
+ if (!Array.isArray(deptCodes) || deptCodes.length == 0) return [];
+ return deptCodes
+ .map((code) => this.getDeptName(code))
+ .filter((name) => name && name.trim());
+ },
+
+ /** 妯℃澘绫诲瀷鍙樻洿 */
+ handleTemplateTypeChange() {
+ this.templateForm.templateId = "";
+ this.currentTemplateInfo = null;
+ this.questionList = [];
+ },
+
+ /** 鍔犺浇闂嵎妯℃澘鍒楄〃 */
+ loadQuestionnaireTemplates() {
+ return new Promise((resolve) => {
+ getQtemplatelist({ pageSize: 1000 })
+ .then((res) => {
+ console.log(res.rows, "res.rows");
+ if (res.code == 200) {
+ console.log(res.rows, 2);
+ this.questionnaireTemplates = (res.rows || []).map((item) => ({
+ id: item.svyid,
+ templateName: item.svyname,
+ isavailable: item.isavailable,
+ }));
+ console.log(this.followupTemplates, 3);
+ } else {
+ this.$message.error(res.msg || "鍔犺浇闂嵎妯℃澘澶辫触");
+ }
+ resolve();
+ })
+ .catch((error) => {
+ console.error("鍔犺浇闂嵎妯℃澘澶辫触:", error);
+ this.$message.error("鍔犺浇闂嵎妯℃澘澶辫触");
+ resolve();
+ });
+ });
+ },
+
+ /** 鍔犺浇璇煶妯℃澘鍒楄〃 */
+ loadFollowupTemplates() {
+ return new Promise((resolve) => {
+ getFollowuplist({ pageSize: 1000 })
+ .then((res) => {
+ console.log(res.rows, "res.rows");
+ if (res.code == 200) {
+ console.log(res.rows, 2);
+
+ this.followupTemplates = (res.rows || []).map((item) => ({
+ id: item.id,
+ templateName: item.templateName,
+ isavailable: item.isavailable,
+ }));
+ console.log(this.followupTemplates, 3);
+ } else {
+ this.$message.error(res.msg || "鍔犺浇璇煶妯℃澘澶辫触");
+ }
+ resolve();
+ })
+ .catch((error) => {
+ console.error("鍔犺浇璇煶妯℃澘澶辫触:", error);
+ this.$message.error("鍔犺浇璇煶妯℃澘澶辫触");
+ resolve();
+ });
+ });
+ },
+
+ /** 妯℃澘閫夋嫨鍙樻洿 */
+ handleTemplateChange(templateId) {
+ if (templateId) {
+ const selectedTemplate = this.filteredTemplateOptions.find(
+ (t) => t.id == templateId
+ );
+ if (selectedTemplate) {
+ this.currentTemplateInfo = {
+ templateName: selectedTemplate.templateName,
+ templateStatus: selectedTemplate.isavailable,
+ questionCount: 0,
+ };
+ }
+ // 鍔犺浇妯℃澘璇︽儏鏁版嵁
+ this.templateLoading = true;
+ this.loading = true;
+ this.questionList = [];
+
+ if (this.templateForm.templateType == 1) {
+ this.loadQuestionnaireTemplateDetail();
+ } else if (this.templateForm.templateType == 2) {
+ this.loadFollowupTemplateDetail();
+ }
+ } else {
+ this.currentTemplateInfo = null;
+ this.questionList = [];
+ }
+ },
+
+ /** 鍔犺浇妯℃澘璇︽儏鍜岄鐩� */
+ handleLoadTemplate() {
+ this.$refs.templateForm.validate((valid) => {
+ if (!valid) {
+ this.$message.warning("璇峰厛閫夋嫨妯℃澘");
+ return;
+ }
+
+ this.templateLoading = true;
+ this.loading = true;
+ this.questionList = [];
+
+ if (this.templateForm.templateType == 1) {
+ this.loadQuestionnaireTemplateDetail();
+ } else if (this.templateForm.templateType == 2) {
+ this.loadFollowupTemplateDetail();
+ }
+ });
+ },
+
+ /** 鍔犺浇闂嵎妯℃澘璇︽儏 */
+ loadQuestionnaireTemplateDetail() {
+ getQtemplateobj({ svyid: this.templateForm.templateId })
+ .then((res) => {
+ this.templateLoading = false;
+ this.loading = false;
+
+ if (res.code == 200 && res.rows && res.rows.length > 0) {
+ const templateDetail = res.rows[0];
+
+ // 鏇存柊妯℃澘淇℃伅
+ this.currentTemplateInfo = {
+ ...templateDetail,
+ templateName: templateDetail.svyname,
+ templateStatus: templateDetail.isavailable,
+ questionCount: templateDetail.svyTemplateLibScripts?.length || 0,
+ };
+
+ // 鎻愬彇棰樼洰鍒楄〃
+ const questions = templateDetail.svyTemplateLibScripts || [];
+ this.processQuestions(questions);
+
+ this.$message.success(`鎴愬姛鍔犺浇 ${questions.length} 涓鐩甡);
+ } else {
+ this.$message.error(res.msg || "鍔犺浇妯℃澘璇︽儏澶辫触");
+ }
+ })
+ .catch((error) => {
+ this.templateLoading = false;
+ this.loading = false;
+ console.error("鍔犺浇闂嵎妯℃澘璇︽儏澶辫触:", error);
+ this.$message.error("鍔犺浇妯℃澘璇︽儏澶辫触");
+ });
+ },
+
+ /** 鍔犺浇璇煶妯℃澘璇︽儏 */
+ loadFollowupTemplateDetail() {
+ getvFollowup({ id: this.templateForm.templateId })
+ .then((res) => {
+ this.templateLoading = false;
+ this.loading = false;
+
+ if (res.code == 200) {
+ const templateDetail = res.data;
+
+ // 鏇存柊妯℃澘淇℃伅
+ this.currentTemplateInfo = {
+ ...this.currentTemplateInfo,
+ templateName: templateDetail.templateName,
+ templateStatus: templateDetail.isavailable,
+ questionCount:
+ templateDetail.ivrLibaTemplateScriptVOList?.length || 0,
+ };
+
+ // 鎻愬彇棰樼洰鍒楄〃
+ const questions = templateDetail.ivrLibaTemplateScriptVOList || [];
+ this.processQuestions(questions);
+
+ this.$message.success(`鎴愬姛鍔犺浇 ${questions.length} 涓鐩甡);
+ } else {
+ this.$message.error(res.msg || "鍔犺浇妯℃澘璇︽儏澶辫触");
+ }
+ })
+ .catch((error) => {
+ this.templateLoading = false;
+ this.loading = false;
+ console.error("鍔犺浇璇煶妯℃澘璇︽儏澶辫触:", error);
+ this.$message.error("鍔犺浇妯℃澘璇︽儏澶辫触");
+ });
+ },
+
+ /** 澶勭悊棰樼洰鏁版嵁 */
+ processQuestions(questions) {
+ this.questionList = questions.map((question) => {
+ // 瑙f瀽璐d换绉戝鍜屾姤澶囩瀹�
+ let exceptionConfig = {
+ responsibilityDept: [], // 璐d换绉戝缂栫爜鏁扮粍
+ reportDept: [], // 鎶ュ绉戝缂栫爜鏁扮粍
+ dutyDeptPersonCode: question.dutyDeptPersonCode || "", // 璐d换浜哄伐鍙�
+ };
+
+ // 浠庨鐩《灞傚瓧娈佃鍙栨暟鎹�
+ if (question.dutyDeptCode) {
+ // 浠庨�楀彿鍒嗛殧鐨勫瓧绗︿覆杞负鏁扮粍
+ exceptionConfig.responsibilityDept = question.dutyDeptCode
+ .split(",")
+ .map((code) => code.trim())
+ .filter((code) => code);
+ }
+
+ if (question.reportDeptCode) {
+ exceptionConfig.reportDept = question.reportDeptCode
+ .split(",")
+ .map((code) => code.trim())
+ .filter((code) => code);
+ }
+
+ return {
+ ...question,
+ // 缁熶竴瀛楁鍚�
+ id: question.id || question.scriptId,
+ scriptTopic: question.scriptTopic || question.scriptTopic,
+ scriptContent: question.scriptContent || question.scriptContent,
+ scriptType: question.scriptType,
+ isavailable: question.isavailable,
+ targetname: question.targetname,
+ categoryid: question.categoryid || question.categoryid,
+ originalConfig: JSON.parse(JSON.stringify(exceptionConfig)),
+ exceptionConfig: exceptionConfig,
+ hasChanges: false,
+ saving: false,
+ saveStatus: null,
+ };
+ });
+
+ this.updateChangedStatus();
+ },
+
+ /** 閲嶇疆妯℃澘閫夋嫨 */
+ handleResetTemplate() {
+ this.templateForm = {
+ templateType: "",
+ templateId: "",
+ };
+ this.currentTemplateInfo = null;
+ this.questionList = [];
+ this.resetQuery();
+ this.$refs.templateForm?.clearValidate();
+ },
+
+ /** 閰嶇疆鍙樻洿澶勭悊 */
+ handleConfigChange(question) {
+ // 鐩存帴瀵规瘮閰嶇疆鏄惁鍙樺寲锛屼笉渚濊禆琛ㄥ崟鏍¢獙锛堥伩鍏嶅彧鏀逛竴涓瓧娈垫椂鏍¢獙涓嶉�氳繃瀵艰嚧 hasChanges 鏃犳硶鏇存柊锛�
+ question.hasChanges = !this.isConfigEqual(
+ question.exceptionConfig,
+ question.originalConfig
+ );
+ this.updateChangedStatus();
+ },
+
+ /** 姣旇緝閰嶇疆鏄惁鏀瑰彉 */
+ isConfigEqual(config1, config2) {
+ if (!config1 || !config2) return false;
+
+ const responsibility1 = [...(config1.responsibilityDept || [])]
+ .sort()
+ .join(",")
+ .toLowerCase();
+ const responsibility2 = [...(config2.responsibilityDept || [])]
+ .sort()
+ .join(",")
+ .toLowerCase();
+ const report1 = [...(config1.reportDept || [])]
+ .sort()
+ .join(",")
+ .toLowerCase();
+ const report2 = [...(config2.reportDept || [])]
+ .sort()
+ .join(",")
+ .toLowerCase();
+ const person1 = (config1.dutyDeptPersonCode || "").trim();
+ const person2 = (config2.dutyDeptPersonCode || "").trim();
+
+ return responsibility1 == responsibility2
+ && report1 == report2
+ && person1 == person2;
+ },
+
+ /** 鏇存柊鍙樻洿鐘舵�� */
+ updateChangedStatus() {
+ const changedItems = this.questionList.filter((q) => q.hasChanges);
+ this.changedCount = changedItems.length;
+ this.hasChanges = changedItems.length > 0;
+
+ // 寮哄埗鏇存柊瑙嗗浘
+ this.$forceUpdate();
+ },
+
+ /** 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」 */
+ checkHasAbnormalOptions(question) {
+ if (this.templateForm.templateType == 1) {
+ return (question.svyLibTemplateTargetoptions || []).some(
+ (opt) => opt.isabnormal == 1
+ );
+ } else if (this.templateForm.templateType == 2) {
+ return (question.ivrLibaScriptTargetoptionList || []).some(
+ (opt) => opt.isabnormal == 1
+ );
+ }
+ return false;
+ },
+
+ /** 淇濆瓨鍗曚釜棰樼洰閰嶇疆 */
+ async saveSingleConfig(question) {
+ // 妫�鏌ユ槸鍚︽湁鍙樻洿
+ if (!question.hasChanges) {
+ this.$message.info("褰撳墠閰嶇疆鏃犲彉鍖�");
+ return;
+ }
+
+ const index = this.questionList.findIndex((q) => q.id == question.id);
+ if (index == -1) return;
+
+ const formRef = this.$refs.configForm && this.$refs.configForm[index];
+ if (!formRef) return;
+
+ // 楠岃瘉琛ㄥ崟
+ try {
+ await formRef.validate();
+ } catch (error) {
+ this.$message.warning("璇峰厛瀹屾垚蹇呭~椤�");
+ return;
+ }
+
+ question.saving = true;
+ question.saveStatus = null;
+
+ try {
+ // 鑾峰彇褰撳墠妯℃澘璇︽儏
+ let templateDetail;
+ if (this.templateForm.templateType == 1) {
+ // 闂嵎妯℃澘
+ const res = await getQtemplateobj({
+ svyid: this.templateForm.templateId,
+ });
+ if (res.code !== 200 || !res.rows || res.rows.length == 0) {
+ throw new Error(res.msg || "鑾峰彇妯℃澘璇︽儏澶辫触");
+ }
+ templateDetail = res.rows[0];
+ } else if (this.templateForm.templateType == 2) {
+ // 璇煶妯℃澘
+ const res = await getvFollowup({ id: this.templateForm.templateId });
+ if (res.code !== 200) {
+ throw new Error(res.msg || "鑾峰彇妯℃澘璇︽儏澶辫触");
+ }
+ templateDetail = res.data;
+ }
+
+ // 鏇存柊棰樼洰閰嶇疆
+ let updatedTemplateDetail = { ...templateDetail };
+ let questionsField =
+ this.templateForm.templateType == 1
+ ? "svyTemplateLibScripts"
+ : "ivrLibaTemplateScriptVOList";
+
+ const questions = updatedTemplateDetail[questionsField] || [];
+ const questionIndex = questions.findIndex((q) => q.id == question.id);
+
+ if (questionIndex == -1) {
+ throw new Error("鏈壘鍒伴鐩�");
+ }
+
+ // 鑾峰彇绉戝鍚嶇О
+ const responsibilityDeptNames = this.getDeptNames(
+ question.exceptionConfig.responsibilityDept
+ );
+ const reportDeptNames = this.getDeptNames(
+ question.exceptionConfig.reportDept
+ );
+
+ // 鐩存帴鏇存柊棰樼洰椤跺眰瀛楁
+ questions[questionIndex] = {
+ ...questions[questionIndex],
+ // 璁剧疆Excel瑕佹眰鐨勫瓧娈�
+ dutyDeptCode: question.exceptionConfig.responsibilityDept.join(","),
+ dutyDeptName: responsibilityDeptNames.join(","),
+ reportDeptCode: question.exceptionConfig.reportDept.join(","),
+ reportDeptName: reportDeptNames.join(","),
+ dutyDeptPersonCode: question.exceptionConfig.dutyDeptPersonCode || "",
+ };
+
+ // 濡傛灉闇�瑕侊紝涔熸洿鏂伴�夐」鏁版嵁
+ if (question.hasChanges && this.templateForm.templateType == 1) {
+ questions[questionIndex].svyLibTemplateTargetoptions =
+ question.svyLibTemplateTargetoptions || [];
+ } else if (question.hasChanges && this.templateForm.templateType == 2) {
+ questions[questionIndex].ivrLibaScriptTargetoptionList =
+ question.ivrLibaScriptTargetoptionList || [];
+ }
+
+ // 鏇存柊妯℃澘
+ updatedTemplateDetail[questionsField] = questions;
+
+ // 淇濆瓨妯℃澘
+ let response;
+ if (this.templateForm.templateType == 1) {
+ response = await compileQtemplate({
+ ...updatedTemplateDetail,
+ id: this.templateForm.templateId,
+ isoperation: 2,
+ });
+ } else {
+ response = await compileFollowup({
+ ...updatedTemplateDetail,
+ id: this.templateForm.templateId,
+ isoperation: 2,
+ });
+ }
+
+ if (response.code == 200) {
+ this.handleSaveSuccess(question);
+ } else {
+ throw new Error(response.msg || "淇濆瓨澶辫触");
+ }
+ } catch (error) {
+ console.error("淇濆瓨澶辫触:", error);
+ question.saveStatus = {
+ type: "error",
+ message: error.message || "淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯",
+ };
+ this.$message.error(error.message || "淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ question.saving = false;
+ }
+ },
+
+ /** 澶勭悊淇濆瓨鎴愬姛 */
+ handleSaveSuccess(question) {
+ // 鍚屾椂鏇存柊棰樼洰椤跺眰瀛楁
+ const responsibilityDeptNames = this.getDeptNames(
+ question.exceptionConfig.responsibilityDept
+ );
+ const reportDeptNames = this.getDeptNames(
+ question.exceptionConfig.reportDept
+ );
+
+ // 鏇存柊棰樼洰鏈韩鐨勫瓧娈�
+ question.dutyDeptCode =
+ question.exceptionConfig.responsibilityDept.join(",");
+ question.dutyDeptName = responsibilityDeptNames.join(",");
+ question.reportDeptCode = question.exceptionConfig.reportDept.join(",");
+ question.reportDeptName = reportDeptNames.join(",");
+ question.dutyDeptPersonCode = question.exceptionConfig.dutyDeptPersonCode || "";
+
+ // 鏇存柊鍘熷閰嶇疆
+ question.originalConfig = JSON.parse(
+ JSON.stringify(question.exceptionConfig)
+ );
+ question.hasChanges = false;
+ question.saveStatus = {
+ type: "success",
+ message: "閰嶇疆淇濆瓨鎴愬姛",
+ };
+
+ this.updateChangedStatus();
+ this.$message.success("閰嶇疆淇濆瓨鎴愬姛");
+
+ // 5绉掑悗娓呴櫎鎴愬姛鎻愮ず
+ setTimeout(() => {
+ question.saveStatus = null;
+ }, 5000);
+ },
+
+ /** 閲嶇疆鍗曚釜棰樼洰閰嶇疆 */
+ resetSingleConfig(question) {
+ this.$confirm("纭畾瑕侀噸缃綋鍓嶉鐩殑閰嶇疆鍚楋紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ question.exceptionConfig = JSON.parse(
+ JSON.stringify(question.originalConfig)
+ );
+ // 鍚屾椂閲嶇疆棰樼洰椤跺眰瀛楁
+ const responsibilityDeptNames = this.getDeptNames(
+ question.exceptionConfig.responsibilityDept
+ );
+ const reportDeptNames = this.getDeptNames(
+ question.exceptionConfig.reportDept
+ );
+
+ question.dutyDeptCode =
+ question.exceptionConfig.responsibilityDept.join(",");
+ question.dutyDeptName = responsibilityDeptNames.join(",");
+ question.reportDeptCode =
+ question.exceptionConfig.reportDept.join(",");
+ question.reportDeptName = reportDeptNames.join(",");
+
+ question.hasChanges = false;
+ question.saveStatus = null;
+ this.updateChangedStatus();
+ this.$message.success("閰嶇疆宸查噸缃�");
+ })
+ .catch(() => {});
+ },
+
+ /** 鎵归噺淇濆瓨閰嶇疆 */
+ async handleBatchSave() {
+ if (!this.hasChanges || this.batchSaving) return;
+
+ // 鑾峰彇鏈夊彉鏇寸殑棰樼洰
+ const changedQuestions = this.questionList.filter((q) => q.hasChanges);
+ if (changedQuestions.length == 0) {
+ this.$message.info("娌℃湁闇�瑕佷繚瀛樼殑閰嶇疆鍙樻洿");
+ return;
+ }
+
+ this.$confirm("纭畾瑕佷繚瀛樻墍鏈変慨鏀硅繃鐨勯厤缃悧锛�", "鎵归噺淇濆瓨", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(async () => {
+ this.batchSaving = true;
+
+ const results = [];
+ for (const question of changedQuestions) {
+ try {
+ await this.saveSingleConfig(question);
+ results.push({
+ id: question.id,
+ success: !question.hasChanges,
+ });
+ } catch (error) {
+ results.push({
+ id: question.id,
+ success: false,
+ error: error.message,
+ });
+ }
+ }
+
+ this.batchSaving = false;
+
+ const successCount = results.filter((r) => r.success).length;
+ const failCount = results.length - successCount;
+
+ if (failCount == 0) {
+ this.saveSuccessVisible = true;
+ this.$message.success(`鎴愬姛淇濆瓨 ${successCount} 涓厤缃甡);
+ } else {
+ this.$message.warning(
+ `鎴愬姛淇濆瓨 ${successCount} 涓紝澶辫触 ${failCount} 涓猔
+ );
+ // 鍙互鏄剧ず鍏蜂綋鍝簺澶辫触浜�
+ const failedQuestions = results
+ .filter((r) => !r.success)
+ .map((r) => r.id);
+ console.error("淇濆瓨澶辫触鐨勯鐩甀D:", failedQuestions);
+ }
+ })
+ .catch(() => {
+ this.batchSaving = false;
+ });
+ },
+
+ /** 棰勮棰樼洰 */
+ previewQuestion(question) {
+ this.currentPreview = { ...question };
+ this.previewAnswer = "";
+ this.previewVisible = true;
+ },
+
+ /** 淇敼閫夐」绠$悊瀵硅瘽妗嗙殑鎵撳紑鏂规硶锛屼繚瀛樺師濮嬮�夐」 */
+ openOptionDialog(question) {
+ this.editingQuestion = question;
+
+ // 淇濆瓨鍘熷閫夐」鐨勫揩鐓�
+ if (this.templateForm.templateType == 1) {
+ this.editingQuestion.originalOptions = JSON.parse(
+ JSON.stringify(question.svyLibTemplateTargetoptions || [])
+ );
+ } else if (this.templateForm.templateType == 2) {
+ this.editingQuestion.originalOptions = JSON.parse(
+ JSON.stringify(question.ivrLibaScriptTargetoptionList || [])
+ );
+ }
+
+ // 澶嶅埗閫夐」鏁版嵁
+ if (this.templateForm.templateType == 1) {
+ this.currentOptions = JSON.parse(
+ JSON.stringify(question.svyLibTemplateTargetoptions || [])
+ ).map((opt, index) => ({
+ ...opt,
+ id: opt.id || `temp_${Date.now()}_${index}`,
+ targetvalue: opt.optioncontent || "",
+ isabnormal: opt.isabnormal || 0,
+ }));
+ } else if (this.templateForm.templateType == 2) {
+ this.currentOptions = JSON.parse(
+ JSON.stringify(question.ivrLibaScriptTargetoptionList || [])
+ ).map((opt, index) => ({
+ ...opt,
+ id: opt.id || `temp_${Date.now()}_${index}`,
+ targetvalue: opt.targetvalue || "",
+ isabnormal: opt.isabnormal || 0,
+ }));
+ }
+
+ this.optionDialogVisible = true;
+ },
+
+ /** 娣诲姞鏂伴�夐」 */
+ addNewOption() {
+ this.currentOptions.push({
+ id: `temp_${Date.now()}_${this.currentOptions.length}`,
+ targetvalue: "",
+ isabnormal: 0,
+ isNew: true,
+ });
+ },
+
+ /** 鍒犻櫎閫夐」 */
+ removeOption(index) {
+ this.$confirm("纭畾瑕佸垹闄よ繖涓�夐」鍚楋紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ this.currentOptions.splice(index, 1);
+ })
+ .catch(() => {});
+ },
+
+ /** 淇濆瓨閫夐」閰嶇疆 */
+ async saveOptions() {
+ try {
+ // 楠岃瘉蹇呭~椤�
+ for (let i = 0; i < this.currentOptions.length; i++) {
+ const option = this.currentOptions[i];
+ if (!option.targetvalue || option.targetvalue.trim() == "") {
+ this.$message.warning(`绗� ${i + 1} 涓�夐」鍐呭涓嶈兘涓虹┖`);
+ return;
+ }
+ }
+
+ // 妫�鏌ユ槸鍚︽湁寮傚父閫夐」
+ const hasAbnormal = this.currentOptions.some(
+ (opt) => opt.isabnormal == 1
+ );
+
+ if (!hasAbnormal) {
+ this.$message.warning("璇疯嚦灏戣缃竴涓紓甯搁�夐」锛坕sabnormal=1锛�");
+ return;
+ }
+
+ // 鍒ゆ柇閫夐」鏄惁鍙戠敓鍙樺寲
+ let isOptionsChanged = false;
+
+ if (this.templateForm.templateType == 1) {
+ const originalOptions =
+ this.editingQuestion.svyLibTemplateTargetoptions || [];
+ isOptionsChanged = this.checkOptionsChanged(
+ originalOptions,
+ this.currentOptions,
+ "questionnaire"
+ );
+ } else if (this.templateForm.templateType == 2) {
+ const originalOptions =
+ this.editingQuestion.ivrLibaScriptTargetoptionList || [];
+ isOptionsChanged = this.checkOptionsChanged(
+ originalOptions,
+ this.currentOptions,
+ "voice"
+ );
+ }
+
+ // 淇濆瓨閫昏緫 - 鏇存柊棰樼洰瀵硅薄鐨勯�夐」鏁版嵁
+ if (this.templateForm.templateType == 1) {
+ this.editingQuestion.svyLibTemplateTargetoptions =
+ this.currentOptions.map((opt) => ({
+ ...opt,
+ optioncontent: opt.targetvalue,
+ isabnormal: opt.isabnormal,
+ // 娓呴櫎涓存椂瀛楁
+ targetvalue: undefined,
+ isNew: undefined,
+ }));
+ } else if (this.templateForm.templateType == 2) {
+ this.editingQuestion.ivrLibaScriptTargetoptionList =
+ this.currentOptions.map((opt) => ({
+ ...opt,
+ // 娓呴櫎涓存椂瀛楁
+ isNew: undefined,
+ }));
+ }
+
+ // 濡傛灉閫夐」鏈夊彉鍖栵紝鍒欒缃鐩负鏈夊彉鏇寸姸鎬�
+ if (isOptionsChanged) {
+ this.editingQuestion.hasChanges = true;
+ this.updateChangedStatus();
+ }
+
+ this.$message.success("閫夐」閰嶇疆淇濆瓨鎴愬姛");
+ this.optionDialogVisible = false;
+ } catch (error) {
+ console.error("淇濆瓨閫夐」澶辫触:", error);
+ this.$message.error("淇濆瓨閫夐」澶辫触");
+ }
+ },
+ /** 妫�鏌ラ�夐」鏄惁鍙戠敓鍙樺寲 */
+ checkOptionsChanged(originalOptions, newOptions, templateType) {
+ // 濡傛灉鏁伴噺涓嶅悓锛屽垯涓�瀹氬彉鍖栦簡
+ if (originalOptions.length !== newOptions.length) {
+ return true;
+ }
+
+ // 姣旇緝姣忎釜閫夐」鐨勫唴瀹瑰拰寮傚父鐘舵��
+ for (let i = 0; i < originalOptions.length; i++) {
+ const original = originalOptions[i];
+ const current = newOptions[i];
+
+ if (templateType == "questionnaire") {
+ // 闂嵎妯℃澘姣旇緝
+ if (
+ original.optioncontent !== current.targetvalue ||
+ original.isabnormal !== current.isabnormal
+ ) {
+ return true;
+ }
+ } else if (templateType == "voice") {
+ // 璇煶妯℃澘姣旇緝
+ if (
+ original.targetvalue !== current.targetvalue ||
+ original.isabnormal !== current.isabnormal
+ ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ },
+ /** 鑾峰彇寮傚父閫夐」缁熻 */
+ getAbnormalStats(question) {
+ if (this.templateForm.templateType == 1) {
+ const options = question.svyLibTemplateTargetoptions || [];
+ return {
+ total: options.length,
+ abnormal: options.filter((opt) => opt.isabnormal == 1).length,
+ warning: options.filter((opt) => opt.isabnormal == 2).length,
+ normal: options.filter((opt) => opt.isabnormal == 0).length,
+ };
+ } else if (this.templateForm.templateType == 2) {
+ const options = question.ivrLibaScriptTargetoptionList || [];
+ return {
+ total: options.length,
+ abnormal: options.filter((opt) => opt.isabnormal == 1).length,
+ warning: options.filter((opt) => opt.isabnormal == 2).length,
+ normal: options.filter((opt) => opt.isabnormal == 0).length,
+ };
+ }
+ return { total: 0, abnormal: 0, warning: 0, normal: 0 };
+ },
+
+ /** 鎼滅储 */
+ handleQuery() {
+ // 浠呯瓫閫夋樉绀猴紝涓嶉渶瑕侀噸鏂板姞杞�
+ },
+
+ /** 閲嶇疆鎼滅储 */
+ resetQuery() {
+ this.queryParams = {
+ scriptTopic: "",
+ scriptContent: "",
+ };
+ },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+.question-exception-config {
+ min-height: 100%;
+ background-color: #f5f7fa;
+ padding: 20px;
+
+ .page-header {
+ margin-bottom: 20px;
+ padding: 20px;
+ background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
+ border-radius: 8px;
+ color: white;
+
+ .header-content {
+ .page-title {
+ margin: 0 0 8px 0;
+ font-size: 20px;
+ font-weight: 600;
+ }
+
+ .page-description {
+ margin: 0;
+ opacity: 0.9;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .template-section {
+ margin-bottom: 20px;
+
+ .template-header {
+ margin-bottom: 20px;
+
+ .template-title {
+ margin: 0 0 8px 0;
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .template-tip {
+ margin: 0;
+ color: #909399;
+ font-size: 13px;
+ }
+ }
+
+ .select-loading {
+ text-align: center;
+ padding: 10px;
+ color: #909399;
+
+ i {
+ margin-right: 8px;
+ }
+ }
+ }
+
+ .template-info-section {
+ margin-bottom: 20px;
+
+ .template-info {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px 0;
+
+ .info-left {
+ .template-name {
+ margin: 0 0 10px 0;
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .template-meta {
+ display: flex;
+ gap: 20px;
+ flex-wrap: wrap;
+
+ .meta-item {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ font-size: 13px;
+ color: #606266;
+
+ i {
+ font-size: 14px;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .search-section {
+ margin-bottom: 20px;
+
+ .search-container {
+ border-radius: 8px;
+
+ .el-form {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ align-items: center;
+ }
+ }
+ }
+
+ .config-content {
+ .batch-actions-card {
+ margin-bottom: 20px;
+
+ .batch-actions {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ padding: 8px 0;
+
+ .change-count {
+ color: #e6a23c;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .total-count {
+ margin-left: auto;
+ color: #909399;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .loading-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 400px;
+
+ .loading-spinner {
+ text-align: center;
+ color: #409eff;
+
+ i {
+ font-size: 24px;
+ margin-right: 8px;
+ }
+
+ span {
+ font-size: 16px;
+ }
+ }
+ }
+
+ .empty-wrapper {
+ min-height: 400px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ .empty-tip {
+ margin-top: 10px;
+ color: #909399;
+ font-size: 13px;
+ text-align: center;
+ }
+ }
+
+ .question-list {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .question-item {
+ .question-card {
+ border-radius: 8px;
+ border: 1px solid #ebeef5;
+ transition: all 0.3s ease;
+
+ &.has-changes {
+ border-color: #409eff;
+ box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
+ }
+
+ &:hover {
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+ }
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 20px;
+ padding-bottom: 20px;
+ border-bottom: 1px solid #f0f0f0;
+
+ .header-left {
+ display: flex;
+ gap: 20px;
+ flex: 1;
+
+ .question-index {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 40px;
+
+ .index-number {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ background: #409eff;
+ color: white;
+ border-radius: 50%;
+ font-size: 14px;
+ font-weight: 600;
+ margin-bottom: 8px;
+ }
+
+ .index-line {
+ width: 2px;
+ height: 100%;
+ background: #e0e0e0;
+ border-radius: 1px;
+ }
+ }
+
+ .question-basic-info {
+ flex: 1;
+
+ .question-title-section {
+ margin-bottom: 12px;
+
+ .question-topic {
+ margin: 0 0 8px 0;
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ line-height: 1.4;
+ }
+
+ .question-tags {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+ }
+
+ .question-content-section {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+
+ .content-label {
+ color: #606266;
+ font-size: 13px;
+ font-weight: 500;
+ min-width: 80px;
+ }
+
+ .content-text {
+ color: #303133;
+ font-size: 13px;
+ line-height: 1.6;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .header-right {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 8px;
+
+ .option-status {
+ .status-tag {
+ cursor: default;
+
+ i {
+ margin-right: 4px;
+ }
+ }
+ }
+ }
+ }
+
+ .config-section {
+ .config-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 20px;
+ padding: 8px 12px;
+ background: #f8f9fa;
+ border-radius: 4px;
+
+ i {
+ color: #409eff;
+ font-size: 16px;
+ }
+
+ span {
+ color: #303133;
+ font-weight: 600;
+ font-size: 14px;
+ }
+ }
+
+ .config-form {
+ .config-fields {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 20px;
+ margin-bottom: 20px;
+
+ .config-field {
+ .config-item {
+ margin-bottom: 0;
+
+ :deep(.el-form-item__label) {
+ font-weight: 500;
+ color: #606266;
+ padding-right: 12px;
+ }
+
+ .config-tip {
+ font-size: 12px;
+ color: #909399;
+ margin-top: 4px;
+ line-height: 1.4;
+ }
+ }
+ }
+ }
+
+ .current-config {
+ margin-bottom: 20px;
+ padding: 15px;
+ background: #f0f9ff;
+ border-radius: 6px;
+ border: 1px solid #d0ebff;
+
+ .config-preview {
+ .preview-item {
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 8px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .preview-label {
+ font-size: 13px;
+ color: #606266;
+ font-weight: 500;
+ min-width: 80px;
+ }
+
+ .preview-value {
+ font-size: 13px;
+ color: #303133;
+ line-height: 1.5;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .config-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-top: 20px;
+ border-top: 1px dashed #dcdfe6;
+
+ .save-status {
+ flex: 1;
+ margin-right: 20px;
+
+ .el-alert {
+ padding: 8px 16px;
+ border-radius: 4px;
+ }
+ }
+
+ .config-actions {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-shrink: 0;
+
+ .el-button {
+ min-width: 100px;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .preview-wrapper {
+ .preview-header {
+ margin-bottom: 20px;
+
+ h4 {
+ margin: 0 0 12px 0;
+ color: #303133;
+ font-size: 18px;
+ font-weight: 600;
+ }
+
+ .preview-tags {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+ }
+
+ .preview-content {
+ .preview-question {
+ margin-bottom: 20px;
+ padding: 16px;
+ background: #f8f9fa;
+ border-radius: 4px;
+ color: #606266;
+ line-height: 1.6;
+ }
+
+ .preview-options {
+ .option-item {
+ display: block;
+ margin-bottom: 12px;
+ padding: 12px;
+ border-radius: 4px;
+ border: 1px solid #ebeef5;
+ transition: all 0.3s;
+
+ &:hover {
+ background: #f5f7fa;
+ border-color: #409eff;
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+ }
+
+ .preview-textarea {
+ .el-textarea__inner {
+ resize: none;
+ }
+ }
+ }
+ }
+
+ .success-content {
+ text-align: center;
+ padding: 20px 0;
+
+ .success-icon {
+ color: #67c23a;
+ font-size: 48px;
+ margin-bottom: 20px;
+ }
+
+ .success-text {
+ font-size: 16px;
+ color: #606266;
+ margin: 0;
+ }
+ }
+}
+.option-config-wrapper {
+ .dialog-header {
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 1px solid #ebeef5;
+
+ h4 {
+ margin: 0 0 8px 0;
+ color: #303133;
+ font-size: 16px;
+ font-weight: 600;
+ }
+
+ .dialog-subtitle {
+ margin: 0;
+ color: #606266;
+ font-size: 13px;
+ line-height: 1.4;
+ }
+ }
+
+ .option-list {
+ .option-item {
+ margin-bottom: 12px;
+ padding: 12px;
+ background: #f8f9fa;
+ border-radius: 4px;
+ border: 1px solid #ebeef5;
+
+ &:hover {
+ border-color: #dcdfe6;
+ }
+
+ .option-form {
+ .option-index {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ color: #909399;
+ font-weight: 500;
+ }
+ }
+ }
+ }
+}
+@media (max-width: 768px) {
+ .question-exception-config {
+ padding: 12px;
+
+ .page-header {
+ padding: 16px;
+ margin-bottom: 16px;
+ }
+
+ .template-info {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ }
+
+ .search-card {
+ margin-bottom: 16px;
+ }
+
+ .config-content {
+ .batch-actions-card {
+ margin-bottom: 16px;
+ }
+
+ .question-item {
+ .question-card {
+ .card-header {
+ flex-direction: column;
+ gap: 12px;
+
+ .header-left {
+ flex-direction: column;
+ gap: 12px;
+
+ .question-index {
+ flex-direction: row;
+ align-items: center;
+ min-width: auto;
+
+ .index-number {
+ margin-bottom: 0;
+ margin-right: 12px;
+ }
+
+ .index-line {
+ width: 100%;
+ height: 2px;
+ }
+ }
+ }
+ }
+
+ .config-section {
+ .config-form {
+ .config-fields {
+ grid-template-columns: 1fr;
+ gap: 16px;
+ }
+
+ .current-config {
+ padding: 12px;
+ }
+
+ .config-footer {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 12px;
+
+ .save-status {
+ margin-right: 0;
+ margin-bottom: 8px;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
index cc1be67..93f0164 100644
--- a/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
+++ b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
@@ -371,6 +371,11 @@
if (!den) return '0.00';
return (num / den).toFixed(2);
},
+ // 缁煎悎寰楀垎灞曠ず锛氱洿鎺ヤ娇鐢ㄥ悗绔� avgScore锛屾牸寮忓寲涓轰袱浣嶅皬鏁�
+ formatScore(val) {
+ const n = Number(val);
+ return isNaN(n) ? '0.00' : n.toFixed(2);
+ },
// 瑙f瀽姣斾緥瀛楃涓诧細"14.29%"銆�"0"銆�"0.5" 鈫� 鏁板�硷紙鐧惧垎姣旓級锛涙棤鏁堣繑鍥� null
parsePercent(value) {
if (value == null || value === '') return null;
@@ -382,7 +387,13 @@
const arr = Array.isArray(list) ? list : (list && (list.list || list.rows)) || [];
const options = [];
let total = 0;
+ let avgScore = null;
arr.forEach((item) => {
+ // 缁煎悎寰楀垎锛氬悗绔繑鍥炵殑棰樼洰绾� avgScore锛堜笌棰樼洰鍚岀骇锛�
+ if (avgScore == null) {
+ const rawAvg = Number(item && item.avgScore);
+ if (!isNaN(rawAvg)) avgScore = rawAvg;
+ }
const details = Array.isArray(item && item.subtaskDetailRatioExportList)
? item.subtaskDetailRatioExportList
: [];
@@ -395,7 +406,7 @@
total += count;
});
});
- return { options, total };
+ return { options, total, avgScore };
},
// 鍗曢閫夐」缁熻锛堢湡瀹炴帴鍙� /smartor/serviceSubtaskDetail/sltdMydTotalByScore锛�
async fetchSingleQuestion() {
@@ -425,7 +436,7 @@
const res = await sltdMydTotalByScore(payload);
console.log('[sltdMydTotalByScore 鍗曢] code=', res && res.code, 'data=', JSON.stringify(res && res.data).slice(0, 1500));
const list = res && res.code === 200 ? res.data : [];
- const { options, total } = this.normalizeSingleQuestion(list);
+ const { options, total, avgScore } = this.normalizeSingleQuestion(list);
this.singleQuestionData = options.map((o) => ({
option: o.option,
count: o.count,
@@ -435,7 +446,7 @@
}));
this.singleQuestionMeta = {
total: total.toLocaleString(),
- score: this.scoreOfOptions(options),
+ score: this.formatScore(avgScore),
};
if (!options.length) this.notify('褰撳墠鏉′欢涓嬫殏鏃犺棰樼殑閫夐」缁熻鏁版嵁', 'warning');
} catch (e) {
diff --git a/src/views/Satisfaction/sfstatistics/components/DataOverview.vue b/src/views/Satisfaction/sfstatistics/components/DataOverview.vue
index 2cfa325..d221e0f 100644
--- a/src/views/Satisfaction/sfstatistics/components/DataOverview.vue
+++ b/src/views/Satisfaction/sfstatistics/components/DataOverview.vue
@@ -445,8 +445,13 @@
const details = pickDetails(item);
let node = map.get(title);
if (!node) {
- node = { title, type: "", options: new Map() };
+ node = { title, type: "", options: new Map(), avgScore: null };
map.set(title, node);
+ }
+ // 缁煎悎寰楀垎锛氬悗绔繑鍥炵殑棰樼洰绾� avgScore锛堜笌棰樼洰鍚岀骇锛�
+ if (node.avgScore == null) {
+ const rawAvg = Number(item && item.avgScore);
+ node.avgScore = isNaN(rawAvg) ? null : rawAvg;
}
details.forEach((d) => {
@@ -480,7 +485,7 @@
return Array.from(map.values()).map((n) => {
const options = Array.from(n.options.values());
- const item = { title: n.title, type: n.type, options };
+ const item = { title: n.title, type: n.type, options, avgScore: n.avgScore };
// 澶氶�夐锛氱敤鍚勯�夐」鏁伴噺涔嬪拰浣滀负濉姤鎬婚噺锛堟帴鍙f湭鍗曠嫭鎻愪緵浜烘锛�
if (n.type === "multiple")
item.total = options.reduce((s, o) => s + o.count, 0);
@@ -595,7 +600,8 @@
veryBadRate: this.rateOf(veryBad.count, total),
naCount: na.count,
naRate: this.rateOf(na.count, total),
- score: this.scoreOfItems(items),
+ total,
+ score: this.formatScore(q.avgScore),
};
});
@@ -609,6 +615,17 @@
});
});
const total = sum.reduce((s, it) => s + it.count, 0);
+ // 鎬昏缁煎悎寰楀垎锛氭寜鍚勯濉姤閲忓姞鏉冨钩鍧囧悇棰� avgScore
+ let totalScoreNum = 0;
+ let totalScoreDen = 0;
+ this.satisfactionQuestions.forEach((q, i) => {
+ const avg = Number(q.avgScore);
+ const qTotal = rows[i] ? rows[i].total : 0;
+ if (!isNaN(avg) && qTotal) {
+ totalScoreNum += avg * qTotal;
+ totalScoreDen += qTotal;
+ }
+ });
rows.push({
category: "鎬昏",
veryGoodCount: sum[0].count,
@@ -623,7 +640,7 @@
veryBadRate: this.rateOf(sum[4].count, total),
naCount: sum[5].count,
naRate: this.rateOf(sum[5].count, total),
- score: this.scoreOfItems(sum),
+ score: totalScoreDen ? (totalScoreNum / totalScoreDen).toFixed(2) : "0.00",
});
return rows;
},
@@ -772,6 +789,11 @@
if (!denominator) return "0.00";
return (numerator / denominator).toFixed(2);
},
+ // 缁煎悎寰楀垎灞曠ず锛氱洿鎺ヤ娇鐢ㄥ悗绔� avgScore锛屾牸寮忓寲涓轰袱浣嶅皬鏁�
+ formatScore(val) {
+ const n = Number(val);
+ return isNaN(n) ? "0.00" : n.toFixed(2);
+ },
defaultRange() {
const end = new Date();
const start = new Date();
diff --git a/src/views/followvisit/discharge/index.vue b/src/views/followvisit/discharge/index.vue
index 3531957..f99e472 100644
--- a/src/views/followvisit/discharge/index.vue
+++ b/src/views/followvisit/discharge/index.vue
@@ -586,6 +586,29 @@
prop="phone"
/>
<el-table-column
+ v-if="
+ orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�' ||
+ orgname == '涓芥按甯備腑鍖婚櫌'
+ "
+ label="鎷ㄥ彿鐘舵��"
+ width="120"
+ align="center"
+ key="isManuallyCalled"
+ prop="isManuallyCalled"
+ >
+ <template slot-scope="scope">
+ <el-tag
+ v-if="Number(scope.row.isManuallyCalled) > 0"
+ type="success"
+ :disable-transitions="false"
+ >鎷ㄩ�歿{ scope.row.isManuallyCalled }}娆�</el-tag
+ >
+ <el-tag v-else type="info" :disable-transitions="false"
+ >鏈嫧閫�</el-tag
+ >
+ </template>
+ </el-table-column>
+ <el-table-column
label="韬唤璇佸彿鐮�"
width="200"
align="center"
diff --git a/src/views/followvisit/record/detailpage/index.vue b/src/views/followvisit/record/detailpage/index.vue
index cb7e4ef..cb22dd1 100644
--- a/src/views/followvisit/record/detailpage/index.vue
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -127,6 +127,29 @@
</el-tooltip>
</template>
</el-table-column>
+ <el-table-column
+ v-if="
+ orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�' ||
+ orgname == '涓芥按甯備腑鍖婚櫌'
+ "
+ label="鎷ㄥ彿鐘舵��"
+ width="120"
+ align="center"
+ key="isManuallyCalled"
+ prop="isManuallyCalled"
+ >
+ <template slot-scope="scope">
+ <el-tag
+ v-if="Number(scope.row.isManuallyCalled) > 0"
+ type="success"
+ :disable-transitions="false"
+ >鎷ㄩ�歿{ scope.row.isManuallyCalled }}娆�</el-tag
+ >
+ <el-tag v-else type="info" :disable-transitions="false"
+ >鏈嫧閫�</el-tag
+ >
+ </template>
+ </el-table-column>
<el-table-column
prop="finishtime"
align="center"
@@ -282,6 +305,8 @@
show-overflow-tooltip
>
</el-table-column>
+
+
<el-table-column
prop="bankcardno"
@@ -1312,7 +1337,11 @@
:visible.sync="CaldialogVisible"
width="60%"
>
- <CallCenterLs ref="CallCenterLs" :initial-phone="currentPhoneNumber" />
+ <CallCenterLs
+ ref="CallCenterLs"
+ :initial-phone="currentPhoneNumber"
+ @call-connected="recordCallConnected"
+ />
</el-dialog>
</div>
</div>
@@ -2349,7 +2378,7 @@
this.CaldialogVisible = true;
return;
}
- // 涓嬫柟鏄腑鍖婚櫌鍛煎彨
+ // 涓嬫柟鏄附姘村競涓尰闄�
if (this.isSipRegistering) {
this.$message.warning("绯荤粺姝e湪鍒濆鍖栵紝璇风◢鍊�...");
return;
@@ -2379,11 +2408,15 @@
this.callStatus = status.type;
if (status.type === "connected") {
- this.currentCall = {
- phone: this.currentPhoneNumber,
- type: this.callType,
- startTime: new Date(),
- };
+ if (!this.currentCall) {
+ this.currentCall = {
+ phone: this.currentPhoneNumber,
+ type: this.callType,
+ startTime: new Date(),
+ };
+ // 涓芥按甯備腑鍖婚櫌锛氱數璇濇帴閫氬悗璁板綍鎷ㄦ墦鎴愬姛娆℃暟
+ this.recordCallConnected();
+ }
} else if (status.type === "ended" || status.type === "failed") {
this.currentCall = null;
}
@@ -2393,6 +2426,39 @@
this.$message.error(`鍛煎彨澶辫触: ${status.text}`);
}
},
+ // 鐢佃瘽鎷ㄦ墦鎴愬姛鍚庯紙鎺ラ�氾級娆℃暟 +1锛屽苟閫氳繃 Editsingletaskson 鏇存柊鏈嶅姟鏁版嵁
+ // 浠呴檺鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄笌涓芥按甯備腑鍖婚櫌
+ recordCallConnected() {
+ const allowedOrgs = ["鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�", "涓芥按甯備腑鍖婚櫌"];
+ if (!allowedOrgs.includes(this.orgname)) return;
+
+ getTaskservelist({
+ patid: this.patid,
+ subId: this.id,
+ }).then((res) => {
+ if (res.code == 200) {
+ const objson = res.rows[0].serviceSubtaskList.find(
+ (item) => item.id == this.id
+ );
+ if (!objson) return;
+ objson.isManuallyCalled = (Number(objson.isManuallyCalled) || 0) + 1;
+ Editsingletaskson(objson).then((r) => {
+ if (r.code == 200) {
+ // 鍙婃椂鏇存柊椤堕儴鏈嶅姟鍒楄〃涓庤〃鍗曚腑鐨勬嫧鍙风姸鎬�
+ const localRow = (this.logsheetlist || []).find(
+ (item) => item.id == this.id
+ );
+ if (localRow) {
+ localRow.isManuallyCalled = objson.isManuallyCalled;
+ }
+ if (this.form && this.form.id == this.id) {
+ this.form.isManuallyCalled = objson.isManuallyCalled;
+ }
+ }
+ });
+ }
+ });
+ },
// 缁撴潫褰撳墠閫氳瘽
endCurrentCall() {
if (!this.currentCall) return;
diff --git a/src/views/followvisit/tasklist/index.vue b/src/views/followvisit/tasklist/index.vue
index cc6c050..069c195 100644
--- a/src/views/followvisit/tasklist/index.vue
+++ b/src/views/followvisit/tasklist/index.vue
@@ -130,19 +130,19 @@
:show-overflow-tooltip="true"
/>
<el-table-column
- label="鎬讳换鍔�/宸查殢璁�"
+ label="鎵ц璇︽儏"
align="center"
- key="nickName"
+ key="taskDetail"
width="120"
- prop="nickName"
>
<template slot-scope="scope">
- <span
- >{{
- scope.row.wfs || scope.row.wfs == 0
- ? scope.row.wfs + scope.row.yfs
- : ""
- }}/{{ scope.row.yfs }}</span
+ <el-button
+ size="medium"
+ type="text"
+ @click="showCountDetail(scope.row)"
+ ><span class="button-xq"
+ ><i class="el-icon-s-data"></i>鎵ц璇︽儏</span
+ ></el-button
>
</template>
</el-table-column>
@@ -385,6 +385,26 @@
>
</div>
</el-dialog>
+ <!-- 浠诲姟鎵ц璇︽儏寮圭獥 -->
+ <el-dialog
+ title="浠诲姟鎵ц璇︽儏"
+ :visible.sync="countDialogVisible"
+ width="600px"
+ :before-close="handleCountClose"
+ >
+ <div v-loading="countLoading" class="count-detail">
+ <div class="count-task-name">浠诲姟鍚嶇О锛歿{ countTaskName || "-" }}</div>
+ <div class="count-grid">
+ <div v-for="f in countFields" :key="f.key" class="count-item">
+ <span class="count-label">{{ f.label }}</span>
+ <span class="count-value">{{ countVal(f) }}</span>
+ </div>
+ </div>
+ </div>
+ <span slot="footer" class="dialog-footer">
+ <el-button @click="countDialogVisible = false">鍏� 闂�</el-button>
+ </span>
+ </el-dialog>
<!-- 閫夋嫨鎮h�呭脊妗� -->
<Patient-Selection
ref="Patient"
@@ -407,6 +427,7 @@
import {
getTasklist,
delTaskInfo,
+ countByCondition,
TaskTemplateSendExecution,
scanGenerateSubtask,
goSfRelay,
@@ -450,6 +471,25 @@
qrDialogVisible: false,
qrCodeUrl: "", // 涓棿椤甸摼鎺�
qrCodeCanvas: null, // 瀛樺偍canvas寮曠敤
+ // 浠诲姟鎵ц璇︽儏寮圭獥
+ countDialogVisible: false,
+ countLoading: false,
+ countTaskName: "",
+ countData: {},
+ countFields: [
+ { key: "total", label: "浠诲姟鎬婚噺" },
+ { key: "blq", label: "寰呴鍙�" },
+ { key: "wfs", label: "鏈彂閫�" },
+ { key: "yfs", label: "宸插彂閫�", altKey: "ysf" },
+ { key: "fssb", label: "鍙戦�佸け璐�" },
+ { key: "dsf", label: "寰呴殢璁�" },
+ { key: "xsf", label: "闇�闅忚" },
+ { key: "wxsf", label: "鏃犻渶闅忚" },
+ { key: "wzx", label: "鏈墽琛�" },
+ { key: "ywc", label: "宸插畬鎴�" },
+ { key: "yc", label: "寮傚父" },
+ { key: "jg", label: "璀﹀憡" },
+ ],
// 鏃ユ湡鑼冨洿
dateRange: [],
// 宀椾綅閫夐」
@@ -1196,6 +1236,44 @@
const container = this.$refs.qrCodeContainer;
if (container) container.innerHTML = "";
},
+ // 鏌ョ湅浠诲姟鎵ц璇︽儏锛坈ountByCondition 鐩存帴杩斿洖鑱氬悎 Map锛�
+ showCountDetail(row) {
+ this.countTaskName = row.taskName || "";
+ this.countData = {};
+ this.countDialogVisible = true;
+ this.countLoading = true;
+ countByCondition({ taskid: row.taskid })
+ .then((res) => {
+ this.countData = this.normalizeCount(res || {});
+ })
+ .catch(() => {
+ this.countData = {};
+ this.$modal.msgError("鑾峰彇浠诲姟鎵ц璇︽儏澶辫触");
+ })
+ .finally(() => {
+ this.countLoading = false;
+ });
+ },
+ // 褰掍竴閿悕锛堣仛鍚� SQL 鍒悕鍙兘甯︾┖鏍硷級
+ normalizeCount(data) {
+ const out = {};
+ Object.keys(data || {}).forEach((k) => {
+ out[String(k).trim()] = data[k];
+ });
+ return out;
+ },
+ // 璇诲彇缁熻鍊硷紙key 浼樺厛锛宎ltKey 鍏滃簳锛岀己澶辨樉绀� 0锛�
+ countVal(f) {
+ const d = this.countData || {};
+ if (d[f.key] != null && d[f.key] !== "") return d[f.key];
+ if (f.altKey && d[f.altKey] != null && d[f.altKey] !== "")
+ return d[f.altKey];
+ return 0;
+ },
+ handleCountClose() {
+ this.countDialogVisible = false;
+ this.countData = {};
+ },
},
};
</script>
@@ -1358,4 +1436,35 @@
font-size: 24px;
}
}
+
+.count-detail {
+ .count-task-name {
+ font-size: 14px;
+ color: #303133;
+ font-weight: 600;
+ margin-bottom: 16px;
+ }
+ .count-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 12px;
+ }
+ .count-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 14px;
+ background: #f5f7fa;
+ border-radius: 4px;
+ .count-label {
+ font-size: 13px;
+ color: #606266;
+ }
+ .count-value {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+ }
+}
</style>
diff --git a/src/views/patient/patient/AwaitingAdmission.vue b/src/views/patient/patient/AwaitingAdmission.vue
index d2e414b..64fb662 100644
--- a/src/views/patient/patient/AwaitingAdmission.vue
+++ b/src/views/patient/patient/AwaitingAdmission.vue
@@ -54,6 +54,17 @@
<el-option label="鏈畨鎺�" :value="2"> </el-option>
</el-select>
</el-form-item>
+ <el-form-item label="搴婂彿鎺掑簭" prop="bedSort">
+ <el-select
+ v-model="queryParams.bedSort"
+ placeholder="涓嶆寜搴婂彿鎺掑簭"
+ style="width: 160px"
+ >
+ <el-option label="涓嶆寜搴婂彿鎺掑簭" :value="null"></el-option>
+ <el-option label="鎸夊簥鍙锋搴�" :value="1"></el-option>
+ <el-option label="鎸夊簥鍙峰�掑簭" :value="2"></el-option>
+ </el-select>
+ </el-form-item>
<el-row>
<el-form-item>
<el-button
@@ -704,6 +715,7 @@
pageNum: 1,
pageSize: 10,
inhospstate: "3",
+ bedSort: null,
},
// 琛ㄥ崟鏍¢獙
rules: {
@@ -893,6 +905,7 @@
this.queryParams = {
pageNum: 1,
pageSize: 10,
+ bedSort: null,
// leavehospitaldistrictcodes: [],
};
diff --git a/src/views/patient/patient/behospitalized.vue b/src/views/patient/patient/behospitalized.vue
index e35a72e..b099067 100644
--- a/src/views/patient/patient/behospitalized.vue
+++ b/src/views/patient/patient/behospitalized.vue
@@ -66,6 +66,17 @@
end-placeholder="缁撴潫鏃ユ湡"
></el-date-picker>
</el-form-item>
+ <el-form-item label="搴婂彿鎺掑簭" prop="bedSort">
+ <el-select
+ v-model="queryParams.bedSort"
+ placeholder="涓嶆寜搴婂彿鎺掑簭"
+ style="width: 160px"
+ >
+ <el-option label="涓嶆寜搴婂彿鎺掑簭" :value="null"></el-option>
+ <el-option label="鎸夊簥鍙锋搴�" :value="1"></el-option>
+ <el-option label="鎸夊簥鍙峰�掑簭" :value="2"></el-option>
+ </el-select>
+ </el-form-item>
<el-row>
<el-form-item>
@@ -767,6 +778,7 @@
pageNum: 1,
pageSize: 10,
cry: 0,
+ bedSort: null,
searchscope: 3,
scopetype: [],
leaveldeptcodes: [],
@@ -1118,6 +1130,7 @@
pageNum: 1,
pageSize: 10,
cry: 0,
+ bedSort: null,
searchscope: 3,
scopetype: [],
leaveldeptcodes: [],
diff --git a/src/views/patient/patient/hospital.vue b/src/views/patient/patient/hospital.vue
index 9726bee..9058f8a 100644
--- a/src/views/patient/patient/hospital.vue
+++ b/src/views/patient/patient/hospital.vue
@@ -77,6 +77,17 @@
end-placeholder="缁撴潫鏃ユ湡"
></el-date-picker>
</el-form-item>
+ <el-form-item label="搴婂彿鎺掑簭" prop="bedSort">
+ <el-select
+ v-model="queryParams.bedSort"
+ placeholder="涓嶆寜搴婂彿鎺掑簭"
+ style="width: 160px"
+ >
+ <el-option label="涓嶆寜搴婂彿鎺掑簭" :value="null"></el-option>
+ <el-option label="鎸夊簥鍙锋搴�" :value="1"></el-option>
+ <el-option label="鎸夊簥鍙峰�掑簭" :value="2"></el-option>
+ </el-select>
+ </el-form-item>
<el-row>
<el-form-item>
@@ -794,6 +805,7 @@
pageNum: 1,
pageSize: 10,
cry: 1,
+ bedSort: null,
searchscope: 3,
scopetype: [],
leaveldeptcodes: [],
@@ -1147,6 +1159,7 @@
pageNum: 1,
pageSize: 10,
cry: 1,
+ bedSort: null,
searchscope: 3,
scopetype: [],
leaveldeptcodes: [],
diff --git "a/\351\232\217\350\256\277\351\200\232\347\224\2509.22.zip" "b/\351\232\217\350\256\277\351\200\232\347\224\250922.zip"
similarity index 93%
rename from "\351\232\217\350\256\277\351\200\232\347\224\2509.22.zip"
rename to "\351\232\217\350\256\277\351\200\232\347\224\250922.zip"
index 08a35f9..ff5a348 100644
--- "a/\351\232\217\350\256\277\351\200\232\347\224\2509.22.zip"
+++ "b/\351\232\217\350\256\277\351\200\232\347\224\250922.zip"
Binary files differ
--
Gitblit v1.9.3