From 3b7fcf5ea471f6cb388f86d0732b8ece47a3cefc Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期一, 29 十二月 2025 21:05:58 +0800
Subject: [PATCH] 页面更新
---
src/views/business/course/components/EthicalReviewStage.vue | 1607 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 1,444 insertions(+), 163 deletions(-)
diff --git a/src/views/business/course/components/EthicalReviewStage.vue b/src/views/business/course/components/EthicalReviewStage.vue
index 47e4877..a5b8476 100644
--- a/src/views/business/course/components/EthicalReviewStage.vue
+++ b/src/views/business/course/components/EthicalReviewStage.vue
@@ -1,206 +1,1487 @@
<template>
- <base-stage :stage-data="stageData" :case-info="caseInfo">
- <template #header>
- <el-alert
- title="浼︾悊瀹℃煡闃舵"
- :type="getAlertType()"
- :description="getAlertDescription()"
- show-icon
- :closable="false"
- />
- </template>
-
- <el-row :gutter="20" style="margin-top: 20px;">
- <el-col :span="12">
- <el-card>
- <div slot="header" class="card-header">
- <span>瀹℃煡濮斿憳浼氫俊鎭�</span>
- </div>
- <el-descriptions :column="1" border>
- <el-descriptions-item label="濮斿憳浼氬悕绉�">
- {{ reviewCommittee.name }}
- </el-descriptions-item>
- <el-descriptions-item label="瀹℃煡浼氳鏃堕棿">
- {{ formatTime(reviewCommittee.meetingTime) }}
- </el-descriptions-item>
- <el-descriptions-item label="鍙備細濮斿憳">
- {{ reviewCommittee.members.length }} 浜�
- </el-descriptions-item>
- <el-descriptions-item label="瀹℃煡缁撹">
- <el-tag :type="reviewCommittee.conclusion ? 'success' : 'warning'">
- {{ reviewCommittee.conclusion ? '瀹℃煡閫氳繃' : '瀹℃煡涓�' }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="涓诲腑绛惧瓧">
- {{ reviewCommittee.chairman }}
- </el-descriptions-item>
- </el-descriptions>
- </el-card>
- </el-col>
-
- <el-col :span="12">
- <el-card>
- <div slot="header" class="card-header">
- <span>瀹℃煡娴佺▼杩涘害</span>
- </div>
- <el-steps direction="vertical" :active="reviewProgress.active" space="80px">
- <el-step
- v-for="step in reviewProgress.steps"
- :key="step.title"
- :title="step.title"
- :description="step.description"
- :status="step.status"
- />
- </el-steps>
- </el-card>
- </el-col>
- </el-row>
-
- <el-card style="margin-top: 20px;">
- <div slot="header" class="card-header">
- <span>濮斿憳瀹℃煡鎰忚</span>
+ <div class="ethics-review-detail">
+ <el-card class="detail-card">
+ <!-- 鍩虹淇℃伅 -->
+ <div slot="header" class="clearfix">
+ <span class="detail-title">浼︾悊瀹℃煡鍩烘湰淇℃伅</span>
</div>
- <el-table :data="reviewComments" border>
- <el-table-column label="濮斿憳濮撳悕" prop="memberName" width="120" />
- <el-table-column label="涓撲笟棰嗗煙" prop="specialty" width="120" />
- <el-table-column label="瀹℃煡鎰忚" prop="comment" min-width="200" />
- <el-table-column label="鎶曠エ缁撴灉" width="100">
+
+ <el-form :model="form" ref="form" :rules="rules" label-width="120px">
+
+ <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">
- <el-tag :type="scope.row.vote === '鍚屾剰' ? 'success' : 'danger'">
- {{ scope.row.vote }}
- </el-tag>
+ <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="160">
+
+ <el-table-column label="鏂囦欢绫诲瀷" width="100" align="center">
<template slot-scope="scope">
- {{ formatTime(scope.row.reviewTime) }}
+ <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 style="margin-top: 20px;">
- <div slot="header" class="card-header">
- <span>瀹℃煡鍐宠鏂囦欢</span>
- <el-button type="primary" size="small" @click="handleViewResolution">
- 鏌ョ湅鍐宠鏂囦欢
- </el-button>
- </div>
- <div class="resolution-content">
- <p><strong>浼︾悊瀹℃煡鍐宠锛�</strong></p>
- <p>{{ resolutionContent }}</p>
- <el-divider />
- <div class="signature-area">
- <p>浼︾悊濮斿憳浼氫富甯細{{ reviewCommittee.chairman }}</p>
- <p>鏃ユ湡锛歿{ formatTime(reviewCommittee.meetingTime) }}</p>
+ <!-- 涓撳瀹℃煡鎯呭喌 -->
+ <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>
- </el-card>
- </base-stage>
-</template>
+ <!-- 涓撳缁熻淇℃伅 -->
+ <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="300"
+ :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="180" 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 BaseStage from './BaseStage.vue';
+import {
+ getEthicsReviewDetail,
+ updateEthicsReview,
+ sendExpertReview,
+ endEthicsReview,
+ uploadAttachment,
+ deleteAttachment,
+ getAttachments
+} from "./api/ethicsReview";
export default {
- name: 'EthicalReviewStage',
- components: { BaseStage },
- props: {
- stageData: {
- type: Object,
- default: () => ({})
- },
- caseInfo: {
- type: Object,
- default: () => ({})
- }
- },
+ name: "EthicsReviewDetail",
data() {
return {
- reviewCommittee: {
- name: '鍖婚櫌浼︾悊瀹℃煡濮斿憳浼�',
- meetingTime: '2023-12-03 15:20:00',
- members: ['寮犳暀鎺�', '鏉庝富浠�', '鐜嬪尰鐢�', '璧靛鍛�', '閽变笓瀹�'],
- conclusion: true,
- chairman: '寮犳暀鎺�'
+ // 琛ㄥ崟鏁版嵁
+ form: {
+ id: undefined,
+ hospitalNo: "",
+ donorName: "",
+ gender: "",
+ age: "",
+ diagnosis: "",
+ ethicsConclusion: "reviewing",
+ ethicsOpinion: "",
+ reviewTime: "",
+ registrant: "",
+ registrationTime: new Date()
+ .toISOString()
+ .replace("T", " ")
+ .substring(0, 19)
},
- reviewProgress: {
- active: 4,
- steps: [
- {
- title: '鏉愭枡鍒濆',
- description: '鐢宠鏉愭枡瀹屾暣鎬у鏌�',
- status: 'finish'
- },
- {
- title: '濮斿憳璇勫',
- description: '鍚勫鍛樼嫭绔嬪鏌�',
- status: 'finish'
- },
- {
- title: '浼氳璁ㄨ',
- description: '濮斿憳浼氶泦浣撹璁�',
- status: 'finish'
- },
- {
- title: '褰㈡垚鍐宠',
- description: '鎶曠エ褰㈡垚鏈�缁堝喅璁�',
- status: 'finish'
- }
+ // 琛ㄥ崟楠岃瘉瑙勫垯
+ rules: {
+ donorName: [
+ { required: true, message: "鎹愮尞鑰呭鍚嶄笉鑳戒负绌�", trigger: "blur" }
+ ],
+ ethicsConclusion: [
+ { required: true, message: "浼︾悊缁撹涓嶈兘涓虹┖", trigger: "change" }
+ ],
+ reviewTime: [
+ { required: true, message: "瀹℃煡鏃堕棿涓嶈兘涓虹┖", trigger: "change" }
]
},
- reviewComments: [
+ // 淇濆瓨鍔犺浇鐘舵��
+ saveLoading: false,
+
+ // 闄勪欢鏁版嵁
+ attachments: [],
+ expertReviews: [
+ // 涓撳锛�18浣嶏級- 鍒濆鐘舵�佷负鐢宠涓�
{
- memberName: '寮犳暀鎺�',
- specialty: '鍖诲浼︾悊',
- comment: '鎹愮尞绋嬪簭绗﹀悎浼︾悊瑙勮寖锛屽悓鎰忛�氳繃',
- vote: '鍚屾剰',
- reviewTime: '2023-12-03 14:30:00'
+ id: 1,
+ expertName: "闄舵槉",
+ isChief: false,
+ reviewStatus: "applying",
+ expertConclusion: "",
+ expertOpinion: "",
+ reviewTime: ""
},
{
- memberName: '鏉庝富浠�',
- specialty: '涓村簥鍖诲',
- comment: '鍖荤枟绋嬪簭瑙勮寖锛屾棤浼︾悊闂',
- vote: '鍚屾剰',
- reviewTime: '2023-12-03 14:45:00'
+ id: 2,
+ expertName: "鍒樻枌",
+ isChief: false,
+ reviewStatus: "applying",
+ expertConclusion: "",
+ expertOpinion: "",
+ reviewTime: ""
},
{
- memberName: '鐜嬪尰鐢�',
- specialty: '娉曞緥鍖诲',
- comment: '娉曞緥鏂囦欢榻愬叏锛岀▼搴忓悎娉�',
- vote: '鍚屾剰',
- reviewTime: '2023-12-03 15:00:00'
+ 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: "钁i渿",
+ 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: ""
}
],
- resolutionContent: '缁忎鸡鐞嗗鏌ュ鍛樹細瀹℃煡锛岃鍣ㄥ畼鎹愮尞妗堜緥绗﹀悎鍖诲浼︾悊瑕佹眰锛屾崘鐚▼搴忚鑼冿紝瀹跺睘鎰忔効鐪熷疄鏈夋晥锛屽悓鎰忚繘琛屽櫒瀹樻崘鐚��'
+ 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: {
- getAlertType() {
- const status = this.stageData.status;
- return status === 'completed' ? 'success' :
- status === 'in_progress' ? 'warning' : 'info';
+ // 鐢熸垚浣忛櫌鍙�
+ generateHospitalNo() {
+ const timestamp = Date.now().toString();
+ this.form.hospitalNo = "D" + timestamp.slice(-6);
},
- getAlertDescription() {
- const status = this.stageData.status;
- return status === 'completed' ? '浼︾悊瀹℃煡宸查�氳繃锛屽彲浠ヨ繘琛屽櫒瀹樺垎閰�' :
- status === 'in_progress' ? '浼︾悊瀹℃煡娴佺▼姝e湪杩涜涓�' : '绛夊緟寮�濮嬩鸡鐞嗗鏌ユ祦绋�';
+ getExpertRowClassName({ row }) {
+ return row.isChief ? "chief-expert-row" : "normal-expert-row";
},
- handleViewResolution() {
- this.$message.info('鏌ョ湅浼︾悊瀹℃煡鍐宠鏂囦欢鍔熻兘');
+ // 鑾峰彇璇︽儏
+ 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>
-.resolution-content {
+.ethics-review-detail {
padding: 20px;
- line-height: 1.8;
+ background-color: #f5f7fa;
}
-.signature-area {
- text-align: right;
- margin-top: 30px;
+.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>
--
Gitblit v1.9.3