WXL
2026-05-15 68daed8ac76b42542e6ed3fbcac19a057c1dedf0
src/views/business/ethicalReview/ethicalReviewInfo.vue
@@ -12,9 +12,28 @@
          </el-button>
          <el-button
            type="success"
            @click="handleCompleteReview"
            :disabled="form.status == '3' || form.status == '2'"
            :loading="completeLoading"
          >
            审查完成
          </el-button>
          <el-button
            type="warning"
            @click="handleSuspendReview"
            :disabled="form.status == '2' || form.status == '3'"
            :loading="suspendLoading"
          >
            审查中止
          </el-button>
          <el-button
            type="danger"
            @click="handleEndReview"
            :disabled="form.status === '2'"
            :disabled="form.status == '2'"
            :loading="endLoading"
          >
            结束审查
          </el-button>
@@ -36,9 +55,6 @@
              <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%">
@@ -51,54 +67,13 @@
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="发起时间" prop="startTime">
              <el-date-picker
                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="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-form-item label="伦理审查结论" prop="expertConclusion">
              <el-select v-model="form.expertConclusion" style="width: 100%">
                <el-option label="同意" value="1" />
                <el-option label="审查中" value="2" />
@@ -107,7 +82,7 @@
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="专家结论时间" prop="expertTime">
            <el-form-item label="伦理审查结论时间" prop="expertTime">
              <el-date-picker
                v-model="form.expertTime"
                type="datetime"
@@ -116,26 +91,16 @@
              />
            </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="expertOpinion">
            <el-form-item label="审查意见" prop="expertOpinion">
              <el-input
                type="textarea"
                :rows="2"
                v-model="form.expertOpinion"
                placeholder="请输入专家意见"
                placeholder="请输入意见"
              />
            </el-form-item>
          </el-col>
@@ -160,9 +125,6 @@
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">相关附件</span>
        <!-- <el-button type="primary" size="mini" @click="openUploadDialog">
          上传附件
        </el-button> -->
      </div>
      <!-- 使用 UploadAttachment 组件 -->
@@ -185,11 +147,7 @@
        <div class="list-title">
          已上传附件 ({{ form.annexfilesList.length }})
        </div>
        <el-table
          :data="form.annexfilesList"
          style="width: 100%"
          size="small"
        >
        <el-table :data="form.annexfilesList" style="width: 100%" size="small">
          <el-table-column label="文件名" min-width="200">
            <template slot-scope="scope">
              <i
@@ -240,8 +198,14 @@
      </div>
      <!-- 空状态 -->
      <div v-if="!form.annexfilesList || form.annexfilesList.length === 0" class="empty-attachment">
        <i class="el-icon-folder-opened" style="font-size: 60px; color: #C0C4CC; margin-bottom: 20px;"></i>
      <div
        v-if="!form.annexfilesList || form.annexfilesList.length == 0"
        class="empty-attachment"
      >
        <i
          class="el-icon-folder-opened"
          style="font-size: 60px; color: #C0C4CC; margin-bottom: 20px;"
        ></i>
        <p style="color: #909399; font-size: 14px;">暂无附件,请上传相关文件</p>
      </div>
    </el-card>
@@ -249,8 +213,11 @@
    <!-- 专家审查情况 -->
    <el-card class="expert-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">专家审查情况 (18位专家 + 1位主委专家)</span>
        <span class="detail-title">专家审查情况</span>
        <div style="float: right;">
          <el-button size="mini" type="primary" @click="handleAddExpert">
            添加专家
          </el-button>
          <el-button
            size="mini"
            type="primary"
@@ -286,20 +253,22 @@
        <el-row :gutter="20">
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">专家已同意:</span>
              <span class="stat-value">{{ approvedNormalExperts }}/18</span>
              <span class="stat-label">普通专家:</span>
              <span class="stat-value">{{ normalExpertsCount }}人</span>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">主委专家状态:</span>
              <span class="stat-value">{{ chiefExpertStatus }}</span>
              <span class="stat-label">主委专家:</span>
              <span class="stat-value">{{ chiefExpertsCount }}人</span>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="stat-item">
              <span class="stat-label">总完成进度:</span>
              <span class="stat-value">{{ completionRate }}%</span>
              <span class="stat-label">已同意:</span>
              <span class="stat-value"
                >{{ approvedExpertsCount }}/{{ totalExpertsCount }}</span
              >
            </div>
          </el-col>
          <el-col :span="6">
@@ -317,10 +286,10 @@
      <!-- 专家审查表格 -->
      <el-table
        :data="expertReviews"
        :data="ethicalreviewopinionsList"
        v-loading="expertLoading"
        style="width: 100%"
        height="800"
        height="600"
        :row-class-name="getExpertRowClassName"
      >
        <el-table-column label="序号" width="60" align="center" type="index" />
@@ -332,9 +301,14 @@
          fixed="left"
        >
          <template slot-scope="scope">
            <span>{{ scope.row.expertName }}</span>
            <span
              class="expert-name-link"
              @click="handleViewExpertHistory(scope.row)"
            >
              {{ scope.row.expertname }}
            </span>
            <el-tag
              v-if="scope.row.isChief"
              v-if="scope.row.expertType == '1'"
              size="mini"
              type="danger"
              style="margin-left: 5px;"
@@ -343,18 +317,31 @@
          </template>
        </el-table-column>
        <el-table-column label="专家编号" width="120" align="center">
          <template slot-scope="scope">
            <span>{{ scope.row.expertNo || "-" }}</span>
          </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
              :class="
                scope.row.expertType == '1' ? 'chief-expert' : 'normal-expert'
              "
            >
              {{ getExpertTypeText(scope.row.expertType) }}
            </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
              :type="getReviewStatusFilter(scope.row.receiveStatus)"
              size="small"
            >
              {{ getReviewStatusText(scope.row.receiveStatus) }}
            </el-tag>
          </template>
        </el-table-column>
