尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python+Vue前后端分离人事管理系统开发实战:Django与Flask选型

Python+Vue前后端分离人事管理系统开发实战:Django与Flask选型 先说我做这个项目的真实感受名字看着很长其实核心就是在Python后端和Vue前端之间把企业里最琐碎的人事流程给捋顺了。我自己用PyCharm从零搭过两套类似系统一套用的Django另一套用的Flask期间踩了不少坑也总结出一套能直接复用的打法。这篇文章不打算讲空泛的理论就想把选型思路、数据库设计、模块拆分、联调排错这些实操层面的东西摊开说清楚给正准备做毕业设计、转岗练手项目或者小团队内部工具的朋友一个参考。你不需要一上来就精通所有框架跟着这套思路走至少能少走三个月的弯路。1. 项目核心需求拆解人事管理系统到底在管什么很多新手拿到企业人事管理系统这个题目第一反应是画一堆功能列表比如员工管理、考勤管理、薪资管理、部门管理、公告管理然后就开始闷头写代码。这样做最容易出的问题是代码写完了业务方一句话就把你怼回来——我要的不是Excel能干的活我要的是Excel干不了的活。所以在动手之前先搞清楚人事管理系统的数据主线是什么这是整个项目的灵魂。1.1 业务模块全景从入职到离职的数据主线我用一句话概括人事系统的本质记录员工生命周期里的每一次状态变化并让这些变化产生可追溯、可统计的数据资产。员工生命周期大致是这样一条线招聘入职 - 签订合同 - 分配到部门/岗位 - 日常考勤 - 绩效考核 - 薪资核算 - 异动调岗/调薪/转正- 离职/退休。围绕这条主线系统至少要拆出这几个核心模块组织架构模块部门树、岗位体系、编制数量这是所有数据的挂靠基础。部门表设计成树形结构parent_id指向上一级部门前端用Vue的递归组件渲染成树形菜单。员工信息模块这里要区分主数据和过程数据。主数据是员工的基本信息姓名、证件号、联系方式、入职日期一旦录入基本不变过程数据是合同续签记录、调岗记录、奖惩记录这些是动态增长的。考勤模块这个模块最容易复杂化。我建议第一版先做打卡记录 请假/加班审批单 月度汇总三件套不要一上来就搞复杂的排班规则后续再迭代也不迟。薪资模块薪资往往是系统里最敏感的模块。实发工资 基本工资 绩效奖金 加班费 补贴 - 社保扣款 - 个税公式要可配置不要写死在代码里。系统管理模块用户表登录账号和员工表人事档案一定要分开账号是账号员工是员工中间用employee_id关联。角色、权限、操作日志都挂在这个模块下面。从技术角度看这个主线对应的就是数据库表之间的外键关系。我在实际设计时最深的体会是宁可前期多花一天梳理字段也不要后期花一周改表结构。尤其是员工表每个字段别急着定死尽量用可扩展的方式。1.2 不同规模企业对系统的差异化需求做这个项目之前一定要先明确目标场景否则功能设计会走样。我接触过两种典型情况小型企业50-200人这类企业往往没有专职的HR系统管理员用的最多的是员工花名册 考勤统计 简单的薪资记录。系统要轻、要快、要容易操作。部署在一台普通服务器上就够用甚至开发阶段直接在本地跑起来演示也行。这种场景下Flask Vue的轻量组合非常合适拆分成前后端两个项目后端跑在5000端口前端用Vite起在5173端口开发时通过代理转发请求。中大型企业500人以上这时候权限模型、审批流、数据隔离就变得非常重要。比如不同部门的HR只能看到自己部门的人员数据财务只能看到薪资模块员工本人只能看到自己的个人信息和考勤记录。这种场景下Django自带的Admin和认证系统会省很多事但也要注意Django的ORM虽然方便复杂查询时一样要手写SQL。权限建议采用RBAC模型用户-角色-权限三层前端路由也要跟着做动态权限控制。我建议你动手前先把这个定位想清楚因为后续所有技术选型都跟着这个走。如果你做的是一份毕业设计或面试项目中小型场景最讨巧既能展示完整闭环又不会因为过度设计把自己耗死。2. 技术选型解析Python Vue这套组合的逻辑市面上做管理系统的技术栈五花八门Java有Spring Boot全家桶Go有GinPHP有ThinkPHP为什么单独拿出来说Python Vue我的看法是这套组合最适合个人开发者中小型项目的节奏。Python的开发效率高Vue的响应式框架写管理端页面很顺手两边都有庞大的社区遇到问题搜一下基本都能解决。2.1 前端为什么选Vue而不是其他框架现在前端三驾马车React、Vue、Angular国内管理系统的生态里Vue确实占了很大优势。这不是说React不好而是Vue的学习曲线更平滑模板语法直观特别是Element Plus这类组件库成熟到开箱即用的程度。你要做的增删改查、分页表格、弹窗表单直接引入组件就能拼出来比从零写要快得多。我一直建议用Vue生态里的Vite构建工具加Element Plus组件库组合。Vite的冷启动速度快到离谱改完代码页面秒刷新不像老一代Webpack要等好几秒。除此之外Vue的核心概念其实不多核心就是响应式数据绑定数据变了页面自动更新页面改了数据自动同步组件化开发把员工列表封装成一个组件把表单弹窗封装成另一个组件页面之间像搭积木一样组装Vue Router前端路由控制页面跳转对应不同菜单项Pinia或Vuex全局状态管理比如登录用户信息、当前权限列表这种全局共享数据以登录功能为例用户在登录页输入账号密码前端拿着这俩字段发给后端接口后端校验成功返回一个token前端把这个token存到localStorage里然后跳转到首页。之后每一次请求都在header里带着这个token后端用它来识别当前是谁在调用接口。这个概念在前后端分离的项目里是最核心的后面的整个权限控制都围绕它展开。2.2 Django与Flask的定位差异与选型建议标题里同时出现了Django和Flask很多人选型时犯难我直接说结论两者不冲突关键看你的项目半径。Django走的是全家桶路线自带ORM数据库操作、Admin后台、用户认证、表单校验、Admin管理界面。你不需要额外装太多第三方库就能搭出一个功能完整的项目。文件结构也是规定好的项目文件夹下面有app文件夹每个app负责一块业务。学习曲线相对陡要理解中间件、信号、迁移这些概念。好处是规范安全适合中大型项目。Flask走的是微框架路线核心只做路由分发其他东西需要什么装什么。比如用SQLAlchemy做ORM用Flask-JWT-Extended做登录认证用Flask-Migrate做数据库迁移。好处是灵活启动一个服务只要几行代码做个原型特别快。坏处是项目大了容易代码混乱需要自己规划目录结构。我的实战建议是如果你只需要一个管理后台后端逻辑主要是增删改查加接口暴露Flask完全足够而且你会更清楚地知道每一条请求是怎么被处理的。如果你想系统的学一遍Web框架直接用Django因为Django强制的项目-应用结构本身就是一种工程实践教育。还要提醒一点热门搜索词里经常出现flask 与 fastapi 比较如果项目未来有高并发实时交互需求FastAPI确实是更先进的选择。但对于人事管理系统这种典型CRUD应用数据量在十万级以下时Flask和Django都能轻松胜任性能瓶颈根本不在框架而在SQL写得好不好、索引建得对不对。2.3 用PyCharm搭建开发环境的细节PyCharm这个IDE在搜索词里跟Python绑定出现是有原因的。社区版免费够用专业版多了数据库工具、前端插件这些便利功能。我个人的配置习惯是这样的解释器配置打开设置-Project-Python Interpreter选择虚拟环境。强烈不建议用全局Python环境每个项目建一个venv虚拟环境依赖隔离打包部署时才不会出幺蛾子。前端插件PyCharm专业版自带Vue插件支持模板语法高亮和跳转。如果用社区版建议前端代码用VS Code写后端用PyCharm写两个窗口各干各的联调用接口文档对接。这听起来有点折腾但体验反而更顺。数据库面板专业版右侧有Database工具面板可以直接查看表结构、执行SQL、甚至可视化编辑数据。开发人事系统时频繁要查员工表、部门表的数据用这个面板比命令行直观得多。快捷键习惯CtrlShiftF全局搜索、CtrlShiftR全局替换、AltF12打开终端。养成这几个就够了其余边用边查。顺便说一句安装依赖的时候建议用pip配合requirements.txt文件统一管理。把项目依赖写进这个文件里换电脑、部署到服务器、别人接手项目时一条pip install -r requirements.txt命令全部搞定。很多新手在搜索pycharm怎么安装pandas包其实就是打开终端敲pip install pandas没那么多花活。3. 系统架构与数据模型设计架构设计这个东西很多人觉得是高级工程师才要考虑的事其实一个几十张表的管理系统同样需要想清楚。核心就一句话前端只负责展示和交互后端只负责业务逻辑和数据持久化两边用JSON格式的HTTP接口通信。3.1 前后端分离架构的边界划分前后端分离是目前管理系统的绝对主流方案。前端项目和后端项目是两个独立的应用可以放在不同的目录、不同的仓库甚至部署到不同的服务器。前端通过axios发HTTP请求后端通过路由接收请求、执行业务逻辑、返回JSON数据。以员工查询功能为例完整的请求链路是这样的前端员工管理页面的搜索框里输入关键字点击查询按钮前端用axios向后端发送GET请求路径类似于/api/employees?keyword张page1page_size10后端路由接收到这个请求先做参数校验然后调用数据库查询逻辑返回JSON数据前端拿到回包后把数据渲染到表格组件里这里有两个关键设计要注意接口路径统一前缀。所有后端接口都挂在/api/下面这样开发时可以用Vite代理转发请求部署时可以用Nginx做反向代理将来如果接口迁移到别的服务地址前端只需要改一个baseURL配置。一个前后端分离的项目接口路径就是两边的契约宁可一开始就规范也不要后面到处改。统一响应格式。我习惯用这样的结构{code: 200, msg: success, data: {...}}。code为200代表成功400代表参数错误401代表未登录403代表无权限500代表服务器异常。前端axios拦截器里统一处理这个结构遇到401自动跳转登录页遇到403弹出无权限提示遇到500弹出错误消息。这个约定看着不起眼实际联调时能省掉一半的沟通成本。3.2 核心数据表设计与字段规划数据库设计是整个项目的压舱石。我在第一版设计的时候犯过一个错误把员工的所有信息全塞进一张表里结果表字段膨胀到四十多个查询和展示都变得很笨重。后来重新拆分才明白应该按信息变更频率来分组。最终我采用的是这样一组核心表表名核心字段说明departmentid, name, parent_id, leader_id, create_time部门表parent_id自关联形成树形结构employeeid, emp_no, name, gender, phone, email, id_card, department_id, position_id, hire_date, status员工主表emp_no是员工编号唯一索引user_accountid, username, password_hash, employee_id, role_id, is_active登录账号表密码存哈希不存明文与employee表一对一关联roleid, role_name, description角色表permissionid, perm_name, perm_code权限表perm_code类似employee:add这样的字符串attendanceid, employee_id, work_date, check_in_time, check_out_time, status考勤打卡表leave_applicationid, employee_id, start_time, end_time, leave_type, reason, status, approver_id请假申请审批表salary_recordid, employee_id, month, base_salary, bonus, overtime_pay, deduction, social_security, tax, final_salary薪资月表final_salary是计算后的实发工资这些表之间的关系说白了就是外键引用。举几个实际场景查询某个部门下的所有员工SELECT * FROM employee WHERE department_id ...如果部门还有子部门就要用递归CTE查询把子孙部门的所有员工一起查出来。查询员工的所有考勤记录SELECT * FROM attendance WHERE employee_id ...按月汇总就是GROUP BY employee_id, DATE_FORMAT(work_date, %Y-%m)。查询员工的历史薪资按员工ID和月份倒序排列。密码存储必须用哈希常见的选择是用Django自带的make_password或者Flask里装werkzeug.security的generate_password_hash。明文密码在管理系统的代码里出现了那基本等于安全事故。3.3 权限控制与登录态设计权限控制这块我单独拿出来说是因为这是管理系统里最容易做砸的部分。简单说目标就是不同角色登录进去看到的东西不一样能操作的东西也不一样。权限模型采用RBACRole-Based Access Control基础表就是上面说的用户表、角色表、权限表再加一张用户-角色关联表或角色-权限关联表。数据库层面的控制逻辑是用户登录成功后后端根据user_id查询对应的角色根据角色查询权限列表把权限码列表一起返回给前端前端把权限码存到Pinia全局状态里路由守卫在进入每个页面之前检查当前用户是否拥有该页面的权限码后端接口层面也要做同样的检查不能只靠前端隐藏按钮来防越权前后端都要校验这一点很重要。前端控制是为了用户体验后端控制才是安全底线。如果后端接口没有做权限校验懂点技术的人完全可以绕过前端直接调用接口把不该看的数据拿走。登录态的常见实现是JWTJSON Web Token。用户登录成功后后端生成一个token里面包含用户ID、过期时间、签名信息。前端保存这个token每次请求在请求头里带上Authorization: Bearer token。后端写一个装饰器或中间件在进入业务逻辑之前先解析token解析失败就返回401。token的过期时间建议设置短一点比如2小时配合刷新机制这样即使token泄露风险窗口也小得多。4. 核心功能模块的实操实现这一章是实操环节我按从前到后的顺序把人事系统里最核心的几个模块怎么落地说一说。每个模块都涉及前后端配合我会把关键代码片段和踩坑点都标出来。4.1 员工信息管理增删改查与部门联动员工信息管理是整个系统的地基。前端页面是左侧部门树 右侧员工表格的经典布局。点击左侧某个部门节点右侧表格展示该部门下所有员工点击根节点全部展示所有员工。这背后的接口逻辑是前端传入department_id可选和keyword可选、page、page_size后端拼查询条件分页返回数据后端Django的查询视图大概长这样def employee_list(request): department_id request.GET.get(department_id) keyword request.GET.get(keyword) employees Employee.objects.select_related(department, position).all() if department_id: # 关键点要包含子部门的员工 dept_ids get_descendant_ids(department_id) employees employees.filter(department_id__indept_ids) if keyword: employees employees.filter( Q(name__icontainskeyword) | Q(emp_no__icontainskeyword) ) # 分页 page int(request.GET.get(page, 1)) page_size int(request.GET.get(page_size, 10)) paginator Paginator(employees, page_size) ...这里最需要注意的是子部门员工查询。如果用户点击的是研发部但研发部下还有前端组和后端组系统的期望是把两个子组的人一起查出来。实现方式有两种一种是查询前先用递归函数把所有子部门ID查出来再IN查询另一种是表里加一个path字段记录每个部门从根到自己的路径比如/1/3/7/然后前缀匹配。数据量小的时候第一种就够用数据量大了建议用path方式。新增员工的时候事务控制很重要。员工基本信息、账号信息、初始角色可能是三张表的数据如果中间某一步出错前面的写入就要回滚。Django里用transaction.atomic()装饰器包裹Flask里用db.session.begin_nested()实现嵌套事务。这里有一个很多新手容易忽略的坑新增员工时如果同时创建登录账号需要生成一个初始密码而这个密码不能明文写进日志里。我通常的作法是初始密码统一为123456登录后强制要求修改修改密码接口里做强度校验。4.2 考勤与请假审批的数据流转考勤模块的数据流转是申请 - 审批 - 汇总三段式。请假流程大概是员工在前端填写请假申请单选择起始时间、结束时间、请假类型事假/病假/年假/调休提交后后端在leave_application表插入一条记录status标记为pending审批人通常是部门经理或HR在待办列表里看到这条申请点击通过或驳回通过后请假单的状态变为approved同时这段期间的考勤状态标记为leave这个流程看着简单实际有两个隐蔽的需求点日期重叠校验一个员工不能在同一时间段提交两个请假申请。后端在插入新申请之前要查一遍该员工在这个时间段内是否已有approved或pending状态的申请。这个校验逻辑用SQL写出来就是conflict LeaveApplication.objects.filter( employee_idemployee_id, status__in[pending, approved], start_time__ltend_time, end_time__gtstart_time, ).exists()审批权限判断谁能审批这张单子最简单的规则是本部门上级和HR可以审批。如果部门经理的表里有manager_id或leader_id字段就查这个字段匹配当前登录用户HR角色则直接放行。权限不足的审批接口要返回403前端看到403要给出明确提示。考勤月度汇总的逻辑是每个月月初或者月末拿上月的打卡数据和请假数据逐员工计算应出勤天数、实际出勤天数、请假天数、迟到次数。这个汇总可以写成后端定时任务也可以做成手动触发的报表生成按钮。我个人推荐做成手动触发因为第一批用户通常对自动化不太放心手动触发让他们能看到整个过程后续信任建立了再加定时任务。定时任务在Django里常用Celery在Flask里常用APScheduler如果只是简单的每天凌晨跑一次汇总APScheduler就够了不必为了这点功能引入Celery这条大鱼。4.3 薪资核算与可视化报表的前后端配合薪资模块是权限要求最高的地方我建议把薪资相关的接口和普通员工接口分离单独挂一套权限码。基本逻辑是每月月底HR在系统里选择工资月份点击生成工资单系统拉取该月考勤汇总和员工基本工资数据按照公式逐项计算最后生成工资列表。计算的核心公式建议做成可配置的不要直接在代码里写数字。工资计算逻辑示意def calc_salary(employee, month): base employee.base_salary attendance_summary get_month_attendance(employee.id, month) # 加班费平时1.5倍周末2倍节假日3倍 overtime_pay attendance_summary[weekday_overtime_hours] * base / 174 * 1.5 # 缺勤扣款按天扣假设每月应出勤22天 absent_deduct attendance_summary[absent_days] * base / 22 # 五险一金按固定比例这里只是演示逻辑实际比例要看各地政策 social_security base * 0.105 # 个税按简易累进税率 taxable base overtime_pay - absent_deduct - social_security tax calc_tax(taxable) final_salary taxable - tax ...这套逻辑我至少重写了两遍才稳定下来主要难点在于各种边界情况员工月中入职该怎么算应出勤天数请假跨月怎么归属调薪生效日期卡在月中怎么办。我的经验是第一版先用最简单的方式按自然月算月中入职就当月发半月工资把整体流程跑通再逐步处理灰度情况。前端展示这块用ECharts画图是很成熟的选择。比如月度薪资趋势折线图、部门人数占比饼图、考勤异常排行柱状图。ECharts在Vue里的基本用法是在mounted钩子里初始化图表实例然后更新option传入数据。要注意的是图表容器必须有明确的高度且当页面从隐藏状态切换回来时图表可能发生尺寸错乱需要调用chart.resize()调整。数据看板这个模块非常适合用来展示项目亮点面试时讲起来也很有说服力。你可以准备两个看板一个管理看板总人数、本月入离职人数、各部门人数、学历分布一个财务看板月度薪资总额、各部门薪资占比、人均成本。前者面向全员或管理层后者只面向财务和老板。5. 常见问题与排查技巧实录这部分是这次项目里最有价值的部分全是调试现场总结出来的经验。我把最容易卡住新手的几个问题整理成速查列表并按排查思路逐一说明。5.1 跨域问题前后端分离的第一个坎如果你用Vue开发环境Vite默认跑在5173端口访问后端APIFlask跑在5000端口打开浏览器控制台会看到一个经典报错Access to XMLHttpRequest at http://localhost:5000/api/... from origin http://localhost:5173 has been blocked by CORS policy。这就是跨域问题。浏览器默认认为5173和5000是两个不同的来源前端JS直接访问另一个来源的接口是不被允许的。解决方式有三种开发阶段使用Vite代理在Vite配置文件里设置proxy把/api开头的请求转发到http://localhost:5000。前端代码里请求路径写成/api/employees浏览器看到的是同源请求Vite在后台悄悄转发。这个方案最优雅不需要后端任何设置。后端开启CORSFlask用flask-cors扩展Django用django-cors-headers。直接把所有来源都放行操作简单但不适合生产环境因为等于允许任何网站来调用你的接口。生产环境用Nginx反向代理前后端构建产物都放在Nginx下面所有/api请求由Nginx转发到后端服务。这样前后端彻底同源不存在跨域问题。我的建议是开发环境用Vite代理生产环境用Nginx这两个方案配合是最稳的。曾经有一次我图省事直接在后端开了CORS放行所有来源结果联调时抓包抓到一堆来路不明的请求吓出一身冷汗。5.2 登录状态丢失与请求无响应联调阶段最常见的两个现象发请求一直是401或者发请求完全没反应。401的原因token没带上、token过期、token解析失败。排查顺序先打开浏览器开发者工具Network面板看请求头里有没有Authorization字段没有就是前端拦截器的问题有但还报401就要看后端日志里解析token时报了什么错通常是过期时间提示或者签名不匹配。签名不匹配的原因往往是后端SECRET_KEY和签发token时用的SECRET_KEY不一致。这种情况在Django里出现频率很高因为settings文件换了环境没改。请求没反应的原因后端服务没启动、端口不对、请求被浏览器或服务端防火墙拦了、Vite代理配置有误。排查顺序先用Postman直接请求后端接口能通说明后端没问题问题出在前端代理Postman也不通就去命令行curl一下确认后端服务真的在监听那个端口。曾经有一次我排查了一个小时最后发现是Flask应用跑在虚拟机里而前端跑在宿主机上端口映射忘了加。5.3 数据库查询慢与联表查询的坑人事系统的数据量在几十万条以内时查询慢的原因绝大多数不是数据量大而是没建索引或者查询语句写得不好。三张表关联查询时用错了JOIN类型就会造成笛卡尔积似的性能灾难。几个优化的基本思路员工表的emp_no、身份证号字段建唯一索引部门表的name字段建普通索引考勤表的employee_id和work_date建联合索引(employee_id, work_date)。Django的ORM查询里留意n1问题查员工列表时如果循环里逐条查询部门名称就会产生大量SQL语句。用select_related(department)预先联表查出来就能避免。页面分页要稳妥不要一次性查几千条数据返给前端前端渲染也会卡顿。索引这个东西我一直觉得是管理系统的隐形功臣。建对了索引大量的接口都能在50毫秒内响应建错或漏建往往用户会反馈系统有点卡但又说不出具体卡在哪里。5.4 开发环境零散配置速查最后给一套我自己常用的配置清单供你参考配置项推荐值说明Python版本3.10Django和Flask新版本都支持Django版本4.x或5.x不要用2.x官方早已停止维护Flask版本3.x注意Flask 3和2的API差异Vue版本3.x Vite不要再开新项目用Vue 2UI组件库Element Plus和Vue 3搭配最顺数据库MySQL 8.0或SQLite学习阶段SQLite够用部署用MySQLIDEPyCharm专业版或社区版VS Code看个人习惯代码管理Git Gitee/GitHub哪怕一个人开发也要用Git管理这套配置是我从多个项目里跑出来的不能说是最优解但稳定性足够可靠。如果你有自己更熟悉的组合比如用FastAPI替代Flask也完全可以核心设计思路是一样的。最后说点真实的体感。这个项目做完我最深的收获不是某个技术点的突破而是理解了从需求到系统的翻译过程。人事管理系统的业务逻辑不算复杂但五脏俱全它逼着你去思考数据结构怎么组织、权限怎么隔离、数据怎么流转、接口怎么约定。如果你在面试时能把这个项目的设计思路讲明白从业务的痛点讲到技术选型的取舍再讲到具体实现里踩过的坑这比任何八股文都更有说服力。如果再让我做一遍我会先花更多时间画清楚接口文档把字段名、返回格式、错误码都定好再开工写代码。前后端联调吃的那些苦有一半是因为当时没说好造成的这句经验送给所有准备开工的朋友。
返回列表