转诊方功能

This commit is contained in:
李琦
2026-02-07 09:42:08 +08:00
parent a130f428b9
commit d233a42754
9 changed files with 1072 additions and 6 deletions

View File

@@ -468,6 +468,13 @@
"navigationBarTitleText": "在线问诊",
"enablePullDownRefresh": false
}
},
{
"path": "transfer/transfer-message",
"style": {
"navigationBarTitleText": "转诊消息",
"enablePullDownRefresh": true
}
}
]
}

View File

@@ -85,6 +85,32 @@
</view>
</view>
<!-- 转诊消息 -->
<view class="list" @click="goTransfer">
<!-- 头像 -->
<view class="avator">
<view class="img">
<image src="/static/xx/ysxx.png" mode=""></image>
<!-- <image src="/static/xx/zhuanzhen.png" mode=""></image>-->
</view>
<u-badge size="default" v-if="transfer.num>=0" :count="transfer.num" :is-dot="transfer.num==0?true:false"
type="error" :offset="transfer.num>0?[-4,-8]:[0,0]"></u-badge>
</view>
<!-- 描述 -->
<view class="info">
<view class="infos_title">
<text class="infos">转诊消息</text>
<text class="time">{{ transfer.time }}</text>
</view>
<view class="preview" v-if="transfer.num>0">
您有{{ transfer.num }}条转诊消息待处理
</view>
<view class="preview" v-if="transfer.num==undefined || transfer.num==0">
暂无转诊消息
</view>
</view>
</view>
<!-- 模拟<u-divider>在线问诊</u-divider>效果-->
<!-- 标题 - 在线咨询 -->
@@ -157,6 +183,7 @@ import {
} from '../../request/api/api'
import {getSystemNoticeIndexApi} from '../../request/api/systemNotice'
import {getChatFriendsListApi} from "@/request/api/im";
import {getTransferPrescriptionListApi} from "@/request/api/transferPrescription";
import {checkDev} from "@/utils/utils";
import MessageNotification from "@/components/MessageNotification/MessageNotification.vue";
@@ -169,6 +196,10 @@ export default {
order: [],
system: [],
doctor: [],
transfer: {
num: 0,
time: ''
},
imChat: [],
onlineConsultationList: [], // 在线咨询列表 (type=1)
onlineReconsultationList: [], // 在线复诊列表 (type=3)
@@ -258,6 +289,12 @@ export default {
// console.log(res, 'res');
})
},
// 转诊消息
goTransfer() {
uni.navigateTo({
url: '/subPackages/transfer/transfer-message'
})
},
goChat(item, index) {
uni.navigateTo({
url: `/subPackages/chat/chat?room_id=${item.room_id}&nick_name=${item.nick_name}&user_id=${item.id}&avatar=${encodeURIComponent(item.avatar || '')}&room_status=${item.room_status || 0}`
@@ -292,10 +329,33 @@ export default {
const allChatList = res.data.result || []
// 根据type字段区分在线咨询和在线复诊
this.onlineConsultationList = allChatList.filter(item => item.type === 1 || !item.type) // type=1或未设置type的为在线咨询
this.onlineReconsultationList = allChatList.filter(item => item.type === 3) // type=3的为在线复诊
this.onlineReconsultationList = allChatList.filter(item => (item.type === 3 || item.type === 2)) // type=3的为在线复诊
// 保持imChat兼容性包含所有
this.imChat = allChatList
})
},
// 获取转诊消息列表
getTransferList() {
getTransferPrescriptionListApi().then((res) => {
if (res.data && res.data.code == 0) {
const transferList = res.data.result || []
// 统计待确认的转诊消息数量
const pendingCount = transferList.filter(item => item.status === 0).length
this.transfer.num = pendingCount
// 获取最新的转诊时间
if (transferList.length > 0) {
const latestTransfer = transferList[0]
if (latestTransfer.transfer_time) {
this.transfer.time = latestTransfer.transfer_time
} else if (latestTransfer.created_at) {
this.transfer.time = latestTransfer.created_at
}
}
}
}).catch((error) => {
console.error('获取转诊消息列表失败:', error)
})
}
},
mounted() {
@@ -305,10 +365,15 @@ export default {
this.order = []
this.system = []
this.doctor = []
this.transfer = {
num: 0,
time: ''
}
this.onlineConsultationList = []
this.onlineReconsultationList = []
this.getInfo()
this.getMyChatFriendsList()
this.getTransferList()
}
}
</script>

