| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="satisfaction-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> |
| | | <span class="meta-item"> |
| | | <i class="el-icon-star-on"></i> |
| | | 满æåº¦é¢ç®ï¼{{ satisfactionQuestionsCount }} |
| | | </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-if="questionList.length > 0" class="search-section"> |
| | | <el-card shadow="never" class="search-container"> |
| | | <el-form :model="queryParams" :inline="true" size="medium"> |
| | | <el-form-item label="é®é¢ä¸»é¢"> |
| | | <el-input |
| | | v-model="queryParams.scriptTopic" |
| | | placeholder="请è¾å
¥é®é¢ä¸»é¢" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="é®é¢å
容"> |
| | | <el-input |
| | | v-model="queryParams.scriptContent" |
| | | placeholder="请è¾å
¥é®é¢å
容" |
| | | clearable |
| | | @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"> |
| | | è¯·éæ©å
¶ä»æ¨¡æ¿ææ£æ¥æ¨¡æ¿ä¸æ¯å¦å
嫿»¡æåº¦ç±»åé¢ç®ï¼åç±»ID: |
| | | 404,405,406ï¼ |
| | | </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"> |
| | | <!-- 责任ç§å®¤ï¼å¤éï¼ --> |
| | | <div class="config-field"> |
| | | <el-form-item |
| | | label="责任ç§å®¤" |
| | | prop="responsibilityDept" |
| | | class="config-item" |
| | | > |
| | | <el-select |
| | | v-model="question.exceptionConfig.responsibilityDept" |
| | | 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 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">责任ç§å®¤ï¼</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" :loading="savingOptions"> |
| | | ä¿åé
ç½® |
| | | </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 { |
| | | compileissue, |
| | | compileQtemplate, |
| | | compileFollowup, |
| | | getQtemplatelist, |
| | | getFollowuplist, |
| | | getvFollowup, |
| | | getQtemplateobj, |
| | | selectInfoByConditiony, |
| | | } from "@/api/AiCentre/index"; |
| | | import { deptTreeSelect } from "@/api/system/user"; |
| | | import store from "@/store"; |
| | | import Pagination from "@/components/Pagination"; |
| | | |
| | | export default { |
| | | name: "SatisfactionExceptionConfig", |
| | | 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: "æ£å¸¸", value: 0, type: "success" }, |
| | | { label: "å¼å¸¸", value: 1, type: "danger" }, |
| | | { label: "è¦å", value: 2, type: "warning" }, |
| | | ], |
| | | // 模æ¿é项 |
| | | questionnaireTemplates: [], // é®å·æ¨¡æ¿å表 |
| | | followupTemplates: [], // è¯é³æ¨¡æ¿å表 |
| | | templateOptionsLoading: false, |
| | | |
| | | // å½å模æ¿ä¿¡æ¯ |
| | | currentTemplateInfo: null, |
| | | templateLoading: false, |
| | | |
| | | // æ¥è¯¢åæ° |
| | | queryParams: { |
| | | scriptTopic: "", |
| | | scriptContent: "", |
| | | }, |
| | | |
| | | // æ°æ®å表 |
| | | 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, |
| | | |
| | | // 满æåº¦åç±»ID |
| | | satisfactionCategoryIds: ["404", "405", "406", "10039", "10041", "10042"], |
| | | questionnaireCategorys: [], |
| | | voiceCategories: [], |
| | | // 表åéªè¯è§å |
| | | 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 []; |
| | | }, |
| | | |
| | | // 满æåº¦é¢ç®æ°é |
| | | satisfactionQuestionsCount() { |
| | | if (this.templateForm.templateType === 1) { |
| | | return this.questionList.filter((q) => |
| | | this.questionnaireCategorys.includes(q.categoryid) |
| | | ).length; |
| | | } else if (this.templateForm.templateType === 2) { |
| | | return this.questionList.filter((q) => |
| | | this.voiceCategories.includes(q.scriptAssortid) |
| | | ).length; |
| | | } |
| | | }, |
| | | // æ£æ¥é¢ç®æ¯å¦æå¼å¸¸é项 |
| | | hasAbnormalOption(question) { |
| | | return (question) => { |
| | | if (!question) return false; |
| | | |
| | | // é®å·æ¨¡æ¿ |
| | | if (this.templateForm.templateType === 1) { |
| | | const options = question.svyLibTemplateTargetoptions || []; |
| | | return options.some((opt) => opt.isabnormal === 1); |
| | | } |
| | | // è¯é³æ¨¡æ¿ |
| | | else if (this.templateForm.templateType === 2) { |
| | | const options = question.ivrLibaScriptTargetoptionList || []; |
| | | return options.some((opt) => opt.isabnormal === 1); |
| | | } |
| | | |
| | | return false; |
| | | }; |
| | | }, |
| | | // çéåçé¢ç®å表 |
| | | filteredQuestionList() { |
| | | let filtered = this.questionList; |
| | | console.log(this.questionnaireCategorys); |
| | | |
| | | // çéæ»¡æåº¦é¢ç® |
| | | if (this.templateForm.templateType === 1) { |
| | | filtered = filtered.filter((q) => |
| | | this.questionnaireCategorys.includes(q.categoryid) |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | filtered = filtered.filter((q) => |
| | | this.voiceCategories.includes(q.scriptAssortid) |
| | | ); |
| | | } |
| | | |
| | | // åºç¨æç´¢æ¡ä»¶ |
| | | 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() { |
| | | if (store.getters.satisfactionCategories) { |
| | | this.questionnaireCategorys = |
| | | store.getters.satisfactionCategories.questionnaireCategorys.map( |
| | | (item) => item.categoryid |
| | | ); |
| | | this.voiceCategories = |
| | | store.getters.satisfactionCategories.voiceCategories.map( |
| | | (item) => item.categoryid |
| | | ); |
| | | } |
| | | 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) => { |
| | | if (res.code === 200) { |
| | | this.questionnaireTemplates = (res.rows || []).map((item) => ({ |
| | | id: item.svyid, |
| | | templateName: item.svyname, |
| | | isavailable: item.isavailable, |
| | | })); |
| | | } 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) => { |
| | | if (res.code === 200) { |
| | | this.followupTemplates = (res.rows || []).map((item) => ({ |
| | | id: item.id, |
| | | templateName: item.templateName, |
| | | isavailable: item.isavailable, |
| | | })); |
| | | } 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) => { |
| | | // è§£æè´£ä»»ç§å®¤åæ¥å¤ç§å®¤ |
| | | let exceptionConfig = { |
| | | responsibilityDept: [], // 责任ç§å®¤ç¼ç æ°ç» |
| | | reportDept: [], // æ¥å¤ç§å®¤ç¼ç æ°ç» |
| | | }; |
| | | |
| | | // ä»é¢ç®é¡¶å±åæ®µè¯»åæ°æ® |
| | | 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) { |
| | | this.$nextTick(() => { |
| | | const index = this.filteredQuestionList.findIndex( |
| | | (q) => q.id === question.id |
| | | ); |
| | | if (index !== -1) { |
| | | const formRef = this.$refs.configForm && this.$refs.configForm[index]; |
| | | if (formRef) { |
| | | formRef.validate((valid) => { |
| | | if (valid) { |
| | | 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(); |
| | | |
| | | return responsibility1 === responsibility2 && report1 === report2; |
| | | }, |
| | | |
| | | /** æ´æ°åæ´ç¶æ */ |
| | | updateChangedStatus() { |
| | | const changedItems = this.questionList.filter((q) => q.hasChanges); |
| | | this.changedCount = changedItems.length; |
| | | this.hasChanges = changedItems.length > 0; |
| | | }, |
| | | |
| | | /** ä¿åå个é¢ç®é
ç½® */ |
| | | async saveSingleConfig(question) { |
| | | if (!question.hasChanges) return; |
| | | |
| | | const index = this.filteredQuestionList.findIndex( |
| | | (q) => q.id === question.id |
| | | ); |
| | | console.log(index, "filteredQuestionList"); |
| | | |
| | | if (index === -1) return; |
| | | |
| | | const formRef = this.$refs.configForm && this.$refs.configForm[index]; |
| | | if (!formRef) return; |
| | | |
| | | const valid = await formRef.validate(); |
| | | if (!valid) { |
| | | this.$message.warning("请å
宿å¿
填项"); |
| | | return; |
| | | } |
| | | |
| | | question.saving = true; |
| | | question.saveStatus = null; |
| | | |
| | | try { |
| | | // è·åå½å模æ¿è¯¦æ
|
| | | 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(","), |
| | | }; |
| | | |
| | | // æ´æ°æ¨¡æ¿ |
| | | 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.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; |
| | | |
| | | this.$confirm("ç¡®å®è¦ä¿åææä¿®æ¹è¿çé
ç½®åï¼", "æ¹éä¿å", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(async () => { |
| | | this.batchSaving = true; |
| | | |
| | | const changedQuestions = this.questionList.filter( |
| | | (q) => q.hasChanges |
| | | ); |
| | | const results = []; |
| | | |
| | | for (const question of changedQuestions) { |
| | | try { |
| | | await this.saveSingleConfig(question); |
| | | results.push({ |
| | | id: question.id, |
| | | success: |
| | | !question.hasChanges && |
| | | question.saveStatus?.type === "success", |
| | | }); |
| | | } catch (error) { |
| | | results.push({ |
| | | id: question.id, |
| | | success: false, |
| | | }); |
| | | } |
| | | } |
| | | |
| | | 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} 个` |
| | | ); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | this.batchSaving = false; |
| | | }); |
| | | }, |
| | | |
| | | /** é¢è§é¢ç® */ |
| | | previewQuestion(question) { |
| | | this.currentPreview = { ...question }; |
| | | this.previewAnswer = ""; |
| | | this.previewVisible = true; |
| | | }, |
| | | /** æ£æ¥é¢ç®æ¯å¦æå¼å¸¸é项 */ |
| | | checkHasAbnormalOptions(question) { |
| | | if (this.templateForm.templateType === 1) { |
| | | return (question.svyLibTemplateTargetoptions || []).some( |
| | | (opt) => opt.isabnormal === 1 |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | return (question.ivrLibaScriptTargetoptionList || []).some( |
| | | (opt) => opt.isabnormal === 1 |
| | | ); |
| | | } |
| | | return false; |
| | | }, |
| | | |
| | | /** æå¼é项管çå¯¹è¯æ¡ */ |
| | | openOptionDialog(question) { |
| | | this.editingQuestion = question; |
| | | |
| | | // å¤å¶éé¡¹æ°æ® |
| | | if (this.templateForm.templateType === 1) { |
| | | this.currentOptions = JSON.parse( |
| | | JSON.stringify(question.svyLibTemplateTargetoptions || []) |
| | | ).map((opt) => ({ |
| | | ...opt, |
| | | id: opt.id, |
| | | targetvalue: opt.optioncontent || "", |
| | | isabnormal: opt.isabnormal || 0, |
| | | })); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | this.currentOptions = JSON.parse( |
| | | JSON.stringify(question.ivrLibaScriptTargetoptionList || []) |
| | | ).map((opt) => ({ |
| | | ...opt, |
| | | targetvalue: opt.targetvalue || "", |
| | | isabnormal: opt.isabnormal || 0, |
| | | })); |
| | | } |
| | | |
| | | this.optionDialogVisible = true; |
| | | }, |
| | | |
| | | /** æ·»å æ°é项 */ |
| | | addNewOption() { |
| | | this.currentOptions.push({ |
| | | id: Date.now(), // 临æ¶ID |
| | | targetvalue: "", |
| | | isabnormal: 0, |
| | | isNew: true, |
| | | }); |
| | | }, |
| | | |
| | | /** å é¤é项 */ |
| | | removeOption(index) { |
| | | this.currentOptions.splice(index, 1); |
| | | }, |
| | | |
| | | /** ä¿åé项é
ç½® */ |
| | | async saveOptions() { |
| | | try { |
| | | // éªè¯å¿
填项 |
| | | for (const option of this.currentOptions) { |
| | | if (!option.targetvalue || option.targetvalue.trim() === "") { |
| | | this.$message.warning("è¯·å¡«åææé项å
容"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦æå¼å¸¸é项 |
| | | const hasAbnormal = this.currentOptions.some( |
| | | (opt) => opt.isabnormal === 1 |
| | | ); |
| | | |
| | | if (!hasAbnormal) { |
| | | this.$message.warning("请è³å°è®¾ç½®ä¸ä¸ªå¼å¸¸é项ï¼isabnormal=1ï¼"); |
| | | return; |
| | | } |
| | | |
| | | // ä¿åé»è¾ - æ´æ°é¢ç®å¯¹è±¡çéé¡¹æ°æ® |
| | | if (this.templateForm.templateType === 1) { |
| | | this.editingQuestion.svyLibTemplateTargetoptions = |
| | | this.currentOptions.map((opt) => ({ |
| | | ...opt, |
| | | optioncontent: opt.targetvalue, |
| | | isabnormal: opt.isabnormal, |
| | | })); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | this.editingQuestion.ivrLibaScriptTargetoptionList = |
| | | this.currentOptions; |
| | | } |
| | | |
| | | // 触åé
ç½®åæ´æ£æ¥ |
| | | this.handleConfigChange(this.editingQuestion); |
| | | |
| | | this.$message.success("é项é
ç½®ä¿åæå"); |
| | | this.optionDialogVisible = false; |
| | | } catch (error) { |
| | | console.error("ä¿åé项失败:", error); |
| | | this.$message.error("ä¿åé项失败"); |
| | | } |
| | | }, |
| | | |
| | | /** ä¿®æ¹ä¿åå个é¢ç®é
ç½®æ¹æ³ï¼æ·»å å¼å¸¸éé¡¹æ£æ¥ */ |
| | | async saveSingleConfig(question) { |
| | | // æ£æ¥æ¯å¦æå¼å¸¸é项 |
| | | if (!this.checkHasAbnormalOptions(question)) { |
| | | this.$confirm("该é¢ç®æ²¡æè®¾ç½®å¼å¸¸éé¡¹ï¼æ¯å¦å
é
ç½®é项ï¼", "æç¤º", { |
| | | confirmButtonText: "å»é
ç½®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | this.openOptionDialog(question); |
| | | }) |
| | | .catch(() => {}); |
| | | return; |
| | | } |
| | | |
| | | // åæçä¿åé»è¾... |
| | | if (!question.hasChanges) return; |
| | | |
| | | const index = this.filteredQuestionList.findIndex( |
| | | (q) => q.id === question.id |
| | | ); |
| | | |
| | | if (index === -1) return; |
| | | |
| | | const formRef = this.$refs.configForm && this.$refs.configForm[index]; |
| | | if (!formRef) return; |
| | | |
| | | const valid = await formRef.validate(); |
| | | if (!valid) { |
| | | this.$message.warning("请å
宿å¿
填项"); |
| | | return; |
| | | } |
| | | |
| | | // ç»§ç»åæçä¿åé»è¾... |
| | | question.saving = true; |
| | | question.saveStatus = null; |
| | | |
| | | try { |
| | | // ... åæçä¿åé»è¾ä¸å |
| | | } catch (error) { |
| | | // ... é误å¤çä¸å |
| | | } finally { |
| | | question.saving = false; |
| | | } |
| | | }, |
| | | |
| | | /** æ¹éä¿åæ¶ä¹è¦æ£æ¥ */ |
| | | async handleBatchSave() { |
| | | if (!this.hasChanges || this.batchSaving) return; |
| | | |
| | | // æ£æ¥æææåæ´çé¢ç®æ¯å¦é½æå¼å¸¸é项 |
| | | const changedQuestions = this.questionList.filter((q) => q.hasChanges); |
| | | const questionsWithoutAbnormal = changedQuestions.filter( |
| | | (q) => !this.checkHasAbnormalOptions(q) |
| | | ); |
| | | |
| | | if (questionsWithoutAbnormal.length > 0) { |
| | | this.$confirm( |
| | | `æ ${questionsWithoutAbnormal.length} 个é¢ç®æ²¡æè®¾ç½®å¼å¸¸é项ï¼è¯·å
é
ç½®éé¡¹ãæ¯å¦ç»§ç»ï¼`, |
| | | "æç¤º", |
| | | { |
| | | confirmButtonText: "ç»§ç»", |
| | | cancelButtonText: "å»é
ç½®", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | // ç»§ç»æ§è¡æ¹éä¿å |
| | | this.executeBatchSave(changedQuestions); |
| | | }) |
| | | .catch(() => { |
| | | // å¯ä»¥å¨è¿é跳转å°ç¬¬ä¸ä¸ªæ²¡æå¼å¸¸é项çé¢ç® |
| | | if (questionsWithoutAbnormal.length > 0) { |
| | | this.openOptionDialog(questionsWithoutAbnormal[0]); |
| | | } |
| | | }); |
| | | } else { |
| | | this.executeBatchSave(changedQuestions); |
| | | } |
| | | }, |
| | | |
| | | /** æ§è¡æ¹éä¿å */ |
| | | async executeBatchSave(changedQuestions) { |
| | | this.$confirm("ç¡®å®è¦ä¿åææä¿®æ¹è¿çé
ç½®åï¼", "æ¹éä¿å", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(async () => { |
| | | this.batchSaving = true; |
| | | |
| | | const results = []; |
| | | for (const question of changedQuestions) { |
| | | try { |
| | | // è¿éè°ç¨ä¿®æ¹åçsaveSingleConfigæ¹æ³ |
| | | await this.saveSingleConfig(question); |
| | | results.push({ |
| | | id: question.id, |
| | | success: |
| | | !question.hasChanges && |
| | | question.saveStatus?.type === "success", |
| | | }); |
| | | } catch (error) { |
| | | results.push({ |
| | | id: question.id, |
| | | success: false, |
| | | }); |
| | | } |
| | | } |
| | | |
| | | this.batchSaving = false; |
| | | // ... åç»å¤çä¸å |
| | | }) |
| | | .catch(() => { |
| | | this.batchSaving = 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> |
| | | .satisfaction-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) { |
| | | .satisfaction-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> |