简介:基于Bootstrap和jQuery的医院大数据展示前端源码,面向网页开发者与医院数据可视化项目人员,用于快速搭建医院运营数据的交互看板,直观呈现病人数量、科室就诊量、医疗费用等核心指标,并能适配个人电脑、平板与手机等多种屏幕。资源压缩包共包含79个文件,容量仅1.4兆,其中网页文件5个、脚本文件12个、样式文件5个、图片40张,另附字体和图标资源,页面覆盖总览、慢性病、指标、趋势等常用模块,下载解压后可直接打开网页预览效果。目前已有149人学习下载,源码重点示范了Bootstrap响应式栅格布局、jQuery事件处理与异步数据加载的结合方法,也涉及图表联动、动态筛选、模态框等大数据展示常见交互。通过研读该项目,可以快速掌握前端大屏看板的搭建思路,适用于毕业设计、课程实践或医疗行业数据可视化项目的参考与二次开发。
1. 医院大屏项目里,最值钱的往往不是图表
医院数据大屏这类项目,最容易翻车的不是图表库不会用,而是页面一旦接入真实数据就散架:标题栏错位、表格撑破布局、接口返回结构一变整屏报错。这套 Bootstrap + jQuery 源码没有上重型可视化框架,却把大屏最容易被低估的模块——标题栏、信息卡片、统计表格、分页查询——做成了可以直接复用的结构,它解决的正是从设计稿到可维护前端之间的空白地带。适合三类人:做院内报表系统的前端、需要给运营大屏快速换肤的工程师、以及想用 bootstrap-table 搭数据管理后台的学生。里面的页面组织方式和分页参数设计,比单纯看文档更有参考价值。
2. 骨架怎么搭:Bootstrap 栅格、common.css 与五页共用的布局模板
打开压缩包先别急着看 JS,把 styles、views、images 三个目录的结构捋一遍,能省下大量排错时间。整个前端只依赖四个 CSS 文件:bootstrap.min.css提供栅格和基础组件,bootstrap-table.css负责表格样式,pagination.css定制分页条,common.css承载大屏专用布局。这种分层方式和后端代码里“框架层、业务层、工具层”的分层逻辑一致,换皮肤时只动 common.css,升级组件时只替换框架文件,互不干扰。
2.1 CSS 分工:基础框架、业务样式与表格组件
这套源码的样式管理思路很朴素但也最实用:框架文件原封不动,业务样式全部收敛到common.css,表格和分页单独拆文件。这样做的直接好处是,当你需要把 demo 改成医院实际品牌色时,不需要在 bootstrap.min.css 里做任何搜索替换,那里面被压缩过的类名会把你逼疯的。
| CSS 文件 | 承担职责 | 改动频率 |
|---|---|---|
| bootstrap.min.css | 栅格系统、按钮、下拉菜单、模态框等基础组件 | 基本不动 |
| bootstrap-table.css | 表格排序箭头、行 hover、选中态样式 | 偶尔调 |
| pagination.css | 分页按钮尺寸、间距、深色背景适配 | 换肤时必改 |
| common.css | 大屏背景、标题栏、信息卡片、导航、图表底板 | 换肤时必改 |
以pagination.css为例,大屏项目里分页条通常会做得比普通后台大一圈,按钮高度从默认的 30px 提到 38px 左右,字号放大到 14px,同时把active页码的背景色改成与主视觉一致的高亮色。这一类改动如果写进 bootstrap-table.css 里,下次升级表格组件时会被直接覆盖,单独拆出来就不会。
2.2 从 index.html 看大屏的布局骨架
五个页面里,index.html是总览大屏,结构上最完整;quota.html、chronic.html、trend.html、NCDindex.html则是分主题页面。它们的共同点很明确:顶部是title_xx.png拼出来的标题栏,下方用 Bootstrap 栅格排布信息卡片和表格区,最底层铺一张chartBack.jpg作为图表区域的底板。
<div class="container-fluid dashboard-body"> <!-- 顶部标题栏:左侧 logo.png + 中间 title_13.png + 右侧时间/导航 --> <div class="row header-row"> <div class="col-xs-4"> <img src="images/logo.png" alt="医院标识" class="logo"> </div> <div class="col-xs-8 text-center"> <img src="images/title_13.png" alt="运营监测平台" class="page-title"> </div> </div> <!-- 信息卡片区:col-md-3 在桌面四分一排布 --> <div class="row card-row"> <div class="col-xs-6 col-md-3"> <div class="stat-card"> <img src="images/info_3.png" alt="门诊量"> <span class="stat-value" id="outpatientTotal">--</span> </div> </div> <div class="col-xs-6 col-md-3"> <div class="stat-card"> <img src="images/info_5.png" alt="住院量"> <span class="stat-value" id="inpatientTotal">--</span> </div> </div> </div> <!-- 图表与表格区 --> <div class="row"> <div class="col-md-8"> <div class="chart-panel" style="background: url('images/chartBack.jpg') no-repeat center;"> <table id="mainTable"></table> </div> </div> <div class="col-md-4"> <div class="side-panel" id="sidePanel"></div> </div> </div> </div>这里的类名和图片编号是根据资源目录还原的常规写法,重点看两个设计决策。第一,信息卡片区用col-md-3,意味着在 1200px 以上的桌面端一行排四张,到了平板宽度自动变成两列,正是大屏项目在 1920x1080 和 1366x768 两种分辨率之间切换时最需要的弹性。第二,图表区没有硬编码高度,而是通过chartBack.jpg的宽高比撑起来,这样一旦某个科室的表格数据量超出预期,页面不会因为固定高度直接溢出滚动条。
2.3 图片资源的组织方式与换肤思路
图片目录里大量title_xx.png和info_xx.png是这套源码的视觉核心。title_开头的是各级标题栏背景,info_开头的是信息卡片图标,nav_开头的是底部导航图标,find.png是查询按钮的放大镜图标。它们的编号没有业务含义,纯粹是 UI 切图时的序列号。
换肤时最容易犯的错是直接改图片内容而不改命名规则。比如把title_13.png替换成新标题图,但新图尺寸比例和原来不一致,结果标题栏背景被拉伸变形。我一般会先量出原图宽高,再做同尺寸替换;如果医院要求换主色调,更快的方案是先看 common.css 里有没有引用这些图片的background-position,有的话优先改 CSS 里的颜色值,而不是重新切图。
提示:大屏项目中的切图资源,命名与物理路径一旦上线就不要随意变更。前端缓存、运维监控、后端模板都可能引用完整路径,改名等于制造一次隐蔽的线上故障。
3. 数据从哪来:jQuery Ajax 异步加载与五个脚本的分工
styles 目录解决了“长什么样”,scripts 目录则解决“数据怎么进来”。这套源码没有用 Vue 或 React,而是纯粹依赖 jQuery 的$.ajax手动操作 DOM 和刷新表格。这种方式的优点是不需要构建工具,改完 JS 刷新页面就能看到效果,对院内网环境尤其友好;缺点是数据流不集中,所以必须把脚本职责拆清楚,否则后期维护时找一个字段要翻五个文件。
3.1 scripts 目录的职责划分
| 脚本文件 | 对应页面 | 核心职责 |
|---|---|---|
| index.js | index.html | 总览大屏:统计卡片、全院核心指标、今日概览 |
| quota.js | quota.html | 科室指标配额、完成率、月度目标进度 |
| chronic.js | chronic.html | 慢性病就诊人数、随访率、病种分布 |
| trend.js | trend.html | 同比环比趋势、周期对比 |
| NCDindex.js | NCDindex.html | 非传染性疾病指数、风险分层统计 |
| common.js | 全部页面 | 公共方法:日期格式化、数值千分位、请求封装 |
拆分的逻辑是按业务域切分,而不是按功能切分。common.js里的方法不依赖任何具体页面,比如数值格式化、请求失败提示、时间范围默认值;页面脚本只负责调用公共方法并绑定本页的 DOM 事件。这样的好处是,当你接到需求要新加一个“手术质量指标”页面,只需要复制quota.html的骨架,新建一个surgery.js,把表格列配置和数据接口地址换掉就行,公共方法一行都不用动。
3.2 一次完整的 Ajax 数据加载链路
以index.js为例,页面初始化时首先要发起一个总览数据的请求,拿到结果后分别填充顶部的统计卡片和下方的表格。
// index.js 页面初始化入口 $(function () { initOverview(); }); function initOverview() { $.ajax({ url: './mock/overview.json', // 开发阶段指向本地 Mock,上线时替换为真实接口 method: 'GET', dataType: 'json', timeout: 10000, // 10 秒超时,避免接口卡死导致大屏空白 success: function (res) { if (res.code !== 0) { showError(res.msg || '数据加载失败'); return; } renderStatCards(res.data.cards); // 填充顶部统计卡片 renderMainTable(res.data.tableData); // 填充主表格 }, error: function (xhr, status) { showError('请求失败,请检查网络或接口地址'); } }); }参数层面的几个细节值得说明。timeout: 10000是医院内网环境常见的超时配置,因为大屏项目挂在门诊大厅时网络质量不稳定,如果接口 30 秒不返回,页面会一直停留在加载状态,不如主动失败并展示提示。res.code !== 0是前后端约定的统一状态码,这里假设 0 为成功,实际项目里可能是"0000"或者200,关键是common.js里要封装一个isSuccess方法统一判断,避免每个页面重复写条件。renderStatCards和renderMainTable是两个纯函数,一个负责把数据写进卡片 DOM,一个负责把数据交给表格组件,职责单一,出了问题只看对应函数就行。
3.3 common.js 公共方法:字段映射、格式化和异常兜底
真实接口返回的字段名通常和前端展示名不一致,比如后端叫pat_count,页面上要显示成“就诊人次”。如果把这种映射关系散落在每个页面脚本里,后端改一个字段名就要全局搜索替换。常见的做法是在common.js里提供统一的字段格式化函数:
// common.js 中的通用格式化方法 var Common = { // 数值千分位 1234567 -> 1,234,567 formatNumber: function (val) { var num = Number(val); if (isNaN(num)) return '--'; return num.toLocaleString('zh-CN'); }, // 百分比字段:后端可能返回 0.156 或 "15.6" formatPercent: function (val, digits) { var num = Number(val); digits = digits || 1; if (isNaN(num)) return '--'; if (num >= 0 && num < 1) { return (num * 100).toFixed(digits) + '%'; } return num.toFixed(digits) + '%'; }, // 对传入的字段做安全兜底 safeGet: function (obj, key, defaultVal) { return obj && obj[key] !== undefined && obj[key] !== null ? obj[key] : (defaultVal || '--'); } };formatPercent处理的是一个很典型的坑:同一个占比字段,不同后端接口有的返回小数0.156,有的返回字符串"15.6",直接用toFixed会得到错误结果。这里先判断数值范围,小于 1 且大于 0 的按小数转百分比,其余按已有百分比处理。safeGet用于兜底字段缺失的情况,医院老系统的接口经常出现某个字段在某条记录里不存在的现象,不兜底的话表格那一列会直接显示undefined,影响大屏观感。
4. 表格分页、筛选与查询:bootstrap-table 的远程数据模式
表格分页是这套源码里最有参考价值的部分。bootstrap-table本身支持两种分页模式:client和server。client 模式把全量数据一次性拉到浏览器,由插件在前端分页;server 模式每次只向接口请求当前页数据。这套源码选择的是 server 模式,也就是远程分页,院内报表系统里几千到几万行的数据量,用 client 模式会直接拖垮渲染,server 模式才是正确姿势。
4.1 为什么源码选择 server 模式分页
看资源目录里同时出现了bootstrap-table.css和pagination.css,就知道表格和分页是深度耦合的。医院的大屏数据量虽然比不上互联网日志那种量级,但门诊记录按月查很容易到几十万行,一次性拉全量数据无论对后端数据库还是浏览器 DOM 都是灾难。server 模式下,后端每次只返回当前页数据,前端表格只渲染 10 到 50 行,性能瓶颈被彻底转移到后端 SQL 上,而分页 SQL 恰恰是所有后端开发都熟悉的能力。
另一个原因是筛选联动。大屏上通常会放科室下拉框、日期范围选择器、指标类型切换,这些条件必须拼进查询参数重新请求后端。server 模式天然支持把筛选条件随着翻页请求一起提交,而 client 模式虽然也能在前端过滤,但实现数据源切换时逻辑会绕很多。
4.2 远程分页的参数约定与返回格式
quota.js里初始化表格的代码逻辑大致如下,分页参数通过queryParams函数传给后端:
// quota.js 中 bootstrap-table 初始化配置 $('#quotaTable').bootstrapTable({ url: './mock/quota-page.json', method: 'get', pagination: true, sidePagination: 'server', // 关键:使用远程分页 pageNumber: 1, // 初始页码 pageSize: 10, // 每页条数 pageList: [10, 20, 50], // 每页条数切换选项 queryParams: function (params) { // 把前端筛选条件合并进分页参数 return { page: params.pageNumber, rows: params.pageSize, dept: $('#deptSelect').val(), // 科室下拉框 dateRange: $('#dateRange').val(), // 日期范围 order: params.sort, orderBy: params.order }; }, columns: [ { field: 'dept', title: '科室', sortable: true }, { field: 'quota', title: '指标值', sortable: true }, { field: 'completeRate', title: '完成率' } ] });参数映射关系最好单独列出来,方便对照后端接口文档:
| 前端参数 | 含义 | 后端常见对应 |
|---|---|---|
| page | 当前页码 | pageNum、pageIndex |
| rows | 每页条数 | pageSize、limit |
| dept | 科室筛选值 | deptCode、deptId |
| dateRange | 时间范围 | startDate、endDate |
| sort | 排序列字段名 | sortField |
| order | 排序方向 | asc / desc |
这段配置里最容易被忽视的是queryParams的返回值没有沿用插件默认的limit和offset,而是改成了page和rows。原因很简单:很多 Java 后台的 PageHelper 插件、Python 的 DRF 分页,默认接收的参数就是pageNum/pageSize或者page/rows,前端按后端要求传参可以省掉一层参数转换。sortable: true开启列排序后,点击表头会触发重新请求,排序字段通过params.sort自动带出,不需要额外绑定事件。
4.3 从 queryParams 到 refresh 的筛选联动
筛选功能是另一个关键点。下拉框切换科室后,需要把表格重置到第一页并重新请求,否则用户会停留在第 5 页看到一堆不属于当前科室的数据。常见做法是监听筛选控件的change事件,调用表格的refresh方法:
// 科室下拉框变化时刷新表格 $('#deptSelect').on('change', function () { // 重置到第一页,并携带新的筛选条件 $('#quotaTable').bootstrapTable('refresh', { pageNumber: 1, silent: false // false 表示显示加载动画 }); }); // 查询按钮 click 事件,多条件同时生效 $('#searchBtn').on('click', function () { $('#quotaTable').bootstrapTable('refresh'); });注意这里queryParams里用了$('#deptSelect').val(),意味着每次 refresh 时都会重新读取当前下拉框的值,所以不需要手动把筛选条件塞进 refresh 参数里。pageNumber: 1是必须的,不重置的话,用户在满足条件的数据只有 3 页的情况下停留在第 5 页,接口会返回空数据,表格显示空白,很容易被误判成 bug。
5. 把源码跑起来:HTTP 服务、Mock 替换与验收检查
拿到这套源码后最容易遇到的第一个坑就是双击index.html打开,结果页面空白、控制台报错。原因是浏览器对file://协议下的 Ajax 请求有严格限制,$.ajax读取本地 JSON 会被 CORS 策略拦截,同时页面里引用的相对路径资源也可能因为协议不同加载失败。所以第一步不是改代码,而是先把服务跑起来。
5.1 用本地 HTTP 服务启动
项目根目录下执行任意一个静态服务器命令即可:
# Python 3 自带,无需额外安装 cd bootstrap-jquery-hospital-dashboard python3 -m http.server 8080 # 或者使用 Node 生态 npx serve -l 8080启动后浏览器访问http://localhost:8080/index.html。验证服务是否正常,直接在 shell 里请求接口:
curl -s http://localhost:8080/mock/quota-page.json | head -20能返回 JSON 数据说明静态服务器正常,接下来重点检查浏览器控制台有没有 404 和 500 报错。404 通常是因为资源路径写死,比如代码里写/images/logo.png而根目录实际是./images/logo.png;500 则大概率是接口地址不存在,需要到对应 JS 文件的url字段里替换成真实接口。
5.2 把 Mock 数据换成真实医院接口
替换时先找出所有 JS 里的url: './mock/xxx.json',逐个替换成后端真实地址。这里有个需要注意的细节:不要把接口地址写死在各页面脚本里,而是统一放进一个config.js或挂在window.AppConfig上,后续环境切换只改一个文件。
// config.js 环境配置示例 window.AppConfig = { baseUrl: window.location.origin + '/api', timeout: 10000 };真实医院接口的字段名几乎不可能和 Mock 完全一致,需要用common.js里的格式化函数做适配。另外,如果接口做了鉴权,需要在$.ajaxSetup里统一加请求头:
$.ajaxSetup({ headers: { 'Authorization': 'Bearer ' + (window.localStorage.getItem('token') || '') } });医院数据属于敏感数据,接口必须做权限校验和脱敏处理,姓名、身份证号、详细住址绝不能出现在大屏上,这是上线前的硬性检查项。
5.3 大屏与业务终端的分辨率适配
这套源码的 Bootstrap 栅格在 1920x1080 大屏上通常没有问题,但在 1366x768 的办公终端上看,底部表格可能会被挤出一部分。检查方法是打开浏览器开发者工具的设备模拟,分别切到 1920x1080、1366x768、1280x720 三个分辨率,重点看标题栏是否换行、表格列是否被压缩、分页条有没有溢出。遇到表格列数较多时,可以在 bootstrap-table 的列定义里加visible: false隐藏次要列,或者用formatter把多列合并展示,而不是硬抗宽度。
本文还有配套的精品资源,点击获取