View File

@@ -153,7 +153,8 @@ function request(url, params, method = 0) {
if (url.split('/').indexOf('xkApi') !== -1) {
baseURL = envUrls.xkApi;
// 如果是guest模式且是xkApi请求添加/guest/前缀(但避免重复添加)
if (isGuestRequest && url.indexOf('/guest/') === -1) {
// 转诊相关接口需要登录不转换为guest路由
if (isGuestRequest && url.indexOf('/guest/') === -1 && url.indexOf('/transfer-prescription') === -1) {
url = url.replace('/xkApi', '/guest/xkApi');
}
}

View File

@@ -0,0 +1,36 @@
import {post, get} from './http'
/**
* 获取转诊消息列表
* @returns {Promise<*>}
*/
export async function getTransferPrescriptionListApi() {
return await post('/transfer-prescription/list', {}, 3)
}
/**
* 获取转诊详情
* @param params { id: number }
* @returns {Promise<*>}
*/
export async function getTransferPrescriptionDetailApi(params) {
return await get('/transfer-prescription/detail', params, 3)
}
/**
* 同意转诊
* @param params { id: number }
* @returns {Promise<*>}
*/
export async function agreeTransferPrescriptionApi(params) {
return await post('/transfer-prescription/agree', params, 3)
}
/**
* 拒绝转诊
* @param params { id: number, reason?: string }
* @returns {Promise<*>}
*/
export async function rejectTransferPrescriptionApi(params) {
return await post('/transfer-prescription/reject', params, 3)
}

View File

@@ -202,6 +202,15 @@
</view>
</block>
<!-- 类型14: 转诊消息 -->
<block v-else-if="msg.message_type === 14">
<TransferMessageBubble
:message-data="parsedContent"
@agree="handleTransferAgree"
@reject="handleTransferReject"
/>
</block>
<block v-else>
<view class="card-body"><text>不支持的消息类型</text></view>
</block>
@@ -217,8 +226,17 @@
</template>
<script>
import TransferMessageBubble from './TransferMessageBubble.vue'
import {
agreeTransferPrescriptionApi,
rejectTransferPrescriptionApi
} from '@/request/api/transferPrescription'
export default {
name: "MessageBubble",
components: {
TransferMessageBubble
},
props: {
msg: {
type: Object,
@@ -240,20 +258,20 @@ export default {
computed: {
// 纯文本、图片、语音、视频以外的特殊类型,不需要默认的气泡背景/Padding
isMediaOrCard() {
// 1:图片, 3:视频, 4,10,11,12,13: 卡片 (9单独处理)
return [1, 3, 4, 10, 11, 12, 13].includes(this.msg.message_type);
// 1:图片, 3:视频, 4,10,11,12,13,14: 卡片 (9单独处理)
return [1, 3, 4, 10, 11, 12, 13, 14].includes(this.msg.message_type);
},
// 是否是系统消息且为价格变动(需要独立卡片样式)
isSystemPriceUpdate() {
return this.msg.message_type === 9 && (this.parsedContent.type === 'price_update' || this.parsedContent.type === 'price_adjust');
},
isCardType() {
return [4, 10, 11, 12, 13].includes(this.msg.message_type);
return [4, 10, 11, 12, 13, 14].includes(this.msg.message_type);
},
parsedContent() {
const { message_type, message_content } = this.msg;
// 包含9(System)在内的复杂类型尝试解析 JSON
if ([4, 9, 10, 11, 12, 13].includes(message_type)) {
if ([4, 9, 10, 11, 12, 13, 14].includes(message_type)) {
try {
return typeof message_content === 'object' ? message_content : JSON.parse(message_content);
} catch (e) {
@@ -274,6 +292,86 @@ export default {
},
getStatusText(status) { const map = { 0: '待审核', 1: '已审核', 2: '未通过' }; return map[status] || '状态未知'; },
getRegisterStatusText(status) { const map = { 0: '待就诊', 1: '已缴费', 2: '已就诊', 3: '已取消', 4: '已退费' }; return map[status] || '状态未知'; },
// 处理转诊同意
handleTransferAgree(messageData) {
if (!messageData || !messageData.transfer_id) {
uni.showToast({
title: '转诊信息不完整',
icon: 'none'
})
return
}
uni.showModal({
title: '确认转诊',
content: '确定同意转诊吗?',
success: (res) => {
if (res.confirm) {
agreeTransferPrescriptionApi({ id: messageData.transfer_id }).then((result) => {
if (result.data.code == 0) {
uni.showToast({
title: '同意转诊成功',
icon: 'success'
})
// 触发消息更新事件
uni.$emit('chat-message-update')
} else {
uni.showToast({
title: result.data.message || '操作失败',
icon: 'none'
})
}
}).catch((error) => {
console.error('同意转诊失败:', error)
uni.showToast({
title: '操作失败,请重试',
icon: 'none'
})
})
}
}
})
},
// 处理转诊拒绝
handleTransferReject(messageData) {
if (!messageData || !messageData.transfer_id) {
uni.showToast({
title: '转诊信息不完整',
icon: 'none'
})
return
}
uni.showModal({
title: '拒绝转诊',
content: '确定拒绝转诊吗?',
success: (res) => {
if (res.confirm) {
rejectTransferPrescriptionApi({ id: messageData.transfer_id }).then((result) => {
if (result.data.code == 0) {
uni.showToast({
title: '已拒绝转诊',
icon: 'success'
})
// 触发消息更新事件
uni.$emit('chat-message-update')
} else {
uni.showToast({
title: result.data.message || '操作失败',
icon: 'none'
})
}
}).catch((error) => {
console.error('拒绝转诊失败:', error)
uni.showToast({
title: '操作失败,请重试',
icon: 'none'
})
})
}
}
})
}
}
}
</script>

View File

@@ -0,0 +1,171 @@
<template>
<view class="transfer-message-bubble">
<view class="bubble-header">
<view class="header-icon">
<text class="iconfont icon-zhuanzhen"></text>
</view>
<view class="header-title">转诊消息</view>
</view>
<view class="bubble-body">
<view class="info-item" v-if="messageData.transfer_store">
<text class="label">转诊诊所</text>
<text class="value">{{ messageData.transfer_store.name || '未知诊所' }}</text>
</view>
<view class="info-item" v-if="messageData.delegate_store">
<text class="label">委托诊所</text>
<text class="value">{{ messageData.delegate_store.name || '未知诊所' }}</text>
</view>
<view class="info-item" v-if="messageData.prescription_no">
<text class="label">处方编号</text>
<text class="value">{{ messageData.prescription_no }}</text>
</view>
<view class="info-item" v-if="messageData.transfer_reason">
<text class="label">转诊原因</text>
<text class="value">{{ messageData.transfer_reason }}</text>
</view>
</view>
<view class="bubble-footer" v-if="messageData.status === 0">
<button class="action-btn agree" @click="handleAgree">同意转诊</button>
<button class="action-btn reject" @click="handleReject">拒绝转诊</button>
</view>
<view class="bubble-footer" v-else-if="messageData.status === 1">
<text class="status-text confirmed">已同意转诊</text>
</view>
<view class="bubble-footer" v-else-if="messageData.status === 3">
<text class="status-text cancelled">已拒绝转诊</text>
</view>
</view>
</template>
<script>
export default {
name: 'TransferMessageBubble',
props: {
messageData: {
type: Object,
required: true,
default: () => ({})
}
},
methods: {
handleAgree() {
this.$emit('agree', this.messageData);
},
handleReject() {
this.$emit('reject', this.messageData);
}
}
}
</script>
<style scoped>
.transfer-message-bubble {
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
border-radius: 16rpx;
border: 2rpx solid #fed7aa;
padding: 24rpx;
margin: 20rpx 0;
max-width: 600rpx;
}
.bubble-header {
display: flex;
align-items: center;
gap: 16rpx;
margin-bottom: 20rpx;
padding-bottom: 16rpx;
border-bottom: 2rpx solid #fed7aa;
}
.header-icon {
width: 48rpx;
height: 48rpx;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 28rpx;
}
.header-title {
font-size: 30rpx;
font-weight: 600;
color: #1e293b;
}
.bubble-body {
margin-bottom: 20rpx;
}
.info-item {
margin-bottom: 16rpx;
font-size: 26rpx;
line-height: 1.6;
}
.info-item:last-child {
margin-bottom: 0;
}
.label {
color: #64748b;
font-weight: 500;
}
.value {
color: #1e293b;
}
.bubble-footer {
display: flex;
gap: 20rpx;
justify-content: flex-end;
padding-top: 16rpx;
border-top: 2rpx solid #fed7aa;
}
.action-btn {
padding: 12rpx 32rpx;
border-radius: 8rpx;
font-size: 26rpx;
font-weight: 500;
border: none;
}
.action-btn.agree {
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.action-btn.reject {
background: white;
color: #64748b;
border: 2rpx solid #cbd5e1;
}
.status-text {
font-size: 26rpx;
font-weight: 500;
padding: 12rpx 32rpx;
border-radius: 8rpx;
}
.status-text.confirmed {
background: rgba(34, 197, 94, 0.1);
color: #16a34a;
}
.status-text.cancelled {
background: rgba(239, 68, 68, 0.1);
color: #dc2626;
}
</style>

View File

@@ -0,0 +1,247 @@
<template>
<view class="transfer-card">
<view class="card-header">
<view class="header-icon">
<text class="iconfont icon-zhuanzhen"></text>
</view>
<view class="header-title">转诊处方</view>
<view class="status-tag" :class="statusClass">
{{ statusText }}
</view>
</view>
<view class="card-body">
<view class="info-row" v-if="transferData.transfer_store">
<view class="info-icon">
<text class="iconfont icon-yiyuan"></text>
</view>
<view class="info-content">
<view class="info-label">转诊诊所</view>
<view class="info-value">{{ transferData.transfer_store.name || '未知诊所' }}</view>
</view>
</view>
<view class="info-row" v-if="transferData.delegate_store">
<view class="info-icon">
<text class="iconfont icon-zhensuo"></text>
</view>
<view class="info-content">
<view class="info-label">委托诊所</view>
<view class="info-value">{{ transferData.delegate_store.name || '未知诊所' }}</view>
</view>
</view>
<view class="info-row" v-if="transferData.prescription_no">
<view class="info-icon">
<text class="iconfont icon-chufang"></text>
</view>
<view class="info-content">
<view class="info-label">处方编号</view>
<view class="info-value">{{ transferData.prescription_no }}</view>
</view>
</view>
<view class="info-row" v-if="transferData.transfer_time">
<view class="info-icon">
<text class="iconfont icon-shijian"></text>
</view>
<view class="info-content">
<view class="info-label">转诊时间</view>
<view class="info-value">{{ transferData.transfer_time }}</view>
</view>
</view>
</view>
<view class="card-footer" v-if="transferData.status === 0">
<button class="agree-btn" @click="handleAgree">同意转诊</button>
<button class="reject-btn" @click="handleReject">拒绝转诊</button>
</view>
</view>
</template>
<script>
export default {
name: 'TransferPrescriptionCard',
props: {
transferData: {
type: Object,
required: true,
default: () => ({})
}
},
computed: {
statusText() {
const status = this.transferData.status;
const statusMap = {
0: '待确认',
1: '已确认',
2: '已导入',
3: '已取消'
};
return statusMap[status] || '未知';
},
statusClass() {
const status = this.transferData.status;
const classMap = {
0: 'status-pending',
1: 'status-confirmed',
2: 'status-imported',
3: 'status-cancelled'
};
return classMap[status] || '';
}
},
methods: {
handleAgree() {
this.$emit('agree', this.transferData);
},
handleReject() {
this.$emit('reject', this.transferData);
}
}
}
</script>
<style scoped>
.transfer-card {
width: 100%;
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
border-radius: 16rpx;
border: 2rpx solid #fed7aa;
margin: 20rpx 0;
overflow: hidden;
}
.card-header {
display: flex;
align-items: center;
gap: 20rpx;
padding: 24rpx 30rpx;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.header-icon {
width: 60rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
}
.header-title {
flex: 1;
font-size: 32rpx;
font-weight: 600;
}
.status-tag {
padding: 8rpx 20rpx;
border-radius: 40rpx;
font-size: 24rpx;
font-weight: 500;
}
.status-pending {
background: rgba(251, 191, 36, 0.2);
color: #fcd34d;
}
.status-confirmed {
background: rgba(59, 130, 246, 0.2);
color: #93c5fd;
}
.status-imported {
background: rgba(34, 197, 94, 0.2);
color: #86efac;
}
.status-cancelled {
background: rgba(239, 68, 68, 0.2);
color: #fca5a5;
}
.card-body {
padding: 30rpx;
}
.info-row {
display: flex;
align-items: flex-start;
gap: 24rpx;
padding: 24rpx 30rpx;
background: white;
border-radius: 16rpx;
margin-bottom: 20rpx;
border: 2rpx solid #fed7aa;
}
.info-row:last-child {
margin-bottom: 0;
}
.info-icon {
width: 56rpx;
height: 56rpx;
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
color: #f97316;
font-size: 28rpx;
flex-shrink: 0;
}
.info-content {
flex: 1;
min-width: 0;
}
.info-label {
font-size: 24rpx;
color: #64748b;
margin-bottom: 8rpx;
font-weight: 500;
}
.info-value {
font-size: 28rpx;
color: #1e293b;
line-height: 1.6;
word-break: break-word;
}
.card-footer {
padding: 24rpx 30rpx;
background: #fff7ed;
border-top: 2rpx solid #fed7aa;
display: flex;
gap: 20rpx;
justify-content: flex-end;
}
.agree-btn,
.reject-btn {
padding: 16rpx 40rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 500;
border: none;
}
.agree-btn {
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
color: white;
}
.reject-btn {
background: white;
color: #64748b;
border: 2rpx solid #cbd5e1;
}
</style>

View File

@@ -62,6 +62,15 @@
</view>
<text>{{item.store}}</text>
</view>
<!-- 转诊卡片 -->
<TransferPrescriptionCard
v-if="item.is_from_transfer == 1 && item.transfer_prescription"
:transfer-data="item.transfer_prescription"
@agree="handleTransferAgree"
@reject="handleTransferReject"
/>
<!-- 查看详情 -->
<view class="detail" @click="getInfo(item.id)"><text>查看详情</text></view>
</view>
@@ -78,7 +87,15 @@
import {
getRegisterListApi
} from '../../request/api/register'
import {
agreeTransferPrescriptionApi,
rejectTransferPrescriptionApi
} from '../../request/api/transferPrescription'
import TransferPrescriptionCard from './components/TransferPrescriptionCard.vue'
export default {
components: {
TransferPrescriptionCard
},
data() {
return {
status: 'nomore',
@@ -112,6 +129,74 @@
url: "/subPackages/register/register-info?id=" + id + '&type=' + 1
})
},
// 同意转诊
handleTransferAgree(transferData) {
uni.showModal({
title: '确认转诊',
content: '确定同意转诊吗?',
success: (res) => {
if (res.confirm) {
agreeTransferPrescriptionApi({ id: transferData.id }).then((result) => {
if (result.data.code == 0) {
uni.showToast({
title: '同意转诊成功',
icon: 'success'
})
// 刷新列表
this.page = 1
this.infoList = []
this.getInfos()
} else {
uni.showToast({
title: result.data.message || '操作失败',
icon: 'none'
})
}
}).catch((error) => {
console.error('同意转诊失败:', error)
uni.showToast({
title: '操作失败,请重试',
icon: 'none'
})
})
}
}
})
},
// 拒绝转诊
handleTransferReject(transferData) {
uni.showModal({
title: '拒绝转诊',
content: '确定拒绝转诊吗?',
success: (res) => {
if (res.confirm) {
rejectTransferPrescriptionApi({ id: transferData.id }).then((result) => {
if (result.data.code == 0) {
uni.showToast({
title: '已拒绝转诊',
icon: 'success'
})
// 刷新列表
this.page = 1
this.infoList = []
this.getInfos()
} else {
uni.showToast({
title: result.data.message || '操作失败',
icon: 'none'
})
}
}).catch((error) => {
console.error('拒绝转诊失败:', error)
uni.showToast({
title: '操作失败,请重试',
icon: 'none'
})
})
}
}
})
},
// 就诊人列表
getInfolist() {
userList({

View File

@@ -0,0 +1,356 @@
<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="@/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-zhuanzhen"></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' })
this.getTransferList()
} else {
uni.showToast({ title: response.data.message, icon: 'none' })
}
} catch (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>