WXL (wul)
13 小时以前 c65b90aaa3477a90ebc325024927d80227c0c841
测试完成
已修改4个文件
709 ■■■■ 文件已修改
src/views/Satisfaction/configurationmyd/batch.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/dispose.vue 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/index.vue 384 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/batch.vue
@@ -59,7 +59,7 @@
                <el-option label="已处理" :value="'1'" />
              </el-select>
            </el-form-item>
            <el-form-item label="模板类型">
            <el-form-item label="满意度类型">
              <el-select
                v-model="filterParams.templateType"
                placeholder="请选择模板类型"
@@ -139,23 +139,23 @@
                <div class="patient-row">
                  <div class="patient-item">
                    <span class="label">姓名:</span>
                    <span class="value">{{ row.patientName }}</span>
                    <span class="value">{{ row.patdescJson.sendname }}</span>
                  </div>
                  <div class="patient-item">
                    <span class="label">性别:</span>
                    <span class="value">{{
                      row.gender === 1 ? "男" : "女"
                      row.patdescJson.sex
                    }}</span>
                  </div>
                  <div class="patient-item">
                    <span class="label">年龄:</span>
                    <span class="value">{{ row.age }}岁</span>
                    <span class="value">{{ row.patdescJson.age }}岁</span>
                  </div>
                </div>
                <div class="patient-row">
                  <div class="patient-item full-width">
                    <span class="label">电话:</span>
                    <span class="value">{{ row.phone }}</span>
                    <span class="value">{{ row.patdescJson.phone }}</span>
                  </div>
                </div>
              </div>
@@ -484,6 +484,7 @@
<script>
import DetailsAnomaly from "./components/DetailsAnomaly.vue";
import { tracelist, traceedit } from "@/api/AiCentre/index";
import dayjs from "dayjs";
import { deptTreeSelect } from "@/api/system/user";
export default {
@@ -512,8 +513,8 @@
      filterParams: {
        todeptcode: "",
        handleFlag: "",
        templateType: "",
        scriptid: null,
        templateType: null,
        scriptids: null,
        pageNum: 1,
        pageSize: 10,
      },
@@ -598,13 +599,18 @@
  created() {
    // 从路由参数获取问题ID
    if (this.$route.query.questionId) {
      this.filterParams.scriptid = this.$route.query.questionId || null;
      this.filterParams.scriptids = null;
    } else if (this.$route.query.questionIds) {
      this.filterParams.scriptids = this.$route.query.questionIds;
      this.filterParams.scriptid=null;
    }
    this.filterParams.scriptids = this.$route.query.questionId || this.$route.query.questionIds||null;
    // if (this.$route.query.questionId) {
    // } else if (this.$route.query.questionIds) {
    //   console.log(
    //     this.$route.query.questionIds,
    //     "this.$route.query.questionIds"
    //   );
      this.filterParams.templateType = Number(this.$route.query.type)||null;
    //   this.filterParams.scriptid = null;
    // }
    this.hasQualityPermission = this.checkQualityPermission();
  },
@@ -745,8 +751,11 @@
        params.templateType = this.filterParams.templateType;
      }
      if (this.filterParams.scriptid) {
        params.scriptid = this.filterParams.scriptid;
      // if (this.filterParams.scriptid) {
      //   params.scriptid = this.filterParams.scriptid;
      // }
      if (this.filterParams.scriptids) {
        params.scriptids = this.filterParams.scriptids.split(",");
      }
      return params;
@@ -789,7 +798,7 @@
        todeptcode: "",
        handleFlag: "",
        templateType: "",
        scriptid: null, // 保留问题ID
        scriptids: null, // 保留问题ID
        pageNum: 1,
        pageSize: 10,
      };
