
1. 项目定位这到底是管理后台还是个推荐引擎1.1 煤矿员工健康管理到底管什么做这类项目我习惯先问自己一个问题这个系统的使用者是谁他每天打开系统要干哪几件事煤矿行业的职业健康管理和普通企业的员工体检管理有本质区别。普通公司一年一次体检报告发下去就完事了煤矿行业有严格的职业健康监护要求员工要经历上岗前体检、在岗期间定期体检、离岗时职业健康检查三道关口。体检项目也比普通白领多出一大截肺功能检测、胸片、电测听、血常规、血压、心电图是家常便饭还要结合采煤、掘进、通风、机电、运输这些不同工种记录职业暴露史。如果只用Excel和纸质档案管理会出现几个很现实的问题体检报告七零八落地堆在档案柜里某位矿工今年肺功能指标比去年下降了多少没人能一眼看出来不同工种的员工该重点关注哪些指标全靠老安全员的工作经验体检结束之后健康宣教和复查提醒基本靠群发通知针对性极差。这套系统要解决的就是把这些碎片数据变成结构化的健康档案再往前推一步——根据每个员工的历史数据和相似员工的健康规律给出个性化的健康建议和复查提醒。这也是题目里为什么强调协同过滤算法的原因。如果只是增删改查它和一个普通的信息管理系统没有区别算法才是这套系统的灵魂。1.2 协同过滤在健康场景的落点在哪协同过滤是推荐系统里最经典的算法核心思想就一句话物以类聚人以群分。放到电商里就是买了A商品的人也买了B商品放到短视频里就是和你兴趣相似的人都在看这个视频放到这套健康管理系统里就是和这位员工工种、年龄、工龄、体检指标都相似的一批员工他们对某些健康建议反馈很好那这位员工大概率也需要这条建议。举一个具体场景张师傅今年45岁在掘进队干了18年最近体检的肺功能指标FVC用力肺活量和FEV1第一秒用力呼气容积出现了轻度下降。系统在员工库里找到了一批和张师傅背景相似、肺功能变化趋势也相似的员工发现这些员工里绝大多数在高分的健康建议中包含了煤工尘肺早期干预方案呼吸功能训练操定期复查低剂量CT这几项。那么系统就可以把这几项建议推荐给张师傅而不是给他推一堆注意饮食清淡加强锻炼这种人人皆知的大路货。这就是协同过滤和传统规则推荐的本质区别。规则推荐是如果肺功能下降就推荐肺部检查靠人工配置条件协同过滤是从历史行为数据中自动发现规律哪怕你没有显式表达任何需求只要你和某群人足够相似系统就能把对那群人有效的健康方案捞出来。这种点到点的个性化能力才是算法在这里的真正价值。1.3 Django还是Flask二选一怎么定项目标题里同时出现了Django和Flask说明这是一个典型的二选一场景很多毕业设计题目就是这么写的。我在实际开发中选择的是Django理由很实在。Flask轻、灵活、自由度高适合做小接口、小工具三五张表的小系统用它写起来确实很舒服。但这个项目不是小工具它有员工管理、体检记录、健康档案、建议推荐、后台管理、权限控制、接口文档再加上协同过滤模块涉及的表和数据关系相当多。这时候Django的优势就体现出来了自带ORM映射不用手写SQL自带Admin后台开发调试阶段可以直接在后台维护数据有Django REST Framework这一整套生态序列化、视图集、路由、分页、权限认证都是现成的。还有一个经常被忽略的点Django的ORM在做跨表查询和聚合分析时写起来非常顺手。比如后面我们要算相似员工体检指标距离需要跨员工表、体检表、建议表做关联计算Django的QuerySet可以直接链式调用代码可读性比手写SQL高一个档次。项目是给人看的也是给人维护的代码整洁非常重要。PyCharm在整个开发流程里承担的是工作台角色。我习惯用PyCharm创建虚拟环境、管理解释器、打断点调试Django接口这些内置功能比命令行效率高很多。需要注意的是PyCharm社区版虽然免费但Django专业支持比如内置的manage.py工具窗口、模板调试在专业版里才完整学生用教育邮箱申请专业版免费授权这个事可以提前办好。2. 协同过滤算法拆解与健康场景建模2.1 算法原理相似度计算与Top-N推荐协同过滤在实现层面分两条路线基于用户的协同过滤UserCF和基于物品的协同过滤ItemCF。UserCF的思路是找相似的人把相似人喜欢的东西推荐给你ItemCF的思路是找相似的物品根据你历史上喜欢过的物品去推荐类似的物品。在健康管理这个场景里我建议以UserCF为主。原因很朴素员工和员工之间的相似度更容易解释也比较贴近职业健康管理的业务逻辑。同样是45岁、掘进工种、15年工龄、肺功能轻度下降的两个员工他们的健康风险模型高度接近这很好理解。而ItemCF在健康建议这个物品维度上建议项数量少、关联性弱做出来的效果远不如用户维度明显。相似度计算最常用的是余弦相似度。我把每个员工看成一个向量向量的每个维度是和某条健康建议的交互得分。两个员工向量的夹角越小说明他们的健康偏好和风险画像越一致。余弦相似度公式长这样similarity(u, v) (u · v) / (|u| × |v|)具体到代码层面我推荐直接用pandas配合scikit-learn的cosine_similarity函数。数据预处理用pivot_table把评分表转成矩阵缺失位置补0然后一次性算出所有员工之间的相似度矩阵。Top-N推荐的逻辑也不复杂找出和目标员工最相似的K个员工把这K个员工评分最高的健康建议汇总排除掉目标员工已经交互过的建议剩下分数最高的N条就是推荐结果。2.2 评分数据从哪来没有评分矩阵怎么办协同过滤的命根子就是评分矩阵但健康管理系统不是电商平台员工通常不会主动给健康建议打分。这是整个项目建模时最需要动脑筋的地方。我的做法是双通道构造成分。第一通道是显式反馈员工在系统里可以对收到的健康建议点有用已有帮助不适用这些操作直接映射成5分制或3分制的评分。第二通道是隐式反馈系统根据员工的健康行为自动计算得分。举个具体例子如果一位员工被推荐了每月复查肺功能这条建议他后续确实去做了复查系统自动给这条建议记4分如果复查结果显示指标稳定再加1分。又比如某位员工持续关注了职业噪声防护相关内容系统在后台给这条建议的隐式评分累加。如果一开始没有历史数据评分矩阵会非常稀疏这是一个绕不开的冷启动问题。我的处理方案很直接在系统运行前期用基于规则的兜底推荐顶上去。比如肺功能异常就推荐呼吸相关建议听力异常就推荐听力保护建议同时积极引导员工使用健康建议反馈功能。等评分数据积累到一定量级再逐步切换到协同过滤主导的模式。这套冷启动用规则、热启动用算法的策略在真实项目里非常实用也避免了算法推荐一片空白导致系统看起来像没开发完的尴尬。2.3 协同过滤核心代码实现算法部分我单独放在一个recommend.py里不和其他业务代码混在一起。这样做的好处是清晰业务层调用算法模块算法替换不影响整体架构。import pandas as pd import numpy as np from sklearn.metrics.pairwise import cosine_similarity def build_score_matrix(ratings_df): 将评分记录转为 员工-建议 评分矩阵缺失值补0 matrix ratings_df.pivot_table( indexemployee_id, columnsadvice_id, valuesscore, aggfuncmean ).fillna(0) return matrix def top_k_similar_users(ratings_df, target_user, k5): 计算余弦相似度矩阵返回与目标用户最相似的k个用户 matrix build_score_matrix(ratings_df) sim_matrix cosine_similarity(matrix) sim_df pd.DataFrame(sim_matrix, indexmatrix.index, columnsmatrix.index) if target_user not in sim_df.index: return [] sim_scores sim_df[target_user].sort_values(ascendingFalse) # 去掉自己取前k个 similar_users sim_scores.iloc[1:k 1].index.tolist() return similar_users def recommend_by_user_cf(ratings_df, target_user, top_n5): 基于用户协同过滤的核心推荐逻辑 matrix build_score_matrix(ratings_df) if target_user not in matrix.index: return [] similar_users top_k_similar_users(ratings_df, target_user) if not similar_users: return [] target_rated_items set(matrix.columns[matrix.loc[target_user] 0]) score_dict {} for user in similar_users: row matrix.loc[user] # 只取相似用户评分过的项 rated_items row[row 0] for advice_id, score in rated_items.items(): if advice_id in target_rated_items: continue score_dict[advice_id] score_dict.get(advice_id, 0) score if not score_dict: return [] sorted_items sorted(score_dict.items(), keylambda x: x[1], reverseTrue) return [item[0] for item in sorted_items[:top_n]]这里我把推荐分数简单做成了相似用户评分累加实际工程里还可以按相似度加权。比如pred_score sum(sim(user, v) * r_v_i for v in similar_users) / sum(sim(user, v) for v in similar_users)加权公式能体现相似度的影响效果更好。不过要注意分母为零的边界情况我在代码里加了判空处理避免运行时崩溃。2.4 健康场景建模时容易踩的坑第一个坑是直接把评分矩阵设为原始指标值。你想血压、血糖、肺功能这些指标量纲完全不一样有的三位数有的一个小数直接混在一个矩阵里算相似度结果会完全被量纲大的指标带偏。正确做法是做标准化或者只使用显式的评分数据不要把原始体检指标直接塞进协同过滤的评分矩阵。体检指标应该作为员工背景属性用于筛选相似人群或者单独做风险评估模型而不是和推荐评分混在一起。第二个坑是相似度计算时矩阵太稠密。我见过有人把全0补位的评分矩阵直接丢进去跑余弦相似度算出来所有用户相似度都很高推荐结果完全没有区分度。因为0和0的夹角在余弦公式里会被当成相似。解决思路一是只保留有评分的维度参与计算二是评分数据特别稀疏时改用调整后的余弦相似度三是干脆切换到ItemCF从建议项之间的共现关系入手。第三个坑是忽视推荐的解释性。健康管理是严肃场景系统给员工推一条建议戒烟和一条建议肺功能深度复查背后的理由必须能说清楚。我的做法是保存推荐理由字段比如相似员工中有85%查出了早期呼吸道异常你们岗位近三年尘肺检出率为2.3%这样员工看到推荐不会觉得是乱弹琴。3. Django后端与Vue前端的工程落地3.1 Django项目结构与数据模型设计Django项目我习惯按业务模块拆应用不太喜欢全部塞在一个app里。这个系统我拆成了几个应用users负责登录认证employee管理员工基础信息health管理体检记录和健康档案recommend负责协同过滤推荐。核心数据模型用一个例子就能说明白。员工表、体检表、建议表、评分表是按逻辑分层设计的from django.db import models from django.contrib.auth.models import User class Employee(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE, nullTrue, blankTrue) emp_no models.CharField(工号, max_length20, uniqueTrue) name models.CharField(姓名, max_length50) age models.IntegerField(年龄) gender models.CharField(性别, max_length10, choices[(M, 男), (F, 女)]) job_type models.CharField(工种, max_length50) work_years models.IntegerField(工龄) department models.CharField(部门, max_length100) phone models.CharField(联系电话, max_length20, blankTrue) class HealthRecord(models.Model): employee models.ForeignKey(Employee, on_deletemodels.CASCADE, related_namehealth_records) check_date models.DateField(体检日期) systolic models.IntegerField(收缩压) diastolic models.IntegerField(舒张压) fvc models.FloatField(FVC用力肺活量) fev1 models.FloatField(FEV1一秒量) hearing_left models.IntegerField(左耳听力) hearing_right models.IntegerField(右耳听力) blood_sugar models.FloatField(空腹血糖) chest_xray models.CharField(胸片结论, max_length200, blankTrue) summary models.TextField(健康小结, blankTrue) class HealthAdvice(models.Model): title models.CharField(建议标题, max_length200) content models.TextField(建议内容) advice_type models.CharField(建议类型, max_length50, choices[(diet, 饮食), (exercise, 运动), (check, 复查), (protect, 防护)]) target_condition models.CharField(适用情况, max_length200, blankTrue) created_at models.DateTimeField(auto_now_addTrue) class Rating(models.Model): employee models.ForeignKey(Employee, on_deletemodels.CASCADE) advice models.ForeignKey(HealthAdvice, on_deletemodels.CASCADE) score models.FloatField(评分) created_at models.DateTimeField(auto_now_addTrue) class Meta: unique_together (employee, advice)设计要点有两个。一是不要把体检指标全塞到一个超长字段甚至TextJSON里做成独立的HealthRecord表方便后续做趋势分析和指标筛选。二是评分表和员工、建议都做成外键保证数据完整性同时用unique_together防止一个人对同一条建议重复评分。建完模型之后makemigrations和migrate两步走表结构就落库了。3.2 RESTful API与JWT认证前端Vue完全走接口取数后端必须有规范的API。Django REST FrameworkDRF在这一步是主力军。我写了一个视图集把推荐接口和基础数据的增删改查全部暴露成REST风格接口from rest_framework import viewsets, permissions from rest_framework.decorators import action from rest_framework.response import Response from .models import Employee, HealthRecord, HealthAdvice, Rating from .serializers import EmployeeSerializer, HealthRecordSerializer, HealthAdviceSerializer, RatingSerializer from .recommend import recommend_by_user_cf class EmployeeViewSet(viewsets.ModelViewSet): queryset Employee.objects.all() serializer_class EmployeeSerializer permission_classes [permissions.IsAuthenticated] class RecommendViewSet(viewsets.ViewSet): permission_classes [permissions.IsAuthenticated] def list(self, request): employee Employee.objects.filter(userrequest.user).first() if not employee: return Response({error: 请先完善员工档案}, status400) ratings_df get_ratings_dataframe() recommended_ids recommend_by_user_cf(ratings_df, employee.id, top_n8) advices HealthAdvice.objects.filter(id__inrecommended_ids) # 保留推荐顺序 advice_map {a.id: a for a in advices} ordered [advice_map[i] for i in recommended_ids if i in advice_map] serializer HealthAdviceSerializer(ordered, manyTrue) return Response(serializer.data)认证方案我用的是JWT装djangorestframework-simplejwt这个库。配置好之后登录接口返回access token和refresh token前端把token存到localStorage里后续请求在请求头加Authorization: Bearer 。这样前后端彻底分离Vue这边拿到token之后用一个axios请求拦截器统一处理比Session模式舒服很多。3.3 Vue3前端页面与交互设计前端我推荐Vue3加Vite加Element Plus的组合这套组合现在生态最活跃Element Plus的表格、表单、弹窗组件做管理端页面非常快。登录页、仪表盘、员工管理、健康档案、智能推荐五个核心页面按Tab菜单组织。智能推荐页面是项目的头号亮点我把它做成左右两栏布局。左栏展示推荐的健康建议卡片每张卡片带一下推荐理由右栏展示当前员工的健康指标雷达图用ECharts画。雷达图的维度是血压、肺功能、听力、血糖这些关键指标把当前员工和同岗位平均线叠在一起一眼就能看出客户的健康短板。这个页面是答辩演示和项目展示的最佳截图位值得多花点心思打磨。前端页面调用接口我统一封装在api.js里import axios from axios import { ElMessage } from element-plus import router from ../router const service axios.create({ baseURL: /api, timeout: 15000 }) service.interceptors.request.use(config { const token localStorage.getItem(access_token) if (token) { config.headers.Authorization Bearer ${token} } return config }) service.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { ElMessage.error(登录已过期请重新登录) router.push(/login) } else { ElMessage.error(error.response?.data?.error || 请求失败) } return Promise.reject(error) } ) export function getRecommendations() { return service.get(/recommend/) }3.4 前后端联调跨域、代理与打包部署前后端分离开发最烦的就是跨域。前端跑在8080端口后端跑在8000端口浏览器会因为同源策略拦截请求。开发环境的解法有两个一是后端装django-cors-headers允许所有来源访问简单粗暴但只适合测试二是在前端开启Vite代理让前端把/api的请求代理到后端。我建议用第二种因为代理方案最终部署到生产环境时思路一致。在vite.config.js里这样配置export default defineConfig({ server: { port: 8080, proxy: { /api: { target: http://127.0.0.1:8000, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } })这样前端请求/api/recommend/实际会转发到后端/recommend/浏览器侧不产生跨域问题。到了生产环境前端npm run build之后生成dist目录后端Django或者Nginx托管静态文件再用Nginx配置反向代理给Django接口整个链路就打通了。4. 完整实操流程从空环境到系统跑通4.1 环境准备版本选对少走一半弯路这个项目的环境版本组合我测试下来最稳定的组合是Python 3.10、Django 4.2、djangorestframework 3.14、Vue 3.4、Vite 5、Element Plus 2.x。Python不要用最新的3.12或3.13虽然新版本功能多但很多第三方依赖跟不上尤其是mysqlclient这种带C扩展的包在新版本上编译容易报错。Django 4.2是LTS版本维护周期长踩坑资料也全。PyCharm这边创建项目时选择虚拟环境虚拟环境名称我建议用venv取名解释器选择刚才装的Python 3.10。虚拟环境的意义不用多说项目依赖隔离不会和本机其他Python环境互相污染。Node.js版本选18或20的LTS版本装完Node自带npm工具。数据库我用MySQL 8.0字符集在创建数据库时指定utf8mb4避免中文乱码CREATE DATABASE coal_health CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;4.2 后端搭建七步走第一步安装依赖。Django项目需要装的核心包包括django、djangorestframework、django-cors-headers、djangorestframework-simplejwt、pymysql、pandas、scikit-learn。requirements.txt直接列好方便别人复现环境。第二步用django-admin startproject创建项目。我习惯把后端项目代码放在backend目录和前端frontend目录平级结构非常清晰。第三步创建应用。users、employee、health、recommend四个应用通过startapp命令逐个创建。第四步注册应用和第三方库。在settings.py的INSTALLED_APPS里把rest_framework、corsheaders、simplejwt和四个应用全部注册。配置数据库连接DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: coal_health, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4 } } }第五步配置CORS和认证。settings.py里配置ALLOWED_HOSTS、CORS_ORIGIN_ALLOW_ALL仅开发环境、REST_FRAMEWORK的默认认证类为JWT认证。第六步写模型、做迁移。按上一节的数据模型写好models.py执行makemigrations和migrate数据库表自动生成。接着创建超级用户用于后台登录python manage.py createsuperuser第七步启动开发服务器python manage.py runserver打开http://127.0.0.1:8000/admin能看到Django自带后台先把测试员工和体检数据维护进去。4.3 算法模块接入后端的正确姿势算法模块不要和视图函数揉在一起我把recommend.py放在recommend应用下视图只负责调用。接口返回数据时注意把推荐结果的顺序保留住千万别直接返回查询集然后让数据库按主键顺序排那样推荐排序就全乱了。另一个关键点是评分数据的获取。我在recommend.py里写了一个get_ratings_dataframe函数从Rating表里读取数据转成pandas的DataFrame。如果数据量比较大可以只在接口被调用时读取一次并做缓存。这套单机项目里数据量不大直接每次实时查也没问题。为了让演示效果更好建议在系统里先录入一批员工的评分数据。比如录入20个员工每个人对10到20条建议有评分评分范围1到5分。这样协同过滤算法有数据可用推荐接口能返回出像样的结果。我用脚本一次性生成模拟数据重要的一点是模拟数据要符合实际分布比如肺功能差的人对呼吸康复类建议评分高听力下降的人对护耳类建议评分高这样演示时推荐结果才有说服力。4.4 前端跑通流程第一步用Vite创建Vue3项目npm create vitelatest frontend -- --template vue cd frontend npm install第二步安装依赖element-plus、axios、vue-router、echarts。npm install element-plus axios vue-router4 echarts第三步搭路由和布局。路由配置登录页、仪表盘、员工管理、健康档案、智能推荐。主布局用Element Plus的Container布局左侧菜单右侧内容区。第四步写页面。员工管理页用el-table展示员工列表支持搜索和分页健康档案页用el-descriptions展示体检详情用ECharts画历史趋势折线图智能推荐页调用推荐接口渲染推荐卡片和健康雷达图。第五步设置代理、启动前端npm run dev打开http://localhost:8080登录后就能在智能推荐页面看到算法返回的推荐结果。4.5 整体联调与效果验证前后端都跑起来之后联调的重点验证三个链路登录认证链路输入用户名密码能拿到token并在后续请求中带上数据读写链路员工管理、健康档案的增删改查都能正常操作算法推荐链路推荐接口能返回有业务含义的推荐结果而不是空数组或者随机数据。推荐链路我习惯用一个简单方法验证找两个被系统判断为相似度很高的员工在一个员工身上查看他会收到哪些推荐建议再对比另一个员工的推荐结果正常情况下两者应该有相当比例的重叠。如果完全没重叠说明相似度计算或者评分矩阵有问题要回到算法模块去检查。5. 常见问题与排查技巧实录5.1 环境依赖问题速查表这一类项目初学者踩坑最多的地方就是环境我把常见的几个问题整理成了一张表问题现象根本原因解决方案pip install mysqlclient报错缺少C编译环境改用pymysql在项目__init__.py里做兼容处理Django启动报No module named MySQLdb没有适配MySQL驱动安装pymysql并执行pymysql.install_as_MySQLdb()pandas或numpy装不上Python版本太高或pip版本太旧降级到Python 3.10升级pip后重装前端npm install卡住默认源访问慢配置淘宝镜像npm config set registryVue运行报Node版本过低Node版本太旧升级Node到18 LTS以上pymysql兼容处理这段代码我放在Django项目的__init__.py里import pymysql pymysql.install_as_MySQLdb()这样Django会认为底层使用的是MySQLdb实际上是pymysql在提供驱动规避了安装mysqlclient的编译难题。这个方案在生产环境也稳定我多个项目都在用。5.2 协同过滤效果不佳怎么排查推荐结果看起来不合理这是算法类项目的高频问题。我按排查顺序列几个方向。先看评分数据量。如果整个系统只有五六个员工的评分算法必然不稳定。数据量不够的解决办法是多录数据或者用隐式反馈自动填充部分评分。再看相似员工质量。算法选出来的相似员工如果和当前员工工种年龄差异巨大说明相似度计算有问题。这里可以打印出相似度矩阵人工检查一下是不是所有员工之间的相似度值都差不多高如果是回头检查矩阵稀疏度考虑用调整后的余弦相似度。最后看兜底逻辑。冷启动阶段推荐为空或者结果差是正常的要保证评分数据不足时有规则推荐兜底系统体验才完整。5.3 前后端联调与部署问题Vue开发时接口能通打包上线后就404这事我已经见过无数回了。排查方向有两点。第一打包后接口请求路径是否正确。如果接口路径写死成了/api/recommend/而线上Nginx没有把/api转发给Django一定会404。第二Vue路由用了history模式刷新页面时Nginx不会自动回退到index.html需要在Nginx配置try_fileslocation / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8000/; proxy_set_header Host $host; }这个配置同时解决了前端history路由和后端接口代理两个问题。如果你的项目用了hash模式路由那部分就不用管但接口代理还是要配好。6. 从项目到作品的进阶建议如果你做这套系统的目的不只是交作业而是希望它能在简历里成为一个亮点项目我给你三个建议。第一把算法效果评估做成一个模块。不要只说推荐了什么东西把数据拉出来算一算推荐建议的点击率、采纳率、员工满意度评分有没有提升。哪怕只是做一个简单的统计图表也能向面试官展示你有数据思维。第二把健康档案的趋势分析做深一点。协同过滤负责推荐该做什么趋势分析负责反映身体在怎么变化。用ECharts把员工的血压、肺功能、听力指标按时间画成折线图配合异常阈值标记这套东西放在健康管理场景里非常有说服力。第三别忘了把隐私安全放进设计里。健康数据属于敏感个人数据可以在系统里设计角色权限比如员工只能看自己的档案安全员和部门负责人才有权限查看整个部门或全矿的统计数据。不用做得很复杂权限模型清晰就能体现工程素养。我在实际开发中还特别注意了一个细节模拟数据尽量真实。员工名字要像人名工号要有规律体检指标要符合人群分布评分数据要符合业务逻辑。很多项目演示效果不佳不是功能没做出来而是演示数据太假一眼看过去就是测试数据说服力大打折扣。这套系统我建议你花半小时把演示数据造到位效果立刻不一样。最后分享一个我做这类管理系统的心得算法再花哨最终也要服务于看一眼就知道下一步该干什么这个目标。员工打开系统能看到自己的健康趋势和针对性建议安全管理员打开系统能看到全矿的健康风险分布和重点人群这才是煤矿员工健康管理系统真正该发挥的价值。你自己动手把这条路完整走一遍收获会远超一个普通的毕业设计。