WXL
14 小时以前 9b2c74ee4f08fad01c2a16bc6e36df073bfa1dd5
推送
已修改17个文件
已添加2个文件
3641 ■■■■ 文件已修改
src/api/businessApi/decide.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/CaseBasicInfo/index.vue 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/affirm/affirmInfo.vue 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/affirm/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/appear/caseDetail.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/appear/index.vue 148 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/assess/assessInfo.vue 123 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/assess/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/decide/DecideInfo.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/decide/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/ethicalReview/ethicalReviewInfo copy.vue 1536 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/ethicalReview/ethicalReviewInfo.vue 943 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/ethicalReview/index.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/maintainInfo.vue 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/transfer/index.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/DonationProcess/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatebaseinfo/EditCaseModal.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatebaseinfo/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/decide.js
@@ -16,6 +16,13 @@
    data: data
  })
}
export function deathinfoadd(data) {
  return request({
    url: '/project/deathinfo/add',
    method: 'post',
    data: data
  })
}
// æ­»äº¡ä¿¡æ¯è¯¦æƒ…
export function deathinfoInfo(id) {
  return request({
src/components/CaseBasicInfo/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,400 @@
<template>
  <el-card class="basic-info-card" v-loading="loading">
    <div slot="header" class="clearfix">
      <span>案例基本信息</span>
      <el-button
        v-if="showAttachment && hasAttachments"
        style="float: right; padding: 3px 0"
        type="text"
        @click="handleAttachmentPreview"
      >
        <i class="el-icon-folder-opened"></i> æŸ¥çœ‹é™„ä»¶
      </el-button>
    </div>
    <el-descriptions v-if="basicData" :column="column" border>
      <!-- 1. æ¡ˆä¾‹ç¼–号 -->
      <el-descriptions-item label="案例编号">
        {{ basicData.caseNo || "--" }}
      </el-descriptions-item>
      <!-- 2. æ½œåœ¨æçŒ®è€…姓名 -->
      <el-descriptions-item label="捐献者姓名">
        {{ basicData.name || basicData.donorName || "--" }}
      </el-descriptions-item>
      <!-- 3. æ€§åˆ«/年龄 -->
      <el-descriptions-item label="性别/年龄">
        <span v-if="basicData.sex">
          <dict-tag
            v-if="useDict"
            :options="sexOptions"
            :value="basicData.sex"
          />
          <template v-else>{{ basicData.sex == "1" ? "男" : "女" }}</template>
        </span>
        <span v-if="basicData.age">
          / {{ basicData.age }}{{ basicData.ageunit || "岁" }}</span
        >
        <span v-if="!basicData.sex && !basicData.age">--</span>
      </el-descriptions-item>
      <!-- 4. è¯ä»¶å·ç  -->
      <el-descriptions-item label="证件号码">
        {{ basicData.idcardno || basicData.idCardNo || "--" }}
      </el-descriptions-item>
      <!-- 5. è¡€åž‹ -->
      <el-descriptions-item label="血型">
        <template v-if="basicData.bloodType || basicData.bloodtype">
          {{ basicData.bloodType || basicData.bloodtype }}
        </template>
        <template v-else>--</template>
      </el-descriptions-item>
      <!-- 6. ç–¾ç—…诊断 -->
      <el-descriptions-item label="疾病诊断">
        {{ basicData.diagnosisname || basicData.diagnosis || "--" }}
      </el-descriptions-item>
      <!-- 7. æ‰€åœ¨åŒ»ç–—机构 -->
      <el-descriptions-item label="所在医疗机构">
        {{ basicData.treatmenthospitalname || basicData.hospitalName || "--" }}
      </el-descriptions-item>
      <!-- 8. åè°ƒå‘˜ -->
      <el-descriptions-item label="协调员">
        {{ basicData.coordinatorName || basicData.contactPerson || "--" }}
      </el-descriptions-item>
      <!-- 9. ä¸ŠæŠ¥æ—¶é—´ -->
      <el-descriptions-item label="上报时间">
        {{ formatDateTime(basicData.reportTime) || "--" }}
      </el-descriptions-item>
      <!-- 10. æ¡ˆä¾‹çŠ¶æ€ -->
      <el-descriptions-item label="案例进度">
        <!-- <el-tag :type="getReportStatusType(basicData.workflow)" size="small">
          {{ getReportStatusText(basicData.workflow) }}
        </el-tag> -->
        <div>
          <dict-tag
            :options="dict.type.sys_donornode"
            :value="basicData.workflow"
          />
        </div>
      </el-descriptions-item>
      <!-- 11. è½¬è¿çŠ¶æ€ï¼ˆæ ¹æ®éœ€æ±‚å¯é€‰ï¼‰ -->
      <el-descriptions-item v-if="showTransport" label="转运状态">
        <el-tag
          :type="getTransportStatusType(basicData.isTransport)"
          size="small"
        >
          {{ getTransportStatusText(basicData.isTransport) }}
        </el-tag>
      </el-descriptions-item>
    </el-descriptions>
    <!-- ç©ºçŠ¶æ€ -->
    <div v-else class="empty-state">
      <el-empty description="暂无案例信息" :image-size="100"></el-empty>
    </div>
  </el-card>
</template>
<script>
import { getDonatebaseinfo } from "@/api/project/donatebaseinfo";
export default {
  name: "CaseBasicInfoSimple",
  props: {
    // æ¡ˆä¾‹ID
    caseId: {
      type: [String, Number],
      required: true
    },
    // åˆ—æ•°
    column: {
      type: Number,
      default: 2
    },
    // æ˜¯å¦æ˜¾ç¤ºé™„件按钮
    showAttachment: {
      type: Boolean,
      default: false
    },
    // æ˜¯å¦ä½¿ç”¨å­—å…¸
    useDict: {
      type: Boolean,
      default: false
    },
    // æ˜¯å¦æ˜¾ç¤ºè½¬è¿çŠ¶æ€
    showTransport: {
      type: Boolean,
      default: false
    },
    // æ˜¯å¦è‡ªåŠ¨åŠ è½½
    autoLoad: {
      type: Boolean,
      default: true
    },
    // å¤–部传入的数据(不调用接口)
    externalData: {
      type: Object,
      default: null
    },
    // è‡ªå®šä¹‰å­—段列表
    fields: {
      type: Array,
      default: () => [
        "caseNo", // æ¡ˆä¾‹ç¼–号
        "name", // å§“名
        "sexAge", // æ€§åˆ«/年龄
        "idcardno", // è¯ä»¶å·ç 
        "bloodType", // è¡€åž‹
        "diagnosis", // ç–¾ç—…诊断
        "hospital", // åŒ»ç–—机构
        "coordinator", // åè°ƒå‘˜
        "reportTime", // ä¸ŠæŠ¥æ—¶é—´
        "status" // æ¡ˆä¾‹çŠ¶æ€
      ]
    }
  },
  dicts: [
    "sys_user_sex",
    "sys_BloodType",
    "sys_DonationCategory",
    "sys_donornode"
  ],
  data() {
    return {
      loading: false,
      basicData: null,
      // å­—典选项
      sexOptions: [],
      bloodTypeOptions: []
    };
  },
  computed: {
    hasAttachments() {
      return (
        this.basicData &&
        (this.basicData.assessannex || this.basicData.attachments)
      );
    }
  },
  watch: {
    caseId: {
      handler(newVal) {
        if (newVal && this.autoLoad && !this.externalData) {
          this.loadBasicInfo();
        }
      },
      immediate: true
    },
    externalData: {
      handler(newVal) {
        if (newVal) {
          this.basicData = this.mapExternalData(newVal);
        }
      },
      immediate: true
    }
  },
  created() {
    if (this.useDict) {
      this.loadDicts();
    }
    if (this.caseId && this.autoLoad && !this.externalData) {
      this.loadBasicInfo();
    } else if (this.externalData) {
      this.basicData = this.mapExternalData(this.externalData);
    }
  },
  methods: {
    // åŠ è½½å­—å…¸
    async loadDicts() {
      try {
        // åŠ è½½æ€§åˆ«å­—å…¸
        this.sexOptions = [
          { dictLabel: "男", dictValue: "1" },
          { dictLabel: "女", dictValue: "2" }
        ];
        // åŠ è½½è¡€åž‹å­—å…¸
        this.bloodTypeOptions = [
          { dictLabel: "A型", dictValue: "A" },
          { dictLabel: "B型", dictValue: "B" },
          { dictLabel: "O型", dictValue: "O" },
          { dictLabel: "AB型", dictValue: "AB" }
        ];
      } catch (error) {
        console.warn("加载字典失败:", error);
      }
    },
    // åŠ è½½åŸºæœ¬ä¿¡æ¯
    async loadBasicInfo() {
      if (!this.caseId) return;
      this.loading = true;
      try {
        const response = await getDonatebaseinfo(this.caseId);
        if (response.code === 200) {
          this.basicData = this.mapApiData(response.data);
          console.log(this.basicData );
          this.loading = false;
        } else {
          this.$message.error(
            "获取案例信息失败:" + (response.msg || "未知错误")
          );
        }
      } catch (error) {
        console.error("加载案例基本信息失败:", error);
        this.$message.error("加载失败,请重试");
      } finally {
        this.loading = false;
      }
    },
    // æ˜ å°„API数据
    mapApiData(apiData) {
      if (!apiData) return null;
      return {
        // æ ¸å¿ƒå­—段
        caseNo: apiData.caseNo,
        name: apiData.name || apiData.donorName,
        donorName: apiData.donorName,
        sex: apiData.sex,
        age: apiData.age,
        ageunit: apiData.ageunit,
        workflow: apiData.workflow,
        bloodType: apiData.bloodType || apiData.bloodtype,
        idcardno: apiData.idcardno || apiData.idCardNo,
        diagnosisname: apiData.diagnosisname || apiData.diagnosis,
        treatmenthospitalname:
          apiData.treatmenthospitalname || apiData.hospitalName,
        coordinatorName: apiData.coordinatorName || apiData.contactPerson,
        reportTime: apiData.reporttime,
        reportStatus: apiData.reportStatus,
        isTransport: apiData.isTransport,
        // é™„件字段
        assessannex: apiData.assessannex,
        attachments: apiData.attachments
      };
    },
    // æ˜ å°„外部数据
    mapExternalData(externalData) {
      return this.mapApiData(externalData);
    },
    // æ ¼å¼åŒ–日期时间
    formatDateTime(dateTimeStr) {
      if (!dateTimeStr) return "";
      try {
        const date = new Date(dateTimeStr);
        return date
          .toLocaleString("zh-CN", {
            year: "numeric",
            month: "2-digit",
            day: "2-digit",
            hour: "2-digit",
            minute: "2-digit",
            second: "2-digit"
          })
          .replace(/\//g, "-");
      } catch (e) {
        return dateTimeStr;
      }
    },
    // ä¸ŠæŠ¥çŠ¶æ€ç›¸å…³
    getReportStatusType(status) {
      const statusMap = {
        "1": "warning", // å·²ä¸ŠæŠ¥
        "2": "primary", // å·²é˜…读
        "3": "success", // å·²åŒæ„
        "4": "danger" // å·²é©³å›ž
      };
      return statusMap[status] || "info";
    },
    getReportStatusText(status) {
      const statusMap = {
        "0": "潜在捐献",
        "2": "已阅读",
        "3": "已同意",
        "4": "已驳回"
      };
      return statusMap[status] || "未知";
    },
    // è½¬è¿çŠ¶æ€ç›¸å…³
    getTransportStatusType(status) {
      const statusMap = {
        "1": "warning", // æ— éœ€è½¬è¿
        "2": "primary", // éœ€è½¬è¿
        "3": "success", // è½¬è¿ä¸­
        "4": "danger" // è½¬è¿å®Œæˆ
      };
      return statusMap[status] || "info";
    },
    getTransportStatusText(status) {
      const statusMap = {
        "1": "无需转运",
        "2": "需转运",
        "3": "转运中",
        "4": "转运完成"
      };
      return statusMap[status] || "未知";
    },
    // æŸ¥çœ‹é™„ä»¶
    handleAttachmentPreview() {
      this.$emit("attachment-preview", this.basicData);
    },
    // åˆ·æ–°æ•°æ®
    async refresh() {
      await this.loadBasicInfo();
    },
    // èŽ·å–æ•°æ®
    getData() {
      return this.basicData;
    }
  }
};
</script>
<style scoped>
.basic-info-card {
  margin-bottom: 20px;
}
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}
.empty-state {
  padding: 40px 0;
  text-align: center;
}
/* å“åº”式设计 */
@media (max-width: 768px) {
  .basic-info-card {
    margin: 10px;
  }
}
</style>
src/views/business/affirm/affirmInfo.vue
@@ -1,9 +1,11 @@
<template>
  <div class="confirmation-detail">
    <case-basic-info :case-id="caseId" :show-attachment="true" />
    <el-card class="detail-card">
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <div slot="header" class="clearfix">
        <span class="detail-title">捐献确认基本信息</span>
        <span class="detail-title">捐献确认信息</span>
        <el-button
          type="success"
          style="float: right;"
@@ -15,45 +17,6 @@
      </div>
      <el-form :model="form" ref="form" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="住院号" prop="caseNo">
              <el-input v-model="form.caseNo" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="name">
              <el-input v-model="form.name" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="sex">
              <el-select v-model="form.sex" style="width: 100%">
                <el-option label="男" value="1" />
                <el-option label="女" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="疾病诊断" prop="diagnosisname">
              <el-input v-model="form.diagnosisname" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="所在医疗机构" prop="treatmenthospitalname">
              <el-input v-model="form.treatmenthospitalname" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="协调员1" prop="coordinatedusernameo">
@@ -91,7 +54,6 @@
              <el-date-picker
                v-model="form.signdate"
                type="datetime"
                value-format="yyyy-MM-dd"
                style="width: 100%"
              />
            </el-form-item>
@@ -343,15 +305,18 @@
<script>
import { relativesList, relativesEdit, relativesAdd } from "@/api/businessApi";
import FilePreviewDialog from "@/components/FilePreviewDialog";
import CaseBasicInfo from "@/components/CaseBasicInfo";
export default {
  name: "ConfirmationDetail",
  components: {
    FilePreviewDialog
    FilePreviewDialog,
    CaseBasicInfo
  },
  dicts: ["sys_FamilyRelation"],
  data() {
    return {
      caseId: null,
      // æ˜¯å¦ç¼–辑模式
      isEdit: false,
      // è¡¨å•数据
@@ -394,6 +359,7 @@
      // åŠ è½½çŠ¶æ€
      loading: false,
      saveLoading: false,
      infoid:null,
      // é™„件相关数据
      activeAttachmentType: "1",
      attachmentLoading: false,
@@ -435,10 +401,11 @@
    }
  },
  created() {
    const infoid = this.$route.query.infoid;
    this.infoid = this.$route.query.infoid;
    this.caseId = this.$route.query.infoid;
    this.isEdit = this.$route.query.confirm === "true";
    if (infoid) {
      this.getDetail(infoid);
    if (this.infoid) {
      this.getDetail(this.infoid);
    }
  },
  methods: {
@@ -801,6 +768,7 @@
        const saveData = {
          ...this.form,
          infoid: this.infoid,
          organdecision: this.organdecision.join(","),
          organdecisionOther: this.organdecisionOther
          // assessannex字段已在updateAssessannexField中更新
src/views/business/affirm/index.vue
@@ -71,7 +71,7 @@
    <el-card class="tool-card">
      <el-row :gutter="10">
        <el-col :span="16">
          <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
          <!-- <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
            >新增确认</el-button
          >
          <el-button
@@ -87,7 +87,7 @@
            :disabled="multiple"
            @click="handleDelete"
            >删除</el-button
          >
          > -->
          <el-button
            type="warning"
            icon="el-icon-download"
src/views/business/appear/caseDetail.vue
@@ -63,7 +63,7 @@
    </el-card>
    <!-- åœ°å€ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section">
    <!-- <el-card class="detail-section">
      <div slot="header" class="section-header">
        <span class="section-title">地址信息</span>
      </div>
@@ -75,7 +75,7 @@
          {{ getFullResidenceAddress() }}
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
    </el-card> -->
    <!-- åŒ»ç–—信息模块 -->
    <el-card class="detail-section">
@@ -86,12 +86,12 @@
        <el-descriptions-item label="疾病诊断名称">{{
          caseData.diagnosisname || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="病情概况">{{
        <!-- <el-descriptions-item label="病情概况">{{
          caseData.illnessoverview || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="病人状况">{{
          caseData.patientstate || "-"
        }}</el-descriptions-item>
        }}</el-descriptions-item> -->
        <el-descriptions-item label="GCS评分">{{
          caseData.gcsScore || "-"
        }}</el-descriptions-item>
@@ -118,18 +118,18 @@
        <el-descriptions-item label="治疗医院名称">{{
          caseData.treatmenthospitalname || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="治疗科室名称">{{
        <!-- <el-descriptions-item label="治疗科室名称">{{
          caseData.treatmentdeptname || "-"
        }}</el-descriptions-item>
        }}</el-descriptions-item> -->
        <el-descriptions-item label="住院号">{{
          caseData.inpatientno || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="部门名称">{{
          caseData.deptName || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="部门编号">{{
        <!-- <el-descriptions-item label="部门编号">{{
          caseData.deptNo || "-"
        }}</el-descriptions-item>
        }}</el-descriptions-item> -->
        <el-descriptions-item label="上报医院">{{
          caseData.toHospital || "-"
        }}</el-descriptions-item>
src/views/business/appear/index.vue
@@ -16,10 +16,10 @@
            style="width: 200px"
          />
        </el-form-item>
        <el-form-item label="捐献者姓名" prop="name">
        <el-form-item label="患者姓名" prop="name">
          <el-input
            v-model="queryParams.name"
            placeholder="请输入捐献者姓名"
            placeholder="请输入患者姓名"
            clearable
            style="width: 200px"
          />
@@ -88,7 +88,26 @@
        width="160"
      />
      <el-table-column
        label="捐献者姓名"
        label="状态"
        align="center"
        prop="reportStatus"
        width="100"
      >
        <template #default="scope">
          <el-tag :type="scope.row.reportStatus | statusFilter">
            {{ scope.row.reportStatus | statusTextFilter }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="转运状态" align="center" width="100">
        <template #default="scope">
          <el-tag :type="getTransportStatusTag(scope.row)">
            {{ getTransportStatusText(scope.row) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        label="患者姓名"
        align="center"
        prop="name"
        width="100"
@@ -127,32 +146,8 @@
        prop="treatmenthospitalname"
        width="150"
      />
      <el-table-column
        label="状态"
        align="center"
        prop="reportStatus"
        width="100"
      >
        <template #default="scope">
          <el-tag :type="scope.row.reportStatus | statusFilter">
            {{ scope.row.reportStatus | statusTextFilter }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="转运状态" align="center" width="100">
        <template #default="scope">
          <el-tag :type="getTransportStatusTag(scope.row)">
            {{ getTransportStatusText(scope.row) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        label="操作"
        align="center"
        fixed="right"
        class-name="small-padding fixed-width"
        width="350"
      >
      <el-table-column label="操作" align="center" fixed="right" width="350">
        <template #default="scope">
          <el-button
            size="mini"
@@ -179,13 +174,13 @@
            icon="el-icon-check"
            @click="handleApprove(scope.row)"
            v-if="scope.row.reportStatus === '2' && scope.row.delFlag === 0"
            >审批</el-button
            >确认</el-button
          >
          <el-button
            size="mini"
            type="text"
            icon="el-icon-truck"
            :type="shouldShowTransportButton(scope.row) ? 'primary' : 'text'"
            :type="getTransportStatustype(scope.row)"
            @click="handleTransport(scope.row)"
            v-if="shouldShowTransportButton(scope.row)"
            :disabled="!canGoToTransport(scope.row)"
@@ -216,9 +211,9 @@
      <case-detail :caseData="currentCase" @close="detailOpen = false" />
    </el-dialog>
    <!-- å®¡æ‰¹å¼¹æ¡† -->
    <!-- ç¡®è®¤å¼¹æ¡† -->
    <el-dialog
      title="案例审批"
      title="案例确认"
      :visible.sync="approveOpen"
      width="80vw"
      append-to-body
@@ -236,7 +231,7 @@
          </div>
        </el-aside>
        <!-- å³ä¾§ï¼šå®¡æ‰¹è¡¨å• -->
        <!-- å³ä¾§ï¼šç¡®è®¤è¡¨å• -->
        <el-main style="padding: 20px;">
          <el-form
            ref="approveForm"
@@ -244,17 +239,17 @@
            :rules="approveRules"
            label-width="100px"
          >
            <el-form-item label="审批结果" prop="approveResult">
            <el-form-item label="确认结果" prop="approveResult">
              <el-radio-group v-model="approveForm.approveResult">
                <el-radio label="3">同意</el-radio>
                <el-radio label="4">驳回</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="审批意见" prop="approveOpinion">
            <el-form-item label="确认意见" prop="approveOpinion">
              <el-input
                type="textarea"
                v-model="approveForm.approveOpinion"
                placeholder="请输入详细的审批意见,包括通过或驳回的理由"
                placeholder="请输入详细的确认意见,包括通过或驳回的理由"
                :rows="6"
                maxlength="500"
                show-word-limit
@@ -305,10 +300,10 @@
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="捐献者姓名" prop="name">
              <el-form-item label="患者姓名" prop="name">
                <el-input
                  v-model="editForm.name"
                  placeholder="请输入捐献者姓名"
                  placeholder="请输入患者姓名"
                />
              </el-form-item>
            </el-col>
@@ -361,10 +356,10 @@
                  placeholder="请选择血型"
                  style="width: 100%"
                >
                  <el-option label="A型" value="A" />
                  <el-option label="B型" value="B" />
                  <el-option label="O型" value="O" />
                  <el-option label="AB型" value="AB" />
                  <el-option label="A型" :value="1" />
                  <el-option label="B型" :value="2" />
                  <el-option label="O型" :value="3" />
                  <el-option label="AB型" :value="4" />
                </el-select>
              </el-form-item>
            </el-col>
@@ -984,7 +979,7 @@
      caseList: [],
      // è¯¦æƒ…弹框是否显示
      detailOpen: false,
      // å®¡æ‰¹å¼¹æ¡†æ˜¯å¦æ˜¾ç¤º
      // ç¡®è®¤å¼¹æ¡†æ˜¯å¦æ˜¾ç¤º
      approveOpen: false,
      // ç¼–辑弹框是否显示
      editOpen: false,
@@ -1002,19 +997,19 @@
        name: undefined,
        reportStatus: undefined
      },
      // å®¡æ‰¹è¡¨å•
      // ç¡®è®¤è¡¨å•
      approveForm: {
        id: null,
        approveResult: "3",
        approveOpinion: ""
      },
      // å®¡æ‰¹è¡¨å•验证
      // ç¡®è®¤è¡¨å•验证
      approveRules: {
        approveResult: [
          { required: true, message: "请选择审批结果", trigger: "change" }
          { required: true, message: "请选择确认结果", trigger: "change" }
        ],
        approveOpinion: [
          { required: true, message: "请输入审批意见", trigger: "blur" }
          { required: true, message: "请输入确认意见", trigger: "blur" }
        ]
      },
      // ç¼–辑表单
@@ -1025,7 +1020,7 @@
          { required: true, message: "请输入案例编号", trigger: "blur" }
        ],
        name: [
          { required: true, message: "请输入捐献者姓名", trigger: "blur" }
          { required: true, message: "请输入患者姓名", trigger: "blur" }
        ],
        sex: [{ required: true, message: "请选择性别", trigger: "change" }],
        age: [{ required: true, message: "请输入年龄", trigger: "blur" }],
@@ -1052,7 +1047,7 @@
    statusFilter(reportStatus) {
      const statusMap = {
        "1": "info", // å·²ä¸ŠæŠ¥
        "2": "warning", // å·²é˜…读(待审批)
        "2": "warning", // å·²é˜…读(待确认)
        "3": "success", // å·²åŒæ„
        "4": "danger" // å·²é©³å›ž
      };
@@ -1112,12 +1107,29 @@
        ) {
          return "查看转运单";
        } else {
          return "前往转运单";
          return "创建转运单";
        }
      }
      return "转运";
      return "无需转运";
    },
    getTransportStatustype(row) {
      if (row.isTransport == "1") {
        return "info"; // ä¸éœ€è¦è½¬è¿
      }
      if (
        row.serviceTransport &&
        Array.isArray(row.serviceTransport) &&
        row.serviceTransport.length > 0
      ) {
        // æ ¹æ®è½¬è¿å•状态显示不同颜色
        const transport = row.serviceTransport[0];
        if (transport.transitStatus) {
         return "primary"; // æœ‰è½¬è¿ä¿¡æ¯ä½†æ— çŠ¶æ€
        }
        return "primary"; // æœ‰è½¬è¿ä¿¡æ¯ä½†æ— çŠ¶æ€
      }
      return "success"; // éœ€è¦è½¬è¿ä½†æ— è½¬è¿ä¿¡æ¯
    },
    /** èŽ·å–è½¬è¿çŠ¶æ€æ ‡ç­¾æ ·å¼ */
    getTransportStatusTag(row) {
      if (row.isTransport === "1") {
@@ -1148,7 +1160,7 @@
        }
        return "primary"; // æœ‰è½¬è¿ä¿¡æ¯ä½†æ— çŠ¶æ€
      }
      return "danger"; // éœ€è¦è½¬è¿ä½†æ— è½¬è¿ä¿¡æ¯
      return "success"; // éœ€è¦è½¬è¿ä½†æ— è½¬è¿ä¿¡æ¯
    },
    /** èŽ·å–è½¬è¿çŠ¶æ€æ–‡æœ¬ */
@@ -1197,7 +1209,7 @@
          ) {
            // å·²æœ‰è½¬è¿å•,跳转到转运单详情页
            const transport = caseData.serviceTransport[0];
            this.goToTransportDetail(transport.id, row.caseNo);
            this.goToTransportDetail(transport.id, row.name);
          } else {
            // æ²¡æœ‰è½¬è¿å•,跳转到创建转运单页面
            this.goToCreateTransport(row);
@@ -1213,12 +1225,11 @@
    /** è·³è½¬åˆ°åˆ›å»ºè½¬è¿å•页面 */
    goToCreateTransport(caseData) {
      // è¿™é‡Œå¯ä»¥è·³è½¬åˆ°åˆ›å»ºè½¬è¿å•的页面
      // æ–¹å¼1:在新页面打开
      this.$router.push({
        path: "/report/transfer",
        query: {
          autoCreate: "true",
          autoCreate: "true", //跳转转运标识
          caseId: caseData.id,
          caseNo: caseData.caseNo,
          patName: caseData.name,
@@ -1228,9 +1239,6 @@
          treatmentHospitalName: caseData.treatmenthospitalname
        }
      });
      // æ–¹å¼2:在当前页面打开弹框(推荐)
      // this.openTransportDialog(caseData);
    },
    /** æ‰“开转运单弹框 */
@@ -1265,12 +1273,12 @@
    },
    /** è·³è½¬åˆ°è½¬è¿å•详情页 */
    goToTransportDetail(transportId, caseNo) {
    goToTransportDetail(transportId, name) {
      this.$router.push({
        path: "/report/transfer",
        query: {
          id: transportId,
          caseNo: caseNo
          autoCreate: "true",
          patName: name
        }
      });
    },
@@ -1380,7 +1388,7 @@
      });
    },
    /** å®¡æ‰¹æŒ‰é’®æ“ä½œ */
    /** ç¡®è®¤æŒ‰é’®æ“ä½œ */
    async handleApprove(row) {
      try {
        const response = await donateInfo(row.id);
@@ -1404,11 +1412,11 @@
        this.approveForm.approveResult = "3";
        this.approveForm.approveOpinion = "";
        this.approveOpen = true;
        this.$modal.msgError("获取详情失败,但已打开审批窗口");
        this.$modal.msgError("获取详情失败,但已打开确认窗口");
      }
    },
    /** æäº¤å®¡æ‰¹ */
    /** æäº¤ç¡®è®¤ */
    async submitApprove() {
      try {
        const valid = await this.$refs.approveForm.validate();
@@ -1424,14 +1432,14 @@
          };
          await donateEdit(approveData);
          this.$modal.msgSuccess("审批成功");
          this.$modal.msgSuccess("确认成功");
          this.approveOpen = false;
          this.getList();
        }
      } catch (error) {
        console.error("审批失败:", error);
        console.error("确认失败:", error);
        if (error !== "cancel") {
          this.$modal.msgError("审批失败");
          this.$modal.msgError("确认失败");
        }
      }
    },
@@ -1774,7 +1782,7 @@
  white-space: nowrap;
}
/* å®¡æ‰¹å¼¹æ¡†æ ·å¼ */
/* ç¡®è®¤å¼¹æ¡†æ ·å¼ */
.approve-dialog >>> .el-dialog__body {
  padding: 0;
}
src/views/business/assess/assessInfo.vue
@@ -1,6 +1,11 @@
<template>
  <div class="assessment-detail">
    <el-card class="basic-info-card">
    <!-- åŸºç¡€æ¡ˆä¾‹ä¿¡æ¯ -->
    <case-basic-info
      :case-id="caseId"
      :show-attachment="true"
    />
    <!-- <el-card class="basic-info-card">
      <div slot="header" class="clearfix">
        <span>案例基本信息</span>
        <el-button
@@ -52,7 +57,7 @@
          </el-tag>
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
    </el-card> -->
    <el-card class="organ-assessment-card">
      <div slot="header" class="clearfix">
@@ -162,10 +167,14 @@
    <!-- åŸºæœ¬ä¿¡æ¯æ±‡æ€» -->
    <el-descriptions title="基本信息汇总" :column="2" border>
      <el-descriptions-item label="器官类型">
        <span class="summary-item">{{ getOrganLabel(scope.row.organno) }}</span>
                        <span class="summary-item">{{
                          getOrganLabel(scope.row.organno)
                        }}</span>
      </el-descriptions-item>
      <el-descriptions-item label="获取机构">
        <span class="summary-item">{{ scope.row.gainhospitalname }}</span>
                        <span class="summary-item">{{
                          scope.row.gainhospitalname
                        }}</span>
      </el-descriptions-item>
      <el-descriptions-item label="评估次数" :span="2">
        <el-tag type="info" size="medium">
@@ -173,24 +182,39 @@
        </el-tag>
      </el-descriptions-item>
      <el-descriptions-item label="最新评估时间" :span="2">
        <span class="highlight-text">{{ getLatestAssessmentTime(scope.row) || "-" }}</span>
                        <span class="highlight-text">{{
                          getLatestAssessmentTime(scope.row) || "-"
                        }}</span>
      </el-descriptions-item>
    </el-descriptions>
    <!-- è¯„估详情汇总 -->
    <el-card header="评估详情列表" style="margin-top: 20px;" class="assessment-detail-card">
      <div v-if="getOrganAssessments(scope.row).length === 0" class="no-assessment">
                    <el-card
                      header="评估详情列表"
                      style="margin-top: 20px;"
                      class="assessment-detail-card"
                    >
                      <div
                        v-if="getOrganAssessments(scope.row).length === 0"
                        class="no-assessment"
                      >
        <el-empty description="暂无评估记录"></el-empty>
      </div>
      <div v-else>
        <!-- æ¯æ¬¡è¯„估详情 -->
        <div v-for="(assessment, index) in getOrganAssessments(scope.row)"
                        <div
                          v-for="(assessment, index) in getOrganAssessments(
                            scope.row
                          )"
             :key="index"
             class="assessment-item">
                          class="assessment-item"
                        >
          <el-card shadow="hover" class="assessment-card">
            <div slot="header" class="clearfix">
              <span class="assessment-title">第{{ index + 1 }}次评估</span>
                              <span class="assessment-title"
                                >第{{ index + 1 }}次评估</span
                              >
              <el-tag
                :type="getAssessmentTagType(assessment.status)"
                size="small"
@@ -200,9 +224,15 @@
              </el-tag>
            </div>
            <el-descriptions :column="2" border class="detail-descriptions">
                            <el-descriptions
                              :column="2"
                              border
                              class="detail-descriptions"
                            >
              <el-descriptions-item label="评估时间" :span="2">
                <span class="time-text">{{ assessment.assessmentTime || "-" }}</span>
                                <span class="time-text">{{
                                  assessment.assessmentTime || "-"
                                }}</span>
              </el-descriptions-item>
              <el-descriptions-item label="评估人">
@@ -213,27 +243,50 @@
              <el-descriptions-item label="功能状态">
                <el-tag
                  :type="getFunctionStatusTagType(assessment.functionStatus)"
                                  :type="
                                    getFunctionStatusTagType(
                                      assessment.functionStatus
                                    )
                                  "
                  size="small"
                >
                  {{ getFunctionStatusText(assessment.functionStatus) }}
                                  {{
                                    getFunctionStatusText(
                                      assessment.functionStatus
                                    )
                                  }}
                </el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="评估意见" :span="2">
                <div class="opinion-content">
                  {{ assessment.assessmentOpinion || "暂无评估意见" }}
                                  {{
                                    assessment.assessmentOpinion ||
                                      "暂无评估意见"
                                  }}
                </div>
              </el-descriptions-item>
              <el-descriptions-item label="附件数量" :span="2" v-if="assessment.attachments && assessment.attachments.length > 0">
                              <el-descriptions-item
                                label="附件数量"
                                :span="2"
                                v-if="
                                  assessment.attachments &&
                                    assessment.attachments.length > 0
                                "
                              >
                <el-tag type="success" size="small">
                  {{ assessment.attachments.length }}个
                </el-tag>
                <el-button
                  type="text"
                  size="mini"
                  @click="showAttachmentList(assessment.attachments, index + 1)"
                                  @click="
                                    showAttachmentList(
                                      assessment.attachments,
                                      index + 1
                                    )
                                  "
                  style="margin-left: 10px;"
                >
                  æŸ¥çœ‹é™„件列表
@@ -246,7 +299,11 @@
    </el-card>
    <!-- å™¨å®˜åŸºæœ¬ä¿¡æ¯å¡ç‰‡ -->
    <el-card header="器官信息" style="margin-top: 20px;" class="organ-info-card">
                    <el-card
                      header="器官信息"
                      style="margin-top: 20px;"
                      class="organ-info-card"
                    >
      <el-descriptions :column="2" border>
        <el-descriptions-item label="获取前活检">
          <el-tag
@@ -427,15 +484,17 @@
  assessedit,
  assessAdd
} from "@/api/businessApi/index";
import CaseBasicInfo from "@/components/CaseBasicInfo";
import FilePreviewDialog from "@/components/FilePreviewDialog";
import OrganAssessmentForm from "@/components/assessInfoComponents/OrganAssessmentForm.vue";
export default {
  name: "AssessmentDetail",
  components: { OrganAssessmentForm, FilePreviewDialog },
  components: { OrganAssessmentForm, FilePreviewDialog, CaseBasicInfo },
  dicts: ["sys_user_sex", "sys_Organ", "sys_0_1"],
  data() {
    return {
      caseId: null,
      // æ˜¯å¦ç¼–辑模式
      isEdit: false,
      // åŠ è½½çŠ¶æ€
@@ -550,6 +609,7 @@
  },
  created() {
    this.infoid = this.$route.query.infoid;
    this.caseId = this.infoid;
    this.assessmentId = this.$route.query.id;
    this.isEdit = this.$route.query.assess === "true";
    this.getAssessmentDetail();
@@ -600,7 +660,9 @@
      `<div>
        <h4>第${assessmentNumber}次评估附件列表</h4>
        <ul style="list-style: none; padding-left: 0;">
          ${attachments.map((item, index) => `
          ${attachments
            .map(
              (item, index) => `
            <li style="margin: 5px 0; padding: 5px; background: #f5f7fa; border-radius: 4px;">
              <i class="el-icon-document"></i>
              <span style="margin-left: 8px;">${item.fileName}</span>
@@ -613,15 +675,17 @@
                ä¸‹è½½
              </el-button>
            </li>
          `).join('')}
          `
            )
            .join("")}
        </ul>
      </div>`,
      '附件列表',
        "附件列表",
      {
        dangerouslyUseHTMLString: true,
        showConfirmButton: false,
        showCancelButton: true,
        cancelButtonText: '关闭'
          cancelButtonText: "关闭"
      }
    );
  },
@@ -718,8 +782,8 @@
        if (response.code === 200) {
          this.$message.success("评估表保存成功!");
          if (!this.assessmentData.id && response.data && response.data.id) {
            this.assessmentData.id = response.data.id;
          if (!this.assessmentData.id && response.data) {
            this.assessmentData.id = response.data;
          }
          this.refreshKey += 1; // è§¦å‘重新渲染
        } else {
@@ -957,7 +1021,6 @@
      } else {
        detailData = response;
      }
      this.assessmentData = {
        id: detailData.id || this.assessmentId,
        infoid: detailData.infoid || this.infoid,
@@ -1467,7 +1530,7 @@
}
.highlight-text {
  color: #409EFF;
  color: #409eff;
  font-weight: 500;
}
@@ -1502,7 +1565,7 @@
.assessment-card:hover {
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  border-color: #409EFF;
  border-color: #409eff;
}
.assessment-title {
@@ -1517,7 +1580,7 @@
}
.time-text {
  color: #67C23A;
  color: #67c23a;
  font-weight: 500;
}
@@ -1635,7 +1698,7 @@
}
::v-deep .el-tabs__item.is-active {
  color: #409EFF;
  color: #409eff;
  font-weight: 600;
}
src/views/business/assess/index.vue
@@ -131,7 +131,7 @@
          width="120"
        />
        <el-table-column
          label="潜在捐献者姓名"
          label="捐献者姓名"
          align="center"
          prop="name"
          width="120"
src/views/business/decide/DecideInfo.vue
@@ -1,5 +1,6 @@
<template>
  <div class="death-judgment-detail">
    <case-basic-info :case-id="caseId" :show-attachment="true" />
    <el-card class="detail-card">
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <div slot="header" class="clearfix">
@@ -26,47 +27,9 @@
      <el-form :model="form" ref="form" :rules="rules" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="捐献者编号" prop="donorno">
              <el-input
                v-model="form.donorno"
                :readonly="!isEdit"
                placeholder="自动生成捐献者编号"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="name">
              <el-input v-model="form.name" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="sex">
              <el-select
                v-model="form.sex"
                :disabled="!isEdit"
                style="width: 100%"
              >
                <el-option label="男" value="1" />
                <el-option label="女" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="疾病诊断" prop="diagnosisname">
              <el-input v-model="form.diagnosisname" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="死亡原因" prop="deathreason">
              <el-select
              <el-input v-model="form.deathreason" :readonly="!isEdit" />
              <!-- <el-select
                v-model="form.deathreason"
                :disabled="!isEdit"
                style="width: 100%"
@@ -74,9 +37,24 @@
                <el-option label="脑死亡" value="brain_death" />
                <el-option label="心死亡" value="heart_death" />
                <el-option label="其他" value="other" />
              </el-select>
              </el-select> -->
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="负责人" prop="responsibleusername">
              <el-input
                v-model="form.responsibleusername"
                :readonly="!isEdit"
              />
            </el-form-item>
          </el-col>
          <!-- <el-col :span="8">
            <el-form-item label="记录状态" prop="recordstate">
              <el-tag :type="getStatusTag(form.recordstate)">
                {{ getStatusText(form.recordstate) }}
              </el-tag>
            </el-form-item>
          </el-col> -->
        </el-row>
        <el-row :gutter="20">
@@ -122,7 +100,7 @@
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="是否恢复遗体仪容" prop="isrestoreremains">
            <el-form-item label="恢复遗体仪容" prop="isrestoreremains">
              <el-select
                v-model="form.isrestoreremains"
                :disabled="!isEdit"
@@ -135,29 +113,11 @@
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="负责人" prop="responsibleusername">
              <el-input
                v-model="form.responsibleusername"
                :readonly="!isEdit"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="记录状态" prop="recordstate">
              <el-tag :type="getStatusTag(form.recordstate)">
                {{ getStatusText(form.recordstate) }}
              </el-tag>
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="死亡判定说明" prop="judgmentDescription">
        <el-form-item label="死亡判定说明" prop="remark">
          <el-input
            type="textarea"
            :rows="3"
            v-model="form.judgmentDescription"
            v-model="form.remark"
            :readonly="!isEdit"
            placeholder="详细记录死亡判定过程和依据"
          />
@@ -337,17 +297,27 @@
</template>
<script>
import { deathinfoedit, deathinfoInfo } from "@/api/businessApi";
import {
  deathinfoedit,
  deathinfoadd,
  queryDathInfoBaseInfo
} from "@/api/businessApi";
import { getToken } from "@/utils/auth";
import CaseBasicInfo from "@/components/CaseBasicInfo";
export default {
  name: "DeathJudgmentDetail",
  components: { CaseBasicInfo },
  data() {
    return {
      caseId: null,
      // æ˜¯å¦ç¼–辑模式
      isEdit: false,
      // ä¿å­˜åŠ è½½çŠ¶æ€
      saveLoading: false,
      infoid: undefined,
      // è¡¨å•数据
      form: {
        id: undefined,
@@ -365,7 +335,7 @@
        gainhospitalname: "",
        isspendremember: 0,
        isrestoreremains: 0,
        rememberannex: "",
        rememberAnnex: "",
        responsibleuserid: "",
        responsibleusername: "",
        recordstate: "0",
@@ -421,13 +391,17 @@
    }
  },
  created() {
    this.infoid = this.$route.query.infoid;
    this.caseId = this.infoid;
    const id = this.$route.query.id;
    this.isEdit = this.$route.query.isEdit;
    if (id && !this.$route.path.includes("/add")) {
      this.getDetail(id);
    } else if (this.$route.path.includes("/add")) {
      this.generateDonorNo();
    }
    this.getDetail(this.infoid);
    // if (id && !this.$route.path.includes("/add")) {
    //   this.getDetail(id);
    // } else if (this.$route.path.includes("/add")) {
    //   this.generateDonorNo();
    // }
    this.getAttachmentList();
  },
  methods: {
@@ -437,13 +411,13 @@
      this.form.donorno = "DONOR" + timestamp.slice(-8);
    },
    // èŽ·å–è¯¦æƒ…
    async getDetail(id) {
    async getDetail(infoid) {
      try {
        const response = await deathinfoInfo(id);
        const response = await queryDathInfoBaseInfo({ infoid });
        let realData = {};
        if (response && response.data) {
          realData = response.data;
          realData = response.data[0];
        } else if (response) {
          realData = response;
        }
@@ -462,8 +436,8 @@
        };
        // è§£æžé™„件信息
        if (realData.rememberannex) {
          this.parseAttachmentData(realData.rememberannex);
        if (realData.rememberAnnex) {
          this.parseAttachmentData(realData.rememberAnnex);
        }
      } catch (error) {
        console.error("获取死亡判定详情失败:", error);
@@ -614,7 +588,7 @@
        }
        // æ›´æ–°é™„ä»¶JSON数据到表单
        this.form.rememberannex = this.buildAttachmentJson();
        this.form.rememberAnnex = this.buildAttachmentJson();
        this.$message.success("文件上传成功");
        this.uploadDialogVisible = false;
@@ -650,7 +624,7 @@
      //   }
      //   // æ›´æ–°é™„ä»¶JSON数据到表单
      //   this.form.rememberannex = this.buildAttachmentJson();
      //   this.form.rememberAnnex = this.buildAttachmentJson();
      //   this.$message.success("文件上传成功");
      //   this.uploadDialogVisible = false;
@@ -676,7 +650,7 @@
          if (index !== -1) {
            this.attachmentList.splice(index, 1);
            // æ›´æ–°é™„ä»¶JSON数据到表单
            this.form.rememberannex = this.buildAttachmentJson();
            this.form.rememberAnnex = this.buildAttachmentJson();
            this.$message.success("评估表删除成功");
          }
        })
@@ -721,16 +695,25 @@
            // æž„建提交数据
            const submitData = {
              ...this.form,
              infoid: this.infoid,
              // ç¡®ä¿é™„件数据最新
              rememberannex: this.buildAttachmentJson()
            };
            let response = null;
            const response = await deathinfoedit(submitData);
            if (submitData.id) {
              response = await deathinfoedit(submitData);
            } else {
              response = await deathinfoadd(submitData);
            }
            // const response = await deathinfoedit(submitData);
            if (response.code === 200) {
              this.$message.success("保存成功");
              this.isEdit = false;
              if (!this.form.id) {
                this.form.id = response.data;
              }
              if (this.$route.path.includes("/add")) {
                this.$router.push("/case/deathJudgment");
              }
src/views/business/decide/index.vue
@@ -62,7 +62,7 @@
    <el-card class="tool-card">
      <el-row :gutter="10">
        <el-col :span="16">
          <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
          <!-- <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
            >新建死亡判定</el-button
          >
          <el-button
@@ -71,7 +71,7 @@
            :disabled="single"
            @click="handleUpdate"
            >修改</el-button
          >
          > -->
          <el-button
            type="warning"
            icon="el-icon-download"
@@ -439,7 +439,7 @@
    handleView(row) {
      this.$router.push({
        path: "/case/DecideInfo",
        query: { id: row.id }
        query: { id: row.id,infoid:row.infoid }
      });
    },
@@ -453,7 +453,7 @@
      const id = row.id || this.ids[0];
      this.$router.push({
        path: "/case/DecideInfo",
        query: { id: id, isEdit: true }
        query: { id: id,infoid:row.infoid, isEdit: true }
      });
    },
src/views/business/ethicalReview/ethicalReviewInfo copy.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1536 @@
<template>
  <div class="ethics-review-detail">
    <el-card class="detail-card">
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <div slot="header" class="clearfix">
        <span class="detail-title">伦理审查基本信息</span>
        <div style="float: right;">
          <el-button type="primary" @click="handleSave" :loading="saveLoading">
            ä¿å­˜
          </el-button>
          <el-button
            type="warning"
            @click="handleEndReview"
            :disabled="form.ethicsConclusion === 'terminated'"
          >
            ç»“束审查
          </el-button>
        </div>
      </div>
      <el-form :model="form" ref="form" :rules="rules" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="住院号" prop="hospitalNo">
              <el-input v-model="form.hospitalNo" readonly />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="donorName">
              <el-input v-model="form.donorName" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="gender">
              <el-select v-model="form.gender" style="width: 100%">
                <el-option label="男" value="0" />
                <el-option label="女" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" />
            </el-form-item>
          </el-col>
          <el-col :span="16">
            <el-form-item label="疾病诊断" prop="diagnosis">
              <el-input v-model="form.diagnosis" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="伦理结论" prop="ethicsConclusion">
              <el-select v-model="form.ethicsConclusion" style="width: 100%">
                <el-option label="审查中" value="reviewing" />
                <el-option label="同意" value="approved" />
                <el-option
                  label="修改后同意"
                  value="approved_with_modifications"
                />
                <el-option label="修改后重审" value="re-review" />
                <el-option label="不同意" value="disapproved" />
                <el-option label="终止审查" value="terminated" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="审查时间" prop="reviewTime">
              <el-date-picker
                v-model="form.reviewTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="登记人" prop="registrant">
              <el-input v-model="form.registrant" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="伦理意见" prop="ethicsOpinion">
              <el-input
                type="textarea"
                :rows="3"
                v-model="form.ethicsOpinion"
                placeholder="请输入伦理审查意见"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="登记时间" prop="registrationTime">
          <el-date-picker
            v-model="form.registrationTime"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            style="width: 100%"
          />
        </el-form-item>
      </el-form>
    </el-card>
    <!-- é™„件上传 -->
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">相关附件</span>
        <el-button type="primary" size="mini" @click="handleUploadAttachment">
          ä¸Šä¼ é™„ä»¶
        </el-button>
      </div>
      <el-table :data="attachments" style="width: 100%">
        <el-table-column label="文件名称" min-width="200">
          <template slot-scope="scope">
            <div class="file-info">
              <i
                class="el-icon-document"
                style="margin-right: 8px; color: #409EFF;"
              ></i>
              <span>{{ scope.row.fileName }}</span>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="文件类型" width="100" align="center">
          <template slot-scope="scope">
            <el-tag size="small">{{ getFileType(scope.row.fileName) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="文件大小" width="100" align="center">
          <template slot-scope="scope">
            <span>{{ formatFileSize(scope.row.fileSize) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="上传时间" width="160" align="center">
          <template slot-scope="scope">
            <span>{{ parseTime(scope.row.uploadTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="上传人" width="100" align="center">
          <template slot-scope="scope">
            <span>{{ scope.row.uploader }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="120" align="center">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click="handlePreviewAttachment(scope.row)"
              >预览</el-button
            >
            <el-button
              size="mini"
              type="text"
              icon="el-icon-download"
              @click="handleDownloadAttachment(scope.row)"
              >下载</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- ä¸“家审查情况 -->
    <el-card class="expert-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">专家审查情况 (18位专家 + 1位主委专家)</span>
        <div style="float: right;">
          <el-button
            size="mini"
            type="primary"
            @click="handleSendToNormalExperts"
            :disabled="!canSendToNormalExperts"
          >
            å‘送专家
          </el-button>
          <el-button
            size="mini"
            type="success"
            @click="handleSendToChiefExpert"
            :disabled="!canSendToChiefExpert"
          >
            å‘送主委专家
          </el-button>
          <el-button
            size="mini"
            type="warning"
            @click="handleBatchSend"
            :disabled="!canBatchSend"
          >
            æ‰¹é‡å‘送
          </el-button>
        </div>
      </div>
      <!-- ä¸“家统计信息 -->
      <div
        class="expert-stats"
        style="margin-top: 20px; padding: 15px; background: #f5f7fa; border-radius: 4px;"
      >
        <el-row :gutter="20">
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">专家已同意:</span>
              <span class="stat-value">{{ approvedNormalExperts }}/18</span>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">主委专家状态:</span>
              <span class="stat-value">{{ chiefExpertStatus }}</span>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">总完成进度:</span>
              <span class="stat-value">{{ completionRate }}%</span>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">审查结果:</span>
              <span class="stat-value">
                <el-tag :type="overallConclusionFilter">
                  {{ overallConclusionText }}
                </el-tag>
              </span>
            </div>
          </el-col>
        </el-row>
      </div>
      <!-- ä¸“家审查表格 -->
      <el-table
        :data="expertReviews"
        v-loading="expertLoading"
        style="width: 100%"
        heiht="800"
        :row-class-name="getExpertRowClassName"
      >
        <el-table-column label="序号" width="60" align="center" type="index" />
        <el-table-column
          label="专家姓名"
          width="120"
          align="center"
          fixed="left"
        >
          <template slot-scope="scope">
            <span>{{ scope.row.expertName }}</span>
            <el-tag
              v-if="scope.row.isChief"
              size="mini"
              type="danger"
              style="margin-left: 5px;"
              >主委</el-tag
            >
          </template>
        </el-table-column>
        <el-table-column label="专家类型" width="100" align="center">
          <template slot-scope="scope">
            <span :class="scope.row.isChief ? 'chief-expert' : 'normal-expert'">
              {{ scope.row.isChief ? "主委专家" : "专家" }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="审查状态" width="100" align="center">
          <template slot-scope="scope">
            <el-tag :type="statusFilter(scope.row.reviewStatus)" size="small">
              {{ statusTextFilter(scope.row.reviewStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="专家结论" width="120" align="center">
          <template slot-scope="scope">
            <el-tag
              v-if="scope.row.expertConclusion"
              :type="conclusionFilter(scope.row.expertConclusion)"
              size="small"
            >
              {{ conclusionTextFilter(scope.row.expertConclusion) }}
            </el-tag>
            <span v-else class="no-data">-</span>
          </template>
        </el-table-column>
        <el-table-column label="审查意见" min-width="200" show-overflow-tooltip>
          <template slot-scope="scope">
            <span :class="{ 'expert-opinion': scope.row.expertOpinion }">
              {{ scope.row.expertOpinion || "暂无意见" }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="审查时间" width="160" align="center">
          <template slot-scope="scope">
            <span>{{
              scope.row.reviewTime ? parseTime(scope.row.reviewTime) : "未审查"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column label="发送时间" width="160" align="center">
          <template slot-scope="scope">
            <span>{{
              scope.row.reviewTime ? parseTime(scope.row.reviewTime) : "未发送"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="280" align="center" fixed="right">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-s-promotion"
              @click="handleSendToExpert(scope.row)"
              :disabled="scope.row.reviewStatus === 'submitted'"
              :class="{ 'sent-button': scope.row.reviewStatus === 'submitted' }"
            >
              {{ scope.row.reviewStatus === "submitted" ? "已发送" : "发送" }}
            </el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click="handleEditExpertReview(scope.row)"
              :disabled="scope.row.reviewStatus !== 'submitted'"
            >
              ç¼–辑
            </el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click="handleViewExpertReview(scope.row)"
            >
              è¯¦æƒ…
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- å‘送专家对话框 -->
    <el-dialog
      title="发送专家审查"
      :visible.sync="sendDialogVisible"
      width="500px"
    >
      <el-form :model="sendForm" ref="sendForm" label-width="100px">
        <el-form-item label="专家类型" prop="expertType">
          <el-radio-group v-model="sendForm.expertType">
            <el-radio label="normal">专家</el-radio>
            <el-radio label="chief">主委专家</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item
          label="选择专家"
          prop="expertIds"
          v-if="sendForm.expertType === 'normal'"
        >
          <el-select
            v-model="sendForm.expertIds"
            multiple
            placeholder="请选择专家"
            style="width: 100%"
          >
            <el-option
              v-for="expert in availableExperts"
              :key="expert.id"
              :label="expert.name"
              :value="expert.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="发送内容" prop="content">
          <el-input
            type="textarea"
            :rows="4"
            v-model="sendForm.content"
            placeholder="请输入发送给专家的审查内容说明"
          />
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="sendDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSendConfirm"
          >确认发送</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>
<script>
import {
  getEthicsReviewDetail,
  updateEthicsReview,
  sendExpertReview,
  endEthicsReview,
  uploadAttachment,
  deleteAttachment,
  getAttachments
} from "./ethicsReview";
import {
  reviewinitiateBaseInfoList,
  ethicalreviewedit,
  ethicalreviewadd
} from "@/api/businessApi";
export default {
  name: "EthicsReviewDetail",
  data() {
    return {
      // è¡¨å•数据
      form: {
        id: undefined,
        hospitalNo: "",
        donorName: "",
        gender: "",
        age: "",
        diagnosis: "",
        ethicsConclusion: "reviewing",
        ethicsOpinion: "",
        reviewTime: "",
        registrant: "",
        registrationTime: new Date()
          .toISOString()
          .replace("T", " ")
          .substring(0, 19)
      },
      // è¡¨å•验证规则
      rules: {
        donorName: [
          { required: true, message: "捐献者姓名不能为空", trigger: "blur" }
        ],
        ethicsConclusion: [
          { required: true, message: "伦理结论不能为空", trigger: "change" }
        ],
        reviewTime: [
          { required: true, message: "审查时间不能为空", trigger: "change" }
        ]
      },
      // ä¿å­˜åŠ è½½çŠ¶æ€
      saveLoading: false,
      // é™„件数据
      attachments: [],
      expertReviews: [
        // ä¸“家(18位)- åˆå§‹çŠ¶æ€ä¸ºç”³è¯·ä¸­
        {
          id: 1,
          expertName: "陶昊",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 2,
          expertName: "刘斌",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 3,
          expertName: "于海初 ",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 4,
          expertName: "王红梅",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 5,
          expertName: "王春光",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 6,
          expertName: "王静",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 7,
          expertName: "边文超",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 8,
          expertName: "闫志勇",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 9,
          expertName: "许凤",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 10,
          expertName: "许传屾",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 11,
          expertName: "张红岩",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 12,
          expertName: "杨苏民",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 13,
          expertName: "宋玉强",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 14,
          expertName: "周传利",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 15,
          expertName: "荆凡波",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 16,
          expertName: "矫文捷",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 17,
          expertName: "董震",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        {
          id: 18,
          expertName: "蔡金贞",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        },
        // ä¸»å§”专家(1位)
        {
          id: 19,
          expertName: "孔心涓",
          isChief: true,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
        }
      ],
      expertLoading: false,
      attachmentLoading: false,
      // å‘送对话框
      sendDialogVisible: false,
      sendForm: {
        expertType: "normal",
        expertIds: [],
        content: ""
      },
      // ä¸Šä¼ ç›¸å…³
      uploadDialogVisible: false,
      uploadLoading: false,
      tempFileList: [],
      // å¯ç”¨ä¸“家列表
      availableExperts: [
        { id: 1, name: "张教授", type: "normal" },
        { id: 2, name: "李教授", type: "normal" },
        { id: 3, name: "王教授", type: "normal" },
        { id: 4, name: "赵主委", type: "chief" }
      ]
    };
  },
  computed: {
    // è®¡ç®—属性:专家同意数量
    approvedNormalExperts() {
      return this.expertReviews.filter(
        expert => !expert.isChief && expert.expertConclusion === "approved"
      ).length;
    },
    // è®¡ç®—属性:主委专家状态
    chiefExpertStatus() {
      const chiefExpert = this.expertReviews.find(expert => expert.isChief);
      return chiefExpert
        ? this.statusTextFilter(chiefExpert.reviewStatus)
        : "未分配";
    },
    // è®¡ç®—属性:完成进度
    completionRate() {
      const totalExperts = this.expertReviews.length;
      const completedExperts = this.expertReviews.filter(
        expert => expert.reviewStatus === "submitted"
      ).length;
      return totalExperts > 0
        ? Math.round((completedExperts / totalExperts) * 100)
        : 0;
    },
    // è®¡ç®—属性:总体结论
    overallConclusionText() {
      if (this.approvedNormalExperts >= 12) {
        return "通过";
      } else if (this.approvedNormalExperts >= 9) {
        return "修改后通过";
      } else {
        return "不通过";
      }
    },
    overallConclusionFilter() {
      if (this.approvedNormalExperts >= 12) {
        return "success";
      } else if (this.approvedNormalExperts >= 9) {
        return "warning";
      } else {
        return "danger";
      }
    },
    // æ˜¯å¦å¯ä»¥å‘送给专家
    canSendToNormalExperts() {
      return (
        this.expertReviews.filter(
          expert => !expert.isChief && expert.reviewStatus === "applying"
        ).length > 0
      );
    },
    // æ˜¯å¦å¯ä»¥å‘送给主委专家(需要至少12个专家同意)
    canSendToChiefExpert() {
      return (
        this.approvedNormalExperts >= 12 &&
        this.expertReviews.filter(
          expert => expert.isChief && expert.reviewStatus === "applying"
        ).length > 0
      );
    },
    // æ˜¯å¦å¯ä»¥æ‰¹é‡å‘送
    canBatchSend() {
      return (
        this.expertReviews.filter(expert => expert.reviewStatus === "applying")
          .length > 0
      );
    },
    // æ˜¯å¦å¯ä»¥å‘送专家审查
    canSendToExperts() {
      return this.form.id && this.form.ethicsConclusion === "reviewing";
    },
    // å½“前用户信息
    currentUser() {
      return JSON.parse(sessionStorage.getItem("user") || "{}");
    }
  },
  created() {
    const id = this.$route.query.id;
    if (id) {
      this.getDetail(id);
      this.getAttachments(id);
      // ä¸å†éœ€è¦ä»ŽæŽ¥å£èŽ·å–ä¸“å®¶åˆ—è¡¨ï¼Œä½¿ç”¨å›ºå®šçš„expertReviews数据
    } else if (this.$route.path.includes("/add")) {
      this.generateHospitalNo();
      this.form.registrant = this.currentUser.username || "当前用户";
    }
  },
  methods: {
    // ç”Ÿæˆä½é™¢å·
    generateHospitalNo() {
      const timestamp = Date.now().toString();
      this.form.hospitalNo = "D" + timestamp.slice(-6);
    },
    getExpertRowClassName({ row }) {
      return row.isChief ? "chief-expert-row" : "normal-expert-row";
    },
    // èŽ·å–è¯¦æƒ…
    getDetail(id) {
      getEthicsReviewDetail(id)
        .then(response => {
          if (response.code === 200) {
            this.form = response.data;
          }
        })
        .catch(error => {
          console.error("获取伦理审查详情失败:", error);
          this.$message.error("获取详情失败");
        });
    },
    // èŽ·å–ä¸“å®¶å®¡æŸ¥åˆ—è¡¨
    getExpertReviews(ethicsReviewId) {
      this.expertLoading = true;
      // æ¨¡æ‹Ÿæ•°æ® - å®žé™…项目中从接口获取
      setTimeout(() => {
        this.expertReviews = [
          // ä¸“家(18位)
          {
            id: 1,
            expertName: "张教授",
            isChief: false,
            reviewStatus: "submitted",
            expertConclusion: "approved",
            expertOpinion: "符合伦理要求",
            reviewTime: "2025-12-01 10:30:00"
          },
          {
            id: 2,
            expertName: "李教授",
            isChief: false,
            reviewStatus: "submitted",
            expertConclusion: "approved",
            expertOpinion: "方案设计合理",
            reviewTime: "2025-12-01 11:20:00"
          },
          {
            id: 3,
            expertName: "王教授",
            isChief: false,
            reviewStatus: "applying",
            expertConclusion: "",
            expertOpinion: "",
            reviewTime: ""
          },
          // ä¸»å§”专家(1位)
          {
            id: 19,
            expertName: "赵主委",
            isChief: true,
            reviewStatus: "applying",
            expertConclusion: "",
            expertOpinion: "",
            reviewTime: ""
          }
        ];
        this.expertLoading = false;
      }, 500);
    },
    // èŽ·å–é™„ä»¶åˆ—è¡¨
    getAttachments(ethicsReviewId) {
      this.attachmentLoading = true;
      getAttachments(ethicsReviewId)
        .then(response => {
          if (response.code === 200) {
            this.attachments = response.data;
          }
          this.attachmentLoading = false;
        })
        .catch(error => {
          console.error("获取附件列表失败:", error);
          this.attachmentLoading = false;
        });
    },
    // çŠ¶æ€è¿‡æ»¤å™¨
    statusFilter(status) {
      const statusMap = {
        applying: "info",
        submitted: "success"
      };
      return statusMap[status] || "info";
    },
    statusTextFilter(status) {
      const statusMap = {
        applying: "申请中",
        submitted: "已提交"
      };
      return statusMap[status] || "未知";
    },
    // ç»“论过滤器
    conclusionFilter(conclusion) {
      const conclusionMap = {
        approved: "success",
        approved_with_modifications: "warning",
        disapproved: "danger"
      };
      return conclusionMap[conclusion] || "info";
    },
    conclusionTextFilter(conclusion) {
      const conclusionMap = {
        approved: "同意",
        approved_with_modifications: "修改后同意",
        disapproved: "不同意"
      };
      return conclusionMap[conclusion] || "未知";
    },
    // ä¿å­˜ä¿¡æ¯
    handleSave() {
      this.$refs.form.validate(valid => {
        if (valid) {
          this.saveLoading = true;
          const apiMethod = this.form.id ? updateEthicsReview : addEthicsReview;
          apiMethod(this.form)
            .then(response => {
              if (response.code === 200) {
                this.$message.success("保存成功");
                if (!this.form.id) {
                  this.form.id = response.data.id;
                  this.$router.replace({
                    query: { ...this.$route.query, id: this.form.id }
                  });
                }
              }
            })
            .catch(error => {
              console.error("保存失败:", error);
              this.$message.error("保存失败");
            })
            .finally(() => {
              this.saveLoading = false;
            });
        }
      });
    },
    // å‘送专家审查
    handleSendToExperts() {
      this.sendDialogVisible = true;
    },
    // å‘送给专家
    handleSendToNormalExperts() {
      const normalExperts = this.expertReviews.filter(
        expert => !expert.isChief && expert.reviewStatus === "applying"
      );
      this.sendForm.expertIds = normalExperts.map(expert => expert.id);
      this.sendForm.expertType = "normal";
      this.sendDialogVisible = true;
    },
    // å‘送给主委专家
    handleSendToChiefExpert() {
      const chiefExpert = this.expertReviews.find(
        expert => expert.isChief && expert.reviewStatus === "applying"
      );
      if (chiefExpert) {
        this.sendForm.expertIds = [chiefExpert.id];
        this.sendForm.expertType = "chief";
        this.sendDialogVisible = true;
      }
    },
    // æ‰¹é‡å‘送
    handleBatchSend() {
      const applyingExperts = this.expertReviews.filter(
        expert => expert.reviewStatus === "applying"
      );
      this.sendForm.expertIds = applyingExperts.map(expert => expert.id);
      this.sendForm.expertType = "batch";
      this.sendDialogVisible = true;
    },
    // å‘送给单个专家
    handleSendToExpert(expert) {
      this.sendForm.expertIds = [expert.id];
      this.sendForm.expertType = expert.isChief ? "chief" : "normal";
      this.sendDialogVisible = true;
    },
    // ç¡®è®¤å‘送
    handleSendConfirm() {
      if (this.sendForm.expertIds.length === 0) {
        this.$message.warning("请选择要发送的专家");
        return;
      }
      sendExpertReview({
        ethicsReviewId: this.form.id,
        expertIds: this.sendForm.expertIds,
        content: this.sendForm.content
      })
        .then(response => {
          if (response.code === 200) {
            this.$message.success("发送成功");
            this.sendDialogVisible = false;
            this.getExpertReviews(this.form.id);
            this.sendForm = {
              expertType: "normal",
              expertIds: [],
              content: ""
            };
          }
        })
        .catch(error => {
          console.error("发送失败:", error);
          this.$message.error("发送失败");
        });
    },
    // ç»“束审查
    handleEndReview() {
      this.$confirm(
        "确定要结束本次伦理审查吗?结束后将无法修改专家审查结果。",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(() => {
          endEthicsReview(this.form.id)
            .then(response => {
              if (response.code === 200) {
                this.$message.success("审查已结束");
                this.form.ethicsConclusion = "terminated";
              }
            })
            .catch(error => {
              console.error("结束审查失败:", error);
              this.$message.error("结束审查失败");
            });
        })
        .catch(() => {});
    },
    // ç¼–辑专家审查
    handleEditExpertReview(expert) {
      this.$prompt("请输入审查意见", "编辑专家审查", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        inputValue: expert.expertOpinion || "",
        inputValidator: value => {
          if (!value || value.trim() === "") {
            return "审查意见不能为空";
          }
          return true;
        }
      })
        .then(({ value }) => {
          // æ¨¡æ‹Ÿæ›´æ–°ä¸“家审查
          const index = this.expertReviews.findIndex(e => e.id === expert.id);
          if (index !== -1) {
            this.expertReviews[index].expertOpinion = value;
            this.$message.success("审查意见已更新");
          }
        })
        .catch(() => {});
    },
    // æŸ¥çœ‹ä¸“家审查详情
    handleViewExpertReview(expert) {
      this.$alert(
        `
        <div>
          <p><strong>专家姓名:</strong>${expert.expertName}</p>
          <p><strong>专家类型:</strong>${
            expert.isChief ? "主委专家" : "专家"
          }</p>
          <p><strong>审查状态:</strong>${this.statusTextFilter(
            expert.reviewStatus
          )}</p>
          <p><strong>专家结论:</strong>${
            expert.expertConclusion
              ? this.conclusionTextFilter(expert.expertConclusion)
              : "未提交"
          }</p>
          <p><strong>审查意见:</strong>${expert.expertOpinion || "无"}</p>
          <p><strong>审查时间:</strong>${expert.reviewTime || "未审查"}</p>
        </div>
      `,
        "专家审查详情",
        {
          dangerouslyUseHTMLString: true,
          customClass: "expert-review-detail-dialog"
        }
      );
    },
    // ä¸Šä¼ é™„ä»¶
    handleUploadAttachment() {
      this.uploadDialogVisible = true;
    },
    // ä¸Šä¼ å‰æ ¡éªŒ
    beforeUpload(file) {
      const allowedTypes = [
        "application/pdf",
        "image/jpeg",
        "image/png",
        "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "application/vnd.ms-excel",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
      ];
      const maxSize = 10 * 1024 * 1024;
      const isTypeOk =
        allowedTypes.includes(file.type) ||
        file.name.endsWith(".pdf") ||
        file.name.endsWith(".jpg") ||
        file.name.endsWith(".jpeg") ||
        file.name.endsWith(".png") ||
        file.name.endsWith(".doc") ||
        file.name.endsWith(".docx") ||
        file.name.endsWith(".xls") ||
        file.name.endsWith(".xlsx");
      if (!isTypeOk) {
        this.$message.error("文件格式不支持");
        return false;
      }
      if (file.size > maxSize) {
        this.$message.error("文件大小不能超过10MB");
        return false;
      }
      return true;
    },
    // æ–‡ä»¶é€‰æ‹©å˜åŒ–
    handleFileChange(file, fileList) {
      this.tempFileList = fileList;
    },
    // æäº¤ä¸Šä¼ 
    submitUpload() {
      if (this.tempFileList.length === 0) {
        this.$message.warning("请先选择要上传的文件");
        return;
      }
      this.uploadLoading = true;
      const uploadPromises = this.tempFileList.map(file => {
        const formData = new FormData();
        formData.append("file", file.raw);
        formData.append("ethicsReviewId", this.form.id);
        return uploadAttachment(formData);
      });
      Promise.all(uploadPromises)
        .then(responses => {
          this.$message.success("文件上传成功");
          this.uploadDialogVisible = false;
          this.tempFileList = [];
          this.getAttachments(this.form.id);
        })
        .catch(error => {
          console.error("上传失败:", error);
          this.$message.error("文件上传失败");
        })
        .finally(() => {
          this.uploadLoading = false;
        });
    },
    // é¢„览附件
    handlePreviewAttachment(attachment) {
      if (attachment.fileName.endsWith(".pdf")) {
        window.open(attachment.fileUrl, "_blank");
      } else if (attachment.fileName.match(/\.(jpg|jpeg|png)$/i)) {
        this.$alert(
          `<img src="${attachment.fileUrl}" style="max-width: 100%;" alt="${attachment.fileName}">`,
          "图片预览",
          {
            dangerouslyUseHTMLString: true,
            customClass: "image-preview-dialog"
          }
        );
      } else {
        this.$message.info("该文件类型暂不支持在线预览,请下载后查看");
      }
    },
    // ä¸‹è½½é™„ä»¶
    handleDownloadAttachment(attachment) {
      const link = document.createElement("a");
      link.href = attachment.fileUrl;
      link.download = attachment.fileName;
      link.click();
      this.$message.success(`开始下载: ${attachment.fileName}`);
    },
    // åˆ é™¤é™„ä»¶
    handleRemoveAttachment(attachment) {
      this.$confirm("确定要删除这个附件吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          deleteAttachment(attachment.id)
            .then(response => {
              if (response.code === 200) {
                this.$message.success("附件删除成功");
                this.getAttachments(this.form.id);
              }
            })
            .catch(error => {
              console.error("删除附件失败:", error);
              this.$message.error("删除附件失败");
            });
        })
        .catch(() => {});
    },
    // èŽ·å–æ–‡ä»¶ç±»åž‹
    getFileType(fileName) {
      const ext = fileName
        .split(".")
        .pop()
        .toLowerCase();
      const typeMap = {
        pdf: "PDF",
        doc: "DOC",
        docx: "DOCX",
        xls: "XLS",
        xlsx: "XLSX",
        jpg: "JPG",
        jpeg: "JPEG",
        png: "PNG"
      };
      return typeMap[ext] || ext.toUpperCase();
    },
    // æ–‡ä»¶å¤§å°æ ¼å¼åŒ–
    formatFileSize(size) {
      if (size === 0) return "0 B";
      const k = 1024;
      const sizes = ["B", "KB", "MB", "GB"];
      const i = Math.floor(Math.log(size) / Math.log(k));
      return parseFloat((size / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    },
    // æ—¶é—´æ ¼å¼åŒ–
    parseTime(time) {
      if (!time) return "";
      const date = new Date(time);
      return `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date
        .getDate()
        .toString()
        .padStart(2, "0")} ${date
        .getHours()
        .toString()
        .padStart(2, "0")}:${date
        .getMinutes()
        .toString()
        .padStart(2, "0")}`;
    }
  }
};
</script>
<style scoped>
.ethics-review-detail {
  padding: 20px;
  background-color: #f5f7fa;
}
.detail-card {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.expert-card {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.attachment-card {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.detail-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
}
.expert-stats {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: rgb(43, 181, 245);
  border-radius: 8px;
  margin-bottom: 20px;
}
.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}
.stat-label {
  font-size: 12px;
  opacity: 0.9;
  margin-bottom: 5px;
}
.stat-value {
  font-size: 18px;
  font-weight: bold;
}
.upload-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding: 10px;
  background-color: #f8f9fa;
  border-radius: 4px;
}
.upload-title {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}
.file-info {
  display: flex;
  align-items: center;
}
.empty-attachment {
  text-align: center;
  padding: 40px 0;
  color: #909399;
}
/* è¡¨å•样式优化 */
:deep(.el-form-item__label) {
  font-weight: 500;
}
:deep(.el-input__inner) {
  border-radius: 4px;
}
:deep(.el-textarea__inner) {
  border-radius: 4px;
  resize: vertical;
}
/* è¡¨æ ¼æ ·å¼ä¼˜åŒ– */
:deep(.el-table) {
  border-radius: 8px;
  overflow: hidden;
}
:deep(.el-table th) {
  background-color: #f5f7fa;
  color: #606266;
  font-weight: 500;
}
:deep(.el-table .cell) {
  padding: 8px 12px;
}
/* æŒ‰é’®æ ·å¼ä¼˜åŒ– */
:deep(.el-button--primary) {
  background: linear-gradient(135deg, #409eff 0%, #3375e0 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--success) {
  background: linear-gradient(135deg, #67c23a 0%, #529b2f 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--warning) {
  background: linear-gradient(135deg, #e6a23c 0%, #d18c2a 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--danger) {
  background: linear-gradient(135deg, #f56c6c 0%, #e05b5b 100%);
  border: none;
  border-radius: 4px;
}
/* æ ‡ç­¾æ ·å¼ */
:deep(.el-tag) {
  border-radius: 12px;
  border: none;
  font-weight: 500;
}
/* å¯¹è¯æ¡†æ ·å¼ä¼˜åŒ– */
:deep(.el-dialog) {
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
:deep(.el-dialog__header) {
  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  border-bottom: 1px solid #e4e7ed;
  padding: 15px 20px;
}
:deep(.el-dialog__title) {
  font-weight: 600;
  color: #303133;
}
/* ä¸Šä¼ ç»„件样式 */
:deep(.el-upload-dragger) {
  border: 2px dashed #dcdfe6;
  border-radius: 6px;
  background-color: #fafafa;
  transition: all 0.3s ease;
}
:deep(.el-upload-dragger:hover) {
  border-color: #409eff;
  background-color: #f0f7ff;
}
/* å“åº”式设计 */
@media (max-width: 768px) {
  .ethics-review-detail {
    padding: 10px;
  }
  .expert-stats .el-col {
    margin-bottom: 10px;
  }
  .upload-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
}
/* åŠ¨ç”»æ•ˆæžœ */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
/* åŠ è½½çŠ¶æ€ */
.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}
/* ä¸“家类型样式 */
.normal-expert {
  color: #409eff;
  font-weight: 500;
}
.chief-expert {
  color: #f56c6c;
  font-weight: 600;
}
/* ä¸“家行样式 */
:deep(.normal-expert-row) {
  background-color: #fafafa;
}
:deep(.chief-expert-row) {
  background-color: #fff7e6;
}
:deep(.normal-expert-row:hover) {
  background-color: #f0f7ff;
}
:deep(.chief-expert-row:hover) {
  background-color: #ffecc2;
}
/* æ— æ•°æ®æ ·å¼ */
.no-data {
  color: #909399;
  font-style: italic;
}
/* ä¸“家意见样式 */
.expert-opinion {
  color: #303133;
  line-height: 1.5;
}
/* å·²å‘送按钮样式 */
.sent-button {
  color: #67c23a !important;
}
/* è¡¨æ ¼è¡Œæ‚¬åœæ•ˆæžœ */
:deep(.el-table__row:hover) {
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}
/* è‡ªå®šä¹‰æ»šåŠ¨æ¡ */
:deep(::-webkit-scrollbar) {
  width: 6px;
  height: 6px;
}
:deep(::-webkit-scrollbar-track) {
  background: #f1f1f1;
  border-radius: 3px;
}
:deep(::-webkit-scrollbar-thumb) {
  background: #c1c1c1;
  border-radius: 3px;
}
:deep(::-webkit-scrollbar-thumb:hover) {
  background: #a8a8a8;
}
/* ä¸“家审查表格特殊样式 */
.expert-table-special :deep(.el-table__row) {
  transition: all 0.3s ease;
}
.expert-table-special :deep(.el-table__row:hover) {
  background-color: #f0f7ff;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* ä¸»å§”专家行高亮 */
:deep(.chief-expert-row) {
  background-color: #fff7e6 !important;
}
:deep(.chief-expert-row:hover) {
  background-color: #ffecc2 !important;
}
</style>
src/views/business/ethicalReview/ethicalReviewInfo.vue
@@ -1,7 +1,9 @@
<template>
  <div class="ethics-review-detail">
    <case-basic-info :case-id="caseId" :show-attachment="true" />
    <el-card class="detail-card">
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <!-- ä¼¦ç†å®¡æŸ¥åŸºæœ¬ä¿¡æ¯ -->
      <div slot="header" class="clearfix">
        <span class="detail-title">伦理审查基本信息</span>
        <div style="float: right;">
@@ -12,7 +14,7 @@
          <el-button
            type="warning"
            @click="handleEndReview"
            :disabled="form.ethicsConclusion === 'terminated'"
            :disabled="form.status === '2'"
          >
            ç»“束审查
          </el-button>
@@ -22,94 +24,155 @@
      <el-form :model="form" ref="form" :rules="rules" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="住院号" prop="hospitalNo">
              <el-input v-model="form.hospitalNo" readonly />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="donorName">
              <el-input v-model="form.donorName" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="gender">
              <el-select v-model="form.gender" style="width: 100%">
                <el-option label="男" value="0" />
                <el-option label="女" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
            <el-form-item label="发起主题" prop="initiateTheme">
              <el-input
                v-model="form.initiateTheme"
                placeholder="请输入发起主题"
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" />
            </el-form-item>
          </el-col>
          <el-col :span="16">
            <el-form-item label="疾病诊断" prop="diagnosis">
              <el-input v-model="form.diagnosis" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="伦理结论" prop="ethicsConclusion">
              <el-select v-model="form.ethicsConclusion" style="width: 100%">
                <el-option label="审查中" value="reviewing" />
                <el-option label="同意" value="approved" />
                <el-option
                  label="修改后同意"
                  value="approved_with_modifications"
                />
                <el-option label="修改后重审" value="re-review" />
                <el-option label="不同意" value="disapproved" />
                <el-option label="终止审查" value="terminated" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="发起人" prop="initiatePerson">
              <el-input v-model="form.initiatePerson"  />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="审查状态" prop="status">
              <el-select
                v-model="form.status"
                style="width: 100%"
              >
                <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="8">
            <el-form-item label="审查时间" prop="reviewTime">
            <el-form-item label="发起时间" prop="startTime">
              <el-date-picker
                v-model="form.reviewTime"
                v-model="form.startTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="登记人" prop="registrant">
              <el-input v-model="form.registrant" />
            <el-form-item label="截止时间" prop="cutOffTime">
              <el-date-picker
                v-model="form.cutOffTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
              >
              </el-date-picker>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- ä¸“家相关信息 -->
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="专家姓名" prop="expertName">
              <el-input v-model="form.expertName"  />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="专家编号" prop="expertNo">
              <el-input v-model="form.expertNo"  />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="专家类型" prop="expertType">
              <el-select
                v-model="form.expertType"
                style="width: 100%"
              >
                <el-option label="普通专家" value="normal" />
                <el-option label="主委专家" value="chief" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="专家结论" prop="expertConclusion">
              <el-select
                v-model="form.expertConclusion"
                style="width: 100%"
              >
                <el-option label="同意" value="1" />
                <el-option label="不同意" value="0" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="专家结论时间" prop="expertTime">
              <el-date-picker
                v-model="form.expertTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="专家排队序号" prop="orderNo">
              <el-input-number
                v-model="form.orderNo"
                :min="1"
                :max="20"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="伦理意见" prop="ethicsOpinion">
            <el-form-item label="专家意见" prop="expertOpinion">
              <el-input
                type="textarea"
                :rows="3"
                v-model="form.ethicsOpinion"
                placeholder="请输入伦理审查意见"
                :rows="2"
                v-model="form.expertOpinion"
                placeholder="请输入专家意见"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="登记时间" prop="registrationTime">
          <el-date-picker
            v-model="form.registrationTime"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            style="width: 100%"
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="备注" prop="remark">
              <el-input
                type="textarea"
                :rows="3"
                v-model="form.remark"
                placeholder="请输入备注信息"
          />
        </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </el-card>
    <!-- é™„件上传 -->
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
@@ -176,12 +239,11 @@
        </el-table-column>
      </el-table>
    </el-card>
    <!-- ä¸“家审查情况 -->
    <el-card class="expert-card">
      <div slot="header" class="clearfix">
        <span class="detail-title"
          >专家审查情况 (18位专家 + 1位主委专家)</span
        >
        <span class="detail-title">专家审查情况 (18位专家 + 1位主委专家)</span>
        <div style="float: right;">
          <el-button
            size="mini"
@@ -209,6 +271,7 @@
          </el-button>
        </div>
      </div>
 <!-- ä¸“家统计信息 -->
      <div
        class="expert-stats"
@@ -245,12 +308,13 @@
          </el-col>
        </el-row>
      </div>
      <!-- ä¸“家审查表格 -->
      <el-table
        :data="expertReviews"
        v-loading="expertLoading"
        style="width: 100%"
        heiht="300"
        height="800"
        :row-class-name="getExpertRowClassName"
      >
        <el-table-column label="序号" width="60" align="center" type="index" />
@@ -320,7 +384,7 @@
        <el-table-column label="发送时间" width="160" align="center">
          <template slot-scope="scope">
            <span>{{
              scope.row.reviewTime ? parseTime(scope.row.reviewTime) : "未发送"
              scope.row.sendTime ? parseTime(scope.row.sendTime) : "未发送"
            }}</span>
          </template>
        </el-table-column>
@@ -357,8 +421,6 @@
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- å‘送专家对话框 -->
@@ -409,50 +471,134 @@
        >
      </div>
    </el-dialog>
    <!-- ä¸Šä¼ é™„件对话框 -->
    <el-dialog
      title="上传附件"
      :visible.sync="uploadDialogVisible"
      width="500px"
      :close-on-click-modal="false"
    >
      <el-upload
        ref="uploadRef"
        class="upload-demo"
        drag
        :action="uploadAction"
        :headers="headers"
        multiple
        :file-list="tempFileList"
        :before-upload="beforeUpload"
        :on-change="handleFileChange"
        :on-remove="handleTempRemove"
        :on-success="handleUploadSuccess"
        :auto-upload="false"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">
          æ”¯æŒä¸Šä¼ pdf、jpg、png、doc、docx、xls、xlsx格式文件,单个文件不超过10MB
        </div>
      </el-upload>
      <div slot="footer" class="dialog-footer">
        <el-button @click="uploadDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="submitUpload"
          :loading="uploadLoading"
          :disabled="tempFileList.length === 0"
        >
          ç¡®è®¤ä¸Šä¼ 
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { getToken } from "@/utils/auth";
import {
  getEthicsReviewDetail,
  updateEthicsReview,
  sendExpertReview,
  endEthicsReview,
  uploadAttachment,
  deleteAttachment,
  getAttachments
} from "./ethicsReview";
  reviewinitiateBaseInfoList,
  ethicalreviewedit,
  ethicalreviewadd
} from "@/api/businessApi";
import CaseBasicInfo from "@/components/CaseBasicInfo";
export default {
  name: "EthicsReviewDetail",
  components: { CaseBasicInfo },
  data() {
    return {
      // é¡µé¢æ¨¡å¼
      isEdit: false,
      // åŸºæœ¬ä¿¡æ¯
      infoid: undefined,
      caseId: null,
      caseNo: "",
      // è¡¨å•数据
      form: {
        // åŸºç¡€ä¿¡æ¯
        id: undefined,
        hospitalNo: "",
        donorName: "",
        gender: "",
        age: "",
        diagnosis: "",
        ethicsConclusion: "reviewing",
        ethicsOpinion: "",
        reviewTime: "",
        registrant: "",
        registrationTime: new Date()
          .toISOString()
          .replace("T", " ")
          .substring(0, 19)
        infoid: undefined,
        caseNo: "",
        initiateTheme: "",
        initiatePerson: "",
        // çŠ¶æ€å’Œæ—¶é—´
        status: "0", // 0:新建, 1:审查中, 2:结束
        startTime: "",
        cutOffTime: "",
        endTime: "",
        // ä¸“家信息
        expertName: "",
        expertNo: "",
        expertType: "normal",
        expertConclusion: "",
        expertOpinion: "",
        expertTime: "",
        orderNo: 1,
        // å¤‡æ³¨
        remark: "",
        // ç³»ç»Ÿå­—段
        createBy: "",
        createTime: "",
        updateBy: "",
        updateTime: "",
        delFlag: "0"
      },
      // è¡¨å•验证规则
      rules: {
        donorName: [
          { required: true, message: "捐献者姓名不能为空", trigger: "blur" }
  initiateTheme: [
    { required: true, message: "发起主题不能为空", trigger: "blur" },
    { min: 2, max: 100, message: "长度在 2 åˆ° 100 ä¸ªå­—符", trigger: "blur" }
        ],
        ethicsConclusion: [
          { required: true, message: "伦理结论不能为空", trigger: "change" }
  initiatePerson: [
    { required: true, message: "发起人不能为空", trigger: "blur" }
        ],
        reviewTime: [
          { required: true, message: "审查时间不能为空", trigger: "change" }
  status: [
    { required: true, message: "审查状态不能为空", trigger: "change" }
  ],
  startTime: [
    { required: true, message: "发起时间不能为空", trigger: "change" }
  ],
  cutOffTime: [
    { required: true, message: "截止时间不能为空", trigger: "change" }
  ],
  expertName: [
    { max: 50, message: "长度不能超过 50 ä¸ªå­—符", trigger: "blur" }
  ],
  expertNo: [
    { max: 50, message: "长度不能超过 50 ä¸ªå­—符", trigger: "blur" }
  ],
  expertConclusion: [
    { max: 2, message: "长度不能超过 2 ä¸ªå­—符", trigger: "change" }
  ],
  remark: [
    { max: 500, message: "长度不能超过 500 ä¸ªå­—符", trigger: "blur" }
        ]
      },
      // ä¿å­˜åŠ è½½çŠ¶æ€
@@ -460,6 +606,7 @@
      // é™„件数据
      attachments: [],
      // ä¸“家审查数据
     expertReviews: [
        // ä¸“家(18位)- åˆå§‹çŠ¶æ€ä¸ºç”³è¯·ä¸­
        {
@@ -469,7 +616,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 2,
@@ -478,7 +626,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 3,
@@ -487,7 +636,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 4,
@@ -496,7 +646,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 5,
@@ -505,7 +656,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 6,
@@ -514,7 +666,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 7,
@@ -523,7 +676,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 8,
@@ -532,7 +686,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 9,
@@ -541,7 +696,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 10,
@@ -550,7 +706,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 11,
@@ -559,7 +716,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 12,
@@ -568,7 +726,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 13,
@@ -577,7 +736,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 14,
@@ -586,7 +746,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 15,
@@ -595,7 +756,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 16,
@@ -604,7 +766,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 17,
@@ -613,7 +776,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 18,
@@ -622,7 +786,8 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        },
        // ä¸»å§”专家(1位)
        {
@@ -632,11 +797,13 @@
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: ""
          reviewTime: "",
          sendTime: ""
        }
      ],
      expertLoading: false,
      attachmentLoading: false,
      // å‘送对话框
      sendDialogVisible: false,
      sendForm: {
@@ -644,16 +811,37 @@
        expertIds: [],
        content: ""
      },
      // ä¸Šä¼ ç›¸å…³
      uploadDialogVisible: false,
      uploadLoading: false,
      tempFileList: [],
      uploadAction: process.env.VUE_APP_BASE_API + "/common/upload",
      headers: {
        Authorization: "Bearer " + getToken()
      },
      // å¯ç”¨ä¸“家列表
      availableExperts: [
        { id: 1, name: "张教授", type: "normal" },
        { id: 2, name: "李教授", type: "normal" },
        { id: 3, name: "王教授", type: "normal" },
        { id: 4, name: "赵主委", type: "chief" }
        { id: 1, name: "陶昊", type: "normal" },
        { id: 2, name: "刘斌", type: "normal" },
        { id: 3, name: "于海初", type: "normal" },
        { id: 4, name: "王红梅", type: "normal" },
        { id: 5, name: "王春光", type: "normal" },
        { id: 6, name: "王静", type: "normal" },
        { id: 7, name: "边文超", type: "normal" },
        { id: 8, name: "闫志勇", type: "normal" },
        { id: 9, name: "许凤", type: "normal" },
        { id: 10, name: "许传屾", type: "normal" },
        { id: 11, name: "张红岩", type: "normal" },
        { id: 12, name: "杨苏民", type: "normal" },
        { id: 13, name: "宋玉强", type: "normal" },
        { id: 14, name: "周传利", type: "normal" },
        { id: 15, name: "荆凡波", type: "normal" },
        { id: 16, name: "矫文捷", type: "normal" },
        { id: 17, name: "董震", type: "normal" },
        { id: 18, name: "蔡金贞", type: "normal" },
        { id: 19, name: "孔心涓", type: "chief" }
      ]
    };
  },
@@ -724,47 +912,63 @@
          .length > 0
      );
    },
    // æ˜¯å¦å¯ä»¥å‘送专家审查
    canSendToExperts() {
      return this.form.id && this.form.ethicsConclusion === "reviewing";
    },
    // å½“前用户信息
    currentUser() {
      return JSON.parse(sessionStorage.getItem("user") || "{}");
    }
  },
  created() {
    const id = this.$route.query.id;
    if (id) {
      this.getDetail(id);
      this.getAttachments(id);
      // ä¸å†éœ€è¦ä»ŽæŽ¥å£èŽ·å–ä¸“å®¶åˆ—è¡¨ï¼Œä½¿ç”¨å›ºå®šçš„expertReviews数据
    } else if (this.$route.path.includes("/add")) {
      this.generateHospitalNo();
      this.form.registrant = this.currentUser.username || "当前用户";
    }
    this.infoid = this.$route.query.infoid;
    this.caseId = this.$route.query.infoid;
    // const id = this.$route.query.id;
    this.getDetail(this.infoid);
    // if (id && !this.$route.path.includes("/add")) {
    //   this.getDetail(this.infoid);
    // } else if (this.$route.path.includes("/add") && this.infoid) {
    //   this.initNewData();
    // }
  },
  methods: {
    // ç”Ÿæˆä½é™¢å·
    generateHospitalNo() {
      const timestamp = Date.now().toString();
      this.form.hospitalNo = "D" + timestamp.slice(-6);
    // åˆå§‹åŒ–新增数据
    initNewData() {
      this.form.infoid = this.infoid;
      this.form.caseNo = this.$route.query.caseNo || "";
      this.form.initiatePerson = this.currentUser.username || "当前用户";
      this.form.startTime = new Date()
        .toISOString()
        .replace("T", " ")
        .substring(0, 19);
      this.form.createBy = this.currentUser.username || "admin";
    },
    getExpertRowClassName({ row }) {
      return row.isChief ? "chief-expert-row" : "normal-expert-row";
    },
    // èŽ·å–è¯¦æƒ…
    getDetail(id) {
      getEthicsReviewDetail(id)
        .then(response => {
    async getDetail(infoid) {
      try {
        this.expertLoading = true;
        const response = await reviewinitiateBaseInfoList({ infoid: infoid });
          if (response.code === 200) {
            this.form = response.data;
          let detailData = {};
          if (response.data) {
            this.form = response.data[0];
          }
        })
        .catch(error => {
          console.log(this.form, "this.form ");
          this.infoid = detailData.infoid || this.infoid;
          this.caseNo = detailData.caseNo || "";
          this.$message.success("数据加载成功");
        } else {
          this.$message.error("获取详情失败:" + (response.msg || "未知错误"));
        }
      } catch (error) {
          console.error("获取伦理审查详情失败:", error);
          this.$message.error("获取详情失败");
        });
        this.$message.error("数据加载失败");
      } finally {
        this.expertLoading = false;
      }
    },
    // èŽ·å–ä¸“å®¶å®¡æŸ¥åˆ—è¡¨
@@ -772,46 +976,6 @@
      this.expertLoading = true;
      // æ¨¡æ‹Ÿæ•°æ® - å®žé™…项目中从接口获取
      setTimeout(() => {
        this.expertReviews = [
          // ä¸“家(18位)
          {
            id: 1,
            expertName: "张教授",
            isChief: false,
            reviewStatus: "submitted",
            expertConclusion: "approved",
            expertOpinion: "符合伦理要求",
            reviewTime: "2025-12-01 10:30:00"
          },
          {
            id: 2,
            expertName: "李教授",
            isChief: false,
            reviewStatus: "submitted",
            expertConclusion: "approved",
            expertOpinion: "方案设计合理",
            reviewTime: "2025-12-01 11:20:00"
          },
          {
            id: 3,
            expertName: "王教授",
            isChief: false,
            reviewStatus: "applying",
            expertConclusion: "",
            expertOpinion: "",
            reviewTime: ""
          },
          // ä¸»å§”专家(1位)
          {
            id: 19,
            expertName: "赵主委",
            isChief: true,
            reviewStatus: "applying",
            expertConclusion: "",
            expertOpinion: "",
            reviewTime: ""
          }
        ];
        this.expertLoading = false;
      }, 500);
    },
@@ -819,17 +983,15 @@
    // èŽ·å–é™„ä»¶åˆ—è¡¨
    getAttachments(ethicsReviewId) {
      this.attachmentLoading = true;
      getAttachments(ethicsReviewId)
        .then(response => {
          if (response.code === 200) {
            this.attachments = response.data;
          }
      // æ¨¡æ‹ŸèŽ·å–é™„ä»¶
      setTimeout(() => {
          this.attachmentLoading = false;
        })
        .catch(error => {
          console.error("获取附件列表失败:", error);
          this.attachmentLoading = false;
        });
      }, 500);
    },
    // ä¸“家行样式
    getExpertRowClassName({ row }) {
      return row.isChief ? "chief-expert-row" : "normal-expert-row";
    },
    // çŠ¶æ€è¿‡æ»¤å™¨
@@ -869,38 +1031,85 @@
    },
    // ä¿å­˜ä¿¡æ¯
    handleSave() {
      this.$refs.form.validate(valid => {
    async handleSave() {
      this.$refs.form.validate(async valid => {
        if (valid) {
          this.saveLoading = true;
          const apiMethod = this.form.id ? updateEthicsReview : addEthicsReview;
          try {
            const submitData = {
              ...this.form,
              // ç¡®ä¿å¿…要字段
              infoid: this.infoid,
              caseNo: this.caseNo
            };
          apiMethod(this.form)
            .then(response => {
            let response = null;
            if (submitData.id) {
              response = await ethicalreviewedit(submitData);
            } else {
              response = await ethicalreviewadd(submitData);
            }
              if (response.code === 200) {
                this.$message.success("保存成功");
                if (!this.form.id) {
              this.isEdit = false;
              if (!this.form.id && response.data && response.data.id) {
                  this.form.id = response.data.id;
                  this.$router.replace({
                    query: { ...this.$route.query, id: this.form.id }
                  });
                }
            } else {
              this.$message.error("保存失败:" + (response.msg || "未知错误"));
              }
            })
            .catch(error => {
          } catch (error) {
              console.error("保存失败:", error);
              this.$message.error("保存失败");
            })
            .finally(() => {
            this.$message.error("保存失败,请重试");
          } finally {
              this.saveLoading = false;
            });
          }
        }
      });
    },
    // å‘送专家审查
    handleSendToExperts() {
      this.sendDialogVisible = true;
    // ç»“束审查
    async handleEndReview() {
      this.$confirm(
        "确定要结束本次伦理审查吗?结束后将无法修改专家审查结果。",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(async () => {
          try {
            const updateData = {
              ...this.form,
              status: "2",
              endTime: new Date()
                .toISOString()
                .replace("T", " ")
                .substring(0, 19)
            };
            const response = await ethicalreviewedit(updateData);
            if (response.code === 200) {
              this.$message.success("审查已结束");
              this.form.status = "2";
              this.form.endTime = updateData.endTime;
            } else {
              this.$message.error("操作失败:" + (response.msg || "未知错误"));
            }
          } catch (error) {
            console.error("结束审查失败:", error);
            this.$message.error("结束审查失败");
          }
        })
        .catch(() => {});
    },
    // å‘送给专家
@@ -949,54 +1158,29 @@
        return;
      }
      sendExpertReview({
        ethicsReviewId: this.form.id,
        expertIds: this.sendForm.expertIds,
        content: this.sendForm.content
      })
        .then(response => {
          if (response.code === 200) {
      // æ¨¡æ‹Ÿå‘送
            this.$message.success("发送成功");
            this.sendDialogVisible = false;
            this.getExpertReviews(this.form.id);
      // æ›´æ–°ä¸“家状态
      this.sendForm.expertIds.forEach(expertId => {
        const index = this.expertReviews.findIndex(
          expert => expert.id === expertId
        );
        if (index !== -1) {
          this.expertReviews[index].reviewStatus = "submitted";
          this.expertReviews[index].sendTime = new Date()
            .toISOString()
            .replace("T", " ")
            .substring(0, 19);
        }
      });
            this.sendForm = {
              expertType: "normal",
              expertIds: [],
              content: ""
            };
          }
        })
        .catch(error => {
          console.error("发送失败:", error);
          this.$message.error("发送失败");
        });
    },
    // ç»“束审查
    handleEndReview() {
      this.$confirm(
        "确定要结束本次伦理审查吗?结束后将无法修改专家审查结果。",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(() => {
          endEthicsReview(this.form.id)
            .then(response => {
              if (response.code === 200) {
                this.$message.success("审查已结束");
                this.form.ethicsConclusion = "terminated";
              }
            })
            .catch(error => {
              console.error("结束审查失败:", error);
              this.$message.error("结束审查失败");
            });
        })
        .catch(() => {});
    },
    // ç¼–辑专家审查
@@ -1052,7 +1236,7 @@
      );
    },
    // ä¸Šä¼ é™„ä»¶
    // ä¸Šä¼ é™„件相关方法
    handleUploadAttachment() {
      this.uploadDialogVisible = true;
    },
@@ -1100,37 +1284,30 @@
      this.tempFileList = fileList;
    },
    // ç§»é™¤ä¸´æ—¶æ–‡ä»¶
    handleTempRemove(file, fileList) {
      this.tempFileList = fileList;
    },
    // ä¸Šä¼ æˆåŠŸå¤„ç†
    handleUploadSuccess(response, file, fileList) {
      if (response.code === 200) {
        this.$message.success("文件上传成功");
        this.uploadDialogVisible = false;
        this.tempFileList = [];
      } else {
        this.$message.error(response.msg || "文件上传失败");
      }
    },
    // æäº¤ä¸Šä¼ 
    submitUpload() {
    async submitUpload() {
      if (this.tempFileList.length === 0) {
        this.$message.warning("请先选择要上传的文件");
        return;
      }
      this.$refs.uploadRef.submit();
      this.uploadLoading = true;
      const uploadPromises = this.tempFileList.map(file => {
        const formData = new FormData();
        formData.append("file", file.raw);
        formData.append("ethicsReviewId", this.form.id);
        return uploadAttachment(formData);
      });
      Promise.all(uploadPromises)
        .then(responses => {
          this.$message.success("文件上传成功");
          this.uploadDialogVisible = false;
          this.tempFileList = [];
          this.getAttachments(this.form.id);
        })
        .catch(error => {
          console.error("上传失败:", error);
          this.$message.error("文件上传失败");
        })
        .finally(() => {
          this.uploadLoading = false;
        });
    },
    // é¢„览附件
@@ -1158,29 +1335,6 @@
      link.download = attachment.fileName;
      link.click();
      this.$message.success(`开始下载: ${attachment.fileName}`);
    },
    // åˆ é™¤é™„ä»¶
    handleRemoveAttachment(attachment) {
      this.$confirm("确定要删除这个附件吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          deleteAttachment(attachment.id)
            .then(response => {
              if (response.code === 200) {
                this.$message.success("附件删除成功");
                this.getAttachments(this.form.id);
              }
            })
            .catch(error => {
              console.error("删除附件失败:", error);
              this.$message.error("删除附件失败");
            });
        })
        .catch(() => {});
    },
    // èŽ·å–æ–‡ä»¶ç±»åž‹
@@ -1231,6 +1385,7 @@
  }
};
</script>
<style scoped>
.ethics-review-detail {
  padding: 20px;
@@ -1286,22 +1441,6 @@
  font-weight: bold;
}
.upload-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding: 10px;
  background-color: #f8f9fa;
  border-radius: 4px;
}
.upload-title {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}
.file-info {
  display: flex;
  align-items: center;
@@ -1313,133 +1452,6 @@
  color: #909399;
}
/* è¡¨å•样式优化 */
:deep(.el-form-item__label) {
  font-weight: 500;
}
:deep(.el-input__inner) {
  border-radius: 4px;
}
:deep(.el-textarea__inner) {
  border-radius: 4px;
  resize: vertical;
}
/* è¡¨æ ¼æ ·å¼ä¼˜åŒ– */
:deep(.el-table) {
  border-radius: 8px;
  overflow: hidden;
}
:deep(.el-table th) {
  background-color: #f5f7fa;
  color: #606266;
  font-weight: 500;
}
:deep(.el-table .cell) {
  padding: 8px 12px;
}
/* æŒ‰é’®æ ·å¼ä¼˜åŒ– */
:deep(.el-button--primary) {
  background: linear-gradient(135deg, #409eff 0%, #3375e0 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--success) {
  background: linear-gradient(135deg, #67c23a 0%, #529b2f 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--warning) {
  background: linear-gradient(135deg, #e6a23c 0%, #d18c2a 100%);
  border: none;
  border-radius: 4px;
}
:deep(.el-button--danger) {
  background: linear-gradient(135deg, #f56c6c 0%, #e05b5b 100%);
  border: none;
  border-radius: 4px;
}
/* æ ‡ç­¾æ ·å¼ */
:deep(.el-tag) {
  border-radius: 12px;
  border: none;
  font-weight: 500;
}
/* å¯¹è¯æ¡†æ ·å¼ä¼˜åŒ– */
:deep(.el-dialog) {
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
:deep(.el-dialog__header) {
  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  border-bottom: 1px solid #e4e7ed;
  padding: 15px 20px;
}
:deep(.el-dialog__title) {
  font-weight: 600;
  color: #303133;
}
/* ä¸Šä¼ ç»„件样式 */
:deep(.el-upload-dragger) {
  border: 2px dashed #dcdfe6;
  border-radius: 6px;
  background-color: #fafafa;
  transition: all 0.3s ease;
}
:deep(.el-upload-dragger:hover) {
  border-color: #409eff;
  background-color: #f0f7ff;
}
/* å“åº”式设计 */
@media (max-width: 768px) {
  .ethics-review-detail {
    padding: 10px;
  }
  .expert-stats .el-col {
    margin-bottom: 10px;
  }
  .upload-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
}
/* åŠ¨ç”»æ•ˆæžœ */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
/* åŠ è½½çŠ¶æ€ */
.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}
/* ä¸“家类型样式 */
.normal-expert {
  color: #409eff;
@@ -1485,49 +1497,14 @@
  color: #67c23a !important;
}
/* è¡¨æ ¼è¡Œæ‚¬åœæ•ˆæžœ */
:deep(.el-table__row:hover) {
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}
/* è‡ªå®šä¹‰æ»šåŠ¨æ¡ */
:deep(::-webkit-scrollbar) {
  width: 6px;
  height: 6px;
/* å“åº”式设计 */
@media (max-width: 768px) {
  .ethics-review-detail {
    padding: 10px;
}
:deep(::-webkit-scrollbar-track) {
  background: #f1f1f1;
  border-radius: 3px;
  .expert-stats .el-col {
    margin-bottom: 10px;
}
:deep(::-webkit-scrollbar-thumb) {
  background: #c1c1c1;
  border-radius: 3px;
}
:deep(::-webkit-scrollbar-thumb:hover) {
  background: #a8a8a8;
}
/* ä¸“家审查表格特殊样式 */
.expert-table-special :deep(.el-table__row) {
  transition: all 0.3s ease;
}
.expert-table-special :deep(.el-table__row:hover) {
  background-color: #f0f7ff;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* ä¸»å§”专家行高亮 */
:deep(.chief-expert-row) {
  background-color: #fff7e6 !important;
}
:deep(.chief-expert-row:hover) {
  background-color: #ffecc2 !important;
}
</style>
src/views/business/ethicalReview/index.vue
@@ -75,16 +75,16 @@
    <el-card class="tool-card">
      <el-row :gutter="10">
        <el-col :span="16">
          <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
          <!-- <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
            >新建审查</el-button
          >
          <el-button
          > -->
          <!-- <el-button
            type="success"
            icon="el-icon-edit"
            :disabled="single"
            @click="handleUpdate"
            >修改</el-button
          >
          > -->
          <el-button
            type="warning"
            icon="el-icon-download"
@@ -361,7 +361,7 @@
    handleView(row) {
      this.$router.push({
        path: "/case/ethicalReviewInfo",
        query: { id: row.infoid }
        query: { infoid: row.infoid }
      });
    },
    // æ–°å¢žæŒ‰é’®æ“ä½œ
@@ -370,10 +370,10 @@
    },
    // ä¿®æ”¹æŒ‰é’®æ“ä½œ
    handleUpdate(row) {
      const id = row.infoid || this.ids[0];
      const infoid = row.infoid;
      this.$router.push({
        path: "/case/ethicalReviewInfo",
        query: { id: id }
        query: { infoid: infoid }
      });
    },
    // ç»“束审查操作
src/views/business/maintain/index.vue
@@ -115,7 +115,7 @@
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column
          label="住院号"
          label="案例编号"
          align="center"
          prop="caseNo"
          width="120"
@@ -191,28 +191,34 @@
          prop="coordinatorName"
          width="100"
        />
        <el-table-column
        <!-- <el-table-column
          label="维护项目"
          align="center"
          prop="itemName"
          width="120"
          show-overflow-tooltip
        />
        /> -->
        <el-table-column
          label="维护时间"
          label="最新维护时间"
          align="center"
          prop="itemTime"
          prop="updateTime"
          width="140"
        >
          <template slot-scope="scope">
            <span>{{
              scope.row.itemTime
                ? parseTime(scope.row.itemTime, "{y}-{m}-{d} {h}:{i}")
              scope.row.updateTime
                ? parseTime(scope.row.updateTime)
                : "-"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="维护人员"
          align="center"
          prop="updateBy"
          width="120"
        />
        <el-table-column
          label="操作"
          align="center"
          width="120"
src/views/business/maintain/maintainInfo.vue
@@ -1,7 +1,8 @@
<template>
  <div class="maintenance-detail">
    <case-basic-info :case-id="caseId" :show-attachment="true" />
    <!-- åŸºç¡€ä¿¡æ¯ -->
    <el-card class="detail-card">
    <!-- <el-card class="detail-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">供者基本信息</span>
        <el-button type="success" style="float: right;" @click="handleSave">
@@ -140,11 +141,11 @@
          />
        </el-form-item>
      </el-form>
    </el-card>
    </el-card> -->
    <el-card class="assessment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">供者评估各项记录</span>
        <span class="detail-title">评估各项记录</span>
        <el-button
          type="primary"
          size="mini"
@@ -234,40 +235,7 @@
            </el-table>
          </el-card>
        </el-tab-pane>
        <!-- è‚åŠŸèƒ½è‚¾åŠŸèƒ½ -->
        <el-tab-pane label="肝功能肾功能" name="liverKidney">
          <liver-kidney-panel
            ref="liverKidney"
            :initial-data="assessmentData.liverKidney"
            :is-editing="isEdit && activeTab === 'liverKidney'"
            @data-change="handleLiverKidneyDataChange"
          />
        </el-tab-pane>
        <!-- è¡€å¸¸è§„ -->
        <el-tab-pane label="血常规" name="bloodRoutine">
          <blood-routine-panel
            ref="bloodRoutine"
            :initial-data="assessmentData.bloodRoutine"
            :is-editing="isEdit && activeTab === 'bloodRoutine'"
            @data-change="handleBloodRoutineDataChange"
          />
        </el-tab-pane>
        <!-- å°¿å¸¸è§„ -->
        <el-tab-pane label="尿常规" name="urineRoutine">
          <urine-routine-panel
            ref="urineRoutine"
            :initial-data="assessmentData.urineRoutine"
            :is-editing="isEdit && activeTab === 'urineRoutine'"
            @data-change="handleUrineRoutineDataChange"
          />
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <!-- æŠ¤ç†æ ¸æŸ¥è®°å½• -->
        <el-tab-pane label="护理核查记录" name="hlihc">
    <el-card class="record-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">护理核查记录</span>
@@ -304,7 +272,9 @@
        <el-table-column label="附件" align="center" width="120">
          <template slot-scope="scope">
            <el-button
              v-if="scope.row.attachments && scope.row.attachments.length > 0"
                    v-if="
                      scope.row.attachments && scope.row.attachments.length > 0
                    "
              size="mini"
              type="text"
              @click="handleViewRecordAttachments(scope.row)"
@@ -340,6 +310,41 @@
        </el-table-column>
      </el-table>
    </el-card>
        </el-tab-pane>
        <!-- è‚åŠŸèƒ½è‚¾åŠŸèƒ½ -->
        <el-tab-pane label="肝功能肾功能" name="liverKidney">
          <liver-kidney-panel
            ref="liverKidney"
            :initial-data="assessmentData.liverKidney"
            :is-editing="isEdit && activeTab === 'liverKidney'"
            @data-change="handleLiverKidneyDataChange"
          />
        </el-tab-pane>
        <!-- è¡€å¸¸è§„ -->
        <el-tab-pane label="血常规" name="bloodRoutine">
          <blood-routine-panel
            ref="bloodRoutine"
            :initial-data="assessmentData.bloodRoutine"
            :is-editing="isEdit && activeTab === 'bloodRoutine'"
            @data-change="handleBloodRoutineDataChange"
          />
        </el-tab-pane>
        <!-- å°¿å¸¸è§„ -->
        <el-tab-pane label="尿常规" name="urineRoutine">
          <urine-routine-panel
            ref="urineRoutine"
            :initial-data="assessmentData.urineRoutine"
            :is-editing="isEdit && activeTab === 'urineRoutine'"
            @data-change="handleUrineRoutineDataChange"
          />
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <!-- æŠ¤ç†æ ¸æŸ¥è®°å½• -->
    <!-- åŸ¹å…»è®°å½•编辑对话框 -->
    <el-dialog
@@ -569,6 +574,8 @@
import LiverKidneyPanel from "@/components/MaintainComponents/LiverKidneyPanel.vue";
import BloodRoutinePanel from "@/components/MaintainComponents/BloodRoutinePanel.vue";
import UrineRoutinePanel from "@/components/MaintainComponents/UrineRoutinePanel.vue";
import CaseBasicInfo from "@/components/CaseBasicInfo";
import store from "@/store";
import dayjs from "dayjs";
export default {
@@ -579,7 +586,8 @@
    FilePreviewDialog,
    LiverKidneyPanel,
    BloodRoutinePanel,
    UrineRoutinePanel
    UrineRoutinePanel,
    CaseBasicInfo
  },
  dicts: [
    "sys_donornode",
@@ -592,7 +600,8 @@
  data() {
    return {
      isEdit: false,
      caseId: null,
      isEdit: true,
      currentMaintenanceId: null,
      isEditMode: false,
      form: {
@@ -686,7 +695,8 @@
      // é™„件相关配置
      attachmentLimit: 10,
      attachmentAccept: ".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt",
      attachmentAccept:
        ".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt",
      // è¯„估数据存储
      assessmentData: {
@@ -699,6 +709,8 @@
    };
  },
  created() {
    this.caseId = this.$route.query.infoid;
    this.loadMaintenanceData();
  },
  watch: {
@@ -808,10 +820,13 @@
        if (response.code === 200) {
          this.$message.success("保存成功");
          this.isEdit = false;
          this.donatebaseinfoEdit({
            id: this.$route.query.infoid,
            extracontent: JSON.stringify(this.extracontentinfo)
          });
          if (!this.currentMaintenanceId) {
            this.currentMaintenanceId = response.data;
          }
          // this.donatebaseinfoEdit({
          //   id: this.$route.query.infoid,
          //   extracontent: JSON.stringify(this.extracontentinfo)
          // });
          if (!this.isEditMode && response.data && response.data.id) {
            this.currentMaintenanceId = response.data.id;
            this.isEditMode = true;
@@ -853,14 +868,16 @@
    handleEditCulture(row) {
      this.cultureDialogTitle = "编辑培养记录";
      this.cultureForm = { ...row };
      this.cultureFileList = row.attachments ? row.attachments.map(item => ({
      this.cultureFileList = row.attachments
        ? row.attachments.map(item => ({
        uid: item.id || Math.random(),
        name: item.fileName,
        fileSize: item.fileSize,
        url: item.path || item.fileUrl,
        uploadTime: item.uploadTime,
        status: "success"
      })) : [];
          }))
        : [];
      this.cultureDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.cultureForm && this.$refs.cultureForm.clearValidate();
@@ -915,7 +932,7 @@
          .toISOString()
          .replace("T", " ")
          .substring(0, 19),
        recorder: "当前用户",
        recorder: store.getters.name,
        checkRecord: "",
        attachments: []
      };
@@ -929,14 +946,16 @@
    handleEditRecord(row) {
      this.recordDialogTitle = "编辑护理核查记录";
      this.recordForm = { ...row };
      this.recordFileList = row.attachments ? row.attachments.map(item => ({
      this.recordFileList = row.attachments
        ? row.attachments.map(item => ({
        uid: item.id || Math.random(),
        name: item.fileName,
        fileSize: item.fileSize,
        url: item.path || item.fileUrl,
        uploadTime: item.uploadTime,
        status: "success"
      })) : [];
          }))
        : [];
      this.recordDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.recordForm && this.$refs.recordForm.clearValidate();
@@ -1113,7 +1132,10 @@
    /** èŽ·å–æ–‡ä»¶ç±»åž‹ */
    getFileType(fileName) {
      if (!fileName) return "other";
      const extension = fileName.split(".").pop().toLowerCase();
      const extension = fileName
        .split(".")
        .pop()
        .toLowerCase();
      const imageTypes = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
      const pdfTypes = ["pdf"];
      const officeTypes = ["doc", "docx", "xls", "xlsx", "ppt", "pptx"];
@@ -1167,7 +1189,10 @@
    /** èŽ·å–æ–‡ä»¶æ‰©å±•å */
    getFileExtension(filename) {
      return filename.split(".").pop().toLowerCase();
      return filename
        .split(".")
        .pop()
        .toLowerCase();
    },
    /** æ ¼å¼åŒ–文件大小 */
src/views/business/transfer/index.vue
@@ -155,6 +155,18 @@
        prop="caseNo"
        width="140"
      />
      <el-table-column
        label="转运状态"
        align="center"
        prop="transitStatus"
        width="100"
      >
        <template slot-scope="scope">
          <el-tag :type="getStatusTagType(scope.row.transitStatus)">
            {{ getStatusText(scope.row.transitStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="患者信息" align="center" width="260">
        <template slot-scope="scope">
          <div class="donor-info">
@@ -194,18 +206,7 @@
        prop="contactPerson"
        width="100"
      />
      <el-table-column
        label="转运状态"
        align="center"
        prop="transitStatus"
        width="100"
      >
        <template slot-scope="scope">
          <el-tag :type="getStatusTagType(scope.row.transitStatus)">
            {{ getStatusText(scope.row.transitStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        label="创建时间"
        align="center"
@@ -429,11 +430,7 @@
      append-to-body
    >
      <div class="action-confirm">
        <p>
          ç¡®å®šè¦{{ actionText }}转运单 "{{
             currentTransport.id
          }}" å—?
        </p>
        <p>确定要{{ actionText }}转运单 "{{ currentTransport.id }}" å—?</p>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="actionOpen = false">取 æ¶ˆ</el-button>
@@ -519,15 +516,15 @@
        pageNum: 1,
        pageSize: 10,
        caseNo: undefined,
        patName: undefined,
        patName: undefined
        // åªæŸ¥è¯¢å·²åŒæ„ä¸”需要转运的案例
        // reportStatus: "3", // å·²åŒæ„
        isTransport: "2" // éœ€è¦è½¬è¿
        // isTransport: "2" // éœ€è¦è½¬è¿
      }
    };
  },
  created() {
    this.getList();
    // this.getList();
    this.checkAutoCreate();
  },
  methods: {
@@ -567,26 +564,31 @@
    },
    checkAutoCreate() {
      const query = this.$route.query;
      // ä¸ŠæŠ¥è·³è½¬è¿‡æ¥è¿›è¡Œå¤„理
      if (query.autoCreate === "true") {
        // è‡ªåŠ¨æ‰“å¼€æ¡ˆä¾‹é€‰æ‹©å¼¹æ¡†
        this.selectCaseOpen = true;
        this.resetCaseSearch();
        // å¦‚果有特定的案例编号,可以预先搜索
        if (query.caseNo) {
          // this.selectCaseOpen = true;
          this.resetCaseSearch(1);
          this.caseQueryParams.caseNo = query.caseNo;
          this.searchCaseList();
          this.searchCaseList(1);
        } else {
          this.queryParams.patName = query.patName;
        }
      }
      this.getList();
    },
    /** æœç´¢å¯ç”¨æ¡ˆä¾‹ */
    async searchCaseList() {
    async searchCaseList(type) {
      this.caseLoading = true;
      try {
        const response = await donateList(this.caseQueryParams);
        if (response.code === 200) {
          this.availableCaseList = response.rows || response.data || [];
          this.caseTotal = response.total || 0;
          if (type == 1 && response.data[0]) {
            this.selectCase(response.data[0]);
          }
        } else {
          this.$modal.msgError(response.msg || "获取案例列表失败");
        }
@@ -599,7 +601,7 @@
    },
    /** é‡ç½®æ¡ˆä¾‹æœç´¢ */
    resetCaseSearch() {
    resetCaseSearch(type) {
      this.caseQueryParams = {
        pageNum: 1,
        pageSize: 10,
@@ -608,7 +610,12 @@
        // reportStatus: "3",
        isTransport: "2"
      };
      if (!type) {
      this.searchCaseList();
      } else {
        // è·¨é¡µé¢æ–°å¢žå–消限制
        this.caseQueryParams.isTransport = null;
      }
    },
    /** åˆ¤æ–­æ¡ˆä¾‹æ˜¯å¦å·²æœ‰è½¬è¿å• */
@@ -636,7 +643,7 @@
      // æ‰“开转运单编辑页面,并传入选中的案例
      this.currentTransport = this.convertCaseToTransport(caseData);
      console.log(this.currentTransport,'currentTransport');
      console.log(this.currentTransport, "currentTransport");
      this.isEditing = false;
      this.editOpen = true;
@@ -644,7 +651,7 @@
    /** å°†æ¡ˆä¾‹ä¿¡æ¯è½¬æ¢ä¸ºè½¬è¿å•格式 */
    convertCaseToTransport(caseData) {
      console.log(caseData,'2');
      console.log(caseData, "2");
      return {
        caseNo: caseData.caseNo,
src/views/project/DonationProcess/index.vue
@@ -172,7 +172,7 @@
        </template>
      </el-table-column>
      <el-table-column label="姓名" align="center" prop="name" width="100" />
      <el-table-column label="捐献者姓名" align="center" prop="name" width="100" />
      <el-table-column label="性别" align="center" prop="sex" width="80">
        <template slot-scope="scope">
src/views/project/donatebaseinfo/EditCaseModal.vue
@@ -45,12 +45,8 @@
            <el-col :span="6">
              <el-form-item label="性别" prop="sex">
                <el-select v-model="formData.sex" placeholder="请选择性别">
                  <el-option
                    v-for="dict in dict.type.sys_user_sex || []"
                    :key="dict.value"
                    :label="dict.label"
                    :value="parseInt(dict.value)"
                  />
                  <el-option label="男" value="1" />
                  <el-option label="女" value="2" />
                </el-select>
              </el-form-item>
            </el-col>
@@ -357,10 +353,10 @@
          <el-row :gutter="20">
            <el-col :span="8">
              <el-form-item label="GSC评分" prop="gcsScore">
              <el-form-item label="GCS评分" prop="gcsScore">
                <el-input
                  v-model="formData.gcsScore"
                  placeholder="请输入GSC评分"
                  placeholder="请输入GCS评分"
                />
              </el-form-item>
            </el-col>
@@ -1148,7 +1144,10 @@
    async handleSubmit() {
      const valid = await this.$refs.formRef.validate().catch(() => false);
      if (!valid) return;
      if (!valid) {
        this.$message.error("请确认表单必填信息完整后提交");
        return;
      }
      this.submitLoading = true;
      try {
src/views/project/donatebaseinfo/index.vue
@@ -10,7 +10,7 @@
    >
      <el-row :gutter="8">
        <el-col :span="5">
          <el-form-item label="患者姓名" prop="name">
          <el-form-item label="捐献者姓名" prop="name">
            <el-input
              v-model="queryParams.name"
              placeholder="请输入姓名"
@@ -105,7 +105,7 @@
        prop="caseNo"
        width="200"
      />
      <el-table-column label="姓名" align="center" prop="name" width="100" />
      <el-table-column label="捐献者姓名" align="center" prop="name" width="100" />
      <el-table-column label="性别" align="center" prop="sex" width="100">
        <template slot-scope="scope">
          <dict-tag
@@ -134,7 +134,7 @@
        align="center"
        prop="treatmenthospitalname"
      />
      <el-table-column label="GSC评分" align="center" prop="gcsScore" />
      <el-table-column label="GCS评分" align="center" prop="gcsScore" />
      <el-table-column label="血型" align="center" prop="bloodtype" width="100">
        <template slot-scope="scope">
          <dict-tag