@@ -362,11 +349,11 @@
        <el-table-column label="专家结论" width="120" align="center">
          <template slot-scope="scope">
            <el-tag
              v-if="scope.row.expertConclusion"
              :type="conclusionFilter(scope.row.expertConclusion)"
              v-if="scope.row.expertconclusion"
              :type="getConclusionFilter(scope.row.expertconclusion)"
              size="small"
            >
              {{ conclusionTextFilter(scope.row.expertConclusion) }}
              {{ getConclusionText(scope.row.expertconclusion) }}
            </el-tag>
            <span v-else class="no-data">-</span>
          </template>
@@ -374,23 +361,33 @@
        <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 :class="{ 'expert-opinion': scope.row.expertopinion }">
              {{ scope.row.expertopinion || "暂无意见" }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="结论顺序" width="100" align="center">
          <template slot-scope="scope">
            <span>{{ scope.row.conclusionorder || "-" }}</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) : "未审查"
              scope.row.conclusiontime
                ? formatDateTime(scope.row.conclusiontime)
                : "未审查"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column label="发送时间" width="160" align="center">
          <template slot-scope="scope">
            <span>{{
              scope.row.sendTime ? parseTime(scope.row.sendTime) : "未发送"
              scope.row.startTime
                ? formatDateTime(scope.row.startTime)
                : "未发送"
            }}</span>
          </template>
        </el-table-column>
@@ -402,17 +399,29 @@
              type="text"
              icon="el-icon-s-promotion"
              @click="handleSendToExpert(scope.row)"
              :disabled="scope.row.reviewStatus === 'submitted'"
              :class="{ 'sent-button': scope.row.reviewStatus === 'submitted' }"
              :disabled="
                scope.row.receiveStatus == '2' ||
                  scope.row.receiveStatus == '3' ||
                  scope.row.receiveStatus == '4'
              "
              :class="{
                'sent-button':
                  scope.row.receiveStatus == '2' ||
                  scope.row.receiveStatus == '3'
              }"
            >
              {{ scope.row.reviewStatus === "submitted" ? "已发送" : "发送" }}
              {{
                scope.row.receiveStatus == "2" || scope.row.receiveStatus == "3"
                  ? "已发送"
                  : "发送"
              }}
            </el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click="handleEditExpertReview(scope.row)"
              :disabled="scope.row.reviewStatus !== 'submitted'"
              :disabled="!['2', '3'].includes(scope.row.receiveStatus)"
            >
              编辑
            </el-button>
