| | |
| | | <view class="header-card"> |
| | | <view class="case-header"> |
| | | <view class="hospital-info"> |
| | | <image :src="caseDetail.hospitalLogo" mode="aspectFit" class="hospital-logo" /> |
| | | <image |
| | | :src="caseDetail.hospitalLogo" |
| | | mode="aspectFit" |
| | | class="hospital-logo" |
| | | /> |
| | | <view class="hospital-details"> |
| | | <text class="hospital-name">{{ caseDetail.hospitalName }}</text> |
| | | <text class="case-type">{{ caseDetail.caseType }}</text> |
| | | <text class="hospital-name">{{ |
| | | caseDetail.treatmenthospitalname || "未填写治疗医院" |
| | | }}</text> |
| | | <text class="case-type">{{ |
| | | caseDetail.donorNo ? "器官捐献案例" : "案例详情" |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="case-status" :class="caseDetail.status"> |
| | | {{ caseDetail.statusText }} |
| | | <view |
| | | class="case-status" |
| | | :class="getStatusClass(caseDetail.reportStatus)" |
| | | > |
| | | {{ getStatusText(caseDetail.reportStatus) }} |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <view class="case-basic-info"> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <text class="label">捐献编号</text> |
| | | <text class="value">{{ caseDetail.donorNo }}</text> |
| | | <text class="label">案例编号</text> |
| | | <text class="value">{{ caseDetail.caseNo || "未生成" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">上报时间</text> |
| | | <text class="value">{{ caseDetail.reportTime }}</text> |
| | | <text class="value">{{ |
| | | formatDateTime(caseDetail.reporttime) |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | |
| | | <!-- 选项卡导航 --> |
| | | <view class="tab-navigation"> |
| | | <text |
| | | v-for="tab in tabs" |
| | | <text |
| | | v-for="tab in tabs" |
| | | :key="tab.id" |
| | | :class="{ active: activeTab === tab.id }" |
| | | @tap="switchTab(tab.id)" |
| | |
| | | <view class="info-grid"> |
| | | <view class="info-item"> |
| | | <text class="label">姓名</text> |
| | | <text class="value">{{ caseDetail.donorName }}</text> |
| | | <text class="value">{{ caseDetail.name || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">性别</text> |
| | | <text class="value">{{ caseDetail.gender }}</text> |
| | | <text class="value">{{ getGenderText(caseDetail.sex) }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">年龄</text> |
| | | <text class="value">{{ caseDetail.age }}岁</text> |
| | | <text class="value" |
| | | >{{ caseDetail.age || "0" }} |
| | | {{ getAgeUnitText(caseDetail.ageunit) }}</text |
| | | > |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">证件号码</text> |
| | | <text class="value">{{ caseDetail.idCardNo }}</text> |
| | | <text class="value">{{ caseDetail.idcardno || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">血型</text> |
| | | <text class="value">{{ caseDetail.bloodType }}</text> |
| | | <text class="value">{{ |
| | | getBloodTypeText(caseDetail.bloodType) |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">民族</text> |
| | | <text class="value">{{ caseDetail.nation }}</text> |
| | | <text class="value">{{ caseDetail.nation || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">国籍</text> |
| | | <text class="value">{{ caseDetail.nationality || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">籍贯</text> |
| | | <text class="value">{{ caseDetail.nativeplace || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">学历</text> |
| | | <text class="value">{{ caseDetail.education || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">职业</text> |
| | | <text class="value">{{ caseDetail.occupation || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item full-width"> |
| | | <text class="label">住址</text> |
| | | <text class="value">{{ caseDetail.address }}</text> |
| | | <text class="label">户籍地址</text> |
| | | <text class="value">{{ |
| | | getFullRegisterAddress() || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item full-width"> |
| | | <text class="label">现住地址</text> |
| | | <text class="value">{{ |
| | | getFullResidenceAddress() || "未填写" |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | <view class="info-content"> |
| | | <view class="info-group"> |
| | | <text class="group-title">疾病诊断</text> |
| | | <text class="group-content">{{ caseDetail.diagnosis }}</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.diagnosisname || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">病情概况</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.illnessoverview || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">病人状况</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.patientstate || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">住院号</text> |
| | | <text class="group-content">{{ caseDetail.inpatientNo }}</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.inpatientno || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">所在科室</text> |
| | | <text class="group-content">{{ caseDetail.departmentName }}</text> |
| | | <text class="group-title">GCS评分</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.gcsScore || "未评估" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">传染病情况</text> |
| | | <text class="group-content">{{ caseDetail.infectiousDisease || '无' }}</text> |
| | | <text class="group-content" |
| | | >{{ caseDetail.infectious || "无" |
| | | }}{{ |
| | | caseDetail.infectiousOther |
| | | ? `(${caseDetail.infectiousOther})` |
| | | : "" |
| | | }}</text |
| | | > |
| | | </view> |
| | | <view class="info-group"> |
| | | <text class="group-title">Rh阴性</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.rhYin === "1" ? "是" : "否" |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 捐献流程信息 --> |
| | | <view v-if="activeTab === 'process'" class="info-section fade-in-up"> |
| | | <!-- 医院与联系信息 --> |
| | | <view v-if="activeTab === 'contact'" class="info-section fade-in-up"> |
| | | <view class="section-card"> |
| | | <view class="section-header"> |
| | | <text class="section-title">捐献流程信息</text> |
| | | <text class="section-title">医院与联系信息</text> |
| | | </view> |
| | | <view class="process-timeline"> |
| | | <view class="timeline-item" v-for="step in processSteps" :key="step.id"> |
| | | <view class="timeline-marker" :class="{ active: step.completed }"></view> |
| | | <view class="timeline-content"> |
| | | <text class="step-title">{{ step.title }}</text> |
| | | <text class="step-time" v-if="step.time">{{ step.time }}</text> |
| | | <text class="step-person" v-if="step.person">经办人:{{ step.person }}</text> |
| | | <view class="info-grid"> |
| | | <view class="info-item full-width"> |
| | | <text class="label">治疗医院</text> |
| | | <text class="value">{{ |
| | | caseDetail.treatmenthospitalname || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">治疗科室</text> |
| | | <text class="value">{{ |
| | | caseDetail.treatmentdeptname || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">上报医院</text> |
| | | <text class="value">{{ caseDetail.toHospital || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item full-width"> |
| | | <text class="label">联系电话</text> |
| | | <text class="value">{{ caseDetail.phone || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">信息员</text> |
| | | <text class="value">{{ caseDetail.infoName || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">信息员编号</text> |
| | | <text class="value">{{ caseDetail.infoNo || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">ICU评估医生</text> |
| | | <text class="value">{{ caseDetail.icuDoctor || "未填写" }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">ICU医生电话</text> |
| | | <text class="value">{{ |
| | | caseDetail.icuDoctorPhone || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">协调员</text> |
| | | <text class="value">{{ |
| | | caseDetail.coordinatorName || "未填写" |
| | | }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="label">协调员编号</text> |
| | | <text class="value">{{ |
| | | caseDetail.coordinatorNo || "未填写" |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 转运信息 --> |
| | | <view v-if="activeTab === 'transport'" class="info-section fade-in-up"> |
| | | <view class="section-card"> |
| | | <view class="section-header"> |
| | | <view |
| | | style=" |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | " |
| | | > |
| | | <text class="section-title">转运信息</text> |
| | | <!-- 转运操作按钮 --> |
| | | <view |
| | | v-if="caseDetail.reportStatus === '3'" |
| | | style="display: flex; gap: 20rpx" |
| | | > |
| | | <button |
| | | v-if="caseDetail.isTransport === '2' && !hasTransport" |
| | | class="small-btn primary" |
| | | @tap.stop="createTransport" |
| | | > |
| | | 创建转运单 |
| | | </button> |
| | | <button |
| | | v-if="hasTransport" |
| | | class="small-btn secondary" |
| | | @tap.stop="viewTransportDetail" |
| | | > |
| | | 查看转运单 |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </view> + |
| | | </view> |
| | | |
| | | <view class="info-content"> |
| | | <view class="info-group"> |
| | | <text class="group-title">是否需要转运</text> |
| | | <text class="group-content">{{ |
| | | caseDetail.isTransport === "2" ? "需要" : "不需要" |
| | | }}</text> |
| | | </view> |
| | | |
| | | <!-- 有转运信息时显示 --> |
| | | <view |
| | | v-if="hasTransport && caseDetail.serviceTransport" |
| | | class="transport-info" |
| | | > |
| | | <view |
| | | class="info-group" |
| | | v-for="transport in caseDetail.serviceTransport" |
| | | :key="transport.id" |
| | | > |
| | | <view class="sub-group"> |
| | | <text class="sub-label">转运单号:</text> |
| | | <text class="sub-value">{{ |
| | | transport.reportId || transport.id |
| | | }}</text> |
| | | </view> |
| | | <view class="sub-group"> |
| | | <text class="sub-label">出发地点:</text> |
| | | <text class="sub-value">{{ |
| | | transport.transportStartPlace |
| | | }}</text> |
| | | </view> |
| | | <view class="sub-group"> |
| | | <text class="sub-label">出发时间:</text> |
| | | <text class="sub-value">{{ |
| | | formatDateTime(transport.transportStartTime) |
| | | }}</text> |
| | | </view> |
| | | <view class="sub-group"> |
| | | <text class="sub-label">负责协调员:</text> |
| | | <text class="sub-value">{{ transport.contactPerson }}</text> |
| | | </view> |
| | | <view class="sub-group"> |
| | | <text class="sub-label">转运状态:</text> |
| | | <text |
| | | class="sub-value status" |
| | | :class="getTransportStatusClass(transport.transitStatus)" |
| | | > |
| | | {{ getTransportStatusText(transport.transitStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="sub-group" v-if="transport.doctor"> |
| | | <text class="sub-label">急诊科医生:</text> |
| | | <text class="sub-value">{{ transport.doctor }}</text> |
| | | </view> |
| | | <view class="sub-group" v-if="transport.nurse"> |
| | | <text class="sub-label">护士:</text> |
| | | <text class="sub-value">{{ transport.nurse }}</text> |
| | | </view> |
| | | <view class="sub-group" v-if="transport.driver"> |
| | | <text class="sub-label">驾驶员:</text> |
| | | <text class="sub-value">{{ transport.driver }}</text> |
| | | </view> |
| | | <view class="sub-group" v-if="transport.icuDoctor"> |
| | | <text class="sub-label">ICU评估医生:</text> |
| | | <text class="sub-value">{{ transport.icuDoctor }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 无转运信息但需要转运 --> |
| | | <view |
| | | v-else-if="caseDetail.isTransport === '2'" |
| | | class="transport-info" |
| | | > |
| | | <view class="empty-transport"> |
| | | <text>该案例需要转运,但尚未创建转运单</text> |
| | | <text |
| | | v-if="caseDetail.reportStatus !== '3'" |
| | | style="color: #f0ad4e; font-size: 24rpx; margin-top: 10rpx" |
| | | > |
| | | 需先审批同意才能创建转运单 |
| | | </text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 无需转运 --> |
| | | <view v-else class="transport-info"> |
| | | <view class="empty-transport"> |
| | | <text>该案例无需转运</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="action-bar"> |
| | | <button class="action-btn secondary" @tap="goBack">返回</button> |
| | | <button class="action-btn primary" v-if="caseDetail.status === 'reported'" |
| | | @tap="withdrawCase">撤回案例</button> |
| | | <button class="action-btn primary" v-else @tap="contactCoordinator">联系协调员</button> |
| | | |
| | | <!-- 根据状态显示不同操作 --> |
| | | <button |
| | | v-if=" |
| | | caseDetail.reportStatus === '1' || caseDetail.reportStatus === '2' |
| | | " |
| | | class="action-btn primary" |
| | | @tap="handleEdit" |
| | | > |
| | | 编辑案例 |
| | | </button> |
| | | |
| | | <!-- <button v-if="canDelete" |
| | | class="action-btn error" |
| | | @tap="handleDelete"> |
| | | 删除案例 |
| | | </button> --> |
| | | </view> |
| | | |
| | | <!-- 加载状态 --> |
| | | <u-loading-icon v-if="loading" :show="loading" text="加载中..." /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted } from 'vue' |
| | | import { ref, computed, onMounted } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { useDict } from "@/utils/dict"; |
| | | |
| | | import { onLoad } from '@dcloudio/uni-app' |
| | | // 字典数据 |
| | | const dict = ref({}); |
| | | |
| | | const caseDetail = ref({ |
| | | id: 1, |
| | | donorNo: 'DON20240325001', |
| | | hospitalName: '青岛镜湖医院', |
| | | hospitalLogo: '/static/hospital/kiang-wu.jpg', |
| | | caseType: '器官捐献案例', |
| | | donorName: '张三', |
| | | idCardNo: '370203198510123456', |
| | | gender: '男', |
| | | age: 38, |
| | | bloodType: 'A型', |
| | | nation: '汉族', |
| | | address: '山东省青岛市市南区香港中路100号', |
| | | diagnosis: '脑外伤导致脑死亡', |
| | | inpatientNo: 'ZY20240325001', |
| | | departmentName: '神经外科', |
| | | infectiousDisease: '无', |
| | | reportTime: '2024-03-25 09:30:00', |
| | | status: 'reported', |
| | | statusText: '已上报' |
| | | }) |
| | | // 数据 |
| | | const caseDetail = ref({}); |
| | | const loading = ref(false); |
| | | const activeTab = ref("basic"); |
| | | const caseId = ref(null); |
| | | |
| | | // 选项卡 |
| | | const tabs = ref([ |
| | | { id: 'basic', label: '基本信息' }, |
| | | { id: 'medical', label: '医疗信息' }, |
| | | { id: 'process', label: '流程信息' } |
| | | ]) |
| | | { id: "basic", label: "基本信息" }, |
| | | { id: "medical", label: "医疗信息" }, |
| | | { id: "contact", label: "联系信息" }, |
| | | { id: "transport", label: "转运信息" }, |
| | | ]); |
| | | |
| | | const activeTab = ref('basic') |
| | | // 计算属性 |
| | | const hasTransport = computed(() => { |
| | | return caseDetail.value.serviceTransport; |
| | | }); |
| | | |
| | | const processSteps = ref([ |
| | | { id: 1, title: '案例上报', completed: true, time: '2024-03-25 09:30', person: '李医生' }, |
| | | { id: 2, title: '信息审核', completed: false, time: null, person: null }, |
| | | { id: 3, title: '家属沟通', completed: false, time: null, person: null }, |
| | | { id: 4, title: '捐献确认', completed: false, time: null, person: null }, |
| | | { id: 5, title: '器官获取', completed: false, time: null, person: null } |
| | | ]) |
| | | const canDelete = computed(() => { |
| | | // 允许删除未审批或已驳回的案例 |
| | | return ( |
| | | caseDetail.value.reportStatus === "1" || |
| | | caseDetail.value.reportStatus === "2" || |
| | | caseDetail.value.reportStatus === "4" |
| | | ); |
| | | }); |
| | | |
| | | onLoad((options) => { |
| | | onLoad(async (options) => { |
| | | if (options.id) { |
| | | // 根据ID加载案例详情 |
| | | loadCaseDetail(options.id) |
| | | caseId.value = options.id; |
| | | // 获取字典数据 |
| | | dict.value = await useDict( |
| | | "sys_user_sex", |
| | | "sys_BloodType", |
| | | "sys_IDType", |
| | | "sys_AgeUnit", |
| | | ); |
| | | // 加载案例详情 |
| | | await loadCaseDetail(options.id); |
| | | } |
| | | }) |
| | | }); |
| | | |
| | | const switchTab = (tabId) => { |
| | | activeTab.value = tabId |
| | | } |
| | | // 加载案例详情 |
| | | const loadCaseDetail = async (id) => { |
| | | loading.value = true; |
| | | try { |
| | | const res = await uni.$uapi.get( |
| | | `/project/donatebaseinforeport/getInfo/${id}`, |
| | | ); |
| | | |
| | | const goBack = () => { |
| | | uni.navigateBack() |
| | | } |
| | | if (res.data) { |
| | | caseDetail.value = res.data; |
| | | |
| | | const withdrawCase = () => { |
| | | uni.showModal({ |
| | | title: '确认撤回', |
| | | content: '确定要撤回这个捐献案例吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | uni.showToast({ title: '撤回成功', icon: 'success' }) |
| | | setTimeout(() => { |
| | | uni.navigateBack() |
| | | }, 1500) |
| | | } |
| | | // 如果状态是"已上报"(1),自动更新为"已阅读"(2) |
| | | // if (caseDetail.value.reportStatus === '1') { |
| | | // await updateCaseStatus('2') |
| | | // } |
| | | } else { |
| | | throw new Error(res.msg || "数据加载失败"); |
| | | } |
| | | }) |
| | | } |
| | | } catch (error) { |
| | | console.error("加载案例详情失败:", error); |
| | | uni.showToast({ |
| | | title: "数据加载失败,请重试", |
| | | icon: "none", |
| | | }); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const contactCoordinator = () => { |
| | | uni.makePhoneCall({ |
| | | phoneNumber: '13800138000' |
| | | }) |
| | | } |
| | | // 更新案例状态 |
| | | const updateCaseStatus = async (newStatus) => { |
| | | try { |
| | | const updateData = { |
| | | ...caseDetail.value, |
| | | reportStatus: newStatus, |
| | | updateTime: new Date().toISOString().replace("T", " ").substring(0, 19), |
| | | updateBy: "移动端用户", |
| | | }; |
| | | |
| | | const loadCaseDetail = (id) => { |
| | | // 模拟API调用 |
| | | console.log('加载案例详情:', id) |
| | | } |
| | | const res = await uni.$uapi.post( |
| | | "/project/donatebaseinforeport/edit", |
| | | updateData, |
| | | ); |
| | | |
| | | if (res.code === 200) { |
| | | caseDetail.value.reportStatus = newStatus; |
| | | } |
| | | } catch (error) { |
| | | console.error("更新状态失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 获取状态样式 |
| | | const getStatusClass = (status) => { |
| | | const map = { |
| | | 1: "reported", |
| | | 2: "read", |
| | | 3: "agreed", |
| | | 4: "rejected", |
| | | }; |
| | | return map[status] || "reported"; |
| | | }; |
| | | |
| | | // 获取状态文本 |
| | | const getStatusText = (status) => { |
| | | const map = { |
| | | 1: "已上报", |
| | | 2: "已阅读", |
| | | 3: "已同意", |
| | | 4: "已驳回", |
| | | }; |
| | | return map[status] || "已上报"; |
| | | }; |
| | | |
| | | // 获取性别文本 |
| | | const getGenderText = (gender) => { |
| | | if (!dict.value.sys_user_sex) return gender; |
| | | const genderItem = dict.value.sys_user_sex.find( |
| | | (item) => item.dictValue === gender, |
| | | ); |
| | | return genderItem ? genderItem.dictLabel : gender; |
| | | }; |
| | | |
| | | // 获取血型文本 |
| | | const getBloodTypeText = (bloodType) => { |
| | | if (!dict.value.sys_BloodType) return bloodType; |
| | | const bloodTypeItem = dict.value.sys_BloodType.find( |
| | | (item) => item.dictValue === bloodType, |
| | | ); |
| | | return bloodTypeItem ? bloodTypeItem.dictLabel : bloodType; |
| | | }; |
| | | |
| | | // 获取年龄单位文本 |
| | | const getAgeUnitText = (ageunit) => { |
| | | if (!ageunit) return ""; |
| | | const unitMap = { |
| | | year: "岁", |
| | | month: "个月", |
| | | day: "天", |
| | | }; |
| | | return unitMap[ageunit] || ageunit; |
| | | }; |
| | | |
| | | // 获取完整户籍地址 |
| | | const getFullRegisterAddress = () => { |
| | | const { |
| | | registerprovincename, |
| | | registercityname, |
| | | registertownname, |
| | | registercommunityname, |
| | | registeraddress, |
| | | } = caseDetail.value; |
| | | |
| | | const parts = [ |
| | | registerprovincename, |
| | | registercityname, |
| | | registertownname, |
| | | registercommunityname, |
| | | registeraddress, |
| | | ]; |
| | | return parts.filter((part) => part).join(""); |
| | | }; |
| | | |
| | | // 获取完整现住地址 |
| | | const getFullResidenceAddress = () => { |
| | | const { |
| | | residenceprovincename, |
| | | residencecountyname, |
| | | residencetownname, |
| | | residencecommunityname, |
| | | residenceaddress, |
| | | } = caseDetail.value; |
| | | |
| | | const parts = [ |
| | | residenceprovincename, |
| | | residencecountyname, |
| | | residencetownname, |
| | | residencecommunityname, |
| | | residenceaddress, |
| | | ]; |
| | | return parts.filter((part) => part).join(""); |
| | | }; |
| | | |
| | | // 获取转运状态文本 |
| | | const getTransportStatusText = (status) => { |
| | | const map = { |
| | | 1: "待转运", |
| | | 2: "转运中", |
| | | 3: "转运完成", |
| | | 4: "转运取消", |
| | | 5: "暂存", |
| | | }; |
| | | return map[status] || "未知"; |
| | | }; |
| | | |
| | | // 获取转运状态样式 |
| | | const getTransportStatusClass = (status) => { |
| | | const map = { |
| | | 1: "pending", |
| | | 2: "transporting", |
| | | 3: "completed", |
| | | 4: "cancelled", |
| | | 5: "draft", |
| | | }; |
| | | return map[status] || "pending"; |
| | | }; |
| | | |
| | | // 格式化日期时间 |
| | | const formatDateTime = (dateTime) => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace("T", " ").substring(0, 16); |
| | | }; |
| | | |
| | | // 选项卡切换 |
| | | const switchTab = (tabId) => { |
| | | activeTab.value = tabId; |
| | | }; |
| | | |
| | | // 返回 |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // 编辑案例 |
| | | const handleEdit = () => { |
| | | uni.navigateTo({ |
| | | url: `/pages/case/CaseDetails?id=${caseId.value}&edit=true`, |
| | | }); |
| | | }; |
| | | |
| | | // 删除案例 |
| | | const handleDelete = () => { |
| | | uni.showModal({ |
| | | title: "确认删除", |
| | | content: `确定要删除案例 ${caseDetail.value.caseNo} 吗?`, |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | try { |
| | | const result = await uni.$uapi.delete( |
| | | `/project/donatebaseinforeport/${caseId.value}`, |
| | | ); |
| | | if (result.code === 200) { |
| | | uni.showToast({ title: "删除成功", icon: "success" }); |
| | | setTimeout(() => { |
| | | uni.navigateBack(); |
| | | }, 1500); |
| | | } else { |
| | | uni.showToast({ title: result.msg || "删除失败", icon: "none" }); |
| | | } |
| | | } catch (error) { |
| | | console.error("删除失败:", error); |
| | | uni.showToast({ title: "删除失败", icon: "none" }); |
| | | } |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // 创建转运单 |
| | | const createTransport = () => { |
| | | if (caseDetail.value.reportStatus !== "3") { |
| | | uni.showToast({ title: "案例需先审批同意", icon: "none" }); |
| | | return; |
| | | } |
| | | |
| | | uni.navigateTo({ |
| | | url: `/pages/transport/create?caseId=${caseId.value}&caseNo=${caseDetail.value.caseNo}`, |
| | | }); |
| | | }; |
| | | |
| | | // 查看转运单详情 |
| | | const viewTransportDetail = () => { |
| | | if (hasTransport.value && caseDetail.value.serviceTransport[0]) { |
| | | const transport = caseDetail.value.serviceTransport[0]; |
| | | uni.navigateTo({ |
| | | url: `/pages/transport/detail?id=${transport.id}`, |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | min-height: 100vh; |
| | | background: linear-gradient(135deg, #fafdff 0%, #e3f0ff 100%); |
| | | padding: 20rpx; |
| | | padding-bottom: 120rpx; /* 为操作栏留出空间 */ |
| | | } |
| | | |
| | | .header-card { |
| | |
| | | border-radius: 32rpx; |
| | | padding: 40rpx 30rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 12px 48px 0 rgba(0, 113, 227, 0.10); |
| | | box-shadow: 0 12px 48px 0 rgba(0, 113, 227, 0.1); |
| | | border: 1.5px solid #e5eaf0; |
| | | } |
| | | |
| | |
| | | height: 80rpx; |
| | | border-radius: 16rpx; |
| | | margin-right: 20rpx; |
| | | background: #f5f5f7; |
| | | } |
| | | |
| | | .hospital-details { |
| | |
| | | font-weight: 600; |
| | | color: #1d1d1f; |
| | | margin-bottom: 8rpx; |
| | | max-width: 400rpx; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .case-type { |
| | |
| | | border-radius: 20rpx; |
| | | font-size: 24rpx; |
| | | font-weight: 500; |
| | | |
| | | |
| | | &.reported { |
| | | background: rgba(255, 149, 0, 0.1); |
| | | color: #ff9500; |
| | | } |
| | | |
| | | |
| | | &.read { |
| | | background: rgba(0, 122, 255, 0.1); |
| | | color: #007aff; |
| | | } |
| | | |
| | | |
| | | &.agreed { |
| | | background: rgba(52, 199, 89, 0.1); |
| | | color: #34c759; |
| | | } |
| | | |
| | | &.rejected { |
| | | background: rgba(255, 59, 48, 0.1); |
| | | color: #ff3b30; |
| | | } |
| | | } |
| | | |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | |
| | | .label { |
| | | font-size: 24rpx; |
| | | color: #86868b; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | color: #1d1d1f; |
| | |
| | | padding: 8rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.05); |
| | | overflow-x: auto; |
| | | white-space: nowrap; |
| | | |
| | | &::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .tab-item { |
| | | flex: 1; |
| | | min-width: 140rpx; |
| | | text-align: center; |
| | | padding: 20rpx; |
| | | font-size: 28rpx; |
| | | color: #86868b; |
| | | transition: all 0.3s ease; |
| | | |
| | | |
| | | &.active { |
| | | color: #007aff; |
| | | background: #f0f7ff; |
| | |
| | | border-radius: 32rpx; |
| | | padding: 40rpx 30rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 12px 48px 0 rgba(0, 113, 227, 0.10); |
| | | box-shadow: 0 12px 48px 0 rgba(0, 113, 227, 0.1); |
| | | border: 1.5px solid #e5eaf0; |
| | | } |
| | | |
| | |
| | | .info-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | |
| | | &.full-width { |
| | | grid-column: 1 / -1; |
| | | } |
| | | |
| | | |
| | | .label { |
| | | font-size: 24rpx; |
| | | color: #86868b; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | color: #1d1d1f; |
| | | font-weight: 500; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | |
| | | .info-content { |
| | | .info-group { |
| | | margin-bottom: 32rpx; |
| | | |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | padding-bottom: 0; |
| | | border-bottom: none; |
| | | } |
| | | } |
| | | |
| | | |
| | | .group-title { |
| | | font-size: 26rpx; |
| | | color: #86868b; |
| | | margin-bottom: 12rpx; |
| | | display: block; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | |
| | | .group-content { |
| | | font-size: 28rpx; |
| | | color: #1d1d1f; |
| | |
| | | } |
| | | } |
| | | |
| | | .process-timeline { |
| | | position: relative; |
| | | padding-left: 40rpx; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 15rpx; |
| | | top: 0; |
| | | bottom: 0; |
| | | width: 2rpx; |
| | | background: #e5e5e7; |
| | | /* 转运信息样式 */ |
| | | .transport-info { |
| | | .info-group { |
| | | border: 2rpx solid #f0f0f0; |
| | | border-radius: 12rpx; |
| | | padding: 20rpx; |
| | | margin-bottom: 20rpx; |
| | | background: #fafafa; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .sub-group { |
| | | display: flex; |
| | | margin-bottom: 12rpx; |
| | | align-items: center; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .sub-label { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | min-width: 160rpx; |
| | | margin-right: 10rpx; |
| | | } |
| | | |
| | | .sub-value { |
| | | font-size: 26rpx; |
| | | color: #303133; |
| | | flex: 1; |
| | | |
| | | &.status { |
| | | padding: 4rpx 12rpx; |
| | | border-radius: 6rpx; |
| | | font-size: 24rpx; |
| | | |
| | | &.pending { |
| | | background: rgba(240, 173, 78, 0.1); |
| | | color: #f0ad4e; |
| | | } |
| | | |
| | | &.transporting { |
| | | background: rgba(0, 122, 255, 0.1); |
| | | color: #007aff; |
| | | } |
| | | |
| | | &.completed { |
| | | background: rgba(76, 217, 100, 0.1); |
| | | color: #4cd964; |
| | | } |
| | | |
| | | &.cancelled { |
| | | background: rgba(220, 223, 230, 0.1); |
| | | color: #dcdfe6; |
| | | } |
| | | |
| | | &.draft { |
| | | background: rgba(144, 147, 153, 0.1); |
| | | color: #909399; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .empty-transport { |
| | | text-align: center; |
| | | padding: 40rpx 0; |
| | | color: #909399; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | |
| | | .timeline-item { |
| | | position: relative; |
| | | margin-bottom: 40rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .timeline-marker { |
| | | position: absolute; |
| | | left: -40rpx; |
| | | top: 8rpx; |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | border-radius: 50%; |
| | | background: #e5e5e7; |
| | | border: 4rpx solid #fff; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
| | | |
| | | &.active { |
| | | background: #007aff; |
| | | } |
| | | } |
| | | |
| | | .timeline-content { |
| | | padding-bottom: 20rpx; |
| | | } |
| | | |
| | | .step-title { |
| | | display: block; |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #1d1d1f; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .step-time, .step-person { |
| | | display: block; |
| | | /* 小型按钮 */ |
| | | .small-btn { |
| | | padding: 8rpx 20rpx; |
| | | font-size: 24rpx; |
| | | color: #86868b; |
| | | margin-bottom: 4rpx; |
| | | border-radius: 6rpx; |
| | | border: none; |
| | | |
| | | &.primary { |
| | | background: #007aff; |
| | | color: #fff; |
| | | } |
| | | |
| | | &.secondary { |
| | | background: #ecf5ff; |
| | | color: #007aff; |
| | | border: 1rpx solid #007aff; |
| | | } |
| | | |
| | | &:active { |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | |
| | | .action-bar { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | padding: 40rpx 0; |
| | | background: transparent; |
| | | padding: 20rpx 0; |
| | | background: #fff; |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | padding: 20rpx 30rpx; |
| | | padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); |
| | | box-shadow: 0 -2rpx 20rpx rgba(0, 0, 0, 0.08); |
| | | z-index: 100; |
| | | } |
| | | |
| | | .action-btn { |
| | |
| | | font-weight: 600; |
| | | border: none; |
| | | transition: all 0.3s ease; |
| | | |
| | | |
| | | &.secondary { |
| | | background: #f5f5f7; |
| | | color: #1d1d1f; |
| | | |
| | | |
| | | &:active { |
| | | background: #e5e5e7; |
| | | } |
| | | } |
| | | |
| | | |
| | | &.primary { |
| | | background: linear-gradient(90deg, #0071e3 0%, #2997ff 100%); |
| | | color: #fff; |
| | | |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | |
| | | &.success { |
| | | background: linear-gradient(90deg, #34c759 0%, #4cd964 100%); |
| | | color: #fff; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | |
| | | &.error { |
| | | background: linear-gradient(90deg, #ff3b30 0%, #ff5a5a 100%); |
| | | color: #fff; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | </style> |
| | | </style> |