WXL (wul)
2026-06-15 741805d8daa2d2baa0b6b75bc1724488baf9c6bc
测试完成
已重命名1个文件
已修改43个文件
已添加10个文件
13724 ■■■■ 文件已修改
dist.zip 补丁 | 查看 | 原始文档 | blame | 历史
src/api/AiCentre/Qtemplate.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/AiCentre/SingleTask.js 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/user.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/CallButton/index.vue 528 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/OptionalForm/index.vue 118 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/StatisticsCards/index.vue 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/ChartDialog.vue 579 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/ContinuedCare.vue 633 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/DetailDialog.vue 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/FirstFollowUp.vue 1511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/SecondFollowUp.vue 1424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/TimelyRateDialog.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/components/styles.scss 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/diseaseStatistics/index.vue 569 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/sfstatistics/components/visitStatistics.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/Continue/index.vue 239 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/HistoricalFollow/index.vue 185 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/OutpatientAgain/index.vue 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/SpecificDisease/index.vue 193 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/Tracking/index.vue 242 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/again/index.vue 379 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/beHospitalized/followUp.vue 311 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/beHospitalized/publicity.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/complaint/index.vue 344 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/discharge/index.vue 367 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/discharge/outpatientService.vue 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/mzsatisfaction/index.vue 228 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/operation/index.vue 250 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/outpatient/index.vue 264 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/detailpage/index.vue 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/index.vue 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/technology/index.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/zbAgain/index.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/zysatisfaction/index.vue 233 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/outsideChainwtnew.vue 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/ExternalPatient.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/outpatient.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/physical.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/profile/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/physical/index.vue 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/propaganda/Missionotice.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/propaganda/QuestionnaireTask.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/propaganda/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/propaganda/particty.vue 130 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/questionnaire/index.vue 195 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/shadow/index.vue 193 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/subsequent/index.vue 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sfstatistics/percentage/components/DetailDialog.vue 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/ruleconfig/index.vue 656 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
随访通用(需同步最新状态).zip 补丁 | 查看 | 原始文档 | blame | 历史
dist.zip
Binary files differ
src/api/AiCentre/Qtemplate.js
@@ -47,6 +47,13 @@
    method: "get",
  });
}
// æŸ¥çœ‹é—®å·é»˜è®¤å¡«æŠ¥æƒé™
export function getconfigKey(Id) {
  return request({
    url: "/system/config/configKey/" + Id,
    method: "get",
  });
}
// æ–°å¢žæˆ–修改问卷模板详情
export function compileQtemplate(data) {
  return request({
src/api/AiCentre/SingleTask.js
@@ -86,6 +86,37 @@
    data: data,
  });
}
// ä»»åŠ¡è§„åˆ™åˆ é™¤
export function deltaskrule(taskid) {
  return request({
    url: "/smartor/taskrule/remove/" + taskid,
    method: "get",
  });
}
// ä»»åŠ¡è§„åˆ™æŸ¥è¯¢
export function taskrulelist(data) {
  return request({
    url: "/smartor/taskrule/list",
    method: "post",
    data: data,
  });
}
// ä»»åŠ¡è§„åˆ™æ–°å¢ž
export function addtaskrule(data) {
  return request({
    url: "/smartor/taskrule/add",
    method: "post",
    data: data,
  });
} // ä»»åŠ¡è§„åˆ™ä¿®æ”¹
export function edittaskrule(data) {
  return request({
    url: "/smartor/taskrule/edit",
    method: "post",
    data: data,
  });
}
// æŸ¥è¯¢ä»»åŠ¡è¯¦æƒ…
export function getTaskInfo(data) {
@@ -139,7 +170,7 @@
// èŽ·å–è¯­éŸ³ä»»åŠ¡æ¨¡æ¿è¯¦æƒ…
export function selectInfoByCondition(data) {
  return request({
     url: "/smartor/ivrTaskTemplate/selectInfoByCondition",
    url: "/smartor/ivrTaskTemplate/selectInfoByCondition",
    method: "post",
    data: data,
  });
src/api/system/user.js
@@ -94,6 +94,14 @@
    data: data,
  });
}
// ä¸“病统计查询
export function getSpecialSfStatistics(data) {
  return request({
    url: "/smartor/serviceSubtask/getSpecialSfStatistics",
    method: "post",
    data: data,
  });
}
// æ»¡æ„åº¦ç»Ÿè®¡
export function getSfStatisticsJoy(data) {
  return request({
src/components/CallButton/index.vue
@@ -2,6 +2,9 @@
  <div class="call-container">
    <div class="sip-status" :class="sipStatusClass">
      SIP状态: {{ sipStatus }}
      <span v-if="reconnectCount > 0" class="reconnect-info">
        (重连: {{ reconnectCount }}次)
      </span>
    </div>
    <!-- çŠ¶æ€æ˜¾ç¤º -->
@@ -16,13 +19,24 @@
        {
          calling: isCalling,
          registering: isRegistering,
          reconnecting: isReconnecting,
        },
      ]"
      @click="startCall"
      :disabled="isButtonDisabled"
    >
      <i v-if="isRegistering" class="el-icon-loading"></i>
      <i v-if="isRegistering || isReconnecting" class="el-icon-loading"></i>
      {{ callButtonText }}
    </button>
    <!-- æ‰‹åŠ¨é‡è¿žæŒ‰é’® -->
    <button
      v-if="showManualReconnect"
      class="reconnect-btn"
      @click="manualReconnect"
      :disabled="isRegistering"
    >
      æ‰‹åŠ¨é‡è¿ž
    </button>
    <!-- æŒ‚断按钮 -->
@@ -45,24 +59,28 @@
    },
  },
  data() {
    const randomNum = Math.floor(Math.random() * 20) + 1000; // å®šä¹‰éšæœºåˆ†æœºå·
    const randomNum = Math.floor(Math.random() * 20) + 1000;
    return {
      isCalling: false,
      isRegistering: true, // åˆå§‹ä¸ºæ³¨å†Œä¸­çŠ¶æ€
      isRegistering: true,
      isReconnecting: false, // æ·»åŠ é‡è¿žä¸­çŠ¶æ€
      randomNum: randomNum,
      randomID: null,
      orgname: localStorage.getItem("orgname"),
      callStatus: "idle", // idle, calling, connected, ended
      callStatus: "idle",
      sipStatus: "未连接",
      sipStatusClass: "status-disconnected",
      reconnectCount: 0, // é‡è¿žæ¬¡æ•°
      lastActivityTime: null, // æœ€åŽæ´»åŠ¨æ—¶é—´
      heartbeatTimer: null, // å¿ƒè·³å®šæ—¶å™¨
      reconnectTimer: null, // é‡è¿žå®šæ—¶å™¨
      maxReconnectAttempts: 5, // æœ€å¤§é‡è¿žå°è¯•次数
      reconnectDelay: 5000, // é‡è¿žå»¶è¿Ÿ(ms)
      sipConfig: {
        // ç§»é™¤ç¡¬ç¼–码的wsUrl和domain
        wsUrl: "",
        sipUri: "",
        password: "Smartor@2023", //丽水
        // password: "heskj@1234",//市一
        password: "Smartor@2023",
        displayName: "Web å°é¾™",
        // realm: "9.208.5.18:8090",
      },
    };
  },
