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/ethicalInfo.vue | 1583 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 1,425 insertions(+), 158 deletions(-)
diff --git a/pages/ethicalReview/ethicalInfo.vue b/pages/ethicalReview/ethicalInfo.vue
index 271f2cd..954d588 100644
--- a/pages/ethicalReview/ethicalInfo.vue
+++ b/pages/ethicalReview/ethicalInfo.vue
@@ -4,32 +4,40 @@
<view class="review-overview card">
<view class="overview-header">
<text class="title">浼︾悊瀹℃煡浠诲姟</text>
- <view class="status-badge" :class="reviewStatus">
- {{ statusText }}
+ <view
+ class="status-badge"
+ :class="getStatusClass(caseInfo.receiveStatus)"
+ >
+ {{ getStatusText(caseInfo.receiveStatus) }}
</view>
</view>
-
+
<!-- 绱у噾鍨嬪熀纭�淇℃伅甯冨眬 -->
<view class="compact-info-grid">
<view class="compact-info-item">
<up-icon name="file-text" size="14" color="#909399" />
<text class="compact-label">浣忛櫌鍙�</text>
- <text class="compact-value">{{ caseInfo.hospitalNo }}</text>
+ <text class="compact-value">{{ caseInfo.inpatientno || "--" }}</text>
</view>
<view class="compact-info-item">
<up-icon name="account" size="14" color="#909399" />
<text class="compact-label">鎹愮尞鑰�</text>
- <text class="compact-value">{{ caseInfo.donorName }}</text>
+ <text class="compact-value">{{ caseInfo.name || "--" }}</text>
</view>
<view class="compact-info-item">
<up-icon name="man" size="14" color="#909399" />
<text class="compact-label">鎬у埆/骞撮緞</text>
- <text class="compact-value">{{ caseInfo.gender }}/{{ caseInfo.age }}宀�</text>
+ <text class="compact-value"
+ >{{ caseInfo.sex || "--" }}/{{ caseInfo.age || "--"
+ }}{{ caseInfo.ageunit || "宀�" }}</text
+ >
</view>
<view class="compact-info-item">
<up-icon name="heart" size="14" color="#909399" />
<text class="compact-label">鐤剧梾璇婃柇</text>
- <text class="compact-value">{{ caseInfo.diagnosis }}</text>
+ <text class="compact-value">{{
+ caseInfo.diagnosisname || "--"
+ }}</text>
</view>
</view>
</view>
@@ -42,8 +50,8 @@
</view>
<view class="compact-material-list">
- <view
- v-for="material in materials"
+ <view
+ v-for="material in materials"
:key="material.id"
class="compact-material-item"
@tap="previewMaterial(material)"
@@ -51,6 +59,9 @@
<view class="material-left">
<up-icon :name="material.icon" :color="material.color" size="18" />
<text class="file-name">{{ material.name }}</text>
+ <view v-if="material.type" class="file-meta">
+ <text class="file-type">{{ material.type || "鏂囦欢" }}</text>
+ </view>
</view>
<view class="material-right">
<text class="file-size">{{ material.size }}</text>
@@ -64,17 +75,22 @@
<view class="review-form card">
<view class="section-header">
<text class="section-title">瀹℃煡鎰忚</text>
+ <view v-if="isTimeout" class="timeout-badge">
+ <up-icon name="clock" size="16" />
+ <text>宸茶秴鏃�</text>
+ </view>
</view>
<view class="form-content">
<!-- 浣跨敤uView鍗曢�夌粍浠舵浛浠h嚜瀹氫箟瀹炵幇 -->
<view class="form-group">
<text class="form-label">瀹℃煡缁撹</text>
- <u-radio-group
- v-model="form.conclusion"
+ <u-radio-group
+ v-model="form.expertconclusion"
placement="column"
activeColor="#007aff"
@change="onConclusionChange"
+ :disabled="isReadonly"
>
<u-radio
v-for="option in conclusionOptions"
@@ -90,42 +106,14 @@
<view class="form-group">
<text class="form-label">璇︾粏鎰忚</text>
<u--textarea
- v-model="form.opinion"
+ v-model="form.expertopinion"
placeholder="璇疯緭鍏ヨ缁嗙殑瀹℃煡鎰忚鍜屾敼杩涘缓璁�..."
maxlength="1000"
count
:height="120"
border="surround"
+ :disabled="isReadonly"
></u--textarea>
- </view>
-
- <!-- 椋庨櫓璇勪及 -->
- <view class="form-group">
- <text class="form-label">椋庨櫓璇勪及</text>
- <view class="risk-assessment">
- <view class="risk-item">
- <text class="risk-label">鍙楄瘯鑰呴闄╃瓑绾�</text>
- <view class="risk-slider-compact">
- <view class="risk-levels">
- <text class="level-label" :class="{ active: form.riskLevel >= 1 }">浣�</text>
- <text class="level-label" :class="{ active: form.riskLevel >= 2 }">涓綆</text>
- <text class="level-label" :class="{ active: form.riskLevel >= 3 }">涓�</text>
- <text class="level-label" :class="{ active: form.riskLevel >= 4 }">涓珮</text>
- <text class="level-label" :class="{ active: form.riskLevel >= 5 }">楂�</text>
- </view>
- <slider
- v-model="form.riskLevel"
- min="1"
- max="5"
- step="1"
- activeColor="#f56c6c"
- backgroundColor="#e4e7ed"
- block-color="#f56c6c"
- block-size="20"
- />
- </view>
- </view>
- </view>
</view>
<!-- 绛惧悕纭 -->
@@ -142,31 +130,158 @@
</view>
</view>
+ <!-- 绛惧悕纭鍖哄煙 -->
+ <view class="signature-section card">
+ <view class="section-header">
+ <text class="section-title">涓撳绛惧悕纭</text>
+ <view v-if="isTimeout" class="timeout-badge">
+ <up-icon name="clock" size="16" />
+ <text>宸茶秴鏃讹紝涓嶅彲鎿嶄綔</text>
+ </view>
+ </view>
+
+ <view class="signature-content">
+ <!-- 鏄剧ず宸茬鍚嶅浘鐗� -->
+ <view v-if="signatureData.signatureUrl" class="signed-preview">
+ <image
+ :src="signatureData.signatureUrl"
+ mode="aspectFit"
+ class="signature-image"
+ @tap="previewSignature"
+ />
+ <view class="signature-info">
+ <text class="signature-name">绛惧悕浜猴細{{ expertInfo.name }}</text>
+ <text class="signature-time">{{
+ signatureData.signatureTime
+ }}</text>
+ <view class="signature-actions" v-if="!isReadonly">
+ <button class="re-sign-btn" @tap="removeSignature">
+ <u-icon name="photo" size="16" />
+ <text>閲嶆柊绛惧悕</text>
+ </button>
+ </view>
+ </view>
+ </view>
+
+ <!-- 娣诲姞绛惧悕鎸夐挳 -->
+ <view
+ v-else
+ class="signature-upload"
+ @tap="openSignaturePanel"
+ v-if="!isReadonly"
+ >
+ <view class="signature-upload-area">
+ <up-icon name="edit-pen" size="48" color="#c0c4cc" />
+ <text class="upload-hint">鐐瑰嚮杩涜鎵嬪啓绛惧悕</text>
+ <text class="upload-tip">绛惧悕灏嗕綔涓洪噸瑕佸嚟璇�</text>
+ </view>
+ </view>
+
+ <!-- 瓒呮椂鐘舵�佷笅鏄剧ず鎻愮ず -->
+ <view
+ v-if="isReadonly && !signatureData.signatureUrl"
+ class="signature-disabled"
+ >
+ <view class="signature-disabled-area">
+ <up-icon name="close-circle" size="48" color="#dcdfe6" />
+ <text class="disabled-hint">褰撳墠浠诲姟宸茶秴鏃�</text>
+ <text class="disabled-tip">鏃犳硶杩涜绛惧悕鎿嶄綔</text>
+ </view>
+ </view>
+ </view>
+ </view>
+
<!-- 鎿嶄綔鎸夐挳 -->
- <view class="action-bar-compact">
- <button
- class="action-btn save-btn"
- @tap="saveDraft"
-
- >
+ <view class="action-bar-compact" v-if="!isReadonly">
+ <button class="action-btn save-btn" @tap="saveDraft" v-if="showSaveBtn">
<up-icon name="file-text" size="16" color="#606266" />
<text>淇濆瓨鑽夌</text>
</button>
- <button
+ <button
class="action-btn submit-btn"
@tap="submitReview"
- :disabled="!canSubmit"
+ v-if="showSubmitBtn"
>
<up-icon name="checkmark" size="16" color="#fff" />
- <text>鎻愪氦瀹℃煡</text>
+ <text>{{ submitBtnText }}</text>
</button>
</view>
+
+ <!-- 鍙鐘舵�佹彁绀� -->
+ <view v-if="isReadonly" class="readonly-tip card">
+ <up-icon name="info-circle" size="20" color="#fa8c16" />
+ <text>褰撳墠浠诲姟宸茶秴鏃讹紝浠呭彲鏌ョ湅锛屼笉鍙搷浣�</text>
+ </view>
+
+ <!-- 浼樺寲鐨勭鍚嶅脊绐楃粍浠� -->
+ <u-popup
+ :show="showSignaturePanel"
+ @close="closeSignaturePanel"
+ mode="bottom"
+ :round="20"
+ :closeable="true"
+ closeIcon="close"
+ >
+ <view class="signature-modal">
+ <view class="modal-header">
+ <text class="modal-title">鎵嬪啓绛惧悕</text>
+ <text class="modal-subtitle">璇峰湪涓嬫柟鍖哄煙杩涜绛惧悕</text>
+ </view>
+
+ <view class="signature-canvas-container">
+ <!-- 鎵嬪啓绛惧悕鐢诲竷 -->
+ <canvas
+ canvas-id="signatureCanvas"
+ class="signature-canvas"
+ :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
+ @touchstart="onTouchStart"
+ @touchmove="onTouchMove"
+ @touchend="onTouchEnd"
+ disable-scroll
+ ></canvas>
+
+ <!-- 鎿嶄綔鎸夐挳 -->
+ <view class="canvas-actions">
+ <button class="action-btn clear-btn" @tap="clearCanvas">
+ <up-icon name="trash" size="20" />
+ <text>娓呯┖</text>
+ </button>
+ <button
+ class="action-btn redo-btn"
+ @tap="undoLastStroke"
+ :disabled="!canUndo"
+ >
+ <up-icon name="play-left" size="20" />
+ <text>鎾ら攢</text>
+ </button>
+ <button
+ class="action-btn confirm-btn"
+ @tap="confirmSignature"
+ :disabled="!hasSignature"
+ >
+ <up-icon name="checkmark" size="20" />
+ <text>纭绛惧悕</text>
+ </button>
+ </view>
+
+ <!-- 绛惧悕棰勮 -->
+ <view v-if="tempSignatureData" class="signature-preview">
+ <text class="preview-title">绛惧悕棰勮</text>
+ <image
+ :src="tempSignatureData"
+ mode="aspectFit"
+ class="preview-image"
+ />
+ </view>
+ </view>
+ </view>
+ </u-popup>
<!-- 鎻愪氦纭寮圭獥 -->
<u-modal
:show="showSubmitModal"
- title="纭鎻愪氦"
- content="纭畾瑕佹彁浜ゅ鏌ユ剰瑙佸悧锛熸彁浜ゅ悗灏嗘棤娉曚慨鏀广��"
+ :title="modalTitle"
+ :content="modalContent"
showCancelButton
@confirm="confirmSubmit"
@cancel="showSubmitModal = false"
@@ -175,114 +290,943 @@
</template>
<script setup>
-import { ref, computed, onMounted } from "vue";
-import { onLoad } from "@dcloudio/uni-app";
+import { ref, computed, reactive, onMounted, nextTick } from "vue";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import dayjs from "dayjs";
+import { useUserStore } from "@/stores/user";
+const userStore = useUserStore();
+const dict = ref({});
// 鍝嶅簲寮忔暟鎹�
const caseInfo = ref({
- hospitalNo: "D230415",
- donorName: "寮犳煇鏌�",
- gender: "鐢�",
- age: "45",
- diagnosis: "缁堟湯鏈熻倽鐥�"
+ hospitalNo: "",
+ donorName: "",
+ gender: "",
+ age: "",
+ diagnosis: "",
+ receiveStatus: "0",
+ endtime: "",
});
-const materials = ref([
- { id: 1, name: "鎹愮尞鑰呯煡鎯呭悓鎰忎功.pdf", icon: "file-text", color: "#f56c6c", size: "2.3MB" },
- { id: 2, name: "鍖诲璇勪及鎶ュ憡.docx", icon: "file-text", color: "#1890ff", size: "1.1MB" },
- { id: 3, name: "瀹為獙瀹ゆ鏌ョ粨鏋�.xlsx", icon: "file-text", color: "#52c41a", size: "0.8MB" },
- { id: 4, name: "褰卞儚瀛﹁祫鏂�.jpg", icon: "photo", color: "#fa8c16", size: "3.2MB" }
-]);
-
+const id = ref(null);
+const fcid = ref(null);
+const materials = ref([]);
const form = ref({
- conclusion: "",
- opinion: "",
- riskLevel: 3
+ expertconclusion: "", // 涓撳缁撹
+ expertopinion: "", // 涓撳鎰忚
});
const expertInfo = ref({
- name: "瀛斿績娑�",
- title: "涓诲涓撳"
+ name: "",
+ title: "",
});
-const reviewStatus = ref("pending");
const showSubmitModal = ref(false);
+const modalTitle = ref("纭鎻愪氦");
+const modalContent = ref("纭畾瑕佹彁浜ゅ鏌ユ剰瑙佸悧锛熸彁浜ゅ悗灏嗘棤娉曚慨鏀广��");
// 璁$畻灞炴��
-const statusText = computed(() => {
- const statusMap = {
- pending: "寰呭鏌�",
- drafted: "鑽夌",
- submitted: "宸叉彁浜�"
- };
- return statusMap[reviewStatus.value];
-});
-
-const canSubmit = computed(() => {
- return form.value.conclusion !== "" && form.value.opinion.trim().length > 10;
-});
-
const currentTime = computed(() => {
- return new Date().toLocaleString('zh-CN', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit'
+ return new Date().toLocaleString("zh-CN", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
});
});
const conclusionOptions = ref([
- { label: "鍚屾剰", value: "approved" },
- { label: "淇敼鍚庡悓鎰�", value: "approved_with_modifications" },
- { label: "淇敼鍚庨噸瀹�", value: "re-review" },
- { label: "涓嶅悓鎰�", value: "disapproved" }
+ { label: "鍚屾剰", value: "1" }, // 瀵瑰簲receiveStatus 5-瀹屾垚
+ { label: "椹冲洖", value: "2" }, // 瀵瑰簲receiveStatus 6-椹冲洖
]);
-// 鏂规硶
-const loadReviewData = (reviewId) => {
- console.log("鍔犺浇瀹℃煡鏁版嵁:", reviewId);
+// 绛惧悕鐩稿叧鏁版嵁
+const showSignaturePanel = ref(false);
+const signatureData = reactive({
+ signatureUrl: "",
+ signatureTime: "",
+ fileName: "",
+ serverData: null,
+});
+
+// 鎵嬪啓绛惧悕鐩稿叧
+const canvasWidth = 650;
+const canvasHeight = 300;
+let ctx = null;
+let isDrawing = false;
+let lastX = 0;
+let lastY = 0;
+let strokeHistory = [];
+const tempSignatureData = ref("");
+const canUndo = computed(() => strokeHistory.length > 0);
+const hasSignature = computed(() => tempSignatureData.value !== "");
+
+// 涓婁紶閰嶇疆
+const uploadConfig = reactive({
+ uploadUrl: "/api/common/upload",
+ extraParams: {
+ caseNo: "",
+ expertId: "",
+ expertName: "",
+ type: "ethics_review_signature",
+ bizType: "expert_review",
+ },
+});
+
+// 鎸夐挳鏄剧ず鎺у埗
+const showSaveBtn = ref(true);
+const showSubmitBtn = ref(true);
+const submitBtnText = ref("鎻愪氦瀹℃煡");
+
+// 鐘舵�佽浆鎹�
+const getStatusText = (status) => {
+ const statusMap = {
+ 0: "寰呮帴鏀�",
+ 1: "鏈帴鏀�",
+ 2: "宸叉帴鏀�",
+ 3: "瓒呮椂",
+ 4: "涓",
+ 5: "瀹屾垚",
+ 6: "椹冲洖",
+ };
+ return statusMap[status] || "鏈煡鐘舵��";
};
-const previewMaterial = (material) => {
- uni.showToast({
- title: `棰勮: ${material.name}`,
- icon: "none"
+const getStatusClass = (status) => {
+ const classMap = {
+ 0: "pending",
+ 1: "pending",
+ 2: "pending",
+ 3: "submitted",
+ 4: "submitted",
+ 5: "success",
+ 6: "error",
+ };
+ return classMap[status] || "pending";
+};
+
+// 鏄惁瓒呮椂
+const isTimeout = computed(() => {
+ return caseInfo.value.receiveStatus === "3";
+});
+
+// 鏄惁鍙妯″紡
+const isReadonly = computed(() => {
+ return isTimeout.value;
+});
+
+// 鏄惁鍙互鎻愪氦
+const canSubmit = computed(() => {
+ if (isReadonly.value) return false;
+ return (
+ form.value.expertconclusion !== "" &&
+ form.value.expertopinion.trim().length > 0 &&
+ signatureData.signatureUrl !== "" &&
+ signatureData.signatureUrl.startsWith("http") // 纭繚鏄畬鏁寸殑URL璺緞
+ );
+});
+
+// 鐢熷懡鍛ㄦ湡
+onLoad(async (options) => {
+ id.value = options.id;
+ fcid.value = options.fcid;
+ if (fcid.value) {
+ await loadCaseData(fcid.value);
+ }
+});
+
+onShow(() => {
+ // 椤甸潰鏄剧ず鏃舵鏌ョ敤鎴风櫥褰曠姸鎬�
+ const userInfo = uni.getStorageSync("userInfo");
+ if (userInfo) {
+ expertInfo.value.name = userInfo.nickName || userInfo.userName || "";
+ }
+});
+
+// 鍔犺浇妗堜欢鏁版嵁
+const loadCaseData = async (id) => {
+ try {
+ uni.showLoading({ title: "鍔犺浇涓�..." });
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ const params = {
+ fcid: id,
+ pageNum: 1,
+ pageSize: 1,
+ };
+
+ const res = await uni.$uapi.get(
+ `/project/ethicalreviewopinions/listnew`,
+ params,
+ );
+
+ if (res.code === 200 && res.rows && res.rows.length > 0) {
+ const data = res.rows[0];
+ console.log("鍔犺浇鐨勫鏌ユ暟鎹�:", data);
+
+ // 璁剧疆妗堜欢淇℃伅
+ caseInfo.value = {
+ ...caseInfo.value,
+ inpatientno: data.inpatientno,
+ name: data.name,
+ sex: data.sex,
+ age: data.age,
+ ageunit: data.ageunit,
+ expertType: data.expertType,
+ diagnosisname: data.diagnosisname,
+ receiveStatus: data.receiveStatus || "0",
+ endtime: data.endtime || "",
+ caseNo: data.caseNo || "",
+ };
+
+ // 璁剧疆琛ㄥ崟鏁版嵁
+ if (data.expertconclusion) {
+ form.value.expertconclusion = data.expertconclusion.toString();
+ }
+ if (data.expertopinion) {
+ form.value.expertopinion = data.expertopinion;
+ }
+
+ // 璁剧疆涓撳淇℃伅
+ if (data.expertname) {
+ expertInfo.value.name = data.expertname;
+ } else {
+ // 浠庣敤鎴蜂俊鎭幏鍙�
+ const userInfo = uni.getStorageSync("userInfo");
+ if (userInfo) {
+ expertInfo.value.name = userInfo.nickName || userInfo.userName || "";
+ }
+ }
+
+ // 璁剧疆绛惧悕
+ if (data.sigin) {
+ // 妫�鏌ョ鍚峌RL鏄惁鏄畬鏁磋矾寰�
+ if (data.sigin.startsWith("http")) {
+ signatureData.signatureUrl = data.sigin;
+ } else {
+ // 濡傛灉涓嶆槸瀹屾暣璺緞锛屽彲鑳介渶瑕佹嫾鎺ュ熀纭�URL
+ signatureData.signatureUrl = `/api${
+ data.sigin.startsWith("/") ? "" : "/"
+ }${data.sigin}`;
+ }
+ signatureData.signatureTime = data.conclusiontime || "";
+ }
+
+ // 瑙f瀽闄勪欢
+ if (data.filePatch) {
+ parseAnnexFiles(data.filePatch);
+ }
+
+ // 妫�鏌ユ槸鍚﹁秴鏃�
+ checkTimeoutStatus(data);
+
+ // 鏍规嵁鐘舵�佹帶鍒舵寜閽樉绀�
+ updateButtonStatus(data.receiveStatus);
+
+ // 鏇存柊涓婁紶鍙傛暟
+ uploadConfig.extraParams.caseNo = data.caseNo || "";
+ uploadConfig.extraParams.expertName = expertInfo.value.name;
+ } else {
+ uni.showToast({
+ title: res.msg || "鏈壘鍒板鏌ユ暟鎹�",
+ icon: "none",
+ });
+ }
+ } catch (error) {
+ if (error.message === "鏈櫥褰�") {
+ // 鉁� 浠�涔堥兘涓嶅仛锛屾嫤鎴櫒宸茬粡澶勭悊
+ return;
+ }
+ uni.showToast({ title: "鍔犺浇澶辫触", icon: "none" });
+ } finally {
+ uni.hideLoading();
+ }
+};
+
+// 妫�鏌ユ槸鍚﹁秴鏃�
+const checkTimeoutStatus = (data) => {
+ if (data.receiveStatus === "3") {
+ // 鐘舵�佸凡缁忔槸瓒呮椂
+ return;
+ }
+
+ // 濡傛灉鏈夋埅姝㈡椂闂达紝妫�鏌ユ槸鍚﹁秴杩囧綋鍓嶆椂闂�
+ if (data.endtime) {
+ const endTime = new Date(data.endtime);
+ const now = new Date();
+ if (now > endTime) {
+ // 鏍囪涓鸿秴鏃剁姸鎬�
+ caseInfo.value.receiveStatus = "3";
+ updateButtonStatus("3");
+ }
+ }
+};
+
+// 瑙f瀽闄勪欢鏂囦欢
+const parseAnnexFiles = (filePatch) => {
+ if (!filePatch) return;
+
+ try {
+ // 瑙f瀽JSON瀛楃涓�
+ let fileList = [];
+
+ // 妫�鏌ユ槸鍚︽槸JSON瀛楃涓叉牸寮�
+ if (filePatch.startsWith("[") && filePatch.endsWith("]")) {
+ // 澶勭悊杞箟瀛楃
+ const cleanJson = filePatch.replace(/\\"/g, '"');
+ fileList = JSON.parse(cleanJson);
+ } else if (filePatch.includes("fileName")) {
+ // 灏濊瘯鐩存帴瑙f瀽
+ fileList = JSON.parse(filePatch);
+ } else {
+ // 鏃ф牸寮忓鐞�
+ const oldFileList = filePatch.split(";").filter((item) => item.trim());
+ fileList = oldFileList.map((file) => ({
+ fileName: file.split("/").pop() || `闄勪欢`,
+ path: file,
+ fileUrl: file,
+ }));
+ }
+
+ // 杞崲涓洪渶瑕佺殑鏍煎紡
+ materials.value = fileList.map((file, index) => {
+ const fileName = file.fileName || `闄勪欢${index + 1}`;
+ const fileUrl = file.fileUrl || file.path || file.url || "";
+ const ext = fileName.split(".").pop().toLowerCase();
+ let icon = "file-text";
+ let color = "#909399";
+
+ if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+ icon = "photo";
+ color = "#fa8c16";
+ } else if (["doc", "docx"].includes(ext)) {
+ icon = "file-text";
+ color = "#1890ff";
+ } else if (["xls", "xlsx", "csv"].includes(ext)) {
+ icon = "file-text";
+ color = "#52c41a";
+ } else if (["pdf"].includes(ext)) {
+ icon = "file-text";
+ color = "#f56c6c";
+ } else if (["txt", "text"].includes(ext)) {
+ icon = "file-text";
+ color = "#909399";
+ } else if (["zip", "rar", "7z"].includes(ext)) {
+ icon = "folder";
+ color = "#722ed1";
+ }
+
+ return {
+ id: file.infoid || index + 1,
+ name: fileName,
+ icon: icon,
+ color: color,
+ size: "--",
+ url: fileUrl,
+ type: ext,
+ createTime: file.createTime || "",
+ };
+ });
+ } catch (error) {
+ console.error("瑙f瀽闄勪欢澶辫触:", error, filePatch);
+
+ // 鍥為��鍒版棫鏍煎紡澶勭悊
+ const fileList = filePatch.split(";").filter((item) => item.trim());
+ materials.value = fileList.map((file, index) => {
+ const fileName = file.split("/").pop() || `闄勪欢${index + 1}`;
+ const ext = fileName.split(".").pop().toLowerCase();
+ let icon = "file-text";
+ let color = "#909399";
+
+ if (["jpg", "jpeg", "png", "gif", "bmp"].includes(ext)) {
+ icon = "photo";
+ color = "#fa8c16";
+ } else if (["doc", "docx"].includes(ext)) {
+ icon = "file-text";
+ color = "#1890ff";
+ } else if (["xls", "xlsx"].includes(ext)) {
+ icon = "file-text";
+ color = "#52c41a";
+ } else if (["pdf"].includes(ext)) {
+ icon = "file-text";
+ color = "#f56c6c";
+ }
+
+ return {
+ id: index + 1,
+ name: fileName,
+ icon: icon,
+ color: color,
+ size: "--",
+ url: file,
+ };
+ });
+ }
+};
+
+// 鏇存柊鎸夐挳鐘舵��
+const updateButtonStatus = (status) => {
+ const statusNum = status;
+ switch (statusNum) {
+ case "3": // 瓒呮椂
+ case "4": // 涓
+ case "5": // 宸插畬鎴�
+ case "6": // 宸查┏鍥�
+ showSaveBtn.value = false;
+ showSubmitBtn.value = false;
+ break;
+ default:
+ showSaveBtn.value = true;
+ showSubmitBtn.value = true;
+ submitBtnText.value = "鎻愪氦瀹℃煡";
+ }
+};
+
+// 鎵撳紑绛惧悕闈㈡澘
+const openSignaturePanel = () => {
+ if (isReadonly.value) {
+ uni.showToast({
+ title: "褰撳墠浠诲姟宸茶秴鏃讹紝涓嶅彲鎿嶄綔",
+ icon: "none",
+ });
+ return;
+ }
+
+ showSignaturePanel.value = true;
+ nextTick(() => {
+ initCanvas();
});
+};
+
+// 鍏抽棴绛惧悕闈㈡澘
+const closeSignaturePanel = () => {
+ showSignaturePanel.value = false;
+ clearCanvas();
+};
+
+// 鍒濆鍖栫敾甯�
+const initCanvas = () => {
+ ctx = uni.createCanvasContext("signatureCanvas");
+ clearCanvas();
+};
+
+// 娓呯┖鐢诲竷
+const clearCanvas = () => {
+ if (!ctx) return;
+
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+ ctx.setStrokeStyle("#000000");
+ ctx.setLineWidth(3);
+ ctx.setLineCap("round");
+ ctx.setLineJoin("round");
+ ctx.draw();
+ strokeHistory = [];
+ tempSignatureData.value = "";
+};
+
+// 鎾ら攢涓婁竴姝�
+const undoLastStroke = () => {
+ if (strokeHistory.length === 0) return;
+
+ // 绉婚櫎鏈�鍚庝竴姝�
+ strokeHistory.pop();
+
+ // 閲嶆柊缁樺埗
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+ ctx.setStrokeStyle("#000000");
+ ctx.setLineWidth(3);
+ ctx.setLineCap("round");
+ ctx.setLineJoin("round");
+
+ // 缁樺埗鍘嗗彶绗旇抗
+ strokeHistory.forEach((stroke) => {
+ ctx.beginPath();
+ ctx.moveTo(stroke.startX, stroke.startY);
+ ctx.lineTo(stroke.endX, stroke.endY);
+ ctx.stroke();
+ });
+
+ ctx.draw();
+
+ // 鏇存柊棰勮
+ if (strokeHistory.length === 0) {
+ tempSignatureData.value = "";
+ } else {
+ getCanvasImage();
+ }
+};
+
+// 瑙︽懜寮�濮�
+const onTouchStart = (e) => {
+ if (isReadonly.value) return;
+
+ isDrawing = true;
+ const touch = e.touches[0];
+ lastX = touch.x;
+ lastY = touch.y;
+ ctx.beginPath();
+ ctx.moveTo(lastX, lastY);
+};
+
+// 瑙︽懜绉诲姩
+const onTouchMove = (e) => {
+ if (!isDrawing || isReadonly.value) return;
+
+ const touch = e.touches[0];
+ const currentX = touch.x;
+ const currentY = touch.y;
+
+ ctx.lineTo(currentX, currentY);
+ ctx.stroke();
+ ctx.draw(true);
+
+ // 淇濆瓨绗旇抗鍒板巻鍙茶褰�
+ strokeHistory.push({
+ startX: lastX,
+ startY: lastY,
+ endX: currentX,
+ endY: currentY,
+ });
+
+ lastX = currentX;
+ lastY = currentY;
+};
+
+// 瑙︽懜缁撴潫
+const onTouchEnd = () => {
+ if (!isDrawing) return;
+
+ isDrawing = false;
+ ctx.closePath();
+
+ // 鏇存柊棰勮
+ getCanvasImage();
+};
+
+// 鑾峰彇鐢诲竷鍥剧墖
+const getCanvasImage = () => {
+ uni.canvasToTempFilePath({
+ canvasId: "signatureCanvas",
+ success: (res) => {
+ tempSignatureData.value = res.tempFilePath;
+ },
+ fail: (err) => {
+ console.error("鑾峰彇鐢诲竷鍥剧墖澶辫触:", err);
+ },
+ });
+};
+
+// 纭绛惧悕
+const confirmSignature = async () => {
+ if (!tempSignatureData.value) {
+ uni.showToast({
+ title: "璇峰厛绛惧悕",
+ icon: "none",
+ });
+ return;
+ }
+
+ try {
+ uni.showLoading({ title: "淇濆瓨绛惧悕涓�..." });
+
+ // 涓婁紶绛惧悕鏂囦欢
+ const uploadResult = await uploadSignature(tempSignatureData.value);
+
+ if (uploadResult) {
+ // 鏇存柊绛惧悕鏁版嵁
+ signatureData.signatureUrl = uploadResult.url;
+ signatureData.signatureTime = new Date().toLocaleString("zh-CN");
+ signatureData.fileName =
+ uploadResult.originalFilename || `signature_${Date.now()}.png`;
+ signatureData.serverData = uploadResult;
+
+ // 淇濆瓨鍒版湰鍦�
+ saveSignatureToLocal(uploadResult);
+
+ uni.hideLoading();
+ uni.showToast({
+ title: "绛惧悕淇濆瓨鎴愬姛",
+ icon: "success",
+ });
+
+ showSignaturePanel.value = false;
+ clearCanvas();
+ } else {
+ uni.hideLoading();
+ uni.showToast({
+ title: "绛惧悕涓婁紶澶辫触",
+ icon: "none",
+ });
+ }
+ } catch (error) {
+ console.error("绛惧悕涓婁紶澶辫触:", error);
+ uni.hideLoading();
+ uni.showToast({
+ title: "绛惧悕涓婁紶澶辫触",
+ icon: "none",
+ });
+ }
+};
+
+// 涓婁紶绛惧悕鏂囦欢鏂规硶
+const uploadSignature = (filePath) => {
+ return new Promise((resolve, reject) => {
+ const token = uni.getStorageSync("token");
+
+ // 鑾峰彇鐢ㄦ埛淇℃伅
+ const userInfo = uni.getStorageSync("userInfo");
+ const expertName =
+ userInfo?.nickName || userInfo?.userName || expertInfo.value.name;
+
+ uni.uploadFile({
+ url: "/api/common/upload",
+ filePath: filePath,
+ name: "file",
+ header: {
+ Authorization: `Bearer ${token}`,
+ },
+ formData: {
+ // 娣诲姞棰濆鍙傛暟锛屽弬鑰冮檮浠剁粍浠�
+ bizType: "expert_review_signature",
+ caseNo: caseInfo.value.caseNo || "",
+ expertName: expertName,
+ uploadType: "signature",
+ },
+ success: (res) => {
+ if (res.statusCode === 200) {
+ const data = JSON.parse(res.data);
+ console.log("绛惧悕涓婁紶鎴愬姛:", data);
+
+ if (data.code === 200) {
+ resolve({
+ url: data.url,
+ fileName: data.fileName,
+ newFileName: data.newFileName,
+ originalFilename: data.originalFilename,
+ filePath: data.filePath || data.fileName,
+ size: data.size,
+ });
+ } else {
+ reject(new Error(data.msg || "涓婁紶澶辫触"));
+ }
+ } else {
+ reject(new Error(`涓婁紶澶辫触锛岀姸鎬佺爜: ${res.statusCode}`));
+ }
+ },
+ fail: (err) => {
+ reject(err);
+ },
+ });
+ });
+};
+
+// 淇濆瓨鍒版湰鍦�
+const saveSignatureToLocal = (uploadData) => {
+ try {
+ const signatureInfo = {
+ signatureUrl: signatureData.signatureUrl,
+ signatureTime: signatureData.signatureTime,
+ fileName: signatureData.fileName,
+ uploadData: uploadData, // 淇濆瓨涓婁紶杩斿洖鐨勬暟鎹�
+ caseNo: caseInfo.value.caseNo,
+ timestamp: Date.now(),
+ };
+
+ uni.setStorageSync("expert_review_signature", signatureInfo);
+ } catch (error) {
+ console.error("淇濆瓨绛惧悕鍒版湰鍦板け璐�:", error);
+ }
+};
+
+// 鍒犻櫎绛惧悕
+const removeSignature = () => {
+ if (isReadonly.value) {
+ uni.showToast({
+ title: "褰撳墠浠诲姟宸茶秴鏃讹紝涓嶅彲鎿嶄綔",
+ icon: "none",
+ });
+ return;
+ }
+
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "纭畾瑕佸垹闄ょ鍚嶅悧锛�",
+ success: (res) => {
+ if (res.confirm) {
+ signatureData.signatureUrl = "";
+ signatureData.signatureTime = "";
+ signatureData.fileName = "";
+ signatureData.serverData = null;
+ uni.removeStorageSync("expert_review_signature");
+ }
+ },
+ });
+};
+
+// 棰勮绛惧悕
+// 棰勮绛惧悕
+const previewSignature = () => {
+ if (signatureData.signatureUrl) {
+ // 妫�鏌RL鏄惁闇�瑕佹嫾鎺ュ熀纭�璺緞
+ let previewUrl = signatureData.signatureUrl;
+ if (!previewUrl.startsWith("http")) {
+ // 鍙兘闇�瑕佹嫾鎺ユ湇鍔″櫒鍩虹URL
+ previewUrl = `${userStore?.baseUrlHt || ""}${previewUrl}`;
+ }
+
+ uni.previewImage({
+ urls: [previewUrl],
+ });
+ }
+};
+
+// 棰勮鏉愭枡
+// 棰勮鏉愭枡
+const previewMaterial = (material) => {
+ if (material.url) {
+ uni.showLoading({ title: "鍔犺浇涓�..." });
+
+ const fileExt =
+ material.type || material.url.split(".").pop().toLowerCase();
+
+ // 鍒ゆ柇鏂囦欢绫诲瀷
+ if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(fileExt)) {
+ // 鍥剧墖鐩存帴棰勮
+ uni.previewImage({
+ urls: [material.url],
+ current: 0,
+ success: () => {
+ console.log("鍥剧墖棰勮鎴愬姛");
+ },
+ fail: (err) => {
+ console.error("鍥剧墖棰勮澶辫触:", err);
+ uni.showToast({
+ title: "鍥剧墖鍔犺浇澶辫触",
+ icon: "none",
+ });
+ },
+ complete: () => {
+ uni.hideLoading();
+ },
+ });
+ } else if (
+ ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt"].includes(
+ fileExt,
+ )
+ ) {
+ // 鏂囨。鏂囦欢涓嬭浇鍚庢墦寮�
+ uni.downloadFile({
+ url: material.url,
+ success: (res) => {
+ if (res.statusCode === 200) {
+ const filePath = res.tempFilePath;
+ uni.openDocument({
+ filePath: filePath,
+ showMenu: true,
+ fileType: fileExt === "pdf" ? "pdf" : "",
+ success: () => {
+ console.log("鎵撳紑鏂囨。鎴愬姛");
+ },
+ fail: (err) => {
+ console.error("鎵撳紑鏂囨。澶辫触:", err);
+ uni.showToast({
+ title: "鏃犳硶鎵撳紑璇ユ枃浠�",
+ icon: "none",
+ });
+ },
+ });
+ }
+ },
+ fail: (err) => {
+ console.error("涓嬭浇鏂囦欢澶辫触:", err);
+ uni.showToast({
+ title: "鏂囦欢涓嬭浇澶辫触",
+ icon: "none",
+ });
+ },
+ complete: () => {
+ uni.hideLoading();
+ },
+ });
+ } else {
+ // 鍏朵粬鏂囦欢绫诲瀷
+ uni.showToast({
+ title: `鏆備笉鏀寔棰勮${fileExt}鏍煎紡鏂囦欢`,
+ icon: "none",
+ });
+ uni.hideLoading();
+ }
+ } else {
+ uni.showToast({
+ title: `棰勮: ${material.name}`,
+ icon: "none",
+ });
+ }
};
const onConclusionChange = (value) => {
console.log("閫変腑缁撹:", value);
};
-const saveDraft = () => {
- uni.showToast({
- title: "鑽夌淇濆瓨鎴愬姛",
- icon: "success"
- });
- reviewStatus.value = "drafted";
+// 淇濆瓨鑽夌
+const saveDraft = async () => {
+ if (isReadonly.value) {
+ uni.showToast({
+ title: "褰撳墠浠诲姟宸茶秴鏃讹紝涓嶅彲鎿嶄綔",
+ icon: "none",
+ });
+ return;
+ }
+
+ if (!validateForm(true)) return;
+
+ try {
+ uni.showLoading({ title: "淇濆瓨涓�..." });
+
+ const submitData = {
+ fcid: fcid.value,
+ expertconclusion: form.value.expertconclusion,
+ expertopinion: form.value.expertopinion,
+ sigin: signatureData.signatureUrl, // 浣跨敤涓婁紶鍚庣殑瀹屾暣璺緞
+ receiveStatus: "2", // 宸叉帴鏀剁姸鎬�
+ conclusiontime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ };
+
+ const res = await uni.$uapi.post(
+ "/project/ethicalreviewopinions/edit",
+ submitData,
+ );
+
+ if (res.code === 200) {
+ uni.showToast({
+ title: "淇濆瓨鎴愬姛",
+ icon: "success",
+ });
+ // 鏇存柊鏈湴鐘舵��
+ caseInfo.value.receiveStatus = "2";
+ updateButtonStatus("2");
+ } else {
+ uni.showToast({
+ title: res.msg || "淇濆瓨澶辫触",
+ icon: "none",
+ });
+ }
+ } catch (error) {
+ console.error("淇濆瓨鑽夌澶辫触:", error);
+ uni.showToast({
+ title: "淇濆瓨澶辫触",
+ icon: "none",
+ });
+ } finally {
+ uni.hideLoading();
+ }
};
+// 鎻愪氦瀹℃煡
const submitReview = () => {
+ console.log(1);
+
+ if (isReadonly.value) {
+ uni.showToast({
+ title: "褰撳墠浠诲姟宸茶秴鏃讹紝涓嶅彲鎿嶄綔",
+ icon: "none",
+ });
+ return;
+ }
+ console.log(2);
+
+ if (!validateForm()) return;
+
+ modalTitle.value = "纭鎻愪氦";
+ modalContent.value = "纭畾瑕佹彁浜ゅ鏌ユ剰瑙佸悧锛熸彁浜ゅ悗灏嗘棤娉曚慨鏀广��";
showSubmitModal.value = true;
};
-const confirmSubmit = () => {
- uni.showLoading({ title: "鎻愪氦涓�..." });
-
- setTimeout(() => {
- uni.hideLoading();
+// 纭鎻愪氦
+const confirmSubmit = async () => {
+ try {
+ uni.showLoading({ title: "鎻愪氦涓�..." });
+ console.log(caseInfo.value, "form.value");
+
+ const submitData = {
+ id: fcid.value,
+ expertconclusion: form.value.expertconclusion,
+ expertopinion: form.value.expertopinion,
+ sigin: signatureData.signatureUrl,
+ expertType: caseInfo.value.expertType,
+ // 鏍规嵁缁撹璁剧疆鐘舵��
+ receiveStatus: form.value.expertconclusion == "1" ? "5" : "6", // 5-瀹屾垚, 6-椹冲洖
+ conclusiontime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ };
+
+ const res = await uni.$uapi.post(
+ "/project/ethicalreviewopinions/edit",
+ submitData,
+ );
+
+ if (res.code === 200) {
+ uni.showToast({
+ title: "鎻愪氦鎴愬姛",
+ icon: "success",
+ duration: 2000,
+ });
+
+ // 鏇存柊鏈湴鐘舵��
+ caseInfo.value.receiveStatus = submitData.receiveStatus;
+ updateButtonStatus(submitData.receiveStatus);
+
+ showSubmitModal.value = false;
+
+ setTimeout(() => {
+ uni.navigateBack();
+ }, 1500);
+ } else {
+ uni.showToast({
+ title: res.msg || "鎻愪氦澶辫触",
+ icon: "none",
+ });
+ }
+ } catch (error) {
+ console.error("鎻愪氦澶辫触:", error);
uni.showToast({
- title: "瀹℃煡鎰忚鎻愪氦鎴愬姛",
- icon: "success"
+ title: "鎻愪氦澶辫触",
+ icon: "none",
});
- reviewStatus.value = "submitted";
- showSubmitModal.value = false;
-
- setTimeout(() => {
- uni.navigateBack();
- }, 1500);
- }, 2000);
+ } finally {
+ uni.hideLoading();
+ }
+};
+
+// 琛ㄥ崟楠岃瘉
+const validateForm = (isDraft = false) => {
+ if (!form.value.expertconclusion && !isDraft) {
+ uni.showToast({
+ title: "璇烽�夋嫨瀹℃煡缁撹",
+ icon: "none",
+ });
+ return false;
+ }
+ console.log(3);
+
+ if (!form.value.expertopinion.trim() && !isDraft) {
+ uni.showToast({
+ title: "璇疯緭鍏ュ鏌ユ剰瑙�",
+ icon: "none",
+ });
+ return false;
+ }
+ console.log(signatureData, "signatureData");
+
+ if (!signatureData.signatureUrl && !isDraft) {
+ uni.showToast({
+ title: "璇疯繘琛屾墜鍐欑鍚�",
+ icon: "none",
+ });
+ return false;
+ }
+
+ return true;
};
</script>
@@ -325,13 +1269,17 @@
background: #fff2e8;
color: #fa8c16;
}
- &.drafted {
+ &.submitted {
background: #e6f7ff;
color: #1890ff;
}
- &.submitted {
+ &.success {
background: #f6ffed;
color: #52c41a;
+ }
+ &.error {
+ background: #fff1f0;
+ color: #ff4d4f;
}
}
}
@@ -363,7 +1311,46 @@
}
}
}
+ .material-left {
+ display: flex;
+ align-items: center;
+ flex: 1;
+ .file-info {
+ margin-left: 16rpx;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .file-name {
+ font-size: 26rpx;
+ color: #303133;
+ max-width: 400rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .file-meta {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ margin-top: 4rpx;
+
+ .file-type {
+ font-size: 20rpx;
+ color: #909399;
+ background: #f0f2f5;
+ padding: 2rpx 8rpx;
+ border-radius: 4rpx;
+ }
+
+ .file-time {
+ font-size: 20rpx;
+ color: #909399;
+ }
+ }
+ }
.materials-section {
padding: 24rpx;
@@ -434,6 +1421,30 @@
.review-form {
padding: 24rpx;
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20rpx;
+
+ .section-title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .timeout-badge {
+ display: flex;
+ align-items: center;
+ gap: 4rpx;
+ padding: 4rpx 12rpx;
+ background: #fff2e8;
+ border-radius: 12rpx;
+ font-size: 22rpx;
+ color: #fa8c16;
+ }
+ }
+
.form-group {
margin-bottom: 32rpx;
@@ -443,36 +1454,6 @@
font-weight: 600;
color: #303133;
margin-bottom: 20rpx;
- }
- }
-
- .risk-assessment {
- .risk-item {
- .risk-label {
- display: block;
- font-size: 26rpx;
- color: #606266;
- margin-bottom: 16rpx;
- }
-
- .risk-slider-compact {
- .risk-levels {
- display: flex;
- justify-content: space-between;
- margin-bottom: 12rpx;
-
- .level-label {
- font-size: 22rpx;
- color: #c0c4cc;
- transition: color 0.3s;
-
- &.active {
- color: #f56c6c;
- font-weight: 500;
- }
- }
- }
- }
}
}
@@ -501,7 +1482,7 @@
.action-bar-compact {
position: fixed;
- bottom: 96rpx;
+ bottom: 0rpx;
left: 0;
right: 0;
display: flex;
@@ -529,7 +1510,7 @@
}
&.submit-btn {
- background: linear-gradient(135deg, #0f95b0, #89C4C1) !important;
+ background: linear-gradient(135deg, #0f95b0, #89c4c1) !important;
color: #fff;
&:disabled {
@@ -540,6 +1521,271 @@
&:active:not(:disabled) {
transform: scale(0.98);
+ }
+ }
+ }
+
+ .readonly-tip {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ padding: 20rpx 24rpx;
+ font-size: 24rpx;
+ color: #fa8c16;
+ }
+}
+
+.signature-section {
+ margin-top: 20rpx;
+ padding: 24rpx;
+ background: #fff;
+ border-radius: 16rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
+
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20rpx;
+
+ .section-title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #333;
+ }
+
+ .timeout-badge {
+ display: flex;
+ align-items: center;
+ gap: 4rpx;
+ padding: 4rpx 12rpx;
+ background: #fff2e8;
+ border-radius: 12rpx;
+ font-size: 22rpx;
+ color: #fa8c16;
+ }
+ }
+}
+
+.signature-content {
+ .signed-preview {
+ display: flex;
+ align-items: center;
+ padding: 20rpx;
+ background: #f8f9fa;
+ border-radius: 12rpx;
+ gap: 20rpx;
+
+ .signature-image {
+ width: 200rpx;
+ height: 100rpx;
+ border: 1rpx solid #dcdfe6;
+ border-radius: 8rpx;
+ background: #fff;
+ }
+
+ .signature-info {
+ flex: 1;
+
+ .signature-name {
+ display: block;
+ font-size: 26rpx;
+ color: #333;
+ margin-bottom: 8rpx;
+ font-weight: 500;
+ }
+
+ .signature-time {
+ display: block;
+ font-size: 24rpx;
+ color: #666;
+ margin-bottom: 8rpx;
+ }
+
+ .signature-actions {
+ margin-top: 12rpx;
+
+ .re-sign-btn {
+ padding: 8rpx 16rpx;
+ border: 1rpx solid #dcdfe6;
+ background: #fff;
+ border-radius: 8rpx;
+ font-size: 24rpx;
+ color: #f56c6c;
+ display: flex;
+ align-items: center;
+ gap: 6rpx;
+
+ &:active {
+ background: #f5f7fa;
+ }
+ }
+ }
+ }
+ }
+
+ .signature-upload {
+ .signature-upload-area {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 200rpx;
+ border: 2rpx dashed #c0c4cc;
+ border-radius: 12rpx;
+ background: #fafafa;
+ transition: all 0.3s;
+
+ &:active {
+ background: #f0f2f5;
+ border-color: #007aff;
+ }
+
+ .upload-hint {
+ font-size: 28rpx;
+ color: #606266;
+ margin-top: 16rpx;
+ margin-bottom: 8rpx;
+ }
+
+ .upload-tip {
+ font-size: 24rpx;
+ color: #909399;
+ }
+ }
+ }
+
+ .signature-disabled {
+ .signature-disabled-area {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 200rpx;
+ border: 2rpx solid #e4e7ed;
+ border-radius: 12rpx;
+ background: #f8f9fa;
+
+ .disabled-hint {
+ font-size: 28rpx;
+ color: #909399;
+ margin-top: 16rpx;
+ margin-bottom: 8rpx;
+ }
+
+ .disabled-tip {
+ font-size: 24rpx;
+ color: #c0c4cc;
+ }
+ }
+ }
+}
+
+// 绛惧悕妯℃�佹鏍峰紡
+.signature-modal {
+ padding: 30rpx;
+ background: #fff;
+ border-radius: 20rpx 20rpx 0 0;
+ max-height: 80vh;
+ overflow: hidden;
+
+ .modal-header {
+ text-align: center;
+ margin-bottom: 30rpx;
+
+ .modal-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #303133;
+ display: block;
+ margin-bottom: 8rpx;
+ }
+
+ .modal-subtitle {
+ font-size: 24rpx;
+ color: #909399;
+ }
+ }
+
+ .signature-canvas-container {
+ .signature-canvas {
+ display: block;
+ margin: 0 auto;
+ border: 2rpx solid #e4e7ed;
+ border-radius: 8rpx;
+ background: #fff;
+ touch-action: none;
+ }
+
+ .canvas-actions {
+ display: flex;
+ gap: 20rpx;
+ margin: 20rpx 0;
+ padding: 0 20rpx;
+
+ .action-btn {
+ flex: 1;
+ height: 60rpx;
+ border-radius: 30rpx;
+ border: 1rpx solid #dcdfe6;
+ background: #fff;
+ font-size: 24rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8rpx;
+
+ &.clear-btn {
+ color: #f56c6c;
+ border-color: #f56c6c;
+ }
+
+ &.redo-btn {
+ color: #1890ff;
+ border-color: #1890ff;
+
+ &:disabled {
+ color: #c0c4cc;
+ border-color: #e4e7ed;
+ }
+ }
+
+ &.confirm-btn {
+ background: linear-gradient(135deg, #0f95b0, #89c4c1);
+ color: #fff;
+ border: none;
+
+ &:disabled {
+ background: #c0c4cc;
+ opacity: 0.6;
+ }
+ }
+
+ &:active:not(:disabled) {
+ transform: scale(0.98);
+ }
+ }
+ }
+
+ .signature-preview {
+ margin-top: 20rpx;
+ padding: 20rpx;
+ background: #f8f9fa;
+ border-radius: 8rpx;
+
+ .preview-title {
+ display: block;
+ font-size: 24rpx;
+ color: #606266;
+ margin-bottom: 12rpx;
+ }
+
+ .preview-image {
+ width: 200rpx;
+ height: 80rpx;
+ border: 1rpx solid #dcdfe6;
+ border-radius: 4rpx;
+ background: #fff;
}
}
}
@@ -558,12 +1804,33 @@
.action-bar-compact {
padding: 16rpx;
gap: 16rpx;
-
+
.action-btn {
height: 72rpx;
font-size: 26rpx;
}
}
}
+
+ .signature-modal {
+ padding: 20rpx;
+
+ .signature-canvas-container {
+ .signature-canvas {
+ width: 100% !important;
+ height: 250rpx !important;
+ }
+
+ .canvas-actions {
+ // flex-direction: column;
+ gap: 12rpx;
+ padding: 0;
+
+ .action-btn {
+ height: 72rpx;
+ }
+ }
+ }
+ }
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3