ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从业务建模到部署:SpringBoot+Vue3开发城乡居民医保管理系统

从业务建模到部署:SpringBoot+Vue3开发城乡居民医保管理系统 1. 先说清楚城乡居民医保管理系统到底在管什么做这个系统之前我先跑了一趟社区服务中心和乡镇卫生院跟负责医保经办的工作人员聊了一下午。说实话不聊不知道聊完才发现大家平时以为的医保管理系统很复杂其实复杂度不在技术上而在业务规则的精细度上。城乡居民基本医疗保险跟职工医保不一样它覆盖的是没有固定工作单位的人群——老人、小孩、农村居民、灵活就业人员。这类人群的特点是参保状态变动频繁、家庭关系复杂、缴费年度与自然年度错位、身份类别多样普通居民、低保户、特困人员、脱贫人口等。比如一个农村家庭爷爷奶奶是普通参保孙子因为父母在外务工可能随父参保也可能随母参保低保户的参保费用是政府代缴的但系统里必须记录财政代缴标识还有每年9月到12月缴下一年度的费次年1月1日生效——这些都是这个系统必须覆盖的核心业务逻辑。所以这个项目的定位就清晰了它不是那种大而全的医保核心系统那是国家医保信息平台的活儿而是一个基层经办侧的管理工具用来做辖区内的参保登记、人员信息维护、缴费记录管理、待遇享受查询、统计报表导出。目标用户是街道/乡镇的医保经办人员、村社区代办员以及系统管理员。我在设计时给系统划了四个核心业务域参保管理新参保登记、续保确认、停保/退保、人员信息变更。缴费管理年度缴费记录个人缴费、财政代缴、缴费状态查询、欠费提醒。待遇查询看病报销记录查询、门诊/住院待遇享受情况这部分一般只读。统计报表按乡镇/村居/人员类别统计参保率、缴费进度、特殊人群覆盖情况。整个系统的数据流主线就一句话从人进来了参保登记到钱交了缴费记录再到待遇能享受报销查询最后生成报表。技术上的所有设计都是围绕这条主线服务的。这也是我想明白的一个道理——先有业务流程再有数据库表最后才有代码结构。2. 技术选型逻辑为什么锁死SpringBootVue3MyBatisMySQL这套技术栈被反复讨论不是没理由的。我在选型的时候没有用任何网红框架就按一个原则来对做业务管理系统来说团队能长期维护、社区生态成熟、遇到问题能快速搜到答案的方案就是好方案。逐个说一下我当时的考量。2.1 前后端分离值得但要把边界划清楚乡镇基层单位的信息化水平参差不齐可能在用的还是老式的JSP项目浏览器兼容性差、改个样式都要重启。前后端分离的价值不在于潮而在于静态资源前端和接口后端可以独立部署、独立升级。举个例子前端要改个按钮文案只需要重新build前端再丢到Nginx后端服务根本不用动。这项目我选择的前后端分离是同域部署、逻辑分离的折中方案前端打包成静态文件后端SpringBoot负责提供/api/**接口生产环境用Nginx统一转发前端请求/api时自动代理到后端端口。这样避免跨域问题的同时又保住了前后端代码上的完全解耦。开发环境则用Vite代理Vue3的devServer里配置代理到localhost:8080就行。这个方案是很多中小型管理系统最稳妥的路径。完全的前后端分离还要加上独立的权限认证中心、网关之类的对这个项目属于过度设计。2.2 后端SpringBoot MyBatis务实管用的组合SpringBoot的作用是把Spring那一堆繁琐的配置收起来。家人有老项目的经验知道以前写Spring MVC配置要配一堆XML——数据源、事务管理器、扫描路径、视图解析器。SpringBoot用自动配置解决了80%的重复劳动剩下的通过application.yml几行配置搞定。对于医保这类CRUD占一大半、且报表查询复杂的业务系统这套组合开发效率非常高。MyBatis是另一回事。很多人纠结MyBatis和JPA选哪个我的建议很直接业务查询复杂、要精细控制SQL、团队里都是SQL熟手——选MyBatis纯粹简单的CRUD、团队更习惯面向对象思维——选JPA。医保系统天然有大量多表关联查询参保人员表关联家庭表、医保类别表、缴费记录表经常要用到动态条件拼接按姓名、身份证、年度、参保状态组合查询。MyBatis的XML里写if标签拼动态SQL在这个场景下真是得心应手。2.3 Vue3组件化开发比Vue2香在哪里选Vue3不是跟风而是看上了两个硬能力组合式APIComposition API和更高效的响应式机制。做管理后台的时候传统的选项式API写业务逻辑是按选项切分——data、methods、computed各放一边一个页面功能多起来滚几百行找代码是常态。组合式API把同一件事的响应数据、计算属性、方法收拢到一个setup里一个功能块一个函数代码的可读性好了一个量级。举个例子我写参保登记页面时把这一个功能相关的逻辑都收在useInsureRegister()这个组合函数里// 组合式API把“参保登记”相关的数据与操作收拢在一个函数里 export function useInsureRegister() { const form reactive({ name: , idCard: , familyId: , category: 1, // 人员类别 finAidFlag: 0, // 是否财政代缴 insuredStatus: 0 }); const rules { name: [{ required: true, message: 请输入姓名, trigger: blur }], idCard: [ { required: true, message: 请输入身份证号, trigger: blur }, { pattern: /(^\d{15}$)|(^\d{17}[0-9Xx]$)/, message: 身份证格式不正确, trigger: blur } ] }; const submitLoading ref(false); const submitForm async () { // 表单校验通过后调后端接口 // POST /api/insured/register }; return { form, rules, submitLoading, submitForm }; }配合Element Plus的表格、表单、弹窗组件做后台管理系统的效率是Vue2时代没法比的。那时候自己写组件或者找第三方库质量参差不齐。现在Element Plus的组件质量、TypeScript支持都明显上了一个台阶。2.4 MySQL项目体量和数据规模决定选择城乡居民医保系统按一个区县来算参保人数一般几万到几十万核心业务数据量撑死百万级。这个规模MySQL 5.7/8.0完全扛得住而且运维成本极低——乡镇机房或者云服务器上跑个MySQL不需要专门的DBA。我还专门做了分表和归档策略缴费记录表按年度做分区历史数据定期归档到备份库既保证查询性能又控制了单表规模。3. 业务建模与数据库设计医保数据的第一道防线系统可以迭代但表结构如果设计错了后面改起来真是欲哭无泪。这块我花的时间最多仅次于写业务代码。我先说一个原则医保业务的数据建模一定是从人和时间两个维度去切因为参保状态、缴费状态、待遇状态全是跟时间强相关的。3.1 核心表结构从人到家庭到缴费我设计了9张核心表这里挑最关键的几张说家庭信息表family字段类型说明idbigint主键family_codevarchar家庭编号业务规则生成village_idbigint所属村/社区addressvarchar家庭地址head_namevarchar户主姓名head_id_cardvarchar户主身份证号contact_phonevarchar联系电话为什么家庭信息单独建表因为城乡居民医保是按家庭参保的模式一个家庭的成员统一登记、统一缴费。每次缴费时系统要按户生成缴费单家庭成员内部可以调整缴费人员但对外是一户一单。参保人员表insured_person——这是全系统最核心的表字段类型说明idbigint主键family_idbigint关联家庭表namevarchar姓名id_cardvarchar身份证号唯一索引gendertinyint性别birth_datedate出生日期categorytinyint人员类别1普通 2低保 3特困 4脱贫人口fin_aid_flagtinyint是否财政代缴 0否 1是insured_statustinyint参保状态 0正常 1停保 2退保first_insured_yearvarchar首次参保年度create_timedatetime创建时间update_timedatetime更新时间身份证号一定要做唯一索引而且要做15位/18位身份证的格式与校验逻辑。这块我后面踩了坑下面细说。人员类别和财政代缴这两个字段直接决定了缴费计划生成时的金额和缴费方式一定要在前端做成精确可控的下拉选择不能手填。缴费记录表payment_record字段类型说明idbigint主键person_idbigint参保人IDfamily_idbigint家庭IDpay_yearvarchar缴费所属年度2024年度等amountdecimal(10,2)应缴金额paid_amountdecimal(10,2)实缴金额pay_typetinyint缴费方式1个人自缴 2财政代缴 3集体补助pay_statustinyint0未缴 1已缴 2减免pay_timedatetime缴费时间operator_idbigint经办人ID这里有个业务细节要注意缴费年度不是自然年度。2024年9月到12月缴的是2025年度的费这笔记录的pay_year是2025但pay_time是2024年。报表统计2025年度参保率时查的是pay_year2025而不是按缴费时间过滤。这个方向搞错了报表数据会全乱。3.2 设计时容易忽视的四个坑第一身份证号查重的时机。新参保登记时做id_card唯一索引约束只是兜底业务上还必须在提交前先查一下这个人是不是已经在系统里、是不是停保状态。城乡居民医保一个人原则上只能在一处参保如果这个人从隔壁县转过来应该走参保关系转入而不是新建一条记录。我在后端接口里加了一个校验传入身份证号时先调selectByIdCard如果存在且insured_status1停保直接返回提示该人员已参保请走关系转入流程有效堵住了重复参保的漏洞。第二日期字段不要用字符串。参保人员的出生日期、缴费时间这些一律用date或datetime类型不要用varchar。用字符串存日期的后果是一旦出现格式不统一比如有的填2024-1-1有的填2024/01/01所有日期比较、排序、区间查询全部出错。MySQL里日期函数的性能优势也是字符串没法比的。第三金额字段必须用 decimal。缴费金额、报销金额都不要用float或double。浮点数存金额会出现 0.10.2≠0.3 的问题在医保这种对钱极其敏感的场景这是绝对不可接受的。decimal(10,2)是标配。第四软删除优先于物理删除。参保人员退保、缴费记录作废都不要直接DELETE。我在每张核心业务表都加了del_flag字段0正常 1已删除查询全部带WHERE del_flag 0。这样做的原因是医保数据涉及资金和待遇一旦发生纠纷需要追溯历史记录物理删除等于销毁证据。3.3 索引设计查询快的背后是字段选得准索引这块我踩的次数最多。一开始图省事只在主键和身份证号上建了索引结果参保人员列表页做组合筛选时——按姓名村居人员类别查询数据量过万后响应直接跑到2秒以上。后来一次性补了三组索引-- 参保人员表常用查询索引 ALTER TABLE insured_person ADD INDEX idx_id_card (id_card); ALTER TABLE insured_person ADD INDEX idx_family_id (family_id); ALTER TABLE insured_person ADD INDEX idx_name_category (name, category); -- 缴费记录表按年度状态查 ALTER TABLE payment_record ADD INDEX idx_person_year (person_id, pay_year); ALTER TABLE payment_record ADD INDEX idx_pay_status_year (pay_status, pay_year);注意idx_name_category是最左前缀索引查询时如果把category放在name前面这个索引就用不上了。这是MyBatis里写动态SQL时最容易犯的错——你的查询条件顺序必须跟索引的字段顺序保持一致。我在XML里查询条件就先固定写name再写category虽然MyBatis的if有空值判断但顺序不敢乱。4. 后端工程落地SpringBootMyBatis里最值钱的细节后端工程搭建本身不难难的是把项目结构组织得清楚、把容易翻车的地方提前堵住。4.1 项目分层与统一响应封装我按标准的四层结构来组织包名划分如下com.xxx.medical ├── controller # 接口层接收参数、调用service、返回统一响应 ├── service # 业务层事务管理、业务规则校验 ├── mapper # 数据访问层MyBatis Mapper接口 ├── entity # 数据库实体类 ├── dto # 接口出入参对象前端传递的数据模型 ├── common # 通用类统一响应、异常处理、工具类 └── config # 配置类拦截器、CORS、异步配置等统一响应类ResultT是必须的。前后端分离的项目如果每个接口返回的结构不一样前端写axios拦截器的时候会很痛苦。我定义的结构是{ code: 200, message: 操作成功, data: { } }code为200表示成功非200表示失败比如 400 参数错误、401 未登录、403 无权限、500 服务器异常。前端在axios响应拦截器里统一判断code ! 200就弹出错误提示不用每个页面单独处理。4.2 MyBatis的XML配置与动态SQL实战这是MyBatis项目里最核心的部分。我在写参保人员分页条件查询这个功能时充分体会到了动态SQL的便利select idselectPersonPage resultTypecom.xxx.medical.entity.InsuredPerson SELECT p.id, p.name, p.id_card, p.gender, p.birth_date, p.category, p.fin_aid_flag, p.insured_status, f.family_code, f.address, v.village_name FROM insured_person p LEFT JOIN family f ON p.family_id f.id LEFT JOIN village v ON f.village_id v.id where p.del_flag 0 if testname ! null and name ! AND p.name LIKE CONCAT(%, #{name}, %) /if if testidCard ! null and idCard ! AND p.id_card #{idCard} /if if testcategory ! null AND p.category #{category} /if if testinsuredStatus ! null AND p.insured_status #{insuredStatus} /if if testvillageId ! null AND f.village_id #{villageId} /if /where ORDER BY p.create_time DESC LIMIT #{offset}, #{pageSize} /select这里有几个细节用where标签而不是手写WHERE 11。where会自动处理掉第一个AND生成的SQL干净且不会出错。LIKE查询用CONCAT(%, #{name}, %)而不是%${name}%。后者会有SQL注入风险${}是字符串替换#{}是预编译占位符——只要用户输入涉及模糊查询一律走#{}CONCAT。分页用LIMIT offset, pageSize配合前端传参。数据量大之后考虑改成WHERE id ? LIMIT ?的 keyset 分页避免深分页的LIMIT 100000, 10性能灾难但我当前的数据量还不需要先按常规写法来。再讲一个容易翻车的点MyBatis的TypeHandler。项目里人员类别是tinyint但前端希望直接拿到普通/低保/特困这样可读的字符串。有两种方案一种是后端用枚举转换另一种是自定义TypeHandler。我的经验是能用枚举就枚举不要过度自定义TypeHandler。MyBatis内置的EnumTypeHandler能处理大部分场景而且代码可读性更好。我在实体里用了一个CategoryEnum返回给前端前做一次转换逻辑清晰也好排查问题。4.3 事务与并发缴费记录不能多扣也不能漏记缴费操作的流程是前端确认缴费 → 后端生成缴费记录 → 更新参保人缴费状态 → 记录经办人操作日志。这三个步骤必须在一个事务里否则可能钱扣了但记录没生成或者记录生成了但状态没更新。SpringBoot里在Service方法上加Transactional(rollbackFor Exception.class)是标配。注意要写rollbackFor默认情况下Transactional只回滚RuntimeException如果业务代码里抛的是Exception比如自定义的BizException继承Exception不写rollbackFor就会出现事务不生效的问题。这个坑非常隐蔽。**并发问题出现在同一家庭多人缴费的场景。经办人员可能同时操作一个家庭的多个成员如果两条线程同时更新payment_record和insured_person可能造成数据不一致。我的处理方案是对家庭缴费单加分布式锁用数据库的SELECT ... FOR UPDATE锁定家庭记录确保同一时刻一个家庭的缴费操作是串行的。用MySQL的行级锁虽然牺牲了一点并发但医保缴费业务量没那么大保证数据准确是第一位的。注意SELECT FOR UPDATE一定要在事务内使用并且要走索引主键查询否则可能锁全表引发性能问题。4.4 登录认证与权限不要重复造轮子也别太依赖轮子医保系统的登录认证不需要复杂到引入Spring Security全家桶——虽然它能做非常细粒度的方法级权限控制但配置和学习成本都不小。对小团队维护的业务系统来说一个轻量级的Token认证方案反而更可控。我用的是JWT 拦截器的方案用户登录成功后后端生成JWT Token返回前端Token里包含用户ID、用户名、角色。前端把Token存到localStorage每次请求在Authorization请求头带上。后端写一个AuthInterceptor拦截所有/api/**请求校验Token的有效期和签名。角色权限用简单的注解或拦截器判断比如管理员才能操作参数配置接口。再说一次不要在生产环境裸用JWT不设过期时间。基础医疗信息是受法律保护的个人敏感信息Token长期有效意味着只要Token泄露别人就能一直访问系统。我把Token过期时间设为8小时并且提供了一个refreshToken机制——用户操作时自动续期避免频繁重新登录。4.5 日志记录医保系统的审计要求医保业务涉及资金、个人身份信息、待遇享受资格操作必须可追溯。我在系统里做了一个简单的日志表谁在什么时间对哪条记录做了什么操作新增/修改/删除/导出。关键业务的增删改接口里统一调用OperLogService.save()记录日志。不要小看这个设计真到数据出问题需要回溯的时候这几乎是救命稻草。5. 前端Vue3从页面骨架到数据闭环说句实话写管理后台的前端最难的不是技术而是让不懂技术的经办人员用得顺手。我在做系统原型时跟使用人员反复确认过一个40多岁的窗口工作人员每天可能要录入几十个参保人员录入界面必须够大、必填项提示必须够明显、操作完必须有明确的成功反馈。前端的很多设计都是围绕让经办不犯错、少费眼神来做的。5.1 Vue3项目结构与Vite配置我用Vite创建项目开发依赖改到package.json的devDependencies构建工具用Vite是因为它冷启动极快基于ESM的按需编译在开发时基本秒开。项目结构src ├── api # 接口请求封装 ├── assets # 静态资源 ├── components # 通用组件 ├── router # 路由配置 ├── store # Pinia状态管理 ├── views # 页面组件 │ ├── insured # 参保管理 │ ├── payment # 缴费管理 │ ├── treatment # 待遇查询 │ └── report # 统计报表 ├── utils # 工具函数 └── App.vue开发环境的代理配置在vite.config.jsimport { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })这样前端开发时请求/api/xxx直接代理到后端8080端口没有跨域问题联调效率很高。5.2 核心页面设计从录入到查询的体验优化参保登记页面是我打磨最多的。布局采用左侧家庭信息 右侧人员列表的两栏结构——先选择或创建家庭再在家庭下添加参保人这个操作路径跟经办人员的实际工作习惯完全一致。表单校验用Element Plus的规则配置身份证号、手机号、金额格式都有校验。每完成一个人员新增页面底部弹出成功的Messenger提示同时自动清空表单开启下一条录入连续录入的场景效率提升非常明显。缴费管理页面的核心是一张待缴费清单表格列出本年度所有未缴费的家庭每行显示家庭编号、户主、人数、应缴金额、缴费截止日期右侧按钮去缴费。点击后弹出确认框显示缴费金额和缴费方式个人自缴/财政代缴确认后调接口生成缴费记录。我把财政代缴的逻辑做成了自动判断家庭成员中存在人员类别为低保/特困/脱贫人口的缴费界面自动切换为财政代缴并置灰不可修改防止经办人员误操作。统计报表页面用的是ECharts折线图柱状图展示参保人数变化趋势、各村缴费完成率排名。报表页面最需要注意的不是图表本身而是查询参数的默认值——默认查询当前年度避免经办人员忘记选年度导致查出一堆跨年数据。5.3 接口对接与axios拦截器前端的统一规范我在src/api/request.js里封装了axios实例把统一响应处理放在拦截器里import axios from axios import { ElMessage } from element-plus const service axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器带上 token service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer ${token} } return config }) // 响应拦截器统一处理业务状态码 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { if (error.response error.response.status 401) { ElMessage.error(登录已过期请重新登录) router.push(/login) } else { ElMessage.error(网络异常请稍后重试) } return Promise.reject(error) } )这个request.js是全前端共用的每个页面只需要 import 对应的API函数不需要关心响应结构。注意router不能直接 import 使用要在文件里用import router from /router避免循环引用问题。5.4 用Pinia管状态当前用户的权限与操作上下文我用了Pinia来管理当前登录用户的信息和权限标识。登录成功后后端返回用户信息角色列表前端存进Pinia store侧边菜单根据角色路由显隐。写判断逻辑时要注意后端接口的权限校验是必须的前端路由的权限控制只是体验优化。千万不要以为前端隐藏了菜单就安全了后端接口不加拦截器有心人直接构造请求一样能访问到。6. 部署联调中最容易翻车的三个环节开发环境一切正常一到部署环境就问题百出这是管理系统的常态。我梳理了几个高概率踩坑点。6.1 MySQL时区与SSL连接问题MySQL 8.0 默认时区是UTC如果后端的连接串没指定时区插入时间的字段会出现数据库时间比本地早8小时的问题。我的连接串这样写jdbc:mysql://localhost:3306/medical?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrueuseSSLfalse是因为本地数据库一般没配置SSL证书不关闭的话会报SSL connection error。这个报错在网上被反复问其实就是连接参数的问题。注意allowPublicKeyRetrievaltrue是MySQL 8.0 用caching_sha2_password插件时必须的否则也可能连不上。6.2 Vue3打包后部署在SpringBoot静态目录还是独立Nginx这是个两难。我的建议生产环境用独立Nginx部署前端后端只管接口。虽然SpringBoot可以把前端打包后的dist目录复制到static目录下一起发布但这样有一个问题——前端页面发版必须跟着后端一起重启这在运维上是灾难。独立Nginx部署的好处是前端更新只要替换静态文件、reload Nginx配置就行后端完全不用动。生产环境Nginx的关键配置server { listen 80; server_name medical.example.com; # 前端静态文件 root /opt/medical/dist; index index.html; # 前端路由使用 history 模式需要 fallback 到 index.html location / { try_files $uri $uri/ /index.html; } # API 反向代理到后端 SpringBoot location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }注意try_files的兜底配置是必须的。Vue Router 用 history 模式时直接刷新某个子路由页面比如/insured/listNginx默认会去找这个路径的物理文件找不到就404。配置了try_files ... /index.html后刷新操作被正确回退到前端路由接管。6.3 数据备份与首次上线的历史数据迁移上线前的第一件大事是历史数据迁移。原本停保、退保状态的数据乡村两级可能用Excel在管理要把这些数据清洗后导入新系统。我在系统里写了一个批量导入的接口支持从Excel模板导入参保人员信息。导入过程中做了一堆校验身份证号格式、必填字段、重复参保检查每行有错误就记录到导入日志并跳过绝不中断全量导入。备份策略上MySQL每天凌晨自动备份一份mysqldump文件保留最近7天定时任务把备份文件同步到另一台服务器或对象存储。医保系统的数据丢了不是小事。7. 这套系统的可复制经验与后续扩展思路做这个项目最大的体会是管理系统的技术难度上限不高但业务理解的下限决定系统质量。光会写CRUD是远远不够的——你得清楚城乡居民医保和职工医保的差别、财政代缴和个缴的处理逻辑、年度缴费和自然年度的时间错位、身份类别对缴费金额的影响。这些业务规则如果搞错了代码写得再漂亮也是白搭。7.1 如果重新做一次我会优化什么第一引入枚举字典表。人员类别、缴费方式、待遇类型这些编码目前是硬编码在前后端代码里的。后续如果政策调整新增一个人员类别要前端、后端同时改代码重新发版效率太低了。如果有一个字典表 字典管理页面新增类别只改数据系统不用动维护成本会低很多。第二文件存储标准化。医保经办过程中会产生很多材料身份证复印件、低保证明、特殊人员证明等目前是存网盘然后记录路径非常松散。后续应该用统一的对象存储服务文件元数据入库跟参保人员的业务记录关联起来。第三移动端适配。基层经办人员很多要下村入户带着笔记本电脑录入很不方便。目前系统只做了PC端Web如果后续做一个小程序或H5让村干部用手机帮老人登记参保业务效率会明显提升。7.2 可以分享给你的技术清单如果你也打算做类似的市县/街道级业务管理系统这套技术组合我可以明确推荐后端SpringBoot 2.7.x MyBatis MySQL 8.0 JWT前端Vue3 Vite Element Plus Pinia Axios ECharts部署前端Nginx 后端jar包systemd守护 MySQL定时备份开发流程先定业务规则 → 再建表 → 再写后端接口 → 再对接前端 → 最后部署验证这套组合的优势是招人容易、换人也能快速接手、遇到问题社区答案多、跑在2核4G的云服务器上毫无压力。对于预算有限、又要做实事的基层单位来说这就是最稳妥的答案。最后再提一件小事写代码之前先去现场跟业务人员待半天。系统里那些看起来不优雅的按钮位置、字段顺序、操作流程可能正是他们最习惯的操作方式。技术是服务业务的这点在医保系统里体现得尤其充分。做管理系统的这些年我最大的收获不是掌握了多少框架而是学会了先听懂业务、再动手写代码。
返回列表