WXL (wul)
5 天以前 5319d5b95497b5b546947ac340c14c71e5b54ca6
测试完成
已修改8个文件
已添加5个文件
5647 ■■■■■ 文件已修改
dist (2).zip 补丁 | 查看 | 原始文档 | blame | 历史
package.json 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/discharge/index.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/knowledge/Medication/index.vue 901 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/knowledge/article/index.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/SignAcontract/Review.vue 827 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/SignAcontract/index.vue 512 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/index.vue 362 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/profile/index.vue 987 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/physical/index.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/group/index.vue 1473 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wx.zip 补丁 | 查看 | 原始文档 | blame | 历史
dist (2).zip
Binary files differ
package.json
@@ -42,7 +42,7 @@
    "@vue/babel-plugin-jsx": "^1.1.5",
    "@vue/composition-api": "^1.0.0-rc.6",
    "axios": "0.24.0",
    "clipboard": "2.0.8",
    "clipboard": "^2.0.11",
    "codemirror": "^5.65.13",
    "core-js": "^3.25.3",
    "cos-js-sdk-v5": "^1.4.18",
@@ -61,6 +61,7 @@
    "lemon-imui": "^1.7.7",
    "moment": "^2.30.1",
    "nprogress": "0.2.0",
    "qrcode": "^1.5.4",
    "quill": "1.3.7",
    "quill-image-drop-module": "^1.0.3",
    "quill-image-resize": "^3.0.9",
@@ -78,6 +79,7 @@
    "vue-count-to": "1.0.13",
    "vue-cropper": "0.5.5",
    "vue-meta": "2.4.0",
    "vue-qr": "^4.0.9",
    "vue-quill-editor": "^3.0.6",
    "vue-router": "3.4.9",
    "vue-sweetalert2": "^5.0.11",
src/views/followvisit/discharge/index.vue
@@ -121,13 +121,13 @@
          </el-select>
        </el-form-item>
        <el-form-item label="患者标签" prop="tagname">
                <el-input
                  v-model="topqueryParams.tagname"
                  placeholder="输入进行模糊查询"
                  maxlength="30"
                  @keyup.enter.native="handleQuery"
                />
              </el-form-item>
          <el-input
            v-model="topqueryParams.tagname"
            placeholder="输入进行模糊查询"
            maxlength="30"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item>
          <el-button
@@ -303,13 +303,13 @@
          </template>
        </el-table-column>
        <el-table-column
            label="标签"
            align="center"
            key="tagname"
            prop="tagname"
            show-overflow-tooltip
            width="180"
          />
          label="标签"
          align="center"
          key="tagname"
          prop="tagname"
          show-overflow-tooltip
          width="180"
        />
        <el-table-column
          label="随访人员"
          align="center"
@@ -532,6 +532,11 @@
                ><i class="el-icon-s-order"></i>查看详情</span
              ></el-button
            >
            <el-button size="medium" type="text" @click="outPathQr(scope.row)"
              ><span class="button-qr"
                ><i class="el-icon-view"></i>二维码</span
              ></el-button
            >
          </template>
        </el-table-column>
      </el-table>
@@ -673,6 +678,55 @@
        >
      </span>
    </el-dialog>
    <!-- äºŒç»´ç  -->
    <el-dialog
    :title="qrDialog.title"
    :visible.sync="qrDialog.visible"
    width="400px"
    center
    @close="handleQrClose"
  >
    <div class="qrcode-container">
      <!-- åŠ è½½çŠ¶æ€ -->
      <div v-if="qrLoading" class="qrcode-loading">
        <i class="el-icon-loading"></i>
        <span>二维码生成中...</span>
      </div>
      <!-- æœ‰æœ‰æ•ˆæ•°æ®æ—¶æ˜¾ç¤ºäºŒç»´ç  -->
      <div v-else-if="safeQrUrl" class="qrcode-content">
        <vue-qr
          :text="safeQrUrl"
          :size="280"
          :margin="10"
          :logoSrc="qrDialog.logo"
          :logoScale="0.2"
          colorDark="#191a23"
          colorLight="#ffffff"
        ></vue-qr>
        <div class="qrcode-info">
          <p><strong>患者姓名:</strong>{{ qrDialog.patientName }}</p>
          <p><strong>任务名称:</strong>{{ qrDialog.taskName }}</p>
        </div>
        <div class="qrcode-actions">
          <el-button type="primary" size="small" @click="downloadQrCode">
            <i class="el-icon-download"></i> ä¸‹è½½äºŒç»´ç 
          </el-button>
          <el-button type="success" size="small" @click="copyQrUrl">
            <i class="el-icon-document-copy"></i> å¤åˆ¶é“¾æŽ¥
          </el-button>
        </div>
      </div>
      <!-- æ— æ•°æ®æç¤º -->
      <div v-else class="qrcode-empty">
        <i class="el-icon-warning"></i>
        <span>暂无有效的二维码链接</span>
      </div>
    </div>
  </el-dialog>
  </div>
