From c58665039ce8b7c895ed4f1000ff4cf525a92085 Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期三, 27 八月 2025 16:28:21 +0800 Subject: [PATCH] 1.设备保养开发联调 --- src/pages/cooperativeOffice/collaborativeApproval/approve.vue | 519 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 519 insertions(+), 0 deletions(-) diff --git a/src/pages/cooperativeOffice/collaborativeApproval/approve.vue b/src/pages/cooperativeOffice/collaborativeApproval/approve.vue new file mode 100644 index 0000000..6011e7b --- /dev/null +++ b/src/pages/cooperativeOffice/collaborativeApproval/approve.vue @@ -0,0 +1,519 @@ +<template> + <view class="approve-page"> + + <PageHeader title="瀹℃牳" @back="goBack" /> + + <!-- 鐢宠淇℃伅 --> + <view class="application-info"> + <view class="info-header"> + <text class="info-title">鐢宠淇℃伅</text> + </view> + <view class="info-content"> + <view class="info-row"> + <text class="info-label">鐢宠浜�</text> + <text class="info-value">{{ approvalData.approveUserName }}</text> + </view> + <view class="info-row"> + <text class="info-label">鐢宠閮ㄩ棬</text> + <text class="info-value">{{ approvalData.approveDeptName }}</text> + </view> + <view class="info-row"> + <text class="info-label">鐢宠浜嬬敱</text> + <text class="info-value">{{ approvalData.approveReason }}</text> + </view> + <view class="info-row"> + <text class="info-label">鐢宠鏃ユ湡</text> + <text class="info-value">{{ approvalData.approveTime }}</text> + </view> + </view> + </view> + + <!-- 瀹℃壒娴佺▼ --> + <view class="approval-process"> + <view class="process-header"> + <text class="process-title">瀹℃壒娴佺▼</text> + </view> + + <view class="process-steps"> + <view + v-for="(step, index) in approvalSteps" + :key="index" + class="process-step" + :class="{ + 'completed': step.status === 'completed', + 'current': step.status === 'current', + 'pending': step.status === 'pending', + 'rejected': step.status === 'rejected' + }" + > + <view class="step-indicator"> + <view class="step-dot"> + <text v-if="step.status === 'completed'" class="step-icon">鉁�</text> + <text v-else-if="step.status === 'rejected'" class="step-icon">鉁�</text> + <text v-else class="step-number">{{ index + 1 }}</text> + </view> + <view v-if="index < approvalSteps.length - 1" class="step-line"></view> + </view> + + <view class="step-content"> + <view class="step-info"> + <text class="step-title">{{ step.title }}</text> + <text class="step-approver">{{ step.approverName }}</text> + <text v-if="step.approveTime" class="step-time">{{ step.approveTime }}</text> + </view> + + <view v-if="step.opinion" class="step-opinion"> + <text class="opinion-label">瀹℃壒鎰忚锛�</text> + <text class="opinion-content">{{ step.opinion }}</text> + </view> + <!-- 绛惧悕灞曠ず --> + <view v-if="step.urlTem" class="step-opinion" style="margin-top:8px;"> + <text class="opinion-label">绛惧悕锛�</text> + <image :src="step.urlTem" mode="widthFix" style="width:180px;border-radius:6px;border:1px solid #eee;" /> + </view> + </view> + </view> + </view> + </view> + + <!-- 瀹℃牳鎰忚杈撳叆 --> + <view v-if="canApprove" class="approval-input"> + <view class="input-header"> + <text class="input-title">瀹℃牳鎰忚</text> + </view> + + <view class="input-content"> + <van-field + v-model="approvalOpinion" + type="textarea" + rows="4" + placeholder="璇疯緭鍏ュ鏍告剰瑙�" + maxlength="200" + show-word-limit + /> + </view> + </view> + + <!-- 搴曢儴鎿嶄綔鎸夐挳 --> + <view v-if="canApprove" class="footer-actions"> + <van-button class="reject-btn" @click="handleReject">椹冲洖</van-button> + <van-button class="approve-btn" @click="handleApprove">閫氳繃</van-button> + </view> + </view> +</template> + +<script setup> +import { ref, onMounted, computed } from 'vue' +import { approveProcessGetInfo, approveProcessDetails, updateApproveNode } from '@/api/collaborativeApproval/approvalProcess' +import useUserStore from '@/store/modules/user' +import { showToast } from 'vant' +import PageHeader from "@/components/PageHeader.vue"; + +const userStore = useUserStore() +const approvalData = ref({}) +const approvalSteps = ref([]) +const approvalOpinion = ref('') +const approveId = ref('') + +// 浠庤鎯呮帴鍙e瓧娈靛榻� canApprove锛氫粎褰撴湁 isShen 鐨勮妭鐐规椂鍙鎵� +const canApprove = computed(() => { + return approvalSteps.value.some(step => step.isShen === true) +}) + +onMounted(() => { + const pages = getCurrentPages() + const currentPage = pages[pages.length - 1] + approveId.value = currentPage.options.approveId + if (approveId.value) { + loadApprovalData() + } +}) + +const loadApprovalData = () => { + // 鍩烘湰鐢宠淇℃伅 + approveProcessGetInfo({ id: approveId.value }).then(res => { + approvalData.value = res.data || {} + }) + // 瀹℃壒鑺傜偣璇︽儏 + approveProcessDetails(approveId.value).then(res => { + const list = Array.isArray(res.data) ? res.data : [] + // 淇濆瓨鍘熷鑺傜偣鏁版嵁渚涙彁浜や娇鐢� + activities.value = list + + approvalSteps.value = list.map((it, idx) => { + // 鑺傜偣鐘舵�佹槧灏勶細1=閫氳繃锛�2=涓嶉�氳繃锛屽惁鍒欑湅鏄惁褰撳墠(isShen)锛屽啀榛樿涓哄緟澶勭悊 + let status = 'pending' + if (it.approveNodeStatus === 1) status = 'completed' + else if (it.approveNodeStatus === 2) status = 'rejected' + else if (it.isShen) status = 'current' + return { + title: `绗�${idx + 1}姝ュ鎵筦, + approverName: it.approveNodeUser || '鏈煡鐢ㄦ埛', + status, + approveTime: it.approveTime || null, + opinion: it.approveNodeReason || '', + urlTem: it.urlTem || '', + isShen: !!it.isShen + } + }) + }) +} + +const goBack = () => { + uni.navigateBack() +} + +const submitForm = (status) => { + // 鍙�夛細鏍¢獙瀹℃牳鎰忚 + if (!approvalOpinion.value?.trim()) { + showToast('璇疯緭鍏ュ鏍告剰瑙�') + return + } + // 鎵惧埌褰撳墠鍙鎵硅妭鐐� + const filteredActivities = activities.value.filter(activity => activity.isShen) + if (!filteredActivities.length) { + showToast('褰撳墠鏃犲彲瀹℃壒鑺傜偣') + return + } + // 鍐欏叆鐘舵�佸拰鎰忚 + filteredActivities[0].approveNodeStatus = status + filteredActivities[0].approveNodeReason = approvalOpinion.value || '' + // 璁$畻鏄惁涓烘渶鍚庝竴姝� + const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length - 1 + // 璋冪敤鍚庣 + updateApproveNode({ ...filteredActivities[0], isLast }).then(() => { + const msg = status === 1 ? '瀹℃壒閫氳繃' : '瀹℃壒宸查┏鍥�' + showToast(msg) + // 鎻愮ず鍚庤繑鍥炰笂涓�涓〉闈� + setTimeout(() => { + goBack() // 鍐呴儴鏄� uni.navigateBack() + }, 800) + }) +} + +const handleApprove = () => { + uni.showModal({ + title: '纭鎿嶄綔', + content: '纭畾瑕侀�氳繃姝ゅ鎵瑰悧锛�', + success: (res) => { + if (res.confirm) submitForm(1) + } + }) +} + +const handleReject = () => { + uni.showModal({ + title: '纭鎿嶄綔', + content: '纭畾瑕侀┏鍥炴瀹℃壒鍚楋紵', + success: (res) => { + if (res.confirm) submitForm(2) + } + }) +} +// 鍘熷鑺傜偣鏁版嵁锛堢敤浜庢彁浜ら�昏緫锛� +const activities = ref([]) +</script> + +<style scoped lang="scss"> +.approve-page { + min-height: 100vh; + background: #f8f9fa; + padding-bottom: 80px; +} + +.header { + display: flex; + align-items: center; + background: #fff; + padding: 16px 20px; + border-bottom: 1px solid #f0f0f0; + position: sticky; + top: 0; + z-index: 100; +} + +.title { + flex: 1; + text-align: center; + font-size: 18px; + font-weight: 600; + color: #333; +} + +.application-info { + background: #fff; + margin: 16px; + border-radius: 12px; + overflow: hidden; +} + +.info-header { + padding: 16px; + border-bottom: 1px solid #f0f0f0; + background: #f8f9fa; +} + +.info-title { + font-size: 16px; + font-weight: 600; + color: #333; +} + +.info-content { + padding: 16px; +} + +.info-row { + display: flex; + align-items: center; + margin-bottom: 12px; + + &:last-child { + margin-bottom: 0; + } +} + +.info-label { + font-size: 14px; + color: #666; + width: 80px; + flex-shrink: 0; +} + +.info-value { + font-size: 14px; + color: #333; + flex: 1; +} + +.approval-process { + background: #fff; + margin: 16px; + border-radius: 12px; + overflow: hidden; +} + +.process-header { + padding: 16px; + border-bottom: 1px solid #f0f0f0; + background: #f8f9fa; +} + +.process-title { + font-size: 16px; + font-weight: 600; + color: #333; +} + +.process-steps { + padding: 20px; +} + +.process-step { + display: flex; + position: relative; + margin-bottom: 24px; + + &:last-child { + margin-bottom: 0; + + .step-line { + display: none; + } + } +} + +.step-indicator { + display: flex; + flex-direction: column; + align-items: center; + margin-right: 16px; +} + +.step-dot { + width: 32px; + height: 32px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + font-weight: 600; + position: relative; + z-index: 2; +} + +.process-step.completed .step-dot { + background: #52c41a; + color: #fff; +} + +.process-step.current .step-dot { + background: #1890ff; + color: #fff; + animation: pulse 2s infinite; +} + +.process-step.pending .step-dot { + background: #d9d9d9; + color: #999; +} + +.step-line { + width: 2px; + height: 40px; + background: #d9d9d9; + margin-top: 8px; +} + +.process-step.completed .step-line { + background: #52c41a; +} + +.process-step.rejected .step-dot { + background: #ff4d4f; + color: #fff; +} +.process-step.rejected .step-line { + background: #ff4d4f; +} + +.step-content { + flex: 1; + padding-top: 4px; +} + +.step-info { + margin-bottom: 8px; +} + +.step-title { + font-size: 16px; + font-weight: 600; + color: #333; + display: block; + margin-bottom: 4px; +} + +.step-approver { + font-size: 14px; + color: #666; + display: block; + margin-bottom: 4px; +} + +.step-time { + font-size: 12px; + color: #999; + display: block; +} + +.step-opinion { + background: #f8f9fa; + padding: 12px; + border-radius: 8px; + border-left: 4px solid #52c41a; +} + +.opinion-label { + font-size: 12px; + color: #666; + display: block; + margin-bottom: 4px; +} + +.opinion-content { + font-size: 14px; + color: #333; + line-height: 1.5; +} + +.approval-input { + background: #fff; + margin: 16px; + border-radius: 12px; + overflow: hidden; +} + +.input-header { + padding: 16px; + border-bottom: 1px solid #f0f0f0; + background: #f8f9fa; +} + +.input-title { + font-size: 16px; + font-weight: 600; + color: #333; +} + +.input-content { + padding: 16px; +} + +.footer-actions { + position: fixed; + left: 0; + right: 0; + bottom: 0; + background: #fff; + display: flex; + justify-content: space-around; + align-items: center; + padding: 16px; + box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); + z-index: 1000; +} + +.reject-btn { + width: 120px; + background: #ff4d4f; + color: #fff; + border: none; +} + +.approve-btn { + width: 120px; + background: #52c41a; + color: #fff; + border: none; +} + +@keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); + } + 70% { + box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); + } +} +.signature-section { + background: #fff; + padding: 12px 16px 16px; + border-top: 1px solid #f0f0f0; +} +.signature-header { + margin-bottom: 8px; +} +.signature-title { + font-size: 14px; + font-weight: 600; + color: #333; +} +.signature-box { + width: 100%; + height: 180px; + background: #fff; + border: 1px dashed #d9d9d9; + border-radius: 8px; + overflow: hidden; +} +.signature-actions { + margin-top: 8px; + display: flex; + justify-content: flex-end; +} +</style> \ No newline at end of file -- Gitblit v1.9.3