From 4d9da000fbe74d344e0e4580b138e79d4ad98ede Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期一, 01 六月 2026 11:07:14 +0800
Subject: [PATCH] 维护
---
pages/ethicalReview/index.vue | 866 +++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 624 insertions(+), 242 deletions(-)
diff --git a/pages/ethicalReview/index.vue b/pages/ethicalReview/index.vue
index ecc7182..139dc6f 100644
--- a/pages/ethicalReview/index.vue
+++ b/pages/ethicalReview/index.vue
@@ -3,22 +3,22 @@
<!-- 缁熻鍗$墖 -->
<view class="stats-card">
<view class="stat-item">
- <text class="count">{{ stats.totalReviews }}</text>
+ <text class="count">{{ stats.count }}</text>
<text class="label">鎬诲鏌ラ噺</text>
</view>
<view class="divider"></view>
<view class="stat-item">
- <text class="count">{{ stats.approvedReviews }}</text>
+ <text class="count">{{ stats.throughCount }}</text>
<text class="label">瀹℃煡閫氳繃</text>
</view>
<view class="divider"></view>
<view class="stat-item">
- <text class="count">{{ stats.rejectedReviews }}</text>
+ <text class="count">{{ stats.rejectCount }}</text>
<text class="label">瀹℃煡椹冲洖</text>
</view>
<view class="divider"></view>
<view class="stat-item">
- <text class="count">{{ stats.abandonedReviews }}</text>
+ <text class="count">{{ stats.waiveCount }}</text>
<text class="label">宸叉斁寮�</text>
</view>
</view>
@@ -26,16 +26,16 @@
<!-- 绛涢�夋爮 -->
<view class="filter-bar">
<view class="status-filter">
- <text
- v-for="status in statusOptions"
+ <text
+ v-for="status in statusOptions"
:key="status.value"
- :class="{ active: currentStatus === status.value }"
+ :class="{ active: currentStatus == status.value }"
@tap="selectStatus(status.value)"
>
{{ status.label }}
</text>
</view>
-
+
<view class="search-filter">
<u-input
v-model="searchKeyword"
@@ -48,17 +48,17 @@
</view>
<!-- 瀹℃煡璁板綍鍒楄〃 -->
- <scroll-view
- scroll-y
+ <scroll-view
+ scroll-y
class="review-list"
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onLoadMore"
>
- <view
- v-for="(review, index) in filteredReviews"
- :key="review.id"
+ <view
+ v-for="(review, index) in reviewList"
+ :key="review.id || index"
class="review-item card"
@tap="viewDetail(review)"
>
@@ -69,13 +69,17 @@
<u-icon name="order" size="16" color="#fff" />
</view>
<view class="info-content">
- <text class="donor-name">{{ review.donorName }}</text>
- <text class="hospital-no">{{ review.hospitalNo }}</text>
- <text class="expert-type" v-if="review.expertType">{{ review.expertType }}</text>
+ <text class="donor-name">{{ review.name || "鏈~鍐欏鍚�" }}</text>
+ <text class="hospital-no">{{
+ review.inpatientno || "鏃犱綇闄㈠彿"
+ }}</text>
+ <text class="expert-type" v-if="review.expertname">
+ 涓撳: {{ review.expertname }}
+ </text>
</view>
</view>
- <view class="status-tag" :class="review.status">
- {{ getStatusText(review.status) }}
+ <view class="status-tag" :class="getReviewStatusClass(review)">
+ {{ getReviewStatusText(review) }}
</view>
</view>
@@ -84,77 +88,91 @@
<view class="info-row">
<view class="info-col">
<text class="info-label">鎬у埆/骞撮緞</text>
- <text class="info-value">{{ review.gender }}/{{ review.age }}宀�</text>
+ <text class="info-value"
+ >{{ review.sex == 1 ? "鐢�" : "濂�" }}/{{
+ getAgeWithUnit(review)
+ }}</text
+ >
</view>
<view class="info-col">
<text class="info-label">琛�鍨�</text>
- <text class="info-value">{{ review.bloodType }}</text>
+ <text class="info-value">{{
+ getDictLabel("sys_BloodType", review.bloodtype) || "鏈煡"
+ }}</text>
</view>
<view class="info-col">
<text class="info-label">鐤剧梾璇婃柇</text>
- <text class="info-value">{{ review.diagnosis }}</text>
+ <text class="info-value">{{
+ review.diagnosisname || "鏈~鍐�"
+ }}</text>
</view>
</view>
</view>
<!-- 瀹℃煡璇︽儏 -->
<view class="review-details">
- <view class="detail-item">
+ <view class="detail-item" v-if="review.createTime">
<u-icon name="clock" size="14" color="#909399" />
- <text class="detail-text">鎻愪氦鏃堕棿锛歿{ review.submitTime }}</text>
+ <text class="detail-text"
+ >鍒涘缓鏃堕棿锛歿{ formatDate(review.createTime) }}</text
+ >
</view>
- <view class="detail-item" v-if="review.reviewTime">
+ <view class="detail-item" v-if="review.conclusiontime">
<u-icon name="checkmark-circle" size="14" color="#909399" />
- <text class="detail-text">瀹℃煡鏃堕棿锛歿{ review.reviewTime }}</text>
+ <text class="detail-text"
+ >瀹℃煡鏃堕棿锛歿{ formatDate(review.conclusiontime) }}</text
+ >
</view>
- <view class="detail-item" v-if="review.reviewer">
+ <view class="detail-item" v-if="review.expertname">
<u-icon name="account" size="14" color="#909399" />
- <text class="detail-text">瀹℃煡浜猴細{{ review.reviewer }}</text>
+ <text class="detail-text">瀹℃煡浜猴細{{ review.expertname }}</text>
</view>
</view>
<!-- 瀹℃煡缁撹 -->
- <view class="conclusion-section" v-if="review.status !== 'abandoned'">
+ <view
+ class="conclusion-section"
+ v-if="review.expertconclusion && review.expertconclusion !== 2"
+ >
<text class="conclusion-label">瀹℃煡缁撹锛�</text>
- <text class="conclusion-content">{{ review.conclusion || '鏆傛棤缁撹' }}</text>
+ <text class="conclusion-content">{{
+ getConclusionText(review.expertconclusion)
+ }}</text>
</view>
- <!-- 鏀惧純鍘熷洜 -->
- <view class="abandon-reason" v-if="review.status === 'abandoned'">
- <text class="reason-label">鏀惧純鍘熷洜锛�</text>
- <text class="reason-content">{{ review.abandonReason || '鐢ㄦ埛涓诲姩鏀惧純' }}</text>
+ <!-- 涓撳鎰忚 -->
+ <view class="opinion-section" v-if="review.expertopinion">
+ <text class="opinion-label">涓撳鎰忚锛�</text>
+ <text class="opinion-content">{{ review.expertopinion }}</text>
</view>
<!-- 鎿嶄綔鎸夐挳 -->
<view class="action-buttons">
- <button
- class="action-btn detail-btn"
- @tap.stop="viewDetail(review)"
- >
+ <button class="action-btn detail-btn" @tap.stop="viewDetail(review)">
<u-icon name="eye" size="14" color="#747CF9" />
<text>鏌ョ湅璇︽儏</text>
</button>
-
- <button
- v-if="review.status === 'approved'"
+
+ <button
+ v-if="review.expertconclusion == 1"
class="action-btn download-btn"
@tap.stop="downloadReport(review)"
>
<u-icon name="download" size="14" color="#52c41a" />
<text>涓嬭浇鎶ュ憡</text>
</button>
-
- <button
- v-if="review.status === 'rejected'"
+
+ <button
+ v-if="review.expertconclusion == 2"
class="action-btn appeal-btn"
@tap.stop="submitAppeal(review)"
>
<u-icon name="arrow-up" size="14" color="#fa8c16" />
<text>鎻愯捣鐢宠瘔</text>
</button>
-
- <button
- v-if="review.status === 'abandoned'"
+
+ <button
+ v-if="review.expertconclusion == 2 || review.expertconclusion == 3"
class="action-btn restart-btn"
@tap.stop="restartReview(review)"
>
@@ -165,15 +183,11 @@
</view>
<!-- 鍔犺浇鐘舵�� -->
- <!-- <view class="load-more" v-if="hasMore">
- <u-loading size="24" color="#747CF9"></u-loading>
- <text>鍔犺浇鏇村...</text>
- </view> -->
- <u-loading-icon :show="hasMore" text="鎻愪氦涓�..."></u-loading-icon>
-
+ <u-loading-icon :show="loading" text="鍔犺浇涓�..."></u-loading-icon>
<!-- 绌虹姸鎬� -->
- <view class="empty-state" v-if="!loading && filteredReviews.length === 0">
+ <view class="empty-state" v-if="!loading && reviewList.length == 0">
+ <view> {{ loading }}-{{ reviewList.length }} </view>
<u-icon name="file-remove" size="80" color="#C0C4CC" />
<text class="empty-text">鏆傛棤瀹℃煡璁板綍</text>
<text class="empty-desc">褰撳墠绛涢�夋潯浠朵笅娌℃湁鎵惧埌鐩稿叧璁板綍</text>
@@ -181,214 +195,523 @@
<text>閲嶇疆绛涢�夋潯浠�</text>
</button>
</view>
+
+ <!-- 鍔犺浇瀹屾垚鎻愮ず -->
+ <view class="load-complete" v-if="!hasMore && reviewList.length > 0">
+ <text>宸插姞杞藉叏閮ㄦ暟鎹�</text>
+ </view>
</scroll-view>
</view>
</template>
<script setup>
-import { ref, computed, onMounted } from 'vue'
-import { onLoad, onShow } from '@dcloudio/uni-app'
+import { ref, computed, onMounted, watch } from "vue";
+import {
+ onLoad,
+ onShow,
+ onPullDownRefresh,
+ onReachBottom,
+} from "@dcloudio/uni-app";
+import { useDict } from "@/utils/dict";
// 鍝嶅簲寮忔暟鎹�
-const loading = ref(false)
-const refreshing = ref(false)
-const hasMore = ref(true)
-const pageNum = ref(1)
-const pageSize = ref(10)
+const loading = ref(false);
+const refreshing = ref(false);
+const hasMore = ref(true);
+const pageNum = ref(1);
+const pageSize = ref(10);
+const dict = ref({});
// 绛涢�夋潯浠�
-const currentStatus = ref('all')
-const searchKeyword = ref('')
+const currentStatus = ref("all");
+const searchKeyword = ref("");
// 缁熻鏁版嵁
const stats = ref({
- totalReviews: 0,
- approvedReviews: 0,
- rejectedReviews: 0,
- abandonedReviews: 0
-})
+ count: 0,
+ throughCount: 0,
+ rejectCount: 0,
+ waiveCount: 0,
+});
-// 鐘舵�侀�夐」 - 鏍规嵁鎮ㄧ殑瑕佹眰璁剧疆
+// 瀹℃煡鍒楄〃鏁版嵁
+const reviewList = ref([]);
+const total = ref(0);
+
+// 鐘舵�侀�夐」
const statusOptions = ref([
- { label: '鍏ㄩ儴', value: 'all' },
- { label: '瀹℃煡閫氳繃', value: 'approved' },
- { label: '瀹℃煡椹冲洖', value: 'rejected' },
- { label: '鏀惧純', value: 'abandoned' }
-])
+ { label: "鍏ㄩ儴", value: "all" },
+ { label: "寰呭鏌�", value: "pending" },
+ { label: "瀹℃煡閫氳繃", value: "approved" },
+ { label: "瀹℃煡椹冲洖", value: "rejected" },
+ { label: "宸叉斁寮�", value: "abandoned" },
+]);
-// 妯℃嫙鏁版嵁
-const reviews = ref([
- {
- id: 1,
- hospitalNo: 'D230415',
- donorName: '寮犳煇鏌�',
- gender: '鐢�',
- age: 45,
- bloodType: 'A鍨�',
- diagnosis: '缁堟湯鏈熻倽鐥�',
- status: 'approved',
- expertType: '涓诲涓撳',
- submitTime: '2025-12-01 10:30',
- reviewTime: '2025-12-02 14:20',
- reviewer: '瀛斿績娑�',
- conclusion: '绗﹀悎浼︾悊瑕佹眰锛屽悓鎰忓紑灞曞櫒瀹樻崘鐚伐浣�'
- },
- {
- id: 2,
- hospitalNo: 'D230416',
- donorName: '鏉庢煇鏌�',
- gender: '濂�',
- age: 38,
- bloodType: 'O鍨�',
- diagnosis: '缁堟湯鏈熻偩鐥�',
- status: 'rejected',
- expertType: '涓撳',
- submitTime: '2025-12-01 14:20',
- reviewTime: '2025-12-03 09:15',
- reviewer: '闄舵槉',
- conclusion: '椋庨櫓璇勪及涓嶈冻锛岄渶瑕佽ˉ鍏呮潗鏂欏悗閲嶆柊瀹℃煡'
- },
- {
- id: 3,
- hospitalNo: 'D230417',
- donorName: '鐜嬫煇鏌�',
- gender: '鐢�',
- age: 52,
- bloodType: 'B鍨�',
- diagnosis: '缁堟湯鏈熷績鑴忕梾',
- status: 'abandoned',
- expertType: '涓撳',
- submitTime: '2025-11-30 16:45',
- abandonReason: '瀹跺睘瑕佹眰鍋滄瀹℃煡娴佺▼',
- reviewer: '鍒樻枌'
- },
- {
- id: 4,
- hospitalNo: 'D230418',
- donorName: '璧垫煇鏌�',
- gender: '濂�',
- age: 29,
- bloodType: 'AB鍨�',
- diagnosis: '鎬ユ�ц倽鍔熻兘琛扮',
- status: 'approved',
- expertType: '涓诲涓撳',
- submitTime: '2025-12-02 08:15',
- reviewTime: '2025-12-03 16:30',
- reviewer: '瀛斿績娑�',
- conclusion: '绱ф�ユ儏鍐靛鐞嗗緱褰擄紝鍚屾剰绔嬪嵆寮�灞曟崘鐚▼搴�'
- }
-])
+// 瀛楀吀鏄犲皠
+const statusDict = {
+ pending: "寰呭鏌�",
+ approved: "瀹℃煡閫氳繃",
+ rejected: "瀹℃煡椹冲洖",
+ abandoned: "宸叉斁寮�",
+};
-// 璁$畻灞炴��
-const filteredReviews = computed(() => {
- let result = reviews.value
+// 缁撹鏄犲皠
+const conclusionDict = {
+ 0: "鏈鏍�",
+ 1: "瀹℃煡閫氳繃",
+ 2: "瀹℃煡椹冲洖",
+ 3: "鏀惧純",
+ 4: "淇敼鍚庡悓鎰�",
+};
- // 鐘舵�佺瓫閫�
- if (currentStatus.value !== 'all') {
- result = result.filter(review => review.status === currentStatus.value)
- }
+// 鑾峰彇瀛楀吀鏍囩
+const getDictLabel = (dictType, dictValue) => {
+ if (!dict.value[dictType] || !dictValue) return "";
+ const dictItem = dict.value[dictType].find(
+ (item) => item.dictValue == String(dictValue),
+ );
+ return dictItem ? dictItem.dictLabel : dictValue;
+};
- // 鍏抽敭璇嶆悳绱�
- if (searchKeyword.value) {
- const keyword = searchKeyword.value.toLowerCase()
- result = result.filter(review =>
- review.donorName.toLowerCase().includes(keyword) ||
- review.hospitalNo.toLowerCase().includes(keyword) ||
- review.diagnosis.toLowerCase().includes(keyword) ||
- (review.reviewer && review.reviewer.toLowerCase().includes(keyword))
- )
- }
+// 鑾峰彇骞撮緞鍜屽崟浣�
+const getAgeWithUnit = (review) => {
+ if (!review.age) return "鏈煡";
+ const unit = getDictLabel("sys_AgeUnit", review.ageunit) || "宀�";
+ return `${review.age}${unit}`;
+};
- return result
-})
+// 鏍煎紡鍖栨棩鏈�
+const formatDate = (dateString) => {
+ if (!dateString) return "";
+ const date = new Date(dateString);
+ 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")}`;
+};
+
+// 鑾峰彇瀹℃煡鐘舵�佹枃鏈�
+const getReviewStatusText = (review) => {
+ if (review.receiveStatus == 0) return "寰呮帹閫�";
+ if (review.receiveStatus == 1) return "鏈槄璇�";
+ if (review.receiveStatus == 2) return "宸查槄璇�";
+ if (review.receiveStatus == 3) return "瓒呮椂";
+ if (review.receiveStatus == 4) return "涓";
+ if (review.receiveStatus == 5) return "瀹屾垚";
+ if (!review.receiveStatus && review.receiveStatus !== 0) return "寰呮帹閫�";
+ return "寰呮帹閫�";
+};
+
+// 鑾峰彇瀹℃煡鐘舵�佺被鍚�
+const getReviewStatusClass = (review) => {
+ if (review.receiveStatus == 0) return "abandoned";
+ if (review.receiveStatus == 1) return "abandoned";
+ if (review.receiveStatus == 2) return "pending";
+ if (review.receiveStatus == 3) return "unknown";
+ if (review.receiveStatus == 4) return "unknown";
+ if (review.receiveStatus == 5) return "approved";
+ if (!review.receiveStatus && review.receiveStatus !== 0) return "pending";
+ return "unknown";
+};
+
+// 鑾峰彇缁撹鏂囨湰
+const getConclusionText = (conclusion) => {
+ return conclusionDict[conclusion] || "鏈煡缁撹";
+};
// 鏂规硶
-const getStatusText = (status) => {
- const statusMap = {
- approved: '瀹℃煡閫氳繃',
- rejected: '瀹℃煡椹冲洖',
- abandoned: '宸叉斁寮�'
- }
- return statusMap[status] || '鏈煡鐘舵��'
-}
-
const selectStatus = (status) => {
- currentStatus.value = status
-}
+ currentStatus.value = status;
+ resetAndLoad();
+};
const handleSearch = () => {
- console.log('鎼滅储鍏抽敭璇�:', searchKeyword.value)
-}
+ resetAndLoad();
+};
const resetFilters = () => {
- currentStatus.value = 'all'
- searchKeyword.value = ''
-}
+ currentStatus.value = "all";
+ searchKeyword.value = "";
+ resetAndLoad();
+};
+// 鏋勫缓鏌ヨ鍙傛暟
+const buildQueryParams = () => {
+ const params = {
+ pageNum: pageNum.value,
+ pageSize: pageSize.value,
+ // receiveStatus: "1,2,3,4,5",
+ };
+
+ // 娣诲姞鎼滅储鍏抽敭璇�
+ if (searchKeyword.value) {
+ params.name = searchKeyword.value;
+ }
+
+ // 娣诲姞鐘舵�佺瓫閫�
+ if (currentStatus.value !== "all") {
+ switch (currentStatus.value) {
+ case "pending":
+ // 寰呭鏌ワ細expertconclusion涓虹┖
+ params.expertconclusion = null;
+ break;
+ case "approved":
+ params.expertconclusion = 1; // 鍚屾剰
+ break;
+ case "rejected":
+ params.expertconclusion = 2; // 涓嶅悓鎰�
+ break;
+ case "abandoned":
+ params.expertconclusion = 3; // 鏀惧純
+ break;
+ }
+ }
+
+ return params;
+};
+
+// 閲嶇疆骞跺姞杞�
+const resetAndLoad = () => {
+ pageNum.value = 1;
+ hasMore.value = true;
+ loadCaseData();
+};
+
+// 涓嬫媺鍒锋柊
const onRefresh = async () => {
- refreshing.value = true
- setTimeout(() => {
- refreshing.value = false
- loadInitialData()
- }, 1000)
-}
+ refreshing.value = true;
+ await resetAndLoad();
+ refreshing.value = false;
+};
+// 涓婃媺鍔犺浇鏇村
const onLoadMore = async () => {
- if (!hasMore.value || loading.value) return
- loading.value = true
- setTimeout(() => {
- loading.value = false
- }, 500)
-}
+ if (!hasMore.value || loading.value) return;
+ pageNum.value++;
+ await loadCaseData(true);
+};
+// 缁熻
+const stateTotal = async () => {
+ const resTotal = await uni.$uapi.get(
+ `/project/ethicalreviewopinions/stateTotal`,
+ );
+ if (resTotal.code == 200)
+ // 鏇存柊缁熻鏁版嵁
+ stats.value = resTotal.data[0];
+};
+// 鍔犺浇妗堜緥鏁版嵁
+const loadCaseData = async (isLoadMore = false) => {
+ if (loading.value) return;
+
+ loading.value = true;
+
+ try {
+ const params = buildQueryParams();
+
+ const res = await uni.$uapi.get(
+ `/project/ethicalreviewopinions/listnew`,
+ params,
+ );
+
+ console.log(res, "11");
+
+ if (res.code == 200) {
+ const list = res.rows || [];
+ const totalCount = res.total || 0;
+
+ if (isLoadMore) {
+ reviewList.value = [...reviewList.value, ...list];
+ } else {
+ reviewList.value = list;
+ }
+ console.log(reviewList.value, "reviewList.value");
+
+ total.value = totalCount;
+ hasMore.value = reviewList.value.length < totalCount;
+ } else {
+ uni.showToast({
+ title: res.msg || "鍔犺浇澶辫触",
+ icon: "none",
+ });
+ }
+ } catch (error) {
+ console.error("鍔犺浇妗堜緥鏁版嵁澶辫触:", error);
+ uni.showToast({
+ title: "鏁版嵁鍔犺浇澶辫触锛岃閲嶈瘯",
+ icon: "none",
+ });
+ } finally {
+ loading.value = false;
+ uni.stopPullDownRefresh();
+ }
+};
+
+// 鏌ョ湅璇︽儏
const viewDetail = (review) => {
uni.navigateTo({
- url: `/pages/ethicalReview/ethicalInfo?id=${review.id}&status=${review.status}`
- })
-}
+ url: `/pages/ethicalReview/ethicalInfo?fcid=${
+ review.fcid
+ }&type=review&status=${review.expertconclusion || "pending"}&id=${
+ review.id
+ }`,
+ });
+};
-const downloadReport = (review) => {
- uni.showToast({
- title: '寮�濮嬩笅杞藉鏌ユ姤鍛�',
- icon: 'success'
- })
-}
+// 涓嬭浇鎶ュ憡
+const downloadReport = async (review) => {
+ if (!review.conclusionannex) {
+ uni.showToast({
+ title: "鏆傛棤鎶ュ憡鍙笅杞�",
+ icon: "none",
+ });
+ return;
+ }
+ try {
+ const annexes = review.conclusionannex
+ .split(";")
+ .filter((item) => item.trim());
+
+ if (annexes.length == 0) {
+ uni.showToast({
+ title: "鏆傛棤鎶ュ憡鍙笅杞�",
+ icon: "none",
+ });
+ return;
+ }
+
+ uni.showLoading({
+ title: "涓嬭浇涓�...",
+ mask: true,
+ });
+
+ // 涓嬭浇绗竴涓檮浠�
+ const fileUrl = annexes[0];
+ const downloadTask = uni.downloadFile({
+ url: fileUrl,
+ success: (downloadRes) => {
+ if (downloadRes.statusCode == 200) {
+ const tempFilePath = downloadRes.tempFilePath;
+
+ // 淇濆瓨鍒版湰鍦�
+ uni.saveFile({
+ tempFilePath: tempFilePath,
+ success: (saveRes) => {
+ uni.hideLoading();
+ uni.showToast({
+ title: "涓嬭浇鎴愬姛",
+ icon: "success",
+ duration: 2000,
+ });
+
+ // 鍦ㄥ井淇″皬绋嬪簭涓彲浠ユ墦寮�鏂囦欢
+ if (uni.getSystemInfoSync().platform == "weixin") {
+ uni.openDocument({
+ filePath: saveRes.savedFilePath,
+ showMenu: true,
+ success: () => {
+ console.log("鎵撳紑鏂囨。鎴愬姛");
+ },
+ fail: (err) => {
+ console.error("鎵撳紑鏂囨。澶辫触", err);
+ },
+ });
+ }
+ },
+ fail: (saveErr) => {
+ uni.hideLoading();
+ uni.showToast({
+ title: "淇濆瓨鏂囦欢澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ },
+ });
+ } else {
+ uni.hideLoading();
+ uni.showToast({
+ title: "涓嬭浇澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ }
+ },
+ fail: (err) => {
+ uni.hideLoading();
+ uni.showToast({
+ title: "涓嬭浇澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ console.error("涓嬭浇鏂囦欢澶辫触:", err);
+ },
+ });
+
+ // 鐩戝惉涓嬭浇杩涘害
+ downloadTask.onProgressUpdate((res) => {
+ console.log("涓嬭浇杩涘害:", res.progress);
+ });
+ } catch (error) {
+ uni.hideLoading();
+ console.error("涓嬭浇鎶ュ憡澶辫触:", error);
+ uni.showToast({
+ title: "涓嬭浇澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ }
+};
+
+// 鎻愯捣鐢宠瘔
const submitAppeal = (review) => {
uni.navigateTo({
- url: `/pages/ethics/appeal?id=${review.id}`
- })
-}
+ url: `/pages/ethics/appeal?id=${review.fcid || review.id}&caseNo=${
+ review.caseNo || ""
+ }&name=${review.name || ""}`,
+ });
+};
-const restartReview = (review) => {
+// 閲嶆柊寮�濮�
+const restartReview = async (review) => {
uni.showModal({
- title: '閲嶆柊寮�濮嬪鏌�',
- content: '纭畾瑕侀噸鏂板紑濮嬭繖涓鏌ユ祦绋嬪悧锛�',
- success: (res) => {
+ title: "閲嶆柊寮�濮嬪鏌�",
+ content: "纭畾瑕侀噸鏂板紑濮嬭繖涓鏌ユ祦绋嬪悧锛�",
+ success: async (res) => {
if (res.confirm) {
- uni.showToast({
- title: '瀹℃煡宸查噸鏂板紑濮�',
- icon: 'success'
- })
+ try {
+ uni.showLoading({
+ title: "澶勭悊涓�...",
+ mask: true,
+ });
+
+ const response = await uni.$uapi.put(
+ `/project/ethicalreviewopinions/reset/${review.fcid || review.id}`,
+ );
+
+ uni.hideLoading();
+
+ if (response.code == 200) {
+ uni.showToast({
+ title: "瀹℃煡宸查噸鏂板紑濮�",
+ icon: "success",
+ duration: 2000,
+ });
+
+ // 閲嶆柊鍔犺浇鏁版嵁
+ resetAndLoad();
+ } else {
+ uni.showToast({
+ title: response.msg || "鎿嶄綔澶辫触",
+ icon: "none",
+ duration: 2000,
+ });
+ }
+ } catch (error) {
+ uni.hideLoading();
+ console.error("閲嶆柊寮�濮嬪鏌ュけ璐�:", error);
+ uni.showToast({
+ title: "鎿嶄綔澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ }
}
+ },
+ });
+};
+
+// 瀵煎嚭瀹℃煡鏁版嵁
+const exportReviews = async () => {
+ try {
+ uni.showLoading({
+ title: "瀵煎嚭涓�...",
+ mask: true,
+ });
+
+ const params = buildQueryParams();
+ delete params.pageNum;
+ delete params.pageSize;
+
+ const res = await uni.$uapi.get(
+ `/project/ethicalreviewopinions/export`,
+ params,
+ );
+
+ uni.hideLoading();
+
+ if (res.code == 200) {
+ const fileUrl = res.data || res.url;
+ if (fileUrl) {
+ uni.showToast({
+ title: "瀵煎嚭鎴愬姛",
+ icon: "success",
+ duration: 2000,
+ });
+
+ // 鍦ㄦ柊绐楀彛涓墦寮�涓嬭浇閾炬帴
+ window.open(fileUrl, "_blank");
+ } else {
+ uni.showToast({
+ title: "瀵煎嚭鏂囦欢鑾峰彇澶辫触",
+ icon: "none",
+ duration: 2000,
+ });
+ }
+ } else {
+ uni.showToast({
+ title: res.msg || "瀵煎嚭澶辫触",
+ icon: "none",
+ duration: 2000,
+ });
}
- })
-}
+ } catch (error) {
+ uni.hideLoading();
+ console.error("瀵煎嚭鏁版嵁澶辫触:", error);
+ uni.showToast({
+ title: "瀵煎嚭澶辫触",
+ icon: "error",
+ duration: 2000,
+ });
+ }
+};
// 鐢熷懡鍛ㄦ湡
-onLoad(() => {
- loadInitialData()
-})
+onLoad(async () => {
+ // 鑾峰彇瀛楀吀鏁版嵁
+ dict.value = await useDict(
+ "sys_IDType",
+ "sys_user_sex",
+ "sys_Nation",
+ "sys_BloodType",
+ "sys_Infectious",
+ "sys_AgeUnit",
+ "ReviewForm_status",
+ "sys_ethical",
+ "expert_Conclusion",
+ );
-const loadInitialData = () => {
- // 璁$畻缁熻鏁版嵁
- stats.value = {
- totalReviews: reviews.value.length,
- approvedReviews: reviews.value.filter(r => r.status === 'approved').length,
- rejectedReviews: reviews.value.filter(r => r.status === 'rejected').length,
- abandonedReviews: reviews.value.filter(r => r.status === 'abandoned').length
- }
-}
+ // 鍔犺浇鏁版嵁
+ await loadCaseData();
+ await stateTotal();
+});
+
+onShow(() => {
+ // 椤甸潰鏄剧ず鏃跺埛鏂版暟鎹�
+ resetAndLoad();
+});
+
+// 鐩戝惉涓嬫媺鍒锋柊
+onPullDownRefresh(() => {
+ onRefresh();
+});
+
+// 鐩戝惉涓婃媺瑙﹀簳
+onReachBottom(() => {
+ onLoadMore();
+});
</script>
<style lang="scss" scoped>
@@ -398,7 +721,7 @@
padding: 20rpx;
.stats-card {
- background: linear-gradient(135deg, #747CF9, #9B7CF9);
+ background: linear-gradient(135deg, #747cf9, #9b7cf9);
border-radius: 16rpx;
padding: 40rpx 20rpx;
display: flex;
@@ -441,28 +764,31 @@
.status-filter {
display: flex;
margin-bottom: 20rpx;
+ flex-wrap: wrap;
text {
flex: 1;
+ // min-width: 120rpx;
text-align: center;
font-size: 26rpx;
color: #606266;
padding: 16rpx 0;
position: relative;
+ margin: 0 8rpx;
&.active {
- color: #747CF9;
+ color: #747cf9;
font-weight: 500;
&::after {
- content: '';
+ content: "";
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
- background: #747CF9;
+ background: #747cf9;
border-radius: 2rpx;
}
}
@@ -491,7 +817,7 @@
align-items: center;
.hospital-badge {
- background: linear-gradient(135deg, #747CF9, #9B7CF9);
+ background: linear-gradient(135deg, #747cf9, #9b7cf9);
width: 64rpx;
height: 64rpx;
border-radius: 12rpx;
@@ -508,20 +834,29 @@
font-weight: 600;
display: block;
margin-bottom: 4rpx;
+ max-width: 300rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
.hospital-no {
font-size: 26rpx;
color: #909399;
margin-right: 16rpx;
+ background: #f5f5f5;
+ padding: 4rpx 12rpx;
+ border-radius: 8rpx;
}
.expert-type {
font-size: 22rpx;
- color: #747CF9;
+ color: #747cf9;
background: #f0f2ff;
padding: 4rpx 12rpx;
border-radius: 12rpx;
+ margin-top: 4rpx;
+ display: inline-block;
}
}
}
@@ -531,6 +866,7 @@
border-radius: 20rpx;
font-size: 24rpx;
font-weight: 500;
+ white-space: nowrap;
&.approved {
background: #f6ffed;
@@ -545,6 +881,16 @@
&.abandoned {
background: #f5f5f5;
color: #8c8c8c;
+ }
+
+ &.pending {
+ background: #e6f7ff;
+ color: #1890ff;
+ }
+
+ &.unknown {
+ background: #f5f5f5;
+ color: #bfbfbf;
}
}
}
@@ -569,6 +915,10 @@
font-size: 26rpx;
color: #303133;
font-weight: 500;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
}
}
@@ -588,6 +938,9 @@
.detail-text {
font-size: 24rpx;
color: #606266;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
}
}
@@ -602,6 +955,7 @@
font-size: 24rpx;
color: #52c41a;
font-weight: 500;
+ margin-right: 8rpx;
}
.conclusion-content {
@@ -610,19 +964,20 @@
}
}
- .abandon-reason {
- background: #f5f5f5;
+ .opinion-section {
+ background: #e6f7ff;
border-radius: 8rpx;
padding: 20rpx;
margin-bottom: 20rpx;
- .reason-label {
+ .opinion-label {
font-size: 24rpx;
- color: #8c8c8c;
+ color: #1890ff;
font-weight: 500;
+ margin-right: 8rpx;
}
- .reason-content {
+ .opinion-content {
font-size: 24rpx;
color: #303133;
}
@@ -630,11 +985,13 @@
.action-buttons {
display: flex;
- justify-content: space-between;
+ justify-content: space-between;
gap: 16rpx;
+ flex-wrap: wrap;
.action-btn {
flex: 1;
+ min-width: 200rpx;
height: 64rpx;
border: none;
border-radius: 32rpx;
@@ -644,10 +1001,11 @@
align-items: center;
justify-content: center;
gap: 6rpx;
+ margin-bottom: 8rpx;
&.detail-btn {
background: #f5f5f5;
- color: #747CF9;
+ color: #747cf9;
}
&.download-btn {
@@ -664,21 +1022,11 @@
&.restart-btn {
background: #f0f2ff;
- color: #747CF9;
+ color: #747cf9;
border: 1rpx solid #adc6ff;
}
}
}
- }
-
- .load-more {
- text-align: center;
- padding: 32rpx;
- color: #909399;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 12rpx;
}
.empty-state {
@@ -699,13 +1047,20 @@
}
.empty-action {
- background: linear-gradient(135deg, #747CF9, #9B7CF9);
+ background: linear-gradient(135deg, #747cf9, #9b7cf9);
color: #fff;
border: none;
border-radius: 32rpx;
padding: 16rpx 32rpx;
font-size: 28rpx;
}
+ }
+
+ .load-complete {
+ text-align: center;
+ padding: 32rpx;
+ color: #909399;
+ font-size: 24rpx;
}
}
}
@@ -715,14 +1070,41 @@
.ethics-review-list {
padding: 20rpx;
+ .stats-card {
+ padding: 30rpx 15rpx;
+
+ .stat-item {
+ .count {
+ font-size: 30rpx;
+ }
+
+ .label {
+ font-size: 22rpx;
+ }
+ }
+ }
+
.review-item .basic-info .info-row {
grid-template-columns: 1fr;
gap: 16rpx;
}
+ .review-header {
+ flex-direction: column;
+ align-items: flex-start !important;
+
+ .status-tag {
+ margin-top: 16rpx;
+ }
+ }
+
.action-buttons {
flex-direction: column;
+
+ .action-btn {
+ min-width: 100% !important;
+ }
}
}
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3