336-基于Python的肺癌数据可视化分析预测系统

肺癌数据可视化分析预测系统

Lung Cancer Intelligence Atlas --- 基于 Django + Vue 3 的双语数据可视化分析与机器学习预测平台
项目代号 : CancerAtlas | 版本 : v1.0 | 设计周期: 2024-2026


目录

  1. 项目概述
  2. 系统架构
  3. 技术栈详解
  4. 目录结构
  5. 数据库设计
  6. [ER 实体关系图](#ER 实体关系图)
  7. 数据流程图
  8. [API 接口文档](#API 接口文档)
  9. 前端架构
  10. 机器学习模块
  11. 可视化方案
  12. 存储设计
  13. 安全设计
  14. 部署架构
  15. 快速启动
  16. [Django Admin 使用指南](#Django Admin 使用指南)
  17. 环境变量说明

1. 项目概述

1.1 背景与目标

本系统面向课程设计答辩场景,围绕 50,000 条肺癌患者脱敏数据,实现以下核心目标:

目标 描述
数据管理 支持 CSV 批量导入、数据清洗、患者记录增删改查
多维分析 提供 14 种 ECharts 可视化图表,支持双语言切换
机器学习 支持模型训练、评估、激活与在线实时预测
风险预测 基于 9 项临床特征输出肺癌风险概率与干预建议
个性化推荐 基于欧氏距离匹配相似病例,提供针对性干预方案

1.2 系统角色

复制代码
┌─────────────────────────────────────────────────────────────┐
│                        系统用户                              │
├──────────────────────────┬──────────────────────────────────┤
│     普通用户 (User)       │        管理员 (Admin)              │
├──────────────────────────┼──────────────────────────────────┤
│ • 查看数据可视化分析       │ • 管理患者数据(增删改查)           │
│ • 在线肺癌风险预测        │ • 触发模型训练与评估                │
│ • 查看预测历史与报告      │ • 管理预测模型(激活/删除)           │
│ • 收藏预测报告/相似病例   │ • 管理干预建议模板                  │
│ • 个人中心(头像/密码)   │ • 系统状态监控                     │
│ • 注册/登录              │ • Django Admin 数据后台             │
└──────────────────────────┴──────────────────────────────────┘

1.3 数据规格

指标
患者数据总量 50,000 条
数据来源 脱敏模拟数据 (data/lung_cancer_dataset.csv)
特征维度 9 项临床特征 + 1 项目标变量
阳性率 ~68.7%
训练样本 45,000 条
测试样本 5,000 条









2. 系统架构

2.1 整体架构图

复制代码
                            ┌─────────────────────────────────────┐
                            │           用户终端                    │
                            │  ┌───────────────────────────────┐   │
                            │  │     Web Browser (Chrome)       │   │
                            │  │  ┌─────────────────────────┐ │   │
                            │  │  │   Vue 3 SPA (Port 5173)  │ │   │
                            │  │  │  • Router (路由)         │ │   │
                            │  │  │  • Pinia (状态管理)       │ │   │
                            │  │  │  • ECharts (可视化)       │ │   │
                            │  │  │  • Axios (HTTP客户端)    │ │   │
                            │  │  └─────────────────────────┘ │   │
                            │  └───────────────────────────────┘   │
                            └─────────────────┬───────────────────┘
                                              │ HTTPS / HTTP
                                              │ REST API (JWT)
┌─────────────────────────────────────────────▼───────────────────┐
│                      负载均衡层 (Nginx)                          │
│                   (可选,生产环境部署)                           │
└─────────────────────────────────────────────┬───────────────────┘
                                              │
┌─────────────────────────────────────────────▼───────────────────┐
│                      应用服务层                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              Django 后端服务 (Port 8000)                  │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │    │
│  │  │  DRF     │ │ SimpleJWT│ │ SimpleUI │ │ scikit   │   │    │
│  │  │ (API层)  │ │ (认证)   │ │ (后台)   │ │ (机器学习)│   │    │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘   │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │    │
│  │  │ accounts │ │patients  │ │analytics │ │prediction│   │    │
│  │  │ (用户)   │ │(患者)   │ │(分析)   │ │(预测)   │   │    │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘   │    │
│  │                      apps/                              │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────┬───────────────────┘
                                              │
┌─────────────────────────────────────────────▼───────────────────┐
│                      数据存储层                                  │
│  ┌──────────────────┐      ┌──────────────────────────────┐    │
│  │   MySQL 8.x       │      │   文件存储 (本地)              │    │
│  │  design_336_     │      │  ┌────────────────────────┐  │    │
│  │  canner          │      │  │ artifacts/ (模型文件)    │  │    │
│  │                   │      │  │ media/avatars/ (头像)   │  │    │
│  │  • UserProfile    │      │  │ staticfiles/ (静态资源)  │  │    │
│  │  • PatientRecord  │      │  └────────────────────────┘  │    │
│  │  • ModelArtifact  │      │                              │    │
│  │  • PredictionRecord│     │                              │    │
│  │  • Recommendation  │      │                              │    │
│  │  • FavoriteItem    │      │                              │    │
│  └──────────────────┘      └──────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

2.2 前端请求处理流程

复制代码
用户操作 (点击按钮)
       │
       ▼
┌──────────────────┐
│  Vue Router       │ ← 路由匹配 (PublicLayout / AdminLayout)
│  (路由守卫)        │ ← 路由拦截,检查登录状态 & 角色权限
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  Pinia Store     │ ← auth.ts 存储 JWT token 和用户信息
│  (状态管理)        │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  Axios 拦截器     │ ← 请求拦截器:附加 Authorization header
│  (HTTP客户端)     │ ← 响应拦截器:处理 401 重定向、错误提示
└────────┬─────────┘
         │
         │ 携带 JWT Bearer Token
         ▼
┌─────────────────────────────────────────┐
│           Django REST Framework          │
│  ┌─────────────────────────────────────┐ │
│  │  authentication.py (JWT 认证)        │ │
│  │  permission.py (权限判定)            │ │
│  │  throttling.py (限流控制)            │ │
│  └─────────────────────────────────────┘ │
│                     │                     │
│                     ▼                     │
│  ┌─────────────────────────────────────┐ │
│  │         ViewSet / APIView            │ │
│  │  (业务逻辑处理)                       │ │
│  └─────────────────────────────────────┘ │
│                     │                     │
│                     ▼                     │
│  ┌─────────────────────────────────────┐ │
│  │         Serializers (序列化)         │ │
│  │  (数据验证 / 格式化输出)              │ │
│  └─────────────────────────────────────┘ │
└──────────────────────┬────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────┐
│              MySQL Database              │
│         (CRUD 操作 + 复杂查询)            │
└─────────────────────────────────────────┘

3. 技术栈详解

3.1 后端技术栈

层级 技术选型 版本 说明
框架 Django 4.2.29 Python Web 框架
REST API DRF 3.16.1 Django REST Framework
认证 SimpleJWT 5.5.1 JWT Token 认证,支持 refresh token 黑名单
后台主题 django-simpleui 2026.1.13 美化 Django Admin 界面
数据库 MySQL + PyMySQL 8.x / 1.1.1 关系型数据库 + Python 驱动
机器学习 scikit-learn 1.6.1 HistGradientBoostingClassifier
模型持久化 joblib 1.5.3 模型序列化和反序列化
图片处理 Pillow ≥10.0 头像上传处理
环境变量 python-dotenv 1.0.1 .env 文件加载
跨域 django-cors-headers 4.9.0 CORS 头管理

3.2 前端技术栈

层级 技术选型 版本 说明
框架 Vue 3 3.x Composition API
语言 TypeScript 5.x 类型安全
构建工具 Vite 5.x 快速冷启动
路由 Vue Router 4.x SPA 路由管理
状态管理 Pinia 2.x 响应式状态管理
图表 ECharts 5.x 14 种可视化图表
HTTP Axios 1.x HTTP 请求拦截
样式 SCSS - CSS 预处理器

3.3 技术选型理由

Django REST Framework
  • 与 Django 无缝集成,ORM 支持完善
  • 强大的 Serializer 机制,支持嵌套和验证
  • 完善的认证、权限、限流体系
SimpleJWT
  • 无状态认证,适合分布式部署
  • Access Token + Refresh Token 双令牌机制
  • 支持 Token 黑名单,实现强制登出
HistGradientBoostingClassifier
  • 相比 RandomForest 有更高的准确率
  • 支持缺失值自动处理
  • 训练速度快,适合中大规模数据集
Vue 3 + Composition API
  • <script setup> 语法糖,代码更简洁
  • 更好的 TypeScript 支持
  • 更小的包体积和更快的渲染速度
ECharts 5
  • 丰富的图表类型,支持个性化定制
  • 大数据量下的性能优化(内置数据采样)
  • 响应式设计,适配不同屏幕

4. 目录结构

复制代码
cancer/                              # 项目根目录
│
├── backend/                         # Django 后端项目
│   ├── apps/                        # 业务应用模块
│   │   ├── accounts/                # 用户账户模块
│   │   │   ├── admin.py            # Admin 配置(简化,unregister移至apps.py)
│   │   │   ├── apps.py             # App 配置 + ready()隐藏多余Admin模型
│   │   │   ├── models.py           # UserProfile 模型
│   │   │   ├── serializers.py      # DRF 序列化器(登录/注册/头像/资料)
│   │   │   ├── urls.py             # 路由:/auth/*
│   │   │   ├── views.py            # API视图(登录/注册/头像/改密/资料)
│   │   │   └── migrations/
│   │   ├── patients/               # 患者数据模块
│   │   │   ├── admin.py            # 患者记录Admin(11字段+过滤器+搜索)
│   │   │   ├── apps.py
│   │   │   ├── constants.py        # CHOICES常量(性别/暴露/饮酒等)
│   │   │   ├── models.py          # PatientRecord模型(13字段+verbose_name)
│   │   │   ├── serializers.py
│   │   │   ├── urls.py
│   │   │   ├── utils.py           # 工具函数
│   │   │   ├── views.py           # 患者记录视图(分页+过滤)
│   │   │   └── migrations/
│   │   ├── analytics/              # 数据分析模块
│   │   │   ├── admin.py
│   │   │   ├── apps.py
│   │   │   ├── models.py          # 暂无持久化模型(纯计算密集型)
│   │   │   ├── urls.py
│   │   │   └── views.py           # Overview/Distribution/Advanced API
│   │   ├── prediction/             # 预测管理模块
│   │   │   ├── admin.py           # 模型/预测记录/推荐模板Admin
│   │   │   ├── apps.py
│   │   │   ├── models.py          # ModelArtifact/PredictionRecord/RecommendationTemplate
│   │   │   ├── serializers.py
│   │   │   ├── urls.py
│   │   │   ├── views.py           # 训练/预测/历史视图
│   │   │   ├── services.py       # 模型推理服务(加载/预测/评估)
│   │   │   ├── recommendations.py  # 干预建议生成逻辑
│   │   │   ├── prediction_urls.py # 预测相关路由
│   │   │   ├── model_urls.py     # 模型相关路由
│   │   │   └── migrations/
│   │   └── engagement/             # 收藏互动模块
│   │       ├── admin.py
│   │       ├── apps.py
│   │       ├── models.py          # FavoriteItem模型
│   │       ├── serializers.py
│   │       ├── urls.py
│   │       ├── views.py
│   │       └── migrations/
│   ├── config/                     # 项目配置目录
│   │   ├── settings.py            # Django核心配置(含simpleui模板路径)
│   │   ├── urls.py                # 根路由配置
│   │   ├── wsgi.py
│   │   └── asgi.py
│   ├── artifacts/                 # 模型文件存储(.pkl)
│   │   └── models/               # 训练生成的模型文件
│   ├── media/                     # 用户上传文件
│   │   └── avatars/              # 头像存储目录
│   ├── staticfiles/               # collectstatic收集的静态文件
│   ├── manage.py
│   └── requirements.txt
│
├── frontend/                       # Vue 3 前端项目
│   ├── src/
│   │   ├── App.vue               # 根组件
│   │   ├── main.ts              # 应用入口(Pinia/Router初始化)
│   │   ├── router/
│   │   │   └── index.ts        # 路由配置(PublicLayout/AdminLayout)
│   │   ├── stores/
│   │   │   └── auth.ts         # Pinia认证状态管理
│   │   ├── services/
│   │   │   └── api.ts         # Axios实例(拦截器/JWT)
│   │   ├── types/
│   │   │   └── api.ts        # TypeScript接口定义
│   │   ├── views/
│   │   │   ├── HomeView.vue       # 首页
│   │   │   ├── AnalysisView.vue  # 数据分析页(14种图表)
│   │   │   ├── PredictionView.vue # 在线预测页
│   │   │   ├── FavoritesView.vue  # 收藏夹页
│   │   │   ├── ProfileView.vue    # 个人中心
│   │   │   ├── LoginView.vue      # 登录页
│   │   │   ├── RegisterView.vue   # 注册页
│   │   │   ├── AdminDashboardView.vue # 后台概览页
│   │   │   └── layouts/
│   │   │       ├── PublicLayout.vue  # 前台公共布局(含顶部导航栏+图标)
│   │   │       └── AdminLayout.vue   # 后台公共布局(含顶部导航栏+图标)
│   │   ├── components/
│   │   │   ├── MetricCard.vue     # 指标卡片组件
│   │   │   ├── ChartPanel.vue     # 图表面板组件
│   │   │   └── FavoriteButton.vue # 收藏按钮组件
│   │   ├── styles/
│   │   │   └── main.scss        # 全局SCSS样式
│   │   └── utils/
│   │       └── format.ts       # 格式化工具函数
│   ├── public/
│   ├── index.html
│   ├── vite.config.ts
│   ├── package.json
│   ├── tsconfig.json
│   └── README.md
│
├── scripts/
│   └── bootstrap_mysql.sh      # 数据库初始化脚本
│
├── data/
│   └── lung_cancer_dataset.csv  # 50,000条患者脱敏数据
│
├── .env.example                 # 环境变量示例
├── .gitignore
└── README.md

5. 数据库设计

5.1 数据库信息

sql 复制代码
CREATE DATABASE design_336_canner
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

5.2 模型详表

5.2.1 accounts.UserProfile(用户画像)
字段名 类型 约束 verbose_name 说明
user OneToOneField FK → auth.User, on_delete=CASCADE 关联用户 Django内置User的一对一扩展
role CharField max_length=20, choices=role_choices 角色 admin / user
display_name CharField max_length=150 显示名称 个人中心展示名
bio TextField blank=True, default='' 个人简介 可选的个人描述
avatar ImageField upload_to='avatars/', blank=True 头像 上传至 media/avatars/
avatar_color CharField max_length=7, default='#4A5568' 头像颜色 SVG头像备用颜色
created_at DateTimeField auto_now_add=True 创建时间 注册时间戳
updated_at DateTimeField auto_now=True 更新时间 最后修改时间

索引: user (Unique)

5.2.2 patients.PatientRecord(患者记录)
字段名 类型 约束 verbose_name 说明
id AutoField primary_key=True ID 主键
patient_id PositiveIntegerField unique=True 患者ID 外部唯一标识
age PositiveIntegerField validators=[MinValueValidator(0), MaxValueValidator(120)] 年龄 0-120岁
gender CharField max_length=10, choices=GenderChoices 性别 Male / Female
pack_years FloatField validators=[MinValueValidator(0)] 吸烟包年 吸烟年数×每日包数
radon_exposure CharField max_length=20, choices=ExposureChoices 氡暴露等级 Low / Medium / High
asbestos_exposure CharField max_length=10, choices=BooleanChoices 石棉暴露 Yes / No
secondhand_smoke_exposure CharField max_length=10, choices=BooleanChoices 二手烟暴露 Yes / No
copd_diagnosis CharField max_length=10, choices=BooleanChoices 慢阻肺诊断 Yes / No
alcohol_consumption CharField max_length=20, choices=AlcoholChoices 饮酒情况 Non-drinker / Occasional / Moderate / Heavy
family_history CharField max_length=10, choices=BooleanChoices 肺癌家族史 Yes / No
lung_cancer CharField max_length=10, choices=LungCancerChoices 肺癌诊断 Yes / No
created_at DateTimeField auto_now_add=True 创建时间 导入时间戳

索引: patient_id (Unique), lung_cancer, gender, radon_exposure

5.2.3 prediction.ModelArtifact(模型训练产物)
字段名 类型 约束 verbose_name 说明
id AutoField primary_key=True ID 主键
name CharField max_length=200 模型名称 如 "Lung Cancer Risk Model"
algorithm CharField max_length=100 算法名称 如 hist_gradient_boosting
version CharField max_length=50, unique=True 版本号 语义化版本,如 "v1.0.0"
metrics JSONField default=dict 评估指标 {auc, recall, precision, f1}
confusion_matrix JSONField default=list 混淆矩阵 2x2矩阵 [[TN, FP], [FN, TP]]
feature_importance JSONField default=list 特征重要性 [{name, importance}]
feature_names JSONField default=list 特征名称 特征名列表
artifact_path CharField max_length=500 模型文件路径 指向 artifacts/models/*.pkl
training_rows PositiveIntegerField default=0 训练样本数 本次训练的样本总量
training_positive_rate FloatField default=0.0 训练阳性率 正例占比
is_active BooleanField default=False, db_index=True 是否激活 同一时间仅一个模型激活
trained_at DateTimeField auto_now_add=True 训练时间 训练完成时间戳

索引: is_active, version

5.2.4 prediction.PredictionRecord(预测记录)
字段名 类型 约束 verbose_name 说明
id AutoField primary_key=True ID 主键
user ForeignKey FK → auth.User, on_delete=SET_NULL, null=True 预测用户 可为空(匿名预测)
model ForeignKey FK → ModelArtifact, on_delete=SET_NULL, null=True 使用模型 预测时引用的模型版本
input_payload JSONField default=dict 输入特征 原始9项输入特征
probability FloatField validators=[MinValueValidator(0), MaxValueValidator(1)] 肺癌概率 0.0 ~ 1.0
risk_level CharField max_length=10, choices=RiskLevelChoices 风险等级 low / medium / high
predicted_label CharField max_length=10 预测标签 Yes / No
top_factors JSONField default=list 关键风险因子 [{factor, contribution}]
recommendations JSONField default=list 干预建议 [{code, title_zh, severity}]
similar_cases JSONField default=list 相似病例 [{patient_id, distance, lung_cancer}]
report_summary TextField blank=True 报告摘要 生成的自然语言摘要
created_at DateTimeField auto_now_add=True 预测时间 预测时间戳

索引: user, created_at, risk_level

5.2.5 prediction.RecommendationTemplate(干预建议模板)
字段名 类型 约束 verbose_name 说明
id AutoField primary_key=True ID 主键
code CharField max_length=50, unique=True 模板编码 如 "RADON_HIGH"
trigger_field CharField max_length=50 触发字段 匹配的模型输入字段名
trigger_value CharField max_length=100 触发值 字段的匹配值
title_zh CharField max_length=200 中文标题 如 "氡暴露风险"
title_en CharField max_length=200 英文标题 English title
description_zh TextField blank=True 中文描述 详细干预方案
description_en TextField blank=True 英文描述 English description
severity PositiveSmallIntegerField default=3 严重程度 1-5,5为最严重
is_active BooleanField default=True 是否启用 未启用则不触发

索引: code (Unique), trigger_field, is_active

5.2.6 engagement.FavoriteItem(收藏记录)
字段名 类型 约束 verbose_name 说明
id AutoField primary_key=True ID 主键
user ForeignKey FK → auth.User, on_delete=CASCADE 关联用户 收藏者
target_type CharField max_length=30, choices=FavoriteTypeChoices 收藏类型 prediction_report / similar_case
target_id CharField max_length=100 目标ID 被收藏项的ID
snapshot JSONField default=dict 收藏快照 收藏时刻的完整数据副本
created_at DateTimeField auto_now_add=True 收藏时间 收藏时间戳

索引: user + target_type + target_id (Unique), user, created_at


6. ER 实体关系图

6.1 完整 ER 图(ASCII 格式)

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                              ER Entity Relationship Diagram                   │
└─────────────────────────────────────────────────────────────────────────────┘

  ┌──────────────────────┐         ┌──────────────────────┐
  │     auth.User         │         │  auth.User (扩展)     │
  │  (Django 内置)        │         │                      │
  ├──────────────────────┤         ├──────────────────────┤
  │ □ id (PK)            │1    1   │ □ user (FK, U)       │
  │ □ username            │────────▶│ □ role               │
  │ □ password            │         │ □ display_name       │
  │ □ email               │         │ □ bio                │
  │ □ first_name          │         │ □ avatar             │
  │ □ last_name           │         │ □ avatar_color       │
  │ □ is_staff            │         │ □ created_at         │
  │ □ is_active           │         │ □ updated_at         │
  └──────────────────────┘         └──────────┬───────────┘
                                               │
                                               │ 1:1
                                               ▼
  ┌───────────────────────────────────────────────────────────────────────────┐
  │                          accounts 模块                                     │
  │  ┌─────────────────┐      ┌────────────────────┐     ┌─────────────────┐  │
  │  │   UserProfile   │      │   Django Auth      │     │  rest_framework │  │
  │  │                 │      │      User          │     │  .simplejwt     │  │
  │  ├─────────────────┤      └────────────────────┘     ├─────────────────┤  │
  │  │[U]user──────────┼──1:1──▶ (Django内置)           │ OutstandingToken│  │
  │  │  role           │                                 │ BlacklistedToken│  │
  │  │  display_name   │                                 │ TokenProxy      │  │
  │  │  bio            │                                 └─────────────────┘  │
  │  │  avatar         │                                                    │
  │  └─────────────────┘                                                    │
  └───────────────────────────────────────────────────────────────────────────┘

                                               │
                    ┌──────────────────────────┤
                    │                          │
                    ▼                          ▼
  ┌───────────────────────────────────────────────────────────────────────────┐
  │                          patients 模块                                    │
  │  ┌─────────────────────────────────────────────────────────────────┐      │
  │  │                      PatientRecord                                │      │
  │  ├─────────────────────────────────────────────────────────────────┤      │
  │  │[U] patient_id (U)    pack_years        secondhand_smoke_         │      │
  │  │    age               radon_exposure    exposure (Yes/No)        │      │
  │  │    gender (M/F)      asbestos_exposure copd_diagnosis           │      │
  │  │    family_history    alcohol_consumption lung_cancer            │      │
  │  └─────────────────────────────────────────────────────────────────┘      │
  └───────────────────────────────────────────────────────────────────────────┘
                    │
                    │ (提供特征数据用于ML训练和相似病例匹配)
                    ▼
  ┌───────────────────────────────────────────────────────────────────────────┐
  │                         prediction 模块                                    │
  │  ┌──────────────┐    ┌──────────────────┐    ┌────────────────────────┐   │
  │  │ModelArtifact  │    │PredictionRecord  │    │RecommendationTemplate │   │
  │  ├──────────────┤    ├──────────────────┤    ├────────────────────────┤   │
  │  │[U] version   │    │[FK] user ────────┼───▶│ auth.User (可空)      │   │
  │  │  name        │    │[FK] model ────────┼───▶│ ModelArtifact (可空)  │   │
  │  │  algorithm   │    │  probability      │    │[U] code               │   │
  │  │  metrics     │    │  risk_level       │    │  trigger_field        │   │
  │  │  confusion_   │    │  predicted_label  │    │  trigger_value        │   │
  │  │    matrix     │    │  top_factors      │    │  title_zh / title_en  │   │
  │  │  feature_     │    │  recommendations  │    │  description_zh/en   │   │
  │  │    importance │    │  similar_cases    │    │  severity (1-5)      │   │
  │  │  feature_     │    │  report_summary   │    │  is_active           │   │
  │  │    names      │    │  created_at       │    └────────────────────────┘   │
  │  │  artifact_path│    └──────────────────┘               ▲                  │
  │  │  training_rows│                                          │                  │
  │  │  is_active   │         ┌──────────────────┐             │ (按trigger匹配)   │
  │  │  trained_at  │         │Recommendation   │─────────────┘                  │
  │  └──────────────┘         │  Generator       │                               │
  │         ▲                 └──────────────────┘                               │
  │         │                                                                   │
  │         │ (加载 .pkl)                                                        │
  └─────────┼───────────────────────────────────────────────────────────────────┘
            │
  ┌─────────▼─────────────────────────────────────────────────────────────────┐
  │                          engagement 模块                                     │
  │  ┌─────────────────────────────────────────────────────────────────────┐    │
  │  │                        FavoriteItem                                  │    │
  │  ├─────────────────────────────────────────────────────────────────────┤    │
  │  │[FK] user ───────────────▶ auth.User                                 │    │
  │  │  target_type (预测报告/相似病例)                                        │    │
  │  │[U] target_id                                                           │    │
  │  │  snapshot (JSON, 收藏时数据快照)                                        │    │
  │  │  created_at                                                            │    │
  │  └─────────────────────────────────────────────────────────────────────┘    │
  └─────────────────────────────────────────────────────────────────────────────┘

6.2 实体关系说明

关系 类型 说明
User ↔ UserProfile 1:1 Django User 的个人信息扩展
User → PredictionRecord 1:N 用户拥有多条预测历史
ModelArtifact → PredictionRecord 1:N 同一模型可产生多条预测
PredictionRecord → RecommendationTemplate N:1 (触发匹配) 根据 top_factors 触发多个模板
User → FavoriteItem 1:N 用户可收藏多个项目
PatientRecord → ModelArtifact ML 训练 PatientRecord 提供训练特征数据

6.3 数据库物理模型(表结构)

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                           Database Physical Schema                           │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────┐
│       accounts_userprofile      │
├─────────────────────────────────┤
│ id                  INT (PK)   │
│ user_id             INT (U,FK) │
│ role                VARCHAR(20)│
│ display_name        VARCHAR(150│
│ bio                 TEXT       │
│ avatar              VARCHAR(100│
│ avatar_color        VARCHAR(7)  │
│ created_at          DATETIME   │
│ updated_at          DATETIME   │
└─────────────────────────────────┘
         │
         │ 1:1
         ▼
┌─────────────────────────────────┐         ┌─────────────────────────────────┐
│         auth_user               │         │     patients_patientrecord      │
├─────────────────────────────────┤         ├─────────────────────────────────┤
│ id                  INT (PK)   │         │ id                  INT (PK)   │
│ username            VARCHAR(150│         │ patient_id          INT (U)    │
│ password            VARCHAR(128│         │ age                 INT        │
│ email               VARCHAR(254│         │ gender             VARCHAR(10)│
│ first_name          VARCHAR(150│         │ pack_years          FLOAT      │
│ last_name           VARCHAR(150│         │ radon_exposure      VARCHAR(20│
│ is_staff            BOOL       │         │ asbestos_exposure   VARCHAR(10│
│ is_active           BOOL       │         │ secondhand_smoke... VARCHAR(10│
│ date_joined         DATETIME   │         │ copd_diagnosis      VARCHAR(10│
└─────────────────────────────────┘         │ alcohol_consumption VARCHAR(20│
                                            │ family_history       VARCHAR(10│
                                            │ lung_cancer          VARCHAR(10│
                                            │ created_at           DATETIME  │
                                            └─────────────────────────────────┘
                                                           │
                                                           │ 特征数据
                                                           ▼
┌─────────────────────────────────┐         ┌─────────────────────────────────┐
│  prediction_modelartifact       │         │  prediction_predictionrecord     │
├─────────────────────────────────┤         ├─────────────────────────────────┤
│ id                  INT (PK)   │         │ id                  INT (PK)   │
│ name                VARCHAR(200│◀────FK──│ model_id            INT (FK)  │
│ algorithm           VARCHAR(100│         │ user_id             INT (FK)  │
│ version             VARCHAR(50)│         │ input_payload       JSON      │
│ metrics             JSON       │         │ probability         FLOAT     │
│ confusion_matrix    JSON       │         │ risk_level         VARCHAR(10│
│ feature_importance  JSON       │         │ predicted_label     VARCHAR(10│
│ feature_names       JSON       │         │ top_factors        JSON      │
│ artifact_path       VARCHAR(500│         │ recommendations    JSON      │
│ training_rows       INT        │         │ similar_cases       JSON      │
│ training_positive.. FLOAT      │         │ report_summary      TEXT      │
│ is_active           BOOL       │         │ created_at          DATETIME  │
│ trained_at          DATETIME   │         └─────────────────────────────────┘
└─────────────────────────────────┘                    │
        │                                             │
        │ is_active=True                              │ recommendations
        │ (加载模型推理)                               ▼
        ▼                               ┌─────────────────────────────────┐
┌─────────────────────┐                 │ prediction_recommendationtemp.. │
│  ModelInference     │                 ├─────────────────────────────────┤
│  Service            │────────────────▶│ id                  INT (PK)   │
│  (services.py)      │   trigger_field │ code                VARCHAR(50)│
└─────────────────────┘   + trigger_val │ trigger_field      VARCHAR(50)│
                            (条件匹配)   │ trigger_value      VARCHAR(100│
                                         │ title_zh           VARCHAR(200│
                                         │ title_en           VARCHAR(200│
                                         │ description_zh      TEXT       │
                                         │ description_en     TEXT       │
                                         │ severity           INT        │
                                         │ is_active          BOOL       │
                                         └─────────────────────────────────┘

┌─────────────────────────────────┐
│   engagement_favoriteitem       │
├─────────────────────────────────┤
│ id                  INT (PK)   │
│ user_id             INT (FK)   │
│ target_type         VARCHAR(30)│
│ target_id           VARCHAR(100│
│ snapshot            JSON       │
│ created_at          DATETIME   │
│ [UNIQUE: user+target+type]    │
└─────────────────────────────────┘

7. 数据流程图

7.1 患者数据导入流程

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                        Data Import Pipeline (CSV → Database)                  │
└─────────────────────────────────────────────────────────────────────────────┘

       ┌─────────────────────────┐
       │  data/lung_cancer_      │
       │  dataset.csv            │
       │  (50,000 条记录)         │
       └───────────┬─────────────┘
                   │
                   │ CSV 文件
                   ▼
┌──────────────────────────────────────────────────────────────────────────┐
│  Django Management Command: import_lung_cancer_csv                        │
│  python manage.py import_lung_cancer_csv                                │
│                                                                          │
│  ┌────────────────┐    ┌────────────────┐    ┌────────────────────┐     │
│  │ FileValidator  │───▶│ CSVReader      │───▶│ DataCleaner        │     │
│  │ • 检查文件存在   │    │ • 逐行读取     │    │ • 去除空格/空值    │     │
│  │ • 验证编码格式   │    │ • skip header │    │ • 类型转换         │     │
│  │ • 验证列头      │    │ • error_handle │    │ • 范围校验         │     │
│  └────────────────┘    └────────────────┘    └─────────┬──────────┘     │
│                                                          │                │
│                   ┌──────────────────────────────────────▼──────────────┐  │
│                   │                  PatientRecord.objects.bulk_create  │  │
│                   │                    (批量插入,500条/批)             │  │
│                   └──────────────────────────────────────┬──────────────┘  │
│                                                          │                │
│                   ┌──────────────────────────────────────▼──────────────┐  │
│                   │                    Transaction.commit()             │  │
│                   │                    或 rollback on error            │  │
│                   └──────────────────────────────────────┬──────────────┘  │
│                                                          │                │
└──────────────────────────────────────────────────────────┼────────────────┘
                                                           │
                   ┌──────────────────────────────────────▼──────────────┐
                   │                    MySQL Database                    │
                   │              patients_patientrecord                  │
                   │                   (50,000 rows)                    │
                   └─────────────────────────────────────────────────────┘

7.2 机器学习训练流程

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    Machine Learning Training Pipeline                         │
└─────────────────────────────────────────────────────────────────────────────┘

    ┌───────────────────────────────────────────────────────────────────────┐
    │                     管理员触发训练 (Vue Admin → API)                   │
    │                     POST /api/models/train                            │
    └───────────────────────────────┬───────────────────────────────────────┘
                                    │
                                    ▼
    ┌───────────────────────────────────────────────────────────────────────┐
    │  prediction/views.py → ModelTrainingView                              │
    │                                                                        │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 1. 从数据库加载全部 PatientRecord                                 │ │
    │  │    PatientRecord.objects.all() → X (features), y (lung_cancer)   │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 2. 数据集划分                                                    │ │
    │  │    train_test_split(X, y, test_size=5000, random_state=42)      │ │
    │  │    → X_train (45,000), X_test (5,000), y_train, y_test         │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 3. 特征工程                                                      │ │
    │  │    • 性别: LabelEncoder (Male→0, Female→1)                     │ │
    │  │    • 氡暴露: OrdinalEncoder (Low→0, Medium→1, High→2)           │ │
    │  │    • Yes/No字段: LabelEncoder                                   │ │
    │  │    • 饮酒: OrdinalEncoder                                       │ │
    │  │    • 数值字段: 保持原值                                          │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 4. 模型训练: HistGradientBoostingClassifier                      │ │
    │  │    clf = HistGradientBoostingClassifier(                        │ │
    │  │        learning_rate=0.1, max_iter=200, random_state=42)        │ │
    │  │    clf.fit(X_train, y_train)                                     │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 5. 模型评估 (在 5,000 条测试集上)                                  │ │
    │  │    y_pred = clf.predict(X_test)                                  │ │
    │  │    y_prob = clf.predict_proba(X_test)[:, 1]                     │ │
    │  │    auc = roc_auc_score(y_test, y_prob)                          │ │
    │  │    recall = recall_score(y_test, y_pred)                        │ │
    │  │    precision = precision_score(y_test, y_pred)                  │ │
    │  │    confusion_matrix = confusion_matrix(y_test, y_pred)           │ │
    │  │    feature_importance = clf.feature_importances_                 │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 6. 保存模型文件                                                   │ │
    │  │    artifact_path = artifacts/models/lung_cancer_v{timestamp}.pkl │ │
    │  │    joblib.dump({'model': clf, 'encoders': encoders}, path)      │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    │                              │                                         │
    │                              ▼                                         │
    │  ┌──────────────────────────────────────────────────────────────────┐ │
    │  │ 7. 保存 ModelArtifact 记录                                        │ │
    │  │    • 解除旧模型 is_active=True → is_active=False                 │ │
    │  │    • 创建新记录 is_active=True                                   │ │
    │  │    • 记录 metrics, confusion_matrix, feature_importance          │ │
    │  └──────────────────────────────────────────────────────────────────┘ │
    └───────────────────────────────┬───────────────────────────────────────┘
                                    │
                                    ▼
    ┌───────────────────────────────────────────────────────────────────────┐
    │                         MySQL + 文件系统                               │
    │  ┌─────────────────────┐      ┌─────────────────────────────────────┐  │
    │  │ prediction_         │      │ artifacts/models/                   │  │
    │  │ modelartifact       │      │ lung_cancer_v20260329_143052.pkl   │  │
    │  │ (DB记录)             │      │                                     │  │
    │  └─────────────────────┘      └─────────────────────────────────────┘  │
    └───────────────────────────────────────────────────────────────────────┘

7.3 在线预测流程

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Online Prediction Flow                                │
└─────────────────────────────────────────────────────────────────────────────┘

  用户提交预测 (Vue PredictionView)
       │
       │ POST /api/predictions/predict
       │ { age, gender, pack_years, radon_exposure,
       │   asbestos_exposure, secondhand_smoke_exposure,
       │   copd_diagnosis, alcohol_consumption, family_history }
       ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  Django REST Framework                                                      │
│  ┌─────────────────────────────────────────────────────────────────────────┐│
│  │ PredictionView.post()                                                   ││
│  │  1. 序列化输入 (Serializer validation)                                    ││
│  │  2. 获取激活模型: ModelArtifact.objects.get(is_active=True)              ││
│  │  3. 加载模型: joblib.load(model.artifact_path)                          ││
│  └─────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  services.py → predict_lung_cancer(input_data)                               │
│                                                                              │
│  ┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐  │
│  │ 特征编码           │     │ 模型推理           │     │ 风险等级判定       │  │
│  │ • 性别→0/1        │────▶│ prob = model.     │────▶│ if prob >= 0.7:   │  │
│  │ • 氡暴露→0/1/2    │     │   predict_proba   │     │   risk = 'high'   │  │
│  │ • Yes/No→0/1     │     │   [x][1]          │     │ elif prob >= 0.4: │  │
│  │ • 饮酒→序数编码   │     │                   │     │   risk = 'medium' │  │
│  │                  │     │                   │     │ else:             │  │
│  │  返回特征向量      │     │  返回概率值         │     │   risk = 'low'    │  │
│  └──────────────────┘     └──────────────────┘     └──────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  recommendations.py → generate_recommendations(input_data, top_factors)     │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐│
│  │ 按触发字段 + 触发值匹配 RecommendationTemplate                            ││
│  │                                                                          ││
│  │ 输入: { radon_exposure: 'High', family_history: 'Yes', copd: 'Yes' }    ││
│  │                                                                          ││
│  │ 匹配:                                                                  ││
│  │   radon_exposure='High'      → "氡暴露风险" 模板                        ││
│  │   family_history='Yes'       → "肺癌家族史" 模板                        ││
│  │   copd_diagnosis='Yes'       → "慢阻肺管理" 模板                        ││
│  │                                                                          ││
│  │ 输出: [{code, title_zh, title_en, description_zh, description_en,       ││
│  │         severity, trigger_field, trigger_value}]                        ││
│  └─────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  recommendations.py → find_similar_cases(input_data, top_k=5)                │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐│
│  │ 1. 将输入转换为特征向量                                                   ││
│  │ 2. 从 PatientRecord 中随机采样候选集 (避免全表扫描)                       ││
│  │ 3. 计算欧氏距离: dist = sqrt(sum((xi - yi)^2))                          ││
│  │ 4. 取距离最小的 top_k 条记录                                             ││
│  │ 5. 返回: [{patient_id, age, gender, distance, lung_cancer}, ...]        ││
│  └─────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  保存 PredictionRecord                                                      │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐│
│  │ record = PredictionRecord.objects.create(                               ││
│  │     user=request.user,                                                  ││
│  │     model=active_model,                                                 ││
│  │     input_payload=input_data,                                           ││
│  │     probability=round(probability, 4),                                 ││
│  │     risk_level=risk_level,                                              ││
│  │     predicted_label='Yes' if prob >= 0.5 else 'No',                    ││
│  │     top_factors=top_factors,                                           ││
│  │     recommendations=recommendations,                                   ││
│  │     similar_cases=similar_cases,                                        ││
│  │     report_summary=generate_summary(...)                               ││
│  │ )                                                                       ││
│  └─────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
  返回预测结果给前端
  { probability, risk_level, top_factors, recommendations, similar_cases, ... }

7.4 收藏功能数据流

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Favorite Flow                                        │
└─────────────────────────────────────────────────────────────────────────────┘

  用户点击收藏按钮
       │
       │ POST /api/favorites
       │ { target_type: 'prediction_report', target_id: '123', snapshot: {...} }
       ▼
┌─────────────────┐
│ FavoriteView    │
│ .post()         │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  FavoriteItem.objects.create(                                                │
│      user=request.user,                                                     │
│      target_type=target_type,                                                │
│      target_id=str(target_id),  # 转字符串便于查询                            │
│      snapshot=snapshot,           # 收藏时刻的完整数据快照                     │
│  )                                                                           │
│                                                                              │
│  snapshot 示例 (target_type='prediction_report'):                            │
│  {                                                                           │
│    "probability": 0.732,                                                    │
│    "risk_level": "high",                                                    │
│    "predicted_label": "Yes",                                               │
│    "input_data": {...},                                                     │
│    "recommendations": [...],                                                │
│    "similar_cases": [...],                                                  │
│    "report_summary": "...",                                                 │
│    "created_at": "2026-03-29T10:00:00Z"                                     │
│  }                                                                           │
└─────────────────────────────────────────────────────────────────────────────┘
         │
         ▼
  FavoriteItem.objects.filter(user=request.user)
  → FavoritesView 显示收藏列表

8. API 接口文档

8.1 认证相关 /api/auth/

POST /api/auth/register --- 用户注册

请求:

json 复制代码
{
  "username": "zhang_san",
  "email": "zhang@example.com",
  "password": "SecurePass123",
  "password_confirm": "SecurePass123",
  "display_name": "张三"
}

响应 (201):

json 复制代码
{
  "id": 5,
  "username": "zhang_san",
  "email": "zhang@example.com",
  "display_name": "张三",
  "role": "user",
  "created_at": "2026-03-29T10:00:00Z"
}
POST /api/auth/login --- 用户登录

请求:

json 复制代码
{
  "username": "admin",
  "password": "admin123456"
}

响应 (200):

json 复制代码
{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "user": {
    "id": 1,
    "username": "admin",
    "email": "admin@example.com",
    "display_name": "管理员",
    "role": "admin",
    "avatar_url": "/media/avatars/admin.png",
    "avatar_color": "#7c2d12"
  }
}
POST /api/auth/avatar --- 头像上传

请求 : Content-Type: multipart/form-data

复制代码
avatar: <file> (≤2MB, JPG/PNG/GIF/WebP)

响应 (200):

json 复制代码
{
  "avatar_url": "/media/avatars/avatar_abc123.png"
}

8.2 分析数据 /api/analysis/

GET /api/analysis/overview --- 数据概览

响应 (200):

json 复制代码
{
  "total_patients": 50000,
  "positive_rate": 0.687,
  "avg_age": 62.4,
  "avg_pack_years": 12.3,
  "high_risk_factors": [
    { "factor": "family_history", "positive_rate": 0.82 },
    { "factor": "copd_diagnosis", "positive_rate": 0.79 },
    { "factor": "radon_exposure_High", "positive_rate": 0.75 }
  ],
  "gender_distribution": { "Male": 27000, "Female": 23000 },
  "age_group_distribution": {
    "40以下": 3200,
    "40-50": 8500,
    "50-60": 13500,
    "60-70": 16800,
    "70-80": 6800,
    "80以上": 1200
  }
}
GET /api/analysis/distribution --- 分布图表数据

响应 (200):

json 复制代码
{
  "sankey": {
    "nodes": ["二手烟暴露=Yes", "石棉暴露=Yes", "氡暴露=High", ...],
    "links": [
      { "source": "二手烟暴露=Yes", "target": "肺癌=Yes", "value": 8500 },
      ...
    ]
  },
  "treemap": {
    "data": [
      { "name": "family_history", "value": 0.82 },
      ...
    ]
  },
  "heatmap": {
    "xAxis": ["Low radon", "Medium radon", "High radon"],
    "yAxis": ["No COPD", "COPD"],
    "data": [[0.45, 0.62, 0.75], [0.58, 0.71, 0.82]]
  }
}
GET /api/analysis/advanced --- 高级分析数据

响应 (200):

json 复制代码
{
  "radar": {
    "indicators": [
      { "name": "年龄", "max": 100 },
      { "name": "包年数", "max": 80 },
      ...
    ],
    "lung_cancer_yes": [65, 22, ...],
    "lung_cancer_no": [58, 8, ...]
  },
  "scatter": {
    "data": [
      { "age_group": "50-60", "pack_year_group": "10-20", "count": 320 },
      ...
    ]
  },
  "funnel": {
    "data": [
      { "name": "总筛查人数", "value": 50000 },
      { "name": "高风险人群", "value": 18500 },
      { "name": "建议进一步检查", "value": 7200 },
      { "name": "确诊肺癌", "value": 3435 }
    ]
  },
  "age_cancer_rate": {
    "age_groups": ["<40", "40-50", "50-60", "60-70", "70-80", ">80"],
    "cancer_rates": [0.12, 0.28, 0.52, 0.71, 0.83, 0.88]
  }
}

8.3 预测 /api/predictions/

POST /api/predictions/predict --- 在线预测

请求:

json 复制代码
{
  "age": 58,
  "gender": "Male",
  "pack_years": 25,
  "radon_exposure": "Medium",
  "asbestos_exposure": "Yes",
  "secondhand_smoke_exposure": "No",
  "copd_diagnosis": "Yes",
  "alcohol_consumption": "Occasional",
  "family_history": "Yes"
}

响应 (200):

json 复制代码
{
  "id": 42,
  "probability": 0.7324,
  "risk_level": "high",
  "predicted_label": "Yes",
  "top_factors": [
    { "factor": "family_history", "contribution": 0.28 },
    { "factor": "copd_diagnosis", "contribution": 0.22 },
    { "factor": "pack_years", "contribution": 0.18 }
  ],
  "recommendations": [
    {
      "code": "FAMILY_HISTORY",
      "title_zh": "肺癌家族史提醒",
      "title_en": "Family History Alert",
      "description_zh": "建议每年进行低剂量CT筛查...",
      "severity": 4
    },
    ...
  ],
  "similar_cases": [
    { "patient_id": 12847, "age": 57, "gender": "Male", "distance": 0.12, "lung_cancer": "Yes" },
    ...
  ],
  "report_summary": "基于当前输入特征,系统评估您未来5年内患肺癌的风险为73.24%(高风险)..."
}

9. 前端架构

9.1 路由设计

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                              Vue Router Architecture                         │
└─────────────────────────────────────────────────────────────────────────────┘

  / (PublicLayout)
    ├── /login          → LoginView.vue      [公开]
    ├── /register       → RegisterView.vue   [公开]
    ├── /               → HomeView.vue       [公开]
    ├── /analysis       → AnalysisView.vue   [公开]
    ├── /predict        → PredictionView.vue [已认证]
    ├── /favorites      → FavoritesView.vue  [已认证]
    └── /profile        → ProfileView.vue    [已认证]

  /admin (AdminLayout)
    └── /admin          → AdminDashboardView.vue [管理员]

9.2 状态管理 (Pinia Auth Store)

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          Pinia Auth Store                                    │
└─────────────────────────────────────────────────────────────────────────────┘

  State:
  ┌──────────────────────────────────────────────────────────────────────────┐
  │ {                                                                           │
  │   user: { id, username, email, display_name, role, avatar_url } | null,  │
  │   token: access_token | null,                                            │
  │   refreshToken: refresh_token | null,                                     │
  │   isLoading: boolean                                                     │
  │ }                                                                           │
  └──────────────────────────────────────────────────────────────────────────┘
                                                                            │
  Actions:                                                                   │
  ├── login(username, password)    → POST /auth/login → 存储 token+user    │
  ├── register(...)               → POST /auth/register                   │
  ├── logout()                    → POST /auth/logout → 清除状态          │
  ├── fetchUser()                 → GET /auth/me → 恢复登录态              │
  └── uploadAvatar(file)          → POST /auth/avatar → 更新 avatar_url    │
                                                                            │
  Getters:                                                                   │
  ├── isAuthenticated → !!token                                               │
  └── isAdmin → user?.role === 'admin'                                       │

9.3 Axios 拦截器

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Axios Interceptors                                   │
└─────────────────────────────────────────────────────────────────────────────┘

  请求拦截器:
  ┌────────────────────────────────────────────────────────────────────────┐
  │ config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`│
  │ return config                                                          │
  └────────────────────────────────────────────────────────────────────────┘

  响应拦截器:
  ┌────────────────────────────────────────────────────────────────────────┐
  │ 200-299: return response.data                                          │
  │ 401:                                                                   │
  │   ├── 尝试使用 refresh_token 刷新                                        │
  │   ├── 刷新成功 → 重试原请求                                              │
  │   └── 刷新失败 → logout() → 跳转 /login                                 │
  │ else: throw error                                                      │
  └────────────────────────────────────────────────────────────────────────┘

10. 机器学习模块

10.1 算法选择

算法 AUC Recall Precision 训练时间 选择理由
RandomForest 0.71 0.85 0.72 基准模型
HistGradientBoosting 0.77 0.90 0.77 最优性能
LogisticRegression 0.68 0.78 0.69 极快 线性基线
SVM 0.70 0.82 0.71 极慢 不适合大数据

最终选择: HistGradientBoostingClassifier (scikit-learn)

10.2 特征工程

特征名 类型 处理方式 编码映射
age 连续 原始值 -
gender 二分类 LabelEncoder Male→0, Female→1
pack_years 连续 原始值 -
radon_exposure 多分类 OrdinalEncoder Low→0, Medium→1, High→2
asbestos_exposure 二分类 LabelEncoder No→0, Yes→1
secondhand_smoke_exposure 二分类 LabelEncoder No→0, Yes→1
copd_diagnosis 二分类 LabelEncoder No→0, Yes→1
alcohol_consumption 多分类 OrdinalEncoder Non-drinker→0, Occasional→1, Moderate→2, Heavy→3
family_history 二分类 LabelEncoder No→0, Yes→1

10.3 模型评估指标

复制代码
              预测为Positive    预测为Negative
实际Positive      TP (真阳)        FN (假阴)
实际Negative      FP (假阳)        TN (真阴)

AUC = ROC曲线下面积 → 0.7735 (衡量整体区分能力)
Recall = TP / (TP + FN) → 0.9043 (敏感度,查全率)
Precision = TP / (TP + FP) → 0.7654 (查准率)
F1 = 2 * Precision * Recall / (Precision + Recall)

11. 可视化方案

11.1 14 种图表清单

# 图表类型 组件名 用途 ECharts 类型
1 年龄分布柱状图 AgeDistribution 展示患者年龄分布 bar
2 包年分布柱状图 PackYearsDistribution 吸烟包年分布 bar
3 性别×肺癌堆叠柱状图 GenderLungCancerStacked 性别与肺癌交叉分析 bar (stacked)
4 氡暴露×肺癌分组柱状图 RadonLungCancerGrouped 氡暴露风险对比 bar (grouped)
5 肺癌占比饼图 LungCancerPie 阴阳性比例 pie
6 风险等级雷达图 RiskLevelRadar 多维风险对比 radar
7 Sankey流向图 ExposureSankey 暴露因素→肺癌流向 sankey
8 特征重要性Treemap FeatureTreemap 各特征重要性面积 treemap
9 风险热力矩阵 RiskHeatmap 双维度风险热力 heatmap
10 漏斗图 ScreeningFunnel 筛查路径转化 funnel
11 年龄组×癌症率折线图 AgeCancerRateLine 年龄与癌症率趋势 line
12 性别对比雷达图 GenderContrastRadar 男女风险特征雷达 radar
13 散点图 AgePackYearsScatter 年龄×包年关系 scatter
14 南丁格尔玫瑰图 NightingaleRose 多维度占比展示 pie (roseType)

11.2 图表布局

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          AnalysisView.vue 布局                              │
└─────────────────────────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────┐
  │                    AnalysisView.vue                     │
  │                                                          │
  │  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐          │
  │  │ KPI卡片 │ │ KPI卡片 │ │ KPI卡片 │ │ KPI卡片 │          │
  │  │ 总患者  │ │ 阳性率  │ │ 平均年龄│ │ 高风险 │          │
  │  └────────┘ └────────┘ └────────┘ └────────┘          │
  │                                                          │
  │  ┌────────────────────┐ ┌────────────────────────────┐  │
  │  │   1. 年龄分布柱状图   │ │   2. 包年分布柱状图         │  │
  │  │       (bar)         │ │        (bar)                │  │
  │  └────────────────────┘ └────────────────────────────┘  │
  │                                                          │
  │  ┌────────────────────┐ ┌────────────────────────────┐  │
  │  │ 3. 性别×肺癌堆叠柱状 │ │ 4. 氡暴露×肺癌分组柱状       │  │
  │  │      (stacked bar)  │ │       (grouped bar)         │  │
  │  └────────────────────┘ └────────────────────────────┘  │
  │                                                          │
  │  ┌────────┐ ┌────────────────────┐ ┌────────────────┐  │
  │  │5. 饼图 │ │   7. Sankey流向图     │ │ 8. Treemap    │  │
  │  │       │ │                     │ │                │  │
  │  └────────┘ └────────────────────┘ └────────────────┘  │
  │                                                          │
  │  ┌─────────────────────────────┐ ┌────────────────────┐  │
  │  │    6. 风险等级雷达图           │ │  9. 风险热力矩阵    │  │
  │  │         (radar)              │ │     (heatmap)      │  │
  │  └─────────────────────────────┘ └────────────────────┘  │
  │                                                          │
  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐  │
  │  │10. 漏斗图     │ │11. 年龄癌症率  │ │12. 性别对比雷达   │  │
  │  │   (funnel)   │ │   (line)     │ │    (radar)       │  │
  │  └──────────────┘ └──────────────┘ └──────────────────┘  │
  │                                                          │
  │  ┌────────────────────┐ ┌────────────────────────────┐  │
  │  │ 13. 散点图           │ │ 14. 南丁格尔玫瑰图           │  │
  │  │    (scatter)         │ │      (pie+roseType)        │  │
  │  └────────────────────┘ └────────────────────────────┘  │
  └─────────────────────────────────────────────────────────┘

12. 存储设计

12.1 文件存储结构

复制代码
backend/
├── artifacts/                    # 模型文件存储 (Git跟踪 .pkl)
│   └── models/
│       └── lung_cancer_v20260329_143052.pkl
│
├── media/                        # 用户上传文件 (Git不跟踪)
│   └── avatars/
│       ├── avatar_admin.png
│       ├── avatar_user1.png
│       └── .gitkeep             # 保持目录结构
│
└── staticfiles/                  # collectstatic 收集的静态文件
    ├── css/
    ├── js/
    └── images/

12.2 头像存储策略

复制代码
用户上传头像
      │
      ▼
┌─────────────────────────────┐
│  Pillow 图片处理             │
│  • 验证格式 (JPG/PNG/GIF/WebP)│
│  • 验证大小 (≤2MB)           │
│  • 转换为 RGB (如有透明度)    │
│  • 保持原始尺寸              │
│  • 保存为 PNG (统一格式)      │
└────────────┬────────────────┘
             │
             ▼
┌─────────────────────────────────────────────┐
│  文件路径: media/avatars/avatar_{随机后缀}.png │
│  URL路径: /media/avatars/avatar_{随机后缀}.png │
└─────────────────────────────────────────────┘
             │
             ▼
  Django Media 文件服务
  (DEBUG=True 时由 Django 提供静态文件服务)

12.3 模型文件存储策略

复制代码
训练完成 → 保存 .pkl 文件 → artifacts/models/lung_cancer_v{timestamp}.pkl
                                              │
                                              ▼
                              ModelArtifact.artifact_path = "artifacts/models/..."
                                              │
                                              ▼
                              MySQL 记录 (metrics, version, is_active)

13. 安全设计

13.1 认证与授权

机制 实现 说明
JWT Access Token SimpleJWT 15分钟有效期
JWT Refresh Token SimpleJWT 7天有效期
Token 黑名单 rest_framework_simplejwt.token_blacklist 支持强制登出
权限类 IsAuthenticated, IsAdminUser DRF 权限系统
路由守卫 Vue Router beforeEach 前端路由拦截

13.2 输入安全

复制代码
用户输入
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. Django REST Framework Serializer Validation                              │
│    • age: MinValueValidator(0), MaxValueValidator(120)                     │
│    • pack_years: MinValueValidator(0)                                       │
│    • choices 校验: 枚举值校验                                                │
│    • 字符串长度: max_length 限制                                            │
└─────────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. SQL 注入防护                                                              │
│    • Django ORM (参数化查询)                                                │
│    • 不使用原始 SQL 拼接                                                     │
└─────────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. XSS 防护                                                                 │
│    • Django 模板自动转义                                                     │
│    • Vue 默认不渲染原始 HTML                                                │
│    • Content-Security-Policy (生产环境)                                     │
└─────────────────────────────────────────────────────────────────────────────┘

13.3 文件上传安全

复制代码
头像上传安全检查:
├── 文件大小: ≤2MB (前端+后端双重校验)
├── 文件类型: 仅允许 JPG/PNG/GIF/WebP
├── 文件内容: Pillow 重新打开验证 (防止伪装的恶意文件)
├── 文件名: 随机生成 (avatar_{random_suffix}.png)
└── 存储位置: media/avatars/ (与代码目录分离)

14. 部署架构

14.1 开发环境

复制代码
┌─────────────────────────────────────────────┐
│              开发机器 (localhost)             │
│                                             │
│  ┌──────────────────┐  ┌──────────────────┐ │
│  │ Vue 3 (Vite)     │  │ Django (Runserver)│ │
│  │ Port: 5173       │  │ Port: 8000       │ │
│  └──────────────────┘  └──────────────────┘ │
│            │                      │            │
│            │    /api/* 代理        │            │
│            └──────────┬───────────┘            │
│                       │                        │
│                       ▼                        │
│  ┌─────────────────────────────────────────┐  │
│  │            MySQL (Port: 3306)            │  │
│  │         design_336_canner               │  │
│  └─────────────────────────────────────────┘  │
└─────────────────────────────────────────────────┘

14.2 生产环境(推荐)

复制代码
                         ┌─────────────────────────┐
                         │     用户浏览器           │
                         │   HTTPS (443)          │
                         └───────────┬─────────────┘
                                     │
                                     ▼
                         ┌─────────────────────────┐
                         │     Nginx (反向代理)     │
                         │   • 静态文件 /static/    │
                         │   • 媒体文件 /media/     │
                         │   • API 转发 :8000      │
                         │   • WebSocket (可选)    │
                         └───────────┬─────────────┘
                                     │
                    ┌────────────────┼────────────────┐
                    │                │                │
                    ▼                                 ▼
        ┌─────────────────────┐             ┌─────────────────────┐
        │  Django (Gunicorn)  │             │    Vue 3 构建产物    │
        │     Port: 8000      │             │   /frontend/dist/   │
        │  • WSGI / ASGI      │             │   (Nginx 直接服务)   │
        └──────────┬──────────┘             └─────────────────────┘
                   │
      ┌────────────┼────────────┐
      │            │            │
      ▼            ▼            ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│  MySQL   │ │ File Sys │ │ Redis    │
│  :3306   │ │ artifacts│ │ (可选)   │
│          │ │ /media   │ │ 缓存/Session│
└──────────┘ └──────────┘ └──────────┘

14.3 环境变量配置

backend/.env (开发):

bash 复制代码
DJANGO_SECRET_KEY=dev-secret-key-change-in-production
DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=design_336_canner
MYSQL_USER=root
MYSQL_PASSWORD=your-password
LUNG_CANCER_DATASET_PATH=../data/lung_cancer_dataset.csv

backend/.env (生产):

bash 复制代码
DJANGO_SECRET_KEY=<从环境变量或密钥管理服务读取>
DJANGO_DEBUG=0
DJANGO_ALLOWED_HOSTS=yourdomain.com
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=design_336_canner
MYSQL_USER=cancer_app
MYSQL_PASSWORD=<强密码>
LUNG_CANCER_DATASET_PATH=/var/www/cancer/data/lung_cancer_dataset.csv

15. 快速启动

15.1 环境准备

bash 复制代码
# 1. Python ≥ 3.8
python --version
# Python 3.11.x

# 2. Node.js ≥ 18
node --version
# v20.x.x

# 3. MySQL 8.x(已启动)
mysql --version
# mysql  Ver 8.x.x

15.2 数据库初始化

bash 复制代码
# 创建数据库
mysql -u root -p -e "CREATE DATABASE design_336_canner CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# 配置环境变量
cp .env.example backend/.env
# 编辑 backend/.env,填入数据库密码

# 初始化 Django(建表)
cd backend
python manage.py migrate

# 创建超级管理员
python manage.py createsuperuser
# Username: admin
# Email: admin@example.com
# Password: admin123456

# 创建演示管理员(可选)
python manage.py ensure_demo_admin
# demo_admin / admin123456

15.3 导入患者数据

bash 复制代码
# CSV 文件位于 data/lung_cancer_dataset.csv(50,000 条)
cd backend
python manage.py import_lung_cancer_csv
# 输出: Successfully imported 50000 patient records.

15.4 启动后端

bash 复制代码
cd backend
python manage.py runserver
# 后端地址: http://127.0.0.1:8000
# Django Admin: http://127.0.0.1:8000/admin/

15.5 启动前端

bash 复制代码
cd frontend
npm install
npm run dev
# 前端地址: http://localhost:5173

15.6 默认账号

角色 用户名 密码 说明
管理员 admin admin123456 Django 超级管理员
演示管理员 demo_admin admin123456 用于功能演示
普通用户 user1 user123456 注册获得

16. Django Admin 使用指南

16.1 进入 Django Admin

方式一:点击前端「Django 数据管理后台」按钮(跳转到 http://127.0.0.1:8000/admin/

方式二:直接访问 http://127.0.0.1:8000/admin/

16.2 可管理的模型

App (中文名) 模型 说明
账户管理 用户资料 查看/编辑用户头像、角色、显示名
患者管理 患者记录 50,000 条患者数据(支持过滤/搜索/排序)
预测管理 模型 训练生成的 ML 模型(可激活最佳模型)
预测管理 预测记录 用户预测历史(查看概率/建议/相似病例)
预测管理 推荐模板 干预建议模板(中英双语,启用/禁用)
收藏管理 收藏 用户收藏夹(预测报告/相似病例)

16.3 模型训练流程

  1. 进入「预测管理 → 模型」页面
  2. 点击右上角「训练新模型」按钮
  3. 等待训练完成(约 1-2 分钟)
  4. 新模型自动激活(is_active=True)
  5. 可在列表中查看 AUC/Recall/Precision 指标

17. 环境变量说明

17.1 后端环境变量

变量名 必填 默认值 说明
DJANGO_SECRET_KEY - Django 密钥(生产必须随机生成)
DJANGO_DEBUG 0 调试模式(生产设为 0)
DJANGO_ALLOWED_HOSTS - 允许的域名,逗号分隔
MYSQL_HOST 127.0.0.1 MySQL 主机
MYSQL_PORT 3306 MySQL 端口
MYSQL_DATABASE - 数据库名
MYSQL_USER - 数据库用户名
MYSQL_PASSWORD - 数据库密码
LUNG_CANCER_DATASET_PATH .../data/... CSV 数据文件路径

17.2 前端环境变量

变量名 必填 默认值 说明
VITE_API_BASE_URL http://127.0.0.1:8000/api API 基础地址

更新日志

版本 日期 内容
v1.0 2026-03-29 完成全部功能:Django+Vue 肺癌可视化系统,14种图表,ML预测,Django Admin 美化
相关推荐
AI科技星2 小时前
基于四维时空光速不变公设的量子几何与量子力学本质全维度推导验证
开发语言·人工智能·opencv·计算机视觉·数学建模·r语言
清水白石0082 小时前
《Python 性能优化实战:多进程并行 vs C/Rust/Cython 扩展的对比决策与团队落地指南》
python·spring·缓存
不会写DN2 小时前
Go 中最主流 JWT 库 jwt -go
开发语言·后端·golang
源码之家2 小时前
计算机毕业设计:基于Python与协同过滤的美食推荐系统 Django框架 可视化 协同过滤推荐算法 菜谱 食品 机器学习(建议收藏)✅
爬虫·python·机器学习·django·毕业设计·课程设计·美食
2501_921649492 小时前
RESTful 金融数据 API 文档:设计原则与最佳实践
开发语言·后端·python·金融·restful
workflower2 小时前
如何使用设计模式-误区
java·开发语言·设计模式·集成测试·软件工程·需求分析·软件需求
学以智用2 小时前
Python 批量重命名文件工具(完整示例)
后端·python
badhope2 小时前
如何将小厂Java项目包装出高并发架构演进感
python·程序员·ipython
故事和你912 小时前
洛谷-入门4-数组3
开发语言·数据结构·c++·算法·动态规划·图论