☰
基于微信小程序的社区医院药品库存管理与自动提醒系统设计
2026/10/2 22:29:51 网站建设 项目流程

基于微信小程序的社区医院药品库存管理和自动提醒系统的设计与实现

社区医院药房是个很容易被低估的地方。我去过不少社区医院调研,发现很多药房的管理方式还停留在"手工台账+Excel"的阶段:入库靠手写,出库靠划勾,盘点靠人海战术。药品过期了没人知道,库存积压了也没人察觉,等到月底对账才发现一批药已经报废。这个问题不是小诊所的专利,一些规模不小的社区医院同样如此。

所以当我接到一个"社区医院药品库存管理"的项目需求时,第一反应就是:必须做一套能自动提醒的系统,而且终端最好用微信小程序。理由很简单——药房工作人员和社区医生手机上都有微信,不需要额外装App,管理员发一条订阅消息就能触达所有人,开发成本还远低于原生应用。这篇文章把整个项目的设计与实现过程完整拆开讲,包括为什么这么设计、核心数据表怎么建、小程序端哪些细节容易被坑、自动提醒的完整链路怎么打通,以及部署上线时需要注意的事情。无论是拿去做毕业设计,还是真给社区医院做信息化改造,都能派上用场。

1. 社区药房药品管理的真实痛点与微信小程序切入点

1.1 药库现场到底在乱什么

先说我调研到的实际情况。一家服务两三万居民的社区医院,药房常备药品大概在500到800种之间,加上不同规格、不同批次,库存记录条数能到几千条。库存周期从几天到几个月不等,这里面最要命的就是近效期药品——一批药生产日期早、有效期短,如果没人盯着,很容易就放过期了。

我在一家社区医院看到他们的做法:每月月底,药剂师把药品按有效期排序,把三个月内到期的品种抄下来,再逐一核对库存数量,决定是退回供应商还是继续使用。这个流程听起来不复杂,但非常耗时,而且容易漏。特别是那些周转慢的应急药品,例如某些解毒剂、抗过敏药,平时几乎不动,等要用的时候才发现过期了,这就不是经济损失的问题,而是用药安全问题。

另一个痛点是信息不透明。医生开处方时不知道某药库存还有没有,药剂师不知道哪些药快用完了该进货,院长想知道各科室药品消耗情况,但数据都在一堆纸质单据里。任何一方想了解信息,都要跑一趟药房去翻账本。这种模式下,药品的效期管理、库存上下限预警、消耗统计全部依赖人工,出错是常态,不出错才是运气。

1.2 为什么是微信小程序而不是App或Web端

最初考虑过两个方向:做一套PC端Web管理系统,或者做原生App。后来都推翻了。

Web端确实适合管理员做库存录入、统计报表,但社区医院的药房工作人员每天在药架间来回走动,不可能一直坐在电脑前操作。药品入库时手机扫一下码、出库时点两下屏幕,这种移动化的操作需求Web端满足不了。原生App功能上没问题,但社区医院没有专门的信息化运维人员,让工作人员装App、注册账号、升级版本,每一样都是麻烦。还有一个最现实的问题:App得单独做iOS和Android两套,开发周期和成本直接翻倍。

微信小程序把这个矛盾完美化解了。用户通过扫码或搜索就能打开,用完即走,不需要安装;微信自带的订阅消息能力可以直接用来做药品过期提醒和库存预警,省掉了自己搭推送通道的成本;而且小程序天生支持摄像头扫码,药品条码扫描这类功能实现起来很顺手。对社区医院来说,微信已经是员工日常使用的工具,学习成本几乎为零。

顺便说一句,如果你是在做毕业设计,选微信小程序还有个隐藏的好处:前后端分离的开发模式和真实企业项目高度一致,答辩的时候能讲清楚"为什么这么选"比"做了什么功能"更能拿分。我从项目一开始就确定了技术栈:小程序端用原生框架(也可以用uni-app,后面细说),后端用Spring Boot,数据库选MySQL,部署在一台低配服务器上。这个组合足够稳定,社区医院的并发量根本不是什么压力。

2. 系统角色、模块与业务流程的整体设计

2.1 三个角色,职责边界要划清楚

