1. 项目概述:老年人健康管理系统的技术实现
这个项目是我去年带队开发的一套面向老年群体的健康管理平台。当时我们团队接到某社区卫生服务中心的需求,希望打造一个能整合健康档案、就诊预约和日常健康管理的系统。经过三个月的开发迭代,最终形成了这套基于ThinkPHP+Vue.js的解决方案。
系统最大的特点是将老年人常见的健康管理需求进行了数字化整合。传统的健康管理往往需要老年人频繁跑医院,各种检查报告散落在不同科室,用药提醒全靠家人手写便签。我们这个系统通过前后端分离架构,实现了数据集中管理+多终端访问的模式,子女可以通过手机帮父母预约挂号,老人在家就能查看最新的检查报告,系统还会自动推送用药提醒。
2. 技术架构设计
2.1 为什么选择ThinkPHP+Vue.js
在技术选型阶段,我们主要考虑了以下几个因素:
-
开发效率:社区卫生服务中心的预算有限,需要快速上线验证效果。ThinkPHP作为国内最成熟的PHP框架之一,其丰富的开发文档和社区资源能显著降低开发风险。
-
维护成本:系统后期将由社区卫生服务中心的兼职IT人员维护。PHP+MySQL的组合在中小型机构中的普及度最高,维护门槛低。
-
用户体验:老年用户对界面友好度要求极高。Vue.js的响应式特性和组件化开发模式,使我们能快速迭代出符合老年人操作习惯的界面。
实际开发中,我们采用了如下技术栈:
code复制后端:
- 核心框架:ThinkPHP 6.0
- Web服务器:Apache
- 数据库:MySQL 5.7
- 开发环境:PHPStudy
前端:
- 核心框架:Vue.js 2.6 + Element UI
- 构建工具:Webpack 4
- 图表库:ECharts 4.0
2.2 系统分层架构
系统采用典型的三层架构设计:
code复制表现层(Vue.js)
├─ 用户界面
├─ 路由管理
└─ 状态管理(Vuex)
业务逻辑层(ThinkPHP)
├─ 控制器
├─ 服务层
└─ 模型验证
数据访问层
├─ 数据库操作(Eloquent ORM)
├─ 文件存储
└─ 缓存管理
这种架构带来了几个明显优势:
- 前后端完全解耦,移动端和PC端可以复用同一套API
- 数据库操作全部通过ORM完成,SQL注入风险大幅降低
- 业务逻辑集中在服务层,便于后期扩展健康管理算法
3. 核心功能实现细节
3.1 健康档案模块
这是系统的核心模块,我们设计了以下数据结构:
php复制// 健康档案模型
class HealthRecord extends Model
{
// 基础信息
protected $fillable = [
'user_id',
'blood_type',
'allergy_history',
'chronic_diseases' // JSON格式存储慢性病信息
];
// 关联体检报告
public function reports()
{
return $this->hasMany('app\model\MedicalReport');
}
}
前端采用标签页形式组织信息:
vue复制<el-tabs v-model="activeTab">
<el-tab-pane label="基本信息" name="basic">
<health-basic :data="basicInfo"/>
</el-tab-pane>
<el-tab-pane label="体检报告" name="reports">
<report-chart :data="reportData"/>
</el-tab-pane>
</el-tabs>
注意事项:老年用户的体检报告需要特别处理异常指标。我们通过颜色标注(红色↑/↓)和通俗易懂的解释文字(如"血糖偏高,建议减少主食摄入")来增强可读性。
3.2 智能用药提醒
这个功能我们接入了微信服务号推送,关键实现逻辑:
php复制// 用药提醒服务
class MedicationReminder
{
public function checkSchedule()
{
$medications = Medication::where('next_reminder_time', '<=', time())
->with('user')
->select();
foreach ($medications as $med) {
$this->sendWechatNotice($med);
$this->updateNextTime($med);
}
}
private function sendWechatNotice($medication)
{
$openid = $medication->user->wechat_openid;
$template = [
'touser' => $openid,
'template_id' => config('wechat.reminder_template'),
'data' => [
'medicine' => $medication->name,
'dosage' => $medication->dosage,
'time' => date('H:i')
]
];
app('wechat')->sendTemplateMessage($template);
}
}
前端用药设置界面特别增加了语音输入功能,方便视力不好的老年用户:
vue复制<el-form-item label="用药时间">
<el-time-picker
v-model="medication.time"
:editable="false"
placeholder="选择时间">
</el-time-picker>
<voice-input @recognized="handleVoiceInput"/>
</el-form-item>
4. 适老化设计实践
4.1 界面设计规范
我们制定了严格的适老化设计标准:
- 字体大小不小于16px,重要信息不小于20px
- 颜色对比度至少达到4.5:1
- 所有交互元素点击区域不小于44×44px
- 关键操作提供语音引导
通过Vue的mixin实现全局样式控制:
javascript复制// 适老化mixin
export default {
computed: {
elderStyle() {
return {
'font-size': this.$store.state.fontSize + 'px',
'theme': this.$store.state.highContrast ? 'dark' : 'light'
}
}
}
}
4.2 简化操作流程
针对老年人容易忘记密码的问题,我们实现了:
- 图形验证码+短信验证码双因素登录
- 子女账号关联,支持远程协助
- 一键呼叫客服功能
登录组件关键代码:
vue复制<template>
<div class="login-container">
<el-form>
<el-form-item>
<el-input
v-model="form.phone"
placeholder="手机号"
:style="elderStyle">
<template #prefix>
<icon-phone/>
</template>
</el-input>
</el-form-item>
<el-form-item>
<div class="captcha-wrapper">
<el-input
v-model="form.captcha"
placeholder="验证码"
:style="elderStyle">
</el-input>
<el-button
type="primary"
@click="sendSms"
:disabled="countdown > 0">
{{ countdown ? `${countdown}s后重试` : '获取验证码' }}
</el-button>
</div>
</el-form-item>
</el-form>
<emergency-call-button/>
</div>
</template>
5. 安全与性能优化
5.1 数据安全措施
- 敏感数据加密:
php复制// 病历数据加密存储
protected function encryptData($data)
{
return openssl_encrypt(
$data,
'AES-256-CBC',
config('app.encrypt_key'),
0,
config('app.encrypt_iv')
);
}
- 权限控制中间件:
php复制class AuthMiddleware
{
public function handle($request, Closure $next)
{
$user = Session::get('user');
if (!$user || !$user->canAccessMedicalData()) {
return response()->json(['error' => '无权访问'], 403);
}
return $next($request);
}
}
5.2 性能优化方案
- 接口响应时间优化:
- 使用Redis缓存高频访问的健康数据
- 数据库查询优化:为体检报告表添加了复合索引(user_id, check_date)
- 前端性能提升:
- 采用路由懒加载
- 使用Webpack的SplitChunksPlugin拆分公共代码
- 对ECharts图表进行按需加载
javascript复制// 动态加载ECharts组件
const loadChart = () => import(
/* webpackChunkName: "echarts" */
'echarts/lib/echarts'
);
6. 部署与运维实践
6.1 服务器配置建议
我们推荐的最低生产环境配置:
code复制CPU: 4核
内存: 8GB
存储: 100GB SSD
带宽: 5Mbps
操作系统: Ubuntu 20.04 LTS
Nginx关键配置优化:
nginx复制server {
listen 80;
server_name health.example.com;
root /var/www/health-system/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# 前端静态资源缓存
location ~* \.(js|css|png|jpg)$ {
expires 30d;
add_header Cache-Control "public";
}
}
6.2 日常维护要点
- 数据备份策略:
bash复制# 每日数据库备份脚本
mysqldump -u root -p$PASSWORD health_db | gzip > /backups/health_$(date +%F).sql.gz
# 保留最近30天备份
find /backups -type f -name '*.sql.gz' -mtime +30 -delete
- 日志监控:
- 使用Logrotate管理PHP和Nginx日志
- 关键API接口日志单独记录:
php复制Log::channel('api')->info('预约挂号', [
'user_id' => $user->id,
'doctor_id' => $doctorId,
'ip' => $request->ip()
]);
7. 开发经验与教训
7.1 踩过的坑
- 时间处理问题:
初期直接使用前端时间戳导致时区混乱,后来统一采用:
javascript复制// 前端处理时区
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.tz.setDefault('Asia/Shanghai')
- 移动端兼容性:
某些安卓机型对flex布局支持不佳,需要增加fallback:
css复制.elder-button {
display: -webkit-box; /* 老版本安卓 */
display: -webkit-flex; /* iOS 6- */
display: flex;
}
7.2 值得推荐的实践
- 接口文档自动化:
使用ThinkPHP的注解生成API文档:
php复制/**
* @route("api/report/list")
* @param("page", type="int", default=1)
* @return("体检报告列表")
*/
public function getReportList($page = 1)
{
// ...
}
- 前端错误监控:
接入Sentry捕获前端异常:
javascript复制import * as Sentry from '@sentry/vue';
Sentry.init({
dsn: 'https://example@sentry.io/1',
release: 'health-system@' + process.env.VERSION,
tracesSampleRate: 0.2
});
这个项目让我深刻体会到,开发老年人使用的系统不仅需要考虑技术实现,更需要从用户体验角度思考每一个细节。比如我们最初设计的用药提醒只有文字提示,后来根据用户反馈增加了语音播报和闪光提醒,大幅提高了使用效果。技术最终是要服务于人的,特别是面对老年用户群体时,更需要我们开发者保持同理心和耐心。