WXL (wul)
5 天以前 38c2fe23d77c9f27d52941dab77a100bb1839dd7
测试完成
已添加1个文件
已修改3个文件
571 ■■■■■ 文件已修改
src/views/followvisit/record/detailpage/MergeAndModify.vue 449 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/detailpage/index.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/outpatient.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/detailpage/MergeAndModify.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,449 @@
<template>
  <div class="merge-questionnaire-container">
    <div class="merge-header">
      <h3>合并编辑问卷 (共 {{ services.length }} ä¸ªæœªå®ŒæˆæœåŠ¡)</h3>
      <el-tag
        v-for="service in services"
        :key="service.id"
        type="info"
        style="margin-right: 10px"
      >
        {{ service.taskName }} ({{ service.sendname }})
      </el-tag>
    </div>
    <div class="merge-content">
      <div class="question-list">
        <div
          v-for="(question, index) in mergedQuestions"
          :key="question.uniqueKey"
          class="question-item"
        >
          <!-- é¢˜ç›®å±•示 - ä¸Žçˆ¶ç»„件保持一致 -->
          <div
            :class="
              question.isabnormal ? 'scriptTopic-isabnormal' : 'scriptTopic-dev'
            "
          >
            <div class="dev-text">
              {{ index + 1 }}、[{{
                getQuestionType(question.scriptType)
              }}]<span> {{ question.scriptContent }}</span>
            </div>
            <!-- å•选 -->
            <div class="dev-xx" v-if="question.scriptType == 1">
              <el-radio-group
                v-model="question.mergedResult"
                @change="
                  handleOptionChange(
                    $event,
                    index,
                    question.svyLibTemplateTargetoptions,
                    question
                  )
                "
                >11
                <el-radio
                  v-for="(
                    option, optIndex
                  ) in question.svyLibTemplateTargetoptions"
                  :key="optIndex"
                  :label="option.optioncontent"
                  :class="option.isabnormal ? 'red-star' : ''"
                >
                  {{ option.optioncontent }}
                </el-radio>
              </el-radio-group>
            </div>
            <!-- å¤šé€‰ -->
            <div class="dev-xx" v-if="question.scriptType == 2">
              <el-checkbox-group
                v-model="question.mergedResult"
                @change="updateScore($event, index, question.options, question)"
              >
                <el-checkbox
                  v-for="(option, optIndex) in question.options"
                  :key="optIndex"
                  :label="option.optioncontent"
                  :class="option.isabnormal ? 'red-star' : ''"
                >
                  {{ option.optioncontent }}
                </el-checkbox>
              </el-checkbox-group>
            </div>
            <!-- å¡«ç©º -->
            <div class="dev-xx" v-if="question.scriptType == 4">
              <el-input
                type="textarea"
                :rows="2"
                placeholder="请输入答案"
                v-model="question.mergedResult"
                clearable
              />
            </div>
            <!-- é™„加输入框 -->
            <div v-if="question.showAppendInput" class="append-input-container">
              <el-input
                type="textarea"
                :rows="2"
                placeholder="请输入具体信息"
                v-model="question.answerps"
                clearable
              />
            </div>
            <!-- æç¤ºä¿¡æ¯ -->
            <div v-show="question.prompt">
              <el-alert :title="question.prompt" type="warning" />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="merge-footer">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" @click="handleSave" :loading="isSaving"
        >保存到所有问卷</el-button
      >
    </div>
  </div>