整个系统围绕三个角色设计:系统管理员、药房操作员、普通员工(医生/护士)。一开始我也纠结过要不要加一个"供应商"角色,让供应商也能登录查看库存情况,后来项目评审时被否决了——社区医院根本不想让供应商直接看到进销存数据,他们更希望由药剂师手工把进货需求发给供应商。所以不要把流程设计理想化,以实际业务为准。

三个角色的权限边界如下:

角色核心权限说明
系统管理员用户管理、药品档案维护、预警阈值配置、全量数据查看通常是院长或药房主任
药房操作员入库、出库、盘点、近效期预警处理在药库现场操作的药剂师
普通员工库存查询、药品信息查看医生开处方前查库存用

这里有一个很容易被忽略的设计细节:普通员工只能查库存,不能看采购价和供应商信息。从商业和数据安全角度都说得通,我在数据库设计中特意把采购相关的字段放到了单独的视图层级,接口层面做了字段过滤,后面讲到权限校验时详细说。

2.2 功能模块拆分:从入库到提醒是一条完整链路

功能模块我按业务流拆成六个板块:

  1. 基础档案管理:药品信息维护,包括药品名称、通用名、规格、生产厂家、批准文号、包装单位、库存上下限预警阈值。
  2. 入库管理:手动录入或条码扫描入库,记录生产批号、生产日期、有效期、入库数量、供应商信息。
  3. 出库管理:按批号出库,支持拦截近效期药品。出库时要遵守"近效期先出"原则,下面会讲。
  4. 库存盘点:支持按药品盘点、按批次盘点,盘盈盘亏自动生成调整记录。
  5. 预警提醒:药品库存低于下限、药品有效期不足N天、药品已过期,三种情况分别触发不同级别提醒。
  6. 统计报表:库存流水、月度消耗排行、近效期药品清单、过期损耗统计。

2.3 核心业务流程:近效期先出是药品库存的灵魂

药品库存和普通商品库存最大的区别在于批次管理。同一盒布洛芬,一批是2025年5月到期,另一批是2026年3月到期,出库时如果先拿2026年的,2025年那批就会压着压着就过期了。所以整个出库流程必须锁定"近效期先出"(FEFO,First Expired First Out)原则。

我的出库流程是这样的:操作员选择药品,系统自动列出当前所有非空批次,按有效期从近到远排序,然后引导操作员从最近效期的批次开始出库。同时前端做了一道人机校验:如果出库的批次效期在90天以内并且库存充足,页面弹出二次确认框"该批药品90天内到期,是否确认出库?",防止操作员手滑。

入库流程相对简单,但有一个细节值得注意:同一批次的药品允许分多次入库。比如供应商一天内送了两趟货,操作员第一次入库20盒、第二次又入库30盒,这两条记录虽然是同一个生产批号,但应该拆成两个批次记录来管——因为它们的入库时间不同,追溯时信息不能混。我在设计数据库时特意给批次表加了一个自增ID而不是用生产批号做唯一键,就是为了应对这种情况。

预警流程是系统主动触发的。后端每天凌晨跑一次定时任务,扫描所有批次的有效期和库存数量,把满足预警条件的记录生成待办消息,通过微信订阅消息推送给相关角色。后面第5章我会把这条链路完整展开。

3. 批次级库存数据模型:一张表撑起整个预警体系

3.1 核心数据表设计思路

数据库设计是整个系统的地基,这里我踩过不少坑,直接给出经过修正的最终版本。核心表有五张。

药品信息表drug_info:存药品静态属性。关键字段包括drug_code(院内药品编码,不是国药准字号,是医院自己编的内部码)、drug_name、spec、dosage_form(剂型)、manufacturer、approval_no(批准文号)、low_stock_threshold、expiry_alert_days。最后两个字段就是预警配置,为什么放在药品表而不是单独的表?因为社区医院药品总量有限,整个系统就几百种药,不需要做复杂的预警规则引擎,直接在每个药品上配置"库存低于多少盒提醒""提前多少天提醒效期"就足够了,简单直接。

药品批次表drug_batch:这是整个系统最核心的表。

