| | |
| | | <span class="meta-item"> |
| | | <i class="el-icon-s-order"></i> |
| | | 模板类型:{{ |
| | | templateForm.templateType === 1 ? "问卷模板" : "语音模板" |
| | | templateForm.templateType == 1 ? "问卷模板" : "语音模板" |
| | | }} |
| | | </span> |
| | | <span class="meta-item"> |
| | |
| | | <div class="info-right"> |
| | | <el-tag |
| | | :type=" |
| | | currentTemplateInfo.templateStatus === 1 ? 'success' : 'info' |
| | | currentTemplateInfo.templateStatus == 1 ? 'success' : 'info' |
| | | " |
| | | size="medium" |
| | | > |
| | | {{ currentTemplateInfo.templateStatus === 1 ? "启用" : "停用" }} |
| | | {{ currentTemplateInfo.templateStatus == 1 ? "启用" : "停用" }} |
| | | </el-tag> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | |
| | | <div |
| | | v-else-if="questionList.length === 0 && templateForm.templateId" |
| | | 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> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | | <div class="config-field"> |
| | | <el-form-item label="责任人工号"> |
| | | <el-input |
| | | v-model="question.exceptionConfig.dutyDeptPersonCode" |
| | | placeholder="请输入责任人工号" |
| | | @input="handleConfigChange(question)" |
| | | /> |
| | | </el-form-item> |
| | | </div> |
| | | <!-- 报备科室(多选) --> |
| | | <div class="config-field"> |
| | | <el-form-item |
| | |
| | | :closable="false" |
| | | show-icon |
| | | :effect=" |
| | | question.saveStatus.type === 'success' |
| | | ? 'dark' |
| | | : 'light' |
| | | question.saveStatus.type == 'success' ? 'dark' : 'light' |
| | | " |
| | | size="small" |
| | | /> |
| | |
| | | |
| | | <div class="option-list"> |
| | | <el-alert |
| | | v-if="!currentOptions.some((opt) => opt.isabnormal === 1)" |
| | | v-if="!currentOptions.some((opt) => opt.isabnormal == 1)" |
| | | title="请至少设置一个异常选项(标记为异常)" |
| | | type="warning" |
| | | :closable="false" |
| | |
| | | |
| | | <span slot="footer" class="dialog-footer"> |
| | | <el-button @click="optionDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="saveOptions" :loading="savingOptions"> |
| | | 保存配置 |
| | | </el-button> |
| | | <el-button type="primary" @click="saveOptions"> 保存配置 </el-button> |
| | | </span> |
| | | </el-dialog> |
| | | <!-- 题目预览对话框 --> |
| | |
| | | }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (!value || value.length === 0) { |
| | | if (!value || value.length == 0) { |
| | | callback(new Error("请至少选择一个责任科室")); |
| | | } else { |
| | | callback(); |
| | |
| | | }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (!value || value.length === 0) { |
| | | if (!value || value.length == 0) { |
| | | callback(new Error("请至少选择一个报备科室")); |
| | | } else { |
| | | callback(); |
| | |
| | | computed: { |
| | | // 根据模板类型过滤模板选项 |
| | | filteredTemplateOptions() { |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | return this.questionnaireTemplates; |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | return this.followupTemplates; |
| | | } |
| | | return []; |
| | |
| | | |
| | | // 满意度题目数量 |
| | | satisfactionQuestionsCount() { |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | return this.questionList.filter((q) => |
| | | this.questionnaireCategorys.includes(q.categoryid) |
| | | ).length; |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | return this.questionList.filter((q) => |
| | | this.voiceCategories.includes(q.scriptAssortid) |
| | | ).length; |
| | |
| | | // 筛选后的题目列表 |
| | | filteredQuestionList() { |
| | | let filtered = this.questionList; |
| | | console.log("queryParams:", this.queryParams); |
| | | console.log("questionList:", this.questionList); |
| | | |
| | | // 筛选满意度题目 |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | filtered = filtered.filter((q) => |
| | | this.questionnaireCategorys.includes(q.categoryid) |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | filtered = filtered.filter((q) => |
| | | this.voiceCategories.includes(q.scriptAssortid) |
| | | ); |
| | |
| | | }, |
| | | created() { |
| | | if (store.getters.satisfactionCategories) { |
| | | // this.questionnaireCategorys = [404, 405, 406, 10039, 10041, 10042]; |
| | | // console.log(1); |
| | | |
| | | this.questionnaireCategorys = |
| | | store.getters.satisfactionCategories.questionnaireCategorys.map( |
| | | (item) => item.categoryid |
| | |
| | | /** 根据科室编码获取科室名称 */ |
| | | getDeptName(deptCode) { |
| | | if (!deptCode) return ""; |
| | | const dept = this.deptOptions.find((d) => d.deptCode === deptCode); |
| | | const dept = this.deptOptions.find((d) => d.deptCode == deptCode); |
| | | return dept ? dept.label : deptCode; |
| | | }, |
| | | |
| | | /** 根据科室编码数组获取科室名称数组 */ |
| | | getDeptNames(deptCodes) { |
| | | if (!Array.isArray(deptCodes) || deptCodes.length === 0) return []; |
| | | if (!Array.isArray(deptCodes) || deptCodes.length == 0) return []; |
| | | return deptCodes |
| | | .map((code) => this.getDeptName(code)) |
| | | .filter((name) => name && name.trim()); |
| | |
| | | handleTemplateChange(templateId) { |
| | | if (templateId) { |
| | | const selectedTemplate = this.filteredTemplateOptions.find( |
| | | (t) => t.id === templateId |
| | | (t) => t.id == templateId |
| | | ); |
| | | if (selectedTemplate) { |
| | | this.currentTemplateInfo = { |
| | |
| | | this.loading = true; |
| | | this.questionList = []; |
| | | |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | this.loadQuestionnaireTemplateDetail(); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | this.loadFollowupTemplateDetail(); |
| | | } |
| | | } else { |
| | |
| | | this.loading = true; |
| | | this.questionList = []; |
| | | |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | this.loadQuestionnaireTemplateDetail(); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | this.loadFollowupTemplateDetail(); |
| | | } |
| | | }); |
| | |
| | | this.templateLoading = false; |
| | | this.loading = false; |
| | | |
| | | if (res.code === 200 && res.rows && res.rows.length > 0) { |
| | | if (res.code == 200 && res.rows && res.rows.length > 0) { |
| | | const templateDetail = res.rows[0]; |
| | | |
| | | // 更新模板信息 |
| | |
| | | this.templateLoading = false; |
| | | this.loading = false; |
| | | |
| | | if (res.code === 200) { |
| | | if (res.code == 200) { |
| | | const templateDetail = res.data; |
| | | |
| | | // 更新模板信息 |
| | |
| | | let exceptionConfig = { |
| | | responsibilityDept: [], // 责任科室编码数组 |
| | | reportDept: [], // 报备科室编码数组 |
| | | dutyDeptPersonCode: question.dutyDeptPersonCode || "", // 责任人工号 |
| | | }; |
| | | |
| | | // 从题目顶层字段读取数据 |
| | |
| | | |
| | | /** 配置变更处理 */ |
| | | handleConfigChange(question) { |
| | | this.$nextTick(() => { |
| | | const index = this.filteredQuestionList.findIndex( |
| | | (q) => q.id === question.id |
| | | ); |
| | | console.log(index, "index"); |
| | | |
| | | 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(); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | // 直接对比配置是否变化,不依赖表单校验(避免只改一个字段时校验不通过导致 hasChanges 无法更新) |
| | | question.hasChanges = !this.isConfigEqual( |
| | | question.exceptionConfig, |
| | | question.originalConfig |
| | | ); |
| | | this.updateChangedStatus(); |
| | | }, |
| | | |
| | | /** 比较配置是否改变 */ |
| | |
| | | .sort() |
| | | .join(",") |
| | | .toLowerCase(); |
| | | const person1 = (config1.dutyDeptPersonCode || "").trim(); |
| | | const person2 = (config2.dutyDeptPersonCode || "").trim(); |
| | | |
| | | return responsibility1 === responsibility2 && report1 === report2; |
| | | return responsibility1 == responsibility2 |
| | | && report1 == report2 |
| | | && person1 == person2; |
| | | }, |
| | | |
| | | /** 更新变更状态 */ |
| | |
| | | |
| | | /** 检查题目是否有异常选项 */ |
| | | checkHasAbnormalOptions(question) { |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | return (question.svyLibTemplateTargetoptions || []).some( |
| | | (opt) => opt.isabnormal === 1 |
| | | (opt) => opt.isabnormal == 1 |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | return (question.ivrLibaScriptTargetoptionList || []).some( |
| | | (opt) => opt.isabnormal === 1 |
| | | (opt) => opt.isabnormal == 1 |
| | | ); |
| | | } |
| | | return false; |
| | |
| | | return; |
| | | } |
| | | |
| | | const index = this.questionList.findIndex((q) => q.id === question.id); |
| | | if (index === -1) 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 { |
| | | // 获取当前模板详情 |
| | | let templateDetail; |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | // 问卷模板 |
| | | const res = await getQtemplateobj({ |
| | | svyid: this.templateForm.templateId, |
| | | }); |
| | | if (res.code !== 200 || !res.rows || res.rows.length === 0) { |
| | | 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) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | // 语音模板 |
| | | const res = await getvFollowup({ id: this.templateForm.templateId }); |
| | | if (res.code !== 200) { |
| | |
| | | // 更新题目配置 |
| | | let updatedTemplateDetail = { ...templateDetail }; |
| | | let questionsField = |
| | | this.templateForm.templateType === 1 |
| | | this.templateForm.templateType == 1 |
| | | ? "svyTemplateLibScripts" |
| | | : "ivrLibaTemplateScriptVOList"; |
| | | |
| | | const questions = updatedTemplateDetail[questionsField] || []; |
| | | const questionIndex = questions.findIndex((q) => q.id === question.id); |
| | | const questionIndex = questions.findIndex((q) => q.id == question.id); |
| | | |
| | | if (questionIndex === -1) { |
| | | if (questionIndex == -1) { |
| | | throw new Error("未找到题目"); |
| | | } |
| | | |
| | |
| | | dutyDeptName: responsibilityDeptNames.join(","), |
| | | reportDeptCode: question.exceptionConfig.reportDept.join(","), |
| | | reportDeptName: reportDeptNames.join(","), |
| | | dutyDeptPersonCode: question.exceptionConfig.dutyDeptPersonCode || "", |
| | | }; |
| | | |
| | | // 如果需要,也更新选项数据 |
| | | if (question.hasChanges && this.templateForm.templateType === 1) { |
| | | if (question.hasChanges && this.templateForm.templateType == 1) { |
| | | questions[questionIndex].svyLibTemplateTargetoptions = |
| | | question.svyLibTemplateTargetoptions || []; |
| | | } else if ( |
| | | question.hasChanges && |
| | | this.templateForm.templateType === 2 |
| | | ) { |
| | | } else if (question.hasChanges && this.templateForm.templateType == 2) { |
| | | questions[questionIndex].ivrLibaScriptTargetoptionList = |
| | | question.ivrLibaScriptTargetoptionList || []; |
| | | } |
| | |
| | | |
| | | // 保存模板 |
| | | let response; |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | response = await compileQtemplate({ |
| | | ...updatedTemplateDetail, |
| | | id: this.templateForm.templateId, |
| | |
| | | }); |
| | | } |
| | | |
| | | if (response.code === 200) { |
| | | if (response.code == 200) { |
| | | this.handleSaveSuccess(question); |
| | | } else { |
| | | throw new Error(response.msg || "保存失败"); |
| | |
| | | question.dutyDeptName = responsibilityDeptNames.join(","); |
| | | question.reportDeptCode = question.exceptionConfig.reportDept.join(","); |
| | | question.reportDeptName = reportDeptNames.join(","); |
| | | question.dutyDeptPersonCode = question.exceptionConfig.dutyDeptPersonCode || ""; |
| | | |
| | | // 更新原始配置 |
| | | question.originalConfig = JSON.parse( |
| | |
| | | |
| | | // 获取有变更的题目 |
| | | const changedQuestions = this.questionList.filter((q) => q.hasChanges); |
| | | if (changedQuestions.length === 0) { |
| | | if (changedQuestions.length == 0) { |
| | | this.$message.info("没有需要保存的配置变更"); |
| | | return; |
| | | } |
| | |
| | | const successCount = results.filter((r) => r.success).length; |
| | | const failCount = results.length - successCount; |
| | | |
| | | if (failCount === 0) { |
| | | if (failCount == 0) { |
| | | this.saveSuccessVisible = true; |
| | | this.$message.success(`成功保存 ${successCount} 个配置`); |
| | | } else { |
| | |
| | | this.editingQuestion = question; |
| | | |
| | | // 保存原始选项的快照 |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | this.editingQuestion.originalOptions = JSON.parse( |
| | | JSON.stringify(question.svyLibTemplateTargetoptions || []) |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | this.editingQuestion.originalOptions = JSON.parse( |
| | | JSON.stringify(question.ivrLibaScriptTargetoptionList || []) |
| | | ); |
| | | } |
| | | |
| | | // 复制选项数据 |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | this.currentOptions = JSON.parse( |
| | | JSON.stringify(question.svyLibTemplateTargetoptions || []) |
| | | ).map((opt, index) => ({ |
| | |
| | | targetvalue: opt.optioncontent || "", |
| | | isabnormal: opt.isabnormal || 0, |
| | | })); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | this.currentOptions = JSON.parse( |
| | | JSON.stringify(question.ivrLibaScriptTargetoptionList || []) |
| | | ).map((opt, index) => ({ |
| | |
| | | // 验证必填项 |
| | | for (let i = 0; i < this.currentOptions.length; i++) { |
| | | const option = this.currentOptions[i]; |
| | | if (!option.targetvalue || option.targetvalue.trim() === "") { |
| | | if (!option.targetvalue || option.targetvalue.trim() == "") { |
| | | this.$message.warning(`第 ${i + 1} 个选项内容不能为空`); |
| | | return; |
| | | } |
| | |
| | | |
| | | // 检查是否有异常选项 |
| | | const hasAbnormal = this.currentOptions.some( |
| | | (opt) => opt.isabnormal === 1 |
| | | (opt) => opt.isabnormal == 1 |
| | | ); |
| | | |
| | | if (!hasAbnormal) { |
| | |
| | | // 判断选项是否发生变化 |
| | | let isOptionsChanged = false; |
| | | |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | const originalOptions = |
| | | this.editingQuestion.svyLibTemplateTargetoptions || []; |
| | | isOptionsChanged = this.checkOptionsChanged( |
| | |
| | | this.currentOptions, |
| | | "questionnaire" |
| | | ); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | const originalOptions = |
| | | this.editingQuestion.ivrLibaScriptTargetoptionList || []; |
| | | isOptionsChanged = this.checkOptionsChanged( |
| | |
| | | } |
| | | |
| | | // 保存逻辑 - 更新题目对象的选项数据 |
| | | if (this.templateForm.templateType === 1) { |
| | | if (this.templateForm.templateType == 1) { |
| | | this.editingQuestion.svyLibTemplateTargetoptions = |
| | | this.currentOptions.map((opt) => ({ |
| | | ...opt, |
| | |
| | | targetvalue: undefined, |
| | | isNew: undefined, |
| | | })); |
| | | } else if (this.templateForm.templateType === 2) { |
| | | } else if (this.templateForm.templateType == 2) { |
| | | this.editingQuestion.ivrLibaScriptTargetoptionList = |
| | | this.currentOptions.map((opt) => ({ |
| | | ...opt, |
| | |
| | | const original = originalOptions[i]; |
| | | const current = newOptions[i]; |
| | | |
| | | if (templateType === "questionnaire") { |
| | | if (templateType == "questionnaire") { |
| | | // 问卷模板比较 |
| | | if ( |
| | | original.optioncontent !== current.targetvalue || |
| | |
| | | ) { |
| | | return true; |
| | | } |
| | | } else if (templateType === "voice") { |
| | | } else if (templateType == "voice") { |
| | | // 语音模板比较 |
| | | if ( |
| | | original.targetvalue !== current.targetvalue || |
| | |
| | | }, |
| | | /** 获取异常选项统计 */ |
| | | getAbnormalStats(question) { |
| | | if (this.templateForm.templateType === 1) { |
| | | 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, |
| | | 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) { |
| | | } 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, |
| | | 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 }; |