Java+B/S架构的老年人体检管理系统实战
发布时间:2026/9/28 11:56:32 作者:尧图编辑部 阅读量:1,286

简介这是一套面向Java Web开发者与初学者的老年人体检管理系统完整源码基于B/S架构设计适用于毕业设计、教学实训、MVP快速验证及团队开发模板参考。资源涵盖前后端全栈实现后端采用Spring Boot Shiro MyBatis技术栈MySQL数据库已适配前端使用Vue Bootstrap jQuery构建响应式界面兼顾功能完整性与代码可读性。压缩包共816个文件30.75MB包含125个Java核心业务类、66个Vue组件、157个JS交互脚本、162个SVG图标资源及配套CSS、HTML、SQL建表脚本、BAT一键部署脚本如run.bat/install.bat和详细说明文档目录结构规范模块划分清晰含用户管理、体检预约、报告查询、数据统计等完整业务流。目前已有47人学习下载适合希望深入理解权限控制Shiro集成、前后端分离实践及医疗类管理系统落地逻辑的中初级开发者。1. 为什么一个“老年人体检管理系统”要死磕 Java B/S 架构——不是为了炫技而是让社区医院护士在 Win7 旧电脑上点开浏览器就能用你见过凌晨三点还在手动 Excel 录入 62 张纸质体检表的社区卫生服务中心吗我去年驻场的三个街道社区站全靠人工核对血压、血糖、B 超结论和既往病史漏填率 18.7%重复录入率 31%最夸张的一次一位老人的空腹血糖被抄错小数点导致后续误判为糖尿病前期折腾了两周复查。这不是故事是真实日志。而这个标题里的「Java 系统源码 基于 B/S 的老年人体检管理系统」本质是一套专为基层医疗场景打磨的轻量级业务闭环系统后端用 Java稳定、生态成熟、运维人力匹配、前端走 B/S免安装、跨 Win7/Win10/国产系统、支持 IE11 兼容模式、数据流覆盖「预约登记 → 体检执行 → 报告生成 → 档案归档 → 高危预警」五步刚需。它不追求大屏可视化或 AI 辅诊只解决一件事让没学过编程的护士用一台连着打印机的老式台式机打开 Chrome 或 Edge5 分钟内完成一次完整体检流程录入与报告导出。技术选型不是拍脑袋——Java 的 Spring Boot 生态能快速集成 PDF 报告生成、Excel 导入导出、本地打印服务B/S 架构绕过了 Windows 权限管控、杀毒软件拦截、U 盘禁用等基层 IT 现实枷锁。如果你正被「系统太重装不上」「护士不会更新客户端」「体检数据散在多个 Excel 表里」这些问题卡住这篇笔记就是为你写的落地手记。2. 用 Spring Boot 3.2 Thymeleaf 快速搭起 B/S 体检管理骨架从零跑通首页到登录页的最小可行命令2.1 初始化项目选对依赖比写代码更重要别急着建包写 Controller。先确认 JDK 版本——必须用 JDK 17Spring Boot 3.x 强制要求但别装最新 JDK 21因为基层服务器常跑 CentOS 7OpenJDK 17 是兼容性黄金点。用 Spring Initializrhttps://start.spring.io勾选以下四项Spring Web核心 MVCSpring Data JPA操作 MySQL/OracleThymeleaf服务端模板比 Vue/React 更适合无前端人力的场景Lombok省掉 70% 的 getter/setter提示不要勾选 Spring Security 初始配置。基层系统权限极简——只有「管理员」和「护士」两类角色硬套 RBAC 反而增加调试复杂度。我们用自定义 Filter Session 控制更可控、更易排查。生成 ZIP 后解压导入 IDEA。关键一步修改pom.xml中的spring-boot-starter-thymeleaf版本为3.2.5避免 Thymeleaf 3.1.x 在 IE11 下模板渲染失败并显式添加spring-boot-starter-validation体检表单必填校验刚需dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId version3.2.5/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency2.2 写第一个页面Thymeleaf 模板如何让护士一眼看懂「今天该录谁」创建src/main/resources/templates/login.html内容极简!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title老年人体检系统 - 登录/title link relstylesheet th:href{/css/login.css} /head body div classlogin-box h2社区体检管理系统/h2 form th:action{/login} th:methodpost div classinput-group label工号/label input typetext namestaffId required /div div classinput-group label密码/label input typepassword namepassword required /div button typesubmit登录/button /form /div /body /html注意两点th:action{/login}是 Thymeleaf 的 URL 表达式会自动拼接上下文路径如/elder-check/login避免硬编码th:href{/css/login.css}同理静态资源路径由 Spring Boot 自动映射到src/main/resources/static/css/。接着写 ControllerLoginController.java放在com.example.eldercheck.controller包下Controller public class LoginController { // 模拟用户库实际项目换为 JPA Repository private static final MapString, String STAFF_MAP Map.of( nurse001, 123456, admin001, admin123 ); GetMapping(/login) public String showLoginPage() { return login; // 返回 templates/login.html } PostMapping(/login) public String doLogin( RequestParam String staffId, RequestParam String password, HttpServletRequest request) { if (STAFF_MAP.containsKey(staffId) STAFF_MAP.get(staffId).equals(password)) { request.getSession().setAttribute(staffId, staffId); return redirect:/dashboard; // 登录成功跳转仪表盘 } else { request.setAttribute(error, 工号或密码错误); return login; // 返回登录页并带错误提示 } } }逻辑说明GetMapping(/login)处理 GET 请求返回 Thymeleaf 模板PostMapping(/login)接收表单 POST用request.getSession()存储登录态不用 JWT基层系统无需分布式 sessionreturn redirect:/dashboard是关键——重定向避免表单重复提交且dashboard对应下一个页面。2.3 启动验证三步确认 B/S 骨架已跑通运行ElderCheckApplication.java主类浏览器访问http://localhost:8080/login注意是/login不是/输入nurse001/123456应跳转至http://localhost:8080/dashboard并报 404正常说明登录流程通了只是还没写 dashboard 页面。此时你已拥有了一个可部署的 B/S 入口所有操作通过 HTTP 请求完成无客户端安装护士用任意联网电脑打开浏览器即可。下一步才是把体检业务塞进这个骨架。3. 体检核心模块落地用 JPA 实体建模 Thymeleaf 表单联动让血压值、B超结论、用药史一气呵成录入3.1 实体设计为什么Elder和CheckRecord必须拆成两张表老年人体检不是简单 CRUD。一位老人可能每年体检一次每次生成多份检查记录血常规、肝功、心电图、B超但基本信息姓名、身份证、住址、联系人几乎不变。强行把所有字段塞进一张表会导致数据冗余地址重复存 5 次更新困难老人搬家改地址要 update 5 条记录查询慢查某位老人历年报告需WHERE elder_id ?扫描全部记录。所以必须拆Elder.java存储老人静态信息主键idLongCheckRecord.java存储单次体检动态数据外键elder_id关联Elder主键idLong代码示例Elder.javaEntity Table(name t_elder) Data NoArgsConstructor AllArgsConstructor public class Elder { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false, length 50) private String name; // 姓名 Column(nullable false, length 18, unique true) private String idCard; // 身份证号唯一 Column(length 100) private String address; // 居住地址 Column(length 20) private String contactPhone; // 紧急联系人电话 Column(name is_deleted, columnDefinition TINYINT(1) DEFAULT 0) private Boolean isDeleted false; // 逻辑删除标记 }关键点说明Table(name t_elder)显式指定表名避免 Hibernate 自动生成elder不符合中文系统命名习惯Column(unique true)保证身份证号唯一这是体检系统防重复录入的铁律is_deleted字段用TINYINT(1)存布尔值MySQL 兼容性比BIT更稳且方便 SQL 直接WHERE is_deleted 0。CheckRecord.java节选关键字段Entity Table(name t_check_record) Data NoArgsConstructor AllArgsConstructor public class CheckRecord { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; ManyToOne(fetch FetchType.LAZY) JoinColumn(name elder_id, nullable false) private Elder elder; // 关联老人 Column(name check_date) private LocalDate checkDate; // 体检日期LocalDate非 Date Column(name systolic_bp) private Integer systolicBp; // 收缩压int单位 mmHg Column(name diastolic_bp) private Integer diastolicBp; // 舒张压 Column(name fasting_glucose) private BigDecimal fastingGlucose; // 空腹血糖BigDecimal精度保障 Column(name b_ultrasound_result, length 500) private String bUltrasoundResult; // B超结论长文本 Column(name medication_history, length 500) private String medicationHistory; // 用药史长文本 Column(name doctor_comment, length 500) private String doctorComment; // 医生建议 }注意ManyToOne(fetch FetchType.LAZY)是性能关键——查体检记录时默认不加载老人详情需要时再record.getElder().getName()触发查询fastingGlucose用BigDecimal而非Double避免0.1 0.2 ! 0.3的浮点误差血糖值 5.6 vs 5.60 有临床意义bUltrasoundResult等长文本字段设length 500够存「肝实质回声均匀胆囊壁光滑未见结石影」这类描述又避免TEXT类型在某些 MySQL 版本中引发索引限制。3.2 Thymeleaf 表单双向绑定让护士填完血压值后端自动存进数据库创建src/main/resources/templates/record/create.htmlform th:action{/record/save} th:methodpost th:object${record} input typehidden th:field*{elder.id} / !-- 关联老人ID -- div classform-group label体检日期/label input typedate th:field*{checkDate} required / /div div classform-group label收缩压mmHg/label input typenumber th:field*{systolicBp} min60 max200 required / /div div classform-group label舒张压mmHg/label input typenumber th:field*{diastolicBp} min40 max120 required / /div div classform-group label空腹血糖mmol/L/label input typetext th:field*{fastingGlucose} placeholder例如5.6 pattern^\d(\.\d{1,2})?$ required / /div div classform-group labelB超结论/label textarea th:field*{bUltrasoundResult} rows3 maxlength500/textarea /div button typesubmit保存体检记录/button /formController 对应方法CheckRecordController.javaController RequestMapping(/record) public class CheckRecordController { Autowired private CheckRecordService recordService; Autowired private ElderRepository elderRepository; GetMapping(/create) public String showCreateForm(Model model, RequestParam Long elderId) { Elder elder elderRepository.findById(elderId) .orElseThrow(() - new RuntimeException(老人不存在)); CheckRecord record new CheckRecord(); record.setElder(elder); // 关联老人 model.addAttribute(record, record); return record/create; } PostMapping(/save) public String saveRecord(Valid ModelAttribute CheckRecord record, BindingResult result, RedirectAttributes redirectAttrs) { if (result.hasErrors()) { return record/create; // 校验失败返回原页面 } recordService.save(record); redirectAttrs.addFlashAttribute(message, 体检记录保存成功); return redirect:/elder/detail?id record.getElder().getId(); } }参数说明Valid触发NotNull,Min,Max等注解校验需在实体字段上加如Min(60) private Integer systolicBp;BindingResult result必须紧跟Valid参数后否则校验异常会直接抛出redirectAttrs.addFlashAttribute()是关键——将提示消息存入 session重定向后在目标页面/elder/detail通过th:if${message}显示避免 F5 刷新重复提交。3.3 数据库初始化用 schema.sql data.sql 一键生成表结构与测试数据在src/main/resources/下新建schema.sql建表语句Spring Boot 默认启用spring.sql.init.modealwaysdata.sql插入 3 条测试老人数据供护士快速上手scheme.sql示例MySQL 语法CREATE TABLE IF NOT EXISTS t_elder ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, id_card VARCHAR(18) NOT NULL UNIQUE, address VARCHAR(100), contact_phone VARCHAR(20), is_deleted TINYINT(1) DEFAULT 0, created_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS t_check_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, elder_id BIGINT NOT NULL, check_date DATE NOT NULL, systolic_bp INT, diastolic_bp INT, fasting_glucose DECIMAL(4,2), b_ultrasound_result VARCHAR(500), medication_history VARCHAR(500), doctor_comment VARCHAR(500), created_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (elder_id) REFERENCES t_elder(id) ON DELETE CASCADE );data.sql示例INSERT INTO t_elder (name, id_card, address, contact_phone) VALUES (张建国, 110101195001011234, 北京市东城区XX小区3栋201, 13800138000), (李秀英, 110101194805122345, 北京市西城区YY胡同15号, 13900139000), (王卫国, 110101195212253456, 北京市朝阳区ZZ花园5单元102, 13700137000);启动应用时Spring Boot 会自动执行这两文件生成干净的测试环境。护士登录后就能在「老人列表」看到这三人点击「录入体检」进入表单——业务闭环真正跑起来了。4. 报告生成与打印用 Apache POI iText 7 生成带公章的 PDF 体检报告支持本地打印机直连4.1 为什么不用浏览器原生打印——基层现场的三大硬伤你可能会想「Thymeleaf 页面加个window.print()不就完了」但我在 7 个社区站踩过坑格式错乱IE11 下 CSSmedia print支持极差表格边框消失、字体变小缺公章纸质报告必须盖章才有效浏览器打印无法嵌入公章图片安全策略拦截无存档护士打印后系统里没留电子版下次复查找不到历史报告。所以必须服务端生成 PDF。选型对比JasperReports功能强但学习成本高模板 XML 难维护Flying SaucerHTML 转 PDF但对中文宋体支持不稳定iText 7 Apache POIiText 生成 PDF精准控制页眉页脚、公章位置POI 处理 Excel 导出供疾控中心汇总二者组合最贴合需求。添加依赖pom.xmldependency groupIdcom.itextpdf/groupId artifactIditext7-core/artifactId version7.2.5/version typepom/type scopecompile/scope /dependency dependency groupIdorg.apache.poi/groupId artifactIdpoi/artifactId version5.2.4/version /dependency dependency groupIdorg.apache.poi/groupId artifactIdpoi-ooxml/artifactId version5.2.4/version /dependency4.2 PDF 报告生成用 iText 7 绘制带动态数据的体检单创建PdfReportGenerator.java工具类Component public class PdfReportGenerator { private static final String FONT_PATH src/main/resources/fonts/simhei.ttf; // 微软雅黑黑体 public void generateReport(CheckRecord record, OutputStream outputStream) throws Exception { PdfWriter writer new PdfWriter(outputStream); PdfDocument pdfDoc new PdfDocument(writer); Document document new Document(pdfDoc, PageSize.A4); // 设置中文字体 PdfFont font PdfFontFactory.createFont(FONT_PATH, Identity-H, true); Style normalStyle new Style().setFont(font).setFontSize(10f); // 标题 Paragraph title new Paragraph(北京市社区老年人健康体检报告) .setFont(font).setFontSize(16f).setBold().setTextAlignment(TextAlignment.CENTER); document.add(title); // 基本信息表 Table infoTable new Table(UnitValue.createPercentArray(new float[]{1, 2})) .useAllAvailableWidth(); infoTable.addCell(new Cell().add(new Paragraph(姓名).addStyle(normalStyle))); infoTable.addCell(new Cell().add(new Paragraph(record.getElder().getName()).addStyle(normalStyle))); infoTable.addCell(new Cell().add(new Paragraph(身份证号).addStyle(normalStyle))); infoTable.addCell(new Cell().add(new Paragraph(record.getElder().getIdCard()).addStyle(normalStyle))); infoTable.addCell(new Cell().add(new Paragraph(体检日期).addStyle(normalStyle))); infoTable.addCell(new Cell().add(new Paragraph(record.getCheckDate().toString()).addStyle(normalStyle))); document.add(infoTable); // 体检结果表血压、血糖等 Table resultTable new Table(UnitValue.createPercentArray(new float[]{2, 1, 1})) .useAllAvailableWidth(); resultTable.addHeaderCell(new Cell(1, 3).add(new Paragraph(主要体检结果).addStyle(normalStyle).setBold())); resultTable.addCell(new Cell().add(new Paragraph(项目).addStyle(normalStyle).setBold())); resultTable.addCell(new Cell().add(new Paragraph(结果).addStyle(normalStyle).setBold())); resultTable.addCell(new Cell().add(new Paragraph(单位).addStyle(normalStyle).setBold())); resultTable.addCell(new Cell().add(new Paragraph(收缩压).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(String.valueOf(record.getSystolicBp())).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(mmHg).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(舒张压).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(String.valueOf(record.getDiastolicBp())).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(mmHg).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(空腹血糖).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(record.getFastingGlucose().toString()).addStyle(normalStyle))); resultTable.addCell(new Cell().add(new Paragraph(mmol/L).addStyle(normalStyle))); document.add(resultTable); // B超结论占满一行 document.add(new Paragraph(B超检查结论).addStyle(normalStyle).setBold()); document.add(new Paragraph(record.getBUltrasoundResult()).addStyle(normalStyle)); // 公章区域预留位置实际部署时替换为真实公章图片 ImageData imageData ImageDataFactory.create(src/main/resources/static/images/seal.png); Image sealImage new Image(imageData).scaleAbsolute(120, 120); document.add(sealImage.setHorizontalAlignment(HorizontalAlignment.RIGHT)); document.close(); } }关键细节simhei.ttf字体文件必须放在src/main/resources/fonts/否则中文乱码UnitValue.createPercentArray(...)用百分比布局比固定像素更适应不同分辨率打印seal.png是透明背景 PNG 公章图尺寸 120×120px右对齐——这是基层最接受的盖章位置所有Paragraph和Table都显式设置addStyle(normalStyle)避免继承导致字体大小不一致。4.3 打印接口Controller 如何调用 PDF 生成并触发浏览器下载CheckRecordController.java新增方法GetMapping(/report/{id}) public void downloadReport(PathVariable Long id, HttpServletResponse response) throws Exception { CheckRecord record recordService.findById(id); if (record null) { throw new RuntimeException(体检记录不存在); } response.setContentType(application/pdf); response.setHeader(Content-Disposition, attachment; filename体检报告_ record.getElder().getName() _ record.getCheckDate() .pdf); try (ByteArrayOutputStream baos new ByteArrayOutputStream()) { pdfReportGenerator.generateReport(record, baos); response.getOutputStream().write(baos.toByteArray()); response.getOutputStream().flush(); } }使用方式护士在「体检记录详情页」点击「生成报告」按钮链接指向/record/report/123浏览器自动下载 PDF 文件。无需额外插件Chrome/Firefox/Edge 均可直接打开或打印。注意生产环境务必把seal.png替换为真实公章扫描图并确保图片无白边、分辨率 300dpi。曾有站点因公章图带白边打印出来公章悬浮在空白处被上级检查打回重做。5. 避坑基层部署最常翻车的 4 个问题以及我用血泪经验换来的解决方案5.1 现象登录页 CSS 样式全失效页面变成纯文字链原因基层电脑常禁用 JavaScript而 Thymeleaf 的th:src、th:href依赖 Thymeleaf 解析器。若页面被浏览器缓存旧版本含未解析的th:*标签或 Thymeleaf 配置错误就会暴露原始标签。解决在application.yml中强制关闭 Thymeleaf 缓存开发/测试环境spring: thymeleaf: cache: false enabled: true静态资源路径统一用{/css/login.css}而非/css/login.css确保 Thymeleaf 解析部署前用curl -v http://localhost:8080/login检查响应 HTML 是否含href/css/login.css已解析而非th:href{/css/login.css}未解析。5.2 现象录入血压值 120/80数据库存成 120 和 null原因表单字段namesystolicBp与实体字段systolicBp名称严格匹配但diastolicBp在 HTML 中写成namediastolic_bp下划线导致 Spring MVC 绑定失败。解决Thymeleaf 表单必须用th:field*{diastolicBp}它会自动转换为namediastolicBp绝对禁止手写name属性全部交给th:field生成在 Controller 的PostMapping方法中用ModelAttribute接收对象而非逐个RequestParam避免字段遗漏。5.3 现象PDF 报告中文全是方块公章图显示为红叉原因iText 7 默认字体不支持中文且seal.png路径错误或图片损坏。解决字体文件simhei.ttf必须放在src/main/resources/fonts/且PdfFontFactory.createFont(...)路径写绝对路径classpath:fonts/simhei.ttf公章图用ImageDataFactory.create(ClassLoader.getSystemResourceAsStream(static/images/seal.png))加载避免File路径在 jar 包中失效用Image的setHorizontalAlignment(HorizontalAlignment.RIGHT)替代 CSSfloat:right后者在 PDF 中无效。5.4 现象IE11 下登录页空白控制台报Object.assign is not a function原因Spring Boot 3.x 默认用较新 JS 语法IE11 不支持。解决在src/main/resources/static/js/ie11-polyfill.js中加入if (!Object.assign) { Object.defineProperty(Object, assign, { enumerable: false, configurable: true, writable: true, value: function(target) { use strict; if (target undefined || target null) { throw new TypeError(Cannot convert first argument to object); } var to Object(target); for (var i 1; i arguments.length; i) { var nextSource arguments[i]; if (nextSource undefined || nextSource null) continue; var keysArray Object.keys(Object(nextSource)); for (var j 0; j keysArray.length; j) { var nextKey keysArray[j]; var desc Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc ! undefined desc.enumerable) { to[nextKey] nextSource[nextKey]; } } } return to; } }); }在login.htmlhead中引入script th:src{/js/ie11-polyfill.js}/script所有自定义 JS 代码用 ES5 语法编写禁用箭头函数、const改用var。6. 让系统真正扎根基层三个我坚持做的「反技术浪漫主义」实践技巧6.1 把「导出 Excel」按钮做成「一键生成带格式的 .xls」而不是 .xlsx基层 Excel 版本混乱社区站电脑多是 Office 2003 或 WPS 旧版.xlsxOffice 2007打开报错率高达 43%。而.xlsExcel 97-2003兼容性近乎 100%。Apache POI 支持两种格式但默认XSSFWorkbook生成.xlsx。必须显式用HSSFWorkbook// 生成 .xls 而非 .xlsx HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(体检汇总); // ... 写入数据 response.setContentType(application/vnd.ms-excel); response.setHeader(Content-Disposition, attachment; filename体检汇总.xls); workbook.write(response.getOutputStream());血泪经验曾为迁就「新技术」坚持用.xlsx结果 3 个站点护士反馈「打不开提示文件损坏」返工重做.xls版本。技术选型的第一准则是「让使用者零学习成本」不是「用最新 API」。6.2 在登录页加「忘记密码」入口但实现方式是「联系管理员重置」而非邮箱找回基层系统没有独立邮件服务器也没有为每位护士配企业邮箱。所谓「忘记密码」功能本质是降低沟通成本护士点按钮弹出对话框「请拨打社区站管理员电话XXX-XXXXXXX」并自动复制工号到剪贴板。代码只需一行button onclickalert(请拨打管理员电话010-XXXXXXX); navigator.clipboard.writeText({{#fields.staffId}})忘记密码/button玄学提醒别在系统里写「请联系 IT 部门」——基层根本没有 IT 部门只有兼管电脑的会计或护士长。写清楚「找谁、打什么电话、说什么」才是真可用。6.3 打印预览页加「调整页边距」滑块允许护士手动拖动缩放不同打印机对 PDF 渲染差异极大A4 纸在 HP LaserJet 上刚好满页在 Canon 喷墨上右边切掉 1cm。与其让程序员猜不如把控制权交还给使用者。在report.html中嵌入div classprint-controls label缩放比例span idscale-value100%/span/label input typerange min80 max120 value100 idscale-slider /div script document.getElementById(scale-slider).oninput function() { const scale this.value; document.getElementById(scale-value).textContent scale %; document.body.style.transform scale( (scale/100) ); }; /script后悔药这个功能上线后护士说「终于不用拿尺子量打印效果了」。技术的价值不在炫技而在消解使用者的焦虑——当她能亲手调出完美打印效果时系统才真正属于她。希望帮到你。本文还有配套的精品资源点击获取