CREATE TABLE drug_batch ( batch_id BIGINT PRIMARY KEY AUTO_INCREMENT, drug_code VARCHAR(50) NOT NULL, batch_no VARCHAR(100) NOT NULL COMMENT '生产批号', production_date DATE, expiry_date DATE NOT NULL, initial_qty INT NOT NULL COMMENT '初始库存', current_qty INT NOT NULL COMMENT '当前库存', supplier VARCHAR(200), status TINYINT COMMENT '1有效 2冻结 3用完', create_time DATETIME, KEY idx_drug_expiry (drug_code, expiry_date) );

注意我加了一个status字段。当一批药品数量归零时不是直接删除记录,而是标记为3用完,这样流水记录里的外键引用不会断,回溯历史记录时信息仍然完整。idx_drug_expiry这个联合索引是出库查询和预警查询都会用的,别省略。

出入库流水表stock_record:记录每一次库存变动。字段包括drug_code、batch_id、record_type(1入库/2出库/3盘点调整)、change_qty(正负号区分入出)、operator(操作人)、create_time、remark。这张表只做插入,不做更新和删除。谁改库存、什么时候改、改了多少,永久留痕。药品追溯的时候全靠它。

用户表app_user:openid、user_name、role_id、phone、active_flag。这里有个细节:用户是管理员提前录好的,还是自己注册的?社区医院场景下我建议管理员后台统一录入,员工首次打开小程序时通过微信登录并绑定手机号,后台审核通过后激活。如果完全开放注册,医生离职后账号就没法清理,权限边界会失控。

3.2 为什么批次表能撑起整个预警体系

预警逻辑其实不复杂,但前提是数据模型支持。我把预警类型拆成三种:

  • 低库存预警:针对药品汇总各有效批次的current_qty,与drug_info.low_stock_threshold比较,低于阈值触发。
  • 近效期预警:针对单个批次,expiry_date与当前日期相差天数小于drug_info.expiry_alert_days时触发。
  • 过期预警:expiry_date已过,current_qty > 0,触发最高级别提醒。

这三种预警都可以在批次表上用一条SQL查出来:

-- 近效期预警示例:查询90天内到期且仍有库存的批次 SELECT d.drug_name, b.batch_no, b.current_qty, b.expiry_date FROM drug_batch b LEFT JOIN drug_info d ON b.drug_code = d.drug_code WHERE b.status = 1 AND b.current_qty > 0 AND b.expiry_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 90 DAY) ORDER BY b.expiry_date ASC;

这也是为什么我说"一张表撑起整个预警体系"——只要批次表的数据是准的,预警的逻辑就极其干净。

3.3 高并发扣库存的坑:要的是原子性不是复杂锁

社区医院药房同时操作的人数不会很多,但药品出库这件事仍然存在并发场景:两个窗口同时给患者发药,都在扫同一批药品的条码,如果没有限制,就会发生库存被扣成负数的情况。

我最初想到的方案是给整条批次记录加数据库悲观锁,SELECT ... FOR UPDATE,简单粗暴。后来想了想,这种做法的风险是持有锁期间万一代码抛异常没释放锁,整个药房的操作就卡死了。更稳妥的方式是利用MySQL的原子更新:

UPDATE drug_batch SET current_qty = current_qty - #{qty} WHERE batch_id = #{batchId} AND current_qty >= #{qty}

current_qty >= #{qty}这个条件就是隐形的乐观锁。如果受影响行数为0,说明库存不够,业务层直接提示"库存不足"并终止后续流程。配合事务,先做这条UPDATE,再插入stock_record流水,两件事要么都成功要么都失败。

这里有一个我实测踩过的坑:千万别先查再改。很多新手写代码习惯先SELECT查一下库存够不够,够就再UPDATE,这在并发下必出问题——两次查询之间数据可能已经被别人改了。原子更新一条SQL就解决,不要想复杂了。

4. 小程序端实现:登录态、列表加载更多与录入表单

4.1 微信登录与角色绑定的完整流程

小程序端的登录逻辑用一句话概括就是:""

前端调wx.login()拿到临时code,传给后端,后端拿这个code去微信接口换openid。之后每次请求都带上后端签发的自定义token,后端通过token识别用户身份。这里有几个容易踩坑的点:

