|
|
@@ -1,432 +0,0 @@
|
|
|
-<template>
|
|
|
- <CustomNav title="复诊管理" leftType="back" />
|
|
|
- <view class="page-container">
|
|
|
- <view class="tabs">
|
|
|
- <view
|
|
|
- class="tab"
|
|
|
- :class="{ active: activeTab === 'pending' }"
|
|
|
- @click="activeTab = 'pending'"
|
|
|
- >
|
|
|
- 待处理({{ pendingCount }})
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="tab"
|
|
|
- :class="{ active: activeTab === 'confirmed' }"
|
|
|
- @click="activeTab = 'confirmed'"
|
|
|
- >
|
|
|
- 已确认({{ confirmedCount }})
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="tab"
|
|
|
- :class="{ active: activeTab === 'completed' }"
|
|
|
- @click="activeTab = 'completed'"
|
|
|
- >
|
|
|
- 已完成({{ completedCount }})
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="tab"
|
|
|
- :class="{ active: activeTab === 'cancelled' }"
|
|
|
- @click="activeTab = 'cancelled'"
|
|
|
- >
|
|
|
- 已取消({{ cancelledCount }})
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="followup-list" v-if="filteredFollowups.length > 0">
|
|
|
- <view
|
|
|
- class="followup-card"
|
|
|
- v-for="followup in filteredFollowups"
|
|
|
- :key="followup.id"
|
|
|
- >
|
|
|
- <view class="card-header">
|
|
|
- <view class="patient-info">
|
|
|
- <text class="patient-name">{{ followup.patientNickname || '未知患者' }}</text>
|
|
|
- <text class="request-time">{{ formattedFollowups[followup.id]?.requestTime }}</text>
|
|
|
- </view>
|
|
|
- <view class="status-badge" :class="followup.status">
|
|
|
- {{ getStatusText(followup.status) }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="card-body">
|
|
|
- <view class="info-row">
|
|
|
- <text class="label">预约时间:</text>
|
|
|
- <text class="value">{{ formattedFollowups[followup.id]?.scheduledTime }}</text>
|
|
|
- </view>
|
|
|
- <view class="info-row">
|
|
|
- <text class="label">复诊原因:</text>
|
|
|
- <text class="value">{{ followup.reason || '无' }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="card-footer" v-if="followup.status === 'PENDING'">
|
|
|
- <button class="action-btn cancel" @click="cancelFollowup(followup.id)">取消</button>
|
|
|
- <button class="action-btn confirm" @click="confirmFollowup(followup.id)">确认</button>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="card-footer" v-else-if="followup.status === 'CONFIRMED'">
|
|
|
- <button class="action-btn cancel" @click="cancelFollowup(followup.id)">取消</button>
|
|
|
- <button class="action-btn complete" @click="completeFollowup(followup.id)">标记为完成</button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="empty-state" v-else>
|
|
|
- <image class="empty-icon" src="/static/icons/remixicon/article-line.svg" />
|
|
|
- <text class="empty-text">暂无复诊请求</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup lang="ts">
|
|
|
-import { ref, computed, onMounted } from 'vue'
|
|
|
-import CustomNav from '@/components/custom-nav.vue'
|
|
|
-import { formatDate } from '@/utils/date'
|
|
|
-import { getFollowUpList, updateFollowUp } from '@/api/followUp'
|
|
|
-import type { FollowUp } from '@/api/followUp'
|
|
|
-
|
|
|
-type FollowupRequest = FollowUp
|
|
|
-
|
|
|
-const activeTab = ref<'pending' | 'confirmed' | 'completed' | 'cancelled'>('pending')
|
|
|
-const followups = ref<FollowupRequest[]>([])
|
|
|
-
|
|
|
-// 统计各状态数量
|
|
|
-const pendingCount = computed(() => followups.value.filter(f => f.status === 'PENDING').length)
|
|
|
-const confirmedCount = computed(() => followups.value.filter(f => f.status === 'CONFIRMED').length)
|
|
|
-const completedCount = computed(() => followups.value.filter(f => f.status === 'COMPLETED').length)
|
|
|
-const cancelledCount = computed(() => followups.value.filter(f => f.status === 'CANCELLED').length)
|
|
|
-
|
|
|
-// 根据标签页过滤的复诊数据
|
|
|
-const filteredFollowups = computed(() => {
|
|
|
- switch (activeTab.value) {
|
|
|
- case 'pending':
|
|
|
- return followups.value.filter(f => f.status === 'PENDING')
|
|
|
- case 'confirmed':
|
|
|
- return followups.value.filter(f => f.status === 'CONFIRMED')
|
|
|
- case 'completed':
|
|
|
- return followups.value.filter(f => f.status === 'COMPLETED')
|
|
|
- case 'cancelled':
|
|
|
- return followups.value.filter(f => f.status === 'CANCELLED')
|
|
|
- default:
|
|
|
- return followups.value
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-// 格式化后的复诊数据
|
|
|
-const formattedFollowups = computed(() => {
|
|
|
- const formatted: Record<string, { requestTime: string; scheduledTime: string }> = {}
|
|
|
- followups.value.forEach(followup => {
|
|
|
- formatted[followup.id] = {
|
|
|
- requestTime: formatDate(followup.createTime),
|
|
|
- scheduledTime: formatDate(followup.appointmentTime)
|
|
|
- }
|
|
|
- })
|
|
|
- return formatted
|
|
|
-})
|
|
|
-
|
|
|
-// 获取状态文本
|
|
|
-const getStatusText = (status: string) => {
|
|
|
- switch (status) {
|
|
|
- case 'PENDING': return '待处理'
|
|
|
- case 'CONFIRMED': return '已确认'
|
|
|
- case 'COMPLETED': return '已完成'
|
|
|
- case 'CANCELLED': return '已取消'
|
|
|
- default: return status
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 获取复诊请求数据
|
|
|
-const fetchFollowups = async () => {
|
|
|
- uni.showLoading({ title: '加载中...' })
|
|
|
-
|
|
|
- try {
|
|
|
- const token = uni.getStorageSync('token')
|
|
|
- if (!token) {
|
|
|
- uni.hideLoading()
|
|
|
- uni.showToast({
|
|
|
- title: '未登录',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 获取当前医生ID
|
|
|
- const userInfo = uni.getStorageSync('user_info')
|
|
|
- const doctorUserId = userInfo?.id
|
|
|
-
|
|
|
- if (!doctorUserId) {
|
|
|
- uni.hideLoading()
|
|
|
- uni.showToast({
|
|
|
- title: '获取医生信息失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 调用API获取复诊列表
|
|
|
- const response: any = await getFollowUpList({})
|
|
|
-
|
|
|
- uni.hideLoading()
|
|
|
-
|
|
|
- if (response && response.data && response.data.code === 200) {
|
|
|
- // 修复:使用records的实际长度而不是total字段
|
|
|
- followups.value = response.data.data.records || []
|
|
|
- } else {
|
|
|
- uni.showToast({
|
|
|
- title: '获取复诊数据失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- uni.hideLoading()
|
|
|
- console.error('获取复诊数据失败:', error)
|
|
|
- uni.showToast({
|
|
|
- title: '获取复诊数据失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 取消复诊请求
|
|
|
-const cancelFollowup = (id: string) => {
|
|
|
- uni.showModal({
|
|
|
- title: '确认取消',
|
|
|
- content: '确定要取消这个复诊请求吗?',
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- // 调用API更新复诊请求状态
|
|
|
- updateFollowUpStatus(id, 'CANCELLED')
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 确认复诊请求
|
|
|
-const confirmFollowup = (id: string) => {
|
|
|
- uni.showModal({
|
|
|
- title: '确认复诊',
|
|
|
- content: '确定要确认这个复诊请求吗?',
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- // 调用API更新复诊请求状态
|
|
|
- updateFollowUpStatus(id, 'CONFIRMED')
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 完成复诊
|
|
|
-const completeFollowup = (id: string) => {
|
|
|
- uni.showModal({
|
|
|
- title: '完成复诊',
|
|
|
- content: '确定已完成本次复诊吗?',
|
|
|
- success: (res) => {
|
|
|
- if (res.confirm) {
|
|
|
- // 调用API更新复诊请求状态
|
|
|
- updateFollowUpStatus(id, 'COMPLETED')
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 更新复诊请求状态
|
|
|
-const updateFollowUpStatus = async (id: string, status: 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED') => {
|
|
|
- uni.showLoading({ title: '处理中...' })
|
|
|
-
|
|
|
- try {
|
|
|
- const response: any = await updateFollowUp(id, { status })
|
|
|
-
|
|
|
- uni.hideLoading()
|
|
|
-
|
|
|
- if (response && response.data && response.data.code === 200) {
|
|
|
- // 更新本地数据
|
|
|
- const index = followups.value.findIndex(f => f.id === id)
|
|
|
- if (index !== -1) {
|
|
|
- followups.value[index].status = status
|
|
|
- }
|
|
|
- uni.showToast({ title: '操作成功', icon: 'success' })
|
|
|
- } else {
|
|
|
- uni.showToast({
|
|
|
- title: '操作失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- uni.hideLoading()
|
|
|
- console.error('更新复诊状态失败:', error)
|
|
|
- uni.showToast({
|
|
|
- title: '操作失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- fetchFollowups()
|
|
|
-})
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.page-container {
|
|
|
- min-height: 100vh;
|
|
|
- background-color: #f5f5f5;
|
|
|
- padding-top: calc(var(--status-bar-height) + 44px);
|
|
|
- padding-bottom: 40rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.tabs {
|
|
|
- display: flex;
|
|
|
- background-color: #fff;
|
|
|
- border-bottom: 1rpx solid #eee;
|
|
|
-}
|
|
|
-
|
|
|
-.tab {
|
|
|
- flex: 1;
|
|
|
- text-align: center;
|
|
|
- padding: 30rpx 0;
|
|
|
- font-size: 28rpx;
|
|
|
- color: #666;
|
|
|
-}
|
|
|
-
|
|
|
-.tab.active {
|
|
|
- color: #3742fa;
|
|
|
- border-bottom: 4rpx solid #3742fa;
|
|
|
-}
|
|
|
-
|
|
|
-.followup-list {
|
|
|
- padding: 20rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.followup-card {
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 20rpx;
|
|
|
- margin-bottom: 20rpx;
|
|
|
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-
|
|
|
-.card-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 30rpx;
|
|
|
- border-bottom: 1rpx solid #eee;
|
|
|
-}
|
|
|
-
|
|
|
-.patient-info {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.patient-name {
|
|
|
- font-size: 32rpx;
|
|
|
- font-weight: bold;
|
|
|
- color: #333;
|
|
|
- margin-bottom: 10rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.request-time {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999;
|
|
|
-}
|
|
|
-
|
|
|
-.status-badge {
|
|
|
- padding: 8rpx 16rpx;
|
|
|
- border-radius: 10rpx;
|
|
|
- font-size: 24rpx;
|
|
|
- color: #fff;
|
|
|
-}
|
|
|
-
|
|
|
-.status-badge.PENDING {
|
|
|
- background-color: #ffa502;
|
|
|
-}
|
|
|
-
|
|
|
-.status-badge.CONFIRMED {
|
|
|
- background-color: #3742fa;
|
|
|
-}
|
|
|
-
|
|
|
-.status-badge.COMPLETED {
|
|
|
- background-color: #2ed573;
|
|
|
-}
|
|
|
-
|
|
|
-.status-badge.CANCELLED {
|
|
|
- background-color: #ccc;
|
|
|
-}
|
|
|
-
|
|
|
-.card-body {
|
|
|
- padding: 30rpx;
|
|
|
- border-bottom: 1rpx solid #eee;
|
|
|
-}
|
|
|
-
|
|
|
-.info-row {
|
|
|
- display: flex;
|
|
|
- margin-bottom: 20rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.info-row:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.label {
|
|
|
- font-size: 28rpx;
|
|
|
- color: #666;
|
|
|
- width: 180rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.value {
|
|
|
- flex: 1;
|
|
|
- font-size: 28rpx;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.card-footer {
|
|
|
- display: flex;
|
|
|
- padding: 30rpx;
|
|
|
- justify-content: flex-end;
|
|
|
-}
|
|
|
-
|
|
|
-.action-btn {
|
|
|
- padding: 0 30rpx;
|
|
|
- height: 60rpx;
|
|
|
- line-height: 60rpx;
|
|
|
- border-radius: 10rpx;
|
|
|
- font-size: 28rpx;
|
|
|
- margin-left: 20rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.cancel {
|
|
|
- background-color: #fff;
|
|
|
- color: #ff4757;
|
|
|
- border: 1rpx solid #ff4757;
|
|
|
-}
|
|
|
-
|
|
|
-.confirm {
|
|
|
- background-color: #3742fa;
|
|
|
- color: #fff;
|
|
|
-}
|
|
|
-
|
|
|
-.complete {
|
|
|
- background-color: #2ed573;
|
|
|
- color: #fff;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-state {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 100rpx 40rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-icon {
|
|
|
- width: 120rpx;
|
|
|
- height: 120rpx;
|
|
|
- margin-bottom: 30rpx;
|
|
|
- opacity: 0.5;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-text {
|
|
|
- font-size: 32rpx;
|
|
|
- color: #666;
|
|
|
-}
|
|
|
-</style>
|