初始化上传医疗项目到 medical-mall

This commit is contained in:
2026-04-10 09:03:21 +08:00
parent ca8794ea3a
commit ce124e7119
421 changed files with 15139 additions and 2363 deletions

View File

@@ -0,0 +1,904 @@
<!-- 机构端 - 健康管理页面 -->
<template>
<view class="hm-page">
<!-- #ifdef MP-WEIXIN -->
<view class="detail-navbar">
<view class="detail-navbar-back" @click="uni.navigateBack()">
<text class="back-arrow"></text>
<text class="back-text">返回</text>
</view>
<text class="detail-navbar-title">健康管理</text>
<view style="width: 120rpx;"></view>
</view>
<!-- #endif -->
<scroll-view class="hm-scroll" direction="vertical">
<!-- 顶部用户选择器 -->
<view class="user-selector-card">
<view class="us-inner">
<view class="us-avatar-wrap">
<view class="us-avatar">{{ currentUser.name.substring(0, 1) }}</view>
</view>
<view class="us-info">
<text class="us-name">{{ currentUser.name }}</text>
<text class="us-sub">{{ currentUser.age }}岁 · {{ currentUser.gender }} · {{ currentUser.diagnosis }}</text>
</view>
<view class="us-switch-btn" @click="switchUser">切换</view>
</view>
<view class="us-tags-row">
<view v-for="tag in currentUser.tags" :key="tag" class="us-tag" :class="tag === '高风险' ? 'us-tag-danger' : ''">{{ tag }}</view>
</view>
</view>
<!-- 健康数据面板 -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">📊</text>
<text class="sct-text">今日健康数据</text>
<text class="sct-time">{{ todayDate }}</text>
</view>
<view class="health-data-grid">
<view v-for="item in healthMetrics" :key="item.key" class="hd-item" :class="item.status === 'warning' ? 'hd-item-warning' : item.status === 'danger' ? 'hd-item-danger' : ''">
<text class="hd-icon">{{ item.icon }}</text>
<text class="hd-val">{{ item.value }}</text>
<text class="hd-unit">{{ item.unit }}</text>
<text class="hd-label">{{ item.label }}</text>
<view v-if="item.status !== 'normal'" class="hd-badge" :class="item.status === 'danger' ? 'hd-badge-danger' : 'hd-badge-warning'">{{ item.statusText }}</view>
</view>
</view>
</view>
<!-- 健康档案 -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">📋</text>
<text class="sct-text">健康档案</text>
<text class="sct-action" @click="editRecord">编辑</text>
</view>
<view class="record-row">
<text class="record-label">身高/体重</text>
<text class="record-val">{{ healthRecord.height }}cm / {{ healthRecord.weight }}kg</text>
</view>
<view class="record-row">
<text class="record-label">血型</text>
<text class="record-val">{{ healthRecord.bloodType }}</text>
</view>
<view class="record-row">
<text class="record-label">主要诊断</text>
<text class="record-val">{{ healthRecord.mainDiagnosis }}</text>
</view>
<view class="record-row">
<text class="record-label">过敏史</text>
<text class="record-val">{{ healthRecord.allergy || '无已知过敏' }}</text>
</view>
<view class="record-row">
<text class="record-label">主治医生</text>
<text class="record-val">{{ healthRecord.doctor }}</text>
</view>
<view class="record-row">
<text class="record-label">就诊医院</text>
<text class="record-val">{{ healthRecord.hospital }}</text>
</view>
</view>
<!-- 慢病管理 -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">🏥</text>
<text class="sct-text">慢病管理</text>
</view>
<view v-for="disease in chronicDiseases" :key="disease.name" class="disease-item">
<view class="disease-header">
<text class="disease-name">{{ disease.name }}</text>
<view class="disease-status" :class="disease.controlled ? 'ds-good' : 'ds-bad'">
{{ disease.controlled ? '控制良好' : '需关注' }}
</view>
</view>
<view class="disease-indicators">
<view v-for="ind in disease.indicators" :key="ind.name" class="di-row">
<text class="di-label">{{ ind.name }}</text>
<text class="di-val" :class="ind.abnormal ? 'di-val-warn' : ''">{{ ind.value }}</text>
<text class="di-ref">参考:{{ ind.reference }}</text>
</view>
</view>
</view>
</view>
<!-- 用药提醒 -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">💊</text>
<text class="sct-text">用药提醒</text>
<text class="sct-action" @click="addMedication">+ 添加</text>
</view>
<view v-if="medications.length === 0" class="empty-tip">
<text class="empty-tip-text">暂无用药记录</text>
</view>
<view v-for="med in medications" :key="med.name" class="med-item">
<view class="med-left">
<view class="med-dot" :class="med.taken ? 'med-dot-done' : 'med-dot-pending'"></view>
</view>
<view class="med-info">
<text class="med-name">{{ med.name }}</text>
<text class="med-dose">{{ med.dose }} · {{ med.frequency }}</text>
</view>
<view class="med-time-col">
<text class="med-time">{{ med.nextTime }}</text>
<text class="med-status" :class="med.taken ? 'ms-done' : 'ms-pending'">{{ med.taken ? '已服' : '待服' }}</text>
</view>
</view>
</view>
<!-- 复查预约 -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">📅</text>
<text class="sct-text">复查预约</text>
<text class="sct-action" @click="bookReview">+ 预约</text>
</view>
<view v-if="appointments.length === 0" class="empty-tip">
<text class="empty-tip-text">暂无复查预约</text>
</view>
<view v-for="appt in appointments" :key="appt.id" class="appt-item">
<view class="appt-date-col">
<text class="appt-month">{{ appt.month }}</text>
<text class="appt-day">{{ appt.day }}</text>
</view>
<view class="appt-info">
<text class="appt-title">{{ appt.title }}</text>
<text class="appt-desc">{{ appt.department }} · {{ appt.doctor }}</text>
<text class="appt-location">{{ appt.hospital }}</text>
</view>
<view class="appt-tag" :class="appt.status === 'upcoming' ? 'at-upcoming' : 'at-done'">
{{ appt.status === 'upcoming' ? '待复查' : '已完成' }}
</view>
</view>
</view>
<!-- 健康趋势图(简单柱状图) -->
<view class="section-card mt16">
<view class="section-card-title">
<text class="sct-icon">📈</text>
<text class="sct-text">本周血压趋势</text>
</view>
<view class="chart-area">
<view v-for="(item, idx) in bpTrend" :key="idx" class="bar-group">
<view class="bar-pair">
<view class="bar bar-sys" :style="'height: ' + (item.sys / 200 * 120) + 'rpx;'"></view>
<view class="bar bar-dia" :style="'height: ' + (item.dia / 200 * 120) + 'rpx;'"></view>
</view>
<text class="bar-label">{{ item.day }}</text>
</view>
</view>
<view class="chart-legend">
<view class="legend-item"><view class="legend-dot ld-sys"></view><text class="legend-text">收缩压</text></view>
<view class="legend-item"><view class="legend-dot ld-dia"></view><text class="legend-text">舒张压</text></view>
</view>
</view>
<view style="height: 60rpx;"></view>
</scroll-view>
</view>
</template>
<script lang="uts">
type HealthMetricType = {
key: string
icon: string
value: string
unit: string
label: string
status: string
statusText: string
}
type IndicatorType = {
name: string
value: string
reference: string
abnormal: boolean
}
type DiseaseType = {
name: string
controlled: boolean
indicators: IndicatorType[]
}
type MedicationType = {
name: string
dose: string
frequency: string
nextTime: string
taken: boolean
}
type AppointmentType = {
id: string
month: string
day: string
title: string
department: string
doctor: string
hospital: string
status: string
}
type BpPointType = {
day: string
sys: number
dia: number
}
type UserType = {
name: string
age: number
gender: string
diagnosis: string
tags: string[]
}
export default {
data() {
return {
todayDate: '' as string,
currentUser: {
name: '李奶奶',
age: 78,
gender: '女',
diagnosis: '高血压·糖尿病',
tags: ['慢病用户', '高风险', '长期服务']
} as UserType,
healthMetrics: [
{ key: 'bp', icon: '❤️', value: '148/92', unit: 'mmHg', label: '血压', status: 'warning', statusText: '偏高' },
{ key: 'blood_sugar', icon: '🩸', value: '7.8', unit: 'mmol/L', label: '血糖', status: 'warning', statusText: '偏高' },
{ key: 'heart_rate', icon: '💓', value: '76', unit: 'bpm', label: '心率', status: 'normal', statusText: '' },
{ key: 'spo2', icon: '🫁', value: '97', unit: '%', label: '血氧', status: 'normal', statusText: '' },
{ key: 'temp', icon: '🌡️', value: '36.5', unit: '°C', label: '体温', status: 'normal', statusText: '' },
{ key: 'weight', icon: '⚖️', value: '62.5', unit: 'kg', label: '体重', status: 'normal', statusText: '' }
] as HealthMetricType[],
healthRecord: {
height: 162,
weight: 62.5,
bloodType: 'A型',
mainDiagnosis: '高血压3级、2型糖尿病、骨质疏松',
allergy: '青霉素',
doctor: '王主任',
hospital: '嘉城医院内科'
},
chronicDiseases: [
{
name: '高血压',
controlled: false,
indicators: [
{ name: '收缩压', value: '148 mmHg', reference: '<140', abnormal: true },
{ name: '舒张压', value: '92 mmHg', reference: '<90', abnormal: true }
]
},
{
name: '2型糖尿病',
controlled: false,
indicators: [
{ name: '空腹血糖', value: '7.8 mmol/L', reference: '3.9-7.0', abnormal: true },
{ name: '糖化血红蛋白', value: '7.2%', reference: '<7.0%', abnormal: true }
]
}
] as DiseaseType[],
medications: [
{ name: '硝苯地平控释片', dose: '30mg', frequency: '每日一次', nextTime: '今日 08:00', taken: true },
{ name: '二甲双胍', dose: '500mg', frequency: '每日三次', nextTime: '今日 12:00', taken: false },
{ name: '阿司匹林肠溶片', dose: '100mg', frequency: '每日一次', nextTime: '今日 08:00', taken: true },
{ name: '骨化三醇胶丸', dose: '0.25μg', frequency: '每日两次', nextTime: '今日 20:00', taken: false }
] as MedicationType[],
appointments: [
{ id: '1', month: '04月', day: '20', title: '高血压复查', department: '心内科', doctor: '王主任', hospital: '嘉城医院', status: 'upcoming' },
{ id: '2', month: '04月', day: '28', title: '糖尿病随访', department: '内分泌科', doctor: '刘副主任', hospital: '嘉城医院', status: 'upcoming' }
] as AppointmentType[],
bpTrend: [
{ day: '周一', sys: 145, dia: 88 },
{ day: '周二', sys: 150, dia: 92 },
{ day: '周三', sys: 142, dia: 86 },
{ day: '周四', sys: 148, dia: 90 },
{ day: '周五', sys: 152, dia: 94 },
{ day: '周六', sys: 144, dia: 87 },
{ day: '周日', sys: 148, dia: 92 }
] as BpPointType[]
}
},
onLoad() {
const now = new Date()
const m = (now.getMonth() + 1).toString().padStart(2, '0')
const d = now.getDate().toString().padStart(2, '0')
this.todayDate = `${m}月${d}日`
},
methods: {
switchUser() {
uni.showToast({ title: '切换用户功能开发中', icon: 'none' })
},
editRecord() {
uni.showToast({ title: '编辑档案功能开发中', icon: 'none' })
},
addMedication() {
uni.showToast({ title: '添加用药功能开发中', icon: 'none' })
},
bookReview() {
uni.showToast({ title: '复查预约功能开发中', icon: 'none' })
}
}
}
</script>
<style>
.hm-page {
background-color: #f0f2f7;
min-height: 100vh;
}
.hm-scroll {
flex: 1;
}
.mt16 { margin-top: 16rpx; }
/* ===== 导航栏 ===== */
.detail-navbar {
display: flex;
flex-direction: row;
align-items: flex-end;
background-color: #ffffff;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #eeeeee;
box-sizing: border-box;
padding-top: var(--status-bar-height);
height: calc(88rpx + var(--status-bar-height));
}
.detail-navbar-back {
display: flex;
flex-direction: row;
align-items: center;
padding: 0 30rpx;
height: 88rpx;
width: 120rpx;
}
.back-arrow {
font-size: 44rpx;
color: #333333;
line-height: 1;
margin-right: 4rpx;
}
.back-text {
font-size: 28rpx;
color: #333333;
}
.detail-navbar-title {
flex: 1;
text-align: center;
font-size: 32rpx;
font-weight: 600;
color: #1a1a1a;
height: 88rpx;
line-height: 88rpx;
}
/* ===== 用户选择器 ===== */
.user-selector-card {
background: linear-gradient(135deg, rgb(66,121,240) 0%, rgb(40,80,180) 100%);
padding: 24rpx 30rpx 20rpx 30rpx;
}
.us-inner {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 16rpx;
}
.us-avatar-wrap {
margin-right: 20rpx;
}
.us-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 40rpx;
background-color: rgba(255,255,255,0.3);
color: #ffffff;
font-size: 34rpx;
font-weight: 700;
line-height: 80rpx;
text-align: center;
}
.us-info {
flex: 1;
display: flex;
flex-direction: column;
}
.us-name {
font-size: 32rpx;
font-weight: 700;
color: #ffffff;
margin-bottom: 6rpx;
}
.us-sub {
font-size: 22rpx;
color: rgba(255,255,255,0.8);
}
.us-switch-btn {
font-size: 24rpx;
color: rgba(255,255,255,0.9);
border-width: 1rpx;
border-style: solid;
border-color: rgba(255,255,255,0.5);
border-radius: 20rpx;
padding: 8rpx 20rpx;
}
.us-tags-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.us-tag {
font-size: 20rpx;
color: rgba(255,255,255,0.9);
background-color: rgba(255,255,255,0.15);
border-radius: 4rpx;
padding: 4rpx 14rpx;
margin-right: 10rpx;
}
.us-tag-danger {
background-color: rgba(255,80,80,0.35);
color: #ffcccc;
}
/* ===== 通用卡片 ===== */
.section-card {
background-color: #ffffff;
}
.section-card-title {
display: flex;
flex-direction: row;
align-items: center;
padding: 22rpx 30rpx 18rpx 30rpx;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f0f0f0;
}
.sct-icon { font-size: 30rpx; margin-right: 10rpx; }
.sct-text {
font-size: 28rpx;
font-weight: 600;
color: #1a1a1a;
flex: 1;
}
.sct-time {
font-size: 22rpx;
color: #999;
}
.sct-action {
font-size: 24rpx;
color: rgb(66,121,240);
}
/* ===== 健康数据网格 ===== */
.health-data-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 16rpx 16rpx 8rpx 16rpx;
}
.hd-item {
width: 33.33%;
display: flex;
flex-direction: column;
align-items: center;
padding: 16rpx 10rpx;
position: relative;
}
.hd-item-warning {
background-color: #fffbf0;
}
.hd-item-danger {
background-color: #fff0f0;
}
.hd-icon {
font-size: 36rpx;
margin-bottom: 8rpx;
}
.hd-val {
font-size: 30rpx;
font-weight: 700;
color: #1a1a1a;
line-height: 1;
}
.hd-unit {
font-size: 18rpx;
color: #999;
margin-top: 2rpx;
margin-bottom: 4rpx;
}
.hd-label {
font-size: 22rpx;
color: #666;
}
.hd-badge {
position: absolute;
top: 10rpx;
right: 10rpx;
font-size: 18rpx;
padding: 2rpx 8rpx;
border-radius: 4rpx;
}
.hd-badge-warning {
color: #FF7800;
background-color: #fff3e0;
}
.hd-badge-danger {
color: #E64A19;
background-color: #fde8e0;
}
/* ===== 健康档案 ===== */
.record-row {
display: flex;
flex-direction: row;
align-items: center;
padding: 16rpx 30rpx;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
}
.record-label {
font-size: 26rpx;
color: #999;
min-width: 150rpx;
flex-shrink: 0;
}
.record-val {
font-size: 26rpx;
color: #333;
flex: 1;
}
/* ===== 慢病管理 ===== */
.disease-item {
padding: 16rpx 30rpx;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
}
.disease-header {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 12rpx;
}
.disease-name {
font-size: 28rpx;
font-weight: 600;
color: #1a1a1a;
flex: 1;
}
.disease-status {
font-size: 22rpx;
border-radius: 4rpx;
padding: 4rpx 14rpx;
}
.ds-good {
color: #4CAF50;
background-color: #e8f5e9;
}
.ds-bad {
color: #E64A19;
background-color: #fde8e0;
}
.disease-indicators {
background-color: #f9f9f9;
border-radius: 8rpx;
padding: 10rpx 16rpx;
}
.di-row {
display: flex;
flex-direction: row;
align-items: center;
padding: 6rpx 0;
}
.di-label {
font-size: 24rpx;
color: #666;
min-width: 140rpx;
}
.di-val {
font-size: 26rpx;
color: #333;
font-weight: 500;
flex: 1;
}
.di-val-warn {
color: #E64A19;
}
.di-ref {
font-size: 20rpx;
color: #bbb;
}
/* ===== 用药提醒 ===== */
.med-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 30rpx;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
}
.med-left {
width: 36rpx;
display: flex;
align-items: center;
justify-content: center;
}
.med-dot {
width: 18rpx;
height: 18rpx;
border-radius: 9rpx;
}
.med-dot-done {
background-color: #4CAF50;
}
.med-dot-pending {
background-color: #FF7800;
}
.med-info {
flex: 1;
margin-left: 16rpx;
display: flex;
flex-direction: column;
}
.med-name {
font-size: 28rpx;
color: #1a1a1a;
margin-bottom: 6rpx;
}
.med-dose {
font-size: 22rpx;
color: #999;
}
.med-time-col {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.med-time {
font-size: 22rpx;
color: #666;
margin-bottom: 4rpx;
}
.med-status {
font-size: 20rpx;
border-radius: 4rpx;
padding: 2rpx 10rpx;
}
.ms-done {
color: #4CAF50;
background-color: #e8f5e9;
}
.ms-pending {
color: #FF7800;
background-color: #fff3e0;
}
/* ===== 复查预约 ===== */
.appt-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 30rpx;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
}
.appt-date-col {
width: 72rpx;
display: flex;
flex-direction: column;
align-items: center;
margin-right: 20rpx;
background-color: #eef2fe;
border-radius: 8rpx;
padding: 8rpx 10rpx;
}
.appt-month {
font-size: 18rpx;
color: rgb(66,121,240);
}
.appt-day {
font-size: 34rpx;
font-weight: 700;
color: rgb(66,121,240);
line-height: 1;
}
.appt-info {
flex: 1;
display: flex;
flex-direction: column;
}
.appt-title {
font-size: 28rpx;
color: #1a1a1a;
font-weight: 500;
margin-bottom: 6rpx;
}
.appt-desc {
font-size: 22rpx;
color: #666;
margin-bottom: 4rpx;
}
.appt-location {
font-size: 20rpx;
color: #999;
}
.appt-tag {
font-size: 22rpx;
border-radius: 4rpx;
padding: 4rpx 14rpx;
}
.at-upcoming {
color: rgb(66,121,240);
background-color: #eef2fe;
}
.at-done {
color: #999;
background-color: #f5f5f5;
}
/* ===== 血压趋势图 ===== */
.chart-area {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: space-around;
padding: 20rpx 30rpx 10rpx 30rpx;
height: 180rpx;
}
.bar-group {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.bar-pair {
display: flex;
flex-direction: row;
align-items: flex-end;
margin-bottom: 8rpx;
}
.bar {
width: 14rpx;
border-radius: 4rpx 4rpx 0 0;
margin: 0 2rpx;
min-height: 6rpx;
}
.bar-sys {
background-color: rgb(66,121,240);
}
.bar-dia {
background-color: #84a8f8;
}
.bar-label {
font-size: 18rpx;
color: #999;
}
.chart-legend {
display: flex;
flex-direction: row;
justify-content: center;
padding: 10rpx 30rpx 20rpx 30rpx;
}
.legend-item {
display: flex;
flex-direction: row;
align-items: center;
margin: 0 20rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 3rpx;
margin-right: 8rpx;
}
.ld-sys { background-color: rgb(66,121,240); }
.ld-dia { background-color: #84a8f8; }
.legend-text {
font-size: 22rpx;
color: #666;
}
/* ===== 通用 ===== */
.empty-tip {
padding: 40rpx 30rpx;
display: flex;
flex-direction: row;
justify-content: center;
}
.empty-tip-text {
font-size: 26rpx;
color: #bbb;
}
</style>