第一,wx.login()生成的code只能用一次,五分钟内有效。很多新手把code存在全局变量里反复用,就会遇到接口返回40029之类的错误。正确做法是每次需要登录态的时候都重新调wx.login()。

第二,用户信息获取要克制。微信官方从2021年起不再默认返回用户头像昵称的授权弹窗,现在用户头像昵称的获取方式是"头像昵称填写能力"——用户自己点一个组件,手动选择头像和昵称。旅游、工具类的项目可以不处理这个,但社区医院系统里最好还是有个实名登记,毕竟涉及药品安全。我这里的做法是:基础登录只拿openid,在用户设置页面用官方提供的button open-type="chooseAvatar"让用户主动完善头像昵称,后台管理员审核后分配角色权限。

第三,token过期要自动续期。我在后端给token设了7天有效期,小程序端请求封装里统一处理401状态码——遇到401就重新走一遍登录流程,然后重放失败的那个请求,用户无感知。这个请求封装怎么写,第6章专门说。

4.2 库存列表"加载更多"的实现,别被onReachBottom坑了

库存列表是小程序端使用频率最高的页面。几百种药品如果一次性全部渲染,页面直接卡死。分页加载是必然选择。

小程序的分页核心是onReachBottom生命周期——页面滚动到底部时触发。我的页面逻辑是:

  1. 维护一个page变量(当前页码)和hasMore标志(是否还有下一页)。
  2. 首次进入页面,page = 1,调用loadList(1)。
  3. onReachBottom触发时,如果hasMore为true,page++并加载下一页。
  4. 每次加载返回的数据条数小于每页数量(比如每页20条,返回10条),就把hasMore置为false。

看起来很简单,实操中有一个特别隐蔽的坑:在某些安卓机型上,onReachBottom会在页面初始渲染时误触发一次。表现就是页面刚打开还没来得及操作,page已经变成了2。原因是页面内容不足一屏时,微信会把"页面已经到底部"当成一次滑动到底事件,触发onReachBottom。解决方式是引入一个"首屏加载完成"的标志位,首次加载完成后至少等500毫秒再放开onReachBottom的处理逻辑:

onReachBottom() { if (!this.pageReady || !this.hasMore || this.loading) return; this.page++; this.loadList(this.page); } // 在列表渲染完成后的setData回调里设置 this.pageReady = true

这个坑不吃一次真的很难发现——用户不会每次都跟你在同一台手机上测试,等你上线后收到反馈"页面数据重复""划两下就到底了",再排查会花不少时间。

列表页还有一个性能要点:大批量数据不要用setData直接传整个数组追加。比如库存列表渲染50条记录,setData时只传新增的那20条,用数组拼接的方式更新,而不是把整个50条重新set进去。差量更新在小程序里的性能提升非常明显,特别是低端安卓机上。

4.3 药品录入表单:从扫码到手动兜底

入库扫码是提升操作效率的关键功能。药品包装上通常有商品条码(69开头的EAN-13码),用小程序内置扫码能力扫一下就能自动填充。但注意——药品的商品条码和药品名称不是一一对应的。同一款药不同规格、不同厂家生产的,条码完全不同,系统里可能根本没有这个条码的档案。所以扫码只作为一个辅助录入手段,扫到能匹配的药就直接带出,匹配失败的还是要走手动录入流程。

扫码组件我用了wx.scanCode。这里有一个体验相关的细节:wx.scanCode是全屏扫码界面,药剂师一天可能扫几十次,每次都要对准、扫描、等待跳转,效率还是偏低的。后来我把流程改成"连续入库"模式:扫码后不跳转,直接在当前页面上追加一条待提交的入库记录,药扫完了统一提交。"一扫码就跳详情、填完再扫下一个"的模式,用户用几次就会骂人。批量操作场景下的交互流程设计真的很重要。

手动录入表单里有一个反直觉的字段:批准文号。一般人的直觉是录国药准字Z2005xxxx或是H开头的那串就能当唯一标识,但实际情况是同一药品不同生产厂家的批准文号不同,一个药品档案可能对应用多个批准文号。设计上就按"一个药品对应一个主批准文号"来约束,避免自找麻烦。

4.4 顶部导航栏高度和自定义导航栏的适配问题

