<template>
|
<view class="medical-container">
|
<!-- 统计卡片 -->
|
<view class="stats-card">
|
<view class="stat-item">
|
<text class="count">{{ stats.total }}</text>
|
<text class="label">就医总次数</text>
|
</view>
|
<view class="divider"></view>
|
<view class="stat-item">
|
<text class="count">{{ stats.thisYear }}</text>
|
<text class="label">今年就医</text>
|
</view>
|
<view class="divider"></view>
|
<view class="stat-item">
|
<text class="count">{{ stats.pending }}</text>
|
<text class="label">待就诊</text>
|
</view>
|
</view>
|
|
<!-- 时间轴视图 -->
|
<scroll-view
|
scroll-y
|
class="timeline-view"
|
refresher-enabled
|
:refresher-triggered="refreshing"
|
@refresherrefresh="onRefresh"
|
@scrolltolower="onLoadMore"
|
>
|
<view class="timeline">
|
<view
|
class="timeline-item"
|
v-for="(record, index) in records"
|
:key="index"
|
@tap="viewDetail(record)"
|
>
|
<!-- 时间点 -->
|
<view class="time-point">
|
<text class="date">{{ record.date.split(' ')[0] }}</text>
|
<text class="time">{{ record.date.split(' ')[1] }}</text>
|
</view>
|
|
<!-- 就医卡片 -->
|
<view class="record-card">
|
<view class="header">
|
<view class="hospital-info">
|
<image :src="record.hospitalLogo" mode="aspectFit" class="logo" />
|
<view class="info">
|
<text class="name">{{ record.hospitalName }}</text>
|
<text class="department">{{ record.departmentName }}</text>
|
</view>
|
</view>
|
<text class="status" :class="record.status">{{ record.statusText }}</text>
|
</view>
|
|
<view class="doctor-info">
|
<image :src="record.doctorAvatar" mode="aspectFill" class="avatar" />
|
<view class="info">
|
<text class="name">{{ record.doctorName }}</text>
|
<text class="title">{{ record.doctorTitle }}</text>
|
</view>
|
</view>
|
|
<view class="diagnosis-info" v-if="record.diagnosis">
|
<text class="label">诊断:</text>
|
<text class="value">{{ record.diagnosis }}</text>
|
</view>
|
|
<view class="footer">
|
<view class="fee-info">
|
<text class="label">就诊费用</text>
|
<text class="amount">¥{{ record.fee }}</text>
|
</view>
|
<view class="actions">
|
<button
|
class="action-btn"
|
v-if="record.status === 'upcoming'"
|
@tap.stop="cancelAppointment(record)"
|
>取消预约</button>
|
<button
|
class="action-btn"
|
v-if="record.status === 'completed'"
|
@tap.stop="viewReport(record)"
|
>查看报告</button>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 加载更多 -->
|
<view class="load-more" v-if="hasMore">
|
<text>加载中...</text>
|
</view>
|
|
<!-- 空状态 -->
|
<view class="empty-state" v-if="records.length === 0">
|
<image src="/static/empty/no-records.png" mode="aspectFit" />
|
<text>暂无就医记录</text>
|
</view>
|
</scroll-view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref } from 'vue'
|
|
// 统计数据
|
const stats = ref({
|
total: 12,
|
thisYear: 5,
|
pending: 2
|
})
|
|
// 就医记录数据
|
const records = ref([
|
{
|
id: 1,
|
date: '2024-03-25 09:30',
|
hospitalName: '青岛镜湖医院',
|
hospitalLogo: '/static/hospital/kiang-wu.jpg',
|
departmentName: '心内科',
|
doctorName: '张医生',
|
doctorTitle: '主任医师',
|
doctorAvatar: '/static/doctor/doctor1.jpg',
|
status: 'upcoming',
|
statusText: '待就诊',
|
fee: 60
|
},
|
{
|
id: 2,
|
date: '2024-03-20 15:00',
|
hospitalName: '青岛科大医院',
|
hospitalLogo: '/static/hospital/must.jpg',
|
departmentName: '儿科',
|
doctorName: '李医生',
|
doctorTitle: '副主任医师',
|
doctorAvatar: '/static/doctor/doctor2.jpg',
|
status: 'completed',
|
statusText: '已完成',
|
diagnosis: '上呼吸道感染',
|
fee: 80,
|
hasReport: true
|
},
|
{
|
id: 3,
|
date: '2024-03-15 10:30',
|
hospitalName: '青岛镜湖医院',
|
hospitalLogo: '/static/hospital/kiang-wu.jpg',
|
departmentName: '骨科',
|
doctorName: '王医生',
|
doctorTitle: '主任医师',
|
doctorAvatar: '/static/doctor/doctor3.jpg',
|
status: 'completed',
|
statusText: '已完成',
|
diagnosis: '腰椎间盘突出',
|
fee: 100,
|
hasReport: true
|
}
|
])
|
|
// 分页相关
|
const hasMore = ref(true)
|
const refreshing = ref(false)
|
|
// 查看详情
|
const viewDetail = (record) => {
|
uni.navigateTo({
|
url: `/pages/records/detail?id=${record.id}`
|
})
|
}
|
|
// 查看报告
|
const viewReport = (record) => {
|
if (record.hasReport) {
|
uni.navigateTo({
|
url: `/pages/records/report?id=${record.id}`
|
})
|
}
|
}
|
|
// 取消预约
|
const cancelAppointment = (record) => {
|
uni.showModal({
|
title: '取消预约',
|
content: '确定要取消该预约吗?',
|
success: (res) => {
|
if (res.confirm) {
|
// 调用取消预约接口
|
console.log('取消预约:', record.id)
|
}
|
}
|
})
|
}
|
|
// 下拉刷新
|
const onRefresh = () => {
|
refreshing.value = true
|
// 重新加载数据
|
loadRecords()
|
setTimeout(() => {
|
refreshing.value = false
|
}, 1000)
|
}
|
|
// 加载更多
|
const onLoadMore = () => {
|
if (!hasMore.value) return
|
loadRecords()
|
}
|
|
// 加载记录数据
|
const loadRecords = () => {
|
// 这里应该调用API获取数据
|
// 模拟加载
|
setTimeout(() => {
|
hasMore.value = false
|
}, 1000)
|
}
|
</script>
|
|
<style lang="scss">
|
.medical-container {
|
min-height: 100vh;
|
background: $bg-color;
|
|
.stats-card {
|
margin: 20rpx;
|
background: $primary-gradient;
|
border-radius: $radius-lg;
|
padding: 40rpx 30rpx;
|
display: flex;
|
align-items: center;
|
box-shadow: $shadow-md;
|
|
.stat-item {
|
flex: 1;
|
text-align: center;
|
|
.count {
|
font-size: 40rpx;
|
color: #fff;
|
font-weight: bold;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.label {
|
font-size: 26rpx;
|
color: rgba(255,255,255,0.9);
|
}
|
}
|
|
.divider {
|
width: 2rpx;
|
height: 60rpx;
|
background: rgba(255,255,255,0.2);
|
}
|
}
|
|
.timeline-view {
|
height: calc(100vh - 200rpx);
|
|
.timeline {
|
padding: 30rpx;
|
|
.timeline-item {
|
display: flex;
|
margin-bottom: 40rpx;
|
|
&:last-child {
|
margin-bottom: 0;
|
|
.time-point::after {
|
display: none;
|
}
|
}
|
|
.time-point {
|
width: 120rpx;
|
text-align: center;
|
padding-top: 20rpx;
|
position: relative;
|
|
.date {
|
font-size: 26rpx;
|
color: $text-secondary;
|
margin-bottom: 8rpx;
|
display: block;
|
}
|
|
.time {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
|
&::before {
|
content: '';
|
display: block;
|
width: 16rpx;
|
height: 16rpx;
|
background: $primary-color;
|
border-radius: 50%;
|
margin: 0 auto 8rpx;
|
}
|
|
&::after {
|
content: '';
|
position: absolute;
|
left: 50%;
|
top: 44rpx;
|
bottom: -60rpx;
|
width: 2rpx;
|
background: #eee;
|
}
|
}
|
|
.record-card {
|
flex: 1;
|
background: #fff;
|
border-radius: $radius-lg;
|
padding: 30rpx;
|
margin-left: 30rpx;
|
box-shadow: $shadow-sm;
|
|
.header {
|
display: flex;
|
justify-content: space-between;
|
align-items: flex-start;
|
margin-bottom: 20rpx;
|
|
.hospital-info {
|
display: flex;
|
align-items: center;
|
|
.logo {
|
width: 60rpx;
|
height: 60rpx;
|
border-radius: $radius-sm;
|
margin-right: 16rpx;
|
}
|
|
.info {
|
.name {
|
font-size: 30rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 4rpx;
|
display: block;
|
}
|
|
.department {
|
font-size: 26rpx;
|
color: $text-regular;
|
}
|
}
|
}
|
|
.status {
|
font-size: 24rpx;
|
padding: 4rpx 12rpx;
|
border-radius: $radius-sm;
|
|
&.upcoming {
|
color: $primary-color;
|
background: $primary-light;
|
}
|
|
&.completed {
|
color: $success;
|
background: rgba($success, 0.1);
|
}
|
|
&.cancelled {
|
color: $text-secondary;
|
background: rgba($text-secondary, 0.1);
|
}
|
}
|
}
|
|
.doctor-info {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 0;
|
border-bottom: 1rpx solid #eee;
|
|
.avatar {
|
width: 80rpx;
|
height: 80rpx;
|
border-radius: 40rpx;
|
margin-right: 20rpx;
|
}
|
|
.info {
|
.name {
|
font-size: 28rpx;
|
color: $text-primary;
|
font-weight: bold;
|
margin-bottom: 4rpx;
|
display: block;
|
}
|
|
.title {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
|
.diagnosis-info {
|
padding: 20rpx 0;
|
border-bottom: 1rpx solid #eee;
|
|
.label {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-right: 12rpx;
|
}
|
|
.value {
|
font-size: 28rpx;
|
color: $text-primary;
|
}
|
}
|
|
.footer {
|
padding-top: 20rpx;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.fee-info {
|
.label {
|
font-size: 26rpx;
|
color: $text-regular;
|
margin-right: 12rpx;
|
}
|
|
.amount {
|
font-size: 32rpx;
|
color: $danger;
|
font-weight: bold;
|
}
|
}
|
|
.actions {
|
display: flex;
|
gap: 20rpx;
|
|
.action-btn {
|
height: 60rpx;
|
line-height: 60rpx;
|
padding: 0 30rpx;
|
font-size: 26rpx;
|
color: $primary-color;
|
background: $primary-light;
|
border-radius: $radius-xl;
|
|
&:active {
|
opacity: 0.8;
|
}
|
}
|
}
|
}
|
|
&:active {
|
transform: scale(0.99);
|
}
|
}
|
}
|
}
|
}
|
|
.empty-state {
|
padding: 120rpx 0;
|
text-align: center;
|
|
image {
|
width: 240rpx;
|
height: 240rpx;
|
margin-bottom: 30rpx;
|
}
|
|
text {
|
font-size: 28rpx;
|
color: $text-secondary;
|
}
|
}
|
}
|
</style>
|