</template>
<script>
import {
  getsearchrResults,
  serviceSubtaskDetailedit,
  serviceSubtaskDetailadd,
  Editsingletaskson,
  getTaskservelist,
  alterpatient,
} from "@/api/AiCentre/index";
export default {
  props: {
    selectedServices: {
      type: Array,
      required: true,
    },
    patid: {
      type: [String, Number],
      required: true,
    },
  },
  data() {
    return {
      services: [],
      mergedQuestions: [], // åˆå¹¶åŽçš„问题数据
      isSaving: false,
    };
  },
  created() {
    this.loadServicesData();
  },
  methods: {
    getQuestionType(type) {
      const types = { 1: "单选", 2: "多选", 4: "问答" };
      return types[type] || "未知";
    },
    async loadServicesData() {
      this.services = this.selectedServices;
      const loading = this.$loading({
        lock: true,
        text: "正在加载未完成问卷数据...",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });
      try {
        // åªåŠ è½½æœªå®Œæˆçš„æœåŠ¡é—®å·æ•°æ®
        const requests = this.services.map((service) =>
          getsearchrResults({
            taskid: service.taskid,
            patid: this.patid,
            subId: service.id,
            isFinish: false, // ç¡®ä¿åªèŽ·å–æœªå®Œæˆçš„é—®å·
          })
        );
        const responses = await Promise.all(requests);
        // åˆå¹¶æ‰€æœ‰é—®é¢˜ï¼ŒåŽ»é‡
        const allQuestions = [];
        const questionMap = {};
        responses.forEach((response, index) => {
          if (response.code == 200 && response.data.scriptResult) {
            response.data.scriptResult.forEach((q) => {
              const key = `${q.scriptContent}_${q.scriptType}`;
              if (!questionMap[key]) {
                questionMap[key] = {
                  ...q,
                  uniqueKey: key,
                  mergedResult: q.scriptType == 2 ? [] : null,
                  originalServices: [], // è®°å½•原始服务ID
                };
                allQuestions.push(questionMap[key]);
              }
              questionMap[key].originalServices.push(this.services[index].id);
            });
          }
        });
        // åˆå§‹åŒ–合并结果
        this.mergedQuestions = allQuestions.map((q) => ({
          ...q,
          mergedResult: q.scriptType == 2 ? [] : q.scriptResult || null,
        }));
        console.log(this.mergedQuestions);
      } catch (error) {
        this.$message.error("加载问卷数据失败: " + error.message);
      } finally {
        loading.close();
      }
    },
    // å¤„理选项变化 (与父组件保持一致)
    handleOptionChange(selectedOption, questionIndex, options, question) {
      const selectedOptionObj = options.find(
        (item) => item.optioncontent == selectedOption
      );
      // è®¾ç½®å¼‚常状态
      question.isabnormal = !!selectedOptionObj?.isabnormal;
      // å¤„理附加输入框显示
      question.showAppendInput = selectedOptionObj?.appendflag == 1;
      if (!question.showAppendInput) {
        question.answerps = "";
      }
      this.$forceUpdate();
    },
    // æ›´æ–°å¤šé€‰åˆ†æ•° (与父组件保持一致)
    updateScore(selectedValues, questionIndex, options, question) {
      const abnormalOptions = options.filter((opt) => opt.isabnormal);
      question.isabnormal = abnormalOptions.some((opt) =>
        selectedValues.includes(opt.optioncontent)
      );
      this.$forceUpdate();
    },
    handleCancel() {
      this.$emit("cancel");
    },
    async handleSave() {
      this.isSaving = true;
      try {
        const saveResults = [];
        const updateServicePromises = [];
        // 1. ä¿å­˜æ‰€æœ‰é—®å·é—®é¢˜
        for (const service of this.services) {
          const serviceId = service.id;
          const questionsToSave = this.mergedQuestions
            .filter((q) => q.originalServices.includes(serviceId))
            .map((question) => ({
              scriptid: question.id,
              scriptResultId: question.scriptResultId,
              scriptType: question.scriptType,
              questiontext: question.scriptContent,
              asrtext:
                question.scriptType == 2
                  ? question.mergedResult.join("&")
                  : question.mergedResult,
              answerps: question.answerps || null,
              isabnormal: question.isabnormal || false,
            }));
          // ä¿å­˜é—®é¢˜æ•°æ®
          for (const question of questionsToSave) {
            const saveData = {
              taskid: service.taskid,
              patid: this.patid,
              subId: serviceId,
              ...question,
            };
            if (saveData.isabnormal) {
              saveData.excep = 1;
            }
            try {
              const response = question.scriptResultId
                ? await serviceSubtaskDetailedit(saveData)
                : await serviceSubtaskDetailadd(saveData);
              saveResults.push({
                serviceId,
                success: response.code === 200,
                message:
                  response.message ||
                  (response.code === 200 ? "保存成功" : "保存失败"),
              });
            } catch (error) {
              saveResults.push({
                serviceId,
                success: false,
                message: error.message || "保存失败",
              });
            }
          }
          // 2. æ›´æ–°æœåŠ¡çŠ¶æ€ä¸ºå·²å®Œæˆ (sendstate = 6)
          updateServicePromises.push(this.updateServiceStatus(serviceId));
        }
        // ç­‰å¾…所有服务状态更新完成
        const updateResults = await Promise.all(updateServicePromises);
        updateResults.forEach((result) => {
          if (!result.success) {
            saveResults.push({
              serviceId: result.serviceId,
              success: false,
              message: result.message || "服务状态更新失败",
            });
          }
        });
        // ç»Ÿè®¡ç»“æžœ
        const successCount = saveResults.filter((r) => r.success).length;
        const totalCount = saveResults.length;
        // é€šçŸ¥çˆ¶ç»„ä»¶
        this.$emit("save", {
          successCount,
          totalCount,
          results: saveResults,
        });
        if (successCount === totalCount) {
          this.$message.success("所有问卷和服务状态更新成功");
        } else {
          this.$message.warning(
            `成功保存 ${successCount} é¡¹ï¼Œå¤±è´¥ ${totalCount - successCount} é¡¹`
          );
        }
      } catch (error) {
        this.$message.error("保存过程中发生错误: " + error.message);
      } finally {
        this.isSaving = false;
      }
    },
    // æ–°å¢žæ–¹æ³•:更新服务状态
    async updateServiceStatus(serviceId) {
      try {
        // èŽ·å–æœåŠ¡å½“å‰æ•°æ®
        const res = await getTaskservelist({
          patid: this.patid,
          subId: serviceId,
        });
        if (res.code === 200) {
          const serviceData = res.rows[0].serviceSubtaskList.find(
            (item) => item.id === serviceId
          );
          if (serviceData) {
            // æ›´æ–°æœåŠ¡çŠ¶æ€ä¸ºå·²å®Œæˆ (sendstate = 6)
            const updateRes = await Editsingletaskson({
              ...serviceData,
              sendstate: 6, // è®¾ç½®ä¸ºå·²å®ŒæˆçŠ¶æ€
              remark: "通过合并编辑完成", // å¯é€‰ï¼šæ·»åŠ å¤‡æ³¨
            });
            return {
              serviceId,
              success: updateRes.code === 200,
              message: updateRes.message || "服务状态更新成功",
            };
          }
        }
        return {
          serviceId,
          success: false,
          message: "获取服务数据失败",
        };
      } catch (error) {
        return {
          serviceId,
          success: false,
          message: error.message || "更新服务状态失败",
        };
      }
    },
  },
};
</script>
<style scoped>
.merge-questionnaire-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 20px;
}
.merge-header {
  margin-bottom: 20px;
}
.merge-content {
  flex: 1;
  overflow-y: auto;
}
.question-list {
  padding: 10px;
}
/* ä¸Žçˆ¶ç»„件一致的题目样式 */
.scriptTopic-dev {
  margin-bottom: 20px;
  padding: 15px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}