</template>
@@ -690,11 +744,12 @@
import Treeselect from "@riophae/vue-treeselect";
import store from "@/store";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import VueQr from "vue-qr";
import Clipboard from "clipboard";
export default {
  name: "Discharge",
  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
  components: { Treeselect },
  components: { Treeselect, VueQr },
  data() {
    return {
      // é®ç½©å±‚
@@ -717,6 +772,7 @@
      addalteropen: false,
      // ä¿®æ”¹å‘送时间对话框
      modificationVisible: false,
      resetQrurl: "",
      // éƒ¨é—¨åç§°
      deptName: undefined,
      // é»˜è®¤å¯†ç 
@@ -746,7 +802,15 @@
      },
      value: [],
      list: [],
      qrDialog: {
        visible: false,
        title: "随访二维码",
        url: "",
        patientName: "",
        taskName: "",
        logo: require("@/assets/logo/logoxh.png"), // å¯é€‰çš„Logo,请确保路径正确
      },
      qrLoading: false,
      sourcetype: [
        {
          value: 1,
@@ -888,8 +952,13 @@
    });
    if (store.getters.belongWards.length) {
      this.topqueryParams.leavehospitaldistrictcodes=[store.getters.belongWards[0].districtCode]
      this.topqueryParams.scopetype=[2,store.getters.belongWards[0].districtCode]
      this.topqueryParams.leavehospitaldistrictcodes = [
        store.getters.belongWards[0].districtCode,
      ];
      this.topqueryParams.scopetype = [
        2,
        store.getters.belongWards[0].districtCode,
      ];
    }
    if (this.errtype) {
      this.toleadExport(2);
@@ -902,6 +971,13 @@
  },
  activated() {
    this.getList(1);
  },
  computed: {
    safeQrUrl() {
      return this.qrDialog.url && this.qrDialog.url !== 'undefined'
        ? this.qrDialog.url.toString()
        : ''
    }
  },
  methods: {
    /** æŸ¥è¯¢é—¨è¯Šéšè®¿æœåŠ¡åˆ—è¡¨ */
@@ -987,7 +1063,8 @@
      let obj = {
        pageNum: 1,
        pageSize: 10,
        leavehospitaldistrictcodes: this.topqueryParams.leavehospitaldistrictcodes,
        leavehospitaldistrictcodes:
          this.topqueryParams.leavehospitaldistrictcodes,
        sendstates: [2, 3],
        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
      };
@@ -1293,6 +1370,122 @@
      }
      this.handleQuery();
    },
    // æ˜¾ç¤ºäºŒç»´ç å¼¹æ¡†
    outPathQr(row) {
      console.log(row);
      if (!row || !row.outPath || row.outPath === 'undefined') {
        this.$message.warning('该记录暂无有效的二维码链接')
        return
      }
      this.qrLoading = true
      this.qrDialog = {
        visible: true,
        title: `${row.sendname || '患者'}的随访二维码`,
        url: row.outPath,
        patientName: row.sendname || '未知',
        taskName: row.taskName || '未知任务',
        logo: require("@/assets/logo/logoxh.png"),
      };
      // ç¡®ä¿ç»„件有足够时间渲染
      this.$nextTick(() => {
        this.qrLoading = false
      })
    },
    // äºŒç»´ç ç”Ÿæˆå›žè°ƒ
    qrCodeCallback(dataUrl, id) {
      console.log("二维码生成成功:", id);
      // è¿™é‡Œå¯ä»¥ä¿å­˜dataUrl用于后续操作
    },
    // ä¸‹è½½äºŒç»´ç 
    downloadQrCode() {
      try {
        const qrComponent = this.$refs.vueQr;
        // èŽ·å–äºŒç»´ç å›¾ç‰‡çš„URL
        const qrImageUrl = qrComponent.$el.src;
        const downloadLink = document.createElement("a");
        downloadLink.href = qrImageUrl;
        downloadLink.download = `随访二维码_${
          this.qrDialog.patientName
        }_${new Date().getTime()}.png`;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        this.$message.success("二维码下载成功");
      } catch (error) {
        console.error("下载失败:", error);
        this.$message.error("下载失败,请重试");
      }
    },
    // å¤åˆ¶é“¾æŽ¥
    copyQrUrl() {
      if (!this.qrDialog.url) {
        this.$message.warning("无有效链接可复制");
        return;
      }
      // æ–¹æ³•1: ä½¿ç”¨clipboard库(如果安装了)
      // this.copyWithClipboard()
      // æ–¹æ³•2: ä½¿ç”¨çŽ°ä»£æµè§ˆå™¨çš„Clipboard API
      this.copyWithModernAPI();
    },
    // ä½¿ç”¨çް代Clipboard API复制
    async copyWithModernAPI() {
      try {
        await navigator.clipboard.writeText(this.qrDialog.url);
        this.$message.success("链接已复制到剪贴板");
      } catch (error) {
        // é™çº§æ–¹æ¡ˆ
        this.copyWithFallback();
      }
    },
    // å…¼å®¹æ€§é™çº§æ–¹æ¡ˆ
    copyWithFallback() {
      const textArea = document.createElement("textarea");
      textArea.value = this.qrDialog.url;
      textArea.style.position = "fixed";
      textArea.style.left = "-999999px";
      textArea.style.top = "-999999px";
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      try {
        document.execCommand("copy");
        this.$message.success("链接已复制到剪贴板");
      } catch (error) {
        this.$message.warning("浏览器不支持自动复制,请手动复制链接");
      } finally {
        document.body.removeChild(textArea);
      }
    },
    // å…³é—­äºŒç»´ç å¼¹æ¡†
    handleQrClose() {
      this.qrDialog.visible = false;
            this.qrLoading = false
      // é‡ç½®æ•°æ®
      setTimeout(() => {
        this.qrDialog = {
          visible: false,
          title: "随访二维码",
          url: "",
          patientName: "",
          taskName: "",
          logo: require("@/assets/logo/logoxh.png"),
        };
      }, 300);
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.topqueryParams.pageNum = null;
@@ -1457,6 +1650,12 @@
  border-radius: 1px;
  color: #ffffff;
}
.button-qr {
  background: #6c14a2;
  padding: 5px;
  border-radius: 1px;
  color: #ffffff;
}
::v-deep.el-radio-group {
  span {
@@ -1464,10 +1663,49 @@
  }
}
// é€‰é¡¹å­—体放大
// ::v-deep.el-checkbox-group {
//   span {
//     font-size: 24px;
//   }
// }
/* äºŒç»´ç å¼¹æ¡†æ ·å¼ */
.qrcode-container {
  text-align: center;
  padding: 10px;
}
.qrcode-wrapper {
  margin: 0 auto 20px;
  padding: 15px;
  background: #f8f9fa;
  border-radius: 8px;
  display: inline-block;
}
.qrcode-info {
  margin: 15px 0;
  padding: 12px;
  background: #f0f2f5;
  border-radius: 6px;
  text-align: left;
}
.qrcode-info p {
  margin: 8px 0;
  font-size: 14px;
}
.qrcode-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 20px;
}
/* å“åº”式设计 */
@media (max-width: 480px) {
  .qrcode-actions {
    flex-direction: column;
    align-items: center;
  }
  .qrcode-actions .el-button {
    width: 200px;
  }
}
</style>
src/views/knowledge/Medication/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,901 @@
<template>
  <div class="patient-medication-management">
    <el-row :gutter="20">
      <el-col :span="24" :xs="24">
        <!-- æœç´¢åŒºåŸŸ -->
        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
          <el-form-item label="患者姓名" prop="patientName">
            <el-input
              v-model="queryParams.patientName"
              placeholder="请输入患者姓名"
              clearable
              style="width: 200px"
              @keyup.enter.native="handleQuery"
            />
          </el-form-item>
          <el-form-item label="药品名称" prop="drugName">
            <el-input
              v-model="queryParams.drugName"
              placeholder="请输入药品名称"
              clearable
              style="width: 200px"
              @keyup.enter.native="handleQuery"
            />
          </el-form-item>
          <el-form-item label="用药状态" prop="medicationStatus">
            <el-select v-model="queryParams.medicationStatus" placeholder="请选择状态" clearable style="width: 200px">
              <el-option
                v-for="item in statusOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </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-form>
        <!-- æ“ä½œæŒ‰é’®åŒºåŸŸ -->
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button
              type="primary"
              plain
              icon="el-icon-plus"
              size="medium"
              @click="handleAssignMedication"
            >分配用药</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
              type="warning"
              plain
              icon="el-icon-close"
              size="medium"
              :disabled="multiple"
              @click="handleStopMedication"
            >停止用药</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
              type="danger"
              plain
              icon="el-icon-delete"
              size="medium"
              :disabled="multiple"
              @click="handleDelete"
            >删除记录</el-button>
          </el-col>
        </el-row>
        <!-- æ•°æ®è¡¨æ ¼ -->
        <el-table v-loading="loading" :data="medicationList" @selection-change="handleSelectionChange">
          <el-table-column type="selection" width="50" align="center" />
          <el-table-column label="记录ID" align="center" prop="id" width="80" />
          <el-table-column label="患者信息" align="center" width="200">
            <template slot-scope="scope">
              <div class="patient-info">
                <div class="patient-name">{{ scope.row.patientName }}</div>
                <div class="patient-details">
                  {{ scope.row.patientAge }}岁 / {{ scope.row.patientGender === '1' ? '男' : '女' }} / {{ scope.row.patientNo }}
                </div>
              </div>
            </template>
          </el-table-column>
          <el-table-column label="过敏信息" align="center" width="120">
            <template slot-scope="scope">
              <el-tag
                v-if="scope.row.allergyHistory"
                type="danger"
                size="small"
                @click="showAllergyDetail(scope.row)"
              >有过敏史</el-tag>
              <span v-else class="no-allergy">无</span>
            </template>
          </el-table-column>
          <el-table-column label="药品信息" align="center" min-width="200">
            <template slot-scope="scope">
              <div class="drug-info">
                <div class="drug-name">{{ scope.row.drugName }} ({{ scope.row.drugSpecification }})</div>
                <div class="dosage-info">{{ scope.row.dosage }} {{ scope.row.dosageUnit }} / æ¬¡</div>
              </div>
            </template>
          </el-table-column>
          <el-table-column label="用法用量" align="center" width="150">
            <template slot-scope="scope">
              <div class="usage-info">
                <div>{{ scope.row.frequency }}次/日</div>
                <div>{{ scope.row.usageMethod }}</div>
              </div>
            </template>
          </el-table-column>
          <el-table-column label="用药时间" align="center" width="200">
            <template slot-scope="scope">
              <div class="time-info">
                <div>开始: {{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</div>
                <div v-if="scope.row.endTime">结束: {{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}</div>
                <div v-else>长期用药</div>
              </div>
            </template>
          </el-table-column>
          <el-table-column label="用药状态" align="center" width="100">
            <template slot-scope="scope">
              <el-tag
                :type="getStatusTagType(scope.row.medicationStatus)"
                size="small"
              >
                {{ getStatusText(scope.row.medicationStatus) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作医生" align="center" width="120" prop="prescribingDoctor" />
          <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="text"
                icon="el-icon-edit"
                @click="handleUpdate(scope.row)"
              >修改</el-button>
              <el-button
                size="mini"
                type="text"
                icon="el-icon-close"
                :class="{ 'stop-button': scope.row.medicationStatus === '1' }"
                @click="handleSingleStop(scope.row)"
                :disabled="scope.row.medicationStatus === '0'"
              >{{ scope.row.medicationStatus === '1' ? '停止' : '已停止' }}</el-button>
              <el-button
                size="mini"
                type="text"
                icon="el-icon-view"
                @click="handleViewDetail(scope.row)"
              >详情</el-button>
            </template>
          </el-table-column>
        </el-table>
        <pagination
          v-show="total>0"
          :total="total"
          :page.sync="queryParams.pageNum"
          :limit.sync="queryParams.pageSize"
          @pagination="getList"
        />
      </el-col>
    </el-row>
    <!-- åˆ†é…ç”¨è¯å¯¹è¯æ¡† -->
    <el-dialog :title="assignTitle" :visible.sync="assignOpen" width="900px" append-to-body>
      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="100px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="选择患者" prop="patientId">
              <el-select
                v-model="assignForm.patientId"
                placeholder="请选择患者"
                filterable
                @change="handlePatientChange"
                style="width: 100%"
              >
                <el-option
                  v-for="patient in patientOptions"
                  :key="patient.id"
                  :label="`${patient.name} (${patient.patientNo})`"
                  :value="patient.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="患者信息">
              <div v-if="selectedPatient" class="patient-detail">
                <div>姓名: {{ selectedPatient.name }}</div>
                <div>年龄: {{ selectedPatient.age }}岁</div>
                <div>病历号: {{ selectedPatient.patientNo }}</div>
                <div v-if="selectedPatient.allergyHistory" class="allergy-warning">
                  è¿‡æ•å²: {{ selectedPatient.allergyHistory }}
                </div>
              </div>
              <span v-else class="placeholder">请先选择患者</span>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="药品名称" prop="drugId">
              <el-select
                v-model="assignForm.drugId"
                placeholder="请选择药品"
                filterable
                @change="handleDrugChange"
                style="width: 100%"
              >
                <el-option
                  v-for="drug in drugOptions"
                  :key="drug.id"
                  :label="drug.name"
                  :value="drug.id"
                >
                  <span>{{ drug.name }}</span>
                  <span style="float: right; color: #8492a6; font-size: 13px">
                    {{ drug.specification }} | åº“å­˜: {{ drug.stock }}
                  </span>
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="药品规格">
              <el-input v-model="selectedDrug.specification" readonly />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="单次剂量" prop="dosage">
              <el-input-number
                v-model="assignForm.dosage"
                :min="0.1"
                :max="10"
                :step="0.1"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="剂量单位" prop="dosageUnit">
              <el-select v-model="assignForm.dosageUnit" style="width: 100%">
                <el-option label="片" value="片" />
                <el-option label="粒" value="粒" />
                <el-option label="mg" value="mg" />
                <el-option label="ml" value="ml" />
                <el-option label="g" value="g" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="用药频次" prop="frequency">
              <el-select v-model="assignForm.frequency" style="width: 100%">
                <el-option label="每日1次" value="1" />
                <el-option label="每日2次" value="2" />
                <el-option label="每日3次" value="3" />
                <el-option label="每日4次" value="4" />
                <el-option label="按需服用" value="0" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="用药方法" prop="usageMethod">
              <el-select v-model="assignForm.usageMethod" style="width: 100%">
                <el-option label="口服" value="口服" />
                <el-option label="静脉注射" value="静脉注射" />
                <el-option label="肌肉注射" value="肌肉注射" />
                <el-option label="皮下注射" value="皮下注射" />
                <el-option label="外用" value="外用" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="用药时间" prop="durationType">
              <el-radio-group v-model="assignForm.durationType">
                <el-radio label="1">长期用药</el-radio>
                <el-radio label="2">指定周期</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20" v-if="assignForm.durationType === '2'">
          <el-col :span="12">
            <el-form-item label="开始时间" prop="startTime">
              <el-date-picker
                v-model="assignForm.startTime"
                type="datetime"
                placeholder="选择开始时间"
                style="width: 100%"
                value-format="yyyy-MM-dd HH:mm:ss"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="结束时间" prop="endTime">
              <el-date-picker
                v-model="assignForm.endTime"
                type="datetime"
                placeholder="选择结束时间"
                style="width: 100%"
                value-format="yyyy-MM-dd HH:mm:ss"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="用药说明" prop="instructions">
          <el-input
            type="textarea"
            :rows="3"
            v-model="assignForm.instructions"
            placeholder="请输入用药注意事项、特殊说明等"
          />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitAssignForm">ç¡® å®š</el-button>
        <el-button @click="cancelAssign">取 æ¶ˆ</el-button>
      </div>
    </el-dialog>
    <!-- åœæ­¢ç”¨è¯å¯¹è¯æ¡† -->
    <el-dialog :title="stopTitle" :visible.sync="stopOpen" width="600px" append-to-body>
      <el-form ref="stopForm" :model="stopForm" :rules="stopRules" label-width="100px">
        <el-form-item label="停止原因" prop="stopReason">
          <el-select v-model="stopForm.stopReason" placeholder="请选择停止原因" style="width: 100%">
            <el-option label="疗程结束" value="疗程结束" />
            <el-option label="不良反应" value="不良反应" />
            <el-option label="疗效不佳" value="疗效不佳" />
            <el-option label="患者要求" value="患者要求" />
            <el-option label="医生建议" value="医生建议" />
            <el-option label="其他原因" value="其他" />
          </el-select>
        </el-form-item>
        <el-form-item label="详细说明" prop="stopDescription">
          <el-input
            type="textarea"
            :rows="4"
            v-model="stopForm.stopDescription"
            placeholder="请详细说明停止用药的原因和情况"
          />
        </el-form-item>
        <el-form-item label="停止时间" prop="stopTime">
          <el-date-picker
            v-model="stopForm.stopTime"
            type="datetime"
            placeholder="选择停止时间"
            style="width: 100%"
            value-format="yyyy-MM-dd HH:mm:ss"
          />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitStopForm">ç¡® å®š</el-button>
        <el-button @click="cancelStop">取 æ¶ˆ</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { parseTime } from '@/utils/ruoyi'
export default {
  name: "PatientMedicationManagement",
  dicts: ['sys_normal_disable'],
  data() {
    return {
      // é®ç½©å±‚
      loading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
      single: true,
      // éžå¤šä¸ªç¦ç”¨
      multiple: true,
      // æ˜¾ç¤ºæœç´¢æ¡ä»¶
      showSearch: true,
      // æ€»æ¡æ•°
      total: 0,
      // ç”¨è¯è®°å½•数据
medicationList: [
  {
    id: 1,
    patientId: 'P1001',
    patientName: '张清扬',
    patientAge: 65,
    patientGender: '1',
    patientNo: '20241209001',
    allergyHistory: '青霉素过敏',
    drugId: 'D1001',
    drugName: '阿司匹林肠溶片',
    drugSpecification: '100mg*30片/盒',
    dosage: 1,
    dosageUnit: '片',
    frequency: '1',
    usageMethod: '口服',
    startTime: '2024-12-01 08:00:00',
    endTime: '',
    durationType: '1',
    instructions: '饭后服用,注意胃肠道反应。长期服用需定期检查血常规。',
    medicationStatus: '1',
    prescribingDoctor: '李成白',
    stopReason: '',
    stopDescription: ''
  },
  {
    id: 2,
    patientId: 'P1001',
    patientName: '张清扬',
    patientAge: 65,
    patientGender: '1',
    patientNo: '20241209001',
    allergyHistory: '青霉素过敏',
    drugId: 'D1002',
    drugName: '阿托伐他汀钙片',
    drugSpecification: '20mg*7片/盒',
    dosage: 1,
    dosageUnit: '片',
    frequency: '1',
    usageMethod: '口服',
    startTime: '2024-11-20 20:00:00',
    endTime: '',
    durationType: '1',
    instructions: '每晚睡前服用。注意监测肝功能,如有肌肉酸痛请及时就医。',
    medicationStatus: '1',
    prescribingDoctor: '李成白',
    stopReason: '',
    stopDescription: ''
  },
  {
    id: 3,
    patientId: 'P2001',
    patientName: '王芳',
    patientAge: 33,
    patientGender: '0',
    patientNo: '20241115002',
    allergyHistory: '无',
    drugId: 'D1003',
    drugName: '泼尼松片',
    drugSpecification: '5mg*100片/瓶',
    dosage: 2,
    dosageUnit: '片',
    frequency: '3',
    usageMethod: '口服',
    startTime: '2024-12-05 09:00:00',
    endTime: '2024-12-20 09:00:00',
    durationType: '2',
    instructions: '早、中、晚餐后服用。需严格遵医嘱逐渐减量,不可突然停药。',
    medicationStatus: '0',
    prescribingDoctor: '刘翊惠',
    stopReason: '疗程结束',
    stopDescription: '标准疗程用药完毕,血小板计数已恢复正常范围。'
  },
  {
    id: 4,
    patientId: 'P2001',
    patientName: '王芳',
    patientAge: 33,
    patientGender: '0',
    patientNo: '20241115002',
    allergyHistory: '无',
    drugId: 'D1004',
    drugName: '多糖铁复合物胶囊',
    drugSpecification: '150mg*10粒/盒',
    dosage: 1,
    dosageUnit: '粒',
    frequency: '2',
    usageMethod: '口服',
    startTime: '2024-12-05 09:00:00',
    endTime: '',
    durationType: '1',
    instructions: '餐后服用,可减轻胃肠道刺激。服药后可能出现黑便,属正常现象。',
    medicationStatus: '1',
    prescribingDoctor: '刘翊惠',
    stopReason: '',
    stopDescription: ''
  },
  {
    id: 5,
    patientId: 'P3001',
    patientName: '李伟',
    patientAge: 58,
    patientGender: '1',
    patientNo: '20241022005',
    allergyHistory: '磺胺类药物过敏',
    drugId: 'D1005',
    drugName: '盐酸二甲双胍片',
    drugSpecification: '0.5g*20片/板',
    dosage: 1,
    dosageUnit: '片',
    frequency: '2',
    usageMethod: '口服',
    startTime: '2024-10-22 08:00:00',
    endTime: '',
    durationType: '1',
    instructions: '随餐或餐后立即服用,以减少胃肠道不适。',
    medicationStatus: '1',
    prescribingDoctor: '张孟涵',
    stopReason: '',
    stopDescription: ''
  },
  {
    id: 6,
    patientId: 'P4001',
    patientName: '赵磊',
    patientAge: 70,
    patientGender: '1',
    patientNo: '20241202011',
    allergyHistory: '海鲜过敏',
    drugId: 'D1006',
    drugName: '呋塞米片',
    drugSpecification: '20mg*100片/瓶',
    dosage: 1,
    dosageUnit: '片',
    frequency: '1',
    usageMethod: '口服',
    startTime: '2024-12-02 07:00:00',
    endTime: '',
    durationType: '1',
    instructions: '晨起服用,避免夜间多次起夜。注意监测电解质水平。',
    medicationStatus: '1',
    prescribingDoctor: '吴思翰',
    stopReason: '',
    stopDescription: ''
  },
  {
    id: 7,
    patientId: 'P5001',
    patientName: '周华',
    patientAge: 52,
    patientGender: '0',
    patientNo: '20241128009',
    allergyHistory: '无',
    drugId: 'D1007',
    drugName: '硝苯地平控释片',
    drugSpecification: '30mg*7片/盒',
    dosage: 1,
    dosageUnit: '片',
    frequency: '1',
    usageMethod: '口服',
    startTime: '2024-11-28 08:00:00',
    endTime: '',
    durationType: '1',
    instructions: '整片吞服,不可嚼碎或掰开。',
    medicationStatus: '1',
    prescribingDoctor: '陈政倩',
    stopReason: '',
    stopDescription: ''
  }
],
      // åˆ†é…ç”¨è¯å¼¹å‡ºå±‚
      assignOpen: false,
      assignTitle: "",
      // åœæ­¢ç”¨è¯å¼¹å‡ºå±‚
      stopOpen: false,
      stopTitle: "",
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        patientName: undefined,
        drugName: undefined,
        medicationStatus: undefined
      },
      // åˆ†é…ç”¨è¯è¡¨å•
      assignForm: {},
      // åœæ­¢ç”¨è¯è¡¨å•
      stopForm: {},
      // é€‰ä¸­æ‚£è€…信息
      selectedPatient: null,
      // é€‰ä¸­è¯å“ä¿¡æ¯
      selectedDrug: {},
      // æ‚£è€…选项
      patientOptions: [
        {
          id: 'P1001',
          name: '张三',
          age: 65,
          patientNo: '20241209001',
          allergyHistory: '青霉素过敏'
        }
      ],
      // è¯å“é€‰é¡¹
      drugOptions: [
        {
          id: 'D1001',
          name: '阿司匹林',
          specification: '100mg',
          stock: 150
        }
      ],
      // çŠ¶æ€é€‰é¡¹
      statusOptions: [
        { value: "1", label: "用药中" },
        { value: "0", label: "已停止" }
      ],
      // è¡¨å•校验
      assignRules: {
        patientId: [
          { required: true, message: "请选择患者", trigger: "change" }
        ],
        drugId: [
          { required: true, message: "请选择药品", trigger: "change" }
        ],
        dosage: [
          { required: true, message: "请输入单次剂量", trigger: "blur" }
        ],
        frequency: [
          { required: true, message: "请选择用药频次", trigger: "change" }
        ]
      },
      stopRules: {
        stopReason: [
          { required: true, message: "请选择停止原因", trigger: "change" }
        ],
        stopTime: [
          { required: true, message: "请选择停止时间", trigger: "change" }
        ]
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    parseTime,
    /** æŸ¥è¯¢ç”¨è¯è®°å½•列表 */
    getList() {
      this.loading = true;
      // æ¨¡æ‹ŸAPI调用
      setTimeout(() => {
        this.loading = false;
        this.total = this.medicationList.length;
      }, 500);
    },
    /** æœç´¢æŒ‰é’®æ“ä½œ */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    /** åˆ†é…ç”¨è¯æŒ‰é’®æ“ä½œ */
    handleAssignMedication() {
      this.resetAssignForm();
      this.assignOpen = true;
      this.assignTitle = "分配用药";
    },
    /** åœæ­¢ç”¨è¯æŒ‰é’®æ“ä½œ */
    handleStopMedication() {
      if (this.ids.length === 0) {
        this.$modal.msgError("请先选择要停止的用药记录");
        return;
      }
      this.resetStopForm();
      this.stopOpen = true;
      this.stopTitle = "停止用药";
    },
    /** å•个停止用药 */
    handleSingleStop(row) {
      this.ids = [row.id];
      this.resetStopForm();
      this.stopForm.patientName = row.patientName;
      this.stopForm.drugName = row.drugName;
      this.stopOpen = true;
      this.stopTitle = `停止用药 - ${row.patientName}`;
    },
    /** æäº¤åˆ†é…ç”¨è¯è¡¨å• */
    submitAssignForm() {
      this.$refs["assignForm"].validate(valid => {
        if (valid) {
          // æ¨¡æ‹ŸAPI调用
          const newRecord = {
            id: Math.max(...this.medicationList.map(item => item.id)) + 1,
            ...this.assignForm,
            patientName: this.selectedPatient?.name,
            patientAge: this.selectedPatient?.age,
            patientGender: this.selectedPatient?.gender,
            patientNo: this.selectedPatient?.patientNo,
            allergyHistory: this.selectedPatient?.allergyHistory,
            drugName: this.selectedDrug?.name,
            drugSpecification: this.selectedDrug?.specification,
            medicationStatus: '1',
            prescribingDoctor: '当前用户',
            startTime: this.assignForm.startTime || new Date().toISOString().replace('T', ' ').substr(0, 19)
          };
          this.medicationList.unshift(newRecord);
          this.total = this.medicationList.length;
          this.$modal.msgSuccess("分配成功");
          this.assignOpen = false;
        }
      });
    },
    /** æäº¤åœæ­¢ç”¨è¯è¡¨å• */
    submitStopForm() {
      this.$refs["stopForm"].validate(valid => {
        if (valid) {
          // æ›´æ–°ç”¨è¯è®°å½•状态
          this.medicationList.forEach(item => {
            if (this.ids.includes(item.id)) {
              item.medicationStatus = '0';
              item.endTime = this.stopForm.stopTime;
              item.stopReason = this.stopForm.stopReason;
              item.stopDescription = this.stopForm.stopDescription;
            }
          });
          this.$modal.msgSuccess("停止用药成功");
          this.stopOpen = false;
          this.getList();
        }
      });
    },
    /** æ‚£è€…选择变化 */
    handlePatientChange(patientId) {
      this.selectedPatient = this.patientOptions.find(p => p.id === patientId) || null;
    },
    /** è¯å“é€‰æ‹©å˜åŒ– */
    handleDrugChange(drugId) {
      this.selectedDrug = this.drugOptions.find(d => d.id === drugId) || {};
    },
    /** æŸ¥çœ‹è¯¦æƒ… */
    handleViewDetail(row) {
      this.$alert(
        `<div>
          <p><strong>患者信息:</strong>${row.patientName} (${row.patientNo})</p>
          <p><strong>药品信息:</strong>${row.drugName} ${row.drugSpecification}</p>
          <p><strong>用法用量:</strong>${row.dosage}${row.dosageUnit}/次,${row.frequency}次/日,${row.usageMethod}</p>
          <p><strong>用药时间:</strong>${this.parseTime(row.startTime, '{y}-{m}-{d}')} - ${row.endTime ? this.parseTime(row.endTime, '{y}-{m}-{d}') : '长期'}</p>
          <p><strong>用药说明:</strong>${row.instructions || '无'}</p>
          ${row.allergyHistory ? `<p><strong>过敏史:</strong><span style="color: red">${row.allergyHistory}</span></p>` : ''}
        </div>`,
        "用药详情",
        {
          dangerouslyUseHTMLString: true,
          customClass: "medication-detail-dialog",
        }
      );
    },
    /** æ˜¾ç¤ºè¿‡æ•å²è¯¦æƒ… */
    showAllergyDetail(row) {
      if (row.allergyHistory) {
        this.$alert(`患者 ${row.patientName} çš„过敏史:${row.allergyHistory}`, "过敏史详情", {
          confirmButtonText: "确定"
        });
      }
    },
    /** èŽ·å–çŠ¶æ€æ ‡ç­¾ç±»åž‹ */
    getStatusTagType(status) {
      const statusMap = {
        '1': 'success', // ç”¨è¯ä¸­
        '0': 'info'     // å·²åœæ­¢
      };
      return statusMap[status] || 'info';
    },
    /** èŽ·å–çŠ¶æ€æ–‡æœ¬ */
    getStatusText(status) {
      const statusMap = {
        '1': '用药中',
        '0': '已停止'
      };
      return statusMap[status] || '未知';
    },
    /** é‡ç½®åˆ†é…ç”¨è¯è¡¨å• */
    resetAssignForm() {
      this.assignForm = {
        patientId: undefined,
        drugId: undefined,
        dosage: 1,
        dosageUnit: '片',
        frequency: '3',
        usageMethod: '口服',
        durationType: '1',
        startTime: new Date().toISOString().replace('T', ' ').substr(0, 19),
        endTime: undefined,
        instructions: ''
      };
      this.selectedPatient = null;
      this.selectedDrug = {};
      this.resetForm("assignForm");
    },
    /** é‡ç½®åœæ­¢ç”¨è¯è¡¨å• */
    resetStopForm() {
      this.stopForm = {
        stopReason: '',
        stopDescription: '',
        stopTime: new Date().toISOString().replace('T', ' ').substr(0, 19)
      };
      this.resetForm("stopForm");
    },
    /** å–消分配用药 */
    cancelAssign() {
      this.assignOpen = false;
      this.resetAssignForm();
    },
    /** å–消停止用药 */
    cancelStop() {
      this.stopOpen = false;
      this.resetStopForm();
    }
  }
};
</script>
<style lang="scss" scoped>
.patient-medication-management {
  padding: 20px;
}
.patient-info {
  text-align: left;
  .patient-name {
    font-weight: bold;
    margin-bottom: 4px;
  }
  .patient-details {
    font-size: 12px;
    color: #909399;
  }
}
.drug-info {
  text-align: left;
  .drug-name {
    font-weight: bold;
    margin-bottom: 4px;
  }
  .dosage-info {
    font-size: 12px;
    color: #67C23A;
  }
}
.usage-info, .time-info {
  font-size: 12px;
  line-height: 1.4;
}
.allergy-warning {
  color: #F56C6C;
  font-size: 12px;
}
.no-allergy {
  color: #909399;
  font-style: italic;
}
.patient-detail {
  font-size: 12px;
  line-height: 1.6;
  padding: 8px;
  background: #f5f7fa;
  border-radius: 4px;
}
.placeholder {
  color: #c0c4cc;
  font-style: italic;
}
.stop-button {
  color: #E6A23C;
  &:hover {
    color: #f56c6c;
  }
}
::v-deep .medication-detail-dialog {
  width: 500px;
}
</style>
src/views/knowledge/article/index.vue
@@ -212,68 +212,105 @@
      // æ€»æ¡æ•°
      total: 0,
      // æ–‡ç« è¡¨æ ¼æ•°æ®
      articleList: [
        {
          id: 1,
          title: "如何提高前端开发效率",
          category: "1",
          coverImage: "https://pic.rmb.bdstatic.com/bjh/news/5e5f1b3e7b1a8a7f8a3d6a7d3a6a7d3a.jpeg",
          author: "张三",
          publishTime: "2023-05-10 09:30:00",
          views: 1250,
          status: "1",
          summary: "本文介绍了几种提高前端开发效率的方法和工具",
          content: "<p>前端开发效率的提升对于项目进度至关重要...</p>"
        },
        {
          id: 2,
          title: "Vue3新特性解析",
          category: "2",
          coverImage: "https://pic.rmb.bdstatic.com/bjh/news/8e5f1b3e7b1a8a7f8a3d6a7d3a6a7d3a.jpeg",
          author: "李四",
          publishTime: "2023-05-15 14:20:00",
          views: 3200,
          status: "1",
          summary: "详细解析Vue3的新特性和使用场景",
          content: "<p>Vue3带来了许多令人兴奋的新特性...</p>"
        },
        {
          id: 3,
          title: "Element UI使用技巧",
          category: "3",
          coverImage: "https://pic.rmb.bdstatic.com/bjh/news/9e5f1b3e7b1a8a7f8a3d6a7d3a6a7d3a.jpeg",
          author: "王五",
          publishTime: "2023-05-20 10:15:00",
          views: 890,
          status: "0",
          summary: "分享一些Element UI的高级使用技巧",
          content: "<p>Element UI作为流行的UI框架,有许多实用技巧...</p>"
        },
        {
          id: 4,
          title: "前端性能优化指南",
          category: "1",
          coverImage: "https://pic.rmb.bdstatic.com/bjh/news/7e5f1b3e7b1a8a7f8a3d6a7d3a6a7d3a.jpeg",
          author: "赵六",
          publishTime: "2023-05-25 16:45:00",
          views: 4500,
          status: "1",
          summary: "全面的前端性能优化方法和实践",
          content: "<p>性能优化是前端开发中永恒的话题...</p>"
        },
        {
          id: 5,
          title: "TypeScript入门教程",
          category: "2",
          coverImage: "https://pic.rmb.bdstatic.com/bjh/news/6e5f1b3e7b1a8a7f8a3d6a7d3a6a7d3a.jpeg",
          author: "钱七",
          publishTime: "2023-06-01 11:10:00",
          views: 2100,
          status: "1",
          summary: "从零开始学习TypeScript",
          content: "<p>TypeScript作为JavaScript的超集越来越受欢迎...</p>"
        }
      ],
     // æ›¿æ¢åŽŸæœ‰çš„articleList数据
articleList: [
  {
    id: 1,
    title: "糖尿病管理新进展:个性化治疗方案的研究与应用",
    category: "1",
    coverImage: "https://example.com/images/diabetes-management.jpg",
    author: "李成白",
    publishTime: "2024-11-15 09:30:00",
    views: 3250,
    status: "1",
    summary: "本文综述了近年来糖尿病个性化治疗的最新研究成果,重点分析了基于患者基因特征的定制化治疗方案。",
    content: "<p>随着精准医疗的发展,糖尿病治疗正从标准化向个性化转变...</p>"
  },
  {
    id: 2,
    title: "心血管疾病预防:从风险评估到早期干预",
    category: "2",
    coverImage: "https://example.com/images/cardiovascular-prevention.jpg",
    author: "刘翊惠",
    publishTime: "2024-11-10 14:20:00",
    views: 4280,
    status: "1",
    summary: "探讨心血管疾病的新型风险评估工具和早期干预策略,为临床实践提供指导。",
    content: "<p>心血管疾病仍然是全球主要的死亡原因,早期预防至关重要...</p>"
  },
  {
    id: 3,
    title: "肿瘤免疫治疗的不良反应管理与应对策略",
    category: "3",
    coverImage: "https://example.com/images/immunotherapy-side-effects.jpg",
    author: "张孟涵",
    publishTime: "2024-11-05 10:15:00",
    views: 2890,
    status: "0",
    summary: "系统分析免疫检查点抑制剂治疗中常见的不良反应及其临床管理方案。",
    content: "<p>免疫治疗为肿瘤患者带来希望,但其独特的不良反应需要特别关注...</p>"
  },
  {
    id: 4,
    title: "人工智能在医学影像诊断中的应用与挑战",
    category: "4",
    coverImage: "https://example.com/images/ai-medical-imaging.jpg",
    author: "吴思翰",
    publishTime: "2024-10-28 16:45:00",
    views: 5120,
    status: "1",
    summary: "回顾AI技术在CT、MRI等医学影像分析中的最新进展及临床应用价值。",
    content: "<p>人工智能技术正在重塑医学影像诊断的格局...</p>"
  },
  {
    id: 5,
    title: "慢性疼痛的药物治疗与非药物干预综合管理",
    category: "1",
    coverImage: "https://example.com/images/chronic-pain-management.jpg",
    author: "陈政倩",
    publishTime: "2024-10-22 11:10:00",
    views: 1950,
    status: "1",
    summary: "基于循证医学证据,提出慢性疼痛的综合管理方案,平衡疗效与安全性。",
    content: "<p>慢性疼痛严重影响患者生活质量,需要多模式综合治疗...</p>"
  },
  {
    id: 6,
    title: "儿科呼吸道感染的诊疗规范更新解读",
    category: "2",
    coverImage: "https://example.com/images/pediatric-respiratory.jpg",
    author: "邓诗涵",
    publishTime: "2024-10-18 13:25:00",
    views: 3670,
    status: "1",
    summary: "结合最新临床指南,详细解读儿童呼吸道感染的诊断标准和治疗原则。",
    content: "<p>儿童呼吸道感染是儿科常见病,规范诊疗对预后至关重要...</p>"
  },
  {
    id: 7,
    title: "精神卫生数字疗法的现状与未来发展",
    category: "3",
    coverImage: "https://example.com/images/digital-mental-health.jpg",
    author: "黄盛玫",
    publishTime: "2024-10-12 15:30:00",
    views: 2430,
    status: "2",
    summary: "探讨数字技术在精神心理疾病治疗中的应用前景和面临的挑战。",
    content: "<p>数字疗法为精神卫生领域带来了新的治疗模式...</p>"
  },
  {
    id: 8,
    title: "老年综合评估在临床实践中的实施路径",
    category: "4",
    coverImage: "https://example.com/images/geriatric-assessment.jpg",
    author: "王恩龙",
    publishTime: "2024-10-05 08:45:00",
    views: 1780,
    status: "1",
    summary: "系统介绍老年综合评估的多维度内容及其在老年患者管理中的价值。",
    content: "<p>随着人口老龄化,老年综合评估成为老年医学的重要工具...</p>"
  }
],
      // å¼¹å‡ºå±‚标题
      title: "",
      // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚
@@ -308,10 +345,10 @@
      },
      // æ–‡ç« åˆ†ç±»é€‰é¡¹
      categoryOptions: [
        { value: "1", label: "技术文章" },
        { value: "2", label: "教程指南" },
        { value: "3", label: "经验分享" },
        { value: "4", label: "行业资讯" }
        { value: "1", label: "临床研究" },
  { value: "2", label: "诊疗指南" },
  { value: "3", label: "药物进展" },
  { value: "4", label: "技术前沿" }
      ],
      // çŠ¶æ€é€‰é¡¹
      statusOptions: [
src/views/patient/SignAcontract/Review.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,827 @@
<template>
  <div class="contract-review-page">
    <!-- ç­›é€‰æ¡ä»¶ -->
    <el-card class="search-card" shadow="never">
      <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="100px">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-form-item label="患者姓名" prop="patientName">
              <el-input
                v-model="queryParams.patientName"
                placeholder="请输入患者姓名"
                clearable
                @keyup.enter="handleQuery"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="审核状态" prop="reviewStatus">
              <el-select v-model="queryParams.reviewStatus" placeholder="请选择状态" clearable>
                <el-option label="待审核" value="0" />
                <el-option label="审核通过" value="1" />
                <el-option label="审核驳回" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="申请时间" prop="applyDate">
              <el-date-picker
                v-model="queryParams.applyDate"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
              <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </el-card>
    <!-- ç»Ÿè®¡ä¿¡æ¯ -->
    <el-row :gutter="20" class="stats-row">
      <el-col :span="8">
        <el-card shadow="hover">
          <div class="stat-item">
            <div class="stat-number">{{ stats.pending }}</div>
            <div class="stat-label">待审核申请</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="8">
        <el-card shadow="hover">
          <div class="stat-item">
            <div class="stat-number" style="color: #67C23A;">{{ stats.approved }}</div>
            <div class="stat-label">已通过审核</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="8">
        <el-card shadow="hover">
          <div class="stat-item">
            <div class="stat-number" style="color: #F56C6C;">{{ stats.rejected }}</div>
            <div class="stat-label">已驳回申请</div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- å®¡æ ¸åˆ—表 -->
    <el-card shadow="never">
      <el-table
        v-loading="loading"
        :data="reviewList"
        style="width: 100%"
        :default-sort="{prop: 'applyTime', order: 'descending'}"
      >
        <el-table-column label="患者信息" min-width="200" fixed>
          <template slot-scope="scope">
            <div class="patient-info">
              <div class="patient-name">{{ scope.row.patientName }}</div>
              <div class="patient-detail">
                {{ scope.row.gender }} | {{ scope.row.age }}岁 | {{ scope.row.phone }}
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="申请套餐" min-width="150">
          <template slot-scope="scope">
            <el-tag :type="getPackageType(scope.row.servicePackageId)">
              {{ scope.row.servicePackage }}
            </el-tag>
            <div style="font-size: 12px; color: #666; margin-top: 4px;">
              å‘¨æœŸ: {{ scope.row.contractPeriod }}å¹´
            </div>
          </template>
        </el-table-column>
        <el-table-column label="包含服务" min-width="200">
          <template slot-scope="scope">
            <el-tooltip effect="dark" :content="scope.row.services.join('、')" placement="top">
              <span>{{ scope.row.services.slice(0, 2).join('、') }}等{{ scope.row.services.length }}项</span>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="申请时间" prop="applyTime" width="160" sortable />
        <el-table-column label="期望医生" prop="expectDoctor" width="120" />
        <el-table-column label="特殊要求" min-width="200">
          <template slot-scope="scope">
            <span v-if="scope.row.specialRequirements" :title="scope.row.specialRequirements">
              {{ scope.row.specialRequirements.substring(0, 30) }}...
            </span>
            <span v-else style="color: #999;">无特殊要求</span>
          </template>
        </el-table-column>
        <el-table-column label="审核状态" width="100">
          <template slot-scope="scope">
            <el-tag :type="getReviewStatusType(scope.row.reviewStatus)" effect="dark">
              {{ getReviewStatusText(scope.row.reviewStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="审核信息" min-width="180">
          <template slot-scope="scope">
            <div v-if="scope.row.reviewStatus !== 0">
              <div style="font-size: 12px;">审核人: {{ scope.row.reviewer }}</div>
              <div style="font-size: 12px;">时间: {{ scope.row.reviewTime }}</div>
              <div v-if="scope.row.reviewStatus === 2" style="color: #f56c6c; font-size: 12px;">
                åŽŸå› : {{ scope.row.rejectReason }}
              </div>
            </div>
            <span v-else style="color: #999;">待审核</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="180" fixed="right">
          <template slot-scope="scope">
            <el-button
              v-if="scope.row.reviewStatus === 0"
              size="mini"
              type="primary"
              @click="handleReview(scope.row, 1)"
            >通过</el-button>
            <el-button
              v-if="scope.row.reviewStatus === 0"
              size="mini"
              type="danger"
              @click="handleReview(scope.row, 2)"
            >驳回</el-button>
            <el-button
              size="mini"
              type="text"
              @click="handleView(scope.row)"
            >详情</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>
    <!-- å®¡æ ¸å¯¹è¯æ¡† -->
    <el-dialog
      :title="reviewForm.reviewStatus === 1 ? '审核通过确认' : '审核驳回确认'"
      :visible.sync="reviewDialogVisible"
      width="500px"
    >
      <el-form :model="reviewForm" ref="reviewFormRef" label-width="100px">
        <el-form-item
          v-if="reviewForm.reviewStatus === 2"
          label="驳回原因"
          prop="rejectReason"
          :rules="[{ required: true, message: '请输入驳回原因', trigger: 'blur' }]"
        >
          <el-input
            type="textarea"
            :rows="3"
            v-model="reviewForm.rejectReason"
            placeholder="请输入驳回的具体原因,便于患者了解情况"
            maxlength="200"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="分配医生" prop="assignDoctor">
          <el-select v-model="reviewForm.assignDoctor" placeholder="请选择负责医生" clearable>
            <el-option
              v-for="doctor in availableDoctors"
              :key="doctor.id"
              :label="doctor.name"
              :value="doctor.id"
            >
              <span>{{ doctor.name }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px">
                {{ doctor.department }}
              </span>
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="备注信息">
          <el-input
            type="textarea"
            :rows="2"
            v-model="reviewForm.remark"
            placeholder="可填写额外的备注信息(可选)"
            maxlength="100"
          />
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="reviewDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitReview">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'ContractReview',
  data() {
    return {
      loading: false,
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        patientName: undefined,
        reviewStatus: undefined,
        applyDate: undefined
      },
      total: 0,
      reviewList: [],
      reviewDialogVisible: false,
      reviewForm: {
        id: undefined,
        reviewStatus: 1,
        rejectReason: undefined,
        assignDoctor: undefined,
        remark: undefined
      },
      currentRow: null,
      stats: {
        pending: 0,
        approved: 0,
        rejected: 0
      },
      availableDoctors: [
        { id: '1', name: '王医生', department: '内科' },
        { id: '2', name: '李医生', department: '老年科' },
        { id: '3', name: '张医生', department: '妇产科' },
        { id: '4', name: '刘医生', department: '儿科' },
        { id: '5', name: '陈医生', department: '全科' }
      ],
      servicePackages: {
        '1': { name: '基础健康管理包', color: 'info' },
        '2': { name: '慢性病管理包', color: 'success' },
        '3': { name: '老年人健康包', color: 'warning' },
        '4': { name: '孕产妇保健包', color: 'danger' },
        '5': { name: '儿童保健包', color: 'primary' }
      },
      rules: {
        rejectReason: [
          { required: true, message: '驳回原因不能为空', trigger: 'blur' }
        ],
        assignDoctor: [
          { required: true, message: '请选择分配医生', trigger: 'change' }
        ]
      }
    }
  },
  created() {
    this.getList()
    this.calculateStats()
  },
  methods: {
//优化后的模拟数据生成方法
generateMockData() {
  const mockData = []
  // ä½¿ç”¨æ‚¨æä¾›çš„真实姓名列表
  const patientNames = [
    '李肇芬', '卢木仲', '李成白', '方兆玉', '刘翊惠', '丁汉臻', '吴佳瑞', '舒绿珮',
    '周白芷', '张姿妤', '张虹伦', '周琼玟', '倪怡芳', '郭贵妃', '杨佩芳', '黄文旺',
    '黄盛玫', '郑丽青', '许智云', '张孟涵', '李小爱', '王恩龙', '朱政廷', '邓诗涵',
    '陈政倩', '吴俊伯', '阮馨学', '翁惠珠', '吴思翰', '林佩玲'
  ]
  const specialReqs = [
    '希望医生能定期上门检查',
    '需要周末时间段的服务',
    '对药物有过敏史,需特别注意',
    '行动不便,需要上门服务',
    '无特殊要求',
    '需要英语服务支持',
    '有高血压病史,需重点关注',
    '需要定期血糖监测服务',
    '希望有固定的家庭医生',
    '需要心理疏导服务'
  ]
  const rejectReasons = [
    '资料不完整,请补充健康档案',
    '不符合当前签约条件',
    '选择的医生档期已满',
    '服务套餐与病情不匹配',
    '年龄不符合套餐要求',
    '请补充完整的病史资料'
  ]
  // ç”Ÿæˆçº¦30条数据(与姓名数量匹配)
  for (let i = 0; i < patientNames.length; i++) {
    const packageId = (i % 5) + 1 + ''
    const reviewStatus = i % 3 // 0:待审核, 1:通过, 2:驳回
    const applyDate = this.generateRandomDate('2024-10-01', '2024-12-08')
    // ç”Ÿæˆæ›´çœŸå®žçš„电话号码
    const phonePrefix = ['138', '139', '150', '151', '152', '186', '187', '188']
    const phone = `${phonePrefix[i % phonePrefix.length]}${this.padNumber(1000 + i * 37, 4)}${this.padNumber(i % 100, 2)}`
    // ç”Ÿæˆåˆç†çš„年龄(0-80岁)
    const age = i % 80
    const gender = i % 2 === 0 ? '男' : '女'
    mockData.push({
      id: `A${2024000 + i}`,
      patientName: patientNames[i],
      gender: gender,
      age: age,
      phone: phone,
      servicePackageId: packageId,
      servicePackage: this.servicePackages[packageId].name,
      services: this.getServicesByPackage(packageId),
      contractPeriod: [1, 2][i % 2],
      applyTime: `${applyDate} ${this.padNumber(8 + (i % 10), 2)}:${this.padNumber(i % 60, 2)}:${this.padNumber(i % 60, 2)}`,
      expectDoctor: ['王医生', '李医生', '张医生', '刘医生', '陈医生'][i % 5],
      specialRequirements: specialReqs[i % specialReqs.length],
      reviewStatus: reviewStatus,
      reviewer: reviewStatus !== 0 ? ['管理员', '系统管理员', '审核专员'][i % 3] : '',
      reviewTime: reviewStatus !== 0 ?
        `${this.addDays(applyDate, 1 + (i % 3))} 14:${this.padNumber(i % 60, 2)}:00` : '',
      rejectReason: reviewStatus === 2 ? rejectReasons[i % rejectReasons.length] : ''
    })
  }
  return mockData
},
// æ ¹æ®å¥—餐获取服务列表
getServicesByPackage(packageId) {
  const servicesMap = {
    '1': ['年度健康评估', '在线健康咨询', '健康档案管理', '定期健康提醒'],
    '2': ['专属医生服务', '用药指导管理', '定期随访监测', '个性化康复计划', '紧急医疗咨询'],
    '3': ['跌倒风险评估', '康复训练指导', '用药安全管理', '定期上门访视', '紧急联系服务', '心理健康关怀'],
    '4': ['孕期健康管理', '产后康复指导', '新生儿护理咨询', '营养膳食建议', '心理情绪支持'],
    '5': ['生长发育监测', '疫苗接种管理', '常见病防治', '营养指导', '早期教育咨询']
  }
  return servicesMap[packageId] || []
},
// è¾…助方法:生成随机日期
generateRandomDate(start, end) {
  const startDate = new Date(start).getTime()
  const endDate = new Date(end).getTime()
  const randomTime = startDate + Math.random() * (endDate - startDate)
  return new Date(randomTime).toISOString().split('T')[0]
},
// è¾…助方法:添加天数
addDays(date, days) {
  const result = new Date(date)
  result.setDate(result.getDate() + days)
  return result.toISOString().split('T')[0]
},
// è¾…助方法:数字补零
padNumber(num, length) {
  return num.toString().padStart(length, '0')
},
    // èŽ·å–å®¡æ ¸åˆ—è¡¨ [1](@ref)
    async getList() {
      this.loading = true
      try {
        await new Promise(resolve => setTimeout(resolve, 500))
        const allData = this.generateMockData()
        let filteredData = allData.filter(item => {
          if (this.queryParams.patientName &&
              !item.patientName.includes(this.queryParams.patientName)) {
            return false
          }
          if (this.queryParams.reviewStatus !== undefined &&
              item.reviewStatus !== parseInt(this.queryParams.reviewStatus)) {
            return false
          }
          if (this.queryParams.applyDate && this.queryParams.applyDate.length === 2) {
            const applyDate = item.applyTime.split(' ')[0]
            if (applyDate < this.queryParams.applyDate[0] ||
                applyDate > this.queryParams.applyDate[1]) {
              return false
            }
          }
          return true
        })
        const start = (this.queryParams.pageNum - 1) * this.queryParams.pageSize
        const end = start + this.queryParams.pageSize
        this.reviewList = filteredData.slice(start, end)
        this.total = filteredData.length
        this.calculateStats()
      } catch (error) {
        console.error('获取审核列表失败:', error)
        this.$message.error('数据加载失败')
      } finally {
        this.loading = false
      }
    },
    // è®¡ç®—统计信息
    calculateStats() {
      const allData = this.generateMockData()
      this.stats.pending = allData.filter(item => item.reviewStatus === 0).length
      this.stats.approved = allData.filter(item => item.reviewStatus === 1).length
      this.stats.rejected = allData.filter(item => item.reviewStatus === 2).length
    },
    // èŽ·å–å®¡æ ¸çŠ¶æ€æ–‡æœ¬ [2](@ref)
    getReviewStatusText(status) {
      const statusMap = { 0: '待审核', 1: '审核通过', 2: '审核驳回' }
      return statusMap[status] || '未知'
    },
    // èŽ·å–å®¡æ ¸çŠ¶æ€ç±»åž‹
    getReviewStatusType(status) {
      const typeMap = { 0: 'warning', 1: 'success', 2: 'danger' }
      return typeMap[status] || 'info'
    },
    // èŽ·å–å¥—é¤ç±»åž‹
    getPackageType(packageId) {
      const typeMap = { '1': 'info', '2': 'success', '3': 'warning', '4': 'danger', '5': 'primary' }
      return typeMap[packageId] || 'info'
    },
    // æœç´¢æ“ä½œ [1](@ref)
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    // é‡ç½®æœç´¢
    resetQuery() {
      this.queryParams = {
        pageNum: 1,
        pageSize: 10,
        patientName: undefined,
        reviewStatus: undefined,
        applyDate: undefined
      }
      this.handleQuery()
    },
    // å¤„理审核操作 [2](@ref)
    handleReview(row, status) {
      this.currentRow = row
      this.reviewForm = {
        id: row.id,
        reviewStatus: status,
        rejectReason: undefined,
        assignDoctor: undefined,
        remark: undefined
      }
      this.reviewDialogVisible = true
      // æ¸…除表单验证
      this.$nextTick(() => {
        if (this.$refs.reviewFormRef) {
          this.$refs.reviewFormRef.clearValidate()
        }
      })
    },
    // æäº¤å®¡æ ¸ [2,6](@ref)
    async submitReview() {
      try {
        // è¡¨å•验证
        if (this.reviewForm.reviewStatus === 2) {
          if (!this.reviewForm.rejectReason) {
            this.$message.error('请填写驳回原因')
            return
          }
        }
        if (!this.reviewForm.assignDoctor) {
          this.$message.error('请选择分配医生')
          return
        }
        // æ¨¡æ‹ŸAPI调用
        await new Promise(resolve => setTimeout(resolve, 1000))
        // æ›´æ–°å½“前行的状态
        const currentIndex = this.reviewList.findIndex(item => item.id === this.currentRow.id)
        if (currentIndex !== -1) {
          this.reviewList[currentIndex].reviewStatus = this.reviewForm.reviewStatus
          this.reviewList[currentIndex].reviewer = '当前用户'
          this.reviewList[currentIndex].reviewTime = new Date().toLocaleString()
          this.reviewList[currentIndex].rejectReason = this.reviewForm.rejectReason
          // å¦‚果审核通过,分配医生
          if (this.reviewForm.reviewStatus === 1) {
            const doctor = this.availableDoctors.find(d => d.id === this.reviewForm.assignDoctor)
            this.reviewList[currentIndex].expectDoctor = doctor ? doctor.name : this.reviewList[currentIndex].expectDoctor
          }
        }
        this.$message.success(this.reviewForm.reviewStatus === 1 ? '审核通过成功' : '审核驳回成功')
        this.reviewDialogVisible = false
        this.calculateStats() // é‡æ–°è®¡ç®—统计信息
      } catch (error) {
        console.error('审核操作失败:', error)
        this.$message.error('审核操作失败')
      }
    },
    // æŸ¥çœ‹è¯¦æƒ…
    handleView(row) {
      this.$message.info(`查看患者 ${row.patientName} çš„申请详情`)
      // å®žé™…开发中跳转到详情页
      // this.$router.push({ path: '/patient/contract/apply-detail', query: { id: row.id } })
    },
    // æ‰¹é‡å®¡æ ¸é€šè¿‡
    handleBatchApprove() {
      const pendingItems = this.reviewList.filter(item => item.reviewStatus === 0)
      if (pendingItems.length === 0) {
        this.$message.warning('没有待审核的申请')
        return
      }
      this.$confirm(`确定要批量通过 ${pendingItems.length} ä¸ªå¾…审核申请吗?`, '批量审核', {
        type: 'warning'
      }).then(async () => {
        try {
          this.loading = true
          // æ¨¡æ‹Ÿæ‰¹é‡å®¡æ ¸API调用
          await new Promise(resolve => setTimeout(resolve, 2000))
          // æ›´æ–°æ‰€æœ‰å¾…审核项的状态
          pendingItems.forEach(item => {
            item.reviewStatus = 1
            item.reviewer = '当前用户'
            item.reviewTime = new Date().toLocaleString()
          })
          this.$message.success(`批量审核通过成功,共处理 ${pendingItems.length} ä¸ªç”³è¯·`)
          this.calculateStats()
        } catch (error) {
          this.$message.error('批量审核失败')
        } finally {
          this.loading = false
        }
      })
    },
    // å¯¼å‡ºå®¡æ ¸æ•°æ®
    handleExport() {
      const exportData = this.generateMockData()
      // å®žé™…开发中这里应该调用导出API
      console.log('导出数据:', exportData)
      this.$message.info('导出功能开发中,数据已打印到控制台')
    }
  },
  watch: {
    // ç›‘听审核状态变化,动态设置验证规则 [6](@ref)
    'reviewForm.reviewStatus': function(newVal) {
      this.$nextTick(() => {
        if (this.$refs.reviewFormRef) {
          this.$refs.reviewFormRef.clearValidate()
        }
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.contract-review-page {
  padding: 20px;
  background: #f5f7fa;
  min-height: calc(100vh - 60px);
  .search-card {
    margin-bottom: 20px;
    ::v-deep .el-form-item {
      margin-bottom: 0;
    }
  }
  .stats-row {
    margin-bottom: 20px;
    .stat-item {
      text-align: center;
      padding: 20px;
      .stat-number {
        font-size: 32px;
        font-weight: bold;
        margin-bottom: 8px;
      }
      .stat-label {
        font-size: 14px;
        color: #666;
      }
    }
  }
  .patient-info {
    .patient-name {
      font-weight: 600;
      margin-bottom: 4px;
      color: #303133;
    }
    .patient-detail {
      font-size: 12px;
      color: #909399;
    }
  }
  // å®¡æ ¸çŠ¶æ€æ ·å¼
  .review-status {
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 500;
    &.status-pending {
      background: #fdf6ec;
      color: #e6a23c;
    }
    &.status-approved {
      background: #f0f9e8;
      color: #67c23a;
    }
    &.status-rejected {
      background: #fef0f0;
      color: #f56c6c;
    }
  }
  // ç‰¹æ®Šè¦æ±‚文本样式
  .special-requirements {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    &:hover {
      white-space: normal;
      overflow: visible;
      background: white;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      padding: 8px;
      border-radius: 4px;
      position: absolute;
      z-index: 1000;
      max-width: 300px;
    }
  }
  // è¡¨æ ¼æ ·å¼
  ::v-deep .el-table {
    .el-table__header-wrapper {
      th {
        background-color: #f5f7fa;
        color: #606266;
        font-weight: 600;
      }
    }
    .el-table__body {
      tr {
        transition: all 0.3s ease;
        &:hover {
          transform: translateY(-1px);
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
        &.pending-row {
          background: #fdf6ec !important;
          &:hover {
            background: #faf2e6 !important;
          }
        }
      }
    }
  }
  // å®¡æ ¸å¯¹è¯æ¡†æ ·å¼
  .review-dialog {
    ::v-deep .el-dialog {
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
    .dialog-footer {
      text-align: right;
      margin-top: 20px;
    }
  }
  // æ“ä½œæŒ‰é’®æ ·å¼
  .action-buttons {
    display: flex;
    gap: 8px;
    .el-button {
      padding: 7px 12px;
      border-radius: 4px;
      font-size: 12px;
      &.approve-btn {
        background: #67c23a;
        border-color: #67c23a;
        color: white;
        &:hover {
          background: #5daf34;
          border-color: #5daf34;
        }
      }
      &.reject-btn {
        background: #f56c6c;
        border-color: #f56c6c;
        color: white;
        &:hover {
          background: #e65c5c;
          border-color: #e65c5c;
        }
      }
      &.detail-btn {
        color: #409eff;
        border-color: #409eff;
        &:hover {
          background: #ecf5ff;
        }
      }
    }
  }
  // æ‰¹é‡æ“ä½œæ 
  .batch-actions {
    background: #ecf5ff;
    padding: 12px 20px;
    margin-bottom: 16px;
    border-radius: 4px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .batch-info {
      color: #409eff;
      font-size: 14px;
    }
  }
  // ç©ºçŠ¶æ€æ ·å¼
  .empty-state {
    text-align: center;
    padding: 40px 20px;
    color: #909399;
    .empty-icon {
      font-size: 48px;
      margin-bottom: 16px;
      opacity: 0.5;
    }
    .empty-text {
      font-size: 14px;
    }
  }
  // å“åº”式设计
  @media (max-width: 768px) {
    padding: 10px;
    .stats-row {
      .el-col {
        margin-bottom: 10px;
      }
    }
    .action-buttons {
      flex-direction: column;
    }
    .batch-actions {
      flex-direction: column;
      gap: 10px;
      align-items: stretch;
    }
  }
}
</style>
src/views/patient/SignAcontract/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,512 @@
<template>
  <div class="signed-patient-page">
    <!-- æœç´¢ç­›é€‰åŒºåŸŸ -->
    <el-card class="search-card" shadow="never">
      <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="100px">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-form-item label="患者姓名" prop="patientName">
              <el-input
                v-model="queryParams.patientName"
                placeholder="请输入患者姓名"
                clearable
                @keyup.enter="handleQuery"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="签约状态" prop="contractStatus">
              <el-select v-model="queryParams.contractStatus" placeholder="请选择状态" clearable>
                <el-option label="正常服务中" value="1" />
                <el-option label="即将到期" value="2" />
                <el-option label="已到期" value="3" />
                <el-option label="已终止" value="4" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="服务套餐" prop="servicePackage">
              <el-select v-model="queryParams.servicePackage" placeholder="请选择套餐" clearable>
                <el-option label="基础健康管理包" value="1" />
                <el-option label="慢性病管理包" value="2" />
                <el-option label="老年人健康包" value="3" />
                <el-option label="孕产妇保健包" value="4" />
                <el-option label="儿童保健包" value="5" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
              <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </el-card>
    <!-- ç»Ÿè®¡ä¿¡æ¯å¡ç‰‡ -->
    <el-row :gutter="20" class="stats-row">
      <el-col :span="6">
        <el-card class="stats-card" shadow="hover">
          <div class="stats-content">
            <div class="stats-number">{{ stats.total }}</div>
            <div class="stats-label">总签约患者</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="stats-card" shadow="hover">
          <div class="stats-content">
            <div class="stats-number" style="color: #67C23A;">{{ stats.active }}</div>
            <div class="stats-label">正常服务中</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="stats-card" shadow="hover">
          <div class="stats-content">
            <div class="stats-number" style="color: #E6A23C;">{{ stats.expiring }}</div>
            <div class="stats-label">即将到期</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="stats-card" shadow="hover">
          <div class="stats-content">
            <div class="stats-number" style="color: #F56C6C;">{{ stats.expired }}</div>
            <div class="stats-label">已到期/终止</div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <el-card shadow="never">
      <el-table
        v-loading="loading"
        :data="patientList"
        @selection-change="handleSelectionChange"
        style="width: 100%"
        :default-sort="{prop: 'signDate', order: 'descending'}"
      >
        <el-table-column type="selection" width="55" />
        <el-table-column label="患者信息" min-width="180" fixed>
          <template slot-scope="scope">
            <div class="patient-info">
              <div class="patient-name">{{ scope.row.patientName }}</div>
              <div class="patient-detail">
                {{ scope.row.gender }} | {{ scope.row.age }}岁 | {{ scope.row.phone }}
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="身份证号" prop="idCard" width="180" />
        <el-table-column label="签约医生" prop="doctorName" width="120" />
        <el-table-column label="服务套餐" min-width="150">
          <template slot-scope="scope">
            <el-tag :type="getPackageType(scope.row.servicePackageId)">
              {{ scope.row.servicePackage }}
            </el-tag>
            <div style="font-size: 12px; color: #666; margin-top: 4px;">
              å‘¨æœŸ: {{ scope.row.contractPeriod }}å¹´
            </div>
          </template>
        </el-table-column>
        <el-table-column label="包含服务" min-width="200">
          <template slot-scope="scope">
            <el-tooltip effect="dark" :content="scope.row.services.join('、')" placement="top">
              <span>{{ scope.row.services.slice(0, 2).join('、') }}等{{ scope.row.services.length }}项</span>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="签约时间" prop="signDate" width="120" sortable />
        <el-table-column label="到期时间" prop="expireDate" width="120" />
        <el-table-column label="剩余天数" width="100">
          <template slot-scope="scope">
            <span :class="getRemainingDaysClass(scope.row.remainingDays)">
              {{ scope.row.remainingDays }}天
            </span>
          </template>
        </el-table-column>
        <el-table-column label="签约状态" width="100" fixed="right">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.contractStatus)" effect="dark">
              {{ getStatusText(scope.row.contractStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200" fixed="right">
          <template slot-scope="scope">
            <el-button size="mini" type="text" @click="handleView(scope.row)">详情</el-button>
            <el-button
              size="mini"
              type="text"
              @click="handleRenew(scope.row)"
              :disabled="scope.row.contractStatus === 1"
            >续约</el-button>
            <el-button
              size="mini"
              type="text"
              @click="handleTerminate(scope.row)"
              :disabled="scope.row.contractStatus === 4"
              style="color: #F56C6C;"
            >终止</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>
  </div>
</template>
<script>
export default {
  name: 'SignedPatientList',
  data() {
    return {
      loading: false,
      ids: [],
      stats: {
        total: 0,
        active: 0,
        expiring: 0,
        expired: 0
      },
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        patientName: undefined,
        contractStatus: undefined,
        servicePackage: undefined
      },
      total: 0,
      patientList: [],
      // æœåŠ¡å¥—é¤é…ç½®
      servicePackages: {
        '1': {
          name: '基础健康管理包',
          services: ['年度健康评估', '在线健康咨询', '健康档案管理', '定期健康提醒'],
          price: 0,
          color: 'info'
        },
        '2': {
          name: '慢性病管理包',
          services: ['专属医生服务', '用药指导管理', '定期随访监测', '个性化康复计划', '紧急医疗咨询'],
          price: 299,
          color: 'success'
        },
        '3': {
          name: '老年人健康包',
          services: ['跌倒风险评估', '康复训练指导', '用药安全管理', '定期上门访视', '紧急联系服务', '心理健康关怀'],
          price: 499,
          color: 'warning'
        },
        '4': {
          name: '孕产妇保健包',
          services: ['孕期健康管理', '产后康复指导', '新生儿护理咨询', '营养膳食建议', '心理情绪支持'],
          price: 399,
          color: 'danger'
        },
        '5': {
          name: '儿童保健包',
          services: ['生长发育监测', '疫苗接种管理', '常见病防治', '营养指导', '早期教育咨询'],
          price: 199,
          color: 'primary'
        }
      }
    }
  },
  created() {
    this.getList()
    this.calculateStats()
  },
  methods: {
    // ç”Ÿæˆæ›´çœŸå®žçš„æ¨¡æ‹Ÿæ•°æ®
   // ç²¾ç®€åŽçš„æ¨¡æ‹Ÿæ•°æ®ç”Ÿæˆæ–¹æ³•
// ä¼˜åŒ–后的模拟数据生成方法
generateMockData() {
  const mockData = []
  // ä½¿ç”¨æ‚¨æä¾›çš„真实姓名列表
  const patientNames = [
    '李肇芬', '卢木仲', '李成白', '方兆玉', '刘翊惠', '丁汉臻', '吴佳瑞', '舒绿珮',
    '周白芷', '张姿妤', '张虹伦', '周琼玟', '倪怡芳', '郭贵妃', '杨佩芳', '黄文旺',
    '黄盛玫', '郑丽青', '许智云', '张孟涵', '李小爱', '王恩龙', '朱政廷', '邓诗涵',
    '陈政倩', '吴俊伯', '阮馨学', '翁惠珠', '吴思翰', '林佩玲'
  ]
  const doctors = ['王医生', '李医生', '张医生', '刘医生', '陈医生']
  const cities = ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市']
  const areas = ['朝阳区', '海淀区', '浦东新区', '黄浦区', '天河区', '福田区', '西湖区']
  // ç”Ÿæˆçº¦20条数据
  for (let i = 0; i < patientNames.length; i++) {
    const packageId = (i % 5) + 1 + ''
    const packageInfo = this.servicePackages[packageId]
    // ç”Ÿæˆæ›´åˆç†çš„签约时间(过去1年内)
    const signDate = this.generateRandomDate('2023-12-01', '2024-11-30')
    const contractPeriod = [1, 2][i % 2] // 1年或2年合同
    const expireDate = this.addYears(signDate, contractPeriod)
    const remainingDays = this.calculateRemainingDays(expireDate)
    const contractStatus = this.getContractStatus(expireDate, remainingDays)
    // ç”Ÿæˆæ›´çœŸå®žçš„电话号码和身份证号
    const phonePrefix = ['138', '139', '150', '151', '152', '186', '187', '188']
    const phone = `${phonePrefix[i % phonePrefix.length]}${this.padNumber(1000 + i * 37, 4)}${this.padNumber(i % 100, 2)}`
    // ç”Ÿæˆåˆç†çš„年龄(20-80岁)
    const age = 20 + (i % 60)
    const birthYear = new Date().getFullYear() - age
    const idCard = `11010${birthYear}${this.padNumber(1 + (i % 12), 2)}${this.padNumber(1 + (i % 28), 2)}${this.padNumber(i % 1000, 3)}X`
    mockData.push({
      id: `P${2024000 + i}`,
      patientName: patientNames[i],
      gender: i % 2 === 0 ? '男' : '女',
      age: age,
      phone: phone,
      idCard: idCard,
      doctorName: doctors[i % doctors.length],
      servicePackageId: packageId,
      servicePackage: packageInfo.name,
      services: packageInfo.services,
      contractPeriod: contractPeriod,
      signDate: signDate,
      expireDate: expireDate,
      remainingDays: remainingDays,
      contractStatus: contractStatus,
      address: `${cities[i % cities.length]}${areas[i % areas.length]}${this.generateStreet(i)}` // æ–°å¢žåœ°å€å­—段
    })
  }
  return mockData
},
// æ–°å¢žè¾…助方法:生成街道地址
generateStreet(index) {
  const streets = [
    '中山路123号', '人民路456号', '解放路789号', '建设路101号', '和平路202号',
    '新华路303号', '光明路404号', '幸福路505号', '团结路606号', '文明路707号'
  ]
  return streets[index % streets.length]
},
    // è¾…助方法
    generateRandomDate(start, end) {
      const startDate = new Date(start).getTime()
      const endDate = new Date(end).getTime()
      const randomTime = startDate + Math.random() * (endDate - startDate)
      return new Date(randomTime).toISOString().split('T')[0]
    },
    addYears(date, years) {
      const result = new Date(date)
      result.setFullYear(result.getFullYear() + years)
      return result.toISOString().split('T')[0]
    },
    calculateRemainingDays(expireDate) {
      const today = new Date()
      const expire = new Date(expireDate)
      const diffTime = expire - today
      return Math.ceil(diffTime / (1000 * 60 * 60 * 24))
    },
    getContractStatus(expireDate, remainingDays) {
      if (remainingDays < 0) return 3 // å·²åˆ°æœŸ
      if (remainingDays <= 30) return 2 // å³å°†åˆ°æœŸ
      return 1 // æ­£å¸¸æœåС䏭
    },
    padNumber(num, length) {
      return num.toString().padStart(length, '0')
    },
    // èŽ·å–æ‚£è€…åˆ—è¡¨
    async getList() {
      this.loading = true
      try {
        // æ¨¡æ‹ŸAPI调用延迟
        await new Promise(resolve => setTimeout(resolve, 500))
        const allData = this.generateMockData()
        // ç®€å•的本地筛选
        let filteredData = allData.filter(item => {
          if (this.queryParams.patientName &&
              !item.patientName.includes(this.queryParams.patientName)) {
            return false
          }
          if (this.queryParams.contractStatus &&
              item.contractStatus !== parseInt(this.queryParams.contractStatus)) {
            return false
          }
          if (this.queryParams.servicePackage &&
              item.servicePackageId !== this.queryParams.servicePackage) {
            return false
          }
          return true
        })
        // åˆ†é¡µå¤„理
        const start = (this.queryParams.pageNum - 1) * this.queryParams.pageSize
        const end = start + this.queryParams.pageSize
        this.patientList = filteredData.slice(start, end)
        this.total = filteredData.length
        this.calculateStats()
      } catch (error) {
        console.error('获取数据失败:', error)
        this.$message.error('数据加载失败')
      } finally {
        this.loading = false
      }
    },
    // è®¡ç®—统计信息
    calculateStats() {
      const allData = this.generateMockData()
      this.stats.total = allData.length
      this.stats.active = allData.filter(item => item.contractStatus === 1).length
      this.stats.expiring = allData.filter(item => item.contractStatus === 2).length
      this.stats.expired = allData.filter(item => item.contractStatus === 3).length
    },
    // çŠ¶æ€ç›¸å…³æ–¹æ³•
    getStatusText(status) {
      const statusMap = { 1: '正常服务中', 2: '即将到期', 3: '已到期', 4: '已终止' }
      return statusMap[status] || '未知'
    },
    getStatusType(status) {
      const typeMap = { 1: 'success', 2: 'warning', 3: 'danger', 4: 'info' }
      return typeMap[status] || 'info'
    },
    getPackageType(packageId) {
      const typeMap = { '1': 'info', '2': 'success', '3': 'warning', '4': 'danger', '5': 'primary' }
      return typeMap[packageId] || 'info'
    },
    getRemainingDaysClass(days) {
      if (days < 0) return 'expired'
      if (days <= 30) return 'expiring'
      return 'normal'
    },
    // æ“ä½œæ–¹æ³•
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    resetQuery() {
      this.queryParams = {
        pageNum: 1,
        pageSize: 10,
        patientName: undefined,
        contractStatus: undefined,
        servicePackage: undefined
      }
      this.handleQuery()
    },
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id)
    },
    handleView(row) {
      this.$message.info(`查看患者 ${row.patientName} çš„详情`)
      // å®žé™…开发中跳转到详情页
      // this.$router.push({ path: '/patient/contract/detail', query: { id: row.id } })
    },
    handleRenew(row) {
      this.$confirm(`确定要为患者 ${row.patientName} åŠžç†ç»­çº¦å—ï¼Ÿ`, '提示', {
        type: 'warning'
      }).then(() => {
        this.$message.success('续约操作成功')
      })
    },
    handleTerminate(row) {
      this.$confirm(`确定要终止与 ${row.patientName} çš„签约关系吗?此操作不可撤销。`, '警告', {
        type: 'error',
        confirmButtonText: '确定终止',
        cancelButtonText: '取消'
      }).then(() => {
        this.$message.success('签约关系已终止')
        this.getList()
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.signed-patient-page {
  padding: 20px;
  .search-card {
    margin-bottom: 20px;
  }
  .stats-row {
    margin-bottom: 20px;
    .stats-card {
      .stats-content {
        text-align: center;
        padding: 10px;
        .stats-number {
          font-size: 28px;
          font-weight: bold;
          color: #409EFF;
          margin-bottom: 8px;
        }
        .stats-label {
          font-size: 14px;
          color: #666;
        }
      }
    }
  }
  .patient-info {
    .patient-name {
      font-weight: 600;
      margin-bottom: 4px;
    }
    .patient-detail {
      font-size: 12px;
      color: #666;
    }
  }
  .expired {
    color: #F56C6C;
    font-weight: bold;
  }
  .expiring {
    color: #E6A23C;
    font-weight: bold;
  }
  .normal {
    color: #67C23A;
  }
}
</style>
src/views/patient/patient/index.vue
@@ -73,20 +73,22 @@
                  @keyup.enter.native="handleQuery"
                />
              </el-form-item>
              <!-- <el-form-item label="患者范围" prop="tagId">
              <el-form-item label="患者性别" prop="tagId">
                <el-select
                  v-model="queryParams.searchscope"
                  placeholder="请选择患者范围"
                  v-model="queryParams.sex"
                  placeholder="请选择患者性别"
                >
                  <el-option
                    v-for="item in source"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  >
                  </el-option>
                  <el-option label="男" :value="1"> </el-option>
                  <el-option label="女" :value="2"> </el-option>
                </el-select>
              </el-form-item> -->
              </el-form-item>
              <el-form-item label="患者年龄" prop="telcode">
                <el-input
                  v-model="queryParams.age"
                  placeholder="请输入查询年龄"
                  @keyup.enter.native="handleQuery"
                />
              </el-form-item>
              <el-form-item label="联系电话" prop="telcode">
                <el-input
                  v-model="queryParams.telcode"
@@ -313,14 +315,14 @@
                      ><i class="el-icon-edit"></i>患者过滤</span
                    ></el-button
                  >
                  <!-- <el-button
                  <el-button
                    size="medium"
                    type="text"
                    @click="Distributionservice(scope.row)"
                    @click="openContractDialog(scope.row)"
                    ><span class="button-textxg"
                      ><i class="el-icon-menu"></i>服务</span
                      ><i class="el-icon-menu"></i>患者签约</span
                    ></el-button
                  > -->
                  >
                  <!-- <el-button
                    size="medium"
                    type="text"
@@ -738,20 +740,123 @@
      </div>
    </el-dialog>
    <!-- è·³è½¬æœåŠ¡å¯¹è¯æ¡† -->
    <el-dialog title="选择服务类型" :visible.sync="serviceVisible">
      <el-card class="box-card">
        <el-radio-group v-model="serviceradio">
          <el-radio :label="1">宣教随访</el-radio>
          <el-radio :label="2">门诊服务</el-radio>
          <el-radio :label="3">出院服务</el-radio>
          <el-radio :label="4">复诊服务</el-radio>
          <el-radio :label="5">体检通知</el-radio>
          <el-radio :label="6">问卷服务</el-radio>
    <!-- ç®€åŒ–版患者签约对话框 -->
    <el-dialog
      title="患者签约服务"
      :visible.sync="contractDialogVisible"
      width="600px"
    >
      <!-- æ­¥éª¤æŒ‡ç¤ºå™¨ -->
      <el-steps
        :active="contractStep"
        align-center
        simple
        style="margin-bottom: 20px"
      >
        <el-step title="选择服务" icon="el-icon-document"></el-step>
        <el-step title="确认签约" icon="el-icon-finished"></el-step>
      </el-steps>
      <!-- æ­¥éª¤1: æœåŠ¡é€‰æ‹© -->
      <div v-if="contractStep === 1" class="step-content">
        <h4>请为 {{ currentPatient.name }} é€‰æ‹©ç­¾çº¦æœåŠ¡å¥—é¤ï¼š</h4>
        <el-radio-group
          v-model="tempContractData.servicePackage"
          style="width: 100%"
        >
          <el-row :gutter="16">
            <el-col :span="8" v-for="pkg in servicePackages" :key="pkg.id">
              <el-card
                :class="[
                  'package-card',
                  { active: tempContractData.servicePackage === pkg.id },
                ]"
                @click.native="tempContractData.servicePackage = pkg.id"
                shadow="hover"
                style="margin-bottom: 16px; cursor: pointer"
              >
                <div style="text-align: center">
                  <h4>{{ pkg.name }}</h4>
                  <p style="color: #666; font-size: 12px; margin: 8px 0">
                    {{ pkg.description }}
                  </p>
                  <p style="color: #e6a23c; font-weight: bold">
                    {{ pkg.price > 0 ? `Â¥${pkg.price}/å¹´` : "免费" }}
                  </p>
                  <el-tag
                    v-for="feature in pkg.features"
                    :key="feature"
                    size="mini"
                    style="margin: 2px"
                    type="info"
                    >{{ feature }}</el-tag
                  >
                </div>
              </el-card>
            </el-col>
          </el-row>
        </el-radio-group>
      </el-card>
        <el-form label-width="80px" style="margin-top: 20px">
          <el-form-item label="签约周期">
            <el-select
              v-model="tempContractData.contractPeriod"
              placeholder="请选择"
            >
              <el-option label="1å¹´" :value="1"></el-option>
              <el-option label="2å¹´" :value="2"></el-option>
              <el-option label="3å¹´" :value="3"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="备注信息">
            <el-input
              type="textarea"
              :rows="2"
              v-model="tempContractData.remark"
              placeholder="可填写特殊健康需求或备注信息"
            ></el-input>
          </el-form-item>
        </el-form>
      </div>
      <!-- æ­¥éª¤2: ç­¾çº¦ç¡®è®¤ -->
      <div v-if="contractStep === 2" class="step-content">
        <el-card>
          <h4>签约信息确认</h4>
          <el-descriptions :column="1" border>
            <el-descriptions-item label="患者姓名">{{
              currentPatient.name
            }}</el-descriptions-item>
            <el-descriptions-item label="患者编号">{{
              currentPatient.patientno
            }}</el-descriptions-item>
            <el-descriptions-item label="服务套餐">
              {{ getSelectedPackage().name }}
            </el-descriptions-item>
            <el-descriptions-item label="签约周期"
              >{{ tempContractData.contractPeriod }}å¹´</el-descriptions-item
            >
            <el-descriptions-item label="签约日期">{{
              new Date().toLocaleDateString()
            }}</el-descriptions-item>
            <el-descriptions-item label="备注信息">{{
              tempContractData.remark || "无"
            }}</el-descriptions-item>
          </el-descriptions>
        </el-card>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="serviceVisible = false">取 æ¶ˆ</el-button>
        <el-button type="primary" @click="CreateService">创建服务</el-button>
        <el-button @click="prevStep" v-if="contractStep > 1">上一步</el-button>
        <el-button @click="closeContractDialog">取消</el-button>
        <el-button
          type="primary"
          @click="nextStep"
          :disabled="contractStep === 1 && !tempContractData.servicePackage"
        >
          {{ contractStep === 2 ? "确认签约" : "下一步" }}
        </el-button>
      </div>
    </el-dialog>
    <!-- é£Žé™©ç±»åž‹ -->
@@ -846,20 +951,87 @@
      serviceradio: 1,
      distributeVisible: false,
      RiskVisible: false,
      tasktopic: "5", //新增类型
      tasktopic: "2", //新增类型
      Riskradio: 1,
      RiskObj: {},
      // æŸ¥è¯¢å‚æ•°
      topqueryParams: {
        pageNum: 1,
        pageSize: 10,
        type: 2,
        userName: undefined,
        tagid: undefined,
        topic: undefined,
      },
      // æ—¥æœŸèŒƒå›´
      dateRange: [],
      taskoptions: [],
      contractDialogVisible: false, // æŽ§åˆ¶ç­¾çº¦å¯¹è¯æ¡†æ˜¾ç¤º
      contractStep: 1, // ç­¾çº¦æ­¥éª¤ï¼š1-选择服务 2-确认信息
      currentPatient: {}, // å½“前签约的患者信息
      tempContractData: {
        // ä¸´æ—¶å­˜å‚¨çš„签约数据
        servicePackage: null, // é€‰ä¸­çš„æœåС套餐
        contractPeriod: 1, // ç­¾çº¦å‘¨æœŸï¼ˆå¹´ï¼‰
        remark: "", // å¤‡æ³¨ä¿¡æ¯
      },
      // æ¨¡æ‹Ÿæ•°æ®ï¼šå¯é€‰çš„签约服务套餐
      servicePackages: [
        {
          id: 1,
          name: "基础健康管理包",
          description: "包含定期健康评估、基本咨询",
          price: 0,
          features: ["年度健康评估", "在线咨询"],
        },
        {
          id: 2,
          name: "慢性病管理包",
          description: "专为慢性病患者设计",
          price: 299,
          features: ["专属医生", "用药提醒", "定期随访"],
        },
        {
          id: 3,
          name: "老年人健康包",
          description: "关注老年人健康问题",
          price: 499,
          features: ["跌倒风险评估", "康复指导", "紧急联系"],
        },
      ],
      taskoptions: [
        // {
        //   value: "1",
        //   label: "监测评估",
        // },
        {
          value: "2",
          label: "出院随访",
        },
        {
          value: "3",
          label: "门诊随访",
        },
        {
          value: "4",
          label: "宣教关怀",
        },
        {
          value: "5",
          label: "复诊管理",
        },
        // {
        //   value: "6",
        //   label: "满意度调查",
        // },
        {
          value: "7",
          label: "患者报告",
        },
        {
          value: "8",
          label: "其他通知",
        },
      ],
      paperstypes: [
        { papersname: "身份证" },
        { papersname: "护照" },
@@ -970,6 +1142,7 @@
      queryParams: {
        pageNum: 1,
        allhosp: "0",
        sex: 1,
        pageSize: 10,
        searchscope: 2,
        notrequiredFlag: 0,
@@ -1031,8 +1204,12 @@
  created() {
    this.getList();
    this.gettabList();
    this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
      (obj) => obj.deptCode
    );
    this.topqueryParams.leavehospitaldistrictcodes =
      store.getters.belongWards.map((obj) => obj.districtCode);
    //获取已筛选后的可选任务类型
    this.taskoptions = store.getters.Serviceauthority;
  },
  methods: {
    /** æŸ¥è¯¢æ‚£è€…列表 */
@@ -1090,8 +1267,76 @@
        this.loading = false;
      });
    },
    Distributionservice(row) {
      this.serviceVisible = true;
    openContractDialog(row) {
      this.currentPatient = { ...row }; // è®¾ç½®å½“前患者
      this.contractDialogVisible = true;
      this.contractStep = 1;
      // é‡ç½®è¡¨å•数据
      this.tempContractData = {
        servicePackage: null,
        contractPeriod: 1,
        remark: "",
      };
    },
    // ä¸‹ä¸€æ­¥æ“ä½œ
    nextStep() {
      if (this.contractStep < 2) {
        this.contractStep++;
      } else {
        this.submitContract();
      }
    },
    // ä¸Šä¸€æ­¥æ“ä½œ
    prevStep() {
      if (this.contractStep > 1) {
        this.contractStep--;
      }
    },
    // èŽ·å–é€‰ä¸­çš„æœåŠ¡å¥—é¤ä¿¡æ¯
    getSelectedPackage() {
      return (
        this.servicePackages.find(
          (pkg) => pkg.id === this.tempContractData.servicePackage
        ) || {}
      );
    },
    // æ¨¡æ‹Ÿæäº¤ç­¾çº¦ä¿¡æ¯
    submitContract() {
      // è¿™é‡Œæ˜¯å‰ç«¯æ¨¡æ‹Ÿæ“ä½œï¼Œå®žé™…开发中应通过API提交数据
      const contractInfo = {
        patientId: this.currentPatient.id,
        patientName: this.currentPatient.name,
        package: this.getSelectedPackage(),
        period: this.tempContractData.contractPeriod,
        signDate: new Date().toISOString().split("T")[0],
        remark: this.tempContractData.remark,
      };
      console.log("模拟签约数据:", contractInfo);
      // æ¨¡æ‹ŸæˆåŠŸæç¤º
      this.$message.success(
        `已成功为 ${this.currentPatient.name} ç­¾çº¦ ${
          this.getSelectedPackage().name
        }`
      );
      // å…³é—­å¯¹è¯æ¡†
      this.closeContractDialog();
      // å¯ä»¥åœ¨è¿™é‡Œè§¦å‘其他操作,如刷新患者列表等
    },
    // å…³é—­å¯¹è¯æ¡†å¹¶é‡ç½®çŠ¶æ€
    closeContractDialog() {
      this.contractDialogVisible = false;
      this.contractStep = 1;
      this.tempContractData = {
        servicePackage: null,
        contractPeriod: 1,
        remark: "",
      };
    },
    RiskMarker(row) {
      this.RiskVisible = true;
@@ -1131,7 +1376,7 @@
        pageSize: 10,
        searchscope: 2,
      };
        this.handleQuery();
      this.handleQuery();
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
@@ -1148,12 +1393,12 @@
    },
    /** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
    handleUpdate(row) {
      const userIds = row.id || this.ids;
      particularpatient(userIds).then((response) => {
        this.form = response.data;
      });
      this.amendtag = true;
      this.Labelchange = true;
      // const userIds = row.id || this.ids;
      // particularpatient(userIds).then((response) => {
      //   this.form = response.data;
      // });
      // this.amendtag = true;
      // this.Labelchange = true;
    },
    //修改/新增患者
    submitForm() {
@@ -1223,23 +1468,20 @@
    },
    distribute() {
      this.distributeVisible = true;
      if (this.tasktopic == 1) {
        this.topqueryParams.type = 3;
      } else if (this.tasktopic == 2) {
        this.topqueryParams.type = 1;
      } else if (this.tasktopic == 3) {
        this.topqueryParams.type = 1;
      } else if (this.tasktopic == 4) {
        this.topqueryParams.type = 1;
      if (
        this.tasktopic == 2 ||
        this.tasktopic == 3 ||
        this.tasktopic == 1 ||
        this.tasktopic == 7 ||
        this.tasktopic == 6
      ) {
        this.topqueryParams.type = "2";
      } else if (this.tasktopic == 4 || this.tasktopic == 8) {
        this.topqueryParams.type = "3";
      } else if (this.tasktopic == 5) {
        this.topqueryParams.type = 1;
      } else if (this.tasktopic == 6) {
        this.topqueryParams.type = 2;
        this.topqueryParams.type = "1";
      }
      this.topqueryParams.typename = this.findLabelByValue(
        this.taskoptions,
        this.tasktopic
      );
      this.topqueryParams.serviceType = Number(this.tasktopic);
      getTasklist(this.topqueryParams).then((response) => {
        this.taskuserList = response.rows;
        this.tasktotal = response.total;
@@ -1345,6 +1587,18 @@
    display: center !important;
  }
}
.package-card.active {
  border-color: #409EFF;
  background-color: #f0f9ff;
}
.step-content {
  min-height: 300px;
}
.dialog-footer {
  text-align: right;
}
.preview-left {
  margin: 20px;
  //   margin: 20px;
src/views/patient/patient/profile/index.vue
@@ -212,6 +212,316 @@
                </el-form-item>
              </el-col>
            </el-row>
            <!-- ç­›æŸ¥æ‘˜è¦æ¨¡å— -->
            <el-row :gutter="20">
              <el-col :span="12">
                <div class="screening-summary">
                  <div class="summary-header">
                    <i class="el-icon-search"></i>
                    <span>筛查摘要</span>
                    <div
                      style="
                        margin-left: auto;
                        display: flex;
                        align-items: center;
                      "
                    >
                      <el-button
                        type="primary"
                        size="mini"
                        @click="addScreening"
                      >
                        <i class="el-icon-plus"></i> æ–°å¢ž
                      </el-button>
                      <el-button
                        type="text"
                        size="mini"
                        @click="refreshScreeningData"
                        style="margin-left: 10px"
                      >
                        <i class="el-icon-refresh"></i> åˆ·æ–°
                      </el-button>
                    </div>
                  </div>
                  <div class="summary-content">
                    <el-table
                      :data="screeningSummaryData"
                      border
                      size="mini"
                      height="200"
                      v-loading="screeningLoading"
                    >
                      <el-table-column
                        prop="screeningType"
                        label="筛查类型"
                        width="100"
                      >
                        <template slot-scope="scope">
                          <el-tag
                            :type="getScreeningTagType(scope.row.screeningType)"
                          >
                            {{ scope.row.screeningType }}
                          </el-tag>
                        </template>
                      </el-table-column>
                      <el-table-column
                        prop="screeningDate"
                        label="筛查日期"
                        width="100"
                      >
                        <template slot-scope="scope">
                          {{ formatTime(scope.row.screeningDate) }}
                        </template>
                      </el-table-column>
                      <el-table-column prop="result" label="结果" width="80">
                        <template slot-scope="scope">
                          <el-tag
                            :type="
                              scope.row.result === '正常'
                                ? 'success'
                                : scope.row.result === '异常'
                                ? 'danger'
                                : 'warning'
                            "
                            size="small"
                          >
                            {{ scope.row.result }}
                          </el-tag>
                        </template>
                      </el-table-column>
                      <el-table-column
                        prop="details"
                        label="详细结果"
                        min-width="120"
                      >
                        <template slot-scope="scope">
                          <el-tooltip
                            :content="scope.row.details"
                            placement="top"
                            v-if="
                              scope.row.details && scope.row.details.length > 10
                            "
                          >
                            <span
                              >{{ scope.row.details.substring(0, 10) }}...</span
                            >
                          </el-tooltip>
                          <span v-else>{{ scope.row.details }}</span>
                        </template>
                      </el-table-column>
                      <el-table-column label="操作" width="150" fixed="right">
                        <template slot-scope="scope">
                          <el-button
                            type="primary"
                            size="mini"
                            @click="editScreening(scope.$index, scope.row)"
                          >
                            ç¼–辑
                          </el-button>
                          <el-button
                            type="danger"
                            size="mini"
                            @click="deleteScreening(scope.$index, scope.row)"
                          >
                            åˆ é™¤
                          </el-button>
                        </template>
                      </el-table-column>
                    </el-table>
                    <div class="summary-stats">
                      <el-row :gutter="10">
                        <el-col :span="8">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #67c23a">
                              {{ screeningStats.normal }}
                            </div>
                            <div class="stat-label">正常</div>
                          </div>
                        </el-col>
                        <el-col :span="8">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #e6a23c">
                              {{ screeningStats.abnormal }}
                            </div>
                            <div class="stat-label">异常</div>
                          </div>
                        </el-col>
                        <el-col :span="8">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #f56c6c">
                              {{ screeningStats.critical }}
                            </div>
                            <div class="stat-label">危急</div>
                          </div>
                        </el-col>
                      </el-row>
                    </div>
                  </div>
                </div>
              </el-col>
              <!-- æ…¢ç—…摘要模块 -->
              <el-col :span="12">
                <div class="chronic-disease-summary">
                  <div class="summary-header">
                    <i class="el-icon-document"></i>
                    <span>慢病摘要</span>
                    <div
                      style="
                        margin-left: auto;
                        display: flex;
                        align-items: center;
                      "
                    >
                      <el-button
                        type="primary"
                        size="mini"
                        @click="addChronicDisease"
                      >
                        <i class="el-icon-plus"></i> æ–°å¢ž
                      </el-button>
                      <el-button
                        type="text"
                        size="mini"
                        @click="refreshChronicData"
                        style="margin-left: 10px"
                      >
                        <i class="el-icon-refresh"></i> åˆ·æ–°
                      </el-button>
                    </div>
                  </div>
                  <div class="summary-content">
                    <el-table
                      :data="chronicDiseaseData"
                      border
                      size="mini"
                      height="200"
                      v-loading="chronicLoading"
                    >
                      <el-table-column
                        prop="diseaseName"
                        label="疾病名称"
                        width="120"
                      >
                        <template slot-scope="scope">
                          <el-tag
                            :type="getDiseaseTagType(scope.row.diseaseName)"
                          >
                            {{ scope.row.diseaseName }}
                          </el-tag>
                        </template>
                      </el-table-column>
                      <el-table-column
                        prop="diagnoseDate"
                        label="确诊日期"
                        width="100"
                      >
                        <template slot-scope="scope">
                          {{ formatTime(scope.row.diagnoseDate) }}
                        </template>
                      </el-table-column>
                      <el-table-column prop="status" label="状态" width="80">
                        <template slot-scope="scope">
                          <el-tag
                            :type="
                              scope.row.status === '稳定'
                                ? 'success'
                                : scope.row.status === '活动期'
                                ? 'warning'
                                : 'danger'
                            "
                            size="small"
                          >
                            {{ scope.row.status }}
                          </el-tag>
                        </template>
                      </el-table-column>
                      <el-table-column
                        prop="currentTreatment"
                        label="当前治疗"
                        min-width="120"
                      >
                        <template slot-scope="scope">
                          <el-tooltip
                            :content="scope.row.currentTreatment"
                            placement="top"
                            v-if="
                              scope.row.currentTreatment &&
                              scope.row.currentTreatment.length > 10
                            "
                          >
                            <span
                              >{{
                                scope.row.currentTreatment.substring(0, 10)
                              }}...</span
                            >
                          </el-tooltip>
                          <span v-else>{{ scope.row.currentTreatment }}</span>
                        </template>
                      </el-table-column>
                      <el-table-column label="操作" width="150" fixed="right">
                        <template slot-scope="scope">
                          <el-button
                            type="primary"
                            size="mini"
                            @click="editChronicDisease(scope.$index, scope.row)"
                          >
                            ç¼–辑
                          </el-button>
                          <el-button
                            type="danger"
                            size="mini"
                            @click="
                              deleteChronicDisease(scope.$index, scope.row)
                            "
                          >
                            åˆ é™¤
                          </el-button>
                        </template>
                      </el-table-column>
                    </el-table>
                    <div class="summary-stats">
                      <el-row :gutter="10">
                        <el-col :span="6">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #67c23a">
                              {{ chronicStats.stable }}
                            </div>
                            <div class="stat-label">稳定</div>
                          </div>
                        </el-col>
                        <el-col :span="6">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #e6a23c">
                              {{ chronicStats.active }}
                            </div>
                            <div class="stat-label">活动期</div>
                          </div>
                        </el-col>
                        <el-col :span="6">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #f56c6c">
                              {{ chronicStats.severe }}
                            </div>
                            <div class="stat-label">严重</div>
                          </div>
                        </el-col>
                        <el-col :span="6">
                          <div class="stat-item">
                            <div class="stat-value" style="color: #909399">
                              {{ chronicStats.total }}
                            </div>
                            <div class="stat-label">总数</div>
                          </div>
                        </el-col>
                      </el-row>
                    </div>
                  </div>
                </div>
              </el-col>
            </el-row>
          </el-form>
        </div>
      </div>
@@ -923,7 +1233,147 @@
        </div>
      </div> -->
    </div>
    <!-- ç­›æŸ¥æ‘˜è¦ç¼–辑对话框 -->
    <el-dialog
      :title="screeningEditing ? '编辑筛查记录' : '新增筛查记录'"
      :visible.sync="screeningDialogVisible"
      width="600px"
    >
      <el-form :model="screeningForm" label-width="100px">
        <el-form-item label="筛查类型" prop="screeningType" required>
          <el-select
            v-model="screeningForm.screeningType"
            placeholder="请选择筛查类型"
            style="width: 100%"
          >
            <el-option
              v-for="item in screeningTypeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="筛查日期" prop="screeningDate" required>
          <el-date-picker
            v-model="screeningForm.screeningDate"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            placeholder="选择筛查日期"
            style="width: 100%"
          >
          </el-date-picker>
        </el-form-item>
        <el-form-item label="筛查结果" prop="result" required>
          <el-select
            v-model="screeningForm.result"
            placeholder="请选择结果"
            style="width: 100%"
          >
            <el-option
              v-for="item in resultOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="详细结果" prop="details">
          <el-input
            type="textarea"
            :rows="3"
            v-model="screeningForm.details"
            placeholder="请输入详细结果信息"
          >
          </el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="screeningDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="saveScreening">确定</el-button>
      </div>
    </el-dialog>
    <!-- æ…¢ç—…摘要编辑对话框 -->
    <el-dialog
      :title="chronicEditing ? '编辑慢病记录' : '新增慢病记录'"
      :visible.sync="chronicDialogVisible"
      width="600px"
    >
      <el-form :model="chronicForm" label-width="100px">
        <el-form-item label="疾病名称" prop="diseaseName" required>
          <el-select
            v-model="chronicForm.diseaseName"
            placeholder="请选择疾病名称"
            style="width: 100%"
          >
            <el-option
              v-for="item in diseaseOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="确诊日期" prop="diagnoseDate" required>
          <el-date-picker
            v-model="chronicForm.diagnoseDate"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="选择确诊日期"
            style="width: 100%"
          >
          </el-date-picker>
        </el-form-item>
        <el-form-item label="当前状态" prop="status" required>
          <el-select
            v-model="chronicForm.status"
            placeholder="请选择状态"
            style="width: 100%"
          >
            <el-option
              v-for="item in statusOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="当前治疗" prop="currentTreatment">
          <el-input
            type="textarea"
            :rows="2"
            v-model="chronicForm.currentTreatment"
            placeholder="请输入当前治疗方案"
          >
          </el-input>
        </el-form-item>
        <el-form-item label="随访计划" prop="followUpPlan">
          <el-input
            v-model="chronicForm.followUpPlan"
            placeholder="请输入随访计划"
          >
          </el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="chronicDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="saveChronicDisease">确定</el-button>
      </div>
    </el-dialog>
    <el-dialog :title="titletb" :visible.sync="AddanumberVisible">
      <el-form :model="numberform" label-width="100px">
        <el-form-item label="姓名">
@@ -984,7 +1434,7 @@
          </el-date-picker> -->
          <el-date-picker
            v-model="borninfoform.generatedTime"
             value-format="yyyy-MM-dd HH:mm:ss"
            value-format="yyyy-MM-dd HH:mm:ss"
            type="datetime"
            placeholder="选择日期时间"
          >
@@ -1065,6 +1515,24 @@
      sonactiveName: "inhospital", //健康监测导航
      sontwoactiveName: "weight", //医疗档案导航
      dynamicTags: [],
      // ç­›æŸ¥æ‘˜è¦ç›¸å…³æ•°æ®
      screeningLoading: false,
      screeningSummaryData: [],
      screeningStats: {
        normal: 0,
        abnormal: 0,
        critical: 0,
      },
      // æ…¢ç—…摘要相关数据
      chronicLoading: false,
      chronicDiseaseData: [],
      chronicStats: {
        stable: 0,
        active: 0,
        severe: 0,
        total: 0,
      },
      borninforules: {
        height: [
          { required: true, message: "身长不能为空", trigger: "blur" },
@@ -1166,6 +1634,58 @@
      xtechartdom: {},
      tzechartdom: {},
      tableData: [],
      // ç­›æŸ¥æ‘˜è¦ç¼–辑相关
      screeningEditing: false,
      screeningEditIndex: -1,
      screeningEditTemp: {},
      screeningDialogVisible: false,
      screeningForm: {
        screeningType: "",
        screeningDate: "",
        result: "正常",
        details: "",
      },
      // æ…¢ç—…摘要编辑相关
      chronicEditing: false,
      chronicEditIndex: -1,
      chronicEditTemp: {},
      chronicDialogVisible: false,
      chronicForm: {
        diseaseName: "",
        diagnoseDate: "",
        status: "稳定",
        currentTreatment: "",
        followUpPlan: "",
      },
      // ç­›é€‰é€‰é¡¹
      resultOptions: [
        { label: "正常", value: "正常" },
        { label: "异常", value: "异常" },
        { label: "危急", value: "危急" },
      ],
      statusOptions: [
        { label: "稳定", value: "稳定" },
        { label: "活动期", value: "活动期" },
        { label: "严重", value: "严重" },
      ],
      screeningTypeOptions: [
        { label: "心血管", value: "心血管" },
        { label: "糖尿病", value: "糖尿病" },
        { label: "肿瘤标志", value: "肿瘤标志" },
        { label: "肾功能", value: "肾功能" },
        { label: "呼吸系统", value: "呼吸系统" },
      ],
      diseaseOptions: [
        { label: "高血压", value: "高血压" },
        { label: "2型糖尿病", value: "2型糖尿病" },
        { label: "冠心病", value: "冠心病" },
        { label: "慢性肾病", value: "慢性肾病" },
      ],
      tableDatalist: [
        {
          id: 12,
@@ -1277,6 +1797,9 @@
    this.id = this.$route.query.id;
    this.getuserinfo();
    this.gettabList();
    // åˆå§‹åŒ–筛查和慢病数据
    this.initScreeningData();
    this.initChronicDiseaseData();
  },
  methods: {
@@ -1306,6 +1829,147 @@
          }
        });
      }
    },
    /** ç­›æŸ¥æ‘˜è¦ - æ–°å¢ž */
    addScreening() {
      this.screeningEditing = false;
      this.screeningEditIndex = -1;
      this.screeningForm = {
        screeningType: "",
        screeningDate: new Date().toISOString().split("T")[0] + " 09:00:00",
        result: "正常",
        details: "",
      };
      this.screeningDialogVisible = true;
    },
    /** ç­›æŸ¥æ‘˜è¦ - ç¼–辑 */
    editScreening(index, row) {
      this.screeningEditing = true;
      this.screeningEditIndex = index;
      this.screeningForm = { ...row };
      this.screeningDialogVisible = true;
    },
    /** ç­›æŸ¥æ‘˜è¦ - ä¿å­˜ */
    saveScreening() {
      if (
        !this.screeningForm.screeningType ||
        !this.screeningForm.screeningDate
      ) {
        this.$message.error("请填写必填字段");
        return;
      }
      if (this.screeningEditing) {
        // ç¼–辑现有记录
        this.screeningSummaryData.splice(this.screeningEditIndex, 1, {
          ...this.screeningForm,
          id: this.screeningSummaryData[this.screeningEditIndex].id,
        });
        this.$message.success("筛查记录修改成功");
      } else {
        // æ–°å¢žè®°å½•
        const newRecord = {
          id: Date.now(), // ä¸´æ—¶ID
          ...this.screeningForm,
          riskLevel: this.getRiskLevelByResult(this.screeningForm.result),
        };
        this.screeningSummaryData.unshift(newRecord);
        this.$message.success("筛查记录新增成功");
      }
      this.calculateScreeningStats();
      this.screeningDialogVisible = false;
    },
    /** ç­›æŸ¥æ‘˜è¦ - åˆ é™¤ */
    deleteScreening(index, row) {
      this.$confirm("确定要删除这条筛查记录吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.screeningSummaryData.splice(index, 1);
          this.calculateScreeningStats();
          this.$message.success("删除成功");
        })
        .catch(() => {});
    },
    /** æ ¹æ®ç»“果获取风险等级 */
    getRiskLevelByResult(result) {
      const riskMap = {
        æ­£å¸¸: "low",
        å¼‚常: "medium",
        å±æ€¥: "critical",
      };
      return riskMap[result] || "low";
    },
    /** æ…¢ç—…摘要 - æ–°å¢ž */
    addChronicDisease() {
      this.chronicEditing = false;
      this.chronicEditIndex = -1;
      this.chronicForm = {
        diseaseName: "",
        diagnoseDate: new Date().toISOString().split("T")[0],
        status: "稳定",
        currentTreatment: "",
        followUpPlan: "每月复诊一次",
      };
      this.chronicDialogVisible = true;
    },
    /** æ…¢ç—…摘要 - ç¼–辑 */
    editChronicDisease(index, row) {
      this.chronicEditing = true;
      this.chronicEditIndex = index;
      this.chronicForm = { ...row };
      this.chronicDialogVisible = true;
    },
    /** æ…¢ç—…摘要 - ä¿å­˜ */
    saveChronicDisease() {
      if (!this.chronicForm.diseaseName || !this.chronicForm.diagnoseDate) {
        this.$message.error("请填写必填字段");
        return;
      }
      if (this.chronicEditing) {
        // ç¼–辑现有记录
        this.chronicDiseaseData.splice(this.chronicEditIndex, 1, {
          ...this.chronicForm,
          id: this.chronicDiseaseData[this.chronicEditIndex].id,
        });
        this.$message.success("慢病记录修改成功");
      } else {
        // æ–°å¢žè®°å½•
        const newRecord = {
          id: Date.now(), // ä¸´æ—¶ID
          ...this.chronicForm,
        };
        this.chronicDiseaseData.unshift(newRecord);
        this.$message.success("慢病记录新增成功");
      }
      this.calculateChronicStats();
      this.chronicDialogVisible = false;
    },
    /** æ…¢ç—…摘要 - åˆ é™¤ */
    deleteChronicDisease(index, row) {
      this.$confirm("确定要删除这条慢病记录吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.chronicDiseaseData.splice(index, 1);
          this.calculateChronicStats();
          this.$message.success("删除成功");
        })
        .catch(() => {});
    },
    checkAgeExists(newAge) {
      // å‡è®¾å·²æœ‰æ•°æ®å­˜å‚¨åœ¨ this.existingData ä¸­
@@ -1341,6 +2005,232 @@
      });
      // è”系信息
      this.getcontactlist();
    },
    /** åˆå§‹åŒ–筛查摘要数据 */
    initScreeningData() {
      // æ¨¡æ‹Ÿç­›æŸ¥æ‘˜è¦æ•°æ®[1,4](@ref)
      this.screeningSummaryData = [
        {
          id: 1,
          screeningType: "心血管",
          screeningDate: "2024-11-15 09:00:00",
          result: "异常",
          details: "心电图显示ST段压低,建议进一步检查",
          riskLevel: "high",
        },
        {
          id: 2,
          screeningType: "糖尿病",
          screeningDate: "2024-11-10 14:30:00",
          result: "正常",
          details: "空腹血糖5.6mmol/L,糖化血红蛋白5.8%",
          riskLevel: "low",
        },
        {
          id: 3,
          screeningType: "肿瘤标志",
          screeningDate: "2024-11-05 10:15:00",
          result: "危急",
          details: "CEA 15.2ng/mL,建议立即专科就诊",
          riskLevel: "critical",
        },
        {
          id: 4,
          screeningType: "肾功能",
          screeningDate: "2024-10-28 16:20:00",
          result: "异常",
          details: "肌酐清除率偏低,eGFR 55mL/min",
          riskLevel: "medium",
        },
        {
          id: 5,
          screeningType: "呼吸系统",
          screeningDate: "2024-10-20 11:00:00",
          result: "正常",
          details: "肺功能检查未见明显异常",
          riskLevel: "low",
        },
      ];
      // è®¡ç®—统计信息
      this.calculateScreeningStats();
    },
    /** è®¡ç®—筛查统计信息 */
    calculateScreeningStats() {
      this.screeningStats = {
        normal: this.screeningSummaryData.filter(
          (item) => item.result === "正常"
        ).length,
        abnormal: this.screeningSummaryData.filter(
          (item) => item.result === "异常"
        ).length,
        critical: this.screeningSummaryData.filter(
          (item) => item.result === "危急"
        ).length,
      };
    },
    /** åˆå§‹åŒ–慢病摘要数据 */
    initChronicDiseaseData() {
      // æ¨¡æ‹Ÿæ…¢ç—…摘要数据[2,5](@ref)
      this.chronicDiseaseData = [
        {
          id: 1,
          diseaseName: "高血压",
          diagnoseDate: "2020-03-15",
          status: "稳定",
          currentTreatment: "氨氯地平 5mg qd,定期监测血压",
          followUpPlan: "每月复诊一次",
        },
        {
          id: 2,
          diseaseName: "2型糖尿病",
          diagnoseDate: "2019-08-20",
          status: "活动期",
          currentTreatment: "二甲双胍 500mg bid,胰岛素注射",
          followUpPlan: "每两周复诊一次",
        },
        {
          id: 3,
          diseaseName: "冠心病",
          diagnoseDate: "2021-05-10",
          status: "稳定",
          currentTreatment: "阿司匹林 100mg qd,阿托伐他汀 20mg qd",
          followUpPlan: "每季度复诊一次",
        },
        {
          id: 4,
          diseaseName: "慢性肾病",
          diagnoseDate: "2022-01-30",
          status: "严重",
          currentTreatment: "控制血压、血糖,低蛋白饮食",
          followUpPlan: "每月专科随访",
        },
      ];
      // è®¡ç®—统计信息
      this.calculateChronicStats();
    },
    /** è®¡ç®—慢病统计信息 */
    calculateChronicStats() {
      this.chronicStats = {
        stable: this.chronicDiseaseData.filter((item) => item.status === "稳定")
          .length,
        active: this.chronicDiseaseData.filter(
          (item) => item.status === "活动期"
        ).length,
        severe: this.chronicDiseaseData.filter((item) => item.status === "严重")
          .length,
        total: this.chronicDiseaseData.length,
      };
    },
    /** èŽ·å–ç­›æŸ¥ç±»åž‹æ ‡ç­¾æ ·å¼ */
    getScreeningTagType(type) {
      const typeMap = {
        å¿ƒè¡€ç®¡: "danger",
        ç³–å°¿ç—…: "warning",
        è‚¿ç˜¤æ ‡å¿—: "danger",
        è‚¾åŠŸèƒ½: "warning",
        å‘¼å¸ç³»ç»Ÿ: "success",
      };
      return typeMap[type] || "info";
    },
    /** èŽ·å–ç–¾ç—…åç§°æ ‡ç­¾æ ·å¼ */
    getDiseaseTagType(diseaseName) {
      const diseaseMap = {
        é«˜è¡€åŽ‹: "warning",
        "2型糖尿病": "danger",
        å† å¿ƒç—…: "danger",
        æ…¢æ€§è‚¾ç—…: "danger",
      };
      return diseaseMap[diseaseName] || "info";
    },
    /** æŸ¥çœ‹ç­›æŸ¥è¯¦æƒ… */
    viewScreeningDetail(row) {
      this.$alert(
        `<div>
        <p><strong>筛查类型:</strong>${row.screeningType}</p>
        <p><strong>筛查日期:</strong>${this.formatTime(row.screeningDate)}</p>
        <p><strong>筛查结果:</strong><el-tag type="${
          row.result === "正常"
            ? "success"
            : row.result === "异常"
            ? "danger"
            : "warning"
        }">${row.result}</el-tag></p>
        <p><strong>详细结果:</strong>${row.details}</p>
        <p><strong>风险评估:</strong>${this.getRiskLevelText(
          row.riskLevel
        )}</p>
      </div>`,
        "筛查详情",
        {
          dangerouslyUseHTMLString: true,
          customClass: "detail-dialog",
        }
      );
    },
    /** æŸ¥çœ‹æ…¢ç—…详情 */
    viewChronicDetail(row) {
      this.$alert(
        `<div>
        <p><strong>疾病名称:</strong>${row.diseaseName}</p>
        <p><strong>确诊日期:</strong>${this.formatTime(row.diagnoseDate)}</p>
        <p><strong>当前状态:</strong><el-tag type="${
          row.status === "稳定"
            ? "success"
            : row.status === "活动期"
            ? "warning"
            : "danger"
        }">${row.status}</el-tag></p>
        <p><strong>当前治疗:</strong>${row.currentTreatment}</p>
        <p><strong>随访计划:</strong>${row.followUpPlan}</p>
      </div>`,
        "慢病详情",
        {
          dangerouslyUseHTMLString: true,
          customClass: "detail-dialog",
        }
      );
    },
    /** èŽ·å–é£Žé™©ç­‰çº§æ–‡æœ¬ */
    getRiskLevelText(level) {
      const levelMap = {
        low: "低风险",
        medium: "中风险",
        high: "高风险",
        critical: "危急",
      };
      return levelMap[level] || "未知";
    },
    /** åˆ·æ–°ç­›æŸ¥æ•°æ® */
    refreshScreeningData() {
      this.screeningLoading = true;
      // æ¨¡æ‹Ÿå¼‚步加载
      setTimeout(() => {
        this.initScreeningData();
        this.screeningLoading = false;
        this.$message.success("筛查数据已刷新");
      }, 1000);
    },
    /** åˆ·æ–°æ…¢ç—…数据 */
    refreshChronicData() {
      this.chronicLoading = true;
      // æ¨¡æ‹Ÿå¼‚步加载
      setTimeout(() => {
        this.initChronicDiseaseData();
        this.chronicLoading = false;
        this.$message.success("慢病数据已刷新");
      }, 1000);
    },
    // ä¿å­˜æ‚£è€…档案
    savefile() {
@@ -2370,6 +3260,81 @@
    }
  }
}
.screening-summary,
.chronic-disease-summary {
  background: #ffffff;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  margin-bottom: 20px;
  .summary-header {
    display: flex;
    align-items: center;
    padding: 12px 15px;
    background: #f5f7fa;
    border-bottom: 1px solid #e6e6e6;
    font-weight: 600;
    color: #333;
    i {
      margin-right: 8px;
      color: #409eff;
    }
  }
  .summary-content {
    padding: 15px;
    .summary-stats {
      margin-top: 15px;
      padding-top: 15px;
      border-top: 1px dashed #e6e6e6;
      .stat-item {
        text-align: center;
        .stat-value {
          font-size: 24px;
          font-weight: bold;
          margin-bottom: 5px;
        }
        .stat-label {
          font-size: 12px;
          color: #909399;
        }
      }
    }
  }
}
/* è¯¦æƒ…对话框样式 */
:deep(.detail-dialog) {
  .el-message-box__message {
    p {
      margin: 10px 0;
      line-height: 1.6;
    }
    strong {
      color: #333;
      min-width: 80px;
      display: inline-block;
    }
  }
}
/* å“åº”式设计 */
@media (max-width: 1200px) {
  .screening-summary,
  .chronic-disease-summary {
    .summary-content {
      .el-table {
        font-size: 12px;
      }
    }
  }
}
.xinz-inf {
  font-size: 18px;
  // white-space: nowrap;
@@ -2470,4 +3435,24 @@
::v-deep.el-table .warning-row {
  background: oldlace;
}
/* æ“ä½œæŒ‰é’®ç»„样式 */
.summary-header .el-button-group {
  margin-left: auto;
}
/* å¯¹è¯æ¡†è¡¨å•样式 */
.el-dialog .el-form-item {
  margin-bottom: 20px;
}
/* ç»Ÿè®¡æ•°å­—样式优化 */
.stat-item {
  cursor: pointer;
  transition: all 0.3s;
}
.stat-item:hover {
  background-color: #f5f7fa;
  border-radius: 4px;
}
</style>
src/views/patient/physical/index.vue
@@ -78,7 +78,27 @@
            placeholder="请选择任务名称"
          ></el-input>
        </el-form-item>
        <el-form-item label="得分区间">
          <el-input
            v-model="topqueryParams.scoreStart"
            placeholder="开始分"
            style="width: 100px"
          ></el-input>
          <span style="margin: 0 10px">-</span>
          <el-input
            v-model="topqueryParams.scoreEnd"
            placeholder="结束分"
            style="width: 100px"
          ></el-input>
        </el-form-item>
        <el-form-item label="答案查询">
          <el-input
            v-model="topqueryParams.detailResult"
            placeholder="请输入答案关键词"
            style="width: 200px"
          ></el-input>
        </el-form-item>
        <el-form-item label="出院时间">
          <el-date-picker
            v-model="dateRange"
@@ -133,6 +153,19 @@
          >
        </el-form-item>
      </el-form>
      <el-row :gutter="10" style="margin-bottom: 15px;">
  <!-- <el-col :span="24">
    <span style="margin-right: 10px; font-size: 14px; color: #606266;">快速选择:</span>
    <el-button-group>
      <el-button size="mini" @click="quickScoreRange('excellent')">优秀(90-100)</el-button>
      <el-button size="mini" @click="quickScoreRange('good')">良好(80-89)</el-button>
      <el-button size="mini" @click="quickScoreRange('medium')">中等(70-79)</el-button>
      <el-button size="mini" @click="quickScoreRange('pass')">及格(60-69)</el-button>
      <el-button size="mini" @click="quickScoreRange('fail')">不及格(0-59)</el-button>
      <el-button size="mini" @click="resetScoreQuery">重置</el-button>
    </el-button-group>
  </el-col> -->
</el-row>
      <el-divider></el-divider>
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
@@ -269,6 +302,17 @@
              :options="dict.type.sys_suggest"
              :value="scope.row.suggest"
            />
          </template>
        </el-table-column>
        <el-table-column
          label="得分"
          align="center"
          key="score"
          prop="score"
          width="100"
        >
          <template slot-scope="scope">
            <span>{{ scope.row.score || "-" }}</span>
          </template>
        </el-table-column>
        <el-table-column
@@ -765,6 +809,9 @@
        pageSize: 10,
        serviceType: 1,
        searchscope: 3,
        scoreStart: undefined, // å¾—分开始
      scoreEnd: undefined,   // å¾—分结束
      detailResult: undefined, // ç»“果查询
        scopetype: [],
        leaveldeptcodes: [],
        leavehospitaldistrictcodes: [],
@@ -850,6 +897,8 @@
  methods: {
    /** æŸ¥è¯¢é—¨è¯Šéšè®¿æœåŠ¡åˆ—è¡¨ */
    getList(refresh) {
      // å¤„理得分区间查询逻辑
    this.handleScoreQuery();
      // é»˜è®¤å…¨éƒ¨
      if (this.topqueryParams.searchscope == 3) {
        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
@@ -869,6 +918,7 @@
      getTaskservelist(this.topqueryParams).then((response) => {
        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);
@@ -906,6 +956,47 @@
        this.total = response.total;
      });
    },
    /** å¾—分区间快速选择 */
  quickScoreRange(range) {
    const ranges = {
      'excellent': { start: 90, end: 100 },
      'good': { start: 80, end: 89 },
      'medium': { start: 70, end: 79 },
      'pass': { start: 60, end: 69 },
      'fail': { start: 0, end: 59 }
    };
    if (ranges[range]) {
      this.topqueryParams.scoreStart = ranges[range].start;
      this.topqueryParams.scoreEnd = ranges[range].end;
      this.handleQuery();
    }
  },
    /** å¤„理得分区间查询 */
  handleScoreQuery() {
    // éªŒè¯å¾—分区间输入
    if (this.topqueryParams.scoreStart && isNaN(this.topqueryParams.scoreStart)) {
      this.$message.warning('开始分必须为数字');
      this.topqueryParams.scoreStart = undefined;
      return;
    }
    if (this.topqueryParams.scoreEnd && isNaN(this.topqueryParams.scoreEnd)) {
      this.$message.warning('结束分必须为数字');
      this.topqueryParams.scoreEnd = undefined;
      return;
    }
    // ç¡®ä¿å¼€å§‹åˆ†ä¸å¤§äºŽç»“束分
    if (this.topqueryParams.scoreStart && this.topqueryParams.scoreEnd) {
      if (parseFloat(this.topqueryParams.scoreStart) > parseFloat(this.topqueryParams.scoreEnd)) {
        this.$message.warning('开始分不能大于结束分');
        // äº¤æ¢å€¼
        [this.topqueryParams.scoreStart, this.topqueryParams.scoreEnd] =
        [this.topqueryParams.scoreEnd, this.topqueryParams.scoreStart];
      }
    }
  },
    // æŸ¥çœ‹é—¨è¯Šéšè®¿è¯¦æƒ…
    Referencequestion(row) {
      this.previewVisible = true;
@@ -1013,6 +1104,11 @@
      this.single = selection.length != 1;
      this.multiple = !selection.length;
    },
    resetScoreQuery() {
    this.topqueryParams.scoreStart = undefined;
    this.topqueryParams.scoreEnd = undefined;
    this.topqueryParams.detailResult = undefined;
  },
    //删除选项
    handleClose(tag) {
      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
@@ -1222,7 +1318,30 @@
    font-size: 23px;
  }
}
/* å¾—分区间输入框样式 */
.score-range-input {
  display: flex;
  align-items: center;
  .score-separator {
    margin: 0 10px;
    color: #909399;
  }
}
/* ç»“果标签样式 */
.result-tag {
  margin: 2px;
}
/* å¿«é€Ÿé€‰æ‹©æŒ‰é’®æ ·å¼ */
.quick-score-buttons {
  margin-bottom: 15px;
  .el-button-group {
    margin-left: 10px;
  }
}
.uploading {
  margin-top: 20px;
  margin: 20px;
src/views/system/group/index.vue
@@ -5,7 +5,14 @@
      <el-tab-pane label="团队管理" name="team">
        <el-row :gutter="20">
          <el-col :span="24" :xs="24">
            <el-form :model="teamQueryParams" ref="teamQueryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
            <el-form
              :model="teamQueryParams"
              ref="teamQueryForm"
              size="small"
              :inline="true"
              v-show="showSearch"
              label-width="68px"
            >
              <el-form-item label="团队名称" prop="name">
                <el-input
                  v-model="teamQueryParams.name"
@@ -16,7 +23,12 @@
                />
              </el-form-item>
              <el-form-item label="团队状态" prop="status">
                <el-select v-model="teamQueryParams.status" placeholder="请选择状态" clearable style="width: 200px">
                <el-select
                  v-model="teamQueryParams.status"
                  placeholder="请选择状态"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="item in teamStatusOptions"
                    :key="item.value"
@@ -26,8 +38,19 @@
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" icon="el-icon-search" size="medium" @click="handleTeamQuery">搜索</el-button>
                <el-button icon="el-icon-refresh" size="medium" @click="resetTeamQuery">重置</el-button>
                <el-button
                  type="primary"
                  icon="el-icon-search"
                  size="medium"
                  @click="handleTeamQuery"
                  >搜索</el-button
                >
                <el-button
                  icon="el-icon-refresh"
                  size="medium"
                  @click="resetTeamQuery"
                  >重置</el-button
                >
              </el-form-item>
            </el-form>
@@ -39,56 +62,104 @@
                  icon="el-icon-plus"
                  size="medium"
                  @click="handleTeamAdd"
                >新增团队</el-button>
                  >新增团队</el-button
                >
              </el-col>
            </el-row>
            <el-table v-loading="teamLoading" :data="filteredTeamList" @selection-change="handleTeamSelectionChange">
            <el-table
              v-loading="teamLoading"
              :data="filteredTeamList"
              @selection-change="handleTeamSelectionChange"
            >
              <el-table-column type="selection" width="50" align="center" />
              <el-table-column label="团队ID" align="center" prop="id" width="80" />
              <el-table-column label="团队名称" align="center" prop="name" :show-overflow-tooltip="true" />
              <el-table-column label="团队组长" align="center" prop="leader" width="120" />
              <el-table-column label="团队成员" align="center" prop="memberCount" width="100">
  <template slot-scope="scope">
    <el-tag>{{ (scope.row.members || []).length }}人</el-tag>
  </template>
</el-table-column>
              <el-table-column label="创建时间" align="center" prop="createTime" width="160">
              <el-table-column
                label="团队ID"
                align="center"
                prop="id"
                width="80"
              />
              <el-table-column
                label="团队名称"
                align="center"
                prop="name"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="团队组长"
                align="center"
                prop="leader"
                width="120"
              />
              <el-table-column
                label="团队成员"
                align="center"
                prop="memberCount"
                width="100"
              >
                <template slot-scope="scope">
                  <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                  <el-tag>{{ (scope.row.members || []).length }}人</el-tag>
                </template>
              </el-table-column>
              <el-table-column label="团队状态" align="center" prop="status" width="100">
              <el-table-column
                label="创建时间"
                align="center"
                prop="createTime"
                width="160"
              >
                <template slot-scope="scope">
                  <dict-tag :options="teamStatusOptions" :value="scope.row.status"/>
                  <span>{{
                    parseTime(scope.row.createTime, "{y}-{m}-{d}")
                  }}</span>
                </template>
              </el-table-column>
              <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
              <el-table-column
                label="团队状态"
                align="center"
                prop="status"
                width="100"
              >
                <template slot-scope="scope">
                  <dict-tag
                    :options="teamStatusOptions"
                    :value="scope.row.status"
                  />
                </template>
              </el-table-column>
              <el-table-column
                label="操作"
                align="center"
                class-name="small-padding fixed-width"
                width="180"
              >
                <template slot-scope="scope">
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-view"
                    @click="handleTeamDetail(scope.row)"
                  >详情</el-button>
                    >详情</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-edit"
                    @click="handleTeamUpdate(scope.row)"
                  >编辑</el-button>
                    >编辑</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-delete"
                    @click="handleTeamDelete(scope.row)"
                  >删除</el-button>
                    >删除</el-button
                  >
                </template>
              </el-table-column>
            </el-table>
            <pagination
              v-show="teamTotal>0"
              v-show="teamTotal > 0"
              :total="teamTotal"
              :page.sync="teamQueryParams.pageNum"
              :limit.sync="teamQueryParams.pageSize"
@@ -102,7 +173,14 @@
      <el-tab-pane label="人员分组" name="member">
        <el-row :gutter="20">
          <el-col :span="24" :xs="24">
            <el-form :model="memberQueryParams" ref="memberQueryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
            <el-form
              :model="memberQueryParams"
              ref="memberQueryForm"
              size="small"
              :inline="true"
              v-show="showSearch"
              label-width="68px"
            >
              <el-form-item label="成员姓名" prop="name">
                <el-input
                  v-model="memberQueryParams.name"
@@ -113,7 +191,12 @@
                />
              </el-form-item>
              <el-form-item label="所属团队" prop="teamId">
                <el-select v-model="memberQueryParams.teamId" placeholder="请选择团队" clearable style="width: 200px">
                <el-select
                  v-model="memberQueryParams.teamId"
                  placeholder="请选择团队"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="item in teamList"
                    :key="item.id"
@@ -123,7 +206,12 @@
                </el-select>
              </el-form-item>
              <el-form-item label="成员状态" prop="status">
                <el-select v-model="memberQueryParams.status" placeholder="请选择状态" clearable style="width: 200px">
                <el-select
                  v-model="memberQueryParams.status"
                  placeholder="请选择状态"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="item in memberStatusOptions"
                    :key="item.value"
@@ -133,8 +221,19 @@
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" icon="el-icon-search" size="medium" @click="handleMemberQuery">搜索</el-button>
                <el-button icon="el-icon-refresh" size="medium" @click="resetMemberQuery">重置</el-button>
                <el-button
                  type="primary"
                  icon="el-icon-search"
                  size="medium"
                  @click="handleMemberQuery"
                  >搜索</el-button
                >
                <el-button
                  icon="el-icon-refresh"
                  size="medium"
                  @click="resetMemberQuery"
                  >重置</el-button
                >
              </el-form-item>
            </el-form>
@@ -146,7 +245,8 @@
                  icon="el-icon-plus"
                  size="medium"
                  @click="handleMemberAdd"
                >新增成员</el-button>
                  >新增成员</el-button
                >
              </el-col>
              <el-col :span="1.5">
                <el-button
@@ -156,50 +256,105 @@
                  size="medium"
                  :disabled="multiple"
                  @click="handleMemberDelete"
                >删除</el-button>
                  >删除</el-button
                >
              </el-col>
            </el-row>
            <el-table v-loading="memberLoading" :data="filteredMemberList" @selection-change="handleMemberSelectionChange">
            <el-table
              v-loading="memberLoading"
              :data="filteredMemberList"
              @selection-change="handleMemberSelectionChange"
            >
              <el-table-column type="selection" width="50" align="center" />
              <el-table-column label="成员ID" align="center" prop="id" width="80" />
              <el-table-column label="成员姓名" align="center" prop="name" :show-overflow-tooltip="true" />
              <el-table-column label="所属团队" align="center" prop="teamName" width="150" />
              <el-table-column label="职位" align="center" prop="position" width="120" />
              <el-table-column label="联系电话" align="center" prop="phone" width="150" />
              <el-table-column label="邮箱" align="center" prop="email" width="200" />
              <el-table-column label="当前工单" align="center" prop="currentWorkOrder" width="120">
              <el-table-column
                label="成员ID"
                align="center"
                prop="id"
                width="80"
              />
              <el-table-column
                label="成员姓名"
                align="center"
                prop="name"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="所属团队"
                align="center"
                prop="teamName"
                width="150"
              />
              <el-table-column
                label="职位"
                align="center"
                prop="position"
                width="120"
              />
              <el-table-column
                label="联系电话"
                align="center"
                prop="phone"
                width="150"
              />
              <el-table-column
                label="邮箱"
                align="center"
                prop="email"
                width="200"
              />
              <el-table-column
                label="当前工单"
                align="center"
                prop="currentWorkOrder"
                width="120"
              >
                <template slot-scope="scope">
                  <el-tag :type="scope.row.currentWorkOrder ? '' : 'info'">
                    {{ scope.row.currentWorkOrder || '空闲' }}
                    {{ scope.row.currentWorkOrder || "空闲" }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="成员状态" align="center" prop="status" width="100">
              <el-table-column
                label="成员状态"
                align="center"
                prop="status"
                width="100"
              >
                <template slot-scope="scope">
                  <dict-tag :options="memberStatusOptions" :value="scope.row.status"/>
                  <dict-tag
                    :options="memberStatusOptions"
                    :value="scope.row.status"
                  />
                </template>
              </el-table-column>
              <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
              <el-table-column
                label="操作"
                align="center"
                class-name="small-padding fixed-width"
                width="180"
              >
                <template slot-scope="scope">
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-edit"
                    @click="handleMemberUpdate(scope.row)"
                  >编辑</el-button>
                    >编辑</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-delete"
                    @click="handleMemberDelete(scope.row)"
                  >删除</el-button>
                    >删除</el-button
                  >
                </template>
              </el-table-column>
            </el-table>
            <pagination
              v-show="memberTotal>0"
              v-show="memberTotal > 0"
              :total="memberTotal"
              :page.sync="memberQueryParams.pageNum"
              :limit.sync="memberQueryParams.pageSize"
@@ -213,7 +368,14 @@
      <el-tab-pane label="工单指派" name="workOrder">
        <el-row :gutter="20">
          <el-col :span="24" :xs="24">
            <el-form :model="workOrderQueryParams" ref="workOrderQueryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
            <el-form
              :model="workOrderQueryParams"
              ref="workOrderQueryForm"
              size="small"
              :inline="true"
              v-show="showSearch"
              label-width="68px"
            >
              <el-form-item label="工单编号" prop="id">
                <el-input
                  v-model="workOrderQueryParams.id"
@@ -224,7 +386,12 @@
                />
              </el-form-item>
              <el-form-item label="工单状态" prop="status">
                <el-select v-model="workOrderQueryParams.status" placeholder="请选择状态" clearable style="width: 200px">
                <el-select
                  v-model="workOrderQueryParams.status"
                  placeholder="请选择状态"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="item in workOrderStatusOptions"
                    :key="item.value"
@@ -234,7 +401,12 @@
                </el-select>
              </el-form-item>
              <el-form-item label="处理人" prop="assignee">
                <el-select v-model="workOrderQueryParams.assignee" placeholder="请选择处理人" clearable style="width: 200px">
                <el-select
                  v-model="workOrderQueryParams.assignee"
                  placeholder="请选择处理人"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="item in memberList"
                    :key="item.id"
@@ -244,8 +416,19 @@
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" icon="el-icon-search" size="medium" @click="handleWorkOrderQuery">搜索</el-button>
                <el-button icon="el-icon-refresh" size="medium" @click="resetWorkOrderQuery">重置</el-button>
                <el-button
                  type="primary"
                  icon="el-icon-search"
                  size="medium"
                  @click="handleWorkOrderQuery"
                  >搜索</el-button
                >
                <el-button
                  icon="el-icon-refresh"
                  size="medium"
                  @click="resetWorkOrderQuery"
                  >重置</el-button
                >
              </el-form-item>
            </el-form>
@@ -257,64 +440,133 @@
                  icon="el-icon-plus"
                  size="medium"
                  @click="handleWorkOrderAdd"
                >新建工单</el-button>
                  >新建工单</el-button
                >
              </el-col>
            </el-row>
            <el-table v-loading="workOrderLoading" :data="filteredWorkOrderList" @selection-change="handleWorkOrderSelectionChange">
            <el-table
              v-loading="workOrderLoading"
              :data="filteredWorkOrderList"
              @selection-change="handleWorkOrderSelectionChange"
            >
              <el-table-column type="selection" width="50" align="center" />
              <el-table-column label="工单编号" align="center" prop="id" width="120" />
              <el-table-column label="工单标题" align="center" prop="title" :show-overflow-tooltip="true" />
              <el-table-column label="优先级" align="center" prop="priority" width="100">
              <el-table-column
                label="工单编号"
                align="center"
                prop="id"
                width="120"
              />
              <el-table-column
                label="工单标题"
                align="center"
                prop="title"
                :show-overflow-tooltip="true"
              />
              <el-table-column
                label="优先级"
                align="center"
                prop="priority"
                width="100"
              >
                <template slot-scope="scope">
                  <el-tag :type="scope.row.priority === '1' ? 'danger' : scope.row.priority === '2' ? 'warning' : ''">
                    {{ scope.row.priority === '1' ? '高' : scope.row.priority === '2' ? '中' : '低' }}
                  <el-tag
                    :type="
                      scope.row.priority === '1'
                        ? 'danger'
                        : scope.row.priority === '2'
                        ? 'warning'
                        : ''
                    "
                  >
                    {{
                      scope.row.priority === "1"
                        ? "高"
                        : scope.row.priority === "2"
                        ? "中"
                        : "低"
                    }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="创建时间" align="center" prop="createTime" width="160">
              <el-table-column
                label="创建时间"
                align="center"
                prop="createTime"
                width="160"
              >
                <template slot-scope="scope">
                  <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
                  <span>{{
                    parseTime(scope.row.createTime, "{y}-{m}-{d}")
                  }}</span>
                </template>
              </el-table-column>
              <el-table-column label="截止时间" align="center" prop="deadline" width="160">
              <el-table-column
                label="截止时间"
                align="center"
                prop="deadline"
                width="160"
              >
                <template slot-scope="scope">
                  <span>{{ parseTime(scope.row.deadline, '{y}-{m}-{d}') }}</span>
                  <span>{{
                    parseTime(scope.row.deadline, "{y}-{m}-{d}")
                  }}</span>
                </template>
              </el-table-column>
              <el-table-column label="处理人" align="center" prop="assigneeName" width="120" />
              <el-table-column label="工单状态" align="center" prop="status" width="120">
              <el-table-column
                label="处理人"
                align="center"
                prop="assigneeName"
                width="120"
              />
              <el-table-column
                label="工单状态"
                align="center"
                prop="status"
                width="120"
              >
                <template slot-scope="scope">
                  <dict-tag :options="workOrderStatusOptions" :value="scope.row.status"/>
                  <dict-tag
                    :options="workOrderStatusOptions"
                    :value="scope.row.status"
                  />
                </template>
              </el-table-column>
              <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
              <el-table-column
                label="操作"
                align="center"
                class-name="small-padding fixed-width"
                width="180"
              >
                <template slot-scope="scope">
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-edit"
                    @click="handleWorkOrderUpdate(scope.row)"
                  >编辑</el-button>
                    >编辑</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-delete"
                    @click="handleWorkOrderDelete(scope.row)"
                  >删除</el-button>
                    >删除</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-s-promotion"
                    @click="handleAssignWorkOrder(scope.row)"
                    v-if="scope.row.status === '0'"
                  >指派</el-button>
                    >指派</el-button
                  >
                </template>
              </el-table-column>
            </el-table>
            <pagination
              v-show="workOrderTotal>0"
              v-show="workOrderTotal > 0"
              :total="workOrderTotal"
              :page.sync="workOrderQueryParams.pageNum"
              :limit.sync="workOrderQueryParams.pageSize"
@@ -326,19 +578,37 @@
    </el-tabs>
    <!-- å›¢é˜Ÿè¯¦æƒ…对话框 -->
    <el-dialog :title="teamDialogTitle" :visible.sync="teamDialogVisible" width="70%" append-to-body>
    <el-dialog
      :title="teamDialogTitle"
      :visible.sync="teamDialogVisible"
      width="70%"
      append-to-body
    >
      <el-descriptions :column="2" border>
        <el-descriptions-item label="团队ID">{{ currentTeam.id }}</el-descriptions-item>
        <el-descriptions-item label="团队名称">{{ currentTeam.name }}</el-descriptions-item>
        <el-descriptions-item label="团队组长">{{ currentTeam.leader }}</el-descriptions-item>
<el-descriptions-item label="团队成员">{{ (currentTeam.members || []).length }}人</el-descriptions-item>        <el-descriptions-item label="创建时间">{{ parseTime(currentTeam.createTime, '{y}-{m}-{d} {h}:{i}') }}</el-descriptions-item>
        <el-descriptions-item label="团队ID">{{
          currentTeam.id
        }}</el-descriptions-item>
        <el-descriptions-item label="团队名称">{{
          currentTeam.name
        }}</el-descriptions-item>
        <el-descriptions-item label="团队组长">{{
          currentTeam.leader
        }}</el-descriptions-item>
        <el-descriptions-item label="团队成员"
          >{{ (currentTeam.members || []).length }}人</el-descriptions-item
        >
        <el-descriptions-item label="创建时间">{{
          parseTime(currentTeam.createTime, "{y}-{m}-{d} {h}:{i}")
        }}</el-descriptions-item>
        <el-descriptions-item label="团队状态">
          <dict-tag :options="teamStatusOptions" :value="currentTeam.status"/>
          <dict-tag :options="teamStatusOptions" :value="currentTeam.status" />
        </el-descriptions-item>
        <el-descriptions-item label="团队描述" :span="2">{{ currentTeam.description || '无' }}</el-descriptions-item>
        <el-descriptions-item label="团队描述" :span="2">{{
          currentTeam.description || "无"
        }}</el-descriptions-item>
      </el-descriptions>
      <div class="team-members" style="margin-top: 20px;">
      <div class="team-members" style="margin-top: 20px">
        <div class="headline">
          <div class="basics">团队成员</div>
        </div>
@@ -351,19 +621,22 @@
          <el-table-column prop="currentWorkOrder" label="当前工单" width="150">
            <template slot-scope="scope">
              <el-tag :type="scope.row.currentWorkOrder ? '' : 'info'">
                {{ scope.row.currentWorkOrder || '空闲' }}
                {{ scope.row.currentWorkOrder || "空闲" }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="status" label="成员状态" width="100">
            <template slot-scope="scope">
              <dict-tag :options="memberStatusOptions" :value="scope.row.status"/>
              <dict-tag
                :options="memberStatusOptions"
                :value="scope.row.status"
              />
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="team-work-orders" style="margin-top: 20px;">
      <div class="team-work-orders" style="margin-top: 20px">
        <div class="headline">
          <div class="basics">团队工单</div>
        </div>
@@ -373,38 +646,90 @@
          <el-table-column prop="title" label="工单标题" />
          <el-table-column prop="priority" label="优先级" width="100">
            <template slot-scope="scope">
              <el-tag :type="scope.row.priority === '1' ? 'danger' : scope.row.priority === '2' ? 'warning' : ''">
                {{ scope.row.priority === '1' ? '高' : scope.row.priority === '2' ? '中' : '低' }}
              <el-tag
                :type="
                  scope.row.priority === '1'
                    ? 'danger'
                    : scope.row.priority === '2'
                    ? 'warning'
                    : ''
                "
              >
                {{
                  scope.row.priority === "1"
                    ? "高"
                    : scope.row.priority === "2"
                    ? "中"
                    : "低"
                }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="assigneeName" label="处理人" width="120" />
          <el-table-column prop="status" label="工单状态" width="120">
            <template slot-scope="scope">
              <dict-tag :options="workOrderStatusOptions" :value="scope.row.status"/>
              <dict-tag
                :options="workOrderStatusOptions"
                :value="scope.row.status"
              />
            </template>
          </el-table-column>
          <el-table-column prop="createTime" label="创建时间" width="160">
            <template slot-scope="scope">
              <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
              <span>{{ parseTime(scope.row.createTime, "{y}-{m}-{d}") }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="deadline" label="截止时间" width="160">
            <template slot-scope="scope">
              <span>{{ parseTime(scope.row.deadline, '{y}-{m}-{d}') }}</span>
              <span>{{ parseTime(scope.row.deadline, "{y}-{m}-{d}") }}</span>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <!-- åœ¨å›¢é˜Ÿè¯¦æƒ…对话框的团队成员表格后添加二维码区域 -->
      <div class="team-qrcode" style="margin-top: 20px">
        <div class="headline">
          <div class="basics">团队二维码</div>
        </div>
        <el-divider></el-divider>
        <div class="qrcode-container">
          <vue-qr
            :text="teamQRContent"
            :size="200"
            :margin="10"
            colorDark="#409EFF"
            :logoScale="0.2"
            :logoSrc="logoUrl"
          ></vue-qr>
          <div class="qrcode-actions">
            <el-button size="mini" @click="downloadQRCode"
              >下载二维码</el-button
            >
            <el-button size="mini" type="primary" @click="refreshQRCode"
              >刷新</el-button
            >
          </div>
          <p class="qrcode-tip">扫描二维码查看团队信息(有效期24小时)</p>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="teamDialogVisible = false">关 é—­</el-button>
      </div>
    </el-dialog>
    <!-- æ–°å¢ž/编辑团队对话框 -->
    <el-dialog :title="teamFormTitle" :visible.sync="teamFormVisible" width="50%" append-to-body>
      <el-form ref="teamForm" :model="teamForm" :rules="teamRules" label-width="80px">
    <el-dialog
      :title="teamFormTitle"
      :visible.sync="teamFormVisible"
      width="50%"
      append-to-body
    >
      <el-form
        ref="teamForm"
        :model="teamForm"
        :rules="teamRules"
        label-width="80px"
      >
        <el-row>
          <el-col :span="24">
            <el-form-item label="团队名称" prop="name">
@@ -430,7 +755,8 @@
                  v-for="dict in teamStatusOptions"
                  :key="dict.value"
                  :label="dict.value"
                >{{dict.label}}</el-radio>
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
@@ -442,14 +768,19 @@
                :titles="['可选成员', '团队成员']"
                :props="{
                  key: 'id',
                  label: 'name'
                  label: 'name',
                }"
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="团队描述" prop="description">
              <el-input type="textarea" :rows="3" v-model="teamForm.description" placeholder="请输入团队描述" />
              <el-input
                type="textarea"
                :rows="3"
                v-model="teamForm.description"
                placeholder="请输入团队描述"
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -461,17 +792,33 @@
    </el-dialog>
    <!-- æ–°å¢ž/编辑成员对话框 -->
    <el-dialog :title="memberFormTitle" :visible.sync="memberFormVisible" width="50%" append-to-body>
      <el-form ref="memberForm" :model="memberForm" :rules="memberRules" label-width="80px">
    <el-dialog
      :title="memberFormTitle"
      :visible.sync="memberFormVisible"
      width="50%"
      append-to-body
    >
      <el-form
        ref="memberForm"
        :model="memberForm"
        :rules="memberRules"
        label-width="80px"
      >
        <el-row>
          <el-col :span="12">
            <el-form-item label="成员姓名" prop="name">
              <el-input v-model="memberForm.name" placeholder="请输入成员姓名" />
              <el-input
                v-model="memberForm.name"
                placeholder="请输入成员姓名"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="所属团队" prop="teamId">
              <el-select v-model="memberForm.teamId" placeholder="请选择所属团队">
              <el-select
                v-model="memberForm.teamId"
                placeholder="请选择所属团队"
              >
                <el-option
                  v-for="item in teamList"
                  :key="item.id"
@@ -483,12 +830,18 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="职位" prop="position">
              <el-input v-model="memberForm.position" placeholder="请输入职位" />
              <el-input
                v-model="memberForm.position"
                placeholder="请输入职位"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话" prop="phone">
              <el-input v-model="memberForm.phone" placeholder="请输入联系电话" />
              <el-input
                v-model="memberForm.phone"
                placeholder="请输入联系电话"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -503,7 +856,8 @@
                  v-for="dict in memberStatusOptions"
                  :key="dict.value"
                  :label="dict.value"
                >{{dict.label}}</el-radio>
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
@@ -516,17 +870,33 @@
    </el-dialog>
    <!-- æ–°å¢ž/编辑工单对话框 -->
    <el-dialog :title="workOrderFormTitle" :visible.sync="workOrderFormVisible" width="60%" append-to-body>
      <el-form ref="workOrderForm" :model="workOrderForm" :rules="workOrderRules" label-width="80px">
    <el-dialog
      :title="workOrderFormTitle"
      :visible.sync="workOrderFormVisible"
      width="60%"
      append-to-body
    >
      <el-form
        ref="workOrderForm"
        :model="workOrderForm"
        :rules="workOrderRules"
        label-width="80px"
      >
        <el-row>
          <el-col :span="24">
            <el-form-item label="工单标题" prop="title">
              <el-input v-model="workOrderForm.title" placeholder="请输入工单标题" />
              <el-input
                v-model="workOrderForm.title"
                placeholder="请输入工单标题"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="优先级" prop="priority">
              <el-select v-model="workOrderForm.priority" placeholder="请选择优先级">
              <el-select
                v-model="workOrderForm.priority"
                placeholder="请选择优先级"
              >
                <el-option
                  v-for="item in priorityOptions"
                  :key="item.value"
@@ -549,7 +919,12 @@
          </el-col>
          <el-col :span="24">
            <el-form-item label="工单内容" prop="content">
              <el-input type="textarea" :rows="4" v-model="workOrderForm.content" placeholder="请输入工单内容" />
              <el-input
                type="textarea"
                :rows="4"
                v-model="workOrderForm.content"
                placeholder="请输入工单内容"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -559,13 +934,17 @@
                  v-for="dict in workOrderStatusOptions"
                  :key="dict.value"
                  :label="dict.value"
                >{{dict.label}}</el-radio>
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="workOrderForm.status === '1'">
            <el-form-item label="处理人" prop="assignee">
              <el-select v-model="workOrderForm.assignee" placeholder="请选择处理人">
              <el-select
                v-model="workOrderForm.assignee"
                placeholder="请选择处理人"
              >
                <el-option
                  v-for="item in memberList"
                  :key="item.id"
@@ -584,13 +963,22 @@
    </el-dialog>
    <!-- æŒ‡æ´¾å·¥å•对话框 -->
    <el-dialog title="指派工单" :visible.sync="assignDialogVisible" width="40%" append-to-body>
    <el-dialog
      title="指派工单"
      :visible.sync="assignDialogVisible"
      width="40%"
      append-to-body
    >
      <el-form :model="assignForm" label-width="80px">
        <el-form-item label="工单标题">
          <el-input v-model="assignForm.title" disabled />
        </el-form-item>
        <el-form-item label="处理人" prop="assignee">
          <el-select v-model="assignForm.assignee" placeholder="请选择处理人" style="width: 100%">
          <el-select
            v-model="assignForm.assignee"
            placeholder="请选择处理人"
            style="width: 100%"
          >
            <el-option
              v-for="item in availableMembers"
              :key="item.id"
@@ -600,7 +988,11 @@
          </el-select>
        </el-form-item>
        <el-form-item label="优先级" prop="priority">
          <el-select v-model="assignForm.priority" placeholder="请选择优先级" style="width: 100%">
          <el-select
            v-model="assignForm.priority"
            placeholder="请选择优先级"
            style="width: 100%"
          >
            <el-option
              v-for="item in priorityOptions"
              :key="item.value"
@@ -628,83 +1020,205 @@
</template>
<script>
import { parseTime } from '@/utils/ruoyi'
import { parseTime } from "@/utils/ruoyi";
import VueQr from "vue-qr";
export default {
  name: "TeamManagement",
  dicts: ['sys_normal_disable', 'sys_user_sex'],
  dicts: ["sys_normal_disable", "sys_user_sex"],
  components: { VueQr },
  data() {
    return {
      // å½“前激活的标签页
      activeTab: 'team',
      activeTab: "team",
      // æ˜¾ç¤ºæœç´¢æ¡ä»¶
      showSearch: true,
      // å›¢é˜Ÿç®¡ç†ç›¸å…³æ•°æ®
      teamLoading: false,
       multiple: false, // è¿™é‡Œæ·»åŠ 
      multiple: false, // è¿™é‡Œæ·»åŠ 
      // æ›¿æ¢åŽŸæœ‰çš„teamList数据
      teamList: [
        {
          id: 1,
          name: "前端开发团队",
          leader: "张三",
          name: "心血管内科团队",
          leader: "李成白",
          members: [
            { id: 1, name: "张三", position: "前端组长", phone: "13800138001", email: "zhangsan@example.com", currentWorkOrder: "WO20230001", status: "1" },
            { id: 2, name: "李四", position: "高级前端", phone: "13800138002", email: "lisi@example.com", currentWorkOrder: "", status: "1" },
            { id: 3, name: "王五", position: "前端开发", phone: "13800138003", email: "wangwu@example.com", currentWorkOrder: "WO20230002", status: "1" }
            {
              id: 1,
              name: "李成白",
              position: "主任医师",
              phone: "13800138001",
              email: "lichengbai@hospital.com",
              currentWorkOrder: "MED20230001",
              status: "1",
            },
            {
              id: 2,
              name: "刘翊惠",
              position: "副主任医师",
              phone: "13800138002",
              email: "liuyihui@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
            {
              id: 3,
              name: "张孟涵",
              position: "主治医师",
              phone: "13800138003",
              email: "zhangmenghan@hospital.com",
              currentWorkOrder: "MED20230002",
              status: "1",
            },
            {
              id: 9,
              name: "吴思翰",
              position: "住院医师",
              phone: "13800138009",
              email: "wusihan@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
          ],
          createTime: "2023-01-15 09:30:00",
          createTime: "2024-01-15 09:30:00",
          status: "1",
          description: "负责公司所有前端项目的开发和维护"
          description: "负责心血管疾病的诊断、治疗和手术,擅长冠心病介入治疗",
        },
        {
          id: 2,
          name: "后端开发团队",
          leader: "赵六",
          name: "肿瘤科治疗团队",
          leader: "陈政倩",
          members: [
            { id: 4, name: "赵六", position: "后端组长", phone: "13800138004", email: "zhaoliu@example.com", currentWorkOrder: "WO20230003", status: "1" },
            { id: 5, name: "钱七", position: "高级后端", phone: "13800138005", email: "qianqi@example.com", currentWorkOrder: "", status: "1" },
            { id: 6, name: "孙八", position: "后端开发", phone: "13800138006", email: "sunba@example.com", currentWorkOrder: "", status: "1" }
            {
              id: 4,
              name: "陈政倩",
              position: "肿瘤科主任",
              phone: "13800138004",
              email: "chenzhengqian@hospital.com",
              currentWorkOrder: "MED20230003",
              status: "1",
            },
            {
              id: 5,
              name: "邓诗涵",
              position: "放疗医师",
              phone: "13800138005",
              email: "dengshihan@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
            {
              id: 6,
              name: "黄盛玫",
              position: "化疗医师",
              phone: "13800138006",
              email: "huangshengmei@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
          ],
          createTime: "2023-01-20 14:20:00",
          createTime: "2024-02-10 14:20:00",
          status: "1",
          description: "负责公司所有后端服务的开发和维护"
          description: "专注于肿瘤的综合治疗,包括化疗、放疗和靶向治疗",
        },
        {
          id: 3,
          name: "测试团队",
          leader: "周九",
          name: "儿科诊疗团队",
          leader: "王恩龙",
          members: [
            { id: 7, name: "周九", position: "测试经理", phone: "13800138007", email: "zhoujiu@example.com", currentWorkOrder: "WO20230004", status: "1" },
            { id: 8, name: "吴十", position: "测试工程师", phone: "13800138008", email: "wushi@example.com", currentWorkOrder: "", status: "1" }
            {
              id: 7,
              name: "王恩龙",
              position: "儿科主任",
              phone: "13800138007",
              email: "wagenlong@hospital.com",
              currentWorkOrder: "MED20230004",
              status: "1",
            },
            {
              id: 8,
              name: "朱政廷",
              position: "儿科医师",
              phone: "13800138008",
              email: "zhuzhengting@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
            {
              id: 10,
              name: "林佩玲",
              position: "儿科护士长",
              phone: "13800138010",
              email: "linpeiling@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
          ],
          createTime: "2023-02-10 10:15:00",
          createTime: "2024-03-05 10:15:00",
          status: "1",
          description: "负责公司所有项目的测试工作"
        }
          description: "负责儿童常见病、多发病的诊疗和预防保健工作",
        },
        {
          id: 4,
          name: "急诊抢救团队",
          leader: "吴俊伯",
          members: [
            {
              id: 11,
              name: "吴俊伯",
              position: "急诊科主任",
              phone: "13800138011",
              email: "wujunbo@hospital.com",
              currentWorkOrder: "MED20230005",
              status: "1",
            },
            {
              id: 12,
              name: "阮馨学",
              position: "急诊医师",
              phone: "13800138012",
              email: "ruanxinxue@hospital.com",
              currentWorkOrder: "MED20230006",
              status: "1",
            },
            {
              id: 13,
              name: "翁惠珠",
              position: "急诊护士",
              phone: "13800138013",
              email: "wenghuizhu@hospital.com",
              currentWorkOrder: "",
              status: "1",
            },
          ],
          createTime: "2024-03-20 16:45:00",
          status: "1",
          description: "24小时待命,负责急危重症患者的抢救和治疗",
        },
      ],
      teamTotal: 4,
      teamQueryParams: {
        pageNum: 1,
        pageSize: 10,
        name: undefined,
        status: undefined
        status: undefined,
      },
      teamTotal: 3,
      teamStatusOptions: [
        { value: "0", label: "禁用" },
        { value: "1", label: "启用" }
        { value: "1", label: "启用" },
      ],
      teamDialogVisible: false,
      teamDialogTitle: "",
      currentTeam: {
      id: undefined,
      name: undefined,
      leader: undefined,
      members: [],  // ç¡®ä¿æœ‰é»˜è®¤ç©ºæ•°ç»„
      createTime: undefined,
      status: undefined,
      description: undefined
    },
        id: undefined,
        name: undefined,
        leader: undefined,
        members: [], // ç¡®ä¿æœ‰é»˜è®¤ç©ºæ•°ç»„
        createTime: undefined,
        status: undefined,
        description: undefined,
      },
      teamFormVisible: false,
      teamFormTitle: "",
      teamForm: {
@@ -713,43 +1227,213 @@
        leader: undefined,
        members: [],
        status: "1",
        description: undefined
        description: undefined,
      },
      teamRules: {
        name: [
          { required: true, message: "团队名称不能为空", trigger: "blur" }
          { required: true, message: "团队名称不能为空", trigger: "blur" },
        ],
        leader: [
          { required: true, message: "团队组长不能为空", trigger: "change" }
          { required: true, message: "团队组长不能为空", trigger: "change" },
        ],
        status: [
          { required: true, message: "团队状态不能为空", trigger: "change" }
        ]
          { required: true, message: "团队状态不能为空", trigger: "change" },
        ],
      },
      // äºŒç»´ç ç›¸å…³æ•°æ®
      teamQRContent: "127.0.0.1:8093/wt?p=0BE9L3C2u",
      logoUrl: require("@/assets/logo/logoxh.png"), // åŒ»é™¢logo
      currentQRCodeUrl: "",
      // äººå‘˜åˆ†ç»„相关数据
      memberLoading: false,
      // æ›¿æ¢åŽŸæœ‰çš„memberList数据
      memberList: [
        { id: 1, name: "张三", teamId: 1, teamName: "前端开发团队", position: "前端组长", phone: "13800138001", email: "zhangsan@example.com", currentWorkOrder: "WO20230001", status: "1" },
        { id: 2, name: "李四", teamId: 1, teamName: "前端开发团队", position: "高级前端", phone: "13800138002", email: "lisi@example.com", currentWorkOrder: "", status: "1" },
        { id: 3, name: "王五", teamId: 1, teamName: "前端开发团队", position: "前端开发", phone: "13800138003", email: "wangwu@example.com", currentWorkOrder: "WO20230002", status: "1" },
        { id: 4, name: "赵六", teamId: 2, teamName: "后端开发团队", position: "后端组长", phone: "13800138004", email: "zhaoliu@example.com", currentWorkOrder: "WO20230003", status: "1" },
        { id: 5, name: "钱七", teamId: 2, teamName: "后端开发团队", position: "高级后端", phone: "13800138005", email: "qianqi@example.com", currentWorkOrder: "", status: "1" },
        { id: 6, name: "孙八", teamId: 2, teamName: "后端开发团队", position: "后端开发", phone: "13800138006", email: "sunba@example.com", currentWorkOrder: "", status: "1" },
        { id: 7, name: "周九", teamId: 3, teamName: "测试团队", position: "测试经理", phone: "13800138007", email: "zhoujiu@example.com", currentWorkOrder: "WO20230004", status: "1" },
        { id: 8, name: "吴十", teamId: 3, teamName: "测试团队", position: "测试工程师", phone: "13800138008", email: "wushi@example.com", currentWorkOrder: "", status: "1" }
        // å¿ƒè¡€ç®¡å†…科团队成员
        {
          id: 1,
          name: "李成白",
          teamId: 1,
          teamName: "心血管内科团队",
          position: "主任医师",
          phone: "13800138001",
          email: "lichengbai@hospital.com",
          currentWorkOrder: "MED20230001",
          status: "1",
        },
        {
          id: 2,
          name: "刘翊惠",
          teamId: 1,
          teamName: "心血管内科团队",
          position: "副主任医师",
          phone: "13800138002",
          email: "liuyihui@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        {
          id: 3,
          name: "张孟涵",
          teamId: 1,
          teamName: "心血管内科团队",
          position: "主治医师",
          phone: "13800138003",
          email: "zhangmenghan@hospital.com",
          currentWorkOrder: "MED20230002",
          status: "1",
        },
        {
          id: 9,
          name: "吴思翰",
          teamId: 1,
          teamName: "心血管内科团队",
          position: "住院医师",
          phone: "13800138009",
          email: "wusihan@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        // è‚¿ç˜¤ç§‘治疗团队成员
        {
          id: 4,
          name: "陈政倩",
          teamId: 2,
          teamName: "肿瘤科治疗团队",
          position: "肿瘤科主任",
          phone: "13800138004",
          email: "chenzhengqian@hospital.com",
          currentWorkOrder: "MED20230003",
          status: "1",
        },
        {
          id: 5,
          name: "邓诗涵",
          teamId: 2,
          teamName: "肿瘤科治疗团队",
          position: "放疗医师",
          phone: "13800138005",
          email: "dengshihan@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        {
          id: 6,
          name: "黄盛玫",
          teamId: 2,
          teamName: "肿瘤科治疗团队",
          position: "化疗医师",
          phone: "13800138006",
          email: "huangshengmei@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        // å„¿ç§‘诊疗团队成员
        {
          id: 7,
          name: "王恩龙",
          teamId: 3,
          teamName: "儿科诊疗团队",
          position: "儿科主任",
          phone: "13800138007",
          email: "wagenlong@hospital.com",
          currentWorkOrder: "MED20230004",
          status: "1",
        },
        {
          id: 8,
          name: "朱政廷",
          teamId: 3,
          teamName: "儿科诊疗团队",
          position: "儿科医师",
          phone: "13800138008",
          email: "zhuzhengting@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        {
          id: 10,
          name: "林佩玲",
          teamId: 3,
          teamName: "儿科诊疗团队",
          position: "儿科护士长",
          phone: "13800138010",
          email: "linpeiling@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        // æ€¥è¯ŠæŠ¢æ•‘团队成员
        {
          id: 11,
          name: "吴俊伯",
          teamId: 4,
          teamName: "急诊抢救团队",
          position: "急诊科主任",
          phone: "13800138011",
          email: "wujunbo@hospital.com",
          currentWorkOrder: "MED20230005",
          status: "1",
        },
        {
          id: 12,
          name: "阮馨学",
          teamId: 4,
          teamName: "急诊抢救团队",
          position: "急诊医师",
          phone: "13800138012",
          email: "ruanxinxue@hospital.com",
          currentWorkOrder: "MED20230006",
          status: "1",
        },
        {
          id: 13,
          name: "翁惠珠",
          teamId: 4,
          teamName: "急诊抢救团队",
          position: "急诊护士",
          phone: "13800138013",
          email: "wenghuizhu@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        // å…¶ä»–医疗人员
        {
          id: 14,
          name: "方兆玉",
          teamId: 1,
          teamName: "心血管内科团队",
          position: "心电技师",
          phone: "13800138014",
          email: "fangzhaoyu@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
        {
          id: 15,
          name: "丁汉臻",
          teamId: 2,
          teamName: "肿瘤科治疗团队",
          position: "病理医师",
          phone: "13800138015",
          email: "dinghanzhen@hospital.com",
          currentWorkOrder: "",
          status: "1",
        },
      ],
      memberTotal: 15,
      memberQueryParams: {
        pageNum: 1,
        pageSize: 10,
        name: undefined,
        teamId: undefined,
        status: undefined
        status: undefined,
      },
      memberTotal: 8,
      memberStatusOptions: [
        { value: "0", label: "禁用" },
        { value: "1", label: "启用" }
        { value: "1", label: "启用" },
      ],
      memberFormVisible: false,
      memberFormTitle: "",
@@ -760,57 +1444,135 @@
        position: undefined,
        phone: undefined,
        email: undefined,
        status: "1"
        status: "1",
      },
      memberRules: {
        name: [
          { required: true, message: "成员姓名不能为空", trigger: "blur" }
          { required: true, message: "成员姓名不能为空", trigger: "blur" },
        ],
        teamId: [
          { required: true, message: "所属团队不能为空", trigger: "change" }
          { required: true, message: "所属团队不能为空", trigger: "change" },
        ],
        position: [
          { required: true, message: "职位不能为空", trigger: "blur" }
          { required: true, message: "职位不能为空", trigger: "blur" },
        ],
        phone: [
          { required: true, message: "联系电话不能为空", trigger: "blur" }
          { required: true, message: "联系电话不能为空", trigger: "blur" },
        ],
        email: [
          { required: true, message: "邮箱不能为空", trigger: "blur" },
          { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
          {
            type: "email",
            message: "请输入正确的邮箱地址",
            trigger: ["blur", "change"],
          },
        ],
        status: [
          { required: true, message: "成员状态不能为空", trigger: "change" }
        ]
          { required: true, message: "成员状态不能为空", trigger: "change" },
        ],
      },
      // å·¥å•指派相关数据
      workOrderLoading: false,
      // æ›¿æ¢åŽŸæœ‰çš„workOrderList数据
      workOrderList: [
        { id: "WO20230001", title: "首页改版需求开发", priority: "1", createTime: "2023-03-01 09:30:00", deadline: "2023-03-15 18:00:00", assignee: 1, assigneeName: "张三", status: "1", content: "完成首页改版的所有前端开发工作" },
        { id: "WO20230002", title: "用户中心接口开发", priority: "2", createTime: "2023-03-05 14:20:00", deadline: "2023-03-20 18:00:00", assignee: 3, assigneeName: "王五", status: "1", content: "开发用户中心相关接口" },
        { id: "WO20230003", title: "订单系统性能优化", priority: "1", createTime: "2023-03-10 10:15:00", deadline: "2023-03-25 18:00:00", assignee: 4, assigneeName: "赵六", status: "1", content: "优化订单系统性能,提高响应速度" },
        { id: "WO20230004", title: "支付功能测试", priority: "3", createTime: "2023-03-15 16:45:00", deadline: "2023-03-30 18:00:00", assignee: 7, assigneeName: "周九", status: "1", content: "完成支付功能的全面测试" },
        { id: "WO20230005", title: "数据报表开发", priority: "2", createTime: "2023-03-20 11:10:00", deadline: "2023-04-05 18:00:00", assignee: undefined, assigneeName: undefined, status: "0", content: "开发数据统计报表功能" }
        {
          id: "MED20230001",
          title: "冠心病患者PCI手术安排",
          priority: "1",
          createTime: "2024-11-01 09:30:00",
          deadline: "2024-11-05 18:00:00",
          assignee: 1,
          assigneeName: "李成白",
          status: "1",
          content:
            "为冠心病患者安排经皮冠状动脉介入治疗手术,需要术前评估和准备",
        },
        {
          id: "MED20230002",
          title: "高血压患者药物治疗方案调整",
          priority: "2",
          createTime: "2024-11-03 14:20:00",
          deadline: "2024-11-08 18:00:00",
          assignee: 3,
          assigneeName: "张孟涵",
          status: "1",
          content: "根据患者血压监测结果,调整降压药物组合和剂量",
        },
        {
          id: "MED20230003",
          title: "肺癌患者化疗周期安排",
          priority: "1",
          createTime: "2024-11-05 10:15:00",
          deadline: "2024-11-10 18:00:00",
          assignee: 4,
          assigneeName: "陈政倩",
          status: "1",
          content: "制定肺癌患者新一期化疗方案,包括药物选择和剂量计算",
        },
        {
          id: "MED20230004",
          title: "儿童肺炎患者诊疗方案",
          priority: "2",
          createTime: "2024-11-08 16:45:00",
          deadline: "2024-11-12 18:00:00",
          assignee: 7,
          assigneeName: "王恩龙",
          status: "1",
          content: "为儿童肺炎患者制定个性化治疗方案,包括抗生素选择和雾化治疗",
        },
        {
          id: "MED20230005",
          title: "急诊胸痛患者快速评估",
          priority: "1",
          createTime: "2024-11-10 11:10:00",
          deadline: "2024-11-10 23:00:00",
          assignee: 11,
          assigneeName: "吴俊伯",
          status: "1",
          content: "对急诊胸痛患者进行快速评估,排除急性心肌梗死可能",
        },
        {
          id: "MED20230006",
          title: "外伤患者清创缝合处理",
          priority: "2",
          createTime: "2024-11-12 13:25:00",
          deadline: "2024-11-12 20:00:00",
          assignee: 12,
          assigneeName: "阮馨学",
          status: "1",
          content: "处理急诊外伤患者的伤口清创和缝合工作",
        },
        {
          id: "MED20230007",
          title: "糖尿病患者胰岛素调整",
          priority: "2",
          createTime: "2024-11-15 08:45:00",
          deadline: "2024-11-20 18:00:00",
          assignee: undefined,
          assigneeName: undefined,
          status: "0",
          content: "根据患者血糖监测数据,调整胰岛素用量和注射方案",
        },
      ],
      workOrderTotal: 7,
      workOrderQueryParams: {
        pageNum: 1,
        pageSize: 10,
        id: undefined,
        status: undefined,
        assignee: undefined
        assignee: undefined,
      },
      workOrderTotal: 5,
      workOrderStatusOptions: [
        { value: "0", label: "待指派" },
        { value: "1", label: "进行中" },
        { value: "2", label: "已完成" },
        { value: "3", label: "已取消" }
        { value: "3", label: "已取消" },
      ],
      priorityOptions: [
        { value: "1", label: "高" },
        { value: "2", label: "中" },
        { value: "3", label: "低" }
        { value: "3", label: "低" },
      ],
      workOrderFormVisible: false,
      workOrderFormTitle: "",
@@ -822,24 +1584,24 @@
        deadline: undefined,
        assignee: undefined,
        status: "0",
        content: undefined
        content: undefined,
      },
      workOrderRules: {
        title: [
          { required: true, message: "工单标题不能为空", trigger: "blur" }
          { required: true, message: "工单标题不能为空", trigger: "blur" },
        ],
        priority: [
          { required: true, message: "优先级不能为空", trigger: "change" }
          { required: true, message: "优先级不能为空", trigger: "change" },
        ],
        deadline: [
          { required: true, message: "截止时间不能为空", trigger: "change" }
          { required: true, message: "截止时间不能为空", trigger: "change" },
        ],
        content: [
          { required: true, message: "工单内容不能为空", trigger: "blur" }
          { required: true, message: "工单内容不能为空", trigger: "blur" },
        ],
        status: [
          { required: true, message: "工单状态不能为空", trigger: "change" }
        ]
          { required: true, message: "工单状态不能为空", trigger: "change" },
        ],
      },
      // æŒ‡æ´¾å·¥å•相关数据
@@ -849,30 +1611,44 @@
        title: undefined,
        assignee: undefined,
        priority: "2",
        deadline: undefined
      }
        deadline: undefined,
      },
    };
  },
  // åœ¨watch中添加监控
  watch: {
    teamDialogVisible(newVal) {
      if (newVal) {
        // å¯¹è¯æ¡†æ˜¾ç¤ºæ—¶é‡æ–°ç”ŸæˆäºŒç»´ç 
        this.$nextTick(() => {
          setTimeout(() => {
            this.generateTeamQRContent(this.currentTeam);
          }, 100);
        });
      }
    },
  },
  computed: {
    // å›¢é˜Ÿæˆå‘˜é€‰é¡¹ï¼ˆç”¨äºŽç©¿æ¢­æ¡†ï¼‰
    memberOptions() {
      return this.memberList.map(member => ({
      return this.memberList.map((member) => ({
        key: member.id,
        label: member.name,
        disabled: member.status === "0"
        disabled: member.status === "0",
      }));
    },
    // è¿‡æ»¤åŽçš„团队列表
    filteredTeamList() {
      let list = [...this.teamList];
      if (this.teamQueryParams.name) {
        list = list.filter(item =>
        list = list.filter((item) =>
          item.name.includes(this.teamQueryParams.name)
        );
      }
      if (this.teamQueryParams.status) {
        list = list.filter(item =>
          item.status === this.teamQueryParams.status
        list = list.filter(
          (item) => item.status === this.teamQueryParams.status
        );
      }
      return list;
@@ -881,18 +1657,18 @@
    filteredMemberList() {
      let list = [...this.memberList];
      if (this.memberQueryParams.name) {
        list = list.filter(item =>
        list = list.filter((item) =>
          item.name.includes(this.memberQueryParams.name)
        );
      }
      if (this.memberQueryParams.teamId) {
        list = list.filter(item =>
          item.teamId === this.memberQueryParams.teamId
        list = list.filter(
          (item) => item.teamId === this.memberQueryParams.teamId
        );
      }
      if (this.memberQueryParams.status) {
        list = list.filter(item =>
          item.status === this.memberQueryParams.status
        list = list.filter(
          (item) => item.status === this.memberQueryParams.status
        );
      }
      return list;
@@ -901,18 +1677,18 @@
    filteredWorkOrderList() {
      let list = [...this.workOrderList];
      if (this.workOrderQueryParams.id) {
        list = list.filter(item =>
        list = list.filter((item) =>
          item.id.includes(this.workOrderQueryParams.id)
        );
      }
      if (this.workOrderQueryParams.status) {
        list = list.filter(item =>
          item.status === this.workOrderQueryParams.status
        list = list.filter(
          (item) => item.status === this.workOrderQueryParams.status
        );
      }
      if (this.workOrderQueryParams.assignee) {
        list = list.filter(item =>
          item.assignee === this.workOrderQueryParams.assignee
        list = list.filter(
          (item) => item.assignee === this.workOrderQueryParams.assignee
        );
      }
      return list;
@@ -920,17 +1696,17 @@
    // å›¢é˜Ÿå·¥å•(用于团队详情)
    teamWorkOrders() {
      if (!this.currentTeam.id) return [];
      const teamMemberIds = this.currentTeam.members.map(member => member.id);
      return this.workOrderList.filter(order =>
      const teamMemberIds = this.currentTeam.members.map((member) => member.id);
      return this.workOrderList.filter((order) =>
        teamMemberIds.includes(order.assignee)
      );
    },
    // å¯ç”¨æˆå‘˜ï¼ˆç”¨äºŽå·¥å•指派)
    availableMembers() {
      return this.memberList.filter(member =>
        member.status === "1" && !member.currentWorkOrder
      return this.memberList.filter(
        (member) => member.status === "1" && !member.currentWorkOrder
      );
    }
    },
  },
  methods: {
    // è§£æžæ—¶é—´
@@ -947,6 +1723,113 @@
    handleTeamQuery() {
      this.teamQueryParams.pageNum = 1;
    },
    // æŸ¥çœ‹å›¢é˜Ÿè¯¦æƒ…时生成二维码
    handleTeamDetail(row) {
      this.currentTeam = row;
      this.teamDialogTitle = "团队详情 - " + row.name;
      this.teamDialogVisible = true;
      // ä½¿ç”¨nextTick确保DOM渲染完成
      this.$nextTick(() => {
        // ç”Ÿæˆä¸´æ—¶äºŒç»´ç å†…容
        this.generateTeamQRContent(row);
      });
    },
    // ç”Ÿæˆå›¢é˜ŸäºŒç»´ç å†…容
    generateTeamQRContent(team) {
      const timestamp = new Date().getTime();
      const expireTime = timestamp + 24 * 60 * 60 * 1000; // 24小时有效期
      const qrData = {
        teamId: team.id,
        teamName: team.name,
        leader: team.leader,
        memberCount: team.members.length,
        timestamp: timestamp,
        expireTime: expireTime,
        type: "team_info",
      };
      // ç¡®ä¿å†…容是字符串格式
      this.teamQRContent = "127.0.0.1:8093/wt?p=0BE9L3C2u";
      console.log("生成的二维码内容:", this.teamQRContent);
    },
    // äºŒç»´ç ç”Ÿæˆå›žè°ƒ
    onQRCodeGenerated(dataURL, id) {
      if (dataURL) {
        this.currentQRCodeUrl = dataURL;
        console.log("二维码生成成功");
      } else {
        console.error("二维码生成失败");
        // å¤‡ç”¨æ–¹æ¡ˆï¼šä½¿ç”¨qrcode.js生成
        this.generateQRCodeWithQRCodeJS();
      }
    },
    // å¤‡ç”¨ç”Ÿæˆæ–¹æ¡ˆ
    generateQRCodeWithQRCodeJS() {
      const QRCode = require("qrcode");
      if (this.teamQRContent) {
        QRCode.toDataURL(
          this.teamQRContent,
          {
            width: 200,
            height: 200,
            margin: 2,
            color: {
              dark: "#409EFF",
              light: "#FFFFFF",
            },
          },
          (err, url) => {
            if (err) {
              console.error("备用二维码生成失败:", err);
              return;
            }
            this.currentQRCodeUrl = url;
            console.log("备用二维码生成成功");
          }
        );
      }
    },
    // ä¸‹è½½äºŒç»´ç 
    downloadQRCode() {
      if (!this.currentQRCodeUrl) {
        this.$message.warning("请先生成二维码");
        return;
      }
      const a = document.createElement("a");
      const event = new MouseEvent("click");
      a.download = `团队二维码_${
        this.currentTeam.name
      }_${new Date().getTime()}.png`;
      a.href = this.currentQRCodeUrl;
      a.dispatchEvent(event);
    },
    // åˆ·æ–°äºŒç»´ç 
    refreshQRCode() {
      this.generateTeamQRContent(this.currentTeam);
      this.$message.success("二维码已刷新");
    },
    // åœ¨å·¥å•详情中也可以添加二维码功能
    handleWorkOrderDetail(row) {
      // ç”Ÿæˆå·¥å•二维码
      const qrData = {
        workOrderId: row.id,
        title: row.title,
        priority: row.priority,
        status: row.status,
        timestamp: new Date().getTime(),
        type: "work_order",
      };
      this.workOrderQRContent = JSON.stringify(qrData);
    },
    // é‡ç½®å›¢é˜Ÿæœç´¢
    resetTeamQuery() {
      this.resetForm("teamQueryForm");
@@ -954,15 +1837,9 @@
    },
    // å›¢é˜Ÿå¤šé€‰
    handleTeamSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.ids = selection.map((item) => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    // æŸ¥çœ‹å›¢é˜Ÿè¯¦æƒ…
    handleTeamDetail(row) {
      this.currentTeam = row;
      this.teamDialogTitle = "团队详情 - " + row.name;
      this.teamDialogVisible = true;
    },
    // æ–°å¢žå›¢é˜Ÿ
    handleTeamAdd() {
@@ -973,56 +1850,65 @@
    // ä¿®æ”¹å›¢é˜Ÿ
    handleTeamUpdate(row) {
      this.resetTeamForm();
      const team = this.teamList.find(item => item.id === row.id);
      const team = this.teamList.find((item) => item.id === row.id);
      this.teamForm = Object.assign({}, team);
      this.teamForm.members = team.members.map(member => member.id);
      this.teamForm.members = team.members.map((member) => member.id);
      this.teamFormTitle = "修改团队";
      this.teamFormVisible = true;
    },
    // åˆ é™¤å›¢é˜Ÿ
    handleTeamDelete(row) {
      const teamIds = row.id || this.ids;
      this.$modal.confirm('是否确认删除团队名称为"' + row.name + '"的数据项?').then(() => {
        // æ¨¡æ‹Ÿåˆ é™¤å›¢é˜Ÿ
        this.teamList = this.teamList.filter(item => item.id !== teamIds);
        this.teamTotal = this.teamList.length;
        this.$modal.msgSuccess("删除成功");
      }).catch(() => {});
      this.$modal
        .confirm('是否确认删除团队名称为"' + row.name + '"的数据项?')
        .then(() => {
          // æ¨¡æ‹Ÿåˆ é™¤å›¢é˜Ÿ
          this.teamList = this.teamList.filter((item) => item.id !== teamIds);
          this.teamTotal = this.teamList.length;
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
    },
    // æäº¤å›¢é˜Ÿè¡¨å•
    submitTeamForm() {
      this.$refs["teamForm"].validate(valid => {
      this.$refs["teamForm"].validate((valid) => {
        if (valid) {
          if (this.teamForm.id != null) {
            // æ¨¡æ‹Ÿä¿®æ”¹å›¢é˜Ÿ
            const index = this.teamList.findIndex(item => item.id === this.teamForm.id);
            const index = this.teamList.findIndex(
              (item) => item.id === this.teamForm.id
            );
            if (index !== -1) {
              const leader = this.memberList.find(member => member.id === this.teamForm.leader);
              const members = this.memberList.filter(member =>
              const leader = this.memberList.find(
                (member) => member.id === this.teamForm.leader
              );
              const members = this.memberList.filter((member) =>
                this.teamForm.members.includes(member.id)
              );
              this.teamList.splice(index, 1, {
                ...this.teamForm,
                leader: leader ? leader.name : '',
                members: members
                leader: leader ? leader.name : "",
                members: members,
              });
            }
            this.$modal.msgSuccess("修改成功");
          } else {
            // æ¨¡æ‹Ÿæ–°å¢žå›¢é˜Ÿ
            const newId = Math.max(...this.teamList.map(item => item.id)) + 1;
            const leader = this.memberList.find(member => member.id === this.teamForm.leader);
            const members = this.memberList.filter(member =>
            const newId = Math.max(...this.teamList.map((item) => item.id)) + 1;
            const leader = this.memberList.find(
              (member) => member.id === this.teamForm.leader
            );
            const members = this.memberList.filter((member) =>
              this.teamForm.members.includes(member.id)
            );
            this.teamList.unshift({
              ...this.teamForm,
              id: newId,
              leader: leader ? leader.name : '',
              leader: leader ? leader.name : "",
              members: members,
              createTime: new Date().toLocaleString()
              createTime: new Date().toLocaleString(),
            });
            this.teamTotal = this.teamList.length;
            this.$modal.msgSuccess("新增成功");
@@ -1039,7 +1925,7 @@
        leader: undefined,
        members: [],
        status: "1",
        description: undefined
        description: undefined,
      };
      this.resetForm("teamForm");
    },
@@ -1068,7 +1954,7 @@
    },
    // æˆå‘˜å¤šé€‰
    handleMemberSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.ids = selection.map((item) => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
@@ -1081,7 +1967,7 @@
    // ä¿®æ”¹æˆå‘˜
    handleMemberUpdate(row) {
      this.resetMemberForm();
      const member = this.memberList.find(item => item.id === row.id);
      const member = this.memberList.find((item) => item.id === row.id);
      this.memberForm = Object.assign({}, member);
      this.memberFormTitle = "修改成员";
      this.memberFormVisible = true;
@@ -1089,37 +1975,49 @@
    // åˆ é™¤æˆå‘˜
    handleMemberDelete(row) {
      const memberIds = row.id || this.ids;
      this.$modal.confirm('是否确认删除成员姓名为"' + row.name + '"的数据项?').then(() => {
        // æ¨¡æ‹Ÿåˆ é™¤æˆå‘˜
        this.memberList = this.memberList.filter(item => item.id !== memberIds);
        this.memberTotal = this.memberList.length;
        this.$modal.msgSuccess("删除成功");
      }).catch(() => {});
      this.$modal
        .confirm('是否确认删除成员姓名为"' + row.name + '"的数据项?')
        .then(() => {
          // æ¨¡æ‹Ÿåˆ é™¤æˆå‘˜
          this.memberList = this.memberList.filter(
            (item) => item.id !== memberIds
          );
          this.memberTotal = this.memberList.length;
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
    },
    // æäº¤æˆå‘˜è¡¨å•
    submitMemberForm() {
      this.$refs["memberForm"].validate(valid => {
      this.$refs["memberForm"].validate((valid) => {
        if (valid) {
          if (this.memberForm.id != null) {
            // æ¨¡æ‹Ÿä¿®æ”¹æˆå‘˜
            const index = this.memberList.findIndex(item => item.id === this.memberForm.id);
            const index = this.memberList.findIndex(
              (item) => item.id === this.memberForm.id
            );
            if (index !== -1) {
              const team = this.teamList.find(item => item.id === this.memberForm.teamId);
              const team = this.teamList.find(
                (item) => item.id === this.memberForm.teamId
              );
              this.memberList.splice(index, 1, {
                ...this.memberForm,
                teamName: team ? team.name : ''
                teamName: team ? team.name : "",
              });
            }
            this.$modal.msgSuccess("修改成功");
          } else {
            // æ¨¡æ‹Ÿæ–°å¢žæˆå‘˜
            const newId = Math.max(...this.memberList.map(item => item.id)) + 1;
            const team = this.teamList.find(item => item.id === this.memberForm.teamId);
            const newId =
              Math.max(...this.memberList.map((item) => item.id)) + 1;
            const team = this.teamList.find(
              (item) => item.id === this.memberForm.teamId
            );
            this.memberList.unshift({
              ...this.memberForm,
              id: newId,
              teamName: team ? team.name : '',
              currentWorkOrder: ''
              teamName: team ? team.name : "",
              currentWorkOrder: "",
            });
            this.memberTotal = this.memberList.length;
            this.$modal.msgSuccess("新增成功");
@@ -1137,7 +2035,7 @@
        position: undefined,
        phone: undefined,
        email: undefined,
        status: "1"
        status: "1",
      };
      this.resetForm("memberForm");
    },
@@ -1166,7 +2064,7 @@
    },
    // å·¥å•多选
    handleWorkOrderSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.ids = selection.map((item) => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
@@ -1179,7 +2077,7 @@
    // ä¿®æ”¹å·¥å•
    handleWorkOrderUpdate(row) {
      this.resetWorkOrderForm();
      const workOrder = this.workOrderList.find(item => item.id === row.id);
      const workOrder = this.workOrderList.find((item) => item.id === row.id);
      this.workOrderForm = Object.assign({}, workOrder);
      this.workOrderFormTitle = "编辑工单";
      this.workOrderFormVisible = true;
@@ -1187,12 +2085,17 @@
    // åˆ é™¤å·¥å•
    handleWorkOrderDelete(row) {
      const workOrderIds = row.id || this.ids;
      this.$modal.confirm('是否确认删除工单标题为"' + row.title + '"的数据项?').then(() => {
        // æ¨¡æ‹Ÿåˆ é™¤å·¥å•
        this.workOrderList = this.workOrderList.filter(item => item.id !== workOrderIds);
        this.workOrderTotal = this.workOrderList.length;
        this.$modal.msgSuccess("删除成功");
      }).catch(() => {});
      this.$modal
        .confirm('是否确认删除工单标题为"' + row.title + '"的数据项?')
        .then(() => {
          // æ¨¡æ‹Ÿåˆ é™¤å·¥å•
          this.workOrderList = this.workOrderList.filter(
            (item) => item.id !== workOrderIds
          );
          this.workOrderTotal = this.workOrderList.length;
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
    },
    // æŒ‡æ´¾å·¥å•
    handleAssignWorkOrder(row) {
@@ -1201,34 +2104,43 @@
        title: row.title,
        assignee: undefined,
        priority: row.priority,
        deadline: row.deadline
        deadline: row.deadline,
      };
      this.assignDialogVisible = true;
    },
    // æäº¤å·¥å•表单
    submitWorkOrderForm() {
      this.$refs["workOrderForm"].validate(valid => {
      this.$refs["workOrderForm"].validate((valid) => {
        if (valid) {
          if (this.workOrderForm.id != null) {
            // æ¨¡æ‹Ÿä¿®æ”¹å·¥å•
            const index = this.workOrderList.findIndex(item => item.id === this.workOrderForm.id);
            const index = this.workOrderList.findIndex(
              (item) => item.id === this.workOrderForm.id
            );
            if (index !== -1) {
              const assignee = this.memberList.find(member => member.id === this.workOrderForm.assignee);
              const assignee = this.memberList.find(
                (member) => member.id === this.workOrderForm.assignee
              );
              this.workOrderList.splice(index, 1, {
                ...this.workOrderForm,
                assigneeName: assignee ? assignee.name : undefined
                assigneeName: assignee ? assignee.name : undefined,
              });
            }
            this.$modal.msgSuccess("修改成功");
          } else {
            // æ¨¡æ‹Ÿæ–°å¢žå·¥å•
            const newId = "WO" + new Date().getFullYear() + (Math.floor(Math.random() * 90000) + 10000);
            const assignee = this.memberList.find(member => member.id === this.workOrderForm.assignee);
            const newId =
              "WO" +
              new Date().getFullYear() +
              (Math.floor(Math.random() * 90000) + 10000);
            const assignee = this.memberList.find(
              (member) => member.id === this.workOrderForm.assignee
            );
            this.workOrderList.unshift({
              ...this.workOrderForm,
              id: newId,
              assigneeName: assignee ? assignee.name : undefined,
              createTime: new Date().toLocaleString()
              createTime: new Date().toLocaleString(),
            });
            this.workOrderTotal = this.workOrderList.length;
            this.$modal.msgSuccess("新增成功");
@@ -1247,7 +2159,7 @@
        deadline: undefined,
        assignee: undefined,
        status: "0",
        content: undefined
        content: undefined,
      };
      this.resetForm("workOrderForm");
    },
@@ -1264,9 +2176,13 @@
      }
      // æ¨¡æ‹ŸæŒ‡æ´¾å·¥å•
      const index = this.workOrderList.findIndex(item => item.id === this.assignForm.id);
      const index = this.workOrderList.findIndex(
        (item) => item.id === this.assignForm.id
      );
      if (index !== -1) {
        const assignee = this.memberList.find(member => member.id === this.assignForm.assignee);
        const assignee = this.memberList.find(
          (member) => member.id === this.assignForm.assignee
        );
        if (assignee) {
          // æ›´æ–°å·¥å•状态
          this.workOrderList.splice(index, 1, {
@@ -1275,15 +2191,17 @@
            assigneeName: assignee.name,
            priority: this.assignForm.priority,
            deadline: this.assignForm.deadline,
            status: "1"
            status: "1",
          });
          // æ›´æ–°æˆå‘˜å½“前工单
          const memberIndex = this.memberList.findIndex(member => member.id === this.assignForm.assignee);
          const memberIndex = this.memberList.findIndex(
            (member) => member.id === this.assignForm.assignee
          );
          if (memberIndex !== -1) {
            this.memberList.splice(memberIndex, 1, {
              ...this.memberList[memberIndex],
              currentWorkOrder: this.assignForm.id
              currentWorkOrder: this.assignForm.id,
            });
          }
@@ -1291,8 +2209,8 @@
          this.assignDialogVisible = false;
        }
      }
    }
  }
    },
  },
};
</script>
@@ -1319,7 +2237,7 @@
}
.avatar-uploader ::v-deep .el-upload:hover {
  border-color: #409EFF;
  border-color: #409eff;
}
.avatar-uploader-icon {
@@ -1337,7 +2255,8 @@
  display: block;
}
.team-members, .team-work-orders {
.team-members,
.team-work-orders {
  margin-top: 20px;
}
</style>
vue.config.js
@@ -38,7 +38,8 @@
        // target: `http://192.168.168.60:8095`,
        // target: `http://192.168.144.34:8095`,
        // target: `http://220.66.136.101:8095`,
        target:`http://localhost:8095`,
        target: `http://192.168.100.10:8099`,
        // target:`http://localhost:8095`,
        changeOrigin: true,
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: ''
wx.zip
Binary files differ