怎样在PHP项目中实现在线问诊?

wen java案例 2

本文目录导读:

怎样在PHP项目中实现在线问诊?

  1. 核心功能模块
  2. 技术架构选择
  3. 数据库表设计 (核心表)
  4. 核心流程实现 (以“图文咨询 + 第三方IM”为例)
  5. 必须注意的关键问题
  6. 总结与推荐

在PHP项目中实现在线问诊功能是一个复杂的系统工程,涉及前端交互、后端业务逻辑、数据安全、实时通信以及医疗合规等多个方面,下面我会为你提供一个从基础到进阶的设计思路和实现步骤。

核心功能模块

一个完整的在线问诊系统通常包含以下模块:

  1. 用户端

    • 图文咨询:发送文字消息、图片(如病历、检查单)。
    • 语音/视频咨询:实时音视频通话。
    • 问诊记录:查看历史对话、处方、医生建议。
    • 支付:支付咨询费。
  2. 医生端

    • 接诊面板:查看待接诊、进行中的患者列表。
    • 回复系统:输入文字、发送图片、发送语音、发起视频。
    • 开具处方/诊断:填写诊断结果、开具电子处方(药品、用法用量)。
    • 患者管理:查看历史患者,回顾历史病历。
  3. 管理后台

    • 医生管理:审核医生资质、排班、上下线。
    • 问诊监控:查看实时问诊状态,处理投诉。
    • 数据统计:问诊量、收入、用户满意度等。

技术架构选择

关键决策:实时通信方案

这是在线问诊的核心,PHP 是阻塞式的,不适合直接处理长时间的双向连接(如WebSocket),因此你需要选择以下方案之一:

  • 方案A:采用第三方服务(推荐)

    • 优点:开发成本低,稳定性高,自带合规证书。
    • 流行选项
      • 腾讯云IM(即时通信):集成简单,支持文字、图片、语音、视频。
      • 声网(Agora):专注音视频领域,延迟极低。
      • 环信、融云:成熟的IM/PaaS平台。
    • 工作流程
      1. 你的PHP后端生成通信所需的 Token/AppKey。
      2. 前端(H5/App)使用SDK直接连接第三方服务器进行实时通信。
      3. PHP后端通过第三方提供的回调或REST API 获取聊天记录、通话时长等数据并存储到自己的数据库。
  • 方案B:自建WebSocket服务 + Swoole/Workerman

    • 原理:PHP 7/8配合Swoole扩展或Workerman框架,常驻内存,性能接近Go/Java。
    • 优点:完全控制数据,长期来看成本可控。
    • 缺点:开发复杂度高,需要对Swoole/Workerman有深入了解,需要处理高并发下的连接管理。
    • 实现:PHP后端作为WebSocket服务器,前端建立WebSocket连接,PHP负责转发消息、存储聊天记录。

存储与业务逻辑

  • PHP框架:Laravel、ThinkPHP、Symfony 等。
  • 数据库
    • MySQL:存储用户信息、订单、病历、药品库。
    • Redis:缓存医生在线状态、未读消息数、会话锁。
  • 文件存储:阿里云OSS、腾讯云COS 或 本地分布式存储。不要存图片到数据库

数据库表设计 (核心表)