.scriptTopic-isabnormal {
  margin-bottom: 20px;
  padding: 15px;
  border: 1px solid #f56c6c;
  border-radius: 4px;
  background-color: #fff6f6;
}
.dev-text {
  font-size: 16px;
  margin-bottom: 15px;
  color: #333;
}
.dev-xx {
  margin-left: 20px;
}
.append-input-container {
  margin-top: 15px;
}
.red-star {
  color: #f56c6c;
}
.merge-footer {
  margin-top: 20px;
  text-align: right;
  padding-top: 15px;
  border-top: 1px solid #ebeef5;
}
</style>
src/views/followvisit/record/detailpage/index.vue
@@ -27,6 +27,23 @@
                å‰å¾€CDSS查询
              </el-link>
            </div>
            <div class="merge-controls" v-if="Whetherall">
              <el-button
                type="primary"
                @click="toggleMergeMode"
                :disabled="selectedServices.length < 2"
              >
                {{ isMergeMode ? "取消合并" : "合并编辑问卷" }}
              </el-button>
              <el-button
                v-if="isMergeMode"
                type="success"
                @click="openMergeDialog"
                :disabled="selectedServices.length < 2"
              >
                å¼€å§‹åˆå¹¶ (已选 {{ selectedServices.length }} ä¸ªæœåŠ¡)
              </el-button>
            </div>
          </div>
          <!-- <el-button type="success">随访后短信</el-button> -->
        </div>
@@ -36,7 +53,14 @@
          :data="logsheetlist"
          :row-class-name="tableRowClassName"
          style="width: 100%"
          @selection-change="handleSelectionChange"
        >
          <el-table-column
            type="selection"
            width="55"
            :selectable="checkSelectable"
            v-if="Whetherall"
          ></el-table-column>
          <el-table-column
            prop="sendname"
            align="center"
@@ -213,7 +237,22 @@
        </el-table>
      </div>
    </div>
    <!-- æ·»åŠ åˆå¹¶ç¼–è¾‘å¯¹è¯æ¡† -->
    <el-dialog
      title="合并编辑问卷"
      :visible.sync="mergeDialogVisible"
      width="80%"
      top="5vh"
      v-dialogDrag
    >
      <MergeAndModify
        v-if="mergeDialogVisible"
        :selected-services="selectedServices"
        :patid="patid"
        @save="handleMergeSave"
        @cancel="mergeDialogVisible = false"
      />
    </el-dialog>
    <div class="action-container">
      <div class="call-action">
        <div class="call-container">
@@ -278,7 +317,7 @@
                          </el-radio-group>
                        </div>
                        <div
                          v-if="item.showAppendInput"
                          v-if="item.showAppendInput||item.answerps"
                          class="append-input-container"
                        >
                          <el-input