很多社区医院的前端操作员用的都是低价安卓手机,屏幕尺寸五花八门,导航栏适配不好页面就会显示错位。我本来想偷懒用默认导航栏,后来发现我们要在页面顶部放一个"近效期预警"的徽标入口,默认导航栏做不了,只能自定义导航栏。这就牵出一个经典问题:自定义导航栏的高度怎么算。

微信小程序获取导航栏高度的正确姿势:

const menuButton = wx.getMenuButtonBoundingClientRect(); const navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height;

其中statusBarHeight从wx.getSystemInfoSync()里取。menuButton.top是胶囊按钮到屏幕顶部的距离,(menuButton.top - statusBarHeight)是导航栏在状态栏下方的高度,乘2加上胶囊高度是为了给上下留间距。实测下来,iPhone的胶囊高度是32px,安卓通常也是32px,但这个公式在几乎所有机型上都通用。

自定义导航栏的另一个坑是页面滚动时导航栏背景透明度的联动。药房操作员在手机上看库存列表时,页面往下滚,导航栏如果不跟着改变背景色,字就会和内容糊在一起。用onPageScroll监听滚动距离,动态切换导航栏的background和文字颜色,这个小细节做出来了整个界面质感会提升一个档次。

5. 自动提醒的实现链路:订阅消息、定时扫描与通知触达

5.1 订阅消息的授权策略:不要一上来就弹框

自动提醒是整个系统的"大脑",而微信订阅消息是提醒的出口。这里面的门道比较多,我一个个说。

微信订阅消息分两种:一次性订阅和长期订阅。长期订阅目前只对部分类目开放(比如医疗健康类的部分服务可用),一般开发者能用的都是一次性订阅。所谓一次性订阅,就是用户点击一次"允许"按钮,你只能推送一条消息。用户再点击一次,你再获得一次推送机会。这对我们这种"每天推送一次预警汇总"的场景来说,授权频次根本不够。

我的解决思路是改变推送策略,从"主动推送"改成"授权兑换"。具体做法是:

  1. 用户进入预警设置页,看到"开启库存预警提醒"的开关。
  2. 开关打开时,弹出订阅消息授权框,用户点"允许",系统拿到1次推送额度。
  3. 后端把这次额度换算成"当天的推送次数",用户在当天可以收到多条提醒。

这个方案绕开了长期订阅的限制,但需要一个前提条件来配合,就是提醒尽量在授权的同一记忆周期内触达。比如药剂师下午3点开了提醒开关,当天傍晚库存不足的消息推送过来,用户的记忆还是连续的,感知到"这个功能确实有用";如果第二天才来消息,用户早就忘了自己授权过什么,还容易觉得是骚扰。

还有一个实测很关键的细节:不要在小程序启动时就弹授权框。微信对授权弹框的时机没有任何硬性限制,但从用户心理上说,刚打开页面还没搞明白你是什么应用就弹授权,拒绝率极高。我在做这个项目时把授权请求放到了"开启预警开关"的用户主动动作之后,授权率从30%出头提升到70%以上,差别非常大。

5.2 订阅消息推送的后端封装

订阅消息接口调微信的subscribeMessage.send,需要准备的是:接收者的openid、模板ID、跳转小程序的页面路径、模板里要填充的数据。后端封装成统一的发送方法:

public void sendSubscribeMsg(String openid, String templateId, String page, Map<String, TemplateData> data) { WxMpSubscribeMessage message = WxMpSubscribeMessage.builder() .toUser(openid) .templateId(templateId) .page(page) .data(data) .build(); wxMpService.getSubscribeMsgService().send(message); }

我这里的模板参数是药品名称、批号、当前库存、有效期截止日期四选二组合使用,按预警类型不同组装。微信订阅消息的模板参数有长度限制(比如"药品名称"参数最长20个字),药品名称超长的需要截断处理,这个处理逻辑别放在后端接口层,在组装模板数据时统一做,避免不同的调用方各写一套截断规则,最后参差不齐。

推送提醒的页面路径也有讲究。消息点进去默认打开小程序首页,但如果能定位到对应药品的详情页,体验会更好。我在跳转参数里带了drugCode,小程序首页的onLoad里解析参数,有参数就自动跳转到该药品的库存详情页。这就是"从提醒到处理"的最短路径。