@@ -833,7 +842,7 @@
      // 生成弹框标题
      let title = "异常反馈详情";
      if (row.patdesc) {
        const patientName = row.patdesc.split("|")[0];
        const patientName = row.patdescJson.sendname;
        if (patientName) {
          title = `${patientName} - ${title}`;
        }
@@ -888,6 +897,8 @@
            handleresult: this.processForm.handleresult,
            handledesc: this.processForm.handledesc,
            finaloption: this.processForm.finaloption,
            handleBy: this.$store.state.user.nickName,
            handleTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
            // 将数组转换为逗号分隔的字符串
            ccdepts: Array.isArray(this.processForm.ccdepts)
              ? this.processForm.ccdepts.join(",")
@@ -1141,7 +1152,7 @@
          .patient-item {
            flex: 1;
            display: flex;
            justify-content: space-between;
            justify-content: flex-start;
            align-items: center;
            padding: 0 5px;
@@ -1175,7 +1186,7 @@
        .info-item {
          display: flex;
          justify-content: space-between;
          justify-content: flex-start;
          align-items: center;
          margin-bottom: 5px;
          padding: 2px 0;
@@ -1188,7 +1199,7 @@
          .value {
            color: #333;
            font-weight: 500;
            text-align: right;
            // text-align: right;
            flex: 1;
            &.time {
src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
@@ -73,12 +73,6 @@
            <span class="value">{{ currentRecord.handleBy || '未处理' }}</span>
          </div>
        </el-col>
        <el-col :span="24" v-if="currentRecord.patdesc">
          <div class="info-item">
            <span class="label">患者信息:</span>
            <span class="value">{{ currentRecord.patdesc }}</span>
          </div>
        </el-col>
        <el-col :span="8" v-if="currentRecord.handleresult">
          <div class="info-item">
            <span class="label">处理结果:</span>
src/views/Satisfaction/configurationmyd/dispose.vue
@@ -21,7 +21,7 @@
        >
          <el-form-item label="满意度类型" prop="templateid">
            <el-select
              v-model="queryParams.templateid"
              v-model="queryParams.templateType"
              placeholder="请选择模板"
              clearable
              style="width: 200px"
@@ -48,7 +48,7 @@
              <el-option
                v-for="dept in deptList"
                :key="dept.deptCode"
                :label="dept.deptName"
                :label="dept.label"
                :value="dept.deptCode"
              />
            </el-select>
@@ -96,11 +96,7 @@
          >
            批量处理 ({{ selectedIds.length }})
          </el-button>
          <el-button
            type="info"
            icon="el-icon-download"
            @click="handleExport"
          >
          <el-button type="info" icon="el-icon-download" @click="handleExport">
            导出异常数据
          </el-button>
          <el-button
@@ -120,12 +116,14 @@
        <el-col :span="8">
          <el-card shadow="never" class="stat-card">
            <div class="stat-content">
              <div class="stat-icon" style="background: #f0f9ff;">
                <i class="el-icon-s-claim" style="color: #5788FE;"></i>
              <div class="stat-icon" style="background: #f0f9ff">
                <i class="el-icon-s-claim" style="color: #5788fe"></i>
              </div>
              <div class="stat-info">
                <div class="stat-title">总异常数量</div>
                <div class="stat-value">{{ overviewData.totalExceptionCount }}</div>
                <div class="stat-value">
                  {{ overviewData.totalExceptionCount }}
                </div>
              </div>
            </div>
          </el-card>
@@ -133,8 +131,8 @@
        <el-col :span="8">
          <el-card shadow="never" class="stat-card">
            <div class="stat-content">
              <div class="stat-icon" style="background: #f0f9ff;">
                <i class="el-icon-s-flag" style="color: #E6A23C;"></i>
              <div class="stat-icon" style="background: #f0f9ff">
                <i class="el-icon-s-flag" style="color: #e6a23c"></i>
              </div>
              <div class="stat-info">
                <div class="stat-title">待处理异常</div>
@@ -146,8 +144,8 @@
        <el-col :span="8">
          <el-card shadow="never" class="stat-card">
            <div class="stat-content">
              <div class="stat-icon" style="background: #f0f9ff;">
                <i class="el-icon-check" style="color: #67C23A;"></i>
              <div class="stat-icon" style="background: #f0f9ff">
                <i class="el-icon-check" style="color: #67c23a"></i>
              </div>
              <div class="stat-info">
                <div class="stat-title">已处理异常</div>
@@ -170,11 +168,7 @@
          @selection-change="handleSelectionChange"
          class="exception-table"
        >
          <el-table-column
            type="selection"
            width="55"
            align="center"
          />
          <el-table-column type="selection" width="55" align="center" />
          <el-table-column
            label="序号"
@@ -197,7 +191,7 @@
                    size="mini"
                    :type="getTemplateTypeTag(row.templateType)"
                  >
                    {{ row.templateType === 1 ? '语音模板' : '问卷模板' }}
                    {{ row.templateType === 1 ? "语音模板" : "问卷模板" }}
                  </el-tag>
                </div>
              </div>
@@ -225,43 +219,45 @@
            </template>
          </el-table-column>
          <el-table-column
            label="填写情况"
            width="200"
            align="center"
          >
          <el-table-column label="填写情况" width="200" align="center">
            <template slot-scope="{ row }">
              <div class="fill-statistics">
                <div class="stat-item">
                  <span class="stat-label">有效填写:</span>
                  <span class="stat-value">{{ row.fillSituation.effectiveFillNum }}</span>
                  <span class="stat-value">{{
                    row.fillSituation.effectiveFillNum
                  }}</span>
                </div>
                <div class="stat-item">
                  <span class="stat-label">异常填写:</span>
                  <span class="stat-value exception-count">{{ row.fillSituation.exceptionFillNum }}</span>
                  <span class="stat-value exception-count">{{
                    row.fillSituation.exceptionFillNum
                  }}</span>
                </div>
              </div>
            </template>
          </el-table-column>
          <el-table-column
            label="异常任务"
            width="280"
            align="center"
          >
          <el-table-column label="异常任务" width="280" align="center">
            <template slot-scope="{ row }">
              <div class="exception-tasks">
                <div class="task-category">
                  <div class="task-title">已处理</div>
                  <div class="task-count processed">{{ row.exceptionQuesNum.yesDeal }}</div>
                  <div class="task-count processed">
                    {{ row.exceptionQuesNum.yesDeal }}
                  </div>
                </div>
                <div class="task-category">
                  <div class="task-title">待处理</div>
                  <div class="task-count pending">{{ row.exceptionQuesNum.noDeal }}</div>
                  <div class="task-count pending">
                    {{ row.exceptionQuesNum.noDeal }}
                  </div>
                </div>
                <div class="task-category">
                  <div class="task-title">异常总数</div>
                  <div class="task-count total">{{ row.exceptionQuesNum.all }}</div>
                  <div class="task-count total">
                    {{ row.exceptionQuesNum.all }}
                  </div>
                </div>
              </div>
            </template>
@@ -275,8 +271,10 @@
          >
            <template slot-scope="{ row }">
              <div v-if="row.handleTime" class="last-process">
                <div class="process-time">{{ formatDateTime(row.handleTime) }}</div>
                <div class="process-user">{{ row.handleBy || '系统处理' }}</div>
                <div class="process-time">
                  {{ formatDateTime(row.handleTime) }}
                </div>
                <div class="process-user">{{ row.handleBy || "系统处理" }}</div>
              </div>
              <span v-else class="no-process">暂无处理记录</span>
            </template>
@@ -321,21 +319,22 @@
<script>
import { tracedeallist } from "@/api/AiCentre/index";
import { deptTreeSelect } from "@/api/system/user";
export default {
  name: 'ExceptionList',
  name: "ExceptionList",
  data() {
    return {
      // 查询参数
      queryParams: {
        todeptcode: [], // 处理科室编号数组
        todeptname: '', // 处理科室名称
        templateid: '', // 任务模板ID
        handleStartTime: '', // 处理开始时间
        handleEndTime: '', // 处理结束时间
        todeptname: "", // 处理科室名称
        templateType: 2, // 任务模板ID
        handleStartTime: "", // 处理开始时间
        handleEndTime: "", // 处理结束时间
        handleTimeRange: [], // 时间范围,用于界面展示
        pageNum: 1,
        pageSize: 10
        pageSize: 10,
      },
      // 加载状态
@@ -346,27 +345,13 @@
      // 模板列表
      templateList: [
        { id: 1, name: '语音模板' },
        { id: 2, name: '问卷模板' }
        { id: 1, name: "语音满意度" },
        { id: 2, name: "问卷满意度" },
        // 你可以根据实际情况从接口获取模板列表
      ],
      // 科室列表
      deptList: [
        // 你可以从接口获取科室列表,这里先用静态数据
        { deptCode: '001', deptName: '心血管内科' },
        { deptCode: '002', deptName: '神经内科' },
        { deptCode: '003', deptName: '普外科' },
        { deptCode: '004', deptName: '骨科' },
        { deptCode: '005', deptName: '妇产科' },
        { deptCode: '006', deptName: '儿科' },
        { deptCode: '007', deptName: '急诊科' },
        { deptCode: '008', deptName: '呼吸内科' },
        { deptCode: '009', deptName: '消化内科' },
        { deptCode: '010', deptName: '内分泌科' },
        { deptCode: '011', deptName: '肾内科' },
        { deptCode: '012', deptName: '肿瘤科' }
      ],
      deptList: [],
      // 异常列表数据
      exceptionList: [],
@@ -377,100 +362,134 @@
        totalExceptionCount: 0,
        pendingCount: 0,
        processedCount: 0,
        todayProcessedCount: 0
        todayProcessedCount: 0,
      },
      // 日期选择器选项
      pickerOptions: {
        shortcuts: [
          {
            text: '最近一周',
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit('pick', [start, end]);
            }
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: '最近一个月',
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit('pick', [start, end]);
            }
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: '最近三个月',
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit('pick', [start, end]);
            }
          }
              picker.$emit("pick", [start, end]);
            },
          },
        ],
        disabledDate(time) {
          return time.getTime() > Date.now();
        }
      }
        },
      },
    };
  },
  mounted() {
    this.loadData();
    this.getDeptOptions();
  },
  methods: {
    // 格式化日期时间
    formatDateTime(dateTime) {
      if (!dateTime) return '';
      if (!dateTime) return "";
      const date = new Date(dateTime);
      return date.toLocaleDateString().replace(/\//g, '-') + ' ' +
             date.toTimeString().split(' ')[0];
      return (
        date.toLocaleDateString().replace(/\//g, "-") +
        " " +
        date.toTimeString().split(" ")[0]
      );
    },
    // 获取模板类型标签样式
    getTemplateTypeTag(type) {
      return type === 1 ? 'primary' : 'success';
      return type === 1 ? "primary" : "success";
    },
    // 构建查询参数
    buildQueryParams() {
      const params = {
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize
        pageSize: this.queryParams.pageSize,
      };
      // 处理科室编号
      if (this.queryParams.todeptcode && this.queryParams.todeptcode.length > 0) {
      if (
        this.queryParams.todeptcode &&
        this.queryParams.todeptcode.length > 0
      ) {
        // 接口可能需要字符串格式的科室编号,根据实际情况调整
        params.todeptcode = this.queryParams.todeptcode.join(',');
        params.todeptcode = this.queryParams.todeptcode.join(",");
      }
      // 模板ID
      if (this.queryParams.templateid) {
        params.templateid = this.queryParams.templateid;
      if (this.queryParams.templateType) {
        params.templateType = this.queryParams.templateType;
      }
      // 处理时间范围
      if (this.queryParams.handleTimeRange && this.queryParams.handleTimeRange.length === 2) {
      if (
        this.queryParams.handleTimeRange &&
        this.queryParams.handleTimeRange.length === 2
      ) {
        params.handleStartTime = this.queryParams.handleTimeRange[0];
        params.handleEndTime = this.queryParams.handleTimeRange[1];
      }
      return params;
    },
    /** 查询科室列表 */
    getDeptOptions() {
      deptTreeSelect()
        .then((res) => {
          if (res.code == 200) {
            this.deptList = 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;
    },
    // 加载数据
    async loadData() {
      this.loading = true;
      try {
        await Promise.all([
          this.loadExceptionList(),
          this.loadOverviewData()
        ]);
        await Promise.all([this.loadExceptionList(), this.loadOverviewData()]);
      } finally {
        this.loading = false;
      }
@@ -484,17 +503,17 @@
        if (response.code==200) {
          this.exceptionList = response.rows.detailTraceDealDTOList || [];
          this.overviewData.totalExceptionCount=response.rows.totalException
          this.overviewData.pendingCount=response.rows.noDealException
          this.overviewData.processedCount=response.rows.yesDealException
          this.overviewData.totalExceptionCount = response.rows.totalException;
          this.overviewData.pendingCount = response.rows.noDealException;
          this.overviewData.processedCount = response.rows.yesDealException;
          this.total = response.total || 0;
        } else {
          this.exceptionList = [];
          this.total = 0;
        }
      } catch (error) {
        console.error('加载异常列表失败:', error);
        this.$message.error('加载异常列表失败,请稍后重试');
        console.error("加载异常列表失败:", error);
        this.$message.error("加载异常列表失败,请稍后重试");
        this.exceptionList = [];
        this.total = 0;
      }
@@ -504,18 +523,26 @@
    async loadOverviewData() {
      try {
        // 从接口数据计算统计数据
        const totalExceptionCount = this.exceptionList.reduce((sum, item) =>
          sum + (item.exceptionQuesNum?.all || 0), 0);
        const pendingCount = this.exceptionList.reduce((sum, item) =>
          sum + (item.exceptionQuesNum?.noDeal || 0), 0);
        const processedCount = this.exceptionList.reduce((sum, item) =>
          sum + (item.exceptionQuesNum?.yesDeal || 0), 0);
        const totalExceptionCount = this.exceptionList.reduce(
          (sum, item) => sum + (item.exceptionQuesNum?.all || 0),
          0
        );
        const pendingCount = this.exceptionList.reduce(
          (sum, item) => sum + (item.exceptionQuesNum?.noDeal || 0),
          0
        );
        const processedCount = this.exceptionList.reduce(
          (sum, item) => sum + (item.exceptionQuesNum?.yesDeal || 0),
          0
        );
        // 计算今日处理数(这里可以根据实际需求调整逻辑)
        const today = new Date().toISOString().split('T')[0];
        const todayProcessedCount = this.exceptionList.filter(item => {
        const today = new Date().toISOString().split("T")[0];
        const todayProcessedCount = this.exceptionList.filter((item) => {
          if (!item.handleTime) return false;
          const handleDate = new Date(item.handleTime).toISOString().split('T')[0];
          const handleDate = new Date(item.handleTime)
            .toISOString()
            .split("T")[0];
          return handleDate === today;
        }).length;
@@ -523,15 +550,15 @@
          totalExceptionCount,
          pendingCount,
          processedCount,
          todayProcessedCount
          todayProcessedCount,
        };
      } catch (error) {
        console.error('加载概览数据失败:', error);
        console.error("加载概览数据失败:", error);
        this.overviewData = {
          totalExceptionCount: 0,
          pendingCount: 0,
          processedCount: 0,
          todayProcessedCount: 0
          todayProcessedCount: 0,
        };
      }
    },
@@ -554,43 +581,44 @@
    // 处理批量处理
    handleBatchProcess() {
      if (this.selectedIds.length === 0) {
        this.$message.warning('请先选择要处理的异常题目');
        this.$message.warning("请先选择要处理的异常题目");
        return;
      }
      // 跳转到批量处理页面
      this.$router.push({
        path: '/Intelligentcenter/batch',
        path: "/Intelligentcenter/batch",
        query: {
          questionIds: this.selectedIds.join(',')
        }
          questionIds: this.selectedIds.join(","),
          type: this.queryParams.templateType,
        },
      });
    },
    // 处理导出
    handleExport() {
      this.$message.success('导出功能开发中...');
      this.$message.success("导出功能开发中...");
    },
    // 刷新数据
    refreshData() {
      this.loadData();
      this.$message.success('数据已刷新');
      this.$message.success("数据已刷新");
    },
    // 处理选择变化
    handleSelectionChange(selection) {
      this.selectedIds = selection.map(item => item.scriptid);
      this.selectedIds = selection.map((item) => item.scriptid);
    },
    // 处理单个题目批量处理
    handleBatchQuestion(row) {
      this.$router.push({
        path: '/Intelligentcenter/batch',
        path: "/Intelligentcenter/batch",
        query: {
          questionId: row.scriptid,
          questionText: encodeURIComponent(row.questiontext)
        }
          type: this.queryParams.templateType,
        },
      });
    },
@@ -605,8 +633,8 @@
    handlePageChange(page) {
      this.queryParams.pageNum = page;
      this.loadExceptionList();
    }
  }
    },
  },
};
</script>
@@ -619,7 +647,7 @@
  .page-header {
    margin-bottom: 20px;
    padding: 20px;
    background: linear-gradient(135deg, #5788FE 0%, #66b1ff 100%);
    background: linear-gradient(135deg, #5788fe 0%, #66b1ff 100%);
    border-radius: 8px;
    color: white;
@@ -803,7 +831,7 @@
            }
            &.total {
              color: #5788FE;
              color: #5788fe;
            }
          }
        }
@@ -818,7 +846,7 @@
        .process-user {
          font-size: 13px;
          color: #5788FE;
          color: #5788fe;
          font-weight: 500;
        }
      }
src/views/Satisfaction/configurationmyd/index.vue
@@ -491,21 +491,25 @@
>
  <div v-if="editingQuestion" class="option-config-wrapper">
    <div class="dialog-header">
      <h4>{{ editingQuestion.scriptTopic || '无主题' }}</h4>
          <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)"
            v-if="!currentOptions.some((opt) => opt.isabnormal === 1)"
        title="请至少设置一个异常选项(标记为异常)"
        type="warning"
        :closable="false"
        show-icon
        style="margin-bottom: 20px;"
            style="margin-bottom: 20px"
      />
      <div v-for="(option, index) in currentOptions" :key="index" class="option-item">
          <div
            v-for="(option, index) in currentOptions"
            :key="index"
            class="option-item"
          >
        <el-form
          :model="option"
          :rules="optionRules"
@@ -543,7 +547,9 @@
                    :label="status.label"
                    :value="status.value"
                  >
                    <el-tag :type="status.type" size="small">{{ status.label }}</el-tag>
                        <el-tag :type="status.type" size="small">{{
                          status.label
                        }}</el-tag>
                  </el-option>
                </el-select>
              </el-form-item>
@@ -848,30 +854,12 @@
          this.voiceCategories.includes(q.scriptAssortid)
        ).length;
      }
      return 0;
    },
    // 检查题目是否有异常选项
    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) {
@@ -888,7 +876,7 @@
      if (this.queryParams.scriptTopic) {
        const keyword = this.queryParams.scriptTopic.toLowerCase();
        filtered = filtered.filter(
          (q) => q.scriptTopic && q.scriptTopic.toLowerCase().includes(keyword)
          (q) => q.scriptTopic && q.criptTopic.toLowerCase().includes(keyword)
        );
      }
@@ -1212,9 +1200,9 @@
    /** 配置变更处理 */
    handleConfigChange(question) {
      this.$nextTick(() => {
        const index = this.filteredQuestionList.findIndex(
          (q) => q.id === question.id
        );
        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) {
@@ -1261,24 +1249,61 @@
      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) return;
    async saveSingleConfig(question, skipAbnormalCheck = false) {
      // 检查是否有变更
      if (!question.hasChanges && !skipAbnormalCheck) {
        this.$message.info("当前配置无变化");
        return;
      }
      const index = this.filteredQuestionList.findIndex(
        (q) => q.id === question.id
      );
      console.log(index, "filteredQuestionList");
      // 检查是否有异常选项
      if (!skipAbnormalCheck && !this.checkHasAbnormalOptions(question)) {
        this.$confirm(
          "该题目没有设置异常选项,必须先配置异常选项才能保存。是否立即配置?",
          "提示",
          {
            confirmButtonText: "去配置",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(() => {
            this.openOptionDialog(question);
          })
          .catch(() => {});
        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;
      const valid = await formRef.validate();
      if (!valid) {
      // 验证表单
      try {
        await formRef.validate();
      } catch (error) {
        this.$message.warning("请先完成必填项");
        return;
      }
@@ -1339,6 +1364,18 @@
          reportDeptName: reportDeptNames.join(","),
        };
        // 如果需要,也更新选项数据
        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;
@@ -1375,7 +1412,6 @@
      }
    },
    /** 处理保存成功 */
    /** 处理保存成功 */
    handleSaveSuccess(question) {
      // 同时更新题目顶层字段
@@ -1450,6 +1486,36 @@
    async handleBatchSave() {
      if (!this.hasChanges || this.batchSaving) return;
      // 获取有变更的题目
      const changedQuestions = this.questionList.filter((q) => q.hasChanges);
      if (changedQuestions.length === 0) {
        this.$message.info("没有需要保存的配置变更");
        return;
      }
      // 检查是否有题目缺少异常选项
      const questionsWithoutAbnormal = changedQuestions.filter(
        (q) => !this.checkHasAbnormalOptions(q)
      );
      if (questionsWithoutAbnormal.length > 0) {
        this.$confirm(
          `有 ${questionsWithoutAbnormal.length} 个题目没有设置异常选项,必须配置异常选项后才能保存。是否先去配置?`,
          "提示",
          {
            confirmButtonText: "去配置",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(() => {
            // 打开第一个没有异常选项的题目的配置对话框
            this.openOptionDialog(questionsWithoutAbnormal[0]);
          })
          .catch(() => {});
        return;
      }
      this.$confirm("确定要保存所有修改过的配置吗?", "批量保存", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
@@ -1458,24 +1524,20 @@
        .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);
              // 跳过异常检查,因为在上面已经检查过了
              await this.saveSingleConfig(question, true);
              results.push({
                id: question.id,
                success:
                  !question.hasChanges &&
                  question.saveStatus?.type === "success",
                success: !question.hasChanges,
              });
            } catch (error) {
              results.push({
                id: question.id,
                success: false,
                error: error.message,
              });
            }
          }
@@ -1492,6 +1554,11 @@
            this.$message.warning(
              `成功保存 ${successCount} 个,失败 ${failCount} 个`
            );
            // 可以显示具体哪些失败了
            const failedQuestions = results
              .filter((r) => !r.success)
              .map((r) => r.id);
            console.error("保存失败的题目ID:", failedQuestions);
          }
        })
        .catch(() => {
@@ -1505,39 +1572,38 @@
      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.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) => ({
        ).map((opt, index) => ({
          ...opt,
          id: opt.id,
          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) => ({
        ).map((opt, index) => ({
          ...opt,
          id: opt.id || `temp_${Date.now()}_${index}`,
          targetvalue: opt.targetvalue || "",
          isabnormal: opt.isabnormal || 0,
        }));
@@ -1549,7 +1615,7 @@
    /** 添加新选项 */
    addNewOption() {
      this.currentOptions.push({
        id: Date.now(), // 临时ID
        id: `temp_${Date.now()}_${this.currentOptions.length}`,
        targetvalue: "",
        isabnormal: 0,
        isNew: true,
@@ -1558,16 +1624,25 @@
    /** 删除选项 */
    removeOption(index) {
      this.$confirm("确定要删除这个选项吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
      this.currentOptions.splice(index, 1);
        })
        .catch(() => {});
    },
    /** 保存选项配置 */
    async saveOptions() {
      try {
        // 验证必填项
        for (const option of this.currentOptions) {
        for (let i = 0; i < this.currentOptions.length; i++) {
          const option = this.currentOptions[i];
          if (!option.targetvalue || option.targetvalue.trim() === "") {
            this.$message.warning("请填写所有选项内容");
            this.$message.warning(`第 ${i + 1} 个选项内容不能为空`);
            return;
          }
        }
@@ -1582,6 +1657,27 @@
          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 =
@@ -1589,14 +1685,24 @@
              ...opt,
              optioncontent: opt.targetvalue,
              isabnormal: opt.isabnormal,
              // 清除临时字段
              targetvalue: undefined,
              isNew: undefined,
            }));
        } else if (this.templateForm.templateType === 2) {
          this.editingQuestion.ivrLibaScriptTargetoptionList =
            this.currentOptions;
            this.currentOptions.map((opt) => ({
              ...opt,
              // 清除临时字段
              isNew: undefined,
            }));
        }
        // 触发配置变更检查
        this.handleConfigChange(this.editingQuestion);
        // 如果选项有变化,则设置题目为有变更状态
        if (isOptionsChanged) {
          this.editingQuestion.hasChanges = true;
          this.updateChangedStatus();
        }
        this.$message.success("选项配置保存成功");
        this.optionDialogVisible = false;
@@ -1605,126 +1711,39 @@
        this.$message.error("保存选项失败");
      }
    },
    /** 修改保存单个题目配置方法,添加异常选项检查 */
    async saveSingleConfig(question) {
      // 检查是否有异常选项
      if (!this.checkHasAbnormalOptions(question)) {
        this.$confirm("该题目没有设置异常选项,是否先配置选项?", "提示", {
          confirmButtonText: "去配置",
          cancelButtonText: "取消",
          type: "warning",
        })
          .then(() => {
            this.openOptionDialog(question);
          })
          .catch(() => {});
        return;
    /** 检查选项是否发生变化 */
    checkOptionsChanged(originalOptions, newOptions, templateType) {
      // 如果数量不同,则一定变化了
      if (originalOptions.length !== newOptions.length) {
        return true;
      }
      // 原有的保存逻辑...
      if (!question.hasChanges) return;
      // 比较每个选项的内容和异常状态
      for (let i = 0; i < originalOptions.length; i++) {
        const original = originalOptions[i];
        const current = newOptions[i];
      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;
        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;
          }
        }
      }
      // 继续原有的保存逻辑...
      question.saving = true;
      question.saveStatus = null;
      try {
        // ... 原有的保存逻辑不变
      } catch (error) {
        // ... 错误处理不变
      } finally {
        question.saving = false;
      }
      return 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) {
@@ -1746,6 +1765,7 @@
      }
      return { total: 0, abnormal: 0, warning: 0, normal: 0 };
    },
    /** 搜索 */
    handleQuery() {
      // 仅筛选显示,不需要重新加载