@@ -843,9 +882,11 @@
  listcontactinformation,
} from "@/api/patient/homepage";
import CallButton from "@/components/CallButton";
import MergeAndModify from "./MergeAndModify.vue";
export default {
  components: {
    CallButton,
    MergeAndModify,
  },
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
@@ -882,6 +923,9 @@
      tableDatatop: [], //题目表
      voiceDatatop: [], //题目表
      dynamicTags: [],
      isMergeMode: false,
      mergeDialogVisible: false,
      selectedServices: [], // é€‰ä¸­çš„æœåŠ¡åˆ—è¡¨
      zcrules: {
        resource: [
          { required: true, message: "请选择随访方式", trigger: "change" },
@@ -1312,6 +1356,7 @@
          console.error("发生错误:", error);
        });
    },
    // ç”µè¯============================
    // éªŒè¯ç”µè¯å·ç æ ¼å¼å¹¶è¿”回错误信息
    validatePhoneNumber(phone) {
      if (!phone) {
@@ -1343,7 +1388,6 @@
        };
      }
    },
    // ä½¿ç”¨ç¤ºä¾‹
    isValidPhone(phone) {
      return this.validatePhoneNumber(phone).isValid;
@@ -1367,7 +1411,6 @@
        });
      });
    },
    // å¤„理通话状态变化
    handleCallStatusChange(status) {
      console.log(status, "status");
@@ -1389,7 +1432,6 @@
        this.$message.error(`呼叫失败: ${status.text}`);
      }
    },
    // ç»“束当前通话
    endCurrentCall() {
      if (!this.currentCall) return;
@@ -1642,7 +1684,7 @@
      this.tableDatatop[questionIndex].showAppendInput =
        selectedOptionObj.appendflag == 1;
        console.log(this.tableDatatop);
      console.log(this.tableDatatop);
      // if (!this.tableDatatop[questionIndex].showAppendInput) {
      //   this.tableDatatop[questionIndex].answerps = ""; // æ¸…除附加信息
@@ -1793,6 +1835,60 @@
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
    updateScore(a, b, c) {},
    // åˆå¹¶ä¿®æ”¹ç›¸å…³=============================
    toggleMergeMode() {
      this.isMergeMode = !this.isMergeMode;
      if (!this.isMergeMode) {
        this.selectedServices = [];
      }
    },
    handleSelectionChange(selection) {
      this.selectedServices = selection
        .filter(
          (item) => !item.preachformson || !item.preachformson.includes("3")
        )
        .map((item) => ({
          id: item.id,
          taskid: item.taskid,
          taskName: item.taskName,
          sendname: item.sendname,
        }));
    },
    checkSelectable(row, index) {
      // å½“ sendstate ä¸º 6 æ—¶ä¸å¯é€‰
      return row.sendstate !== 6;
    },
    openMergeDialog() {
      if (this.selectedServices.length < 2) {
        this.$message.warning("请至少选择2个问卷服务进行合并");
        return;
      }
      this.mergeDialogVisible = true;
    },
    handleMergeSave(mergedData) {
      // å¤„理合并保存逻辑
      this.mergeDialogVisible = false;
      this.isMergeMode = false;
      this.selectedServices = [];
      // æ˜¾ç¤ºä¿å­˜ç»“æžœ
      if (mergedData.successCount == mergedData.totalCount) {
        this.$message.success(`成功保存 ${mergedData.successCount} ä¸ªé—®å·`);
      } else if (mergedData.successCount > 0) {
        this.$message.warning(
          `成功保存 ${mergedData.successCount} ä¸ªé—®å·ï¼Œå¤±è´¥ ${
            mergedData.totalCount - mergedData.successCount
          } ä¸ª`
        );
      } else {
        this.$message.error("所有问卷保存失败");
      }
      // åˆ·æ–°æ•°æ®
      this.getTaskservelist();
    },
  },
};
</script>
@@ -1852,7 +1948,11 @@
    margin-top: 20px;
  }
}
.merge-controls {
  background: #f5f7fa;
  border-radius: 4px;
  margin-left: 20px;
}
.Followuserinfo {
  margin: 10px 10px 0 10px;
  align-items: center;
src/views/patient/patient/outpatient.vue
@@ -440,6 +440,12 @@
                  <span>{{ formatTime(scope.row.createTime) }}</span>
                </template>
              </el-table-column>
              <template #empty>
                <div class="empty-message">
                  <i class="el-icon-warning"></i>
                  <span>患者科室无匹配服务</span>
                </div>
              </template>
            </el-table>
          </div>
        </el-col>
vue.config.js
@@ -37,7 +37,7 @@
      [process.env.VUE_APP_BASE_API]: {
        // target: `https://www.health-y.cn/lssf`,
        // target: `http://10.202.20.185:8095`,
        // target: `http://9.208.2.190:8095`,
        // target: `http://192.168.100.195:8095`,
        target:`http://localhost:8095`,
        // target: `http://192.168.100.193:8095`,
        // target: `http://192.168.101.166:8093`,