-- 问诊订单表
CREATE TABLE `consultation_orders` (
    `id` bigint unsigned NOT NULL AUTO_INCREMENT,
    `order_sn` varchar(32) NOT NULL COMMENT '订单号',
    `user_id` bigint unsigned NOT NULL COMMENT '患者ID',
    `doctor_id` bigint unsigned NOT NULL COMMENT '医生ID',
    `status` tinyint NOT NULL DEFAULT '0' COMMENT '状态: 0待支付, 1待接诊, 2进行中, 3已完成, 4已取消',
    `type` tinyint NOT NULL COMMENT '类型: 1图文, 2语音, 3视频',
    `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '金额',
    `start_time` datetime DEFAULT NULL COMMENT '接诊时间',
    `end_time` datetime DEFAULT NULL COMMENT '结束时间',
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_user_id` (`user_id`),
    KEY `idx_doctor_id` (`doctor_id`),
    KEY `idx_status` (`status`)
);
-- 消息记录表 (如果自建IM)
CREATE TABLE `chat_messages` (
    `id` bigint unsigned NOT NULL AUTO_INCREMENT,
    `order_id` bigint unsigned NOT NULL COMMENT '会话ID',
    `sender_type` tinyint NOT NULL COMMENT '发送者类型: 1患者, 2医生',
    `msg_type` tinyint NOT NULL COMMENT '消息类型: 1文本, 2图片, 3语音, 4视频',
    `content` text COMMENT '文本内容 或 文件URL',
    `duration` int DEFAULT '0' COMMENT '音频/视频时长(秒)',
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_order_id` (`order_id`)
);
-- 处方表
CREATE TABLE `prescriptions` (
    `id` bigint unsigned NOT NULL AUTO_INCREMENT,
    `order_id` bigint unsigned NOT NULL,
    `doctor_id` bigint unsigned NOT NULL,
    `diagnosis` text COMMENT '诊断结果',
    `advice` text COMMENT '医师建议',
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
);
-- 处方明细表
CREATE TABLE `prescription_items` (
    `id` bigint unsigned NOT NULL AUTO_INCREMENT,
    `prescription_id` bigint unsigned NOT NULL,
    `drug_name` varchar(100) NOT NULL COMMENT '药品名称',
    `specification` varchar(50) COMMENT '规格',
    `dosage` varchar(50) COMMENT '用量',
    `frequency` varchar(50) COMMENT '频次',
    `days` tinyint COMMENT '天数',
    `quantity` int COMMENT '数量',
    PRIMARY KEY (`id`)
);

核心流程实现 (以“图文咨询 + 第三方IM”为例)

创建问诊订单

// ConsultationController.php (Laravel 示例)
public function createOrder(Request $request) {
    // 1. 验证参数
    $userId = auth()->id();
    $doctorId = $request->input('doctor_id');
    $type = $request->input('type', 1); // 1=图文
    // 2. 检查医生在线状态 (从Redis获取)
    $doctorOnline = Redis::get('doctor:online:'.$doctorId);
    if (!$doctorOnline) {
        return response()->json(['error' => '医生当前不在线'], 400);
    }
    // 3. 生成订单(状态为待支付)
    $order = ConsultationOrder::create([
        'order_sn' => generateOrderSn(),
        'user_id' => $userId,
        'doctor_id' => $doctorId,
        'type' => $type,
        'status' => 0, // 待支付
        'amount' => $doctor->consultation_fee,
    ]);
    // 4. 生成支付凭证 (调用支付网关)
    // ...
    return response()->json(['order' => $order, 'payment_url' => $payUrl]);
}

支付成功后,分配会话

// PaymentController.php (支付回调)
public function paymentCallback(Request $request) {
    // 1. 验证签名
    // 2. 更新订单状态为 "待接诊"
    $order = ConsultationOrder::where('order_sn', $request->order_sn)->first();
    $order->status = 1;
    $order->save();
    // 3. 通过第三方IM创建会话 (例如使用腾讯云IM)
    // 调用腾讯云IM API:创建一个新的单聊会话
    // 参数:from_account = 系统管理员,to_account = 医生ID,会话组 = 患者ID
    $imService->createConversation($order->user_id, $order->doctor_id);
    // 4. 通知医生有新订单 (通过WebSocket 或 推送)
    event(new NewConsultationEvent($order));
    // 5. 生成通信Token
    $userSig = $imService->genUserSig($order->user_id);
    $doctorSig = $imService->genUserSig($order->doctor_id);
    // 返回给前端
}

前端接入第三方IM

// 前端 (JS SDK 示例)
// 1. 初始化 SDK
let tim = TIM.create({
    SDKAppID: YOUR_SDK_APP_ID
});
// 2. 登录 (用户点击开始咨询时)
tim.login({
    userID: userId,
    userSig: userSig // 从PHP后端获取
});
// 3. 获取会话列表
let conversation = tim.getConversationList();
// 4. 发送消息 (用户输入并点击发送)
let message = tim.createTextMessage({
    to: doctorUserId,
    conversationType: TIM.TYPES.CONV_C2C,
    payload: { text: '医生您好,我最近经常头痛...' }
});
tim.sendMessage(message);
// 5. 接收消息 (监听事件)
tim.on(TIM.EVENT.MESSAGE_RECEIVED, function(event) {
    // 新消息到达,更新聊天界面
});

医生开具处方

// DoctorPrescriptionController.php
public function createPrescription(Request $request, $orderId) {
    $order = ConsultationOrder::findOrFail($orderId);
    // 验证医生身份
    if ($order->doctor_id != auth()->id()) {
        abort(403);
    }
    // 创建处方主表
    $prescription = Prescription::create([
        'order_id' => $orderId,
        'doctor_id' => auth()->id(),
        'diagnosis' => $request->input('diagnosis'),
        'advice' => $request->input('advice'),
    ]);
    // 创建处方明细
    foreach ($request->input('drugs') as $drug) {
        $prescription->items()->create($drug);
    }
    // 更新订单状态为 "已完成"
    $order->status = 3; // 已完成
    $order->end_time = now();
    $order->save();
    // 通知患者 (推送)
    return response()->json(['prescription' => $prescription->load('items')]);
}

必须注意的关键问题

  1. 数据安全与合规

    • 问诊数据是敏感医疗数据。必须使用HTTPS 传输。
    • 数据库中的问诊记录、处方、聊天记录等应做加密存储(字段级加密或全库加密)。
    • 严格遵守当地医疗数据保护法规(如中国的《互联网诊疗管理办法》),问诊记录需保留至少15年
  2. 医生资质核验

    • 上线前必须强制医生上传《医师执业证》、《医师资格证》。
    • 后台有严格的审核流程,确保“人证合一”。
  3. 责任划分

    • 清晰的用户协议,界定“在线问诊仅提供健康咨询,不能替代线下诊疗”。
    • 处方药需要更强的审核机制(如医生电子签名)。
  4. 性能优化

    • 冷热数据分离:将最近1个月的问诊记录放在MySQL热库,历史数据定期迁移到归档库或ES。
    • 缓存:医生排班、在线状态、常见问答等缓存到Redis。
  5. 应急处理

    • 断线重连:音视频或IM服务需要实现牢固的重连机制。
    • 超时未接诊:如果医生5分钟未接诊,系统自动取消订单并全额退款。

总结与推荐

  • 学习成本最低、最稳定的方案:PHP(Laravel)+ 第三方IM/音视频服务(腾讯云IM/声网)

    • PHP专注于处理订单、用户、支付、处方这些业务逻辑
    • 实时通信交给专业的第三方平台,你只需要几个API调用就搞定了。
  • 如果想自己秀肌肉或成本极致压缩:PHP(Laravel) + Workerman/Swoole + WebSocket。

    • 你自己实现消息的路由、持久化、推送。
    • 注意:这会消耗大量时间和Bug调试,除非你的团队有Swoole专家,否则不推荐自建IM。

额外建议:不要试图在一个Query里查所有聊天记录,分页加载,一定要做好图片、语音文件的CDN加速,否则医生打开患者发的检查单图片会非常慢。

如果需要更具体的代码片段或某个模块的深入讲解,可以告诉我你卡在哪一步。

抱歉,评论功能暂时关闭!