@@ -424,28 +433,187 @@
            >
              详情
            </el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-delete"
              @click="handleDeleteExpertReview(scope.$index)"
              style="color: #f56c6c;"
            >
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- 添加专家对话框 -->
    <el-dialog
      title="添加专家"
      :visible.sync="expertDialogVisible"
      width="800px"
      @close="handleExpertDialogClose"
    >
      <div style="margin-bottom: 20px;">
        <el-input
          v-model="expertSearchQuery"
          placeholder="请输入专家姓名或编号搜索"
          style="width: 300px; margin-right: 10px;"
          @keyup.enter.native="handleSearchExperts"
        >
          <el-button
            slot="append"
            icon="el-icon-search"
            @click="handleSearchExperts"
          ></el-button>
        </el-input>
        <el-select
          v-model="filterExpertType"
          placeholder="专家类型"
          style="width: 150px; margin-right: 10px;"
          @change="handleSearchExperts"
        >
          <el-option label="全部" value=""></el-option>
          <el-option label="普通专家" value="0"></el-option>
          <el-option label="主任委员" value="1"></el-option>
        </el-select>
        <el-button type="primary" @click="handleSearchExperts">搜索</el-button>
        <el-button @click="handleResetSearch">重置</el-button>
      </div>
      <el-table
        :data="expertList"
        v-loading="expertListLoading"
        style="width: 100%"
        max-height="400"
        @selection-change="handleExpertSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column
          label="专家姓名"
          prop="username"
          width="120"
        ></el-table-column>
        <el-table-column
          label="专家编号"
          prop="userno"
          width="120"
        ></el-table-column>
        <el-table-column label="专家类型" width="100">
          <template slot-scope="scope">
            <el-tag
              size="small"
              :type="getIsChiefExpert(scope.row) ? 'danger' : ''"
            >
              {{ getIsChiefExpert(scope.row) ? "主任委员" : "普通专家" }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="单位名称"
          prop="unitname"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          label="职称"
          prop="title"
          width="100"
        ></el-table-column>
        <el-table-column
          label="联系电话"
          prop="telephone"
          width="120"
        ></el-table-column>
      </el-table>
      <div style="margin-top: 20px; text-align: center;">
        <el-pagination
          @size-change="handlePageSizeChange"
          @current-change="handlePageChange"
          :current-page="expertPage.pageNum"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="expertPage.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="expertTotal"
        ></el-pagination>
      </div>
      <div slot="footer">
        <el-button @click="expertDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="handleConfirmAddExpert"
          :disabled="selectedExperts.length == 0"
          >确定添加</el-button
        >
      </div>
    </el-dialog>
    <!-- 发送专家对话框 -->
    <el-dialog
      title="发送专家审查"
      :title="sendDialogTitle"
      :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-group
            v-model="sendForm.expertType"
            @change="handleExpertTypeChange"
          >
            <el-radio label="normal">普通专家</el-radio>
            <el-radio label="chief">主委专家</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="发送时间" prop="startTime" required>
          <el-date-picker
            v-model="sendForm.startTime"
            type="datetime"
            placeholder="请选择发送时间"
            value-format="yyyy-MM-dd HH:mm:ss"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item
          label="截止时间"
          prop="endTime"
          :required="sendForm.expertType !== 'chief'"
        >
          <el-date-picker
            v-model="sendForm.endTime"
            type="datetime"
            placeholder="请选择截止时间"
            value-format="yyyy-MM-dd HH:mm:ss"
            style="width: 100%"
            :disabled="sendForm.expertType === 'chief'"
          />
          <div
            v-if="sendForm.expertType === 'chief'"
            style="font-size: 12px; color: #999; margin-top: 5px;"
          >
            主委专家无需设置截止时间
          </div>
        </el-form-item>
        <el-form-item label="发送方式" prop="sendType" required>
          <el-select
            v-model="sendForm.sendType"
            placeholder="请选择发送方式"
            style="width: 100%"
          >
            <el-option label="系统发送" value="0"></el-option>
            <el-option label="邮件发送" value="1"></el-option>
            <el-option label="短信发送" value="2"></el-option>
            <el-option label="其他方式" value="3"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item
          label="选择专家"
          prop="expertIds"
          v-if="sendForm.expertType === 'normal'"
          v-if="sendForm.expertType == 'normal'"
        >
          <el-select
            v-model="sendForm.expertIds"
@@ -454,13 +622,18 @@
            style="width: 100%"
          >
            <el-option
              v-for="expert in availableExperts"
              :key="expert.id"
              :label="expert.name"
              :value="expert.id"
              v-for="expert in availableNormalExperts"
              :key="getExpertKey(expert)"
              :label="
                `${expert.expertname}${
                  expert.expertNo ? '(' + expert.expertNo + ')' : ''
                }`
              "
              :value="getExpertKey(expert)"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="发送内容" prop="content">
          <el-input
            type="textarea"
@@ -472,9 +645,122 @@
      </el-form>
      <div slot="footer">
        <el-button @click="sendDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSendConfirm"
        <el-button type="primary" @click="handleSendConfirm" :loading="sending"
          >确认发送</el-button
        >
      </div>
    </el-dialog>
    <!-- 专家历史审批情况对话框 -->
    <el-dialog
      title="专家历史审批情况"
      :visible.sync="expertHistoryDialogVisible"
      width="600px"
    >
      <div v-loading="expertHistoryLoading">
        <div v-if="expertHistoryData" style="padding: 20px;">
          <el-row :gutter="20" style="margin-bottom: 20px;">
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">专家姓名</div>
                <div class="history-stat-value">
                  {{ currentExpertInfo.expertname || "-" }}
                </div>
              </div>
            </el-col>
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">专家编号</div>
                <div class="history-stat-value">
                  {{ currentExpertInfo.expertNo || "-" }}
                </div>
              </div>
            </el-col>
          </el-row>
          <el-divider></el-divider>
          <el-row :gutter="20">
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">总审批数量</div>
                <div
                  class="history-stat-value"
                  style="font-size: 24px; color: #409EFF;"
                >
                  {{ expertHistoryData.count || 0 }}
                </div>
              </div>
            </el-col>
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">已接收数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.acceptCount || 0 }}
                </div>
              </div>
            </el-col>
          </el-row>
          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">未接收数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.notAcceptCount || 0 }}
                </div>
              </div>
            </el-col>
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">有意见数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.opinionCount || 0 }}
                </div>
              </div>
            </el-col>
          </el-row>
          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">无意见数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.notOpinionCount || 0 }}
                </div>
              </div>
            </el-col>
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">有附件数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.annexCount || 0 }}
                </div>
              </div>
            </el-col>
          </el-row>
          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="12">
              <div class="history-stat-item">
                <div class="history-stat-label">无附件数量</div>
                <div class="history-stat-value">
                  {{ expertHistoryData.notAnnexCount || 0 }}
                </div>
              </div>
            </el-col>
          </el-row>
        </div>
        <div v-else style="text-align: center; padding: 40px 0;">
          <i
            class="el-icon-info"
            style="font-size: 60px; color: #C0C4CC; margin-bottom: 20px;"
          ></i>
          <p style="color: #909399; font-size: 14px;">暂无历史审批数据</p>
        </div>
      </div>
      <div slot="footer">
        <el-button @click="expertHistoryDialogVisible = false">关闭</el-button>
      </div>
    </el-dialog>
@@ -494,8 +780,10 @@
  reviewinitiateBaseInfoList,
  ethicalreviewedit,
  ethicalreviewadd,
  ethicalreviewInfo
  ethicalreviewInfo,
  ethicalreExpertTotal
} from "@/api/businessApi";
import { listExternalperson } from "@/api/project/externalperson";
import CaseBasicInfo from "@/components/CaseBasicInfo";
import UploadAttachment from "@/components/UploadAttachment";
import FilePreviewDialog from "@/components/FilePreviewDialog";
@@ -504,7 +792,7 @@
export default {
  name: "EthicsReviewDetail",
  components: { CaseBasicInfo, UploadAttachment, FilePreviewDialog },
  dicts: ["sys_user_sex", "sys_ethical"],
  dicts: ["sys_user_sex", "sys_ethical", "Review_status"],
  data() {
    return {
@@ -526,7 +814,7 @@
        initiatePerson: "",
        // 状态和时间
        status: "0", // 0:新建, 1:审查中, 2:结束
        status: "0", // 0:待审查, 1:审查中, 2:审查中止, 3:审查完成
        startTime: "",
        cutOffTime: "",
        endTime: "",
@@ -534,7 +822,7 @@
        // 专家信息
        expertName: "",
        expertNo: "",
        expertType: "normal",
        expertType: "0",
        expertConclusion: "",
        expertOpinion: "",
        expertTime: "",
@@ -547,6 +835,9 @@
        annexfilesList: [],
        filePatch: "",
        // 专家审查意见列表
        ethicalreviewopinionsList: [],
        // 系统字段
        createBy: "",
        createTime: "",
@@ -554,6 +845,7 @@
        updateTime: "",
        delFlag: "0"
      },
      // 表单验证规则
      rules: {
        initiateTheme: [
@@ -571,12 +863,6 @@
        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" }
        ],
@@ -590,8 +876,13 @@
          { max: 500, message: "长度不能超过 500 个字符", trigger: "blur" }
        ]
      },
      // 保存加载状态
      saveLoading: false,
      completeLoading: false,
      suspendLoading: false,
      endLoading: false,
      sending: false,
      // 附件相关
      attachmentFileList: [],
@@ -601,305 +892,175 @@
      currentPreviewFile: null,
      // 专家审查数据
      expertReviews: [
        // 专家(18位)- 初始状态为申请中
        {
          id: 1,
          expertName: "陶昊",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 2,
          expertName: "刘斌",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 3,
          expertName: "于海初 ",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 4,
          expertName: "王红梅",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 5,
          expertName: "王春光",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 6,
          expertName: "王静",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 7,
          expertName: "边文超",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 8,
          expertName: "闫志勇",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 9,
          expertName: "许凤",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 10,
          expertName: "许传屾",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 11,
          expertName: "张红岩",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 12,
          expertName: "杨苏民",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 13,
          expertName: "宋玉强",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 14,
          expertName: "周传利",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 15,
          expertName: "荆凡波",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 16,
          expertName: "矫文捷",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 17,
          expertName: "董震",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        {
          id: 18,
          expertName: "蔡金贞",
          isChief: false,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        },
        // 主委专家(1位)
        {
          id: 19,
          expertName: "孔心涓",
          isChief: true,
          reviewStatus: "applying",
          expertConclusion: "",
          expertOpinion: "",
          reviewTime: "",
          sendTime: ""
        }
      ],
      expertReviews: [],
      expertLoading: false,
      attachmentLoading: false,
      // 添加专家对话框
      expertDialogVisible: false,
      expertList: [],
      expertListLoading: false,
      expertSearchQuery: "",
      filterExpertType: "",
      expertPage: {
        pageNum: 1,
        pageSize: 50
      },
      expertTotal: 0,
      selectedExperts: [],
      // 发送对话框
      sendDialogVisible: false,
      sendForm: {
        expertType: "normal",
        expertIds: [],
        startTime: "",
        endTime: "",
        sendType: "0",
        content: ""
      },
      // 可用专家列表
      availableExperts: [
        { 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" }
      ]
      // 专家历史审批情况
      expertHistoryDialogVisible: false,
      expertHistoryLoading: false,
      expertHistoryData: null,
      currentExpertInfo: {},
      // 内部状态跟踪
      internalExpertList: []
    };
  },
  computed: {
    // 计算属性:专家同意数量
    approvedNormalExperts() {
      return this.expertReviews.filter(
        expert => !expert.isChief && expert.expertConclusion === "approved"
    // 计算属性:获取专家列表(确保响应式)
    ethicalreviewopinionsList() {
      return this.form.ethicalreviewopinionsList || [];
    },
    // 计算属性:普通专家数量
    normalExpertsCount() {
      return this.ethicalreviewopinionsList.filter(
        expert => expert.expertType === "0"
      ).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"
    // 计算属性:主委专家数量
    chiefExpertsCount() {
      return this.ethicalreviewopinionsList.filter(
        expert => expert.expertType === "1"
      ).length;
      return totalExperts > 0
        ? Math.round((completedExperts / totalExperts) * 100)
        : 0;
    },
    // 计算属性:总专家数量
    totalExpertsCount() {
      return this.ethicalreviewopinionsList.length;
    },
    // 计算属性:已同意专家数量
    approvedExpertsCount() {
      return this.ethicalreviewopinionsList.filter(
        expert => expert.expertconclusion === "1"
      ).length;
    },
    // 计算属性:总体结论
    overallConclusionText() {
      if (this.approvedNormalExperts >= 12) {
      const total = this.totalExpertsCount;
      const approved = this.approvedExpertsCount;
      if (total === 0) return "未审查";
      if (approved >= Math.ceil(total * 0.7)) {
        // 超过70%同意
        return "通过";
      } else if (this.approvedNormalExperts >= 9) {
      } else if (approved >= Math.ceil(total * 0.5)) {
        // 超过50%同意
        return "修改后通过";
      } else {
        return "不通过";
      }
    },
    overallConclusionFilter() {
      if (this.approvedNormalExperts >= 12) {
      const total = this.totalExpertsCount;
      const approved = this.approvedExpertsCount;
      if (total === 0) return "info";
      if (approved >= Math.ceil(total * 0.7)) {
        return "success";
      } else if (this.approvedNormalExperts >= 9) {
      } else if (approved >= Math.ceil(total * 0.5)) {
        return "warning";
      } else {
        return "danger";
      }
    },
    // 是否可以发送给专家
    // 可发送的普通专家
    availableNormalExperts() {
      return this.ethicalreviewopinionsList.filter(
        expert =>
          expert.expertType === "0" &&
          (!expert.receiveStatus ||
            expert.receiveStatus === "0" ||
            expert.receiveStatus === "1")
      );
    },
    // 可发送的主委专家
    availableChiefExperts() {
      return this.ethicalreviewopinionsList.filter(
        expert =>
          expert.expertType === "1" &&
          (!expert.receiveStatus ||
            expert.receiveStatus === "0" ||
            expert.receiveStatus === "1")
      );
    },
    // 是否可以发送给普通专家
    canSendToNormalExperts() {
      return (
        this.expertReviews.filter(
          expert => !expert.isChief && expert.reviewStatus === "applying"
        ).length > 0
      );
      return this.availableNormalExperts.length > 0;
    },
    // 是否可以发送给主委专家(需要至少12个专家同意)
    // 是否可以发送给主委专家(需要至少12个普通专家同意)
    canSendToChiefExpert() {
      return (
        this.approvedNormalExperts >= 12 &&
        this.expertReviews.filter(
          expert => expert.isChief && expert.reviewStatus === "applying"
        ).length > 0
      );
      const normalApprovedCount = this.ethicalreviewopinionsList.filter(
        expert => expert.expertType === "0" && expert.expertconclusion === "1"
      ).length;
      return this.availableChiefExperts.length > 0 && normalApprovedCount >= 12;
    },
    // 是否可以批量发送
    canBatchSend() {
      return (
        this.expertReviews.filter(expert => expert.reviewStatus === "applying")
          .length > 0
        this.availableNormalExperts.length > 0 ||
        this.availableChiefExperts.length > 0
      );
    },
    // 当前用户信息
    currentUser() {
      return JSON.parse(sessionStorage.getItem("user") || "{}");
    },
    // 发送对话框标题
    sendDialogTitle() {
      if (this.sendForm.expertType === "chief") {
        return "发送主委专家审查";
      } else if (this.sendForm.expertType === "normal") {
        return "发送普通专家审查";
      } else {
        return "发送专家审查";
      }
    }
  },
  watch: {
    // 监听表单中的专家列表变化
    "form.ethicalreviewopinionsList": {
      handler(newVal) {
        console.log("专家列表变化:", newVal);
        // 强制触发计算属性更新
        this.$forceUpdate();
      },
      deep: true
    }
  },
  created() {
@@ -940,16 +1101,25 @@
            // 解析 filePatch 字段
            this.parseFilePatch(this.form.filePatch);
            this.initAttachmentFileList();
            // 如果专家审查意见列表不存在,初始化为空数组
            if (!this.form.ethicalreviewopinionsList) {
              this.$set(this.form, "ethicalreviewopinionsList", []);
            }
          } else if (response.data && infoid) {
            this.form = response.data[0];
            // 解析 filePatch 字段
            this.parseFilePatch(this.form.filePatch);
            this.initAttachmentFileList();
          }
          console.log(this.form, "this.form ");
          this.infoid = detailData.infoid || this.infoid;
          this.caseNo = detailData.caseNo || "";
            // 如果专家审查意见列表不存在,初始化为空数组
            if (!this.form.ethicalreviewopinionsList) {
              this.$set(this.form, "ethicalreviewopinionsList", []);
            }
          }
          // 设置 expertReviews 用于表格显示
          this.expertReviews = this.form.ethicalreviewopinionsList;
          this.$message.success("数据加载成功");
        } else {
@@ -982,7 +1152,11 @@
    initAttachmentFileList() {
      if (this.form.annexfilesList && this.form.annexfilesList.length > 0) {
        this.attachmentFileList = this.form.annexfilesList.map(item => ({
          uid: item.id || Math.random().toString(36).substr(2, 9),
          uid:
            item.id ||
            Math.random()
              .toString(36)
              .substr(2, 9),
          name: item.fileName,
          url: item.path || item.fileUrl,
          status: "success"
@@ -1046,11 +1220,6 @@
    handleUploadError({ file, fileList, error }) {
      console.error("附件上传失败:", error);
      this.$message.error("文件上传失败,请重试");
    },
    // 打开上传对话框
    openUploadDialog() {
      this.$refs.uploadAttachment.openUpload();
    },
    // 文件预览
@@ -1129,53 +1298,80 @@
      }
    },
    // 获取专家审查列表
    getExpertReviews(ethicsReviewId) {
      this.expertLoading = true;
      setTimeout(() => {
        this.expertLoading = false;
      }, 500);
    // 判断是否为主任委员
    getIsChiefExpert(expert) {
      // 职称包含"主任委员"或者expertType为"1"
      return (
        (expert.title && expert.title.includes("主任委员")) ||
        expert.expertType === "1"
      );
    },
    // 专家行样式
    getExpertRowClassName({ row }) {
      return row.isChief ? "chief-expert-row" : "normal-expert-row";
    // 专家类型文本转换
    getExpertTypeText(type) {
      return type === "1" ? "主委专家" : "普通专家";
    },
    // 状态过滤器
    statusFilter(status) {
    // 审查状态过滤器
    getReviewStatusFilter(status) {
      const statusMap = {
        applying: "info",
        submitted: "success"
        "0": "info", // 待接收
        "1": "warning", // 未接收
        "2": "success", // 已接收
        "3": "danger", // 超时
        "4": "danger", // 中止
        "5": "success" // 完成
      };
      return statusMap[status] || "info";
    },
    statusTextFilter(status) {
    getReviewStatusText(status) {
      const statusMap = {
        applying: "申请中",
        submitted: "已提交"
        "0": "待接收",
        "1": "未接收",
        "2": "已接收",
        "3": "超时",
        "4": "中止",
        "5": "完成"
      };
      return statusMap[status] || "未知";
    },
    // 结论过滤器
    conclusionFilter(conclusion) {
    getConclusionFilter(conclusion) {
      const conclusionMap = {
        approved: "success",
        approved_with_modifications: "warning",
        disapproved: "danger"
        "1": "success", // 同意
        "2": "warning", // 审查中
        "0": "danger" // 不同意
      };
      return conclusionMap[conclusion] || "info";
    },
    conclusionTextFilter(conclusion) {
    getConclusionText(conclusion) {
      const conclusionMap = {
        approved: "同意",
        approved_with_modifications: "修改后同意",
        disapproved: "不同意"
        "1": "同意",
        "2": "审查中",
        "0": "不同意"
      };
      return conclusionMap[conclusion] || "未知";
    },
    // 专家行样式
    getExpertRowClassName({ row }) {
      return row.expertType === "1" ? "chief-expert-row" : "normal-expert-row";
    },
    // 获取专家唯一标识
    getExpertKey(expert) {
      return expert.id || expert.expertNo || expert.expertname;
    },
    // 专家类型变更处理
    handleExpertTypeChange() {
      if (this.sendForm.expertType === "chief") {
        // 主委专家无需设置截止时间
        this.sendForm.endTime = "";
      }
    },
    // 保存信息
@@ -1223,6 +1419,98 @@
      });
    },
    // 审查完成
    async handleCompleteReview() {
      this.$confirm("确定要将本次伦理审查状态设为完成吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(async () => {
          this.completeLoading = true;
          try {
            const updateData = {
              ...this.form,
              status: "3", // 审查完成
              endTime: new Date()
                .toISOString()
                .replace("T", " ")
                .substring(0, 19)
            };
            const response = await ethicalreviewedit(updateData);
            if (response.code === 200) {
              this.$message.success("审查状态已更新为完成");
              this.form.status = "3";
              this.form.endTime = updateData.endTime;
            } else {
              this.$message.error("操作失败:" + (response.msg || "未知错误"));
            }
          } catch (error) {
            console.error("更新审查状态失败:", error);
            this.$message.error("更新审查状态失败");
          } finally {
            this.completeLoading = false;
          }
        })
        .catch(() => {});
    },
    // 审查中止
    async handleSuspendReview() {
      this.$confirm(
        "确定要中止本次伦理审查吗?所有专家的审查状态将变为中止。",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(async () => {
          this.suspendLoading = true;
          try {
            // 更新所有专家的接收状态为中止
            if (
              this.form.ethicalreviewopinionsList &&
              this.form.ethicalreviewopinionsList.length > 0
            ) {
              this.form.ethicalreviewopinionsList.forEach(expert => {
                expert.receiveStatus = "4"; // 中止状态
                expert.updateTime = new Date()
                  .toISOString()
                  .replace("T", " ")
                  .substring(0, 19);
              });
            }
            const updateData = {
              ...this.form,
              status: "2" // 审查中止
            };
            const response = await ethicalreviewedit(updateData);
            if (response.code === 200) {
              this.$message.success("审查已中止,所有专家状态已更新");
              this.form.status = "2";
              // 触发计算属性更新
              this.$forceUpdate();
            } else {
              this.$message.error("操作失败:" + (response.msg || "未知错误"));
            }
          } catch (error) {
            console.error("中止审查失败:", error);
            this.$message.error("中止审查失败");
          } finally {
            this.suspendLoading = false;
          }
        })
        .catch(() => {});
    },
    // 结束审查
    async handleEndReview() {
      this.$confirm(
@@ -1235,10 +1523,11 @@
        }
      )
        .then(async () => {
          this.endLoading = true;
          try {
            const updateData = {
              ...this.form,
              status: "2",
              status: "2", // 审查中止
              endTime: new Date()
                .toISOString()
                .replace("T", " ")
@@ -1257,78 +1546,292 @@
          } catch (error) {
            console.error("结束审查失败:", error);
            this.$message.error("结束审查失败");
          } finally {
            this.endLoading = false;
          }
        })
        .catch(() => {});
    },
    // 发送给专家
    handleSendToNormalExperts() {
      const normalExperts = this.expertReviews.filter(
        expert => !expert.isChief && expert.reviewStatus === "applying"
    // 打开添加专家对话框
    handleAddExpert() {
      this.expertDialogVisible = true;
      this.loadExperts();
    },
    // 加载专家列表
    async loadExperts() {
      try {
        this.expertListLoading = true;
        const params = {
          usertype: "伦理专家", // 伦理专家
          pageNum: this.expertPage.pageNum,
          pageSize: this.expertPage.pageSize
        };
        if (this.expertSearchQuery) {
          params.username = this.expertSearchQuery;
        }
        const response = await listExternalperson(params);
        if (response.code === 200) {
          this.expertList = response.rows;
          this.expertTotal = response.total;
        } else {
          this.$message.error(
            "加载专家列表失败:" + (response.msg || "未知错误")
          );
        }
      } catch (error) {
        console.error("加载专家列表失败:", error);
        this.$message.error("加载专家列表失败");
      } finally {
        this.expertListLoading = false;
      }
    },
    // 搜索专家
    handleSearchExperts() {
      this.expertPage.pageNum = 1;
      this.loadExperts();
    },
    // 重置搜索
    handleResetSearch() {
      this.expertSearchQuery = "";
      this.filterExpertType = "";
      this.expertPage.pageNum = 1;
      this.loadExperts();
    },
    // 专家选择变化
    handleExpertSelectionChange(selection) {
      this.selectedExperts = selection;
    },
    // 确认添加专家
    handleConfirmAddExpert() {
      if (this.selectedExperts.length === 0) {
        this.$message.warning("请选择要添加的专家");
        return;
      }
      // 确保ethicalreviewopinionsList存在
      if (!this.form.ethicalreviewopinionsList) {
        this.$set(this.form, "ethicalreviewopinionsList", []);
      }
      // 过滤已存在的专家
      const existingExpertIds = this.form.ethicalreviewopinionsList.map(
        expert => expert.expertNo || expert.expertname
      );
      this.sendForm.expertIds = normalExperts.map(expert => expert.id);
      const newExperts = this.selectedExperts.filter(expert => {
        return !existingExpertIds.includes(expert.userno || expert.username);
      });
      if (newExperts.length === 0) {
        this.$message.warning("选择的专家已存在");
        return;
      }
      // 添加专家到列表
      newExperts.forEach(expert => {
        // 判断是否为主任委员
        const isChief = this.getIsChiefExpert(expert);
        const expertReview = {
          id: undefined,
          infoid: this.infoid,
          nitiateId: this.form.id || undefined,
          caseNo: this.form.caseNo,
          expertname: expert.username,
          expertNo: expert.userno,
          expertType: isChief ? "1" : "0", // 主任委员设置为主委专家
          deptName: expert.unitname || "",
          title: expert.title || "",
          telephone: expert.telephone || "",
          receiveStatus: "0", // 待接收
          expertconclusion: "",
          expertopinion: "",
          conclusionannex: "",
          conclusionorder: this.form.ethicalreviewopinionsList.length + 1,
          conclusiontime: "",
          startTime: "",
          endTime: "",
          sendType: "",
          createBy: this.currentUser.username || "admin",
          createTime: new Date()
            .toISOString()
            .replace("T", " ")
            .substring(0, 19),
          updateBy: this.currentUser.username || "admin",
          updateTime: new Date()
            .toISOString()
            .replace("T", " ")
            .substring(0, 19),
          delFlag: "0"
        };
        // 使用Vue.set确保响应式
        this.form.ethicalreviewopinionsList.push(expertReview);
      });
      // 触发计算属性更新
      this.$forceUpdate();
      console.log(
        "添加专家后,当前专家列表:",
        this.form.ethicalreviewopinionsList
      );
      console.log("普通专家数量:", this.normalExpertsCount);
      console.log("主委专家数量:", this.chiefExpertsCount);
      console.log("可发送普通专家:", this.availableNormalExperts);
      this.$message.success(`成功添加 ${newExperts.length} 位专家`);
      this.expertDialogVisible = false;
      this.selectedExperts = [];
    },
    // 添加专家对话框关闭
    handleExpertDialogClose() {
      this.selectedExperts = [];
      this.expertSearchQuery = "";
      this.filterExpertType = "";
      this.expertPage.pageNum = 1;
    },
    // 页码变化
    handlePageChange(pageNum) {
      this.expertPage.pageNum = pageNum;
      this.loadExperts();
    },
    // 每页条数变化
    handlePageSizeChange(pageSize) {
      this.expertPage.pageSize = pageSize;
      this.expertPage.pageNum = 1;
      this.loadExperts();
    },
    // 发送给普通专家
    handleSendToNormalExperts() {
      this.sendForm.expertIds = this.availableNormalExperts.map(expert =>
        this.getExpertKey(expert)
      );
      this.sendForm.expertType = "normal";
      this.sendForm.endTime = ""; // 重置截止时间
      this.sendDialogVisible = true;
    },
    // 发送给主委专家
    handleSendToChiefExpert() {
      const chiefExpert = this.expertReviews.find(
        expert => expert.isChief && expert.reviewStatus === "applying"
      this.sendForm.expertIds = this.availableChiefExperts.map(expert =>
        this.getExpertKey(expert)
      );
      if (chiefExpert) {
        this.sendForm.expertIds = [chiefExpert.id];
        this.sendForm.expertType = "chief";
        this.sendDialogVisible = true;
      }
      this.sendForm.expertType = "chief";
      this.sendForm.endTime = ""; // 主委专家无需截止时间
      this.sendDialogVisible = true;
    },
    // 批量发送
    handleBatchSend() {
      const applyingExperts = this.expertReviews.filter(
        expert => expert.reviewStatus === "applying"
      const allAvailableExperts = [
        ...this.availableNormalExperts,
        ...this.availableChiefExperts
      ];
      this.sendForm.expertIds = allAvailableExperts.map(expert =>
        this.getExpertKey(expert)
      );
      this.sendForm.expertIds = applyingExperts.map(expert => expert.id);
      this.sendForm.expertType = "batch";
      this.sendForm.endTime = ""; // 重置截止时间
      this.sendDialogVisible = true;
    },
    // 发送给单个专家
    handleSendToExpert(expert) {
      this.sendForm.expertIds = [expert.id];
      this.sendForm.expertType = expert.isChief ? "chief" : "normal";
      this.sendForm.expertIds = [this.getExpertKey(expert)];
      this.sendForm.expertType = expert.expertType === "1" ? "chief" : "normal";
      this.sendForm.endTime = expert.expertType === "1" ? "" : ""; // 主委专家无需截止时间
      this.sendDialogVisible = true;
    },
    // 确认发送
    handleSendConfirm() {
    async handleSendConfirm() {
      if (!this.sendForm.startTime) {
        this.$message.warning("请选择发送时间");
        return;
      }
      // 普通专家需要截止时间,主委专家不需要
      if (this.sendForm.expertType !== "chief" && !this.sendForm.endTime) {
        this.$message.warning("请选择截止时间");
        return;
      }
      if (!this.sendForm.sendType) {
        this.$message.warning("请选择发送方式");
        return;
      }
      if (this.sendForm.expertIds.length === 0) {
        this.$message.warning("请选择要发送的专家");
        return;
      }
      this.$message.success("发送成功");
      this.sendDialogVisible = false;
      this.sending = true;
      try {
        // 模拟发送过程
        await new Promise(resolve => setTimeout(resolve, 1000));
      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.expertIds.forEach(expertKey => {
          const index = this.form.ethicalreviewopinionsList.findIndex(
            expert => this.getExpertKey(expert) === expertKey
          );
          if (index !== -1) {
            this.form.ethicalreviewopinionsList[index].receiveStatus = "2"; // 已接收
            this.form.ethicalreviewopinionsList[
              index
            ].startTime = this.sendForm.startTime;
            this.form.ethicalreviewopinionsList[
              index
            ].endTime = this.sendForm.endTime;
            this.form.ethicalreviewopinionsList[
              index
            ].sendType = this.sendForm.sendType;
            this.form.ethicalreviewopinionsList[index].updateTime = new Date()
              .toISOString()
              .replace("T", " ")
              .substring(0, 19);
      this.sendForm = {
        expertType: "normal",
        expertIds: [],
        content: ""
      };
            // 使用Vue.set确保响应式
            this.$set(
              this.form.ethicalreviewopinionsList,
              index,
              this.form.ethicalreviewopinionsList[index]
            );
          }
        });
        this.$message.success("发送成功");
        this.sendDialogVisible = false;
        this.sendForm = {
          expertType: "normal",
          expertIds: [],
          startTime: "",
          endTime: "",
          sendType: "0",
          content: ""
        };
        // 触发计算属性更新
        this.$forceUpdate();
      } catch (error) {
        console.error("发送失败:", error);
        this.$message.error("发送失败,请重试");
      } finally {
        this.sending = false;
      }
    },
    // 编辑专家审查
@@ -1336,7 +1839,8 @@
      this.$prompt("请输入审查意见", "编辑专家审查", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        inputValue: expert.expertOpinion || "",
        inputValue: expert.expertopinion || "",
        inputPlaceholder: "请输入审查意见",
        inputValidator: value => {
          if (!value || value.trim() === "") {
            return "审查意见不能为空";
@@ -1345,42 +1849,134 @@
        }
      })
        .then(({ value }) => {
          const index = this.expertReviews.findIndex(e => e.id === expert.id);
          const index = this.form.ethicalreviewopinionsList.findIndex(
            e => e.id === expert.id || e.expertNo === expert.expertNo
          );
          if (index !== -1) {
            this.expertReviews[index].expertOpinion = value;
            this.form.ethicalreviewopinionsList[index].expertopinion = value;
            this.form.ethicalreviewopinionsList[index].updateTime = new Date()
              .toISOString()
              .replace("T", " ")
              .substring(0, 19);
            // 使用Vue.set确保响应式
            this.$set(
              this.form.ethicalreviewopinionsList,
              index,
              this.form.ethicalreviewopinionsList[index]
            );
            this.$message.success("审查意见已更新");
          }
        })
        .catch(() => {});
    },
    // 查看专家历史审批情况
    async handleViewExpertHistory(expert) {
      console.log(12);
      if (!expert.expertNo) {
        this.$message.warning("该专家没有编号,无法查询历史审批情况");
        return;
      }
      this.currentExpertInfo = expert;
      this.expertHistoryLoading = true;
      this.expertHistoryDialogVisible = true;
      try {
        const params = {
          expertNo: expert.expertNo
        };
        console.log(11);
        const response = await ethicalreExpertTotal(params);
        console.log(response);
        if (response) {
          this.expertHistoryData = response[0];
        } else {
          this.$message.error(
            "查询专家历史审批情况失败:" + (response.msg || "未知错误")
          );
          this.expertHistoryData = null;
        }
      } catch (error) {
        console.error("查询专家历史审批情况失败:", error);
        this.$message.error("查询专家历史审批情况失败");
        this.expertHistoryData = null;
      } finally {
        this.expertHistoryLoading = false;
      }
    },
    // 查看专家审查详情
    handleViewExpertReview(expert) {
      this.$alert(
        `
        <div>
          <p><strong>专家姓名:</strong>${expert.expertName}</p>
          <p><strong>专家类型:</strong>${
            expert.isChief ? "主委专家" : "专家"
          }</p>
          <p><strong>审查状态:</strong>${this.statusTextFilter(
            expert.reviewStatus
        <div style="line-height: 1.6;">
          <p><strong>专家姓名:</strong>${expert.expertname}</p>
          <p><strong>专家编号:</strong>${expert.expertNo || "-"}</p>
          <p><strong>专家类型:</strong>${this.getExpertTypeText(
            expert.expertType
          )}</p>
          <p><strong>科室名称:</strong>${expert.deptName || "-"}</p>
          <p><strong>职称:</strong>${expert.title || "-"}</p>
          <p><strong>联系电话:</strong>${expert.telephone || "-"}</p>
          <p><strong>审查状态:</strong>${this.getReviewStatusText(
            expert.receiveStatus
          )}</p>
          <p><strong>专家结论:</strong>${
            expert.expertConclusion
              ? this.conclusionTextFilter(expert.expertConclusion)
            expert.expertconclusion
              ? this.getConclusionText(expert.expertconclusion)
              : "未提交"
          }</p>
          <p><strong>审查意见:</strong>${expert.expertOpinion || "无"}</p>
          <p><strong>审查时间:</strong>${expert.reviewTime || "未审查"}</p>
          <p><strong>审查意见:</strong>${expert.expertopinion || "无"}</p>
          <p><strong>结论顺序:</strong>${expert.conclusionorder || "-"}</p>
          <p><strong>审查时间:</strong>${expert.conclusiontime || "未审查"}</p>
          <p><strong>发送时间:</strong>${expert.startTime || "未发送"}</p>
          <p><strong>截止时间:</strong>${expert.endTime || "-"}</p>
          <p><strong>发送方式:</strong>${
            expert.sendType
              ? expert.sendType === "0"
                ? "系统发送"
                : expert.sendType === "1"
                ? "邮件发送"
                : expert.sendType === "2"
                ? "短信发送"
                : "其他方式"
              : "-"
          }</p>
        </div>
      `,
        "专家审查详情",
        {
          dangerouslyUseHTMLString: true,
          customClass: "expert-review-detail-dialog"
          customClass: "expert-review-detail-dialog",
          showConfirmButton: false,
          showCancelButton: true,
          cancelButtonText: "关闭"
        }
      );
    },
    // 删除专家审查
    handleDeleteExpertReview(index) {
      this.$confirm("确定要删除该专家的审查记录吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.form.ethicalreviewopinionsList.splice(index, 1);
          // 触发计算属性更新
          this.$forceUpdate();
          this.$message.success("专家审查记录已删除");
        })
        .catch(() => {});
    },
    // 时间格式化
@@ -1403,8 +1999,6 @@
  }
};
</script>
<style scoped>
.ethics-review-detail {
@@ -1516,6 +2110,40 @@
.sent-button {
  color: #67c23a !important;
}
/* 专家姓名链接样式 */
.expert-name-link {
  color: #409eff;
  cursor: pointer;
  text-decoration: none;
  transition: color 0.3s;
}
.expert-name-link:hover {
  color: #66b1ff;
  text-decoration: underline;
}
/* 历史统计样式 */
.history-stat-item {
  padding: 10px;
  border-radius: 4px;
  background-color: #f5f7fa;
  text-align: center;
}
.history-stat-label {
  font-size: 12px;
  color: #909399;
  margin-bottom: 5px;
}
.history-stat-value {
  font-size: 18px;
  font-weight: bold;
  color: #303133;
}
.form-section {
  margin-bottom: 16px;
}
@@ -1576,6 +2204,7 @@
.case-info-card {
  border-left: 4px solid #67c23a;
}
/* 响应式设计 */
@media (max-width: 768px) {
  .ethics-review-detail {