@@ -78,7 +96,6 @@
    },
    countdownText() {
      if (this.sipStatus !== "已注册") return "";
      const { canCall, reason } = sipService.canMakeCall();
      if (!canCall && reason.includes("等待")) {
        return reason;
@@ -87,15 +104,27 @@
    },
    isButtonDisabled() {
      return (
        this.isCalling || this.sipStatus !== "已注册" || this.isRegistering
        this.isCalling ||
        this.sipStatus !== "已注册" ||
        this.isRegistering ||
        this.isReconnecting
      );
    },
    callButtonText() {
      if (this.isRegistering) return "注册中...";
      if (this.isReconnecting) return "重连中...";
      return this.isCalling ? "通话中..." : "一键呼叫";
    },
    callStatusClass() {
      return `status-${this.callStatus}`;
    },
    showManualReconnect() {
      return (
        !this.isCalling &&
        !this.isRegistering &&
        this.sipStatus !== "已注册" &&
        this.sipStatus !== "连接中"
      );
    },
  },
  created() {
@@ -107,8 +136,6 @@
    } else {
      this.sipConfig.password = "Smartor@2023";
    }
    // CallgetList();
  },
  async mounted() {
@@ -117,44 +144,198 @@
      return;
    }
    await this.CallgetList();
    this.isRegistering = true; // å¼€å§‹æ³¨å†Œ
    sipService.init(this.sipConfig);
    // è®¾ç½®çŠ¶æ€å›žè°ƒ
    sipService.onStatusChange = (status) => {
      this.sipStatus = status.text;
      this.sipStatusClass = `status-${status.type}`;
      // æ³¨å†ŒæˆåŠŸæˆ–å¤±è´¥æ—¶å–æ¶ˆåŠ è½½çŠ¶æ€
      if (status.type === "registered" || status.type === "failed") {
        this.isRegistering = false;
      }
      // æ³¨å†ŒæˆåŠŸ
      if (status.type === "registered") {
        this.startCallsetState();
      }
      // å¤„理注册失败和断开连接情况
      if (status.type === "failed" || status.type === "disconnected") {
        this.overCallsetState(); // é‡Šæ”¾åˆ†æœºå·
        this.isRegistering = false;
      }
    };
    // ç›‘听通话状态变化
    sipService.onCallStatusChange = (status) => {
      this.callStatus = status.type;
      this.isCalling = status.type === "calling" || status.type === "connected";
      // é€šçŸ¥çˆ¶ç»„件通话状态变化
      this.$emit("call-status-change", status);
    };
    // æ·»åŠ æ³¨å†Œè¶…æ—¶å¤„ç†
    setTimeout(() => {
      if (this.isRegistering && this.sipStatus !== "已注册") {
        this.isRegistering = false;
        this.$message.warning("SIP注册超时,请检查网络连接");
      }
    }, 10000); // 10秒超时
    this.isRegistering = true;
    this.initSipService();
    this.setupHeartbeat();
  },
  methods: {
    async initSipService() {
      try {
        // åˆå§‹åŒ–sipService
        sipService.init(this.sipConfig);
        // è®¾ç½®çŠ¶æ€å›žè°ƒ
        sipService.onStatusChange = (status) => {
          this.sipStatus = status.text;
          this.sipStatusClass = `status-${status.type}`;
          // å¤„理各种状态
          if (status.type === "registered") {
            this.handleRegistered();
          } else if (status.type === "failed" || status.type === "disconnected") {
            this.handleDisconnected();
          } else if (status.type === "connecting") {
            this.handleConnecting();
          }
        };
        // ç›‘听通话状态变化
        sipService.onCallStatusChange = (status) => {
          this.callStatus = status.type;
          this.isCalling = status.type === "calling" || status.type === "connected";
          this.updateLastActivityTime(); // é€šè¯çŠ¶æ€å˜åŒ–æ—¶æ›´æ–°æ´»åŠ¨æ—¶é—´
          this.$emit("call-status-change", status);
        };
        // è®¾ç½®è¶…时处理
        this.setupRegistrationTimeout();
      } catch (error) {
        console.error("SIP服务初始化失败:", error);
        this.handleDisconnected();
      }
    },
    handleRegistered() {
      console.log("SIP注册成功");
      this.isRegistering = false;
      this.isReconnecting = false;
      this.reconnectCount = 0; // é‡ç½®é‡è¿žè®¡æ•°
      this.updateLastActivityTime();
      this.startCallsetState();
      // æ¸…除重连定时器
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
        this.reconnectTimer = null;
      }
    },
    handleDisconnected() {
      console.log("SIP连接断开");
      this.isRegistering = false;
      this.overCallsetState();
      // å¦‚果不是通话中断开,尝试重连
      if (!this.isCalling) {
        this.scheduleReconnect();
      }
    },
    handleConnecting() {
      this.isReconnecting = true;
    },
    setupRegistrationTimeout() {
      setTimeout(() => {
        if (this.isRegistering && this.sipStatus !== "已注册") {
          this.isRegistering = false;
          this.$message.warning("SIP注册超时,正在尝试重连...");
          this.scheduleReconnect();
        }
      }, 10000);
    },
    // è®¾ç½®å¿ƒè·³æ£€æµ‹
    setupHeartbeat() {
      this.heartbeatTimer = setInterval(() => {
        this.checkConnection();
      }, 60000); // æ¯30秒检查一次连接
    },
    // æ£€æŸ¥è¿žæŽ¥çŠ¶æ€
    async checkConnection() {
      // å¦‚果正在注册、重连或通话中,不检查
      if (this.isRegistering || this.isReconnecting || this.isCalling) {
        return;
      }
      // æ£€æŸ¥SIP连接状态
      if (sipService && sipService.ua) {
        const isConnected = sipService.ua.isConnected();
        const isRegistered = sipService.ua.isRegistered();
        if (!isConnected || !isRegistered) {
          console.log("心跳检测: è¿žæŽ¥å¼‚常,尝试重连");
          await this.reconnectSip();
        } else {
          console.log("心跳检测: è¿žæŽ¥æ­£å¸¸");
          this.updateLastActivityTime();
        }
      } else {
        console.log("心跳检测: UA不存在,尝试重新初始化");
        await this.reconnectSip();
      }
    },
    // è®¡åˆ’重连
    scheduleReconnect() {
      if (this.reconnectTimer || this.isReconnecting) {
        return;
      }
      if (this.reconnectCount >= this.maxReconnectAttempts) {
        console.log("达到最大重连次数,停止重连");
        this.$message.error("SIP连接失败,请刷新页面重试");
        return;
      }
      this.reconnectCount++;
      const delay = Math.min(this.reconnectDelay * Math.pow(1.5, this.reconnectCount - 1), 30000);
      console.log(`计划在${delay}ms后重连,第${this.reconnectCount}次尝试`);
      this.reconnectTimer = setTimeout(() => {
        this.reconnectSip();
      }, delay);
    },
    // é‡æ–°è¿žæŽ¥SIP
    async reconnectSip() {
      if (this.isReconnecting || this.isRegistering) {
        return;
      }
      console.log("开始重连SIP服务...");
      this.isReconnecting = true;
      try {
        // æ¸…理现有连接
        this.cleanupSipConnection();
        // ç­‰å¾…一段时间
        await new Promise(resolve => setTimeout(resolve, 1000));
        // é‡æ–°åˆå§‹åŒ–
        await this.CallgetList(); // é‡æ–°èŽ·å–åˆ†æœºå·
        this.initSipService();
      } catch (error) {
        console.error("重连失败:", error);
        this.isReconnecting = false;
        this.scheduleReconnect(); // å¤±è´¥åŽç»§ç»­é‡è¯•
      } finally {
        if (this.reconnectTimer) {
          clearTimeout(this.reconnectTimer);
          this.reconnectTimer = null;
        }
      }
    },
    // æ¸…理SIP连接
    cleanupSipConnection() {
      if (sipService && sipService.ua) {
        try {
          sipService.ua.stop();
          sipService.ua.unregister();
        } catch (e) {
          console.warn("清理SIP连接时出错:", e);
        }
      }
    },
    // æ‰‹åŠ¨é‡è¿ž
    async manualReconnect() {
      this.reconnectCount = 0; // é‡ç½®é‡è¿žè®¡æ•°
      await this.reconnectSip();
    },
    // æ›´æ–°æœ€åŽæ´»åŠ¨æ—¶é—´
    updateLastActivityTime() {
      this.lastActivityTime = Date.now();
    },
    async startCall() {
      if (!this.phoneNumber) {
        this.$message.error("请输入电话号码");
@@ -165,46 +346,43 @@
        // å…ˆæ£€æŸ¥æ˜¯å¦å¯ä»¥å‘¼å«
        const { canCall, reason } = sipService.canMakeCall();
        if (!canCall) {
          const { canCall, reason } = sipService.canMakeCall();
          //this.$message.warning(reason);
          //return;
          // å¯é€‰: å¯ä»¥æ˜¾ç¤ºæç¤º
        }
        this.callStatus = "calling";
        this.isCalling = true;
        console.log("开始呼叫:", sipService);
        await sipService.makeCall(this.phoneNumber);
      } catch (error) {
        let registrationTime = Date.now(); // è®°å½•注销成功时间
        console.log(registrationTime, "呼叫失败时间");
        console.error("呼叫失败1:", error);
        // this.callStatus = "ended";
        // this.isCalling = false;
        //this.$message.error(`呼叫失败: ${error.message}`);
        try {
          // å…ˆæ£€æŸ¥æ˜¯å¦å¯ä»¥å‘¼å«
          // å°è¯•加0再次呼叫
          const { canCall, reason } = sipService.canMakeCall();
          if (!canCall) {
            const { canCall, reason } = sipService.canMakeCall();
            // å¯é€‰å¤„理
          }
          this.callStatus = "calling";
          this.isCalling = true;
          console.log("开始呼叫:", sipService);
          console.log("尝试加0再次呼叫:", sipService);
          await sipService.makeCall("0" + this.phoneNumber);
        } catch (error) {
          this.callStatus = "ended";
          this.isCalling = false;
          this.$message.error("呼叫失败,请检查网络或号码");
        }
      }
    },
    // æŸ¥è¯¢å¯ç”¨åˆ†æœºå·
    async CallgetList() {
      try {
        const res = await CallgetList();
        this.randomNum = res.data[0].tel;
        this.randomID = res.data[0].id;
        // åŠ¨æ€è®¾ç½®sipUri,域名部分会在sipService中动态处理
        const orgName = localStorage.getItem("orgname");
        if (orgName == "丽水市中医院") {
          this.sipConfig.sipUri = `${this.randomNum}@192.168.10.124`;
@@ -218,9 +396,10 @@
        }
      } catch (error) {
        console.error("获取分机号失败:", error);
        // this.updateStatus("failed", "获取分机号失败");
        throw error; // æŠ›å‡ºé”™è¯¯ä»¥ä¾¿ä¸Šå±‚处理
      }
    },
    async startCallsetState() {
      try {
        await CallsetState({ id: this.randomID, state: 1 });
@@ -240,12 +419,25 @@
        console.error("释放分机号失败:", error);
      }
    },
    endCall() {
      sipService.endCall();
      this.callStatus = "ended";
      this.isCalling = false;
    },
    cleanupResources() {
      // æ¸…除所有定时器
      if (this.heartbeatTimer) {
        clearInterval(this.heartbeatTimer);
        this.heartbeatTimer = null;
      }
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
        this.reconnectTimer = null;
      }
      // ç»“束通话
      if (this.isCalling) {
        sipService.endCall();
@@ -255,19 +447,17 @@
      this.overCallsetState();
      // æ–­å¼€ SIP è¿žæŽ¥
      if (sipService.ua) {
        sipService.ua.stop();
      }
      this.cleanupSipConnection();
    },
  },
  beforeUnmount() {
    // ç»„件销毁时确保释放资源
    this.cleanupResources();
  },
};
</script>
<style scoped>
/* ä¿æŒåŽŸæœ‰æ ·å¼ä¸å˜ï¼Œåªæ·»åŠ æ–°æ ·å¼ */
.call-container {
  display: flex;
  flex-direction: column;
@@ -279,25 +469,93 @@
  border-radius: 8px;
}
input {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
.reconnect-info {
  font-size: 12px;
  color: #666;
  margin-left: 5px;
}
.call-btn {
.reconnect-btn {
  padding: 8px 12px;
  background-color: #ff9800;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
}
.reconnect-btn:hover:not(:disabled) {
  background-color: #f57c00;
}
.reconnect-btn:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}
.call-btn.reconnecting {
  background-color: #ff9800;
}
.call-btn:hover:not(:disabled) {
  background-color: #45a049;
}
.call-btn:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}
.call-btn.calling {
  background-color: #2196f3;
}
.call-btn.registering,
.call-btn.reconnecting {
  position: relative;
}
.end-call-btn {
  padding: 10px;
  background-color: #4caf50;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.end-call-btn:hover {
  background-color: #d32f2f;
}
/* çŠ¶æ€æ ·å¼ä¿æŒä¸å˜ */
.sip-status,
.call-status {
  padding: 8px;
  margin: 10px 0;
  margin-bottom: 10px;
  border-radius: 4px;
  text-align: center;
}
.status-disconnected {
  background-color: #ffebee;
  color: #c62828;
}
.status-connecting {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-registered {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-failed {
  background-color: #ffebee;
  color: #c62828;
}
.status-idle {
@@ -316,132 +574,6 @@
}
.status-ended {
  background-color: #ffebee;
  color: #c62828;
}
/* åŽŸæœ‰æ ·å¼ä¿æŒä¸å˜ */
.call-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 300px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
}
.call-btn {
  padding: 10px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.call-btn:hover:not(:disabled) {
  background-color: #45a049;
}
.call-btn:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}
.call-btn.calling {
  background-color: #2196f3;
}
.end-call-btn {
  padding: 10px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.end-call-btn:hover {
  background-color: #d32f2f;
}
.sip-status {
  padding: 8px;
  margin-bottom: 10px;
  border-radius: 4px;
  text-align: center;
}
.status-disconnected {
  background-color: #ffebee;
  color: #c62828;
}
.status-connecting {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-registered {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-failed {
  background-color: #ffebee;
  color: #c62828;
}
.call-btn:hover {
  background-color: #45a049;
}
.call-btn.calling {
  background-color: #2196f3;
}
.end-call-btn {
  padding: 10px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.end-call-btn:hover {
  background-color: #d32f2f;
}
.call-status {
  margin-top: 10px;
  font-size: 14px;
  color: #666;
}
.sip-status {
  padding: 8px;
  margin-bottom: 10px;
  border-radius: 4px;
  text-align: center;
}
.status-disconnected {
  background-color: #ffebee;
  color: #c62828;
}
.status-connecting {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-registered {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-failed {
  background-color: #ffebee;
  color: #c62828;
}
src/components/OptionalForm/index.vue
@@ -66,9 +66,16 @@
              :data="donorchargeList"
              tooltip-effect="dark"
              style="width: 100%"
              @select="handleSelect"
              @select-all="handleSelectAll"
              @selection-change="handleSelectionChange"
            >
              <el-table-column class="checkall" type="selection" width="55">
              <el-table-column
                class="checkall"
                type="selection"
                width="55"
                :selectable="checkSelectable"
              >
              </el-table-column>
              <el-table-column
                prop="icdid"
@@ -121,6 +128,8 @@
      },
      donorchargeList: [],
      donorchargeanlList: [], //案例列表
      // æ–°å¢žï¼šæ˜¯å¦æ­£åœ¨å¤„理全选操作的标志
      isSelectAllProcessing: false,
    };
  },
@@ -202,41 +211,83 @@
        this.Restorecheck();
      });
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      if (this.decision) return;
      // åˆ¤æ–­æ˜¯å¦æœ‰åˆ é™¤
      if (this.multipleSelection.length <= selection.length) {
        this.multipleSelection = selection;
    // æ–°å¢žï¼šå¤„理单个选择
    handleSelect(selection, row) {
      if (this.isSelectAllProcessing) return;
      const isSelected = selection.includes(row);
      this.handleItemSelection(row, isSelected);
    },
    // æ–°å¢žï¼šå¤„理全选/全不选
    handleSelectAll(selection) {
      this.isSelectAllProcessing = true;
      if (selection.length === 0) {
        // å…¨ä¸é€‰ï¼šç§»é™¤å½“前页所有数据
        this.donorchargeList.forEach(item => {
          this.removeFromSelections(item);
        });
      } else {
        this.multipleSelection.forEach((item) => {
          if (selection.includes(item)) {
          } else {
            if (this.multipleSelection.length == 1) {
              this.multipleSelection = [];
            } else {
              this.multipleSelection.splice(
                this.multipleSelection.indexOf(item),
                1
              );
            }
            if (this.overallCase.length == 1) {
              this.overallCase = [];
            } else {
              this.overallCase.splice(this.overallCase.indexOf(item), 1);
            }
          }
        // å…¨é€‰ï¼šæ·»åŠ å½“å‰é¡µæ‰€æœ‰æ•°æ®
        this.donorchargeList.forEach(item => {
          this.addToSelections(item);
        });
      }
      // èµ‹å€¼ç»™æ•´ä½“选中数组
      this.multipleSelection.forEach((item) => {
        if (this.overallCase.every((obj) => obj.icdname != item.icdname)) {
          this.overallCase.push(item);
        }
      this.$nextTick(() => {
        this.isSelectAllProcessing = false;
      });
      console.log(this.multipleSelection, "触发选择后multipleSelection");
    },
    // æ–°å¢žï¼šå¤„理单个项目的选择/取消选择
    handleItemSelection(row, isSelected) {
      if (isSelected) {
        this.addToSelections(row);
      } else {
        this.removeFromSelections(row);
      }
    },
    // æ–°å¢žï¼šæ·»åŠ åˆ°é€‰ä¸­åˆ—è¡¨
    addToSelections(row) {
      // å¦‚果已经在多选数组中,不再添加
      if (this.multipleSelection.some(item => item.icdid === row.icdid)) {
        return;
      }
      this.multipleSelection.push(row);
      // æ·»åŠ åˆ°æ€»æ•°ç»„
      if (this.overallCase.every(item => item.icdid !== row.icdid)) {
        this.overallCase.push({...row});
      }
    },
    // æ–°å¢žï¼šä»Žé€‰ä¸­åˆ—表移除
    removeFromSelections(row) {
      const index = this.multipleSelection.findIndex(item => item.icdid === row.icdid);
      if (index > -1) {
        this.multipleSelection.splice(index, 1);
      }
      // ä»Žæ€»æ•°ç»„中移除
      const overallIndex = this.overallCase.findIndex(item => item.icdid === row.icdid);
      if (overallIndex > -1) {
        this.overallCase.splice(overallIndex, 1);
      }
    },
    // ä¿ç•™åŽŸæœ‰çš„selection-change事件处理,但简化逻辑
    handleSelectionChange(selection) {
      // å¦‚果正在处理全选操作,不执行这里的逻辑
      if (this.isSelectAllProcessing) return;
      // åŽŸæœ‰çš„å¤æ‚é€»è¾‘å¯ä»¥ä¿ç•™ï¼Œä½†ä¸ºäº†æ¸…æ™°ï¼Œå»ºè®®ä½¿ç”¨ä¸Šé¢çš„æ–°æ–¹æ³•
      console.log('selection changed:', selection.length);
    },
    // åˆ‡æ¢é¡µåŽæ¢å¤é€‰ä¸­
    Restorecheck() {
      console.log(this.overallCase, "this.overallCase");
@@ -268,6 +319,11 @@
    AddDispatchpatients() {
      this.$emit("addoption");
    },
    // æ–°å¢žï¼šæ£€æŸ¥æ˜¯å¦å¯ä»¥é€‰æ‹©ï¼ˆå¯é€‰ï¼Œç”¨äºŽæŽ§åˆ¶æŸäº›è¡Œä¸å¯é€‰ï¼‰
    checkSelectable(row, index) {
      return true; // æ‰€æœ‰è¡Œéƒ½å¯é€‰
    }
  },
};
</script>
@@ -316,7 +372,7 @@
  }
}
::v-deep.el-table .el-table__header th:first-child .el-checkbox {
  display: none;
  display: inline-block; /* ä¿®æ”¹è¿™é‡Œï¼Œæ˜¾ç¤ºå…¨é€‰å¤é€‰æ¡† */
}
.el-tag + .el-tag {
  margin-left: 10px;
src/components/StatisticsCards/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,271 @@
<template>
  <div class="statistics-cards" style="margin-bottom: 20px">
    <el-row :gutter="16">
      <el-col
        v-for="(item, index) in mergedCardList"
        :key="index"
        :xs="12"
        :sm="8"
        :md="colSpan"
        :lg="colSpan"
      >
        <el-tooltip
          :content="getTooltipContent(item.name)"
          placement="top"
          effect="light"
          popper-class="statistics-tooltip"
        >
          <el-card
            shadow="hover"
            :body-style="item.router ? 'cursor: pointer' : 'cursor: default'"
            :class="getCardClass(item.name)"
          >
            <div
              class="card-content"
              @click="handleCardClick(item)"
            >
              <div class="card-label">
                <span class="label-text">{{ item.name }}</span>
              </div>
              <div class="card-value">
                {{ item.value !== undefined && item.value !== null ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-tooltip>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  name: "StatisticsCards",
  props: {
    cardlist: {
      type: Array,
      default: () => []
    },
    colSpan: {
      type: Number,
      default: 4
    },
    showExtra: {
      type: Boolean,
      default: true
    },
    ycvalue: {
      type: Number,
      default: 0
    },
    jgvalue: {
      type: Number,
      default: 0
    },
    showWarningCondition: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    mergedCardList() {
      let list = [...this.cardlist];
      if (this.showExtra) {
        list.push({
          name: "异常",
          value: this.ycvalue
        });
      }
      if (this.showWarningCondition) {
        list.push({
          name: "警告",
          value: this.jgvalue
        });
      }
      return list;
    }
  },
  methods: {
    getCardClass(name) {
      const classMap = {
        "患者服务总量": "total-card",
        "无需随访": "no-follow-card",
        "需随访": "need-follow-card",
        "待随访": "pending-card",
        "已完成": "completed-card",
        "异常": "error-card",
        "警告": "warning-card"
      };
      return classMap[name] || "default-card";
    },
    getTooltipContent(name) {
      const tooltips = {
        "患者服务总量": "患者服务总量 = æ— éœ€éšè®¿ + éœ€éšè®¿",
        "无需随访": "无需随访:不需要进行随访的患者数量",
        "需随访": "需随访 = å¾…随访 + å·²å®Œæˆ",
        "待随访": "待随访:等待进行随访的患者数量",
        "已完成": "已完成:已完成随访的患者数量",
        "异常": "异常数据统计",
        "警告": "警告数据统计"
      };
      return tooltips[name] || "";
    },
    handleCardClick(item) {
      if (item.router) {
        this.$router.push(item.router);
      }
      this.$emit("card-click", item);
    }
  }
};
</script>
<style scoped>
.statistics-cards {
  padding: 4px;
}
.card-content {
  padding: 12px 8px;
  transition: all 0.3s ease;
  cursor: default;
}
.card-label {
  margin-bottom: 10px;
  font-size: 20px;
  font-weight: 600;
  color: #666;
}
.card-value {
  text-align: center;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: 1px;
  transition: all 0.3s ease;
}
/* æ‚¬æµ®æ•ˆæžœ - æ•´ä½“上移+阴影加深 */
.el-card {
  border-radius: 10px;
  transition: all 0.3s ease;
  border: none;
}
.el-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1) !important;
}
/* å“åº”式 */
@media (max-width: 768px) {
  .card-value {
    font-size: 22px;
  }
  .card-content {
    padding: 12px 8px;
  }
}
</style>
<style>
/* ===== å¡ç‰‡èƒŒæ™¯è‰²ï¼ˆå…¨å±€æ ·å¼ï¼‰ ===== */
/* æ‚£è€…服务总量 - æµ…紫色 */
.total-card .el-card__body {
  background: #f0edff;
  border-radius: 10px;
}
.total-card .card-value {
  color: #7c5cfc;
}
/* æ— éœ€éšè®¿ - æµ…粉色 */
.no-follow-card .el-card__body {
  background: #fde8ef;
  border-radius: 10px;
}
.no-follow-card .card-value {
  color: #f06292;
}
/* éœ€éšè®¿ - æµ…蓝色 */
.need-follow-card .el-card__body {
  background: #e3f2fd;
  border-radius: 10px;
}
.need-follow-card .card-value {
  color: #42a5f5;
}
/* å¾…随访 - æµ…橙色 */
.pending-card .el-card__body {
  background: #fff3e0;
  border-radius: 10px;
}
.pending-card .card-value {
  color: #ff9800;
}
/* å·²å®Œæˆ - æµ…绿色 */
.completed-card .el-card__body {
  background: #e8f5e9;
  border-radius: 10px;
}
.completed-card .card-value {
  color: #66bb6a;
}
/* å¼‚常 - æµ…红色 */
.error-card .el-card__body {
  background: #fce4ec;
  border-radius: 10px;
}
.error-card .card-value {
  color: #ef5350;
}
/* è­¦å‘Š - æµ…黄色 */
.warning-card .el-card__body {
  background: #fff8e1;
  border-radius: 10px;
}
.warning-card .card-value {
  color: #ffa726;
}
/* é»˜è®¤å¡ç‰‡ */
.default-card .el-card__body {
  background: #f5f5f5;
  border-radius: 10px;
}
.default-card .card-value {
  color: #757575;
}
/* ===== æ¸…新白底蓝字 Tooltip ===== */
.statistics-tooltip {
  background: #ffffff !important;
  color: #1976d2 !important;
  border: 1px solid #bbdefb !important;
  border-radius: 8px !important;
  padding: 10px 14px !important;
  font-size: 13px !important;
  line-height: 1.6 !important;
  box-shadow: 0 4px 12px rgba(25, 118, 210, 0.15) !important;
}
.statistics-tooltip .popper__arrow {
  border-bottom-color: #bbdefb !important;
}
.statistics-tooltip .popper__arrow::after {
  border-bottom-color: #ffffff !important;
}
</style>
src/views/Satisfaction/diseaseStatistics/components/ChartDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,579 @@
<template>
  <el-dialog
    title="随访统计趋势图"
    :visible.sync="visible"
    width="80%"
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <div class="chart-container">
      <el-row :gutter="20">
        <el-col :span="12">
          <div class="chart-title">随访状态分布</div>
          <div id="pieChart" style="width: 100%; height: 400px"></div>
        </el-col>
        <el-col :span="12">
          <div class="chart-title">随访趋势分析</div>
          <div id="barLineChart" style="width: 100%; height: 400px"></div>
        </el-col>
      </el-row>
    </div>
  </el-dialog>
</template>
<script>
import * as echarts from 'echarts'
export default {
  name: 'ChartDialog',
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    data: {
      type: Array,
      default: () => []
    },
    activeTab: {
      type: String,
      default: 'first'
    }
  },
  data() {
    return {
      pieChart: null,
      barLineChart: null
    }
  },
  watch: {
    visible(newVal) {
      if (newVal) {
        this.$nextTick(() => {
          this.initCharts()
        })
      } else {
        this.destroyCharts()
      }
    }
  },
  mounted() {
    if (this.visible) {
      this.$nextTick(() => {
        this.initCharts()
      })
    }
  },
  beforeDestroy() {
    this.destroyCharts()
  },
  methods: {
    initCharts() {
      this.initPieChart()
      this.initBarLineChart()
    },
    initPieChart() {
      const pieDom = document.getElementById('pieChart')
      if (!pieDom) return
      if (this.pieChart) {
        this.pieChart.dispose()
      }
      this.pieChart = echarts.init(pieDom)
      // æ ¹æ®å½“前tab计算饼图数据
      const pieData = this.getPieChartData()
      const pieOption = {
        title: {
          text: '随访状态分布',
          left: 'center',
          textStyle: {
            color: '#333',
            fontSize: 16
          }
        },
        tooltip: {
          trigger: 'item',
          formatter: '{a} <br/>{b}: {c} ({d}%)'
        },
        legend: {
          orient: 'vertical',
          left: 'left',
          data: pieData.legendData,
          textStyle: {
            color: '#666'
          }
        },
        color: ['#FF9D4D', '#36B37E', '#FF5C5C'],
        series: [
          {
            name: '随访状态',
            type: 'pie',
            radius: ['40%', '70%'],
            avoidLabelOverlap: true,
            itemStyle: {
              borderRadius: 10,
              borderColor: '#fff',
              borderWidth: 2
            },
            label: {
              show: true,
              formatter: '{b}: {c} ({d}%)',
              color: '#333'
            },
            emphasis: {
              label: {
                show: true,
                fontSize: '18',
                fontWeight: 'bold'
              },
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            },
            data: pieData.seriesData
          }
        ]
      }
      this.pieChart.setOption(pieOption)
      window.addEventListener('resize', this.resizePieChart)
    },
    getPieChartData() {
      let legendData = []
      let seriesData = []
      if (this.activeTab === 'first') {
        legendData = ['待随访', '随访成功', '随访失败']
        const followUpData = {
          pending: 0,
          success: 0,
          fail: 0
        }
        this.data.forEach((item) => {
          followUpData.pending += item.pendingFollowUp || 0
          followUpData.success += item.followUpSuccess || 0
          followUpData.fail += item.followUpFail || 0
        })
        seriesData = [
          { value: followUpData.pending, name: '待随访' },
          { value: followUpData.success, name: '随访成功' },
          { value: followUpData.fail, name: '随访失败' }
        ]
      } else if (this.activeTab === 'second') {
        legendData = ['待随访(再次)', '随访成功(再次)', '随访失败(再次)']
        const followUpData = {
          pending: 0,
          success: 0,
          fail: 0
        }
        this.data.forEach((item) => {
          followUpData.pending += item.pendingFollowUpAgain || 0
          followUpData.success += item.followUpSuccessAgain || 0
          followUpData.fail += item.followUpFailAgain || 0
        })
        seriesData = [
          { value: followUpData.pending, name: '待随访(再次)' },
          { value: followUpData.success, name: '随访成功(再次)' },
          { value: followUpData.fail, name: '随访失败(再次)' }
        ]
      } else if (this.activeTab === 'continued') {
        legendData = ['护理完成', '护理进行中', '护理未开始']
        const careData = {
          completed: 0,
          inProgress: 0,
          notStarted: 0
        }
        this.data.forEach((item) => {
          careData.completed += item.careCompleted || 0
          careData.inProgress += item.careInProgress || 0
          careData.notStarted += item.careNotStarted || 0
        })
        seriesData = [
          { value: careData.completed, name: '护理完成' },
          { value: careData.inProgress, name: '护理进行中' },
          { value: careData.notStarted, name: '护理未开始' }
        ]
      }
      return { legendData, seriesData }
    },
    initBarLineChart() {
      const barDom = document.getElementById('barLineChart')
      if (!barDom) return
      if (this.barLineChart) {
        this.barLineChart.dispose()
      }
      this.barLineChart = echarts.init(barDom)
      // å‡†å¤‡æ•°æ®
      const chartData = this.getBarLineChartData()
      const option = {
        title: {
          text: `${chartData.title}趋势`,
          left: 'center',
          textStyle: {
            color: '#333',
            fontSize: 16
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            crossStyle: {
              color: '#999'
            }
          }
        },
        legend: {
          data: chartData.legendData,
          top: 'bottom',
          textStyle: {
            color: '#666'
          }
        },
        color: chartData.colors,
        xAxis: {
          type: 'category',
          data: chartData.categories,
          axisLabel: {
            interval: 0,
            rotate: 30,
            color: '#666'
          },
          axisLine: {
            lineStyle: {
              color: '#ddd'
            }
          }
        },
        yAxis: [
          {
            type: 'value',
            name: chartData.yAxisName1,
            min: 0,
            axisLabel: {
              color: '#666'
            },
            axisLine: {
              lineStyle: {
                color: '#ddd'
              }
            },
            splitLine: {
              lineStyle: {
                color: '#f0f0f0'
              }
            }
          },
          {
            type: 'value',
            name: '百分比(%)',
            min: 0,
            max: 100,
            axisLabel: {
              color: '#666',
              formatter: '{value}%'
            },
            axisLine: {
              lineStyle: {
                color: '#ddd'
              }
            },
            splitLine: {
              show: false
            }
          }
        ],
        series: chartData.series,
        grid: {
          top: '15%',
          left: '3%',
          right: '4%',
          bottom: '15%',
          containLabel: true
        }
      }
      this.barLineChart.setOption(option)
      window.addEventListener('resize', this.resizeBarLineChart)
    },
    getBarLineChartData() {
      const categories = this.data.map(
        (item) => item.leavehospitaldistrictname || item.deptname
      )
      let title = '科室/病区'
      let yAxisName1 = '人次'
      let legendData = []
      let colors = []
      let series = []
      if (this.activeTab === 'first') {
        title = '首次随访'
        yAxisName1 = '人次'
        legendData = ['出院人次', '应随访人次', '随访率(%)', '及时率(%)']
        colors = ['#5470C6', '#91CC75', '#EE6666', '#9A60B4']
        const dischargeData = this.data.map((item) => item.dischargeCount || 0)
        const followUpData = this.data.map((item) => item.followUpNeeded || 0)
        const followUpRateData = this.data.map((item) => {
          if (!item.followUpRate) return 0
          const rateStr = String(item.followUpRate).replace('%', '')
          return parseFloat(rateStr) || 0
        })
        const timelyRateData = this.data.map((item) =>
          item.rate ? (Number(item.rate) * 100).toFixed(2) : 0
        )
        series = [
          {
            name: '出院人次',
            type: 'bar',
            barWidth: '25%',
            data: dischargeData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '应随访人次',
            type: 'bar',
            barWidth: '25%',
            data: followUpData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '随访率(%)',
            type: 'line',
            yAxisIndex: 1,
            data: followUpRateData,
            symbolSize: 8,
            lineStyle: {
              width: 3
            },
            markLine: {
              silent: true,
              data: [
                {
                  yAxis: 80,
                  lineStyle: {
                    color: '#EE6666',
                    type: 'dashed'
                  }
                }
              ]
            }
          },
          {
            name: '及时率(%)',
            type: 'line',
            yAxisIndex: 1,
            data: timelyRateData,
            symbolSize: 8,
            lineStyle: {
              width: 3,
              type: 'dotted'
            },
            markLine: {
              silent: true,
              data: [
                {
                  yAxis: 90,
                  lineStyle: {
                    color: '#9A60B4',
                    type: 'dashed'
                  }
                }
              ]
            }
          }
        ]
      } else if (this.activeTab === 'second') {
        title = '再次随访'
        yAxisName1 = '人次'
        legendData = ['出院人次', '应随访人次', '随访率(%)']
        colors = ['#5470C6', '#91CC75', '#EE6666']
        const dischargeData = this.data.map((item) => item.dischargeCount || 0)
        const followUpData = this.data.map((item) => item.followUpNeeded || 0)
        const followUpRateAgainData = this.data.map((item) => {
          if (!item.followUpRateAgain) return 0
          const rateStr = String(item.followUpRateAgain).replace('%', '')
          return parseFloat(rateStr) || 0
        })
        series = [
          {
            name: '出院人次',
            type: 'bar',
            barWidth: '25%',
            data: dischargeData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '应随访人次',
            type: 'bar',
            barWidth: '25%',
            data: followUpData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '随访率(%)',
            type: 'line',
            yAxisIndex: 1,
            data: followUpRateAgainData,
            symbolSize: 8,
            lineStyle: {
              width: 3
            },
            markLine: {
              silent: true,
              data: [
                {
                  yAxis: 80,
                  lineStyle: {
                    color: '#EE6666',
                    type: 'dashed'
                  }
                }
              ]
            }
          }
        ]
      } else if (this.activeTab === 'continued') {
        title = '延续护理'
        yAxisName1 = '人次'
        legendData = ['延续护理人次', '护理完成', '完成率(%)']
        colors = ['#5470C6', '#91CC75', '#EE6666']
        const continuedCareData = this.data.map((item) => item.continuedCareCount || 0)
        const careCompletedData = this.data.map((item) => item.careCompleted || 0)
        const completionRateData = this.data.map((item) => {
          if (!item.completionRate) return 0
          const rateStr = String(item.completionRate).replace('%', '')
          return parseFloat(rateStr) || 0
        })
        series = [
          {
            name: '延续护理人次',
            type: 'bar',
            barWidth: '25%',
            data: continuedCareData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '护理完成',
            type: 'bar',
            barWidth: '25%',
            data: careCompletedData,
            itemStyle: {
              borderRadius: [4, 4, 0, 0]
            }
          },
          {
            name: '完成率(%)',
            type: 'line',
            yAxisIndex: 1,
            data: completionRateData,
            symbolSize: 8,
            lineStyle: {
              width: 3
            },
            markLine: {
              silent: true,
              data: [
                {
                  yAxis: 85,
                  lineStyle: {
                    color: '#EE6666',
                    type: 'dashed'
                  }
                }
              ]
            }
          }
        ]
      }
      return {
        title,
        yAxisName1,
        categories,
        legendData,
        colors,
        series
      }
    },
    resizePieChart() {
      if (this.pieChart) {
        this.pieChart.resize()
      }
    },
    resizeBarLineChart() {
      if (this.barLineChart) {
        this.barLineChart.resize()
      }
    },
    destroyCharts() {
      if (this.pieChart) {
        this.pieChart.dispose()
        this.pieChart = null
      }
      if (this.barLineChart) {
        this.barLineChart.dispose()
        this.barLineChart = null
      }
      window.removeEventListener('resize', this.resizePieChart)
      window.removeEventListener('resize', this.resizeBarLineChart)
    },
    handleClose() {
      this.destroyCharts()
      this.$emit('close')
    }
  }
}
</script>
<style lang="scss" scoped>
.chart-container {
  .chart-title {
    text-align: center;
    font-size: 16px;
    font-weight: bold;
    margin-bottom: 20px;
    color: #333;
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/ContinuedCare.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,633 @@
<template>
  <div class="continued-care">
    <div class="your-table-container">
      <el-table
        v-loading="loading"
        :data="tableData"
        :border="true"
        show-summary
        :summary-method="getSummaries"
      >
        <!-- è¡¨æ ¼åˆ—定义 -->
        <el-table-column
          label="序号"
          type="index"
          align="center"
          width="60"
        />
        <el-table-column
          label="病区名称"
          align="center"
          prop="wardName"
          width="200"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          label="已延续数量"
          align="center"
          prop="continuedCount"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="handleViewDetails(scope.row, 'continued', '已延续列表')"
            >
              <span class="button-zx">{{ scope.row.continuedCount }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="未延续数量"
          align="center"
          prop="unContinuedCount"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="handleViewDetails(scope.row, 'uncontinued', '未延续列表')"
            >
              <span class="button-zx">{{ scope.row.unContinuedCount }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="延续率"
          align="center"
          prop="continuedRate"
          width="120"
        />
        <!-- <el-table-column
          label="操作"
          align="center"
          width="150"
        >
          <template slot-scope="scope">
            <el-button
              size="small"
              type="primary"
              @click="handleRowClick(scope.row)"
            >
              æŸ¥çœ‹æŠ¤å£«è¯¦æƒ…
            </el-button>
          </template>
        </el-table-column> -->
      </el-table>
    </div>
    <!-- æŠ¤å£«è¯¦æƒ…弹窗 -->
    <el-dialog
      title="护士延续护理详情"
      :visible.sync="nurseDialogVisible"
      width="80%"
      :close-on-click-modal="false"
    >
      <div v-if="currentWardData">
        <el-table
          v-loading="nurseLoading"
          :data="nurseData"
          :border="true"
        >
          <el-table-column
            label="护士姓名"
            prop="nurseName"
            align="center"
            width="120"
          />
          <el-table-column
            label="科室"
            prop="deptName"
            align="center"
            width="150"
          />
          <el-table-column
            label="已延续数量"
            prop="continuedCount"
            align="center"
          />
          <el-table-column
            label="未延续数量"
            prop="unContinuedCount"
            align="center"
          />
          <el-table-column
            label="延续率"
            prop="continuedRate"
            align="center"
            width="120"
          />
        </el-table>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { getContinueNerseCount, getNurseContinuedDetail } from "@/api/system/user";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
export default {
  name: "ContinuedCare",
  props: {
    queryParams: {
      type: Object,
      required: true,
    },
    flatArrayhospit: {
      type: Array,
      default: () => [],
    },
    flatArraydept: {
      type: Array,
      default: () => [],
    },
    options: {
      type: Array,
      default: () => [],
    },
    orgname: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      tableData: [],
      loading: false,
      nurseDialogVisible: false,
      nurseLoading: false,
      currentWardData: null,
      nurseData: [],
      originalData: {},
      totalData: {
        continued: 0,
        uncontinued: 0
      }
    };
  },
  methods: {
    loadData() {
      this.loading = true;
      const params = {
        leavehospitaldistrictcodes:
          this.queryParams.leavehospitaldistrictcodes.includes("all")
            ? this.getAllWardCodes()
            : this.queryParams.leavehospitaldistrictcodes,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
      };
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      getContinueNerseCount(params)
        .then((response) => {
          this.originalData = response.data;
          this.processData(response.data);
        })
        .catch((error) => {
          console.error("获取延续护理数据失败:", error);
          this.$message.error("获取延续护理数据失败");
        })
        .finally(() => {
          this.loading = false;
        });
    },
    processData(data) {
      this.totalData = {
        continued: data.已延续总数量 || 0,
        uncontinued: data.未延续总数量 || 0
      };
      const processedData = [];
      if (data.详情 && Array.isArray(data.详情)) {
        data.详情.forEach((item) => {
          // æå–病区名称和数据
          Object.keys(item).forEach(key => {
            if (key.startsWith('已延续_')) {
              const wardName = key.replace('已延续_', '');
              const continuedCount = item[key];
              const unContinuedCount = item[`未延续_${wardName}`] || 0;
              const total = continuedCount + unContinuedCount;
              const continuedRate = total > 0 ? ((continuedCount / total) * 100).toFixed(2) + '%' : '0.00%';
              processedData.push({
                wardName,
                continuedCount,
                unContinuedCount,
                continuedRate,
                originalData: item
              });
            }
          });
        });
      }
      // æŽ’序
      this.tableData = this.customSort(processedData);
    },
    getAllWardCodes() {
      return this.flatArrayhospit
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    getAllDeptCodes() {
      return this.flatArraydept
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    customSort(data) {
      const order = [
        "一", "二", "三", "四", "五", "六", "七", "八", "九", "十",
        "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
        "二十一", "二十二", "二十三", "二十四", "二十五", "二十六", "二十七", "二十八", "二十九", "三十",
        "三十一", "三十二", "三十三", "三十四", "三十五", "三十六", "三十七", "三十八", "三十九", "四十",
        "四十一", "四十二", "四十三", "四十四", "四十五"
      ];
      return data.sort((a, b) => {
        const getIndex = (name) => {
          if (!name || typeof name !== "string") return -1;
          const chineseMatch = name.match(/^(\d+)-/);
          if (chineseMatch && chineseMatch[1]) {
            const num = parseInt(chineseMatch[1], 10);
            if (num >= 1 && num <= 45) {
              return num - 1;
            }
          }
          // å°è¯•匹配中文数字
          for (let i = 0; i < order.length; i++) {
            if (name.includes(order[i])) {
              return i;
            }
          }
          return -1;
        };
        const indexA = getIndex(a.wardName);
        const indexB = getIndex(b.wardName);
        if (indexA === -1 && indexB === -1) {
          return (a.wardName || "").localeCompare(b.wardName || "");
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
        return indexA - indexB;
      });
    },
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }
        if (index === 1) { // ç—…区名称列
          sums[index] = "/";
          return;
        }
        if (index === 2) { // å·²å»¶ç»­æ•°é‡åˆè®¡
          const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
          sums[index] = this.formatNumber(totalContinued);
        } else if (index === 3) { // æœªå»¶ç»­æ•°é‡åˆè®¡
          const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
          sums[index] = this.formatNumber(totalUnContinued);
        } else if (index === 4) { // å»¶ç»­çŽ‡å¹³å‡å€¼
          const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
          const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
          const total = totalContinued + totalUnContinued;
          const avgRate = total > 0 ? ((totalContinued / total) * 100).toFixed(2) + '%' : '0.00%';
          sums[index] = avgRate;
        } else {
          sums[index] = "";
        }
      });
      return sums;
    },
    formatNumber(num) {
      if (isNaN(num)) return "-";
      return Number.isInteger(num) ? num.toString() : num.toFixed(0);
    },
    handleViewDetails(row, type, titleSuffix) {
      const title = `${row.wardName}${titleSuffix}`;
      // è¿™é‡Œéœ€è¦æ ¹æ®ä½ çš„实际情况获取详情数据
      // ä½ å¯ä»¥ä»Žrow.originalData中获取,或者调用新的API
      const detailData = this.getMockDetailData(row, type);
      this.$emit("view-details", detailData, title);
    },
    handleRowClick(row) {
      this.currentWardData = row;
      this.nurseDialogVisible = true;
      this.loadNurseData(row.wardName);
    },
    async loadNurseData(wardName) {
      this.nurseLoading = true;
      try {
        const params = {
          wardName: wardName,
          startTime: this.queryParams.startTime,
          endTime: this.queryParams.endTime
        };
        const response = await getNurseContinuedDetail(params);
        this.nurseData = this.processNurseData(response.data);
      } catch (error) {
        console.error("获取护士详情失败:", error);
        this.$message.error("获取护士详情失败");
      } finally {
        this.nurseLoading = false;
      }
    },
    processNurseData(data) {
      // æ ¹æ®ä½ çš„实际API响应结构处理数据
      // è¿™é‡Œæ˜¯ä¸€ä¸ªç¤ºä¾‹
      return [
        {
          nurseName: "护士A",
          deptName: this.currentWardData.wardName,
          continuedCount: Math.floor(this.currentWardData.continuedCount * 0.3),
          unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.3),
          continuedRate: "75.00%"
        },
        {
          nurseName: "护士B",
          deptName: this.currentWardData.wardName,
          continuedCount: Math.floor(this.currentWardData.continuedCount * 0.4),
          unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.4),
          continuedRate: "80.00%"
        },
        {
          nurseName: "护士C",
          deptName: this.currentWardData.wardName,
          continuedCount: Math.floor(this.currentWardData.continuedCount * 0.3),
          unContinuedCount: Math.floor(this.currentWardData.unContinuedCount * 0.3),
          continuedRate: "70.00%"
        }
      ];
    },
    getMockDetailData(row, type) {
      // æ¨¡æ‹Ÿè¯¦æƒ…数据,实际应该调用API
      const detailData = [];
      const count = type === 'continued' ? row.continuedCount : row.unContinuedCount;
      for (let i = 1; i <= Math.min(count, 10); i++) {
        detailData.push({
          sendname: `患者${i}`,
          taskName: `${row.wardName}延续护理`,
          sendstate: type === 'continued' ? 6 : 2,
          preachform: ["人工随访", "电话随访"],
          visitTime: "2024-01-15 10:00:00",
          finishtime: type === 'continued' ? "2024-01-15 11:00:00" : "",
          endtime: "2024-01-10 09:00:00",
          nurseName: "护士A",
          drname: "医生A",
          excep: 1,
          suggest: 2,
          templatename: "延续护理服务模板",
          remark: type === 'continued' ? "已完成延续护理" : "未开始延续护理",
          bankcardno: "已完成"
        });
      }
      return detailData;
    },
    async exportTable() {
      try {
        let dateRangeString = "";
        let sheetNameSuffix = "";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateStr = this.queryParams.dateRange[0];
          const endDateStr = this.queryParams.dateRange[1];
          const formatDateForDisplay = (dateTimeStr) => {
            return dateTimeStr.split(" ")[0];
          };
          const startDateFormatted = formatDateForDisplay(startDateStr);
          const endDateFormatted = formatDateForDisplay(endDateStr);
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
        } else {
          const now = new Date();
          const currentMonth = now.getMonth() + 1;
          dateRangeString = `${currentMonth}月`;
          sheetNameSuffix = `${currentMonth}月`;
        }
        const excelName = `延续护理统计表_${dateRangeString}.xlsx`;
        const worksheetName = `延续护理统计_${sheetNameSuffix}`;
        if (!this.tableData || this.tableData.length === 0) {
          this.$message.warning("暂无延续护理数据可导出");
          return false;
        }
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(worksheetName);
        this.buildExportSheet(worksheet, sheetNameSuffix);
        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        saveAs(blob, excelName);
        this.$message.success("导出成功");
        return true;
      } catch (error) {
        console.error("导出失败:", error);
        this.$message.error(`导出失败: ${error.message}`);
        return false;
      }
    },
    buildExportSheet(worksheet, sheetNameSuffix) {
      const titleStyle = {
        font: {
          name: "微软雅黑",
          size: 16,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFE6F3FF" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const headerStyle = {
        font: {
          name: "微软雅黑",
          size: 11,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const cellStyle = {
        font: { name: "宋体", size: 10, color: { argb: "FF000000" } },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const summaryStyle = {
        font: {
          name: "宋体",
          size: 10,
          bold: true,
          color: { argb: "FF409EFF" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      // æ·»åŠ æ ‡é¢˜è¡Œ
      worksheet.mergeCells(1, 1, 1, 6);
      const titleCell = worksheet.getCell(1, 1);
      titleCell.value = `延续护理统计表_${sheetNameSuffix}`;
      titleCell.style = titleStyle;
      worksheet.getRow(1).height = 35;
      // è¡¨å¤´
      const headers = ["序号", "病区名称", "已延续数量", "未延续数量", "延续率", "操作"];
      headers.forEach((header, index) => {
        const cell = worksheet.getCell(2, index + 1);
        cell.value = header;
        cell.style = headerStyle;
      });
      worksheet.getRow(2).height = 25;
      // æ•°æ®è¡Œ
      this.tableData.forEach((item, rowIndex) => {
        const dataRow = worksheet.addRow(
          [
            rowIndex + 1,
            item.wardName,
            item.continuedCount,
            item.unContinuedCount,
            item.continuedRate,
            "查看护士详情"
          ],
          rowIndex + 3
        );
        dataRow.eachCell((cell) => {
          cell.style = cellStyle;
        });
        dataRow.height = 24;
      });
      // åˆè®¡è¡Œ
      const totalContinued = this.tableData.reduce((sum, item) => sum + item.continuedCount, 0);
      const totalUnContinued = this.tableData.reduce((sum, item) => sum + item.unContinuedCount, 0);
      const total = totalContinued + totalUnContinued;
      const totalRate = total > 0 ? ((totalContinued / total) * 100).toFixed(2) + '%' : '0.00%';
      const summaryRow = worksheet.addRow([
        "合计",
        "/",
        totalContinued,
        totalUnContinued,
        totalRate,
        "/"
      ]);
      summaryRow.eachCell((cell, colNumber) => {
        cell.style = summaryStyle;
      });
      summaryRow.height = 28;
      // åˆ—宽
      worksheet.columns = [
        { width: 8 },
        { width: 30 },
        { width: 15 },
        { width: 15 },
        { width: 12 },
        { width: 15 }
      ];
    }
  }
};
</script>
<style lang="scss" scoped>
.continued-care {
  .your-table-container {
    margin-top: 10px;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/DetailDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,302 @@
<template>
  <el-dialog
    :title="title"
    :visible.sync="visible"
    v-loading="loading"
    width="70%"
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <div class="detail-dialog">
      <div style="margin-bottom: 16px; display: flex; align-items: center">
        <span style="margin-right: 10px; font-weight: bold">患者姓名查询:</span>
        <el-input
          v-model="searchName"
          placeholder="请输入患者姓名进行筛选"
          clearable
          style="width: 300px"
          @input="handleSearch"
          @clear="handleSearch"
        />
        <span style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px">
          å…± {{ displayList.length }} æ¡è®°å½•
        </span>
      </div>
      <div class="examine-jic">
        <div class="jic-value">
          <el-row :gutter="20">
            <div class="data-list" ref="dataList" @scroll="handleScroll" v-loading="loading">
              <el-table :data="currentDisplayList" height="660" style="width: 100%">
                <el-table-column prop="sendname" align="center" label="姓名" width="100" />
                <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="任务名称" />
                <el-table-column prop="sendstate" align="center" width="200" label="任务状态">
                  <template slot-scope="scope">
                    <el-tag
                      :type="getStateTagType(scope.row.sendstate)"
                      :disable-transitions="false"
                    >
                      {{ getStateText(scope.row.sendstate) }}
                    </el-tag>
                  </template>
                </el-table-column>
                <el-table-column
                  label="任务执行方式"
                  align="center"
                  key="preachform"
                  prop="preachform"
                  width="160"
                  :show-overflow-tooltip="true"
                >
                  <template slot-scope="scope">
                    <span v-for="(item, index) in scope.row.preachform" :key="index">
                      {{ item }}{{ index < scope.row.preachform.length - 1 ? '、' : '' }}
                    </span>
                  </template>
                </el-table-column>
                <el-table-column
                  prop="visitTime"
                  align="center"
                  label="应随访时间"
                  width="200"
                  show-overflow-tooltip
                />
                <el-table-column
                  prop="finishtime"
                  align="center"
                  label="随访完成时间"
                  width="200"
                  show-overflow-tooltip
                />
                <el-table-column label="出院日期" width="200" align="center" key="endtime" prop="endtime">
                  <template slot-scope="scope">
                    <span>{{ formatTime(scope.row.endtime) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="责任护士" width="120" align="center" key="nurseName" prop="nurseName" />
                <el-table-column label="主治医生" width="120" align="center" key="drname" prop="drname" />
                <el-table-column label="结果状态" align="center" key="excep" prop="excep" width="120">
                  <template slot-scope="scope">
                    <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
                  </template>
                </el-table-column>
                <el-table-column label="处理意见" align="center" key="suggest" prop="suggest" width="120">
                  <template slot-scope="scope">
                    <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
                  </template>
                </el-table-column>
                <el-table-column prop="templatename" align="center" label="服务模板" width="200" show-overflow-tooltip />
                <el-table-column prop="remark" align="center" label="服务记录" width="200" show-overflow-tooltip />
                <el-table-column prop="bankcardno" align="center" label="呼叫状态" width="210" />
                <el-table-column label="操作" fixed="right" align="center" width="200" class-name="small-padding fixed-width">
                  <template slot-scope="scope">
                    <el-button size="medium" type="text" @click="handleDetailsGo(scope.row)">
                      <span class="button-zx">
                        <i class="el-icon-s-order"></i>查看
                      </span>
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </el-row>
        </div>
      </div>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: 'DetailDialog',
  dicts: ['sys_yujing', 'sys_suggest'],
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: ''
    },
    data: {
      type: Array,
      default: () => []
    },
    searchName: {
      type: String,
      default: ''
    },
    loading: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      localSearchName: '',
      displayList: [],
      currentDisplayList: [],
      loadIndex: 0,
      pageSize: 100,
      isLoading: false
    }
  },
  watch: {
    data: {
      immediate: true,
      handler(newData) {
        this.initializeData(newData)
      }
    },
    searchName(newVal) {
      this.localSearchName = newVal
      this.handleSearch()
    }
  },
  mounted() {
    if (this.data && this.data.length > 0) {
      this.initializeData(this.data)
    }
  },
  methods: {
    initializeData(data) {
      this.displayList = [...data]
      this.formatPreachformData()
      this.loadIndex = 0
      this.currentDisplayList = []
      this.$nextTick(() => {
        this.loadMoreData()
      })
    },
    formatPreachformData() {
      this.displayList.forEach((item) => {
        if (item.preachform) {
          if (item.endtime) {
            item.preachformson = item.preachform
            const idArray = item.preachform.split(',')
            item.preachform = idArray.map((value) => {
              const checkboxlist = this.$store.getters.checkboxlist
              const foundItem = checkboxlist.find((item) => item.value == value)
              return foundItem ? foundItem.label : null
            }).filter(label => label !== null)
          }
        }
      })
    },
    handleSearch() {
      if (!this.localSearchName.trim()) {
        this.displayList = [...this.data]
        this.formatPreachformData()
      } else {
        const keyword = this.localSearchName.toLowerCase()
        this.displayList = this.data.filter((item) => {
          return item.sendname && item.sendname.toLowerCase().includes(keyword)
        })
        this.formatPreachformData()
      }
      this.loadIndex = 0
      this.currentDisplayList = []
      this.$nextTick(() => {
        this.loadMoreData()
      })
      this.$emit('search', this.localSearchName)
    },
    loadMoreData() {
      if (this.isLoading || this.loadIndex >= this.displayList.length) return
      this.isLoading = true
      setTimeout(() => {
        const nextChunk = this.displayList.slice(
          this.loadIndex,
          this.loadIndex + this.pageSize
        )
        this.currentDisplayList = this.currentDisplayList.concat(nextChunk)
        this.loadIndex += this.pageSize
        this.isLoading = false
      }, 200)
    },
    handleScroll(event) {
      const scrollContainer = event.target
      const isAtBottom =
        scrollContainer.scrollTop + scrollContainer.clientHeight >=
        scrollContainer.scrollHeight - 10
      if (
        isAtBottom &&
        !this.isLoading &&
        this.loadIndex < this.displayList.length
      ) {
        this.loadMoreData()
      }
    },
    getStateTagType(state) {
      const stateMap = {
        1: 'primary',  // è¡¨å•已领取
        2: 'primary',  // å¾…随访
        3: 'success',  // è¡¨å•已发送
        4: 'info',     // ä¸æ‰§è¡Œ
        5: 'danger',   // å‘送失败
        6: 'success'   // å·²å®Œæˆ
      }
      return stateMap[state] || 'info'
    },
    getStateText(state) {
      const stateTextMap = {
        1: '表单已领取',
        2: '待随访',
        3: '表单已发送',
        4: '不执行',
        5: '发送失败',
        6: '已完成'
      }
      return stateTextMap[state] || '未知状态'
    },
    formatTime(time) {
      if (!time) return ''
      return this.parseTime(time)
    },
    handleDetailsGo(row) {
      this.$emit('details-go', row)
    },
    handleClose() {
      this.$emit('close')
    }
  }
}
</script>
<style lang="scss" scoped>
.detail-dialog {
  .data-list {
    max-height: 800px;
    overflow-y: auto;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/FirstFollowUp.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1511 @@
<template>
  <div class="first-follow-up">
    <div class="your-table-container">
      <el-table
        ref="exportTable"
        id="exportTableid"
        v-loading="loading"
        :data="tableData"
        :border="true"
        @selection-change="handleSelectionChange"
        @expand-change="handleRowClick"
        :row-key="getRowKey"
        show-summary
        :summary-method="getSummaries"
        :expand-row-keys="expands"
      >
        <!-- è¡¨æ ¼åˆ—定义 -->
        <el-table-column
          v-if="queryParams.statisticaltype == 1"
          label="出院病区"
          align="center"
          sortable
          key="leavehospitaldistrictname"
          prop="leavehospitaldistrictname"
          width="150"
          :show-overflow-tooltip="true"
          :sort-method="sortChineseNumber"
        />
        <el-table-column
          v-if="queryParams.statisticaltype == 2"
          label="科室"
          align="center"
          key="deptname"
          prop="deptname"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          v-if="queryParams.statisticaltype == 3"
          label="专病任务"
          width="200"
          align="center"
          key="taskName"
          prop="taskName"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          label="出院人次"
          align="center"
          key="dischargeCount"
          prop="dischargeCount"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(
                  scope.row,
                  'dischargeCountInfo',
                  '出院患者列表'
                )
              "
            >
              <span class="button-zx">{{ scope.row.dischargeCount }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="无需随访人次"
          align="center"
          width="100"
          key="nonFollowUp"
          prop="nonFollowUp"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(scope.row, 'nonFollowUpInfo', '无需随访列表')
              "
            >
              <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="应随访人次"
          align="center"
          width="100"
          key="followUpNeeded"
          prop="followUpNeeded"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(scope.row, 'followUpNeededInfo', '应随访列表')
              "
            >
              <span class="button-zx">{{ scope.row.followUpNeeded }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column align="center" label="首次专病随访">
          <el-table-column
            label="需随访"
            align="center"
            key="needFollowUp"
            prop="needFollowUp"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'needFollowUpInfo', '需随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.needFollowUp }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="待随访"
            align="center"
            key="pendingFollowUp"
            prop="pendingFollowUp"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'pendingFollowUpInfo',
                    '待随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.pendingFollowUp }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="随访成功"
            align="center"
            key="followUpSuccess"
            prop="followUpSuccess"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpSuccessInfo',
                    '随访成功列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpSuccess }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="随访失败"
            align="center"
            key="followUpFail"
            prop="followUpFail"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpFailInfo',
                    '随访失败列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpFail }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="成功率"
            align="center"
            width="120"
            key="successRate"
            prop="successRate"
          >
            <template slot-scope="scope">
              <span class="success-rate">{{
                calculateSuccessRate(
                  scope.row.followUpSuccess,
                  scope.row.needFollowUp,
                  scope.row.pendingFollowUp
                )
              }}</span>
            </template>
          </el-table-column>
          <el-table-column
            v-if="orgname != '丽水市中医院'"
            label="及时率"
            align="center"
            width="120"
            key="rate"
            prop="rate"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="handleSeeDetails(scope.row)"
              >
                <span class="button-zx"
                  >{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span
                >
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="人工"
            align="center"
            key="manual"
            prop="manual"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'manualInfo', '人工随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.manual }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="语音" align="center" key="voice" prop="voice">
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'voiceInfo', '语音随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.voice }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="短信" align="center" key="sms" prop="sms">
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="handleViewDetails(scope.row, 'smsInfo', '短信随访列表')"
              >
                <span class="button-zx">{{ scope.row.sms }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="微信"
            align="center"
            key="weChat"
            prop="weChat"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'weChatInfo', '微信随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.weChat }}</span>
              </el-button>
            </template>
          </el-table-column>
        </el-table-column>
        <!-- éšè®¿æƒ…况列(仅丽水市中医院显示) -->
        <el-table-column
          v-if="
            orgname == '丽水市中医院' || orgname == '景宁畲族自治县人民医院'
          "
          align="center"
          label="随访情况"
        >
          <el-table-column
            label="正常语音"
            align="center"
            width="100"
            key="taskSituation1"
            prop="taskSituation1"
          />
          <el-table-column
            label="患者拒接或拒访"
            align="center"
            width="100"
            key="taskSituation2"
            prop="taskSituation2"
          />
          <el-table-column
            label="面访或者接诊"
            align="center"
            width="100"
            key="taskSituation3"
            prop="taskSituation3"
          />
          <el-table-column
            label="微信随访"
            align="center"
            width="100"
            key="taskSituation4"
            prop="taskSituation4"
          />
          <el-table-column
            label="随访电话不正确"
            align="center"
            width="100"
            key="taskSituation5"
            prop="taskSituation5"
          />
          <el-table-column
            label="其他情况不宜随访"
            align="center"
            width="100"
            key="taskSituation6"
            prop="taskSituation6"
          />
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>
<script>
import { getSfStatisticsHyperlink } from "@/api/AiCentre/index";
import store from "@/store";
import { getSpecialSfStatistics, selectTimelyRate } from "@/api/system/user";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
export default {
  name: "FirstFollowUp",
  props: {
    queryParams: {
      type: Object,
      required: true,
    },
    flatArrayhospit: {
      type: Array,
      default: () => [],
    },
    flatArraydept: {
      type: Array,
      default: () => [],
    },
    options: {
      type: Array,
      default: () => [],
    },
    orgname: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      tableData: [],
      loading: false,
      expands: [],
      ids: [],
      patientqueryParams: { pn: 1, ps: 10 },
      tasktypes: store.getters.tasktypes,
    };
  },
  methods: {
    loadData() {
      this.loading = true;
      const params = {
        ...this.queryParams,
        visitCount: 1,
        leavehospitaldistrictcodes:
          this.queryParams.leavehospitaldistrictcodes.includes("all")
            ? this.getAllWardCodes()
            : this.queryParams.leavehospitaldistrictcodes,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
      };
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      params.rateDay = 7;
      getSpecialSfStatistics(params)
        .then((response) => {
          this.tableData = this.customSort(response.data);
        })
        .catch((error) => {
          console.error("获取首次随访数据失败:", error);
          this.$message.error("获取首次随访数据失败");
        })
        .finally(() => {
          this.loading = false;
        });
    },
    getAllWardCodes() {
      return this.flatArrayhospit
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    getAllDeptCodes() {
      return this.flatArraydept
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    customSort(data) {
      const order = [
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
        "十三",
        "十四",
        "十五",
        "十六",
        "十七",
        "十八",
        "十九",
        "二十",
        "二十一",
        "二十二",
        "二十三",
        "二十四",
        "二十五",
        "二十六",
        "二十七",
        "二十八",
        "二十九",
        "三十",
        "三十一",
        "三十二",
        "三十三",
        "三十四",
        "三十五",
        "三十六",
        "三十七",
        "三十八",
        "三十九",
        "四十",
        "四十一",
        "四十二",
        "四十三",
        "四十四",
        "四十五",
      ];
      return data.sort((a, b) => {
        const getIndex = (name) => {
          if (!name || typeof name !== "string") return -1;
          const chineseMatch = name.match(/^([一二三四五六七八九十]+)/);
          if (chineseMatch && chineseMatch[1]) {
            return order.indexOf(chineseMatch[1]);
          }
          const arabicMatch = name.match(/^(\d+)/);
          if (arabicMatch && arabicMatch[1]) {
            const num = parseInt(arabicMatch[1], 10);
            if (num >= 1 && num <= 45) {
              return num - 1;
            }
          }
          return -1;
        };
        const indexA = getIndex(a.leavehospitaldistrictname);
        const indexB = getIndex(b.leavehospitaldistrictname);
        if (indexA === -1 && indexB === -1) {
          return (a.leavehospitaldistrictname || "").localeCompare(
            b.leavehospitaldistrictname || ""
          );
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
        return indexA - indexB;
      });
    },
    sortChineseNumber(aRow, bRow) {
      const a = aRow.leavehospitaldistrictname;
      const b = bRow.leavehospitaldistrictname;
      const chineseNumMap = {
        ä¸€: 1,
        äºŒ: 2,
        ä¸‰: 3,
        å››: 4,
        äº”: 5,
        å…­: 6,
        ä¸ƒ: 7,
        å…«: 8,
        ä¹: 9,
        å: 10,
        åä¸€: 11,
        åäºŒ: 12,
        åä¸‰: 13,
        åå››: 14,
        åäº”: 15,
        åå…­: 16,
        åä¸ƒ: 17,
        åå…«: 18,
        åä¹: 19,
        äºŒå: 20,
        äºŒåä¸€: 21,
        äºŒåäºŒ: 22,
        äºŒåä¸‰: 23,
        äºŒåå››: 24,
        äºŒåäº”: 25,
        äºŒåå…­: 26,
        äºŒåä¸ƒ: 27,
        äºŒåå…«: 28,
        äºŒåä¹: 29,
        ä¸‰å: 30,
        ä¸‰åä¸€: 31,
        ä¸‰åäºŒ: 32,
        ä¸‰åä¸‰: 33,
        ä¸‰åå››: 34,
        ä¸‰åäº”: 35,
        ä¸‰åå…­: 36,
        ä¸‰åä¸ƒ: 37,
        ä¸‰åå…«: 38,
        ä¸‰åä¹: 39,
        å››å: 40,
        å››åä¸€: 41,
        å››åäºŒ: 42,
        å››åä¸‰: 43,
        å››åå››: 44,
        å››åäº”: 45,
      };
      const getNumberFromText = (text) => {
        if (!text || typeof text !== "string") return -1;
        const match = text.match(/^([一二三四五六七八九十]+)/);
        if (match && match[1]) {
          const chineseNum = match[1];
          return chineseNumMap[chineseNum] !== undefined
            ? chineseNumMap[chineseNum]
            : -1;
        }
        const arabicMatch = text.match(/^(\d+)/);
        if (arabicMatch && arabicMatch[1]) {
          const num = parseInt(arabicMatch[1], 10);
          return num >= 1 && num <= 45 ? num : -1;
        }
        return -1;
      };
      const numA = getNumberFromText(a);
      const numB = getNumberFromText(b);
      if (numA === -1 && numB === -1) {
        return (a || "").localeCompare(b || "");
      }
      if (numA === -1) return 1;
      if (numB === -1) return -1;
      return numA - numB;
    },
    getRowKey(row) {
      return row.statisticaltype == 1
        ? row.leavehospitaldistrictcode
        : row.deptcode;
    },
    handleRowClick(row) {
      if (this.expands.includes(this.getRowKey(row))) {
        this.expands = [];
        return;
      }
      const params = {
        ...this.queryParams,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
        leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
        drcode: "1",
        visitCount: 1,
      };
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      if (!row.doctorStats) {
        this.loading = true;
        params.rateDay = 7;
        getSpecialSfStatistics(params).then((res) => {
          this.$set(row, "doctorStats", res.data);
          this.expands = [this.getRowKey(row)];
          this.loading = false;
        });
      } else {
        this.expands = [this.getRowKey(row)];
      }
    },
    // è®¡ç®—成功率的方法
    calculateSuccessRate(followUpSuccess, needFollowUp, pendingFollowUp) {
      const success = Number(followUpSuccess) || 0;
      const need = Number(needFollowUp) || 0;
      const pending = Number(pendingFollowUp) || 0;
      // åˆ†æ¯ = éœ€éšè®¿ - å¾…随访
      const denominator = need - pending;
      if (denominator <= 0) {
        return "0.00%";
      }
      const rate = (success / denominator) * 100;
      return rate.toFixed(2) + "%";
    },
    // åœ¨ç»Ÿè®¡æ±‡æ€»æ–¹æ³•中处理成功率
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }
        if (index === 1) {
          sums[index] = "/";
          return;
        }
        if (column.property === "successRate") {
          // æˆåŠŸçŽ‡éœ€è¦é‡æ–°è®¡ç®—æ€»çš„æˆåŠŸçŽ‡ï¼Œè€Œä¸æ˜¯å¹³å‡å€¼
          const totalSuccess = data.reduce((sum, item) => {
            return sum + (Number(item.followUpSuccess) || 0);
          }, 0);
          const totalNeed = data.reduce((sum, item) => {
            return sum + (Number(item.needFollowUp) || 0);
          }, 0);
          const totalPending = data.reduce((sum, item) => {
            return sum + (Number(item.pendingFollowUp) || 0);
          }, 0);
          const denominator = totalNeed - totalPending;
          if (denominator > 0) {
            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else if (
          column.property === "followUpRate" ||
          column.property === "rate"
        ) {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-";
          }
        }
      });
      return sums;
    },
    getInnerSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "小计";
          return;
        }
        if (column.property === "drname" || column.property === "deptname") {
          sums[index] = "-";
          return;
        }
        if (column.property === "successRate") {
          // æˆåŠŸçŽ‡éœ€è¦é‡æ–°è®¡ç®—æ€»çš„æˆåŠŸçŽ‡ï¼Œè€Œä¸æ˜¯å¹³å‡å€¼
          const totalSuccess = data.reduce((sum, item) => {
            return sum + (Number(item.followUpSuccess) || 0);
          }, 0);
          const totalNeed = data.reduce((sum, item) => {
            return sum + (Number(item.needFollowUp) || 0);
          }, 0);
          const totalPending = data.reduce((sum, item) => {
            return sum + (Number(item.pendingFollowUp) || 0);
          }, 0);
          const denominator = totalNeed - totalPending;
          if (denominator > 0) {
            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else if (
          column.property === "followUpRate" ||
          column.property === "rate"
        ) {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-";
          }
        }
      });
      return sums;
    },
    formatNumber(num) {
      if (isNaN(num)) return "-";
      return Number.isInteger(num) ? num.toString() : num.toFixed(0);
    },
    handleSelectionChange(selection) {
      this.ids = selection.map((item) => item.tagid);
    },
    handleViewDetails(row, infoKey, titleSuffix, type) {
      const title = `${
        row.leavehospitaldistrictname || row.deptname
      }${titleSuffix}`;
      this.$emit("view-details", row, infoKey, title, type);
    },
    handleSeeDetails(row) {
      this.$emit("see-details", row);
    },
    // ä¸»è¡¨å¯¼å‡º
    async exportTable() {
      try {
        let dateRangeString = "";
        let sheetNameSuffix = "";
        // åˆ¤æ–­æ˜¯å¦æ˜¯ä¸½æ°´å¸‚中医院
        const isLishuiHospital = this.orgname == "丽水市中医院";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateStr = this.queryParams.dateRange[0];
          const endDateStr = this.queryParams.dateRange[1];
          if (isLishuiHospital) {
            // ä¸½æ°´å¸‚中医院:只显示年月
            const formatMonthOnly = (dateTimeStr) => {
              const date = new Date(dateTimeStr);
              const year = date.getFullYear();
              const month = date.getMonth() + 1;
              return `${year}å¹´${month}月`;
            };
            const startDateFormatted = formatMonthOnly(startDateStr);
            const endDateFormatted = formatMonthOnly(endDateStr);
            dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
            sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          } else {
            // å…¶ä»–医院:显示年月日
            const formatDateForDisplay = (dateTimeStr) => {
              return dateTimeStr.split(" ")[0];
            };
            const startDateFormatted = formatDateForDisplay(startDateStr);
            const endDateFormatted = formatDateForDisplay(endDateStr);
            dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
            sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          }
        } else {
          const now = new Date();
          const currentMonth = now.getMonth() + 1;
          const currentYear = now.getFullYear();
          if (isLishuiHospital) {
            // ä¸½æ°´å¸‚中医院:显示年月
            dateRangeString = `${currentYear}å¹´${currentMonth}月`;
            sheetNameSuffix = `${currentYear}å¹´${currentMonth}月`;
          } else {
            // å…¶ä»–医院:显示月份
            dateRangeString = `${currentMonth}月`;
            sheetNameSuffix = `${currentMonth}月`;
          }
        }
        // æ ¹æ® serviceType ç”Ÿæˆéšè®¿ç±»åž‹åç§°
        let serviceTypeName = "首次专病随访"; // æ–‡ä»¶åä½¿ç”¨çš„名称
        let sheetTypeName = "首次随访"; // å·¥ä½œè¡¨ä½¿ç”¨çš„名称(简化版)
        if (
          this.queryParams.serviceType &&
          Array.isArray(this.queryParams.serviceType) &&
          this.queryParams.serviceType.length > 0
        ) {
          if (this.tasktypes && Array.isArray(this.tasktypes)) {
            // è¿‡æ»¤å‡ºåŒ¹é…çš„随访类型
            const matchedTypes = this.tasktypes.filter((task) =>
              this.queryParams.serviceType.includes(task.value)
            );
            if (matchedTypes.length === 1) {
              // å•个类型
              const label = matchedTypes[0].label;
              serviceTypeName = `首次${label}`;
              sheetTypeName = `首次${label}`;
            } else if (matchedTypes.length > 1) {
              // å¤šä¸ªç±»åž‹
              const typeNames = matchedTypes.map((task) => task.label);
              // æ–‡ä»¶åï¼šç”¨æ–œæ åˆ†éš”
              serviceTypeName = `首次${typeNames.join("/")}`;
              // å·¥ä½œè¡¨åï¼šä½¿ç”¨ç¬¬ä¸€ä¸ªç±»åž‹æˆ–简化名称
              if (matchedTypes.length <= 2) {
                // å¦‚果只有2个类型,都显示
                sheetTypeName = `首次${typeNames[0]}等`;
              } else {
                // å¦‚果超过2个类型,只显示第一个
                sheetTypeName = `首次${typeNames[0]}等`;
              }
            } else if (this.queryParams.serviceType.length > 0) {
              // å¦‚果没有匹配的,使用原始值
              const typeStr = this.queryParams.serviceType.join("/");
              serviceTypeName = `首次${typeStr}`;
              sheetTypeName = "首次随访";
            }
          } else if (this.queryParams.serviceType.length > 0) {
            // å¦‚果没有 tasktypes,使用原始值
            const typeStr = this.queryParams.serviceType.join("/");
            serviceTypeName = `首次${typeStr}`;
            sheetTypeName = "首次随访";
          }
        }
        const excelName = `${serviceTypeName}统计表_${dateRangeString}.xlsx`;
        // æ¸…理工作表名称,移除非法字符
        const cleanSheetName = (name) => {
          // Excel工作表名不能包含的字符: * ? : \ / [ ]
          return name.replace(/[*?:\\/[\]]/g, " ");
        };
        const worksheetName = cleanSheetName(
          `${sheetTypeName}统计_${sheetNameSuffix}`
        );
        if (!this.tableData || this.tableData.length === 0) {
          this.$message.warning(`暂无${serviceTypeName}数据可导出`);
          return false;
        }
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(worksheetName);
        // æž„建表格
        this.buildExportSheet(worksheet, sheetNameSuffix);
        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        saveAs(blob, excelName);
        this.$message.success("导出成功");
        return true;
      } catch (error) {
        console.error("导出失败:", error);
        this.$message.error(`导出失败: ${error.message}`);
        return false;
      }
    },
    // å­è¡¨å¯¼å‡º
    /** å¯¼å‡ºåŒ»ç”Ÿå­è¡¨ */
    async exportDoctorTable(row) {
      try {
        const areaName =
          row.leavehospitaldistrictname || row.deptname || "未知病区";
        let dateRangeString = "";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const start = this.queryParams.dateRange[0].split(" ")[0];
          const end = this.queryParams.dateRange[1].split(" ")[0];
          dateRangeString = `${start}至${end}`;
        } else {
          dateRangeString = `${new Date().getMonth() + 1}月`;
        }
        const fileName = `${areaName}医生随访列表_${dateRangeString}.xlsx`;
        const sheetName = `${areaName}医生随访`;
        if (!row.doctorStats || row.doctorStats.length === 0) {
          this.$message.warning("当前病区暂无医生随访数据");
          return;
        }
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(sheetName);
        console.log(111);
        this.buildDoctorExportSheet(worksheet, row.doctorStats, areaName);
        console.log(222);
        const buffer = await workbook.xlsx.writeBuffer();
        saveAs(
          new Blob([buffer], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          }),
          fileName
        );
        this.$message.success("医生随访列表导出成功");
      } catch (err) {
        console.error(err);
        this.$message.error("导出失败");
      }
    },
    buildDoctorExportSheet(worksheet, data, areaName) {
      const titleStyle = {
        font: { name: "微软雅黑", size: 16, bold: true },
        alignment: { horizontal: "center", vertical: "middle" },
      };
      const headerStyle = {
        font: { name: "微软雅黑", size: 11, bold: true },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { horizontal: "center", vertical: "middle", wrapText: true },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      const cellStyle = {
        font: { name: "宋体", size: 10 },
        alignment: { horizontal: "center", vertical: "middle" },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      // æ ‡é¢˜
      worksheet.mergeCells(1, 1, 1, 10);
      worksheet.getCell(1, 1).value = `${areaName}医生随访列表`;
      worksheet.getCell(1, 1).style = titleStyle;
      worksheet.getRow(1).height = 30;
      // è¡¨å¤´
      const headers = [
        "医生姓名",
        "科室",
        "出院人次",
        "无需随访",
        "应随访",
        "需随访",
        "待随访",
        "随访成功",
        "随访失败",
        "成功率", // æ–°å¢ž
        // "随访率", // åŽŸæ¥åœ¨æˆåŠŸçŽ‡ä½ç½®
      ];
      const headerRow = worksheet.addRow(headers);
      headerRow.eachCell((cell) => {
        cell.style = headerStyle;
      });
      worksheet.getRow(2).height = 25;
      // æ•°æ®
      data.forEach((item) => {
        const row = worksheet.addRow([
          item.drname,
          item.deptname,
          item.dischargeCount,
          item.nonFollowUp,
          item.followUpNeeded,
          item.needFollowUp,
          item.pendingFollowUp,
          item.followUpSuccess,
          item.followUpFail,
          this.calculateSuccessRate(
            item.followUpSuccess,
            item.needFollowUp,
            item.pendingFollowUp
          ),
          item.followUpRate,
        ]);
        row.eachCell((cell) => {
          cell.style = cellStyle;
        });
      });
      // å°è®¡è¡Œ
      const summaryRow = worksheet.addRow(this.getDoctorExportSummary(data));
      summaryRow.eachCell((cell) => {
        cell.font = { bold: true };
        cell.fill = {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        };
      });
      // åˆ—宽
      worksheet.columns = [
        { width: 15 },
        { width: 15 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 }, // æˆåŠŸçŽ‡
        // { width: 12 }, // éšè®¿çއ
      ];
    },
    getDoctorExportSummary(data) {
      const sums = ["小计"];
      const keys = [
        "dischargeCount",
        "nonFollowUp",
        "followUpNeeded",
        "needFollowUp",
        "pendingFollowUp",
        "followUpSuccess",
        "followUpFail",
      ];
      keys.forEach((key) => {
        sums.push(data.reduce((t, r) => t + (Number(r[key]) || 0), 0));
      });
      // æˆåŠŸçŽ‡ï¼ˆå¹³å‡å€¼ï¼‰
      const successRates = data
        .map((item) => {
          const success = Number(item.followUpSuccess) || 0;
          const need = Number(item.needFollowUp) || 0;
          const pending = Number(item.pendingFollowUp) || 0;
          const denominator = need - pending;
          if (denominator <= 0) return 0;
          return success / denominator;
        })
        .filter((rate) => !isNaN(rate));
      sums.push(
        successRates.length
          ? (
              (successRates.reduce((a, b) => a + b, 0) / successRates.length) *
              100
            ).toFixed(2) + "%"
          : "0.00%"
      );
      // // éšè®¿çŽ‡ï¼ˆå¹³å‡å€¼ï¼‰
      // const followUpRates = data
      //   .map((i) => this.extractPercentageValue(i.followUpRate))
      //   .filter(Boolean);
      // sums.push(
      //   followUpRates.length
      //     ? (
      //         (followUpRates.reduce((a, b) => a + b, 0) /
      //           followUpRates.length) *
      //         100
      //       ).toFixed(2) + "%"
      //     : "0.00%"
      // );
      return sums;
    },
    buildExportSheet(worksheet, sheetNameSuffix) {
      const titleStyle = {
        font: {
          name: "微软雅黑",
          size: 16,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFE6F3FF" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const headerStyle = {
        font: {
          name: "微软雅黑",
          size: 11,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const cellStyle = {
        font: { name: "宋体", size: 10, color: { argb: "FF000000" } },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const summaryStyle = {
        font: {
          name: "宋体",
          size: 10,
          bold: true,
          color: { argb: "FF409EFF" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      // æ·»åŠ æ ‡é¢˜è¡Œ
      worksheet.mergeCells(1, 1, 1, 16);
      const titleCell = worksheet.getCell(1, 1);
      titleCell.value = `首次专病随访统计表_${sheetNameSuffix}`;
      titleCell.style = titleStyle;
      worksheet.getRow(1).height = 35;
      // è¡¨å¤´
      const secondRowHeaders = [
        "",
        "出院病区",
        "科室",
        "出院人次",
        "无需随访人次",
        "应随访人次",
        "需随访",
        "待随访",
        "随访成功",
        "随访失败",
        "成功率", // æ–°å¢ž
        // "随访率", // åŽŸä½ç½®åŽç§»
        "及时率", // åŠæ—¶çŽ‡åŽç§»
        "人工",
        "语音", // ä¿®æ­£ï¼šåº”该是语音
        "短信", // çŸ­ä¿¡
        "微信", // å¾®ä¿¡
      ];
      secondRowHeaders.forEach((header, index) => {
        const cell = worksheet.getCell(3, index + 1);
        cell.value = header;
        cell.style = headerStyle;
      });
      // åˆå¹¶å•元格
      for (let i = 1; i <= 6; i++) {
        worksheet.mergeCells(2, i, 3, i);
        const cell = worksheet.getCell(2, i);
        cell.style = headerStyle;
      }
      worksheet.getCell(2, 1).value = "";
      worksheet.getCell(2, 2).value = "出院病区";
      worksheet.getCell(2, 3).value = "科室";
      worksheet.getCell(2, 4).value = "出院人次";
      worksheet.getCell(2, 5).value = "无需随访人次";
      worksheet.getCell(2, 6).value = "应随访人次";
      worksheet.mergeCells(2, 7, 2, 16); // ä»Ž7合并到16(原来是7-15)
      worksheet.getCell(2, 7).value = "首次专病随访";
      worksheet.getCell(2, 7).style = headerStyle;
      worksheet.getRow(2).height = 28;
      worksheet.getRow(3).height = 25;
      // æ•°æ®è¡Œ
      this.tableData.forEach((item, rowIndex) => {
        const dataRow = worksheet.addRow(
          [
            "",
            item.leavehospitaldistrictname || "",
            item.deptname || "",
            item.dischargeCount || 0,
            item.nonFollowUp || 0,
            item.followUpNeeded || 0,
            item.needFollowUp || 0,
            item.pendingFollowUp || 0,
            item.followUpSuccess || 0,
            item.followUpFail || 0,
            // æˆåŠŸçŽ‡ - éœ€è¦åŠ¨æ€è®¡ç®—
            this.calculateSuccessRate(
              item.followUpSuccess,
              item.needFollowUp,
              item.pendingFollowUp
            ),
            // item.followUpRate || "0%", // éšè®¿çއ
            item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%", // åŠæ—¶çއ
            item.manual || 0,
            item.voice || 0, // è¯­éŸ³
            item.sms || 0, // çŸ­ä¿¡
            item.weChat || 0, // å¾®ä¿¡
          ],
          rowIndex + 4
        );
        dataRow.eachCell((cell) => {
          cell.style = cellStyle;
        });
        dataRow.height = 24;
      });
      // åˆè®¡è¡Œ
      const summaries = this.getExportSummaries();
      const summaryRow = worksheet.addRow(summaries);
      summaryRow.eachCell((cell, colNumber) => {
        cell.style = summaryStyle;
        if (colNumber === 1) {
          cell.value = "合计";
        }
      });
      summaryRow.height = 28;
      // åˆ—宽
      worksheet.columns = [
        { width: 8 },
        { width: 20 },
        { width: 15 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 12 }, // æˆåŠŸçŽ‡
        // { width: 12 }, // éšè®¿çއ
        { width: 12 }, // åŠæ—¶çއ
        { width: 8 }, // äººå·¥
        { width: 8 }, // è¯­éŸ³
        { width: 8 }, // çŸ­ä¿¡
        { width: 8 }, // å¾®ä¿¡
      ];
    },
    getExportSummaries() {
      const summaries = [
        "合计",
        "/",
        "/",
        0, // 3: dischargeCount
        0, // 4: nonFollowUp
        0, // 5: followUpNeeded
        0, // 6: needFollowUp
        0, // 7: pendingFollowUp
        0, // 8: followUpSuccess
        0, // 9: followUpFail
        "0%", // 10: æˆåŠŸçŽ‡
        // "0%", // 11: éšè®¿çއ
        "0%", // 12: åŠæ—¶çއ
        0, // 13: manual
        0, // 14: voice
        0, // 15: sms
        0, // 16: weChat
      ];
      this.tableData.forEach((item) => {
        summaries[3] += Number(item.dischargeCount) || 0;
        summaries[4] += Number(item.nonFollowUp) || 0;
        summaries[5] += Number(item.followUpNeeded) || 0;
        summaries[6] += Number(item.needFollowUp) || 0;
        summaries[7] += Number(item.pendingFollowUp) || 0;
        summaries[8] += Number(item.followUpSuccess) || 0;
        summaries[9] += Number(item.followUpFail) || 0;
        summaries[13] += Number(item.manual) || 0;
        summaries[14] += Number(item.voice) || 0;
        summaries[15] += Number(item.sms) || 0;
        summaries[16] += Number(item.weChat) || 0;
      });
      // æˆåŠŸçŽ‡è®¡ç®—
      const totalSuccess = summaries[8]; // followUpSuccess的总和
      const totalNeed = summaries[6]; // needFollowUp的总和
      const totalPending = summaries[7]; // pendingFollowUp的总和
      const denominator = totalNeed - totalPending;
      if (denominator > 0) {
        summaries[10] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
      } else {
        summaries[10] = "0.00%";
      }
      // éšè®¿çŽ‡è®¡ç®—
      // const followUpRateValues = this.tableData
      //   .map((item) => this.extractPercentageValue(item.followUpRate))
      //   .filter((value) => value !== null);
      // if (followUpRateValues.length > 0) {
      //   const avgFollowUpRate =
      //     followUpRateValues.reduce((sum, val) => sum + val, 0) /
      //     followUpRateValues.length;
      //   summaries[11] = (avgFollowUpRate * 100).toFixed(2) + "%";
      // }
      // åŠæ—¶çŽ‡è®¡ç®—
      const rateValues = this.tableData
        .map((item) => this.extractPercentageValue(item.rate))
        .filter((value) => value !== null);
      if (rateValues.length > 0) {
        const avgRate =
          rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length;
        summaries[12] = (avgRate * 100).toFixed(2) + "%";
      }
      // æ ¼å¼åŒ–æ•°å­—
      [3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16].forEach((index) => {
        summaries[index] = this.formatNumber(summaries[index]);
      });
      return summaries;
    },
    extractPercentageValue(value) {
      if (!value) return null;
      if (typeof value === "string" && value.includes("%")) {
        const num = parseFloat(value.replace("%", ""));
        return isNaN(num) ? null : num / 100;
      }
      const num = parseFloat(value);
      return isNaN(num) ? null : num;
    },
    selectTimelyRate(row, queryParams) {
      console.log(row, queryParams, 88);
      // const params = {
      //   ...this.patientqueryParams,
      //   starttime: this.parseTime(dateRange[0]),
      //   endtime: this.parseTime(dateRange[1]),
      //   deptcode: row.deptcode,
      // };
      this.patientqueryParams.starttime = this.parseTime(
        queryParams.dateRange[0]
      );
      this.patientqueryParams.endtime = this.parseTime(
        queryParams.dateRange[1]
      );
      this.patientqueryParams.deptcode = row.deptcode;
      console.log(1);
      this.patientqueryParams.serviceTypes = queryParams.serviceType
        ? queryParams.serviceType.join(",")
        : null;
      return selectTimelyRate(this.patientqueryParams);
    },
    selectTimelyRates(dateRange) {
      this.patientqueryParams.pn = dateRange.pageNum;
      this.patientqueryParams.ps = dateRange.pageSize;
      return selectTimelyRate(this.patientqueryParams);
    },
  },
};
</script>
<style lang="scss" scoped>
.first-follow-up {
  .your-table-container {
    margin-top: 10px;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/SecondFollowUp.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1424 @@
<template>
  <div class="second-follow-up">
    <div class="your-table-container">
      <el-table
        ref="exportTableSecond"
        id="exportTableidSecond"
        v-loading="loading"
        :data="tableData"
        :border="true"
        @selection-change="handleSelectionChange"
        @expand-change="handleRowClick"
        :row-key="getRowKey"
        show-summary
        :summary-method="getSummaries"
        :expand-row-keys="expands"
      >
        <!-- è¡¨æ ¼åˆ—定义 -->
        <el-table-column
          v-if="queryParams.statisticaltype == 1"
          label="出院病区"
          align="center"
          sortable
          key="leavehospitaldistrictname"
          prop="leavehospitaldistrictname"
          width="150"
          :show-overflow-tooltip="true"
          :sort-method="sortChineseNumber"
        />
        <el-table-column
          v-if="queryParams.statisticaltype == 2"
          label="科室"
          align="center"
          key="deptname"
          prop="deptname"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          v-if="queryParams.statisticaltype == 3"
          label="专病任务"
          width="200"
          align="center"
          key="taskName"
          prop="taskName"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          label="出院人次"
          align="center"
          key="dischargeCount"
          prop="dischargeCount"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(
                  scope.row,
                  'dischargeCountInfo',
                  '出院患者列表'
                )
              "
            >
              <span class="button-zx">{{ scope.row.dischargeCount }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="无需随访人次"
          align="center"
          width="100"
          key="nonFollowUp"
          prop="nonFollowUp"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(scope.row, 'nonFollowUpInfo', '无需随访列表')
              "
            >
              <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column
          label="应随访人次"
          align="center"
          width="100"
          key="followUpNeeded"
          prop="followUpNeeded"
        >
          <template slot-scope="scope">
            <el-button
              size="medium"
              type="text"
              @click="
                handleViewDetails(scope.row, 'followUpNeededInfo', '应随访列表')
              "
            >
              <span class="button-zx">{{ scope.row.followUpNeeded }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column align="center" label="再次专病随访">
          <el-table-column
            label="需随访"
            align="center"
            key="needFollowUpAgain"
            prop="needFollowUpAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'needFollowUpAgainInfo',
                    '再次随访需随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.needFollowUpAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="待随访"
            align="center"
            key="pendingFollowUpAgain"
            prop="pendingFollowUpAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'pendingFollowUpAgainInfo',
                    '再次随访待随访列表'
                  )
                "
              >
                <span class="button-zx">{{
                  scope.row.pendingFollowUpAgain
                }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="随访成功"
            align="center"
            key="followUpSuccessAgain"
            prop="followUpSuccessAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpSuccessAgainInfo',
                    '再次随访随访成功列表'
                  )
                "
              >
                <span class="button-zx">{{
                  scope.row.followUpSuccessAgain
                }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="随访失败"
            align="center"
            key="followUpFailAgain"
            prop="followUpFailAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpFailAgainInfo',
                    '再次随访随访失败列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpFailAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="成功率"
            align="center"
            width="120"
            key="successRateAgain"
            prop="successRateAgain"
          >
            <template slot-scope="scope">
              <span class="success-rate">{{
                calculateSuccessRate(
                  scope.row.followUpSuccessAgain,
                  scope.row.needFollowUpAgain,
                  scope.row.pendingFollowUpAgain
                )
              }}</span>
            </template>
          </el-table-column>
          <!-- <el-table-column
            label="随访率"
            align="center"
            width="120"
            key="followUpRateAgain"
            prop="followUpRateAgain"
          /> -->
          <el-table-column
            label="人工"
            align="center"
            key="manualAgain"
            prop="manualAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'manualAgainInfo',
                    '再次随访人工随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.manualAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="语音"
            align="center"
            key="voiceAgain"
            prop="voiceAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'voiceAgainInfo', '语音随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.voiceAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="短信"
            align="center"
            key="smsAgain"
            prop="smsAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'smsAgainInfo',
                    '再次随访短信随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.smsAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            label="微信"
            align="center"
            key="weChatAgain"
            prop="weChatAgain"
          >
            <template slot-scope="scope">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'weChatAgainInfo',
                    '再次随访微信随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.weChatAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>
<script>
import { getSfStatistics } from "@/api/system/user";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
import store from "@/store";
export default {
  name: "SecondFollowUp",
  props: {
    queryParams: {
      type: Object,
      required: true,
    },
    flatArrayhospit: {
      type: Array,
      default: () => [],
    },
    flatArraydept: {
      type: Array,
      default: () => [],
    },
    options: {
      type: Array,
      default: () => [],
    },
    orgname: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      tableData: [],
      loading: false,
      expands: [],
      ids: [],
      tasktypes: store.getters.tasktypes,
    };
  },
  methods: {
    loadData() {
      this.loading = true;
      const params = {
        ...this.queryParams,
        visitCount: 2,
        leavehospitaldistrictcodes:
          this.queryParams.leavehospitaldistrictcodes.includes("all")
            ? this.getAllWardCodes()
            : this.queryParams.leavehospitaldistrictcodes,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
      };
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      params.rateDay = 7;
      getSfStatistics(params)
        .then((response) => {
          this.tableData = this.customSort(response.data);
        })
        .catch((error) => {
          console.error("获取再次随访数据失败:", error);
          this.$message.error("获取再次随访数据失败");
        })
        .finally(() => {
          this.loading = false;
        });
    },
    getAllWardCodes() {
      return this.flatArrayhospit
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    getAllDeptCodes() {
      return this.flatArraydept
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    customSort(data) {
      const order = [
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
        "十三",
        "十四",
        "十五",
        "十六",
        "十七",
        "十八",
        "十九",
        "二十",
        "二十一",
        "二十二",
        "二十三",
        "二十四",
        "二十五",
        "二十六",
        "二十七",
        "二十八",
        "二十九",
        "三十",
        "三十一",
        "三十二",
        "三十三",
        "三十四",
        "三十五",
        "三十六",
        "三十七",
        "三十八",
        "三十九",
        "四十",
        "四十一",
        "四十二",
        "四十三",
        "四十四",
        "四十五",
      ];
      return data.sort((a, b) => {
        const getIndex = (name) => {
          if (!name || typeof name !== "string") return -1;
          const chineseMatch = name.match(/^([一二三四五六七八九十]+)/);
          if (chineseMatch && chineseMatch[1]) {
            return order.indexOf(chineseMatch[1]);
          }
          const arabicMatch = name.match(/^(\d+)/);
          if (arabicMatch && arabicMatch[1]) {
            const num = parseInt(arabicMatch[1], 10);
            if (num >= 1 && num <= 45) {
              return num - 1;
            }
          }
          return -1;
        };
        const indexA = getIndex(a.leavehospitaldistrictname);
        const indexB = getIndex(b.leavehospitaldistrictname);
        if (indexA === -1 && indexB === -1) {
          return (a.leavehospitaldistrictname || "").localeCompare(
            b.leavehospitaldistrictname || ""
          );
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
        return indexA - indexB;
      });
    },
    sortChineseNumber(aRow, bRow) {
      const a = aRow.leavehospitaldistrictname;
      const b = bRow.leavehospitaldistrictname;
      const chineseNumMap = {
        ä¸€: 1,
        äºŒ: 2,
        ä¸‰: 3,
        å››: 4,
        äº”: 5,
        å…­: 6,
        ä¸ƒ: 7,
        å…«: 8,
        ä¹: 9,
        å: 10,
        åä¸€: 11,
        åäºŒ: 12,
        åä¸‰: 13,
        åå››: 14,
        åäº”: 15,
        åå…­: 16,
        åä¸ƒ: 17,
        åå…«: 18,
        åä¹: 19,
        äºŒå: 20,
        äºŒåä¸€: 21,
        äºŒåäºŒ: 22,
        äºŒåä¸‰: 23,
        äºŒåå››: 24,
        äºŒåäº”: 25,
        äºŒåå…­: 26,
        äºŒåä¸ƒ: 27,
        äºŒåå…«: 28,
        äºŒåä¹: 29,
        ä¸‰å: 30,
        ä¸‰åä¸€: 31,
        ä¸‰åäºŒ: 32,
        ä¸‰åä¸‰: 33,
        ä¸‰åå››: 34,
        ä¸‰åäº”: 35,
        ä¸‰åå…­: 36,
        ä¸‰åä¸ƒ: 37,
        ä¸‰åå…«: 38,
        ä¸‰åä¹: 39,
        å››å: 40,
        å››åä¸€: 41,
        å››åäºŒ: 42,
        å››åä¸‰: 43,
        å››åå››: 44,
        å››åäº”: 45,
      };
      const getNumberFromText = (text) => {
        if (!text || typeof text !== "string") return -1;
        const match = text.match(/^([一二三四五六七八九十]+)/);
        if (match && match[1]) {
          const chineseNum = match[1];
          return chineseNumMap[chineseNum] !== undefined
            ? chineseNumMap[chineseNum]
            : -1;
        }
        const arabicMatch = text.match(/^(\d+)/);
        if (arabicMatch && arabicMatch[1]) {
          const num = parseInt(arabicMatch[1], 10);
          return num >= 1 && num <= 45 ? num : -1;
        }
        return -1;
      };
      const numA = getNumberFromText(a);
      const numB = getNumberFromText(b);
      if (numA === -1 && numB === -1) {
        return (a || "").localeCompare(b || "");
      }
      if (numA === -1) return 1;
      if (numB === -1) return -1;
      return numA - numB;
    },
    getRowKey(row) {
      return row.statisticaltype === 1
        ? row.leavehospitaldistrictcode
        : row.deptcode;
    },
    handleRowClick(row) {
      if (this.expands.includes(this.getRowKey(row))) {
        this.expands = [];
        return;
      }
      const params = {
        ...this.queryParams,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
        leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
        drcode: "1",
        visitCount: 2,
      };
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      if (!row.doctorStats) {
        this.loading = true;
        params.rateDay = 7;
        getSfStatistics(params).then((res) => {
          this.$set(row, "doctorStats", res.data);
          this.expands = [this.getRowKey(row)];
          this.loading = false;
        });
      } else {
        this.expands = [this.getRowKey(row)];
      }
    },
    // åœ¨ç»Ÿè®¡æ±‡æ€»æ–¹æ³•中处理成功率
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }
        if (index === 1) {
          sums[index] = "/";
          return;
        }
        if (column.property === "successRateAgain") {
          // æˆåŠŸçŽ‡éœ€è¦é‡æ–°è®¡ç®—æ€»çš„æˆåŠŸçŽ‡ï¼Œè€Œä¸æ˜¯å¹³å‡å€¼
          const totalSuccess = data.reduce((sum, item) => {
            return sum + (Number(item.followUpSuccessAgain) || 0);
          }, 0);
          const totalNeed = data.reduce((sum, item) => {
            return sum + (Number(item.needFollowUpAgain) || 0);
          }, 0);
          const totalPending = data.reduce((sum, item) => {
            return sum + (Number(item.pendingFollowUpAgain) || 0);
          }, 0);
          const denominator = totalNeed - totalPending;
          if (denominator > 0) {
            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else if (column.property === "followUpRateAgain") {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-";
          }
        }
      });
      return sums;
    },
    getInnerSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "小计";
          return;
        }
        if (column.property === "drname" || column.property === "deptname") {
          sums[index] = "-";
          return;
        }
        if (column.property === "successRateAgain") {
          // æˆåŠŸçŽ‡éœ€è¦é‡æ–°è®¡ç®—æ€»çš„æˆåŠŸçŽ‡ï¼Œè€Œä¸æ˜¯å¹³å‡å€¼
          const totalSuccess = data.reduce((sum, item) => {
            return sum + (Number(item.followUpSuccessAgain) || 0);
          }, 0);
          const totalNeed = data.reduce((sum, item) => {
            return sum + (Number(item.needFollowUpAgain) || 0);
          }, 0);
          const totalPending = data.reduce((sum, item) => {
            return sum + (Number(item.pendingFollowUpAgain) || 0);
          }, 0);
          const denominator = totalNeed - totalPending;
          if (denominator > 0) {
            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else if (column.property === "followUpRateAgain") {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-";
          }
        }
      });
      return sums;
    },
    formatNumber(num) {
      if (isNaN(num)) return "-";
      return Number.isInteger(num) ? num.toString() : num.toFixed(0);
    },
    handleSelectionChange(selection) {
      this.ids = selection.map((item) => item.tagid);
    },
    handleViewDetails(row, infoKey, titleSuffix, type) {
      const title = `${
        row.leavehospitaldistrictname || row.deptname
      }${titleSuffix}`;
      this.$emit("view-details", row, infoKey, title, type);
    },
    // è®¡ç®—成功率的方法
    calculateSuccessRate(followUpSuccess, needFollowUp, pendingFollowUp) {
      const success = Number(followUpSuccess) || 0;
      const need = Number(needFollowUp) || 0;
      const pending = Number(pendingFollowUp) || 0;
      // åˆ†æ¯ = éœ€éšè®¿ - å¾…随访
      const denominator = need - pending;
      if (denominator <= 0) {
        return "0.00%";
      }
      const rate = (success / denominator) * 100;
      return rate.toFixed(2) + "%";
    },
    async exportTable() {
      try {
        let dateRangeString = "";
        let sheetNameSuffix = "";
        // åˆ¤æ–­æ˜¯å¦æ˜¯ä¸½æ°´å¸‚中医院
        const isLishuiHospital = this.orgname == "丽水市中医院";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateStr = this.queryParams.dateRange[0];
          const endDateStr = this.queryParams.dateRange[1];
          if (isLishuiHospital) {
            // ä¸½æ°´å¸‚中医院:只显示年月
            const formatMonthOnly = (dateTimeStr) => {
              const date = new Date(dateTimeStr);
              const year = date.getFullYear();
              const month = date.getMonth() + 1;
              return `${year}å¹´${month}月`;
            };
            const startDateFormatted = formatMonthOnly(startDateStr);
            const endDateFormatted = formatMonthOnly(endDateStr);
            dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
            sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          } else {
            // å…¶ä»–医院:显示年月日
            const formatDateForDisplay = (dateTimeStr) => {
              return dateTimeStr.split(" ")[0];
            };
            const startDateFormatted = formatDateForDisplay(startDateStr);
            const endDateFormatted = formatDateForDisplay(endDateStr);
            dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
            sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          }
        } else {
          const now = new Date();
          const currentMonth = now.getMonth() + 1;
          const currentYear = now.getFullYear();
          if (isLishuiHospital) {
            // ä¸½æ°´å¸‚中医院:显示年月
            dateRangeString = `${currentYear}å¹´${currentMonth}月`;
            sheetNameSuffix = `${currentYear}å¹´${currentMonth}月`;
          } else {
            // å…¶ä»–医院:显示月份
            dateRangeString = `${currentMonth}月`;
            sheetNameSuffix = `${currentMonth}月`;
          }
        }
        // æ ¹æ® serviceType ç”Ÿæˆéšè®¿ç±»åž‹åç§°
        let serviceTypeName = "出院随访"; // æ–‡ä»¶åä½¿ç”¨çš„名称
        let sheetTypeName = "再次随访"; // å·¥ä½œè¡¨ä½¿ç”¨çš„名称(简化版)
        console.log(this.queryParams.serviceType);
        if (
          this.queryParams.serviceType &&
          Array.isArray(this.queryParams.serviceType) &&
          this.queryParams.serviceType.length > 0
        ) {
          if (this.tasktypes && Array.isArray(this.tasktypes)) {
            // è¿‡æ»¤å‡ºåŒ¹é…çš„随访类型
            const matchedTypes = this.tasktypes.filter((task) =>
              this.queryParams.serviceType.includes(task.value)
            );
            if (matchedTypes.length === 1) {
              // å•个类型
              const label = matchedTypes[0].label;
              serviceTypeName = label;
              sheetTypeName = label;
            } else if (matchedTypes.length > 1) {
              // å¤šä¸ªç±»åž‹
              const typeNames = matchedTypes.map((task) => task.label);
              // æ–‡ä»¶åï¼šç”¨æ–œæ åˆ†éš”
              serviceTypeName = typeNames.join("/");
              // å·¥ä½œè¡¨åï¼šä½¿ç”¨ç¬¬ä¸€ä¸ªç±»åž‹æˆ–简化名称
              if (matchedTypes.length <= 2) {
                // å¦‚果只有2个类型,都显示
                sheetTypeName = `${typeNames[0]}等`;
              } else {
                // å¦‚果超过2个类型,只显示第一个
                sheetTypeName = `${typeNames[0]}等`;
              }
            } else if (this.queryParams.serviceType.length > 0) {
              // å¦‚果没有匹配的,使用原始值
              const typeStr = this.queryParams.serviceType.join("/");
              serviceTypeName = typeStr;
              sheetTypeName = "再次随访";
            }
          } else if (this.queryParams.serviceType.length > 0) {
            // å¦‚果没有 tasktypes,使用原始值
            const typeStr = this.queryParams.serviceType.join("/");
            serviceTypeName = typeStr;
            sheetTypeName = "再次随访";
          }
        }
        const excelName = `再次${serviceTypeName}统计表_${dateRangeString}.xlsx`;
        // æ¸…理工作表名称,移除非法字符
        const cleanSheetName = (name) => {
          // Excel工作表名不能包含的字符: * ? : \ / [ ]
          return name.replace(/[*?:\\/[\]]/g, " ");
        };
        const worksheetName = cleanSheetName(
          `再次${sheetTypeName}统计_${sheetNameSuffix}`
        );
        if (!this.tableData || this.tableData.length === 0) {
          this.$message.warning(`暂无再次${serviceTypeName}数据可导出`);
          return false;
        }
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(worksheetName);
        // æž„建表格
        this.buildExportSheet(worksheet, sheetNameSuffix);
        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        saveAs(blob, excelName);
        this.$message.success("导出成功");
        return true;
      } catch (error) {
        console.error("导出失败:", error);
        this.$message.error(`导出失败: ${error.message}`);
        return false;
      }
    },
    /** å¯¼å‡ºåŒ»ç”Ÿå­è¡¨ï¼ˆå†æ¬¡éšè®¿ï¼‰ */
    async exportDoctorTable(row) {
      try {
        const areaName =
          row.leavehospitaldistrictname || row.deptname || "未知病区";
        let dateRangeString = "";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const start = this.queryParams.dateRange[0].split(" ")[0];
          const end = this.queryParams.dateRange[1].split(" ")[0];
          dateRangeString = `${start}至${end}`;
        } else {
          dateRangeString = `${new Date().getMonth() + 1}月`;
        }
        const fileName = `${areaName}医生再次随访列表_${dateRangeString}.xlsx`;
        const sheetName = `${areaName}医生再次随访`;
        if (!row.doctorStats || row.doctorStats.length === 0) {
          this.$message.warning("当前病区暂无医生再次随访数据");
          return;
        }
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(sheetName);
        this.buildDoctorExportSheet(worksheet, row.doctorStats, areaName);
        const buffer = await workbook.xlsx.writeBuffer();
        saveAs(
          new Blob([buffer], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          }),
          fileName
        );
        this.$message.success("医生再次随访列表导出成功");
      } catch (err) {
        console.error(err);
        this.$message.error("导出失败");
      }
    },
    buildDoctorExportSheet(worksheet, data, areaName) {
      const titleStyle = {
        font: { name: "微软雅黑", size: 16, bold: true },
        alignment: { horizontal: "center", vertical: "middle" },
      };
      const headerStyle = {
        font: { name: "微软雅黑", size: 11, bold: true },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { horizontal: "center", vertical: "middle", wrapText: true },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      const cellStyle = {
        font: { name: "宋体", size: 10 },
        alignment: { horizontal: "center", vertical: "middle" },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      // æ ‡é¢˜
      worksheet.mergeCells(1, 1, 1, 10);
      worksheet.getCell(1, 1).value = `${areaName}医生再次随访列表`;
      worksheet.getCell(1, 1).style = titleStyle;
      worksheet.getRow(1).height = 30;
      // è¡¨å¤´
      const headers = [
        "医生姓名",
        "科室",
        "出院人次",
        "无需随访",
        "应随访",
        "需随访",
        "待随访",
        "随访成功",
        "随访失败",
        "成功率", // æ–°å¢ž
        // "随访率", // åŽŸæ¥åœ¨æˆåŠŸçŽ‡ä½ç½®
      ];
      const headerRow = worksheet.addRow(headers);
      headerRow.eachCell((cell) => {
        cell.style = headerStyle;
      });
      worksheet.getRow(2).height = 25;
      // æ•°æ®
      data.forEach((item) => {
        const row = worksheet.addRow([
          item.drname,
          item.deptname,
          item.dischargeCount,
          item.nonFollowUp,
          item.followUpNeeded,
          item.needFollowUpAgain,
          item.pendingFollowUpAgain,
          item.followUpSuccessAgain,
          item.followUpFailAgain,
          this.calculateSuccessRate(
            item.followUpSuccessAgain,
            item.needFollowUpAgain,
            item.pendingFollowUpAgain
          ),
          item.followUpRateAgain,
        ]);
        row.eachCell((cell) => {
          cell.style = cellStyle;
        });
      });
      // å°è®¡è¡Œ
      const summaryRow = worksheet.addRow(
        this.getDoctorAgainExportSummary(data)
      );
      summaryRow.eachCell((cell) => {
        cell.font = { bold: true };
        cell.fill = {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        };
      });
      // åˆ—宽
      worksheet.columns = [
        { width: 15 },
        { width: 15 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 }, // æˆåŠŸçŽ‡
        // { width: 12 }, // éšè®¿çއ
      ];
    },
    /** å†æ¬¡éšè®¿ - åŒ»ç”Ÿå­è¡¨å¯¼å‡ºå°è®¡ */
    getDoctorAgainExportSummary(data) {
      const sums = ["小计"];
      const keys = [
        "dischargeCount",
        "nonFollowUp",
        "followUpNeeded",
        "needFollowUpAgain",
        "pendingFollowUpAgain",
        "followUpSuccessAgain",
        "followUpFailAgain",
      ];
      keys.forEach((key) => {
        sums.push(data.reduce((t, r) => t + (Number(r[key]) || 0), 0));
      });
      // æˆåŠŸçŽ‡ï¼ˆå¹³å‡å€¼ï¼‰
      const successRates = data
        .map((item) => {
          const success = Number(item.followUpSuccessAgain) || 0;
          const need = Number(item.needFollowUpAgain) || 0;
          const pending = Number(item.pendingFollowUpAgain) || 0;
          const denominator = need - pending;
          if (denominator <= 0) return 0;
          return success / denominator;
        })
        .filter((rate) => !isNaN(rate));
      sums.push(
        successRates.length
          ? (
              (successRates.reduce((a, b) => a + b, 0) / successRates.length) *
              100
            ).toFixed(2) + "%"
          : "0.00%"
      );
      // // éšè®¿çŽ‡ï¼ˆå¹³å‡å€¼ï¼‰
      // const followUpRates = data
      //   .map((i) => this.extractPercentageValue(i.followUpRateAgain))
      //   .filter(Boolean);
      // sums.push(
      //   followUpRates.length
      //     ? (
      //         (followUpRates.reduce((a, b) => a + b, 0) /
      //           followUpRates.length) *
      //         100
      //       ).toFixed(2) + "%"
      //     : "0.00%"
      // );
      return sums;
    },
    buildExportSheet(worksheet, sheetNameSuffix) {
      const titleStyle = {
        font: {
          name: "微软雅黑",
          size: 16,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFE6F3FF" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const headerStyle = {
        font: {
          name: "微软雅黑",
          size: 11,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const cellStyle = {
        font: { name: "宋体", size: 10, color: { argb: "FF000000" } },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      const summaryStyle = {
        font: {
          name: "宋体",
          size: 10,
          bold: true,
          color: { argb: "FF409EFF" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center" },
        border: {
          top: { style: "thin", color: { argb: "FFD0D0D0" } },
          left: { style: "thin", color: { argb: "FFD0D0D0" } },
          bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
          right: { style: "thin", color: { argb: "FFD0D0D0" } },
        },
      };
      // æ·»åŠ æ ‡é¢˜è¡Œ
      worksheet.mergeCells(1, 1, 1, 15);
      const titleCell = worksheet.getCell(1, 1);
      titleCell.value = `再次专病随访统计表_${sheetNameSuffix}`;
      titleCell.style = titleStyle;
      worksheet.getRow(1).height = 35;
      // è¡¨å¤´
      // è¡¨å¤´éœ€è¦å¢žåŠ æˆåŠŸçŽ‡åˆ—
      const secondRowHeaders = [
        "",
        "出院病区",
        "科室",
        "出院人次",
        "无需随访人次",
        "应随访人次",
        "需随访",
        "待随访",
        "随访成功",
        "随访失败",
        "成功率", // æˆåŠŸçŽ‡åº”è¯¥åœ¨éšè®¿å¤±è´¥åŽé¢
        // "随访率", // éšè®¿çŽ‡åœ¨æˆåŠŸçŽ‡åŽé¢
        "人工",
        "语音", // ä¿®æ­£ï¼šåº”该是语音,不是短信
        "短信", // çŸ­ä¿¡
        "微信", // å¾®ä¿¡
      ];
      secondRowHeaders.forEach((header, index) => {
        const cell = worksheet.getCell(3, index + 1);
        cell.value = header;
        cell.style = headerStyle;
      });
      // æ›´æ–°åˆå¹¶å•元格的范围
      for (let i = 1; i <= 6; i++) {
        worksheet.mergeCells(2, i, 3, i);
        const cell = worksheet.getCell(2, i);
        cell.style = headerStyle;
      }
      worksheet.getCell(2, 1).value = "";
      worksheet.getCell(2, 2).value = "出院病区";
      worksheet.getCell(2, 3).value = "科室";
      worksheet.getCell(2, 4).value = "出院人次";
      worksheet.getCell(2, 5).value = "无需随访人次";
      worksheet.getCell(2, 6).value = "应随访人次";
      // æ³¨æ„ï¼šç”±äºŽå¢žåŠ äº†æˆåŠŸçŽ‡åˆ—ï¼Œåˆå¹¶åˆ—æ•°è¦å¢žåŠ 
      worksheet.mergeCells(2, 7, 2, 16); // ä»Ž7合并到16(原来是7-14)
      worksheet.getCell(2, 7).value = "再次专病随访";
      worksheet.getCell(2, 7).style = headerStyle;
      worksheet.getRow(2).height = 28;
      worksheet.getRow(3).height = 25;
      // æ•°æ®è¡Œ
      this.tableData.forEach((item, rowIndex) => {
        const dataRow = worksheet.addRow(
          [
            "",
            item.leavehospitaldistrictname || "",
            item.deptname || "",
            item.dischargeCount || 0,
            item.nonFollowUp || 0,
            item.followUpNeeded || 0,
            item.needFollowUpAgain || 0,
            item.pendingFollowUpAgain || 0,
            item.followUpSuccessAgain || 0,
            item.followUpFailAgain || 0,
            // æˆåŠŸçŽ‡ - éœ€è¦åŠ¨æ€è®¡ç®—
            this.calculateSuccessRate(
              item.followUpSuccessAgain,
              item.needFollowUpAgain,
              item.pendingFollowUpAgain
            ),
            // item.followUpRateAgain || "0%", // éšè®¿çއ
            item.manualAgain || 0,
            item.voiceAgain || 0,
            item.smsAgain || 0,
            item.weChatAgain || 0,
          ],
          rowIndex + 4
        );
        dataRow.eachCell((cell) => {
          cell.style = cellStyle;
        });
        dataRow.height = 24;
      });
      // åˆè®¡è¡Œ
      const summaries = this.getExportSummaries();
      const summaryRow = worksheet.addRow(summaries);
      summaryRow.eachCell((cell, colNumber) => {
        cell.style = summaryStyle;
        if (colNumber === 1) {
          cell.value = "合计";
        }
      });
      summaryRow.height = 28;
      // åˆ—宽
      // ä¿®æ­£åˆ—宽
      worksheet.columns = [
        { width: 8 },
        { width: 20 },
        { width: 15 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 12 }, // æˆåŠŸçŽ‡
        // { width: 12 }, // éšè®¿çއ
        { width: 8 }, // äººå·¥
        { width: 8 }, // è¯­éŸ³
        { width: 8 }, // çŸ­ä¿¡
        { width: 8 }, // å¾®ä¿¡
      ];
    },
    getExportSummaries() {
      const summaries = [
        "合计",
        "/",
        "/",
        0, // 3: dischargeCount
        0, // 4: nonFollowUp
        0, // 5: followUpNeeded
        0, // 6: needFollowUpAgain
        0, // 7: pendingFollowUpAgain
        0, // 8: followUpSuccessAgain
        0, // 9: followUpFailAgain
        "0%", // 10: æˆåŠŸçŽ‡
        // "0%", // 11: éšè®¿çއ
        0, // 12: manualAgain
        0, // 13: voiceAgain
        0, // 14: smsAgain
        0, // 15: weChatAgain
      ];
      this.tableData.forEach((item) => {
        summaries[3] += Number(item.dischargeCount) || 0;
        summaries[4] += Number(item.nonFollowUp) || 0;
        summaries[5] += Number(item.followUpNeeded) || 0;
        summaries[6] += Number(item.needFollowUpAgain) || 0;
        summaries[7] += Number(item.pendingFollowUpAgain) || 0;
        summaries[8] += Number(item.followUpSuccessAgain) || 0;
        summaries[9] += Number(item.followUpFailAgain) || 0;
        summaries[12] += Number(item.manualAgain) || 0;
        summaries[13] += Number(item.voiceAgain) || 0;
        summaries[14] += Number(item.smsAgain) || 0;
        summaries[15] += Number(item.weChatAgain) || 0;
      });
      // æˆåŠŸçŽ‡è®¡ç®—
      const totalSuccess = summaries[8]; // followUpSuccessAgain的总和
      const totalNeed = summaries[6]; // needFollowUpAgain的总和
      const totalPending = summaries[7]; // pendingFollowUpAgain的总和
      const denominator = totalNeed - totalPending;
      if (denominator > 0) {
        summaries[10] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
      } else {
        summaries[10] = "0.00%";
      }
      // éšè®¿çŽ‡è®¡ç®—
      // const followUpRateAgainValues = this.tableData
      //   .map((item) => this.extractPercentageValue(item.followUpRateAgain))
      //   .filter((value) => value !== null);
      // if (followUpRateAgainValues.length > 0) {
      //   const avgFollowUpRateAgain =
      //     followUpRateAgainValues.reduce((sum, val) => sum + val, 0) /
      //     followUpRateAgainValues.length;
      //   summaries[11] = (avgFollowUpRateAgain * 100).toFixed(2) + "%";
      // }
      // æ ¼å¼åŒ–æ•°å­—
      [3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15].forEach((index) => {
        summaries[index] = this.formatNumber(summaries[index]);
      });
      return summaries;
    },
    extractPercentageValue(value) {
      if (!value) return null;
      if (typeof value === "string" && value.includes("%")) {
        const num = parseFloat(value.replace("%", ""));
        return isNaN(num) ? null : num / 100;
      }
      const num = parseFloat(value);
      return isNaN(num) ? null : num;
    },
  },
};
</script>
<style lang="scss" scoped>
.second-follow-up {
  .your-table-container {
    margin-top: 10px;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/TimelyRateDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,249 @@
<template>
  <el-dialog
    title="未及时随访患者服务"
    :visible.sync="visible"
    v-loading="loading"
    width="70%"
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <div class="timely-rate-dialog">
      <div class="examine-jic">
        <div class="jic-value">
          <el-row :gutter="20">
            <!-- æœç´¢è¡¨å• -->
            <el-form
              :model="queryParams"
              ref="queryForm"
              size="small"
              :inline="true"
              label-width="98px"
              class="search-form"
            >
              <el-form-item label="患者:">
                <el-input
                  v-model="queryParams.name"
                  placeholder="请输入患者姓名"
                  @keyup.enter.native="handleSearch"
                />
              </el-form-item>
              <el-form-item label="患者诊断:">
                <el-input
                  v-model="queryParams.leavediagname"
                  placeholder="请输入患者诊断"
                  @keyup.enter.native="handleSearch"
                />
              </el-form-item>
              <el-form-item>
                <el-button
                  type="primary"
                  icon="el-icon-search"
                  size="medium"
                  @click="handleSearch"
                >
                  æœç´¢
                </el-button>
                <el-button
                  icon="el-icon-refresh"
                  size="medium"
                  @click="resetQuery"
                >
                  é‡ç½®
                </el-button>
              </el-form-item>
            </el-form>
            <!-- æ‚£è€…列表 -->
            <el-table :data="data" style="width: 100%" v-loading="loading">
              <el-table-column prop="sendname" align="center" label="姓名" width="100" />
              <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="任务名称" />
              <el-table-column prop="sendstate" align="center" width="200" label="任务状态">
                <template slot-scope="scope">
                  <el-tag
                    :type="getStateTagType(scope.row.sendstate)"
                    :disable-transitions="false"
                  >
                    {{ getStateText(scope.row.sendstate) }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column prop="visitTime" align="center" label="应随访时间" width="200" show-overflow-tooltip />
              <el-table-column prop="finishtime" align="center" label="随访完成时间" width="200" show-overflow-tooltip />
              <el-table-column label="出院日期" width="200" align="center" key="endtime" prop="endtime">
                <template slot-scope="scope">
                  <span>{{ formatTime(scope.row.endtime) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="责任护士" width="120" align="center" key="nurseName" prop="nurseName" />
              <el-table-column label="主治医生" width="120" align="center" key="drname" prop="drname" />
              <el-table-column label="结果状态" align="center" key="excep" prop="excep" width="120">
                <template slot-scope="scope">
                  <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
                </template>
              </el-table-column>
              <el-table-column label="处理意见" align="center" key="suggest" prop="suggest" width="120">
                <template slot-scope="scope">
                  <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
                </template>
              </el-table-column>
              <el-table-column prop="templatename" align="center" label="服务模板" width="200" show-overflow-tooltip />
              <el-table-column prop="remark" align="center" label="服务记录" width="200" show-overflow-tooltip />
              <el-table-column prop="bankcardno" align="center" label="呼叫状态" width="210" />
              <el-table-column label="操作" fixed="right" align="center" width="200" class-name="small-padding fixed-width">
                <template slot-scope="scope">
                  <el-button size="medium" type="text" @click="handleDetailsGo(scope.row)">
                    <span class="button-zx">
                      <i class="el-icon-s-order"></i>查看
                    </span>
                  </el-button>
                </template>
              </el-table-column>
            </el-table>
          </el-row>
          <!-- åˆ†é¡µ -->
          <pagination
            v-show="total > 0"
            :total="total"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="handlePagination"
          />
        </div>
      </div>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: 'TimelyRateDialog',
  dicts: ['sys_yujing', 'sys_suggest'],
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    loading: {
      type: Boolean,
      default: false
    },
    data: {
      type: Array,
      default: () => []
    },
    total: {
      type: Number,
      default: 0
    },
    queryParams: {
      type: Object,
      default: () => ({
        pageNum: 1,
        pageSize: 10
      })
    }
  },
  data() {
    return {
      localQueryParams: { ...this.queryParams }
    }
  },
  watch: {
    queryParams: {
      deep: true,
      handler(newParams) {
        this.localQueryParams = { ...newParams }
      }
    }
  },
  mounted() {
    this.localQueryParams = { ...this.queryParams }
  },
  methods: {
    handleSearch() {
      this.$emit('search', this.localQueryParams)
    },
    resetQuery() {
      this.localQueryParams = {
        pageNum: 1,
        pageSize: 10,
        name: '',
        leavediagname: ''
      }
      this.$emit('search', this.localQueryParams)
    },
    handlePagination(pagination) {
      this.localQueryParams.pageNum = pagination.page
      this.localQueryParams.pageSize = pagination.limit
      console.log(pagination,'pagination');
      console.log(this.localQueryParams,'this.localQueryParams');
      this.$emit('search', this.localQueryParams)
    },
    getStateTagType(state) {
      const stateMap = {
        1: 'primary',
        2: 'primary',
        3: 'success',
        4: 'info',
        5: 'danger',
        6: 'success'
      }
      return stateMap[state] || 'info'
    },
    getStateText(state) {
      const stateTextMap = {
        1: '表单已领取',
        2: '待随访',
        3: '表单已发送',
        4: '不执行',
        5: '发送失败',
        6: '已完成'
      }
      return stateTextMap[state] || '未知状态'
    },
    formatTime(time) {
      if (!time) return ''
      return this.parseTime(time)
    },
    handleDetailsGo(row) {
      this.$emit('details-go', row)
    },
    handleClose() {
      this.$emit('close')
    }
  }
}
</script>
<style lang="scss" scoped>
.timely-rate-dialog {
  .search-form {
    margin-bottom: 20px;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
}
</style>
src/views/Satisfaction/diseaseStatistics/components/styles.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
// å…¨å±€æ ·å¼
.follow-up-statistics,
.first-follow-up,
.second-follow-up,
.continued-care {
  .your-table-container {
    margin-top: 10px;
  }
  .button-zx {
    color: rgb(70, 204, 238);
  }
  // ç¾ŽåŒ–合计行样式
  ::v-deep .el-table__footer {
    .el-table__cell {
      background-color: #f5f7fa;
      font-weight: 600;
      color: #409eff;
      .cell {
        font-weight: 600;
        color: #409eff;
      }
    }
  }
  // å†…部表格合计行样式
  ::v-deep .inner-table .el-table__footer {
    .el-table__cell {
      background-color: #ecf5ff;
      font-weight: 500;
      color: #67c23a;
      .cell {
        font-weight: 500;
        color: #67c23a;
      }
    }
  }
  // ç™¾åˆ†æ¯”字段特殊样式
  ::v-deep .el-table__footer .el-table__cell[data-field="followUpRate"] .cell,
  ::v-deep .el-table__footer .el-table__cell[data-field="rate"] .cell,
  ::v-deep .el-table__footer .el-table__cell[data-field="followUpRateAgain"] .cell,
  ::v-deep .el-table__footer .el-table__cell[data-field="completionRate"] .cell {
    color: #e6a23c !important;
    font-weight: 700 !important;
  }
  // å†…层医生表格样式
  .inner-table {
    ::v-deep .el-table__header-wrapper {
      background-color: #f0f7ff !important;
      th {
        background-color: #f0f7ff !important;
      }
    }
    ::v-deep .el-table__body-wrapper {
      tr {
        background-color: #f9fbfe !important;
        &:hover {
          background-color: #e6f1ff !important;
        }
      }
    }
    ::v-deep .el-table--border {
      border-color: #d9e8ff !important;
      td, th {
        border-color: #d9e8ff !important;
      }
    }
  }
  /* ä½¿è¡Œæœ‰æ‰‹åž‹æŒ‡é’ˆ */
  ::v-deep .el-table__row {
    cursor: pointer;
  }
  /* å±•开行样式 */
  ::v-deep .el-table__expanded-cell {
    padding: 10px 0 !important;
    background: #f8f8f8;
  }
}
src/views/Satisfaction/diseaseStatistics/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,569 @@
<template>
  <div class="follow-up-statistics">
    <!-- æœç´¢è¡¨å•区域 -->
    <div class="search-section">
      <el-form
        :model="queryParams"
        ref="queryForm"
        size="small"
        :inline="true"
        v-show="showSearch"
        label-width="98px"
      >
        <el-form-item label="统计类型" prop="userName">
          <el-select
            v-model="queryParams.statisticaltype"
            placeholder="请选择统计类型"
          >
            <el-option
              v-for="item in Statisticallist"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-select
            style="margin-left: 10px"
            v-if="queryParams.statisticaltype == 1"
            v-model="queryParams.leavehospitaldistrictcodes"
            size="medium"
            multiple
            filterable
            placeholder="请选择病区"
          >
            <el-option
              v-for="item in flatArrayhospit"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-select
            v-else-if="queryParams.statisticaltype == 2"
            v-model="queryParams.deptcodes"
            size="medium"
            multiple
            filterable
            placeholder="请选择科室"
          >
            <el-option
              v-for="item in flatArraydept"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-select
            v-model="queryParams.diagTypes"
            v-else-if="queryParams.statisticaltype == 3"
            filterable
            remote
            allow-create
            default-first-option
            placeholder="请选择/查询"
            multiple
            :remote-method="remoteSearch"
            :loading="loading"
            @visible-change="handleVisibleChange"
            @focus="handleFocus"
          >
            <el-option
              v-for="item in donorchargeList"
              :key="item.icdid"
              :label="item.icdname"
              :value="item.icdid"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="专病任务" prop="userName">
          <el-select
            v-model="queryParams.taskNames"
            multiple
            placeholder="请选择"
          >
            <el-option
              v-for="item in taskList"
              :key="item.taskName"
              :label="item.taskName"
              :value="item.taskName"
            />
          </el-select>
        </el-form-item>
        <el-form-item label-width="200" label="应随访时间范围" prop="userName">
          <el-date-picker
            v-model="queryParams.dateRange"
            value-format="yyyy-MM-dd HH:mm:ss"
            type="daterange"
            unlink-panels
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :default-time="['00:00:00', '23:59:59']"
            :picker-options="pickerOptions"
          />
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            icon="el-icon-search"
            size="medium"
            @click="handleQuery"
            >搜索</el-button
          >
          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
            >重置</el-button
          >
        </el-form-item>
        <el-button
          type="warning"
          plain
          icon="el-icon-download"
          size="medium"
          @click="handleExport"
          >导出</el-button
        >
        <!-- <el-button
          type="primary"
          plain
          icon="el-icon-data-line"
          size="medium"
          @click="showChartDialog"
          >统计趋势图</el-button
        > -->
      </el-form>
    </div>
    <!-- Tab切换区域 -->
    <div class="tab-section">
      <el-tabs v-model="activeTab" @tab-click="handleTabClick">
        <el-tab-pane label="首次随访" name="first">
          <FirstFollowUp
            ref="firstFollowUp"
            :query-params="queryParams"
            :flat-array-hospit="flatArrayhospit"
            :flat-array-dept="flatArraydept"
            :options="options"
            :orgname="orgname"
            @view-details="viewDetails"
            @see-details="Seedetails"
          />
        </el-tab-pane>
        <el-tab-pane label="再次随访" name="second">
          <SecondFollowUp
            ref="secondFollowUp"
            :query-params="queryParams"
            :flat-array-hospit="flatArrayhospit"
            :flat-array-dept="flatArraydept"
            :options="options"
            :orgname="orgname"
            @view-details="viewDetails"
          />
        </el-tab-pane>
      </el-tabs>
    </div>
  </div>
</template>
<script>
import FirstFollowUp from "./components/FirstFollowUp.vue";
import SecondFollowUp from "./components/SecondFollowUp.vue";
import ContinuedCare from "./components/ContinuedCare.vue";
import ChartDialog from "./components/ChartDialog.vue";
import DetailDialog from "./components/DetailDialog.vue";
import TimelyRateDialog from "./components/TimelyRateDialog.vue";
import {
  getSfStatisticsHyperlink,
  getTasklist,
  getillnesslist,
} from "@/api/AiCentre/index";
export default {
  name: "FollowUpStatistics",
  components: {
    FirstFollowUp,
    SecondFollowUp,
    ContinuedCare,
    ChartDialog,
    DetailDialog,
    TimelyRateDialog,
  },
  data() {
    return {
      activeTab: "first",
      orgname: localStorage.getItem("orgname") || "",
      Statisticallist: [
        { label: "病区统计", value: 1 },
        { label: "科室统计", value: 2 },
        { label: "病种统计", value: 3 },
      ],
      options: this.$store.getters.tasktypes,
      queryParams: {
        serviceType: [13],
        statisticaltype: 3,
        dateRange: this.getLastMonthRange(),
        leavehospitaldistrictcodes: ["all"],
        deptcodes: [],
        diagTypes: [],
      },
      pickerOptions: {
        shortcuts: [
          {
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit("pick", [start, end]);
            },
          },
        ],
      },
      flatArrayhospit: [],
      flatArraydept: [],
      allDeptCodes: [],
      allWardCodes: [],
      donorchargeList: [], //病种集合
      taskList: [],
      showSearch: true,
      loading: false,
      searchTimeout: null,
      hasSearched: false, // æ ‡è®°æ˜¯å¦å·²è¿›è¡Œè¿‡æœç´¢
      // å¼¹çª—相关状态
      chartDialogVisible: false,
      chartData: [],
      infotitleVisible: false,
      SeedetailsVisible: false,
      searchName: "",
      infotitle: "",
      infotitlelist: [],
      patienttotal: 0,
      logsheetlist: [],
      Seedloading: false,
      patientqueryParams: {
        pageNum: 1,
        pageSize: 10,
      },
    };
  },
  created() {
    this.getDeptTree();
    this.loadCurrentTabData();
  },
  methods: {
    // å„类型列表
    getDeptTree() {
      // ç§‘室列表
      this.flatArraydept = this.$store.getters.belongDepts.map((dept) => {
        return {
          label: dept.deptName,
          value: dept.deptCode,
        };
      });
      this.allDeptCodes = this.$store.getters.belongDepts.map(
        (dept) => dept.deptCode
      );
      // ç—…区列表
      this.flatArrayhospit = this.$store.getters.belongWards.map((ward) => {
        return {
          label: ward.districtName,
          value: ward.districtCode,
        };
      });
      this.allWardCodes = this.$store.getters.belongWards.map(
        (ward) => ward.districtCode
      );
      // ç–¾ç—…
      getillnesslist({ pageNum: 1, pageSize: 100 }).then((res) => {
        this.donorchargeList = res.rows;
      });
      // ä¸“病任务
      getTasklist({ pageNum: 1, pageSize: 50, serviceType: 13, type: 2 }).then(
        (response) => {
          this.taskList = response.rows;
        }
      );
      this.flatArraydept.push({ label: "全部", value: "all" });
      this.flatArrayhospit.push({ label: "全部", value: "all" });
    },
    // è¿œç¨‹æœç´¢æ–¹æ³•
    remoteSearch(query) {
      if (this.searchTimeout) {
        clearTimeout(this.searchTimeout);
      }
      this.loading = true;
      // é˜²æŠ–处理,300ms后执行搜索
      this.searchTimeout = setTimeout(() => {
        this.performSearch(query);
      }, 300);
    },
    // æ‰§è¡Œæœç´¢
    performSearch(query) {
      if (!query) {
        // å¦‚果搜索内容为空,显示所有数据
        this.loadInitialData();
        this.loading = false;
        this.hasSearched = true;
        return;
      }
      const params = {
        pageNum: 1,
        pageSize: 100,
        icdname: query, // å‡è®¾å¯ä»¥æ ¹æ®icdname搜索
      };
      getillnesslist(params)
        .then((res) => {
          this.donorchargeList = res.rows || [];
          this.loading = false;
          this.hasSearched = true;
        })
        .catch(() => {
          this.loading = false;
          this.hasSearched = true;
        });
    },
    // ä¸‹æ‹‰æ¡†æ˜¾ç¤º/隐藏时的处理
    handleVisibleChange(visible) {
      if (visible && !this.hasSearched) {
        // é¦–次展开时加载数据
        this.loadInitialData();
      }
    },
    // èŽ·å–ç„¦ç‚¹æ—¶çš„å¤„ç†
    handleFocus() {
      if (this.donorchargeList.length === 0 && !this.hasSearched) {
        this.loadInitialData();
      }
    },
    // æ·»åŠ èŽ·å–æœ€è¿‘ä¸€ä¸ªæœˆæ—¶é—´èŒƒå›´çš„æ–¹æ³•
    getLastMonthRange() {
      const end = new Date();
      const start = new Date();
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
      // æ ¼å¼åŒ–为 yyyy-MM-dd HH:mm:ss
      const formatDate = (date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, "0");
        const day = String(date.getDate()).padStart(2, "0");
        return `${year}-${month}-${day} 00:00:00`;
      };
      const formatEndDate = (date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, "0");
        const day = String(date.getDate()).padStart(2, "0");
        return `${year}-${month}-${day} 23:59:59`;
      };
      return [formatDate(start), formatEndDate(end)];
    },
    handleTabClick(tab) {
      this.activeTab = tab.name;
      this.loadCurrentTabData();
    },
    loadCurrentTabData() {
      switch (this.activeTab) {
        case "first":
          this.$refs.firstFollowUp.loadData();
          break;
        case "second":
          this.$refs.secondFollowUp.loadData();
          break;
        case "continued":
          this.$refs.continuedCare.loadData();
          break;
      }
    },
    handleQuery() {
      this.queryParams.startTime = this.parseTime(
        this.queryParams.dateRange[0]
      );
      this.queryParams.endTime = this.parseTime(this.queryParams.dateRange[1]);
      if (this.queryParams.statisticaltype == 1) {
        this.queryParams.deptcodes = [];
      } else if (this.queryParams.statisticaltype == 2) {
        this.queryParams.leavehospitaldistrictcodes = [];
      }
      this.loadCurrentTabData();
    },
    resetQuery() {
      this.queryParams.dateRange = [];
      this.queryParams.leavehospitaldistrictcodes = [];
      this.handleQuery();
    },
    async handleExport() {
      switch (this.activeTab) {
        case "first":
          await this.$refs.firstFollowUp.exportTable();
          break;
        case "second":
          await this.$refs.secondFollowUp.exportTable();
          break;
        case "continued":
          await this.$refs.continuedCare.exportTable();
          break;
      }
    },
    showChartDialog() {
      this.chartData = this.getCurrentTabData();
      this.chartDialogVisible = true;
    },
    getCurrentTabData() {
      switch (this.activeTab) {
        case "first":
          return this.$refs.firstFollowUp.tableData;
        case "second":
          return this.$refs.secondFollowUp.tableData;
        case "continued":
          return this.$refs.continuedCare.tableData;
        default:
          return [];
      }
    },
    viewDetails(row, infoKey, title, type) {
      this.infotitle = title;
      let obj = {
        hyperLinkInfoType: infoKey,
        leavehospitaldistrictcodes: this.queryParams.leavehospitaldistrictcodes,
        serviceType: this.queryParams.serviceType,
      };
      if (type == 1) {
        obj.drcode = row.drcode;
      }
      if (this.queryParams.statisticaltype == 1) {
        obj.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
        obj.deptcodes = [];
      } else {
        obj.deptcodes = [row.deptcode];
        obj.leavehospitaldistrictcodes = [];
      }
      obj.endTime = this.queryParams.endTime;
      obj.startTime = this.queryParams.startTime;
      obj.statisticaltype = this.queryParams.statisticaltype;
      getSfStatisticsHyperlink(obj).then((response) => {
        this.infotitlelist = response.data;
      });
      this.infotitleVisible = true;
    },
    Seedetails(row) {
      this.SeedetailsVisible = true;
      this.Seedloading = true;
      this.$refs.firstFollowUp
        .selectTimelyRate(row, this.queryParams)
        .then((response) => {
          this.logsheetlist = response.data.detail;
          this.patienttotal = response.data.total;
          this.Seedloading = false;
        });
    },
    Seedetailstion() {
      console.log(this.patientqueryParams);
      this.$refs.firstFollowUp
        .selectTimelyRates(this.patientqueryParams)
        .then((response) => {
          this.logsheetlist = response.data.detail;
          this.patienttotal = response.data.total;
        });
    },
    SeedetailsgGo(row) {
      this.SeedetailsVisible = false;
      let type = "";
      if (row.preachformson && row.preachformson.includes("3")) {
        type = 1;
      }
      setTimeout(() => {
        this.$router.push({
          path: "/followvisit/record/detailpage/",
          query: {
            taskid: row.taskid,
            patid: row.patid,
            id: row.id,
            Voicetype: type,
          },
        });
      }, 300);
    },
    handleSearch() {
      // æœç´¢é€»è¾‘
    },
  },
};
</script>
<style lang="scss" scoped>
.follow-up-statistics {
  padding: 20px;
  background: #ffff;
  border: 1px solid #dcdfe6;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
  .search-section {
    margin-bottom: 20px;
  }
  .tab-section {
    ::v-deep .el-tabs__header {
      margin-bottom: 20px;
    }
    ::v-deep .el-tabs__item {
      font-size: 16px;
      padding: 0 20px;
      height: 40px;
      line-height: 40px;
    }
    ::v-deep .el-tabs__active-bar {
      height: 3px;
    }
  }
}
</style>
src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -323,6 +323,7 @@
        :row-data="currentRow"
        :topicList="topiclist"
        :query-params="queryParams"
        :topType="2"
        @close="topicVisible = false"
      />
    </el-dialog>
src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue
@@ -89,6 +89,7 @@
<script>
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
export default {
  name: "TopicDialog",
  props: {
@@ -100,6 +101,9 @@
      type: Object,
      default: () => ({}),
    },
    topType: {
      type: String,
    },
    topicList: {
      type: [Array, Object],
      default: () => ({}),
@@ -107,211 +111,260 @@
  },
  data() {
    return {
      processedTopicList: [], // å¤„理后的数据
      processedTopicList: [],
      orgname: "", // æ–°å¢žï¼šåŒ»é™¢åç§°
    };
  },
  computed: {
    configTitle() {
      // ä»Žçˆ¶çº§ queryParams ä¸­è¯»å–
      const key = this.queryParams?.configKey;
      return key === "returnVisitCount" ? "复诊通知" : "满意度";
    },
  },
  created() {
    // èŽ·å–åŒ»é™¢åç§°
    this.orgname = localStorage.getItem("orgname") || "";
  },
  watch: {
    // ç›‘听父组件传递的数据变化
    topicList: {
      immediate: true,
      handler(newVal) {
        console.log("TopicDialog接收到父组件数据:", newVal);
        this.processTopicList(newVal);
      },
    },
  },
  mounted() {
    console.log("TopicDialog mounted, props:", this.$props);
  },
  methods: {
    // å¤„理topicList数据
    processTopicList(data) {
      console.log("开始处理数据:", data);
      if (!data || typeof data !== "object") {
        this.processedTopicList = [];
        return;
      }
      // å°†å¯¹è±¡è½¬æ¢ä¸ºæ•°ç»„
      const result = [];
      Object.keys(data).forEach((key) => {
        const item = data[key];
        if (item && item.scriptContent) {
          // æ·±æ‹·è´item,避免修改原数据
          const processedItem = JSON.parse(JSON.stringify(item));
          // è¿‡æ»¤details,只保留有选项文本的
          if (processedItem.details && Array.isArray(processedItem.details)) {
            processedItem.details = processedItem.details.filter(
              (detail) => detail && detail.optionText
            );
          }
          result.push(processedItem);
        }
      });
      console.log("处理后的数据:", result);
      this.processedTopicList = result;
    },
    /** å¯¼å‡ºé¢˜ç›®æ˜Žç»† */
    // æ ¼å¼åŒ–日期范围字符串(与主页面一致)
    formatDateRangeForExport() {
      let dateRangeString = "";
      let sheetNameSuffix = "";
      const isLishuiHospital = this.orgname == "丽水市中医院";
      if (
        this.queryParams.dateRange &&
        this.queryParams.dateRange.length === 2
      ) {
        const startDateStr = this.queryParams.dateRange[0];
        const endDateStr = this.queryParams.dateRange[1];
        if (isLishuiHospital) {
          // ä¸½æ°´å¸‚中医院:只显示年月
          const formatMonthOnly = (dateStr) => {
            const date = new Date(dateStr);
            const year = date.getFullYear();
            const month = date.getMonth() + 1;
            return `${year}å¹´${month}月`;
          };
          const startDateFormatted = formatMonthOnly(startDateStr);
          const endDateFormatted = formatMonthOnly(endDateStr);
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
        } else {
          // å…¶ä»–医院:显示年月日
          const formatDateForDisplay = (dateStr) => {
            return dateStr.split(" ")[0]; // å¦‚果包含时间部分,只取日期
          };
          const startDateFormatted = formatDateForDisplay(startDateStr);
          const endDateFormatted = formatDateForDisplay(endDateStr);
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
        }
      } else {
        const now = new Date();
        const currentMonth = now.getMonth() + 1;
        const currentYear = now.getFullYear();
        if (isLishuiHospital) {
          // ä¸½æ°´å¸‚中医院:显示年月
          dateRangeString = `${currentYear}å¹´${currentMonth}月`;
          sheetNameSuffix = `${currentYear}å¹´${currentMonth}月`;
        } else {
          // å…¶ä»–医院:显示月份
          dateRangeString = `${currentMonth}月`;
          sheetNameSuffix = `${currentMonth}月`;
        }
      }
      return { dateRangeString, sheetNameSuffix };
    },
    // å¯¼å‡ºé¢˜ç›®æ˜Žç»†
    async exportTopicDetail() {
      if (!this.processedTopicList.length) {
        this.$message.warning("暂无数据可导出");
        return;
      }
      const workbook = new ExcelJS.Workbook();
      const sheetName = `${
        this.rowData.leavehospitaldistrictname || this.rowData.deptname
      }${this.configTitle}明细`;
      const worksheet = workbook.addWorksheet(sheetName);
      try {
        // èŽ·å–æ ¼å¼åŒ–åŽçš„æ—¥æœŸèŒƒå›´
        const { dateRangeString, sheetNameSuffix } =
          this.formatDateRangeForExport();
      /* ---------- æ ·å¼ ---------- */
      const titleStyle = {
        font: { name: "微软雅黑", size: 14, bold: true },
        alignment: { horizontal: "center", vertical: "middle" },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
      };
        const workbook = new ExcelJS.Workbook();
        const sheetName = `${
          this.rowData.leavehospitaldistrictname || this.rowData.deptname
        }${this.configTitle}明细_${sheetNameSuffix}`;
        const worksheet = workbook.addWorksheet(sheetName);
      const subtitleStyle = {
        font: { name: "微软雅黑", size: 12, bold: true },
        alignment: { horizontal: "left", vertical: "middle" },
      };
        // æ ·å¼å®šä¹‰ï¼ˆä¿æŒä¸å˜ï¼‰
        const titleStyle = {
          font: { name: "微软雅黑", size: 14, bold: true },
          alignment: { horizontal: "center", vertical: "middle" },
          fill: {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FFF5F7FA" },
          },
        };
      const headerStyle = {
        font: { name: "微软雅黑", size: 11, bold: true },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFEBEEF5" },
        },
        alignment: { horizontal: "center", vertical: "middle" },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
        const subtitleStyle = {
          font: { name: "微软雅黑", size: 12, bold: true },
          alignment: { horizontal: "left", vertical: "middle" },
        };
      const cellStyle = {
        font: { name: "宋体", size: 10 },
        alignment: { horizontal: "center", vertical: "middle" },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
        const headerStyle = {
          font: { name: "微软雅黑", size: 11, bold: true },
          fill: {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FFEBEEF5" },
          },
          alignment: { horizontal: "center", vertical: "middle" },
          border: {
            top: { style: "thin" },
            left: { style: "thin" },
            bottom: { style: "thin" },
            right: { style: "thin" },
          },
        };
      /* ---------- æ ‡é¢˜åŒº ---------- */
      worksheet.mergeCells(1, 1, 1, 4);
      worksheet.getCell(1, 1).value = `${this.configTitle}题目明细`;
      worksheet.getCell(1, 1).style = titleStyle;
        const cellStyle = {
          font: { name: "宋体", size: 10 },
          alignment: { horizontal: "center", vertical: "middle" },
          border: {
            top: { style: "thin" },
            left: { style: "thin" },
            bottom: { style: "thin" },
            right: { style: "thin" },
          },
        };
      worksheet.mergeCells(2, 1, 2, 4);
      worksheet.getCell(2, 1).value = `统计对象:${
        this.rowData.leavehospitaldistrictname || this.rowData.deptname
      }`;
      worksheet.getCell(2, 1).style = subtitleStyle;
        // æ ‡é¢˜åŒº
        worksheet.mergeCells(1, 1, 1, 4);
        worksheet.getCell(
          1,
          1
        ).value = `${this.configTitle}题目明细(${dateRangeString})`;
        worksheet.getCell(1, 1).style = titleStyle;
      worksheet.mergeCells(3, 1, 3, 4);
      worksheet.getCell(3, 1).value = `统计时间:${
        this.queryParams.dateRange?.[0] || "-"
      } è‡³ ${this.queryParams.dateRange?.[1] || "-"}`;
      worksheet.getCell(3, 1).style = subtitleStyle;
        worksheet.mergeCells(2, 1, 2, 4);
        worksheet.getCell(2, 1).value = `统计对象:${
          this.rowData.leavehospitaldistrictname || this.rowData.deptname
        }`;
        worksheet.getCell(2, 1).style = subtitleStyle;
      let currentRow = 5;
        let currentRow = 4;
      /* ---------- é€é¢˜å†™å…¥ ---------- */
      this.processedTopicList.forEach((item, index) => {
        worksheet.mergeCells(currentRow, 1, currentRow, 4);
        worksheet.getCell(currentRow, 1).value = `第${index + 1}题:${
          item.scriptContent
        } [${item.scriptType == 1 ? "单选题" : "多选题"}]`;
        worksheet.getCell(currentRow, 1).style = subtitleStyle;
        currentRow++;
        // é€é¢˜å†™å…¥
        this.processedTopicList.forEach((item, index) => {
          worksheet.mergeCells(currentRow, 1, currentRow, 4);
          worksheet.getCell(currentRow, 1).value = `第${index + 1}题:${
            item.scriptContent
          } [${item.scriptType == 1 ? "单选题" : "多选题"}]`;
          worksheet.getCell(currentRow, 1).style = subtitleStyle;
          currentRow++;
        const headerRow = worksheet.addRow([
          "问题选项",
          "选择人数",
          "占比",
          "",
        ]);
        headerRow.eachCell((cell) => {
          cell.style = headerStyle;
        });
        currentRow++;
        item.details.forEach((detail) => {
          const percent =
            detail.chosenPercentage != null
              ? (Number(detail.chosenPercentage) * 100).toFixed(2) + "%"
              : "-";
          const row = worksheet.addRow([
            detail.optionText,
            detail.chosenQuantity || 0,
            percent,
          const headerRow = worksheet.addRow([
            "问题选项",
            "选择人数",
            "占比",
            "",
          ]);
          row.eachCell((cell) => {
            cell.style = cellStyle;
          headerRow.eachCell((cell) => {
            cell.style = headerStyle;
          });
          currentRow++;
          item.details.forEach((detail) => {
            const percent =
              detail.chosenPercentage != null
                ? (Number(detail.chosenPercentage) * 100).toFixed(2) + "%"
                : "-";
            const row = worksheet.addRow([
              detail.optionText,
              detail.chosenQuantity || 0,
              percent,
              "",
            ]);
            row.eachCell((cell) => {
              cell.style = cellStyle;
            });
            currentRow++;
          });
          currentRow++;
        });
        currentRow++;
      });
        // è®¾ç½®åˆ—宽
        worksheet.columns = [
          { width: 40 },
          { width: 12 },
          { width: 12 },
          { width: 10 },
        ];
      /* ---------- åˆ—宽 ---------- */
      worksheet.columns = [
        { width: 40 },
        { width: 12 },
        { width: 12 },
        { width: 10 },
      ];
        // ç”Ÿæˆæ–‡ä»¶åï¼ˆä¸Žä¸»é¡µé¢ä¿æŒä¸€è‡´ï¼‰
        const fileName = `${
          this.rowData.leavehospitaldistrictname || this.rowData.deptname
        }${this.configTitle}明细_${dateRangeString}.xlsx`;
      /* ---------- å¯¼å‡º ---------- */
      const buffer = await workbook.xlsx.writeBuffer();
      const fileName =
        `${this.rowData.leavehospitaldistrictname || this.rowData.deptname}` +
        `${this.configTitle}明细_` +
        `${this.queryParams.dateRange?.[0]}至${this.queryParams.dateRange?.[1]}.xlsx`;
        const buffer = await workbook.xlsx.writeBuffer();
        saveAs(
          new Blob([buffer], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          }),
          fileName
        );
      saveAs(
        new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        }),
        fileName
      );
      this.$message.success("导出成功");
        this.$message.success("导出成功");
      } catch (error) {
        console.error("导出失败:", error);
        this.$message.error(`导出失败: ${error.message}`);
      }
    },
    // æ ¼å¼åŒ–百分比
    formatPercent(value) {
      if (value === null || value === undefined) return "-";
      const num = parseFloat(value);
      if (isNaN(num)) return "-";
      return `${num.toFixed(2)}%`; // æ³¨æ„ï¼šä½ çš„æ•°æ®ä¸­ç™¾åˆ†æ¯”已经是0-100的形式
      return `${num.toFixed(2)}%`;
    },
    // å…³é—­å¯¹è¯æ¡†
    handleClose() {
      this.$emit("close");
    },
@@ -354,6 +407,7 @@
    overflow: hidden;
    font-size: 14px;
  }
  .dialog-header {
    display: flex;
    justify-content: space-between;
@@ -368,6 +422,7 @@
      color: #303133;
    }
  }
  ::v-deep .el-table th {
    background-color: #f1f5f9;
    color: #333;
src/views/Satisfaction/sfstatistics/components/visitStatistics.vue
@@ -323,6 +323,7 @@
        :row-data="currentRow"
        :topicList="topiclist"
        :query-params="queryParams"
        :topType="1"
        @close="topicVisible = false"
      />
    </el-dialog>
src/views/followvisit/Continue/index.vue
@@ -172,16 +172,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <!-- <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -330,7 +329,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -342,22 +341,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -400,7 +389,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -411,7 +400,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -500,6 +489,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -798,17 +835,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -1063,36 +1105,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "出院服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1334,14 +1402,14 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.jgvalue = response.rows[0].jg;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1426,7 +1494,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1529,6 +1597,37 @@
      this.topqueryParams.startSendDateTime = this.dateRangefs[0];
      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
@@ -2113,4 +2212,24 @@
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/HistoricalFollow/index.vue
@@ -31,16 +31,15 @@
            placeholder="请输入诊断名称"
          ></el-input>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -122,7 +121,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -134,22 +133,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -201,7 +190,7 @@
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -212,7 +201,7 @@
        >
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -307,6 +296,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -590,41 +627,62 @@
        },
      ],
      loading: false,
      cardlist: [
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          name: "出院服务总量",
          value: 0,
          value: null,
          label: "全部",
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "需随访",
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
     cardlist: [
        {
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      // è¡¨å•参数
@@ -841,7 +899,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -947,6 +1005,37 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
src/views/followvisit/OutpatientAgain/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -125,16 +69,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -177,7 +120,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -185,7 +128,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -281,11 +224,11 @@
              type="text"
              @click="
                gettoken360(
                    scope.row.sfzh,
                    scope.row.drcode,
                    scope.row.drname,
                    scope.row.patid
                  )
                  scope.row.sfzh,
                  scope.row.drcode,
                  scope.row.drname,
                  scope.row.patid
                )
              "
              ><span class="button-textsc">{{
                scope.row.sendname
@@ -313,22 +256,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -382,7 +315,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -493,6 +426,54 @@
          prop="templatename"
          width="200"
        />
        <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -657,17 +638,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -837,17 +823,18 @@
  buidegetTasklist,
  addserviceSubtask,
  query360PatInfo,
  query360PatInfonh
  query360PatInfonh,
} from "@/api/AiCentre/index";
import { alterpatient, particularpatient } from "@/api/patient/homepage";
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -922,34 +909,26 @@
      loading: false,
      cardlist: [
        {
          name: "服务跟踪总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -959,6 +938,41 @@
          { required: true, message: "请选择随访时间", trigger: "blur" },
        ],
      },
      // çº§è”选择器绑定值
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // æœåŠ¡çŠ¶æ€é€‰é¡¹ï¼ˆä¸€çº§å’ŒäºŒçº§å€¼ä¸å†²çªï¼‰
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      // è¡¨å•参数
      form: {
        phonenumber: "",
@@ -998,7 +1012,8 @@
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 æœåŠ¡æ—¶é—´(正序)    1 æœåŠ¡æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 3,
        searchscope: 3,
@@ -1011,7 +1026,7 @@
      propss: { multiple: true },
      options: [],
       topicoptions: [
      topicoptions: [
        {
          value: null,
          label: "全部",
@@ -1172,13 +1187,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1252,7 +1267,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1380,6 +1395,37 @@
        this.topqueryParams.searchscope = 3;
      }
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
@@ -1387,7 +1433,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 æœåŠ¡æ—¶é—´(正序)    1 æœåŠ¡æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 3,
        searchscope: 3,
@@ -1603,8 +1650,7 @@
            '"的数据项?'
        )
        .then(() => {
      getTaskservelist({
          getTaskservelist({
            patid: row.patid,
            taskid: row.taskid,
          }).then((res) => {
@@ -1857,7 +1903,26 @@
    font-size: 24px;
  }
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/followvisit/SpecificDisease/index.vue
@@ -108,16 +108,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -232,7 +231,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -244,22 +243,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -308,7 +297,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -319,7 +308,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -414,6 +403,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -812,41 +849,62 @@
        },
      ],
      loading: false,
      cardlist: [
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          name: "出院服务总量",
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
     cardlist: [
        {
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "待随访",
          value: 0,
        },
        {
          name: "待发送",
          name: "已完成",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "已发送未领取",
        //   value: 0,
        // },
      ],
      // è¡¨å•参数
@@ -981,13 +1039,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1119,6 +1177,37 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
src/views/followvisit/Tracking/index.vue
@@ -64,16 +64,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -240,7 +239,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -252,22 +251,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -321,7 +310,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -432,6 +421,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -596,17 +633,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -859,36 +901,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "延续护理服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -937,7 +1005,8 @@
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å»¶ç»­æŠ¤ç†æ—¶é—´(正序)    1 å»¶ç»­æŠ¤ç†æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 3,
        searchscope: 3,
@@ -1111,13 +1180,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1191,7 +1260,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1298,6 +1367,37 @@
      console.log("2");
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
@@ -1326,7 +1426,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 å»¶ç»­æŠ¤ç†æ—¶é—´(正序)    1 å»¶ç»­æŠ¤ç†æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 3,
        searchscope: 3,
@@ -1796,7 +1897,26 @@
    font-size: 24px;
  }
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/followvisit/again/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -125,16 +69,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -177,7 +120,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -185,7 +128,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -302,54 +245,7 @@
          :show-overflow-tooltip="true"
        >
        </el-table-column>
            <!-- <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column> -->
        <el-table-column
          label="随访状态"
          align="center"
@@ -370,22 +266,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -428,7 +314,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -439,7 +325,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -448,6 +334,7 @@
            <span>{{ formatTime(scope.row.visitTime) }}</span>
          </template></el-table-column
        >
        <el-table-column
          label="主治医生"
          width="120"
@@ -541,6 +428,55 @@
          prop="templatename"
          width="200"
        />
        <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -705,17 +641,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -890,12 +831,14 @@
import { alterpatient, particularpatient } from "@/api/patient/homepage";
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import StatisticsCards from "@/components/StatisticsCards";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect, StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -951,7 +894,41 @@
      },
      value: [],
      list: [],
      // çº§è”选择器绑定值
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // æœåŠ¡çŠ¶æ€é€‰é¡¹ï¼ˆä¸€çº§å’ŒäºŒçº§å€¼ä¸å†²çªï¼‰
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      sourcetype: [
        {
          value: 1,
@@ -971,34 +948,26 @@
      loading: false,
      cardlist: [
        {
          name: "出院服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1047,7 +1016,7 @@
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:1,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 2,
        searchscope: 3,
@@ -1212,7 +1181,6 @@
        this.topqueryParams.deptOrDistrict = 1;
      }
      if (!this.followupAuthority()) {
        this.$message.warning("未配置科室/病区相关权限不可查询");
        return Promise.reject(new Error("无权限查询"));
@@ -1221,14 +1189,14 @@
        this.userList = response.rows[0].serviceSubtaskList;
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
         this.cardlist[0].value =
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1301,8 +1269,8 @@
        this.userList = response.rows[0].serviceSubtaskList;
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
         this.cardlist[0].value =
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1430,14 +1398,47 @@
        this.topqueryParams.searchscope = 3;
      }
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
      this.dateRangefs = [];
      this.serviceStatusValue = 10;
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:1,
        sort: 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 2,
        searchscope: 3,
@@ -1653,8 +1654,7 @@
            '"的数据项?'
        )
        .then(() => {
      getTaskservelist({
          getTaskservelist({
            patid: row.patid,
            taskid: row.taskid,
          }).then((res) => {
@@ -1907,7 +1907,26 @@
    font-size: 24px;
  }
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/followvisit/beHospitalized/followUp.vue
@@ -172,16 +172,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -224,7 +223,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -232,7 +231,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -436,22 +435,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -494,7 +483,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -505,7 +494,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -531,12 +520,11 @@
          width="120"
        />
        <el-table-column
          v-if="orgname != '丽水市中医院'"
          label="经管医生"
          label="联系电话"
          width="200"
          align="center"
          key="managementDoctor"
          prop="managementDoctor"
          width="120"
          key="phone"
          prop="phone"
        />
        <el-table-column
          label="出院天数"
@@ -550,18 +538,27 @@
          </template>
        </el-table-column>
        <el-table-column
          label="联系电话"
          width="200"
          align="center"
          key="phone"
          prop="phone"
        />
        <el-table-column
          label="身份证号码"
          width="200"
          align="center"
          key="sfzh"
          prop="sfzh"
        />
        <el-table-column
          label="联系电话"
          width="200"
          v-if="orgname != '丽水市中医院'"
          label="经管医生"
          align="center"
          key="phone"
          prop="phone"
          key="managementDoctor"
          prop="managementDoctor"
          width="120"
        />
        <el-table-column
          label="责任护士"
@@ -607,6 +604,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -946,17 +991,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -1211,36 +1261,97 @@
        },
      ],
      loading: false,
      cardlist: [
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          name: "出院服务总量",
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
    cardlist: [
        {
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      // çº§è”选择器绑定值
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // æœåŠ¡çŠ¶æ€é€‰é¡¹ï¼ˆä¸€çº§å’ŒäºŒçº§å€¼ä¸å†²çªï¼‰
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      zcrules: {
        date1: [
@@ -1306,7 +1417,7 @@
        pageNum: 1,
        pageSize: 10,
        sendstateView:
          localStorage.getItem("orgname") == "省立同德翠苑院区" ? null : 2,
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 18,
        searchscope: 3,
@@ -1530,16 +1641,14 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) +
            Number(response.rows[0].ysf) +
            Number(response.rows[0].fssb);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.jgvalue = response.rows[0].jg;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1643,7 +1752,7 @@
        this.userList = response.rows[0].serviceSubtaskList;
        this.total = response.total;
        this.cardlist[0].value =
          Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
          Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
        this.cardlist[1].value = response.rows[0].wzx;
        this.cardlist[2].value = response.rows[0].ysf;
        this.ycvalue = response.rows[0].yc;
@@ -1767,6 +1876,37 @@
        this.topqueryParams.searchscope = 3;
      }
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
@@ -1774,7 +1914,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 18,
        searchscope: 3,
@@ -2347,6 +2488,26 @@
  border-color: #d8b4fe;
  opacity: 1; /* ä¿æŒç¦ç”¨çŠ¶æ€é€æ˜Žåº¦ */
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/followvisit/beHospitalized/publicity.vue
@@ -98,7 +98,7 @@
      </el-form>
      <el-divider></el-divider>
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -106,7 +106,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
            <div class="document">
@@ -246,7 +246,7 @@
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
src/views/followvisit/complaint/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -133,16 +77,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -311,7 +254,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -323,22 +266,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -381,7 +314,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -491,6 +424,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -830,17 +811,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -946,12 +932,14 @@
import { alterpatient, particularpatient } from "@/api/patient/homepage";
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import StatisticsCards from "@/components/StatisticsCards";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -987,6 +975,41 @@
        type: [],
      },
      zcform: {},
      // çº§è”选择器绑定值
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // æœåŠ¡çŠ¶æ€é€‰é¡¹ï¼ˆä¸€çº§å’ŒäºŒçº§å€¼ä¸å†²çªï¼‰
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      dynamicTags: ["选项一", "选项二", "选项三"], //选项
      inputVisible: false,
      Labelchange: false,
@@ -1023,36 +1046,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1263,13 +1312,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1339,7 +1388,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1441,6 +1490,37 @@
      this.topqueryParams.startSendDateTime = this.dateRangefs[0];
      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
@@ -1982,4 +2062,24 @@
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/discharge/index.vue
@@ -1,86 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5" v-if="orgname == '省立同德翠苑院区'">
          <div class="jgleftvlue">
            <el-card shadow="hover ">
              <div style="padding: 8px">
                <span>警告</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ jgvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -172,16 +97,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
@@ -225,7 +149,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -233,7 +157,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -383,6 +307,7 @@
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
              popper-class="statistics-tooltip"
            >
              <div v-if="scope.row.sendstateView == 1">
                <el-tag type="primary" :disable-transitions="false"
@@ -390,22 +315,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -427,6 +342,7 @@
            />
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -452,7 +368,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -463,7 +379,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -489,13 +405,53 @@
          width="120"
        />
        <el-table-column
          v-if="orgname != '丽水市中医院'"
          label="经管医生"
          label="任务状态"
          align="center"
          key="managementDoctor"
          prop="managementDoctor"
          key="sendstate"
          prop="sendstate"
          width="120"
        />
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="出院天数"
          width="120"
@@ -508,13 +464,6 @@
          </template>
        </el-table-column>
        <el-table-column
          label="身份证号码"
          width="200"
          align="center"
          key="sfzh"
          prop="sfzh"
        />
        <el-table-column
          label="联系电话"
          width="200"
          align="center"
@@ -522,13 +471,28 @@
          prop="phone"
        />
        <el-table-column
          label="身份证号码"
          width="200"
          align="center"
          key="sfzh"
          prop="sfzh"
        />
        <el-table-column
          label="责任护士"
          width="120"
          align="center"
          key="nurseName"
          prop="nurseName"
        />
        <el-table-column
          v-if="orgname != '丽水市中医院'"
          label="经管医生"
          align="center"
          key="managementDoctor"
          prop="managementDoctor"
          width="120"
        />
        <!-- <el-table-column
          label="病历号"
          align="center"
@@ -580,6 +544,7 @@
            </span>
          </template>
        </el-table-column> -->
        <el-table-column
          label="任务结果说明"
          width="220"
@@ -901,6 +866,11 @@
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
              <!-- æé†’文字 -->
              <div class="filter-warning">
                <i class="el-icon-warning-outline"></i>
                è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
              </div>
            </el-form-item>
          </el-col>
        </el-row>
@@ -1078,13 +1048,15 @@
} from "@/api/AiCentre/index";
import { alterpatient, particularpatient } from "@/api/patient/homepage";
import Treeselect from "@riophae/vue-treeselect";
import StatisticsCards from "@/components/StatisticsCards";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect, StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -1137,7 +1109,41 @@
      // æ»¡æ„åº¦è°ƒæŸ¥æ•°æ®
      scoreDialogVisible: false,
      selectedRows: [],
      // çº§è”选择器绑定值
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // æœåŠ¡çŠ¶æ€é€‰é¡¹ï¼ˆä¸€çº§å’ŒäºŒçº§å€¼ä¸å†²çªï¼‰
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      value: [],
      list: [],
@@ -1160,34 +1166,26 @@
      loading: false,
      cardlist: [
        {
          name: "出院服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1252,10 +1250,10 @@
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        sendstateView:
          localStorage.getItem("orgname") == "省立同德翠苑院区" ? null : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        sendstateView: 1,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 1, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 2,
        sendstate: null,
        searchscope: 3,
        visitCount: 1,
        scopetype: [],
@@ -1477,16 +1475,14 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) +
            Number(response.rows[0].ysf) +
            Number(response.rows[0].fssb);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.jgvalue = response.rows[0].jg;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1590,7 +1586,7 @@
        this.userList = response.rows[0].serviceSubtaskList;
        this.total = response.total;
        this.cardlist[0].value =
          Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
          Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
        this.cardlist[1].value = response.rows[0].wzx;
        this.cardlist[2].value = response.rows[0].ysf;
        this.ycvalue = response.rows[0].yc;
@@ -1714,10 +1710,42 @@
        this.topqueryParams.searchscope = 3;
      }
    },
    // æœåŠ¡çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
      this.dateRangefs = [];
      this.serviceStatusValue = 10;
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
@@ -2300,10 +2328,47 @@
  border-color: #d8b4fe;
  opacity: 1; /* ä¿æŒç¦ç”¨çŠ¶æ€é€æ˜Žåº¦ */
}
.statistics-tooltip {
  background: #ffffff !important;
  color: #1976d2 !important;
  border: 1px solid #bbdefb !important;
  border-radius: 8px !important;
  padding: 10px 14px !important;
  font-size: 13px !important;
  line-height: 1.6 !important;
  box-shadow: 0 4px 12px rgba(25, 118, 210, 0.15) !important;
}
.statistics-tooltip .popper__arrow {
  border-bottom-color: #bbdefb !important;
}
.statistics-tooltip .popper__arrow::after {
  border-bottom-color: #ffffff !important;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/discharge/outpatientService.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -131,16 +75,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -307,7 +250,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -319,22 +262,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -389,7 +322,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -491,6 +424,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -645,17 +626,22 @@
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -830,12 +816,14 @@
import { alterpatient, particularpatient } from "@/api/patient/homepage";
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import StatisticsCards from "@/components/StatisticsCards";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -909,36 +897,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "门诊服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1156,13 +1170,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1233,7 +1247,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1336,6 +1350,37 @@
      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
@@ -1361,7 +1406,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 3,
        searchscope: 3,
@@ -1837,4 +1883,24 @@
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/mzsatisfaction/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -187,7 +131,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -195,7 +139,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -312,7 +256,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -324,22 +268,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -382,7 +316,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -492,6 +426,54 @@
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -798,17 +780,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -984,11 +971,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -1063,34 +1051,26 @@
      loading: false,
      cardlist: [
        {
          name: "服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1309,13 +1289,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1385,7 +1365,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1996,4 +1976,24 @@
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/operation/index.vue
@@ -172,16 +172,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -224,7 +223,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -232,7 +231,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -384,7 +383,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -396,22 +395,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -440,6 +429,54 @@
            />
          </template>
        </el-table-column>
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -465,7 +502,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -476,7 +513,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -906,17 +943,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -1171,36 +1213,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "手术总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1266,7 +1334,7 @@
        pageNum: 1,
        pageSize: 10,
        sendstateView:
          localStorage.getItem("orgname") == "省立同德翠苑院区" ? null : 2,
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 æ‰‹æœ¯å®Œæˆæ—¶é—´(正序)    1 æ‰‹æœ¯å®Œæˆæ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 19,
        searchscope: 3,
@@ -1489,16 +1557,14 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) +
            Number(response.rows[0].ysf) +
            Number(response.rows[0].fssb);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.jgvalue = response.rows[0].jg;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1602,7 +1668,7 @@
        this.userList = response.rows[0].serviceSubtaskList;
        this.total = response.total;
        this.cardlist[0].value =
          Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
          Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
        this.cardlist[1].value = response.rows[0].wzx;
        this.cardlist[2].value = response.rows[0].ysf;
        this.ycvalue = response.rows[0].yc;
@@ -1708,6 +1774,37 @@
      }
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
@@ -1733,7 +1830,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 æ‰‹æœ¯å®Œæˆæ—¶é—´(正序)    1 æ‰‹æœ¯å®Œæˆæ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 19,
        searchscope: 3,
@@ -2318,4 +2416,24 @@
//     font-size: 24px;
//   }
// }
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
</style>
src/views/followvisit/outpatient/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
              {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <!-- <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col> -->
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -108,16 +52,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -235,7 +178,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -247,22 +190,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -338,7 +271,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -433,6 +366,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -660,11 +641,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -734,41 +716,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "门诊服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        // {
        //   name: "发送失败",
        //   value: 0,
        // },
        {
          name: "待随访",
          value: 0,
        },
        {
          name: "已随访",
          name: "已完成",
          value: 0,
        },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
      ],
      // è¡¨å•参数
@@ -887,7 +890,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          // this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -991,9 +994,50 @@
    handleChange(value) {
      let type = value[0];
      let code = value.slice(-1)[0];
      this.topqueryParams.leavehospitaldistrictcodes = [];
      this.topqueryParams.leaveldeptcodes = [];
      if (type == 1) {
        this.topqueryParams.leaveldeptcodes.push(code);
        this.topqueryParams.leavehospitaldistrictcodes = [];
        this.topqueryParams.searchscope = 1;
      } else if (type == 2) {
        this.topqueryParams.leavehospitaldistrictcodes.push(code);
        this.topqueryParams.leaveldeptcodes = [];
        this.topqueryParams.searchscope = 2;
      } else {
        this.topqueryParams.searchscope = 3;
      }
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
src/views/followvisit/record/detailpage/index.vue
@@ -144,6 +144,18 @@
            show-overflow-tooltip
          >
          </el-table-column>
            <el-table-column
            v-if="orgname == '南华大学附属第一医院'"
            label="入院日期"
            width="200"
            align="center"
            key="starttime"
            prop="starttime"
          >
            <template slot-scope="scope">
              <span>{{ formatTime(scope.row.starttime) }}</span>
            </template></el-table-column
          >
          <el-table-column
            label="出院日期"
            width="200"
@@ -155,6 +167,7 @@
              <span>{{ formatTime(scope.row.endtime) }}</span>
            </template></el-table-column
          >
          <el-table-column
            label="责任护士"
            width="120"
@@ -264,15 +277,34 @@
      <!-- éšè®¿å†…容 -->
      <div class="call-action">
        <div class="call-container">
          <template-selector
          <div
            style="display: flex"
            v-if="orgname == '南华大学附属第一医院' && !Voicetype"
            v-model="form.templateid"
            :templateName="form.templatename"
            :service-type="form.serviceType"
            :is-editable="form.sendState !== 2"
            @select="handleTemplateSelect"
            @clear="handleTemplateClear"
          />
          >
            <template-selector
              v-model="form.templateid"
              :templateName="form.templatename"
              :service-type="form.serviceType"
              :is-editable="form.sendState !== 2"
              @select="handleTemplateSelect"
              @clear="handleTemplateClear"
            />
            <div
              v-if="defaultKey"
              style="
                display: flex;
                align-items: center;
                justify-content: center;
                height: 100%;
                padding: 33px 0 0 50px;
              "
            >
              <el-button type="success" round @click="handleConfirmReplace">
                é»˜è®¤å¡«å……
              </el-button>
            </div>
          </div>
          <div class="headline">
            <div>随访内容</div>
          </div>
@@ -1187,6 +1219,7 @@
  updateTemplate,
  query360PatInfonh,
  sendMsg,
  getconfigKey,
} from "@/api/AiCentre/index";
import {
  messagelistpatient,
@@ -1290,6 +1323,7 @@
    return {
      visitAgain: 1,
      userid: "",
      defaultKey: false, //是否可默认填报
      currentPhoneNumber: "",
      callType: "", // ç”¨äºŽåŒºåˆ†æ˜¯å“ªä¸ªç”µè¯
      isSipRegistering: true, // SIP注册状态
@@ -1472,56 +1506,6 @@
          // ç¦ç”¨ä»Šå¤©åŠä¹‹å‰çš„æ—¥æœŸ
          return time.getTime() < Date.now() - 24 * 60 * 60 * 1000;
        },
        // shortcuts: [
        //   {
        //     text: "七天后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
        //       picker.$emit("pick", date);
        //     },
        //   },
        //   {
        //     text: "15天后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 15);
        //       picker.$emit("pick", date);
        //     },
        //   },
        //   {
        //     text: "一个月后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 30);
        //       picker.$emit("pick", date);
        //     },
        //   },
        //   {
        //     text: "三个月后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 90);
        //       picker.$emit("pick", date);
        //     },
        //   },
        //   {
        //     text: "六个月后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 180);
        //       picker.$emit("pick", date);
        //     },
        //   },
        //   {
        //     text: "一年后",
        //     onClick(picker) {
        //       const date = new Date();
        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 365);
        //       picker.$emit("pick", date);
        //     },
        //   },
        // ],
      },
      options: [
        {
@@ -1644,6 +1628,7 @@
      ];
    }
    this.getTaskservelist();
    this.getconfigKey();
  },
  mounted() {
    // ç›‘听子组件的sipStatus属性变化
@@ -1683,7 +1668,30 @@
        return "scriptTopic-dev"; // æ­£å¸¸ - é»˜è®¤æ ·å¼
      }
    },
    getconfigKey() {
      getconfigKey("default.value.icon").then((res) => {
        if (res.msg) {
          if (
            this.getAssignArr(res.msg).includes(this.$store.state.user.name) ||
            this.$store.state.user.name == "admin"
          ) {
            this.defaultKey = true;
          } else {
            this.defaultKey = false;
          }
        }
      });
    },
    getAssignArr(rule) {
      let arr = [];
      let assiginArr = rule.split(",");
      for (let i = 0; i < assiginArr.length; i++) {
        arr[i] = assiginArr[i];
      }
      arr.sort(this.compare);
      return arr;
    },
    // èŽ·å–é€‰é¡¹æ ·å¼ç±»
    getOptionClass(items) {
      if (items.isabnormal == 1) {
@@ -2102,6 +2110,39 @@
    handleTemplateClear() {
      console.log("清除了模板选择");
    },
    handleConfirmReplace() {
      // éåŽ†æ‰€æœ‰é¢˜ç›®ï¼ˆtableDatatop)
      this.tableDatatop.forEach((item) => {
        // åªå¤„理未填报的题目(scriptResult ä¸ºç©ºæˆ–空数组)
        if (
          !item.scriptResult ||
          (Array.isArray(item.scriptResult) && item.scriptResult.length === 0)
        ) {
          // æŸ¥æ‰¾é€‰é¡¹ä¸­ defaultValue ä¸º 2 çš„选项
          const defaultOption = item.svyTaskTemplateTargetoptions?.find(
            (opt) => opt.defaultValue == 2
          );
          console.log(item);
          if (defaultOption) {
            // æ ¹æ®é¢˜ç›®ç±»åž‹èµ‹å€¼
            if (item.scriptType === "1") {
              // å•选题:直接赋值为 optioncontent å­—符串
              item.scriptResult = defaultOption.optioncontent;
            } else if (item.scriptType === "2") {
              // å¤šé€‰é¢˜ï¼šèµ‹å€¼ä¸ºåŒ…含 optioncontent çš„æ•°ç»„
              item.scriptResult = [defaultOption.optioncontent];
            } else if (item.scriptType === "4") {
              // å¡«ç©ºé¢˜ï¼šä¸€èˆ¬æ²¡æœ‰é€‰é¡¹ï¼Œä½†å¦‚果有则赋值
              item.scriptResult = defaultOption.optioncontent;
            }
            // è§¦å‘视图更新(因为 Vue å¯èƒ½æ— æ³•检测到深层嵌套对象的变化)
            this.$forceUpdate();
          }
        }
      });
    },
    // ä½¿ç”¨ç¤ºä¾‹
    isValidPhone(phone) {
      return this.validatePhoneNumber(phone).isValid;
src/views/followvisit/record/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -165,7 +109,7 @@
      </el-form>
      <el-divider></el-divider>
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -173,7 +117,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
            <div class="document">
@@ -288,7 +232,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -300,22 +244,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -364,7 +298,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -375,7 +309,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -478,6 +412,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -773,11 +755,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -894,39 +877,26 @@
      loading: false,
      cardlist: [
        {
          name: "出院服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "需随访",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      // è¡¨å•参数
@@ -1098,13 +1068,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1208,7 +1178,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
src/views/followvisit/technology/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -108,16 +52,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -245,7 +188,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -257,22 +200,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -321,7 +254,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -332,7 +265,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -427,6 +360,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -717,11 +698,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -793,41 +775,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "出院服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "需随访",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      postData: {
        XiaoXiTou: {
@@ -994,13 +997,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1056,7 +1059,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1194,6 +1197,37 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
src/views/followvisit/zbAgain/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -125,16 +69,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item label="排序方式" prop="status">
          <el-select v-model="topqueryParams.sort" placeholder="请选择">
@@ -301,7 +244,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -313,22 +256,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -371,7 +304,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -382,7 +315,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -492,6 +425,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -646,17 +627,22 @@
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -832,11 +818,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -910,36 +897,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "出院服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -988,7 +1001,8 @@
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 13,
        searchscope: 3,
@@ -1162,13 +1176,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1242,7 +1256,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1349,6 +1363,37 @@
      console.log("2");
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
@@ -1377,7 +1422,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
        sendstateView: 1,
        sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 13,
        searchscope: 3,
@@ -1846,7 +1892,26 @@
    font-size: 24px;
  }
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/followvisit/zysatisfaction/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
                {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
     <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -187,7 +131,7 @@
            </div>
          </div>
        </el-col>
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -195,7 +139,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
@@ -312,7 +256,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -324,22 +268,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -382,7 +316,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -491,6 +425,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -830,17 +812,22 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="过滤原因">
              <el-input
                v-model="form.notrequiredreason"
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
       <el-row>
  <el-col :span="24">
    <el-form-item label="过滤原因">
      <el-input
        v-model="form.notrequiredreason"
        type="textarea"
        placeholder="请输入过滤原因"
      ></el-input>
      <!-- æé†’文字 -->
      <div class="filter-warning">
        <i class="el-icon-warning-outline"></i>
        è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
      </div>
    </el-form-item>
  </el-col>
</el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
@@ -946,11 +933,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -1024,34 +1012,26 @@
      loading: false,
      cardlist: [
        {
          name: "服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "发送失败",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      zcrules: {
        date1: [
@@ -1101,7 +1081,7 @@
        pageNum: 1,
        pageSize: 10,
         sendstateView:
          localStorage.getItem("orgname") == "省立同德翠苑院区" ? null : 2,
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: localStorage.getItem("orgname") == "丽水市中医院" ? 8 : 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)  7应随访日期(倒序) åº”随访日期(正序)
        serviceType: 6,
        searchscope: 3,
@@ -1271,13 +1251,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -1347,7 +1327,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -1475,7 +1455,8 @@
      this.topqueryParams = {
        pageNum: 1,
        pageSize: 10,
          sendstateView: 1,
          sendstateView:
          localStorage.getItem("orgname") == "南华大学附属第一医院" ? 1 : 2,
        sort: 2, //0 å‡ºé™¢æ—¶é—´(正序)    1 å‡ºé™¢æ—¶é—´(倒序)   2 å‘送时间(正序)    3 å‘送时间(倒序)
        serviceType: 6,
        searchscope: 3,
@@ -1984,6 +1965,26 @@
  border-color: #d8b4fe;
  opacity: 1; /* ä¿æŒç¦ç”¨çŠ¶æ€é€æ˜Žåº¦ */
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
src/views/outsideChainwtnew.vue
@@ -23,6 +23,7 @@
                  : "亲爱的患者-家属,我们是医院的医护人员,为了更好地了解您的康复情况,请您抽一点宝贵时间,完成这份随访问卷。"
              }}
            </div>
            <div v-if="orgname" class="questionnaire-signature">———{{ orgname }}</div>
          </div>
          <el-divider class="custom-divider"></el-divider>
@@ -93,7 +94,7 @@
                        @click.native.prevent="
                          handleRadioToggle(
                            item,
                            getGlobalIndex(dimension, group, index),
                            getGlobalIndex(item.dimension, group, index),
                            item.svyTaskTemplateTargetoptions,
                            option.optioncontent
                          )
@@ -159,6 +160,18 @@
                      :closable="false"
                      class="warning-alert"
                    ></el-alert>
                  </div>
                  <div
                    v-if="item.showAppendInput || item.answerps"
                    class="append-input-container"
                  >
                    <el-input
                      type="textarea"
                      :rows="1"
                      placeholder="请输入具体信息"
                      v-model="item.answerps"
                      clearable
                    ></el-input>
                  </div>
                </div>
              </div>
@@ -281,6 +294,18 @@
                  class="warning-alert"
                ></el-alert>
              </div>
              <div
                v-if="item.showAppendInput || item.answerps"
                class="append-input-container"
              >
                <el-input
                  type="textarea"
                  :rows="1"
                  placeholder="请输入具体信息"
                  v-model="item.answerps"
                  clearable
                ></el-input>
              </div>
            </div>
          </div>
@@ -335,6 +360,7 @@
      excep: 0,
      isabnormal: 0,
      taskname: "",
      orgname: "",
      questionList: [],
      param6: null,
      jsy: null,
@@ -480,6 +506,8 @@
            res.data.param3,
            res.data.param5
          );
          this.orgname = res.data.orgname;
          this.param6 = res.data.param6;
        }
      });
@@ -746,6 +774,7 @@
      this.questionList[questionIndex].showAppendInput =
        selectedOptionObj.appendflag == 1;
      console.log(this.questionList);
      console.log(selectedOptionObj.appendflag);
      // if (!this.questionList[questionIndex].showAppendInput) {
      //   this.questionList[questionIndex].answerps = ""; // æ¸…除附加信息
@@ -818,6 +847,7 @@
          hiddenByEnd: index == questionIndex + 1 ? false : item.hiddenByEnd,
        }));
      }
      this.$forceUpdate();
      // åœ¨å¤„理完题目显示/隐藏后,强制更新视图以确保序号正确
      this.$nextTick(() => {
@@ -864,13 +894,24 @@
}
.questionnaire-description {
  font-size: 18px;
  font-size: 16px;
  color: #5a6c84;
  line-height: 1.6;
  max-width: 700px;
  margin: 0 auto;
  line-height: 1.8;
  max-width: 720px;
  margin: 0;
  padding: 0 16px;
  text-align: justify; /* ä¸¤ç«¯å¯¹é½ï¼Œæ›´ç¾Žè§‚ */
  text-indent: 2em; /* é¦–行缩进 */
}
.questionnaire-signature {
  font-size: 15px;
  color: #8a9bb5; /* æ¯”正文颜色稍浅,体现附属感 */
  text-align: right; /* å³å¯¹é½ */
  max-width: 720px;
  margin: 8px 0 0 auto; /* ä¸Šè¾¹è·8px,右边靠齐 */
  padding: 0 16px;
  letter-spacing: 1px; /* å­—间距稍宽,更有落款感 */
}
.custom-divider {
  margin: 25px 0;
  background-color: #eaeef2;
@@ -930,8 +971,10 @@
}
.question-stem {
  display: flex;
  align-items: flex-start;
  display: grid;
  grid-template-columns: auto 1fr auto; /* é¢˜å·è‡ªé€‚应,文本占满剩余空间,题型标签自适应 */
  gap: 3px;
  align-items: center;
  margin-bottom: 20px;
  font-size: 18px;
}
@@ -939,22 +982,23 @@
.question-number {
  font-weight: 600;
  color: #175997;
  margin-right: 8px;
  min-width: 24px;
  min-width: 16px;
}
.question-text {
  flex: 1;
  line-height: 1.5;
  color: #2c3e50;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.question-type-tag {
  color: #3ba2f7;
  font-size: 14px;
  margin-left: 10px;
  font-weight: 500;
  text-align: right;
}
.question-options {
@@ -1021,7 +1065,13 @@
.question-warning {
  margin-top: 15px;
}
.append-input-container {
  margin-top: 15px;
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
}
.warning-alert {
  :deep(.el-alert__title) {
    font-size: 15px;
src/views/patient/patient/ExternalPatient.vue
@@ -736,21 +736,24 @@
      cardlist: [
        {
          name: "患者总数",
          value: 123,
          name: "患者服务总量",
          value: 0,
        },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "在院患者",
          value: 23,
          router: "/patient/inpatient",
          name: "需随访",
          value: 0,
        },
        {
          name: "出院患者",
          value: 41,
          router: "/patient/hospital",
          name: "待随访",
          value: 0,
        },
        {
          name: "离世患者",
          name: "已完成",
          value: 0,
        },
      ],
src/views/patient/patient/index.vue
@@ -668,6 +668,11 @@
                type="textarea"
                placeholder="请输入过滤原因"
              ></el-input>
              <!-- æé†’文字 -->
              <div class="filter-warning">
                <i class="el-icon-warning-outline"></i>
                è¯¥åŠŸèƒ½é€‚ç”¨äºŽæ­»äº¡ã€åˆ—å…¥åŒ»é™¢é»‘åå•ã€æ˜Žç¡®æ‹’ç»éšè®¿ç­‰æ‚£è€…çš„è¿‡æ»¤æŽ’é™¤ï¼Œè¿‡æ»¤åŽè¯¥æ‚£è€…æ‰€æœ‰è¿›è¡Œä¸­ä»»åŠ¡å…¨éƒ¨åœæ­¢ä¸”æ— æ³•åŒ¹é…æ–°çš„éšè®¿ä»»åŠ¡ï¼Œè¯·è°¨æ…Žæ“ä½œï¼
              </div>
            </el-form-item>
          </el-col>
        </el-row>
@@ -1640,6 +1645,26 @@
    height: 50px;
  }
}
.filter-warning {
  margin-top: 8px;
  padding: 10px 14px;
  background: #fff7e6;
  border: 1px solid #ffe58f;
  border-radius: 6px;
  color: #d46b08;
  font-size: 18px;
  line-height: 1.6;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.filter-warning .el-icon-warning-outline {
  font-size: 16px;
  color: #faad14;
  flex-shrink: 0;
  margin-top: 2px;
}
.button-textsc {
  color: #3664d9;
}
src/views/patient/patient/outpatient.vue
@@ -211,7 +211,7 @@
            align="center"
            key="admitdate"
            prop="admitdate"
            width="160"
            width="140"
          >
            <template slot-scope="scope">
              <span>{{ formatTime(scope.row.admitdate) }}</span>
@@ -225,6 +225,7 @@
          /> -->
          <el-table-column
            label="病案号"
            width="100"
            align="center"
            key="outhospno"
            prop="outhospno"
@@ -297,7 +298,6 @@
            align="center"
            key="diagname"
            prop="diagname"
            width="190"
          />
          <!-- <el-table-column
            label="主述"
@@ -311,14 +311,12 @@
            align="center"
            key="deptname"
            prop="deptname"
            width="120"
          />
          <el-table-column
            label="接诊医生"
            align="center"
            key="drname"
            prop="drname"
            width="120"
          />
          <el-table-column
            label="是否存在任务"
@@ -341,7 +339,6 @@
            label="操作"
            fixed="right"
            align="center"
            width="160"
            class-name="small-padding fixed-width"
          >
            <template slot-scope="scope">
src/views/patient/patient/physical.vue
@@ -256,7 +256,7 @@
            align="center"
            key="admitdate"
            prop="admitdate"
            width="160"
            width="140"
          >
            <template slot-scope="scope">
              <span>{{ formatTime(scope.row.admitdate) }}</span>
@@ -276,7 +276,6 @@
            label="操作"
            fixed="right"
            align="center"
            width="160"
            class-name="small-padding fixed-width"
          >
            <template slot-scope="scope">
src/views/patient/patient/profile/index.vue
@@ -375,7 +375,6 @@
            align="center"
            key="admitdate"
            prop="admitdate"
            width="160"
          >
            <template slot-scope="scope">
              <span>{{ formatTime(scope.row.admitdate) }}</span>
@@ -384,6 +383,7 @@
          <el-table-column
            label="病案号"
            width="100"
            align="center"
            key="outhospno"
            prop="outhospno"
src/views/patient/physical/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
              {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <!-- <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col> -->
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -108,16 +52,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -235,7 +178,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -247,22 +190,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -338,7 +271,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -433,6 +366,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -660,11 +641,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -734,41 +716,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "心电服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        // {
        //   name: "发送失败",
        //   value: 0,
        // },
        {
          name: "待随访",
          value: 0,
        },
        {
          name: "已随访",
          name: "已完成",
          value: 0,
        },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
      ],
      // è¡¨å•参数
@@ -887,7 +890,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          // this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -987,13 +990,54 @@
      this.getList(refresh);
    },
    // æ‚£è€…范围处理
   // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
      let code = value.slice(-1)[0];
      this.topqueryParams.leavehospitaldistrictcodes = [];
      this.topqueryParams.leaveldeptcodes = [];
      if (type == 1) {
        this.topqueryParams.leaveldeptcodes.push(code);
        this.topqueryParams.leavehospitaldistrictcodes = [];
        this.topqueryParams.searchscope = 1;
      } else if (type == 2) {
        this.topqueryParams.leavehospitaldistrictcodes.push(code);
        this.topqueryParams.leaveldeptcodes = [];
        this.topqueryParams.searchscope = 2;
      } else {
        this.topqueryParams.searchscope = 3;
      }
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
src/views/patient/propaganda/Missionotice.vue
@@ -200,7 +200,7 @@
          align="center"
          key="admitdate"
          prop="admitdate"
          width="160"
          width="140"
        >
        </el-table-column>
        <el-table-column
src/views/patient/propaganda/QuestionnaireTask.vue
@@ -1503,13 +1503,16 @@
      if (this.submitLoading) {
        return;
      }
      // ç¬¬äºŒæ­¥ï¼šå¼€å¯åŠ è½½çŠ¶æ€ï¼Œç¦ç”¨æŒ‰é’®
      // å¼€å¯åŠ è½½çŠ¶æ€
      this.submitLoading = true;
      console.log(this.submitLoading);
      try {
        if (this.time4 && this.form.sendType == 3)
        // æ—¶é—´å¤„理
        if (this.time4 && this.form.sendType == 3) {
          this.form.showTimeMorn = this.time4;
        }
        this.form.sendTimeslot = [
          {
            begantime: this.time4,
@@ -1517,8 +1520,8 @@
            xh: 1,
          },
        ];
        console.log(1);
        // æ ¹æ®åº”用类型清理字段
        if (this.form.appltype == 1) {
          this.leavehospitaldistrictcodes = [];
          this.form.oplevelcode = null;
@@ -1536,75 +1539,90 @@
          this.illnesscodes = [];
          this.leavehospitaldistrictcodes = [];
        }
        // æ ¡éªŒï¼šæœåŠ¡ç±»åž‹
        if (this.checkList) {
          this.form.preachform = this.checkList.join(",");
          this.form.preachformList = this.selectedOrder;
        } else {
          this.$modal.msgError("请选择服务类型");
          this.submitLoading = false;
          return;
        }
        console.log(2);
        if (
        // æ ¡éªŒï¼šç–¾ç—…关联科室或病区
        if (this.form.appltype == 3) {
          const hasDept = this.diseaseDept?.deptCode;
          const hasWard = this.diseaseWard?.districtCode;
          if (!hasDept && !hasWard) {
            this.$modal.msgError("当前疾病需关联科室或病区");
            this.submitLoading = false;
            return;
          }
        }
        // æ ¡éªŒï¼šä»»åŠ¡å…³è”æ¡ä»¶
        const hasCondition =
          this.deptcodesWards[0] ||
          this.leavehospitaldistrictcodes[0] ||
          this.diagglist[0] ||
          this.form.oplevelcode ||
          this.form.longTask == 2 ||
          this.serviceType == 3
        ) {
        } else {
          this.serviceType == 3;
        if (!hasCondition) {
          this.$modal.msgError("请选择任务关联条件");
          this.submitLoading = false;
          return;
        }
        //暂停任务患者限制
        // if (!this.form.patTaskRelevances[0] && !this.form.longTask) {
        //   this.$modal.msgError("请选择病人");
        //   return;
        // }
        console.log(3);
        // æ ¡éªŒï¼šæ¨¡æ¿
        if (!this.form.templatename && !this.templateor) {
          this.$modal.msgError("未选择模板");
          this.submitLoading = false;
          return;
        }
        if (
        // æ ¡éªŒï¼šæ—¶é—´ä¿¡æ¯
        const isValidTime =
          (this.form.sendType == 1 && this.time1) ||
          this.form.sendType == 2
        ) {
        } else if (
          this.form.sendType == 2 ||
          (this.form.sendType == 3 && this.time4) ||
          this.form.longTask
        ) {
        } else {
          this.form.longTask;
        if (!isValidTime) {
          this.submitLoading = false;
          return this.$modal.msgError("时间信息缺失");
          this.$modal.msgError("时间信息缺失");
          return;
        }
        // å¤„理文本参数
        const filteredArray = this.variableList.filter(
          (item) =>
            item.name !== "姓名" && item.name !== "电话" && item.name !== "地址"
        );
        this.form.textParam = this.convertFormat2ToFormat1(filteredArray);
        // è®¾ç½®æ“ä½œç±»åž‹
        if (this.form.taskid) {
          this.form.isoperation = 2;
        } else {
          this.form.isoperation = 1;
        }
        // è®¾ç½®ç±»åž‹
        if (!this.form.type) {
          this.form.type = this.$route.query.type;
        }
        console.log(4);
        // ç»„装提交数据
        this.form.serviceType = this.serviceType;
        this.form.deptcode = this.deptcodesWards.join(",");
        this.form.leavehospitaldistrictcode =
          this.leavehospitaldistrictcodes.join(",");
        // this.form.opcode = this.operationcodes.join(",");
        // ç–¾ç—…关联的科室/病区
        if (this.form.appltype == 3) {
          if (this.diseaseDept) {
            this.form.deptcode = this.diseaseDept.deptCode;
@@ -1617,30 +1635,46 @@
          }
        }
        // è¯Šæ–­ä¿¡æ¯
        this.form.icd10code = this.diagglist
          .map((item) => item.icdcode)
          .join(",");
        this.form.icd10name = this.diagglist
          .map((item) => item.icdname)
          .join(",");
        Editsingletask(this.form).then((res) => {
          if (res.code == 200) {
            if (this.form.taskid) {
              this.$modal.msgSuccess("修改成功");
        // æäº¤æŽ¥å£
        Editsingletask(this.form)
          .then((res) => {
            if (res.code == 200) {
              if (this.form.taskid) {
                this.$modal.msgSuccess("修改成功");
              } else {
                this.$modal.msgSuccess("新增成功");
              }
              this.$router.push({
                path: "/followvisit/tasklist",
                query: { tasktopic: this.form.serviceType },
              });
            } else {
              this.$modal.msgSuccess("新增成功");
              // âœ… æŽ¥å£è¿”回错误码时的处理
              this.$modal.msgError(res.msg || "操作失败");
            }
            this.$router.push({
              path: "/followvisit/tasklist",
              query: { tasktopic: this.form.serviceType },
            });
          })
          .catch((error) => {
            // âœ… æ•获接口请求异常
            console.error("提交失败:", error);
            this.$modal.msgError(error.message || "网络异常,请稍后重试");
          })
          .finally(() => {
            // âœ… æ— è®ºæˆåŠŸæˆ–å¤±è´¥ï¼Œæœ€ç»ˆéƒ½å…³é—­åŠ è½½çŠ¶æ€
            this.submitLoading = false;
          }
        });
          });
      } catch (error) {
        // âœ… æ•获同步代码异常
        console.error("表单提交异常:", error);
        this.$modal.msgError(error.message || "表单提交异常");
        this.submitLoading = false;
      } finally {
        // ç¬¬å››æ­¥ï¼šæ— è®ºæˆåŠŸæˆ–å¤±è´¥ï¼Œæœ€ç»ˆéƒ½å…³é—­åŠ è½½çŠ¶æ€
      }
    },
    handleDiseaseDeptChange(dept) {
@@ -2102,6 +2136,14 @@
            this.form.patTaskRelevances = this.form.patTaskRelevances
              ? this.form.patTaskRelevances
              : [];
            this.diseaseDept = {
              deptCode: this.form.deptcode,
              deptName: this.form.deptname,
            };
            this.diseaseWard = {
              districtCode: this.form.leavehospitaldistrictcode,
              districtName: this.form.leavehospitaldistrictname,
            };
            this.overallCase = this.form.patTaskRelevances.concat();
            this.checkList = this.form.preachform.split(",");
            this.selectedOrder = this.form.preachformList;
src/views/patient/propaganda/index.vue
@@ -98,7 +98,7 @@
      </el-form>
      <el-divider></el-divider>
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
        <!-- <el-col :span="1.5">
          <el-button
            type="primary"
            icon="el-icon-plus"
@@ -106,7 +106,7 @@
            @click="handleAdd"
            >新增</el-button
          >
        </el-col>
        </el-col> -->
        <el-col :span="1.5">
          <div class="documentf">
            <div class="document">
@@ -246,7 +246,7 @@
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
src/views/patient/propaganda/particty.vue
@@ -1530,15 +1530,24 @@
    },
    // ä¿å­˜
    submitForm(type) {
      // é˜²æ­¢é‡å¤æäº¤
      if (this.submitLoading) {
        return;
      }
      // ç¬¬äºŒæ­¥ï¼šå¼€å¯åŠ è½½çŠ¶æ€ï¼Œç¦ç”¨æŒ‰é’®
      // å¼€å¯åŠ è½½çŠ¶æ€
      this.submitLoading = true;
      try {
        if (this.templateor && type) this.templateor = false;
        if (this.time4 && this.form.sendType == 3)
        // æ¨¡æ¿ç›¸å…³å¤„理
        if (this.templateor && type) {
          this.templateor = false;
        }
        // æ—¶é—´å¤„理
        if (this.time4 && this.form.sendType == 3) {
          this.form.showTimeMorn = this.time4;
        }
        this.form.sendTimeslot = [
          {
            begantime: this.time4,
@@ -1546,6 +1555,8 @@
            xh: 1,
          },
        ];
        // æ ¹æ®åº”用类型清理字段
        if (this.form.appltype == 1) {
          this.leavehospitaldistrictcodes = [];
          this.operationcodes = [];
@@ -1563,68 +1574,88 @@
          this.illnesscodes = [];
          this.leavehospitaldistrictcodes = [];
        }
        // ===== è¡¨å•校验 =====
        // 1. æœåŠ¡ç±»åž‹æ ¡éªŒ
        if (this.checkList) {
          this.form.preachform = this.checkList.join(",") || [];
          this.form.preachformList = this.selectedOrder || [];
        } else {
          this.$modal.msgError("请选择服务类型");
          this.submitLoading = false;
          return;
        }
        if (
        // 2. ç–¾ç—…关联科室或病区校验
        if (this.form.appltype == 3) {
          const hasDept = this.diseaseDept?.deptCode;
          const hasWard = this.diseaseWard?.districtCode;
          if (!hasDept && !hasWard) {
            this.$modal.msgError("当前疾病需关联科室或病区");
            this.submitLoading = false;
            return;
          }
        }
        // 3. ä»»åŠ¡å…³è”æ¡ä»¶æ ¡éªŒ
        const hasCondition =
          this.deptcodesWards[0] ||
          this.leavehospitaldistrictcodes[0] ||
          this.diagglist[0] ||
          this.operationcodes[0] ||
          this.form.longTask == 2 ||
          this.serviceType == 3
        ) {
        } else {
          this.serviceType == 3;
        if (!hasCondition) {
          this.$modal.msgError("请选择任务关联条件");
          this.submitLoading = false;
          return;
        }
        // if (!this.form.patTaskRelevances[0] && !this.form.longTask) {
        //   this.$modal.msgError("请选择病人");
        //   return;
        // }
        // 4. æ¨¡æ¿æ ¡éªŒ
        if (!this.form.templatename && !this.templateor) {
          this.$modal.msgError("未选择模板");
          this.submitLoading = false;
          return;
        }
        if (
        // 5. æ—¶é—´ä¿¡æ¯æ ¡éªŒ
        const isValidTime =
          (this.form.sendType == 1 && this.time1) ||
          this.form.sendType == 2
        ) {
        } else if (
          this.form.sendType == 2 ||
          (this.form.sendType == 3 && this.time4) ||
          this.form.longTask
        ) {
        } else {
          this.submitLoading = false;
          this.form.longTask;
          return this.$modal.msgError("时间信息缺失");
        if (!isValidTime) {
          this.submitLoading = false;
          this.$modal.msgError("时间信息缺失");
          return;
        }
        // ===== æ•°æ®å¤„理 =====
        // è¿‡æ»¤æ–‡æœ¬å‚æ•°
        const filteredArray = this.variableList.filter(
          (item) =>
            item.name !== "姓名" && item.name !== "电话" && item.name !== "地址"
        );
        this.form.textParam = this.convertFormat2ToFormat1(filteredArray);
        // è®¾ç½®æ“ä½œç±»åž‹
        if (this.form.taskid) {
          this.form.isoperation = 2;
        } else {
          this.form.isoperation = 1;
        }
        // è®¾ç½®ç±»åž‹
        if (!this.form.type) {
          this.form.type = this.$route.query.type;
        }
        // ç–¾ç—…关联的科室/病区
        if (this.form.appltype == 3) {
          if (this.diseaseDept) {
            this.form.deptcode = this.diseaseDept.deptCode;
@@ -1636,6 +1667,8 @@
            this.form.leavehospitaldistrictname = this.diseaseWard.districtName;
          }
        }
        // ç»„装提交数据
        this.form.serviceType = this.serviceType;
        this.form.deptcode = this.deptcodesWards.join(",");
        this.form.leavehospitaldistrictcode =
@@ -1647,24 +1680,39 @@
        this.form.icd10name = this.diagglist
          .map((item) => item.icdname)
          .join(",");
        Editsingletask(this.form).then((res) => {
          if (res.code == 200) {
            if (this.form.taskid) {
              this.$modal.msgSuccess("修改成功");
        // ===== æäº¤æŽ¥å£ =====
        Editsingletask(this.form)
          .then((res) => {
            if (res.code == 200) {
              // âœ… æˆåŠŸ
              if (this.form.taskid) {
                this.$modal.msgSuccess("修改成功");
              } else {
                this.$modal.msgSuccess("新增成功");
              }
              this.submitLoading = false;
              this.$router.push({
                path: "/followvisit/tasklist",
                query: { tasktopic: this.form.serviceType },
              });
            } else {
              this.$modal.msgSuccess("新增成功");
              // âœ… æŽ¥å£è¿”回错误码
              this.$modal.msgError(res.msg || "操作失败");
              this.submitLoading = false;
            }
          })
          .catch((error) => {
            // âœ… æ•获接口请求异常
            console.error("提交失败:", error);
            this.$modal.msgError(error.message || "网络异常,请稍后重试");
            this.submitLoading = false;
            this.$router.push({
              path: "/followvisit/tasklist",
              query: { tasktopic: this.form.serviceType },
            });
          }
        });
          });
      } catch (error) {
        // âœ… æ•获同步代码异常
        console.error("表单提交异常:", error);
        this.$modal.msgError(error.message || "表单提交异常");
        this.submitLoading = false;
      } finally {
        // ç¬¬å››æ­¥ï¼šæ— è®ºæˆåŠŸæˆ–å¤±è´¥ï¼Œæœ€ç»ˆéƒ½å…³é—­åŠ è½½çŠ¶æ€
      }
    },
    handleDiseaseDeptChange(dept) {
@@ -2041,6 +2089,16 @@
          let filteredArray = "";
          if (res.code == 200) {
            this.form = res.data;
            this.diseaseDept = {
              deptCode: this.form.deptcode,
              deptName: this.form.deptname,
            };
            this.diseaseWard = {
              districtCode: this.form.leavehospitaldistrictcode,
              districtName: this.form.leavehospitaldistrictname,
            };
            console.log(this.diseaseWard, this.diseaseDept);
            this.form.serviceType = this.serviceType;
            this.form.patTaskRelevances = this.form.patTaskRelevances
              ? this.form.patTaskRelevances
src/views/patient/questionnaire/index.vue
@@ -108,16 +108,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -220,7 +219,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -232,22 +231,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -296,7 +285,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -307,7 +296,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -402,6 +391,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -718,41 +755,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "出院服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "需随访",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      // è¡¨å•参数
@@ -887,13 +945,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -993,6 +1051,37 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
src/views/patient/shadow/index.vue
@@ -108,16 +108,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -220,7 +219,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -232,22 +231,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -296,7 +285,7 @@
        </el-table-column>
        <el-table-column
          label="出院日期"
          width="200"
          width="146"
          align="center"
          key="endtime"
          prop="endtime"
@@ -307,7 +296,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -402,6 +391,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -718,41 +755,62 @@
        },
      ],
      loading: false,
      cardlist: [
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          name: "出院服务总量",
          value: 0,
          value: null,
          label: "全部",
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "需随访",
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
     cardlist: [
        {
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        {
          name: "发送失败",
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        {
          name: "待随访",
          value: 0,
        },
        // {
        //   name: "已发送",
        //   value: 0,
        // },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
        {
          name: "已完成",
          value: 0,
        },
      ],
      // è¡¨å•参数
@@ -887,13 +945,13 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          this.cardlist[1].value = response.rows[0].ysf;
          this.cardlist[1].value = response.rows[0].wxsf || 0;
          this.ycvalue = response.rows[0].yc;
          this.cardlist[2].value = response.rows[0].fssb;
          this.cardlist[3].value = response.rows[0].dsf;
          // this.cardlist[4].value = response.rows[0].yfs2;
          this.cardlist[2].value = response.rows[0].xsf || 0;
          this.cardlist[3].value = response.rows[0].dsf || 0;
          this.cardlist[4].value = response.rows[0].ywc || 0;
          this.yfsvalue = response.rows[0].yfs;
        }
        this.loading = false;
@@ -993,6 +1051,37 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
src/views/patient/subsequent/index.vue
@@ -1,67 +1,11 @@
<template>
  <div class="app-container">
    <div class="leftvlue" style="margin-bottom: 20px">
      <el-row :gutter="10">
        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
          <el-card
            shadow="hover"
            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
          >
            <div style="padding: 8px" @click="$router.push(item.router)">
              <span>{{ item.name }}</span>
              <div
                style="
                  text-align: center;
                  font-size: 18px;
                  margin-top: 10px;
                  font-weight: 600;
                "
              >
              {{ item.value ? item.value : 0 }}
              </div>
            </div>
          </el-card>
        </el-col>
        <!-- <el-col :span="2.5">
          <div class="ysfleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>表单已发送</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ yfsvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col> -->
        <el-col :span="2.5">
          <div class="errleftvlue">
            <el-card shadow="hover">
              <div style="padding: 8px">
                <span>异常</span>
                <div
                  style="
                    text-align: center;
                    font-size: 18px;
                    margin-top: 10px;
                    font-weight: 600;
                  "
                >
                  {{ ycvalue }}
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
    <statistics-cards
      :cardlist="cardlist"
      :ycvalue="ycvalue"
      :jgvalue="jgvalue"
      :show-warning-condition="orgname == '省立同德翠苑院区'"
    />
    <el-row :gutter="20">
      <!--用户数据-->
      <el-form
@@ -108,16 +52,15 @@
          ></el-cascader>
        </el-form-item>
        <el-form-item label="服务状态" prop="status">
          <el-select v-model="topqueryParams.sendstateView" placeholder="请选择">
            <el-option
              v-for="item in topicoptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        <el-form-item label="随访状态" prop="status">
          <el-cascader
            v-model="serviceStatusValue"
            placeholder="请选择"
            :options="serviceStatusOptions"
            :props="cascaderProps"
            @change="handleServiceStatusChange"
            clearable
          ></el-cascader>
        </el-form-item>
        <el-form-item>
@@ -235,7 +178,7 @@
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
             <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
@@ -247,22 +190,12 @@
                >
              </div>
              <div v-if="scope.row.sendstateView == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >随访中</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >未完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 4">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstateView == 5">
                <el-tag type="danger" :disable-transitions="false"
              <div v-if="scope.row.sendstateView == 3">
                <el-tag type="warning" :disable-transitions="false"
                  >无需随访</el-tag
                >
              </div>
@@ -338,7 +271,7 @@
        >
        <el-table-column
          label="应随访日期"
          width="200"
          width="146"
          align="center"
          key="visitTime"
          prop="visitTime"
@@ -433,6 +366,54 @@
          prop="templatename"
          width="200"
        />
         <el-table-column
          label="任务状态"
          align="center"
          key="sendstate"
          prop="sendstate"
          width="120"
        >
          <template slot-scope="scope">
            <el-tooltip
              class="item"
              effect="dark"
              :content="scope.row.remark"
              placement="top-start"
            >
              <div v-if="scope.row.sendstate == 1">
                <el-tag type="primary" :disable-transitions="false"
                  >表单已领取</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 2">
                <el-tag type="primary" :disable-transitions="false"
                  >待随访</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 3">
                <el-tag type="success" :disable-transitions="false"
                  >表单已发送</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 4">
                <el-tag type="info" :disable-transitions="false">不执行</el-tag>
              </div>
              <div v-if="scope.row.sendstate == 5">
                <el-tag type="danger" :disable-transitions="false"
                  >发送失败</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 6">
                <el-tag type="success" :disable-transitions="false"
                  >已完成</el-tag
                >
              </div>
              <div v-if="scope.row.sendstate == 7">
                <el-tag type="danger" :disable-transitions="false">超时</el-tag>
              </div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column
          label="任务执行方式"
          align="center"
@@ -660,11 +641,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import StatisticsCards from "@/components/StatisticsCards";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect,StatisticsCards },
  data() {
    return {
      // é®ç½©å±‚
@@ -734,41 +716,62 @@
        },
      ],
      loading: false,
      serviceStatusValue: 10,
      cascaderProps: {
        expandTrigger: "hover", // æ‚¬åœå±•å¼€
        checkStrictly: true, // âœ… å…³é”®ï¼šå…è®¸é€‰ä¸­ä»»æ„ä¸€çº§
        emitPath: false, // âœ… åªè¿”回选中的值,不返回路径数组
      },
      // éšè®¿çŠ¶æ€çº§è”é€‰æ‹©å™¨
      serviceStatusOptions: [
        {
          value: null,
          label: "全部",
        },
        {
          value: 10, // ä¸€çº§ï¼šå¾…随访
          label: "待随访",
          children: [
            { value: 1, label: "被领取" },
            { value: 2, label: "待发送" },
            { value: 3, label: "已发送" },
            { value: 5, label: "发送失败" },
            { value: 7, label: "超时" },
          ],
        },
        {
          value: 20, // ä¸€çº§ï¼šå·²å®Œæˆ
          label: "已完成",
          children: [{ value: 6, label: "已完成" }],
        },
        {
          value: 30, // ä¸€çº§ï¼šæ— éœ€éšè®¿
          label: "无需随访",
          children: [{ value: 4, label: "不执行" }],
        },
      ],
      cardlist: [
        {
          name: "体检服务总量",
          name: "患者服务总量",
          value: 0,
        },
        // {
        //   name: "患者过滤",
        //   value: 0,
        // },
        {
          name: "无需随访",
          value: 0,
        },
        {
          name: "需随访",
          value: 0,
        },
        // {
        //   name: "异常",
        //   value: 0,
        // },
        // {
        //   name: "发送失败",
        //   value: 0,
        // },
        {
          name: "待随访",
          value: 0,
        },
        {
          name: "已随访",
          name: "已完成",
          value: 0,
        },
        // {
        //   name: "表单已发送",
        //   value: 0,
        // },
      ],
      // è¡¨å•参数
@@ -887,7 +890,7 @@
        this.total = response.total;
        if (refresh) {
          this.cardlist[0].value =
            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
            Number(response.rows[0].wxsf) + Number(response.rows[0].xsf) || 0;
          // this.cardlist[1].value = response.rows[0].wzx;
          // this.cardlist[2].value = response.rows[0].ysf;
          this.ycvalue = response.rows[0].yc;
@@ -987,13 +990,55 @@
      this.getList(refresh);
    },
    // éšè®¿çŠ¶æ€å˜æ›´å¤„ç†
    handleServiceStatusChange(value) {
      // æ¸…空选择
      if (value === null || value === undefined || value === "") {
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = null;
        return;
      }
      console.log(value, "value");
      // ä¸€çº§èŠ‚ç‚¹çš„å€¼ï¼ˆå¤§äºŽç­‰äºŽ10)
      if (value >= 10) {
        // é€‰ä¸­äº†ä¸€çº§
        switch (value) {
          case 10:
            this.topqueryParams.sendstateView = 1; // å¾…随访
            break;
          case 20:
            this.topqueryParams.sendstateView = 2; // å·²å®Œæˆ
            break;
          case 30:
            this.topqueryParams.sendstateView = 3; // æ— éœ€éšè®¿
            break;
        }
        this.topqueryParams.sendstate = null;
      } else {
        // é€‰ä¸­äº†äºŒçº§ï¼ˆå…·ä½“状态)
        this.topqueryParams.sendstateView = null;
        this.topqueryParams.sendstate = value;
      }
    },
    // æ‚£è€…范围处理
    handleChange(value) {
      let type = value[0];
      let code = value.slice(-1)[0];
      this.topqueryParams.leavehospitaldistrictcodes = [];
      this.topqueryParams.leaveldeptcodes = [];
      if (type == 1) {
        this.topqueryParams.leaveldeptcodes.push(code);
        this.topqueryParams.leavehospitaldistrictcodes = [];
        this.topqueryParams.searchscope = 1;
      } else if (type == 2) {
        this.topqueryParams.leavehospitaldistrictcodes.push(code);
        this.topqueryParams.leaveldeptcodes = [];
        this.topqueryParams.searchscope = 2;
      } else {
        this.topqueryParams.searchscope = 3;
      }
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
src/views/sfstatistics/percentage/components/DetailDialog.vue
@@ -18,7 +18,9 @@
          @input="handleSearch"
          @clear="handleSearch"
        />
        <span style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px">
        <span
          style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px"
        >
          å…± {{ displayList.length }} æ¡è®°å½•
        </span>
      </div>
@@ -26,12 +28,43 @@
      <div class="examine-jic">
        <div class="jic-value">
          <el-row :gutter="20">
            <div class="data-list" ref="dataList" @scroll="handleScroll" v-loading="loading">
              <el-table :data="currentDisplayList" height="660" style="width: 100%">
                <el-table-column prop="sendname" align="center" label="姓名" width="100" />
                <el-table-column prop="taskName" align="center" width="200" show-overflow-tooltip label="任务名称" />
            <div
              class="data-list"
              ref="dataList"
              @scroll="handleScroll"
              v-loading="loading"
            >
              <el-table
                :data="currentDisplayList"
                height="660"
                style="width: 100%"
              >
                <el-table-column
                  prop="sendname"
                  align="center"
                  label="姓名"
                  width="100"
                />
                <el-table-column
                  prop="telcode"
                  align="center"
                  label="联系电话"
                  width="100"
                />
                <el-table-column
                  prop="taskName"
                  align="center"
                  width="200"
                  show-overflow-tooltip
                  label="任务名称"
                />
                <el-table-column prop="sendstate" align="center" width="200" label="任务状态">
                <el-table-column
                  prop="sendstate"
                  align="center"
                  width="200"
                  label="任务状态"
                >
                  <template slot-scope="scope">
                    <el-tag
                      :type="getStateTagType(scope.row.sendstate)"
@@ -51,8 +84,14 @@
                  :show-overflow-tooltip="true"
                >
                  <template slot-scope="scope">
                    <span v-for="(item, index) in scope.row.preachform" :key="index">
                      {{ item }}{{ index < scope.row.preachform.length - 1 ? '、' : '' }}
                    <span
                      v-for="(item, index) in scope.row.preachform"
                      :key="index"
                    >
                      {{ item
                      }}{{
                        index < scope.row.preachform.length - 1 ? "、" : ""
                      }}
                    </span>
                  </template>
                </el-table-column>
@@ -71,35 +110,98 @@
                  width="200"
                  show-overflow-tooltip
                />
                <el-table-column label="出院日期" width="200" align="center" key="endtime" prop="endtime">
                <el-table-column
                  label="出院日期"
                  width="200"
                  align="center"
                  key="endtime"
                  prop="endtime"
                >
                  <template slot-scope="scope">
                    <span>{{ formatTime(scope.row.endtime) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="责任护士" width="120" align="center" key="nurseName" prop="nurseName" />
                <el-table-column label="主治医生" width="120" align="center" key="drname" prop="drname" />
                <el-table-column
                  label="责任护士"
                  width="120"
                  align="center"
                  key="nurseName"
                  prop="nurseName"
                />
                <el-table-column
                  label="主治医生"
                  width="120"
                  align="center"
                  key="drname"
                  prop="drname"
                />
                <el-table-column label="结果状态" align="center" key="excep" prop="excep" width="120">
                <el-table-column
                  label="结果状态"
                  align="center"
                  key="excep"
                  prop="excep"
                  width="120"
                >
                  <template slot-scope="scope">
                    <dict-tag :options="dict.type.sys_yujing" :value="scope.row.excep" />
                    <dict-tag
                      :options="dict.type.sys_yujing"
                      :value="scope.row.excep"
                    />
                  </template>
                </el-table-column>
                <el-table-column label="处理意见" align="center" key="suggest" prop="suggest" width="120">
                <el-table-column
                  label="处理意见"
                  align="center"
                  key="suggest"
                  prop="suggest"
                  width="120"
                >
                  <template slot-scope="scope">
                    <dict-tag :options="dict.type.sys_suggest" :value="scope.row.suggest" />
                    <dict-tag
                      :options="dict.type.sys_suggest"
                      :value="scope.row.suggest"
                    />
                  </template>
                </el-table-column>
                <el-table-column prop="templatename" align="center" label="服务模板" width="200" show-overflow-tooltip />
                <el-table-column prop="remark" align="center" label="服务记录" width="200" show-overflow-tooltip />
                <el-table-column
                  prop="templatename"
                  align="center"
                  label="服务模板"
                  width="200"
                  show-overflow-tooltip
                />
                <el-table-column
                  prop="remark"
                  align="center"
                  label="服务记录"
                  width="200"
                  show-overflow-tooltip
                />
                <el-table-column prop="bankcardno" align="center" label="呼叫状态" width="210" />
                <el-table-column
                  prop="bankcardno"
                  align="center"
                  label="呼叫状态"
                  width="210"
                />
                <el-table-column label="操作" fixed="right" align="center" width="200" class-name="small-padding fixed-width">
                <el-table-column
                  label="操作"
                  fixed="right"
                  align="center"
                  width="200"
                  class-name="small-padding fixed-width"
                >
                  <template slot-scope="scope">
                    <el-button size="medium" type="text" @click="handleDetailsGo(scope.row)">
                    <el-button
                      size="medium"
                      type="text"
                      @click="handleDetailsGo(scope.row)"
                    >
                      <span class="button-zx">
                        <i class="el-icon-s-order"></i>查看
                      </span>
@@ -117,175 +219,181 @@
<script>
export default {
  name: 'DetailDialog',
  dicts: ['sys_yujing', 'sys_suggest'],
  name: "DetailDialog",
  dicts: ["sys_yujing", "sys_suggest"],
  props: {
    visible: {
      type: Boolean,
      default: false
      default: false,
    },
    title: {
      type: String,
      default: ''
      default: "",
    },
    data: {
      type: Array,
      default: () => []
      default: () => [],
    },
    searchName: {
      type: String,
      default: ''
      default: "",
    },
    loading: {
      type: Boolean,
      default: false
    }
      default: false,
    },
  },
  data() {
    return {
      localSearchName: '',
      localSearchName: "",
      displayList: [],
      currentDisplayList: [],
      loadIndex: 0,
      pageSize: 100,
      isLoading: false
    }
      isLoading: false,
    };
  },
  watch: {
    data: {
      immediate: true,
      handler(newData) {
        this.initializeData(newData)
      }
        this.initializeData(newData);
      },
    },
    searchName(newVal) {
      this.localSearchName = newVal
      this.handleSearch()
    }
      this.localSearchName = newVal;
      this.handleSearch();
    },
  },
  mounted() {
    if (this.data && this.data.length > 0) {
      this.initializeData(this.data)
      this.initializeData(this.data);
    }
  },
  methods: {
    initializeData(data) {
      this.displayList = [...data]
      this.formatPreachformData()
      this.loadIndex = 0
      this.currentDisplayList = []
      this.displayList = [...data];
      this.formatPreachformData();
      this.loadIndex = 0;
      this.currentDisplayList = [];
      this.$nextTick(() => {
        this.loadMoreData()
      })
        this.loadMoreData();
      });
    },
    formatPreachformData() {
      this.displayList.forEach((item) => {
        if (item.preachform) {
          if (item.endtime) {
            item.preachformson = item.preachform
            const idArray = item.preachform.split(',')
            item.preachformson = item.preachform;
            const idArray = item.preachform.split(",");
            item.preachform = idArray.map((value) => {
              const checkboxlist = this.$store.getters.checkboxlist
              const foundItem = checkboxlist.find((item) => item.value == value)
              return foundItem ? foundItem.label : null
            }).filter(label => label !== null)
            item.preachform = idArray
              .map((value) => {
                const checkboxlist = this.$store.getters.checkboxlist;
                const foundItem = checkboxlist.find(
                  (item) => item.value == value
                );
                return foundItem ? foundItem.label : null;
              })
              .filter((label) => label !== null);
          }
        }
      })
      });
    },
    handleSearch() {
      if (!this.localSearchName.trim()) {
        this.displayList = [...this.data]
        this.formatPreachformData()
        this.displayList = [...this.data];
        this.formatPreachformData();
      } else {
        const keyword = this.localSearchName.toLowerCase()
        const keyword = this.localSearchName.toLowerCase();
        this.displayList = this.data.filter((item) => {
          return item.sendname && item.sendname.toLowerCase().includes(keyword)
        })
        this.formatPreachformData()
          return item.sendname && item.sendname.toLowerCase().includes(keyword);
        });
        this.formatPreachformData();
      }
      this.loadIndex = 0
      this.currentDisplayList = []
      this.loadIndex = 0;
      this.currentDisplayList = [];
      this.$nextTick(() => {
        this.loadMoreData()
      })
        this.loadMoreData();
      });
      this.$emit('search', this.localSearchName)
      this.$emit("search", this.localSearchName);
    },
    loadMoreData() {
      if (this.isLoading || this.loadIndex >= this.displayList.length) return
      if (this.isLoading || this.loadIndex >= this.displayList.length) return;
      this.isLoading = true
      this.isLoading = true;
      setTimeout(() => {
        const nextChunk = this.displayList.slice(
          this.loadIndex,
          this.loadIndex + this.pageSize
        )
        this.currentDisplayList = this.currentDisplayList.concat(nextChunk)
        this.loadIndex += this.pageSize
        this.isLoading = false
      }, 200)
        );
        this.currentDisplayList = this.currentDisplayList.concat(nextChunk);
        this.loadIndex += this.pageSize;
        this.isLoading = false;
      }, 200);
    },
    handleScroll(event) {
      const scrollContainer = event.target
      const scrollContainer = event.target;
      const isAtBottom =
        scrollContainer.scrollTop + scrollContainer.clientHeight >=
        scrollContainer.scrollHeight - 10
        scrollContainer.scrollHeight - 10;
      if (
        isAtBottom &&
        !this.isLoading &&
        this.loadIndex < this.displayList.length
      ) {
        this.loadMoreData()
        this.loadMoreData();
      }
    },
    getStateTagType(state) {
      const stateMap = {
        1: 'primary',  // è¡¨å•已领取
        2: 'primary',  // å¾…随访
        3: 'success',  // è¡¨å•已发送
        4: 'info',     // ä¸æ‰§è¡Œ
        5: 'danger',   // å‘送失败
        6: 'success'   // å·²å®Œæˆ
      }
      return stateMap[state] || 'info'
        1: "primary", // è¡¨å•已领取
        2: "primary", // å¾…随访
        3: "success", // è¡¨å•已发送
        4: "info", // ä¸æ‰§è¡Œ
        5: "danger", // å‘送失败
        6: "success", // å·²å®Œæˆ
        7: "danger", // è¶…æ—¶
      };
      return stateMap[state] || "info";
    },
    getStateText(state) {
      const stateTextMap = {
        1: '表单已领取',
        2: '待随访',
        3: '表单已发送',
        4: '不执行',
        5: '发送失败',
        6: '已完成'
      }
      return stateTextMap[state] || '未知状态'
        1: "表单已领取",
        2: "待随访",
        3: "表单已发送",
        4: "不执行",
        5: "发送失败",
        6: "已完成",
        7: "超时",
      };
      return stateTextMap[state] || "未知状态";
    },
    formatTime(time) {
      if (!time) return ''
      return this.parseTime(time)
      if (!time) return "";
      return this.parseTime(time);
    },
    handleDetailsGo(row) {
      this.$emit('details-go', row)
      this.$emit("details-go", row);
    },
    handleClose() {
      this.$emit('close')
    }
  }
}
      this.$emit("close");
    },
  },
};
</script>
<style lang="scss" scoped>
src/views/system/ruleconfig/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,656 @@
<template>
  <div class="app-container">
    <!-- å¤´éƒ¨ï¼šæ ‡é¢˜å’Œæ“ä½œæŒ‰é’® -->
    <div class="header-container">
      <div class="header-left">
        <div class="title">规则配置管理</div>
        <div class="tips">配置科室和病区的执行优先级规则</div>
      </div>
      <div class="header-right">
        <el-button type="primary" icon="el-icon-plus" @click="openAddDialog">
          æ–°å¢žè§„则
        </el-button>
      </div>
    </div>
    <!-- æœç´¢åŒºåŸŸ -->
    <el-card class="filter-container" shadow="never">
      <div class="filter-title">查询条件</div>
      <el-form :model="searchForm" :inline="true" class="filter-form">
        <el-form-item label="科室名称">
          <el-input
            v-model="searchForm.deptname"
            placeholder="请输入科室名称"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleSearch"
          />
        </el-form-item>
        <el-form-item label="病区名称">
          <el-input
            v-model="searchForm.wardname"
            placeholder="请输入病区名称"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleSearch"
          />
        </el-form-item>
        <el-form-item label="科室规则">
          <el-select
            v-model="searchForm.deptRule"
            placeholder="请选择"
            clearable
            style="width: 120px"
          >
            <el-option label="首先执行" value="1" />
            <el-option label="次要执行" value="2" />
          </el-select>
        </el-form-item>
        <el-form-item label="病区规则">
          <el-select
            v-model="searchForm.wradRule"
            placeholder="请选择"
            clearable
            style="width: 120px"
          >
            <el-option label="首先执行" value="1" />
            <el-option label="次要执行" value="2" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="handleSearch"
            >查询</el-button
          >
          <el-button icon="el-icon-refresh" @click="resetSearch"
            >重置</el-button
          >
        </el-form-item>
      </el-form>
    </el-card>
    <!-- è§„则列表表格 -->
    <el-card class="table-container" shadow="never">
      <el-table
        v-loading="loading"
        :data="tableData"
        style="width: 100%"
        stripe
        :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
      >
        <el-table-column
          prop="deptname"
          label="科室"
          min-width="120"
          align="center"
        />
        <el-table-column
          prop="wardname"
          label="病区"
          min-width="120"
          align="center"
        />
        <el-table-column label="科室优先级" min-width="100" align="center">
          <template slot-scope="{ row }">
            <el-tag
              :type="row.deptRule === '1' ? 'success' : 'warning'"
              size="small"
            >
              {{ row.deptRule === "1" ? "首先执行" : "次要执行" }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="病区优先级" min-width="100" align="center">
          <template slot-scope="{ row }">
            <el-tag
              :type="row.wradRule === '1' ? 'success' : 'warning'"
              size="small"
            >
              {{ row.wradRule === "1" ? "首先执行" : "次要执行" }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="疾病优先级" min-width="100" align="center">
          <template slot-scope="{ row }">
            <el-tag
              :type="row.diagRule === '1' ? 'success' : 'warning'"
              size="small"
            >
              {{ row.diagRule === "1" ? "首先执行" : "次要执行" }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          prop="createTime"
          label="创建时间"
          min-width="150"
          align="center"
        />
        <el-table-column label="操作" width="180" fixed="right" align="center">
          <template slot-scope="{ row }">
            <el-button
              type="text"
              size="mini"
              icon="el-icon-edit"
              @click="openEditDialog(row)"
              class="action-btn"
            >
              ç¼–辑
            </el-button>
            <el-button
              type="text"
              size="mini"
              icon="el-icon-delete"
              @click="handleDelete(row)"
              style="color: #f56c6c"
              class="action-btn"
            >
              åˆ é™¤
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="searchForm.pageNum"
        :limit.sync="searchForm.pageSize"
        @pagination="getList"
        style="margin-top: 20px"
      />
    </el-card>
    <!-- æ·»åŠ /编辑对话框 -->
    <el-dialog
      :title="dialogTitle"
      :visible.sync="dialogVisible"
      width="500px"
      :close-on-click-modal="false"
      @close="resetDialog"
    >
      <el-form
        ref="ruleFormRef"
        :model="ruleForm"
        :rules="rules"
        label-width="100px"
        class="rule-form"
      >
        <el-form-item label="科室" prop="deptcode">
          <el-select
            v-model="ruleForm.deptcode"
            placeholder="请选择科室"
            filterable
            clearable
            style="width: 100%"
            @change="handleDeptChange"
          >
            <el-option
              v-for="dept in departmentOptions"
              :key="dept.value"
              :label="dept.label"
              :value="dept.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="病区" prop="wardcode">
          <el-select
            v-model="ruleForm.wardcode"
            placeholder="请选择病区"
            filterable
            clearable
            style="width: 100%"
            @change="handleDeptChangebq"
          >
            <el-option
              v-for="ward in wardOptions"
              :key="ward.value"
              :label="ward.label"
              :value="ward.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="科室优先级" prop="deptRule">
          <el-radio-group v-model="ruleForm.deptRule">
            <el-radio label="1">首先执行</el-radio>
            <el-radio label="2">次要执行</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="病区优先级" prop="wradRule">
          <el-radio-group v-model="ruleForm.wradRule">
            <el-radio label="1">首先执行</el-radio>
            <el-radio label="2">次要执行</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="疾病优先级" prop="diagRule">
          <el-radio-group v-model="ruleForm.diagRule">
            <el-radio label="1">首先执行</el-radio>
            <el-radio label="2">次要执行</el-radio>
          </el-radio-group>
        </el-form-item>
        <div class="form-tips">
          <i class="el-icon-info"></i>
          æç¤ºï¼šç§‘室和病区至少需要选择一个
        </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 æ¶ˆ</el-button>
        <el-button type="primary" @click="handleSubmit" :loading="submitting"
          >ç¡® å®š</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>
<script>
import {
  taskrulelist,
  addtaskrule,
  edittaskrule,
  deltaskrule,
} from "@/api/AiCentre/index";
export default {
  name: "RuleConfig",
  data() {
    // éªŒè¯ç§‘室和病区至少选一个
    const validateDeptOrWard = (rule, value, callback) => {
      if (!this.ruleForm.deptcode && !this.ruleForm.wardcode) {
        callback(new Error("科室和病区至少需要选择一个"));
      } else {
        callback();
      }
    };
    return {
      // æœç´¢è¡¨å•
      searchForm: {
        pageNum: 1,
        pageSize: 10,
        deptname: "",
        wardname: "",
        deptRule: "",
        wradRule: "",
      },
      // è¡¨æ ¼æ•°æ®
      tableData: [],
      total: 0,
      loading: false,
      // å¯¹è¯æ¡†ç›¸å…³
      dialogVisible: false,
      dialogTitle: "",
      submitting: false,
      isEdit: false,
      currentId: null,
      // è¡¨å•数据
      ruleForm: {
        deptcode: "",
        deptname: "",
        wardcode: "",
        wardname: "",
        deptRule: "1",
        wradRule: "1",
        diagRule: "1",
      },
      // éªŒè¯è§„则
      rules: {
        deptRule: [
          { required: true, message: "请选择科室优先级", trigger: "change" },
        ],
        wradRule: [
          { required: true, message: "请选择病区优先级", trigger: "change" },
        ],
        diagRule: [
          { required: true, message: "请选择疾病优先级", trigger: "change" },
        ],
        deptcode: [{ validator: validateDeptOrWard, trigger: "change" }],
        wardcode: [{ validator: validateDeptOrWard, trigger: "change" }],
      },
      // é€‰é¡¹æ•°æ®
      departmentOptions: [],
      wardOptions: [],
    };
  },
  computed: {
    // ç§‘室选项
    computedDepartmentOptions() {
      if (this.$store.getters.belongDepts) {
        return this.$store.getters.belongDepts.map((dept) => ({
          label: dept.deptName,
          value: dept.deptCode,
        }));
      }
      return [];
    },
  },
  created() {
    this.getList();
    this.departmentOptions = this.computedDepartmentOptions;
    this.fetchWardOptions();
  },
  methods: {
    // èŽ·å–è§„åˆ™åˆ—è¡¨
    getList() {
      this.loading = true;
      taskrulelist(this.searchForm)
        .then((response) => {
          if (response.code === 200) {
            this.tableData = response.rows;
            this.total = response.total;
          } else {
            this.$message.error(response.msg || "获取列表失败");
          }
        })
        .catch((error) => {
          console.error("获取规则列表失败:", error);
          this.$message.error("获取规则列表失败");
        })
        .finally(() => {
          this.loading = false;
        });
    },
    // èŽ·å–ç—…åŒºæ•°æ®
    fetchWardOptions() {
      // TODO: è°ƒç”¨èŽ·å–ç—…åŒºåˆ—è¡¨çš„æŽ¥å£
      // getWardList().then(response => {
      //   this.wardOptions = response.data.map(ward => ({
      //     label: ward.wardName,
      //     value: ward.wardCode
      //   }));
      // }).catch(error => {
      //   console.error('获取病区列表失败:', error);
      // });
      // ä¸´æ—¶æ•°æ®
      this.wardOptions = [
        { label: "心血管内科一病区", value: "W001" },
        { label: "心血管内科二病区", value: "W002" },
        { label: "呼吸内科病区", value: "W003" },
        { label: "神经内科病区", value: "W004" },
      ];
    },
    // ç§‘室变化处理
    handleDeptChange(value) {
      const selectedDept = this.departmentOptions.find(
        (dept) => dept.value === value
      );
      if (selectedDept) {
        this.ruleForm.deptname = selectedDept.label;
      } else {
        this.ruleForm.deptname = "";
      }
    },
    handleDeptChangebq(value) {
      const selectedDept = this.wardOptions.find(
        (dept) => dept.value === value
      );
      if (selectedDept) {
        this.ruleForm.wardname = selectedDept.label;
      } else {
        this.ruleForm.wardname = "";
      }
    },
    // æœç´¢
    handleSearch() {
      this.searchForm.pageNum = 1;
      this.getList();
    },
    // é‡ç½®æœç´¢
    resetSearch() {
      this.searchForm = {
        pageNum: 1,
        pageSize: 10,
        deptname: "",
        wardname: "",
        deptRule: "",
        wradRule: "",
      };
      this.getList();
    },
    // æ‰“开新增对话框
    openAddDialog() {
      this.dialogTitle = "新增规则";
      this.isEdit = false;
      this.currentId = null;
      this.dialogVisible = true;
    },
    // æ‰“开编辑对话框
    openEditDialog(row) {
      this.dialogTitle = "编辑规则";
      this.isEdit = true;
      this.currentId = row.id;
      // å¡«å……表单数据
      this.ruleForm = {
        deptcode: row.deptcode || "",
        deptname: row.deptname || "",
        wardcode: row.wardcode || "",
        wardname: row.wardname || "",
        deptRule: row.deptRule || "1",
        wradRule: row.wradRule || "1",
        diagRule: row.diagRule || "1",
      };
      this.dialogVisible = true;
    },
    // é‡ç½®å¯¹è¯æ¡†
    resetDialog() {
      this.$refs.ruleFormRef && this.$refs.ruleFormRef.resetFields();
      this.ruleForm = {
        deptcode: "",
        deptname: "",
        wardcode: "",
        wardname: "",
        deptRule: "1",
        wradRule: "1",
        diagRule: "1",
      };
      this.currentId = null;
      this.submitting = false;
    },
    // æäº¤è¡¨å•
    handleSubmit() {
      this.$refs.ruleFormRef.validate((valid) => {
        if (valid) {
          this.submitting = true;
          const formData = { ...this.ruleForm };
          if (this.isEdit) {
            formData.id = this.currentId;
          }
          const api = this.isEdit ? edittaskrule : addtaskrule;
          api(formData)
            .then((response) => {
              if (response.code === 200) {
                this.$message.success(this.isEdit ? "编辑成功" : "新增成功");
                this.dialogVisible = false;
                this.getList();
              } else {
                this.$message.error(
                  response.msg || (this.isEdit ? "编辑失败" : "新增失败")
                );
              }
            })
            .catch((error) => {
              console.error("提交失败:", error);
              this.$message.error("提交失败,请稍后重试");
            })
            .finally(() => {
              this.submitting = false;
            });
        }
      });
    },
    // åˆ é™¤è§„则
    handleDelete(row) {
      this.$confirm(
        `确定要删除规则"${row.deptname || row.wardname}"吗?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(() => {
          return deltaskrule({ id: row.id });
        })
        .then((response) => {
          if (response.code === 200) {
            this.$message.success("删除成功");
            this.getList();
          } else {
            this.$message.error(response.msg || "删除失败");
          }
        })
        .catch((error) => {
          if (error !== "cancel") {
            console.error("删除失败:", error);
            this.$message.error("删除失败");
          }
        });
    },
  },
};
</script>
<style scoped>
.app-container {
  padding: 20px;
  background-color: #f0f2f5;
  min-height: calc(100vh - 84px);
}
.header-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 16px 20px;
  background: white;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.header-left {
  display: flex;
  flex-direction: column;
}
.header-left .title {
  font-size: 20px;
  font-weight: 500;
  color: #303133;
  margin-bottom: 6px;
}
.header-left .tips {
  font-size: 13px;
  color: #909399;
}
.filter-container {
  margin-bottom: 20px;
  border-radius: 4px;
}
.filter-title {
  font-size: 15px;
  font-weight: 500;
  color: #303133;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid #ebeef5;
}
.filter-form {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 0;
}
.filter-form .el-form-item {
  margin-bottom: 0;
  margin-right: 20px;
}
.table-container {
  border-radius: 4px;
  margin-bottom: 20px;
}
.action-btn {
  padding: 5px 8px;
  font-size: 12px;
}
.rule-form {
  padding-right: 20px;
}
.form-tips {
  background-color: #f0f9ff;
  border: 1px solid #c6e2ff;
  border-radius: 4px;
  padding: 10px 15px;
  margin-left: 100px;
  color: #409eff;
  font-size: 12px;
  line-height: 1.5;
}
.form-tips i {
  margin-right: 5px;
}
.dialog-footer {
  text-align: right;
  padding-top: 20px;
  border-top: 1px solid #ebeef5;
}
/* å“åº”式调整 */
@media (max-width: 768px) {
  .header-container {
    flex-direction: column;
    align-items: flex-start;
  }
  .header-right {
    margin-top: 10px;
  }
  .filter-form .el-form-item {
    width: 100%;
    margin-right: 0;
  }
  .filter-form .el-form-item .el-input,
  .filter-form .el-form-item .el-select {
    width: 100%;
  }
}
</style>
Ëæ·ÃͨÓã¨Ðèͬ²½×îÐÂ״̬£©.zip
Binary files differ