5.3 定时扫描任务的设计与执行时机

后端用Spring Boot自带的@Scheduled定时任务就够了,不需要引入Quartz增加复杂度。扫描频率我设置为每天凌晨1点扫描一次。为什么选这个时间?白天药房随时有人操作,库存数据一直变动,扫描结果很快就不准了;凌晨1点基本没人操作,数据相对稳定,生成预警清单最有参考价值。

扫描任务的逻辑分三步:

  1. 扫描所有status=1且current_qty > 0的批次,校验有效期。
  2. 按药品汇总有效库存,与low_stock_threshold比对。
  3. 把生成的预警记录写入warning_record表,同时给绑定了订阅消息额度的用户发推送。

这里有个"消息发不发"的细节:同一批药品连续多天处于低库存状态,是否需要每天推送?如果每天推,用户第三天就会把订阅消息当作骚扰,直接卸载小程序。我的做法是——第一天的预警做了提示,后端记录一个"已提醒"状态;只有当库存数量发生变化(比如更低或已补货)时才再次触发推送。这样药剂师每天收到的预警都是新增或变化的信息,而不是一片复读机。

定时任务的执行失败处理也要考虑。凌晨1点的扫描如果服务器当时恰好重启,任务不会自动补跑,预警就漏了。我加了一个补救机制:每天第一次有人登录小程序时,后端顺手跑一次轻量级扫描,只推送当天新出现的预警。这个逻辑很轻,不需要定时器,只要在登录接口里加一个"是否已完成今日扫描"的标志判断即可。

6. 后端接口封装、联调踩坑与发布上线经验

6.1 请求封装的正确打开方式

小程序端的请求封装看着简单,实际上决定了整个前端团队(哪怕就你一个人)的开发和排错效率。我最终封装的核心逻辑包含三件事:公共参数注入、token自动续期、错误码统一处理。

公共参数包括appId、timestamp、sign(防篡改签名,社区医院内部项目可以不搞这么重,但基础的timestamp必须加,方便后面排查问题)、以及token。我把这些统一放进请求头,不散落在每个请求里。

token过期处理刚才提过,这里给出代码逻辑:

request(url, data, method) { return new Promise((resolve, reject) => { wx.request({ url: baseUrl + url, method, data, header: { token: wx.getStorageSync('token') }, success: (res) => { if (res.data.code === 401) { // token过期,静默重新登录 this.reLogin().then(() => this.request(url, data, method)) .then(resolve).catch(reject); } else { resolve(res.data); } } }); }); }

错误码统一处理指的是:后端无论哪个接口报错,都返回{ code: xxx, msg: '...' }的结构。小程序端在请求封装里把非成功状态码统一弹toast提示,不再每个页面各写一遍错误提示逻辑。错误提示的文案要直接可读,例如"药品编码已存在",而不是"系统错误,请稍后重试"——稍后重试这种话用户看到只会更困惑。

有一点值得多说:接口的返回数据结构必须前后端提前约定好。我见过太多项目因为返回结构前后端理解不一致,联调阶段反复改来改去。直接用统一的{ code, msg, data }三件套,接口文档里标明每个字段的含义和可选值,省掉大量扯皮时间。

6.2 真实联调时踩过的几个典型报错

微信小程序请求fail的"真凶"不是代码而是域名。开发阶段在开发者工具里关掉"校验合法域名"就能跑通,但真机预览时如果依然报request:fail,十有八九是正式环境没配置request合法域名。在微信公众平台后台的"开发管理->服务器域名"里把https接口域名加进去,记得必须https且域名不能带路径。如果你用的是IP地址或者带端口的域名,微信目录下只支持443端口,就需要考虑用nginx做反向代理。

10002错误我很意外地遇到过不少次。具体场景是这样的:开发环境中点击订阅消息的授权框没反应,或者偶尔报错10002。排查后发现这是因为我的测试号没有绑定正确的模板ID,到微信公众平台后台找到对应类目的模板消息库,申请添加模板,再通过审核才能正常使用。这个错和代码逻辑没关系,纯粹是配置问题,但排查的过程真的很费时间,如果你也用订阅消息,第一件事先去后台确认模板ID是不是有效。

**"H5唤起小程序链接无法访问"**的情况也遇到过。我们有个需求是社区医院官网的文章里加一个"打开小程序"的入口,需要用到URL Link或者URL Scheme。生成URL Link的时候,后端要配置小程序的路径和参数。我最初生成的链接直接在浏览器里打开一直报错,后来发现是要给URL Link配置一个"备用网页",在不能打开小程序的场景下会跳转到那个网页,否则就会报无法访问。另外要注意URL Link的有效期,默认30天,长期入口需要用"有效期大于30天的URL Link"类型,需要单独申请。

6.3 体验版试用、年审与合规这些"非技术活"

小程序写完了,总得给同事、给医院的负责人测试。直接把代码通过微信开发者工具上传,然后在公众平台后台把版本设为"体验版",生成了体验版二维码。体验版二维码的权限是受控的,只有添加到体验成员列表里的微信号才能打开,这在测试阶段很重要——不然一个没做完的系统被外人扫到,麻烦就大了。

收集试用反馈这件事,我也建议做得有仪式感一点。体验版发给10个医院的工作人员用一周,收集到的反馈大部分集中在:录入表单流程繁琐、列表加载速度慢、推送消息点进去看不到对应数据——这些都是开发者在开发环境中根本感受不到的真实问题。比如有个反馈是"列表加载慢",我在开发工具里完全没察觉,但医院的老安卓机上确实卡,后来做了分页优化、差量setData优化后明显改善。

到期年审的事别忘。微信小程序每年要交300元认证费,认证到期前一个月公众平台会提醒。如果因为没及时年审导致小程序被冻结,恢复流程会很折腾。还有一个与合规相关的点:类目选择。我们做的是药品库存管理,不是直接卖药,类目选"医疗"下面的"健康管理"就够了;如果涉及在线售药,需要额外提供《药品经营许可证》等资质,项目边界没划好后面的审核会卡很久。我不建议为了过审谎报类目——也就是网上传的"骗审"——因为审核不通过是一回事,被平台发现类目不符下架是另一回事,对真实项目来说风险完全不值得。

6.4 部署环境与性能优化建议

部署这块,社区医院项目没有高并发需求,一台2核4G的云服务器完全够用。我在nginx里配了反向代理,域名走https,证书用免费版就行。MySQL用默认配置,定时任务跑起来毫无压力。

数据量方面,社区医院一年大约产生5到10万条出入库流水,MySQL对这种数据量根本用不着分库分表,但索引一定要建对。我的经验是:根据三类高频查询来设计索引——按药品编码查询批次(drug_code上建普通索引)、按有效期范围查询批次(expiry_date上建普通索引)、按时间范围查询流水(create_time上建普通索引)。冗余索引不要建太多,否则写操作的成本反而上去了。

最后一个小技巧:灰度发布。小程序不是传统的客户端,理论上每次发布都是全量。我刚做这个系统时很谨慎,每次改版都先在体验版环境跑一周,让医院的人先试,确认没有新问题再上传正式版。因为小程序上传新版本后用户需要重新进入才会加载新版本,如果当天有紧急修复,老用户还停留在旧版上,容易出岔子。

这个系统从需求调研到上线,前后大概用了两个多月。真正写代码的时间不算长,大头都耗在调研和价值取舍上——社区医院到底要什么、不要什么,比技术本身更重要。比如供应商端,我最初拍脑袋加了这个模块,后来被医院否了。再比如报表导出的格式,医院要的是能直接打印贴在药房墙上的格式,而不是一个花里胡哨的图表。这些"非主流需求"恰恰是项目成败的关键。

做这类面向特定场景的小程序,我最深的体会是:技术方案的选择永远服务于使用者。微信小程序解决的不是"用技术炫技"的问题,而是"社区医院药房那个最低效的环节到底在哪"的问题。技术选型、数据模型、提醒链路这些都是手段,最终目标就是让药剂师少跑几趟、少翻几次台账、少浪费几批药。

如果你也正在做类似的项目,我的建议是先去医院药房待一个下午,看看他们真实的工作流,然后再决定怎么设计系统。你会发现很多你认为"理所当然"的需求,在现场根本不存在;而现场那些真正让人头疼的时刻,恰恰是系统最应该解决的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询