Files
xk-client-wx/subPackages/transfer/transfer-message.vue
2026-05-15 16:42:32 +08:00

366 lines
9.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container safe-area-inset-bottom">
<view class="header">
<text class="title">转诊消息</text>
</view>
<!-- 空页仅在非加载中且列表为空时显示 -->
<view class="empty" v-if="!loading && transferList.length === 0">
<image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/empty/orders.png" mode="aspectFit" @error="handleImageError"></image>
<view class="word">暂无转诊消息~</view>
</view>
<!-- 转诊消息列表 -->
<!-- 修复使用显式 v-if 替代 v-else确保逻辑清晰 -->
<view class="list-container" v-if="transferList.length > 0">
<!-- 修复:key 绑定改为简单的 item.id解决 wx:key 警告 -->
<view class="list-item" v-for="(item, index) in transferList" :key="item.id">
<view class="card">
<view class="card-header">
<view class="header-icon">
<text class="iconfont icon-mendian"></text>
</view>
<view class="header-title">转诊处方</view>
<!-- 修复不直接调用方法而是使用预处理好的属性 -->
<view class="status-tag" :class="item.statusClass">
{{ item.statusText }}
</view>
</view>
<view class="card-body">
<view class="info-row" v-if="item.transfer_store">
<view class="info-label">转诊诊所</view>
<view class="info-value">{{ item.transfer_store.name || '未知诊所' }}</view>
</view>
<view class="info-row" v-if="item.delegate_store">
<view class="info-label">委托诊所</view>
<view class="info-value">{{ item.delegate_store.name || '未知诊所' }}</view>
</view>
<view class="info-row" v-if="item.prescription_no">
<view class="info-label">处方编号</view>
<view class="info-value">{{ item.prescription_no }}</view>
</view>
<view class="info-row" v-if="item.transfer_time">
<view class="info-label">转诊时间</view>
<!-- 优化同样使用预处理的时间字符串 -->
<view class="info-value">{{ item.transferTimeStr }}</view>
</view>
</view>
<!-- 仅在待确认状态显示操作按钮 -->
<view class="card-footer" v-if="item.status === 0">
<button class="reject-btn" @click="handleReject(item)">拒绝转诊</button>
<button class="agree-btn" @click="handleAgree(item)">同意转诊</button>
</view>
</view>
</view>
</view>
<view v-if="transferList.length > 0" class="loadmore">
<u-loadmore :status="status" />
</view>
</view>
</template>
<script>
import {
getTransferPrescriptionListApi,
agreeTransferPrescriptionApi,
rejectTransferPrescriptionApi
} from '@/request/api/transferPrescription'
export default {
data() {
return {
transferList: [],
loading: false,
status: 'nomore',
page: 1
}
},
onLoad() {
this.getTransferList()
},
// 如下拉刷新等场景可增加
onPullDownRefresh() {
this.getTransferList().finally(() => {
uni.stopPullDownRefresh()
})
},
methods: {
getStatusText(status) {
const statusMap = {
0: '待确认',
1: '已确认',
2: '已导入',
3: '已取消'
}
return statusMap[status] || '未知'
},
getStatusClass(status) {
const classMap = {
0: 'status-pending',
1: 'status-confirmed',
2: 'status-imported',
3: 'status-cancelled'
}
return classMap[status] || ''
},
formatTransferTime(time) {
if (!time) return '未知时间'
// 兼容时间戳(秒级)
if (!isNaN(time) && typeof time !== 'object') {
const date = new Date(Number(time) * 1000)
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
const h = String(date.getHours()).padStart(2, '0')
const mm = String(date.getMinutes()).padStart(2, '0')
return `${y}-${m}-${d} ${h}:${mm}`
}
return time
},
async getTransferList() {
this.loading = true
try {
const res = await getTransferPrescriptionListApi()
// 关键:请确认 res.data.result 是否为数组
// 如果后端返回的是 res.data.data请修改此处
if (res.data && res.data.code === 0) {
const list = res.data.result || []
// 核心修复:预处理数据,直接将 class 和 text 计算好放入 item 中
// 避免在 template 中使用函数调用导致小程序渲染异常
this.transferList = Array.isArray(list) ? list.map(item => {
return {
...item,
statusClass: this.getStatusClass(item.status),
statusText: this.getStatusText(item.status),
transferTimeStr: this.formatTransferTime(item.transfer_time)
}
}) : []
console.log('转诊列表加载成功:', this.transferList)
} else {
throw new Error(res.data.message || '获取数据失败')
}
} catch (error) {
console.error('获取转诊列表异常:', error)
uni.showToast({
title: error.message || '网络异常',
icon: 'none'
})
} finally {
this.loading = false
}
},
handleAgree(item) {
uni.showModal({
title: '提示',
content: '确定要同意该转诊申请吗?',
confirmColor: '#f97316',
success: async (res) => {
if (res.confirm) {
try {
const response = await agreeTransferPrescriptionApi({ id: item.id })
if (response.data.code === 0) {
uni.showToast({ title: '已同意', icon: 'success' })
// 跳转到咨询页面直接使用transfer_id传参
setTimeout(() => {
uni.redirectTo({
url: `/subPackages/transfer/transfer-consultation?transfer_id=${item.id}`,
fail: (err) => {
console.error('跳转失败:', err)
uni.showToast({ title: '跳转失败,请重试', icon: 'none' })
}
})
}, 1000)
} else {
uni.showToast({ title: response.data.message, icon: 'none' })
}
} catch (e) {
console.error('同意转诊异常:', e)
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
}
})
},
handleReject(item) {
uni.showModal({
title: '提示',
content: '确定要拒绝该转诊申请吗?',
confirmColor: '#64748b',
success: async (res) => {
if (res.confirm) {
try {
const response = await rejectTransferPrescriptionApi({ id: item.id })
if (response.data.code === 0) {
uni.showToast({ title: '已拒绝', icon: 'success' })
this.getTransferList()
} else {
uni.showToast({ title: response.data.message, icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
}
})
},
handleImageError(e) {
console.error('图片加载失败', e)
}
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100%;
min-height: 100vh;
background-color: #F8FAFC;
padding: 30rpx;
box-sizing: border-box;
}
.header {
margin-bottom: 30rpx;
.title {
font-size: 36rpx;
font-weight: bold;
color: #1e293b;
}
}
.empty {
padding-top: 200rpx;
text-align: center;
image {
width: 240rpx;
height: 240rpx;
}
.word {
margin-top: 20rpx;
color: #94a3b8;
font-size: 28rpx;
}
}
/* 确保列表容器有宽度,防止塌陷 */
.list-container {
width: 100%;
}
.list-item {
margin-bottom: 30rpx;
width: 100%;
}
.card {
background: #ffffff;
border-radius: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
overflow: hidden;
border: 1rpx solid #f1f5f9;
}
.card-header {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
background: #fff;
border-bottom: 1rpx solid #f1f5f9;
}
.header-icon {
width: 48rpx;
height: 48rpx;
background: #fff7ed;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
.iconfont {
color: #f97316;
font-size: 28rpx;
}
}
.header-title {
flex: 1;
font-size: 30rpx;
font-weight: 600;
color: #334155;
}
.status-tag {
padding: 6rpx 16rpx;
border-radius: 8rpx;
font-size: 22rpx;
}
.status-pending { background: #fef3c7; color: #d97706; }
.status-confirmed { background: #dcfce7; color: #16a34a; }
.status-imported { background: #dbeafe; color: #2563eb; }
.status-cancelled { background: #f1f5f9; color: #64748b; }
.card-body {
padding: 20rpx 30rpx;
}
.info-row {
display: flex;
padding: 12rpx 0;
font-size: 28rpx;
line-height: 1.4;
}
.info-label {
color: #64748b;
width: 150rpx;
flex-shrink: 0;
}
.info-value {
color: #1e293b;
word-break: break-all;
}
.card-footer {
padding: 24rpx 30rpx;
display: flex;
justify-content: flex-end;
gap: 20rpx;
border-top: 1rpx solid #f1f5f9;
background: #fafafa;
}
.agree-btn, .reject-btn {
margin: 0;
padding: 0 36rpx;
height: 64rpx;
line-height: 64rpx;
font-size: 26rpx;
border-radius: 32rpx;
}
.agree-btn {
background: #f97316;
color: #fff;
}
.reject-btn {
background: #fff;
color: #64748b;
border: 1rpx solid #cbd5e1;
}
.loadmore {
padding: 30rpx 0;
}
</style>