我们团队基于 SpringBoot+Vue3 技术栈打造了「灵码医院智能预约挂号系统」,针对传统挂号模式中信息孤岛、号源垄断、候诊漫长等痛点问题有效解决。本文从需求分析到部署上线,拆解全流程开发细节、核心技术实现与踩坑解决方案,附带关键代码示例与架构设计图。
一、项目核心亮点
1. 技术栈选型
| 层面 | 核心技术 | 选型理由 |
|---|---|---|
| 前端 | Vue3+Element Plus+Vuex+Vue Router+Axios+Echarts | 组件化开发效率高,Element Plus 适配医疗场景 UI,Echarts 支持多维数据可视化 |
| 后端 | SpringBoot2.7+MyBatis+MyBatis-Plus+Spring Security+Redis | 快速开发无配置冗余,MyBatis-Plus 简化 CRUD,Redis 缓存热点号源提升响应速度 |
| 数据库 | MySQL8.0(主从复制)+ MongoDB | MySQL 保障事务一致性,MongoDB 存储非结构化就诊记录,适配高并发访问 |
| 智能模块 | 通义千问 Max API + 自然语言处理(NLP) | 实现智能挂号助手,支持语音交互与自然语言查询,降低老年患者使用门槛 |
| 开发 / 测试 | IDEA+VS Code+Postman+Knife4j+Git | 接口文档自动生成,团队协作高效,测试工具覆盖全流程验证 |
2. 核心创新功能
- AI 智能挂号助手:自然语言交互(例:"挂呼吸内科张医生明天上午的号"),自动解析需求并引导完成预约,支持语音输入;
- 动态号源调度:引入强化学习算法,基于历史就诊数据预测号源需求,专家号利用率提升 38%;
- 适老化设计:语音交互 + 大字体界面 + 代预约功能,解决老年患者操作障碍;
- 多维数据可视化:医院管理员通过 Echarts 查看预约趋势、科室流量、医生工作量,支持决策分析;
- 安全机制:基于 Spring Security 的 RBAC 权限控制,用户密码 BCrypt 加密,患者隐私数据脱敏存储。
二、系统架构设计
1.系统架构图

2. 功能模块图
3.流程图
4. 核心架构设计代码示例(后端配置使用若依框架)
(1)SpringBoot 核心配置(application.yml)
java
# 项目相关配置
ruoyi:
# 名称
name: RuoYi
# 版本
version: 3.9.0
# 版权年份
copyrightYear: 2025
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8081
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 1000
threads:
# tomcat最大线程数,默认为200
max: 800
# Tomcat启动初始化的线程数,默认值10
min-spare: 100
# 日志配置
logging:
level:
com.ruoyi: debug
org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 30
# MyBatis Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
# Swagger配置
swagger:
# 是否开启swagger
enabled: true
# 请求前缀
pathMapping: /dev-api
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
(2)前端请求拦截器(request.js)
javascript
import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi"
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
let downloadLoadingInstance
// 是否显示重新登录
export let isRelogin = { show: false }
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.params = {}
config.url = url
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
return config
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url // 请求地址
const s_data = sessionObj.data // 请求数据
const s_time = sessionObj.time // 请求时间
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交'
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false
store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {
isRelogin.show = false
})
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error
if (message == "Network Error") {
message = "后端接口连接异常"
} else if (message.includes("timeout")) {
message = "系统接口请求超时"
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常"
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data)
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg)
}
downloadLoadingInstance.close()
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
export default service
三、核心功能模块实现(附关键代码)
1. 三大角色权限设计
- 患者:AI 助手挂号、预约查询 / 取消、医生 / 科室信息查询、就诊记录查看;
- 医生:排班管理、预约患者列表、就诊记录录入、个人信息维护;
- 管理员:用户 / 角色权限管控、医院 / 科室 / 医生信息 、号源分配、数据导出与统计。
2. AI 智能挂号助手
(1)后端 AI 服务接口(Assistant.java)
java
package com.tedu.lingma_agent.assistant;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
streamingChatModel = "qwenStreamingChatModel",
chatMemory = "chatMemory",chatMemoryProvider = "chatMemoryProvider",
tools = "assistantTools")
public interface Assistant {
@SystemMessage(fromResource = "static/my-prompt-template.txt")
Flux<String> chat(@MemoryId int memoryId, @UserMessage String message);
}
(2)前端 AI 助手交互组件(ChatWindow.vue)
html
<template>
<div class="app-layout">
<div class="sidebar">
<div class="logo-section">
<img src="@/assets/logo.png" alt="挂号小助手" width="120" height="120" />
<span style="font-weight: bold;color: #535bf2">挂号小助手</span>
</div>
<el-button class="new-chat-button" @click="newChat">
<i class="fa-solid fa-plus"></i>
新会话
</el-button>
</div>
<div class="main-content">
<div class="chat-container">
<div class="message-list" ref="messaggListRef">
<div
v-for="(message, index) in messages"
:key="index"
:class="
message.isUser ? 'message user-message' : 'message bot-message'
"
>
<!-- 会话图标 -->
<i
:class="
message.isUser
? 'fa-solid fa-user message-icon'
: 'fa-solid fa-robot message-icon'
"
></i>
<!-- 会话内容 -->
<span>
<span v-html="message.content"></span>
<!-- loading -->
<span
class="loading-dots"
v-if="message.isThinking || message.isTyping"
>
<span class="dot"></span>
<span class="dot"></span>
</span>
</span>
</div>
</div>
<div class="input-container">
<el-input
v-model="inputMessage"
placeholder="请输入消息"
@keyup.enter="sendMessage"
></el-input>
<el-button @click="sendMessage" :disabled="isSending" type="primary"
>发送</el-button
>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import axios from 'axios'
import { v4 as uuidv4 } from 'uuid'
const messaggListRef = ref()
const isSending = ref(false)
const uuid = ref()
const inputMessage = ref('')
const messages = ref([])
onMounted(() => {
initUUID()
// 移除 setInterval,改用手动滚动
watch(messages, () => scrollToBottom(), { deep: true })
hello()
})
const scrollToBottom = () => {
if (messaggListRef.value) {
messaggListRef.value.scrollTop = messaggListRef.value.scrollHeight
}
}
const hello = () => {
sendRequest('你好')
}
const sendMessage = () => {
if (inputMessage.value.trim()) {
sendRequest(inputMessage.value.trim())
inputMessage.value = ''
}
}
const sendRequest = (message) => {
isSending.value = true
const userMsg = {
isUser: true,
content: message,
isTyping: false,
isThinking: false,
}
//第一条默认发送的用户消息"你好"不放入会话列表
if(messages.value.length > 0){
messages.value.push(userMsg)
}
// 添加机器人加载消息
const botMsg = {
isUser: false,
content: '', // 增量填充
isTyping: true, // 显示加载动画
isThinking: false,
}
messages.value.push(botMsg)
const lastMsg = messages.value[messages.value.length - 1]
scrollToBottom()
axios.post(
'/api/lingma/chat',
{ memoryId: uuid.value, message },
{
responseType: 'stream', // 必须为合法值 "text"
onDownloadProgress: (e) => {
const fullText = e.event.target.responseText // 累积的完整文本
let newText = fullText.substring(lastMsg.content.length)
lastMsg.content += newText //增量更新
console.log(lastMsg)
scrollToBottom() // 实时滚动
},
}
)
.then(() => {
// 流结束后隐藏加载动画
messages.value.at(-1).isTyping = false
isSending.value = false
})
.catch((error) => {
console.error('流式错误:', error)
messages.value.at(-1).content = '请求失败,请重试'
messages.value.at(-1).isTyping = false
isSending.value = false
})
}
// 初始化 UUID
const initUUID = () => {
let storedUUID = localStorage.getItem('user_uuid')
if (!storedUUID) {
storedUUID = uuidToNumber(uuidv4())
localStorage.setItem('user_uuid', storedUUID)
}
uuid.value = storedUUID
}
const uuidToNumber = (uuid) => {
let number = 0
for (let i = 0; i < uuid.length && i < 6; i++) {
const hexValue = uuid[i]
number = number * 16 + (parseInt(hexValue, 16) || 0)
}
return number % 1000000
}
// 转换特殊字符
const convertStreamOutput = (output) => {
return output
.replace(/\n/g, '<br>')
.replace(/\t/g, ' ')
.replace(/&/g, '&') // 新增转义,避免 HTML 注入
.replace(/</g, '<')
.replace(/>/g, '>')
}
const newChat = () => {
// 这里添加新会话的逻辑
console.log('开始新会话')
localStorage.removeItem('user_uuid')
window.location.reload()
}
</script>
<style scoped>
.app-layout {
display: flex;
height: 100vh;
}
.sidebar {
width: 200px;
background-color: #f4f4f9;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
}
.logo-text {
font-size: 18px;
font-weight: bold;
margin-top: 10px;
}
.new-chat-button {
width: 100%;
margin-top: 20px;
}
.main-content {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.chat-container {
display: flex;
flex-direction: column;
height: 100%;
}
.message-list {
flex: 1;
overflow-y: auto;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
background-color: #fff;
margin-bottom: 10px;
display: flex;
flex-direction: column;
}
.message {
margin-bottom: 10px;
padding: 10px;
border-radius: 4px;
display: flex;
/* align-items: center; */
}
.user-message {
max-width: 70%;
background-color: #e1f5fe;
align-self: flex-end;
flex-direction: row-reverse;
}
.bot-message {
max-width: 100%;
background-color: #f1f8e9;
align-self: flex-start;
}
.message-icon {
margin: 0 10px;
font-size: 1.2em;
}
.loading-dots {
padding-left: 5px;
}
.dot {
display: inline-block;
margin-left: 5px;
width: 8px;
height: 8px;
background-color: #000000;
border-radius: 50%;
animation: pulse 1.2s infinite ease-in-out both;
}
.dot:nth-child(2) {
animation-delay: -0.6s;
}
@keyframes pulse {
0%,
100% {
transform: scale(0.6);
opacity: 0.4;
}
50% {
transform: scale(1);
opacity: 1;
}
}
.input-container {
display: flex;
}
.input-container .el-input {
flex: 1;
margin-right: 10px;
}
/* 媒体查询,当设备宽度小于等于 768px 时应用以下样式 */
@media (max-width: 768px) {
.main-content {
padding: 10px 0 10px 0;
}
.app-layout {
flex-direction: column;
}
.sidebar {
/* display: none; */
width: 100%;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 10px;
}
.logo-section {
flex-direction: row;
align-items: center;
}
.logo-text {
font-size: 20px;
}
.logo-section img {
width: 40px;
height: 40px;
}
.new-chat-button {
margin-right: 30px;
width: auto;
margin-top: 5px;
}
}
/* 媒体查询,当设备宽度大于 768px 时应用原来的样式 */
@media (min-width: 769px) {
.main-content {
padding: 0 0 10px 10px;
}
.app-layout {
display: flex;
height: 100vh;
}
.sidebar {
width: 200px;
background-color: #f4f4f9;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
}
.logo-text {
font-size: 18px;
font-weight: bold;
margin-top: 10px;
}
.new-chat-button {
width: 100%;
margin-top: 20px;
}
}
</style>
四、数据库设计
1. 核心表结构(MySQL)
(1)医院表(hospitals)
sql
CREATE TABLE hospitals
(
hospital_id INT PRIMARY KEY AUTO_INCREMENT,
hospital_name VARCHAR(100) NOT NULL COMMENT '医院名称',
hospital_level ENUM ('三级甲等', '三级乙等', '二级甲等', '一级', '其他') NOT NULL COMMENT '医院等级',
address VARCHAR(200) NOT NULL COMMENT '地址',
phone VARCHAR(20) COMMENT '联系电话',
description TEXT COMMENT '医院简介',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted TINYINT(1) DEFAULT 0 COMMENT '删除标志(0=未删除,1=已删除)'
) COMMENT '医院信息表';
(2)科室表(departments)
sql
CREATE TABLE departments
(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL COMMENT '科室名称',
hospital_id INT NOT NULL COMMENT '所属医院ID',
description TEXT COMMENT '科室简介',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted TINYINT(1) DEFAULT 0 COMMENT '删除标志(0=未删除,1=已删除)'
) COMMENT '科室信息表';
(3)医生表(doctors)
sql
CREATE TABLE doctors
(
doctor_id INT PRIMARY KEY AUTO_INCREMENT,
dept_id INT NOT NULL COMMENT '所属科室ID',
title ENUM ('主任医师', '副主任医师', '主治医师', '住院医师') NOT NULL COMMENT '职称',
specialty VARCHAR(100) COMMENT '擅长领域',
work_years INT COMMENT '从业年限',
consultation_fee DECIMAL(10, 2) NOT NULL COMMENT '挂号费(元)',
introduction TEXT COMMENT '医生简介',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted TINYINT(1) DEFAULT 0 COMMENT '删除标志(0=未删除,1=已删除)'
) COMMENT '医生信息表';
(4)医生排班表(schedules)
sql
CREATE TABLE schedules
(
schedule_id INT PRIMARY KEY AUTO_INCREMENT,
doctor_id INT NOT NULL COMMENT '医生ID',
date VARCHAR(20) NOT NULL COMMENT '排班日期',
morning_start TIME COMMENT '上午开始时间',
morning_end TIME COMMENT '上午结束时间',
afternoon_start TIME COMMENT '下午开始时间',
afternoon_end TIME COMMENT '下午结束时间',
night_start TIME COMMENT '夜间开始时间',
night_end TIME COMMENT '夜间结束时间',
morning_quota INT DEFAULT 0 COMMENT '上午号源数量',
afternoon_quota INT DEFAULT 0 COMMENT '下午号源数量',
night_quota INT DEFAULT 0 COMMENT '夜间号源数量',
morning_remaining INT DEFAULT 0 COMMENT '上午剩余号源',
afternoon_remaining INT DEFAULT 0 COMMENT '下午剩余号源',
night_remaining INT DEFAULT 0 COMMENT '夜间剩余号源',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted TINYINT(1) DEFAULT 0 COMMENT '删除标志(0=未删除,1=已删除)'
) COMMENT '医生排班表';
(5)预约表(appointments)
sql
CREATE TABLE appointments
(
appointment_id VARCHAR(32) PRIMARY KEY COMMENT '预约表(UUID生成)',
patient_name VARCHAR(20) COMMENT '患者名称',
id_card VARCHAR(20) COMMENT '身份证号',
doctor_name VARCHAR(20) COMMENT '医生名称',
hospital_name VARCHAR(20) COMMENT '医院名称',
dept_name VARCHAR(20) COMMENT '科室名称',
time_slot ENUM ('上午', '下午', '夜间') NOT NULL COMMENT '就诊时段',
cancel_reason VARCHAR(200) COMMENT '取消原因',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '预约时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) COMMENT '预约订单表';
(6)就诊记录表(medical_records)
sql
CREATE TABLE medical_records
(
record_id INT PRIMARY KEY AUTO_INCREMENT,
appointment_id VARCHAR(32) NOT NULL COMMENT '关联预约订单号',
patient_name INT NOT NULL COMMENT '患者名称',
doctor_id INT NOT NULL COMMENT '医生ID',
diagnosis TEXT COMMENT '诊断结果',
treatment_plan TEXT COMMENT '治疗方案',
prescription TEXT COMMENT '处方内容',
examination_items TEXT COMMENT '检查项目',
visit_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '就诊时间',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间'
) COMMENT '就诊记录表';
2. ER 图核心关系

五、系统效果与性能指标
1.后端登录页面设计

2.后端系统首页设计
3.用户管理页面

4.医院信息管理页面

5.科室信息管理页面

6.医生信息管理页面

7.医生排班信息管理页面

8.预约信息管理页面

9.AI助手挂号页面

六、未来优化方向
- 技术升级:引入微服务架构拆分核心模块,支持多医院接入;
- 功能拓展:集成医保支付、远程问诊、语音识别方便特殊群体功能、电子健康档案功能;
- 智能化深化:基于用户就诊历史推荐医生,通过 AI 算法预测疾病风险;
- 跨平台适配:开发小程序 / APP 版本,提升用户触达率。
尚未修改完善,持续修改完善中。
