客户购物偏好数据可视化分析系统 --- 技术文档
目录
1. 项目概述
1.1 项目简介
本系统是一个基于 Flask 的全栈 Web 应用,用于对客户购物行为数据进行多维度可视化分析。系统提供六大分析模块(消费分析、偏好分析、订阅分析、评分分析、预测分析、相关性分析)、一个全屏数据可视化大屏、以及完整的数据管理(CRUD)功能。
1.2 核心功能
| 功能模块 | 说明 |
|---|---|
| 数据看板 | 概览统计卡片 + 4 个核心图表(性别/类别/季节/年龄分布) |
| 消费分析 | 品类消费对比、地区消费 TOP15、支付方式分布 |
| 偏好分析 | 颜色偏好 TOP10、尺码分布、配送方式、热门商品 TOP10 |
| 订阅分析 | 订阅状态、订阅×性别交叉、折扣使用、购买频率 |
| 评分分析 | 评分区间分布、品类平均评分、季节平均评分 |
| 预测分析 | 年龄趋势+线性回归、季节消费预测(移动平均)、RFM 分层、品类气泡图 |
| 相关性分析 | Pearson 相关热力图、性别×品类交叉、季节×支付交叉、品类箱线图 |
| 可视化大屏 | 全屏独立页面,8 个图表 + 6 个 KPI 指标 + 实时订单滚动 |
| 数据管理 | 搜索、分页、新增、编辑、删除购物记录 |
| 用户系统 | 注册、登录、个人中心(修改用户名/密码) |
1.3 数据规模
- 数据来源:
shopping_trends.csv,共 3900 条客户购物记录 - 覆盖范围:美国 50 个州、4 大商品类别、25 种商品、25 种颜色、6 种支付方式、6 种配送方式














2. 技术栈与依赖
2.1 后端技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| Python | 3.8+ | 运行时环境 |
| Flask | 3.0.0 | Web 框架 |
| Flask-SQLAlchemy | 3.1.1 | ORM,数据库操作 |
| Flask-Login | 0.6.3 | 用户认证与会话管理 |
| Werkzeug | 3.0.1 | 密码哈希、WSGI 工具 |
| Pandas | 2.1.4 | CSV 数据导入 |
| SQLite | (内置) | 数据库引擎 |
2.2 前端技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| Bootstrap | 5.3.0 | 响应式布局与 UI 组件 |
| Bootstrap Icons | 1.11.0 | 图标库 |
| ECharts | 5.4.3 | 数据可视化图表库 |
| Jinja2 | (Flask 内置) | 服务端模板引擎 |
| 原生 JavaScript | ES6+ | 前端交互逻辑 |
2.3 依赖安装
txt
# requirements.txt
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
Flask-Login==0.6.3
Werkzeug==3.0.1
pandas==2.1.4
bash
pip install -r requirements.txt
3. 系统架构
3.1 整体架构
┌─────────────────────────────────────────────────────┐
│ 浏览器 (Client) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
│ │ Bootstrap │ │ ECharts │ │ 原生 JS (main.js / │ │
│ │ 5.3 │ │ 5.4.3 │ │ screen.js) │ │
│ └──────────┘ └──────────┘ └──────────────────────┘ │
└────────────────────┬────────────────────────────────┘
│ HTTP (GET/POST)
▼
┌─────────────────────────────────────────────────────┐
│ Flask 应用 (app.py) │
│ ┌────────────────┐ ┌──────────────────────────────┐│
│ │ 页面路由 (12) │ │ API 端点 (15) ││
│ │ GET → 模板渲染 │ │ 返回 JSON 数据 ││
│ └────────────────┘ └──────────────────────────────┘│
│ ┌────────────────┐ ┌──────────────────────────────┐│
│ │ Flask-Login │ │ SQLAlchemy ORM ││
│ │ 认证中间件 │ │ 数据库操作层 ││
│ └────────────────┘ └──────────────────────────────┘│
└────────────────────┬────────────────────────────────┘
│ SQL
▼
┌─────────────────────────────────────────────────────┐
│ SQLite (instance/shopping.db) │
│ ┌──────────────┐ ┌───────────────────────────┐ │
│ │ users 表 │ │ shopping_data 表 (3900行) │ │
│ └──────────────┘ └───────────────────────────┘ │
└─────────────────────────────────────────────────────┘
3.2 架构特点
- 单文件后端 :所有路由、API、配置集中在
app.py(733 行) - 模板继承 :所有页面继承
base.html,大屏页面独立 - 前后端分离的 API :页面加载后通过
fetch()调用 API 获取 JSON 数据,前端渲染图表 - 服务端计算:统计聚合、线性回归、Pearson 相关系数均在 Python 端计算
4. 项目目录结构
shop/
├── app.py # Flask 主应用(路由 + API + 配置,733 行)
├── models.py # SQLAlchemy 数据模型(42 行)
├── init_db.py # 数据库初始化脚本(49 行)
├── requirements.txt # Python 依赖清单
├── shopping_trends.csv # 源数据集(3900 条记录)
│
├── instance/
│ └── shopping.db # SQLite 数据库文件(运行时生成)
│
├── static/
│ ├── css/
│ │ ├── style.css # 主样式表(暗色主题,1338 行)
│ │ └── screen.css # 大屏专用样式(596 行)
│ ├── js/
│ │ ├── main.js # 主图表引擎(1055 行)
│ │ └── screen.js # 大屏图表引擎(483 行)
│ ├── icons/ # SVG 图标(logo, analytics, chart 等)
│ └── images/ # 背景图 + 轮播图 SVG
│
├── templates/
│ ├── base.html # 基础布局模板
│ ├── login.html # 登录页
│ ├── register.html # 注册页
│ ├── dashboard.html # 数据看板
│ ├── data_manage.html # 数据管理(CRUD)
│ ├── screen.html # 可视化大屏(独立布局)
│ ├── profile.html # 个人中心
│ ├── analysis.html # 遗留模板(已被 6 个独立页面替代)
│ ├── partials/
│ │ └── sidebar.html # 侧边栏导航组件
│ └── analysis/
│ ├── purchase.html # 消费分析
│ ├── preference.html # 偏好分析
│ ├── subscription.html # 订阅分析
│ ├── rating.html # 评分分析
│ ├── prediction.html # 预测分析
│ └── correlation.html # 相关性分析
│
└── TECHNICAL_DOC.md # 本文档
5. 数据库设计
5.1 ER 图
┌──────────────────────┐ ┌──────────────────────────────────┐
│ users │ │ shopping_data │
├──────────────────────┤ ├──────────────────────────────────┤
│ id (PK, Integer) │ │ id (PK, Integer) │
│ username (String, UQ) │ │ customer_id (Integer, UQ) │
│ password_hash (String)│ │ age (Integer) │
│ created_at (DateTime) │ │ gender (String(10)) │
└──────────────────────┘ │ item_purchased (String(50)) │
│ category (String(50)) │
│ purchase_amount (Float) │
│ location (String(50)) │
│ size (String(10)) │
│ color (String(20)) │
│ season (String(10)) │
│ review_rating (Float) │
│ subscription_status (String(10)) │
│ shipping_type (String(30)) │
│ discount_applied (String(5)) │
│ promo_code_used (String(5)) │
│ previous_purchases (Integer) │
│ payment_method (String(20)) │
│ frequency_of_purchases (String) │
└──────────────────────────────────┘
5.2 users 表
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id |
Integer | PK, 自增 | 用户 ID |
username |
String(80) | UNIQUE, NOT NULL | 用户名 |
password_hash |
String(256) | NOT NULL | 密码哈希值(Werkzeug pbkdf2) |
created_at |
DateTime | 默认 datetime.utcnow |
注册时间 |
密码使用 werkzeug.security.generate_password_hash 加密,算法为 pbkdf2:sha256。
5.3 shopping_data 表
| 字段 | 类型 | 说明 | 数据示例 |
|---|---|---|---|
id |
Integer (PK) | 自增主键 | 1, 2, 3... |
customer_id |
Integer (UQ) | 客户编号 | 1-3900 |
age |
Integer | 客户年龄 | 18-70 |
gender |
String(10) | 性别 | Male, Female |
item_purchased |
String(50) | 购买商品 | Blouse, Jeans, Sneakers... |
category |
String(50) | 商品类别 | Clothing, Footwear, Outerwear, Accessories |
purchase_amount |
Float | 消费金额 (USD) | 20.0-100.0 |
location |
String(50) | 所在州 | Kentucky, California... (50州) |
size |
String(10) | 尺码 | S, M, L, XL |
color |
String(20) | 颜色 | Gray, Red, Blue... (25色) |
season |
String(10) | 季节 | Spring, Summer, Fall, Winter |
review_rating |
Float | 评价评分 | 2.5-5.0 |
subscription_status |
String(10) | 订阅状态 | Yes, No |
shipping_type |
String(30) | 配送方式 | Free Shipping, Standard, Express... |
discount_applied |
String(5) | 是否使用折扣 | Yes, No |
promo_code_used |
String(5) | 是否使用优惠码 | Yes, No |
previous_purchases |
Integer | 历史购买次数 | 1-50 |
payment_method |
String(20) | 支付方式 | Credit Card, Debit Card, PayPal... |
frequency_of_purchases |
String(20) | 购买频率 | Weekly, Monthly, Quarterly... |
5.4 数据初始化
运行 init_db.py 完成以下操作:
- 创建所有数据库表(
db.create_all()) - 创建默认管理员账户:
admin/123456 - 从
shopping_trends.csv导入 3900 条数据到shopping_data表
bash
python init_db.py
CSV 字段映射关系:
| CSV 列名 | 数据库字段 |
|---|---|
| Customer ID | customer_id |
| Age | age |
| Gender | gender |
| Item Purchased | item_purchased |
| Category | category |
| Purchase Amount (USD) | purchase_amount |
| Location | location |
| Size | size |
| Color | color |
| Season | season |
| Review Rating | review_rating |
| Subscription Status | subscription_status |
| Shipping Type | shipping_type |
| Discount Applied | discount_applied |
| Promo Code Used | promo_code_used |
| Previous Purchases | previous_purchases |
| Payment Method | payment_method |
| Frequency of Purchases | frequency_of_purchases |
6. 后端接口设计
6.1 应用配置
python
# app.py 关键配置
SECRET_KEY = 'shopping-analysis-secret-key-2024'
SQLALCHEMY_DATABASE_URI = 'sqlite:///shopping.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
LOGIN_VIEW = '/login'
LOGIN_MESSAGE = '请先登录以访问此页面'
应用使用工厂模式 create_app() 初始化 Flask 实例、数据库和登录管理器。
6.2 页面路由总览
| 路由 | 方法 | 认证 | 模板 | 功能 |
|---|---|---|---|---|
/ |
GET | 否 | 重定向 | 已登录跳 dashboard,否则跳 login |
/login |
GET/POST | 否 | login.html |
登录页面与认证处理 |
/register |
GET/POST | 否 | register.html |
注册页面与用户创建 |
/logout |
GET | 是 | 重定向 | 登出,跳转 login |
/dashboard |
GET | 是 | dashboard.html |
数据看板(统计卡片+4图表) |
/data-manage |
GET | 是 | data_manage.html |
数据管理列表(搜索+分页) |
/screen |
GET | 是 | screen.html |
可视化大屏(独立布局) |
/profile |
GET | 是 | profile.html |
个人中心 |
/analysis |
GET | 是 | 重定向 | 重定向到 /analysis/purchase |
/analysis/purchase |
GET | 是 | analysis/purchase.html |
消费分析 |
/analysis/preference |
GET | 是 | analysis/preference.html |
偏好分析 |
/analysis/subscription |
GET | 是 | analysis/subscription.html |
订阅分析 |
/analysis/rating |
GET | 是 | analysis/rating.html |
评分分析 |
/analysis/prediction |
GET | 是 | analysis/prediction.html |
预测分析 |
/analysis/correlation |
GET | 是 | analysis/correlation.html |
相关性分析 |
6.3 数据管理路由
| 路由 | 方法 | 认证 | 功能 |
|---|---|---|---|
/data-manage/add |
POST | 是 | 新增购物记录 |
/data-manage/edit/<id> |
POST | 是 | 编辑购物记录 |
/data-manage/delete/<id> |
POST | 是 | 删除购物记录 |
/api/record/<id> |
GET | 是 | 获取单条记录 JSON(编辑弹窗用) |
新增记录逻辑 :自动分配 customer_id 为当前最大值 +1,17 个字段均有默认值。
编辑记录逻辑 :使用 get_or_404 获取记录,逐字段更新,使用 request.form.get(field, old_value) 保留未修改字段。
6.4 分析 API 端点
6.4.1 /api/overview-stats --- 概览统计
返回 Dashboard 页面所需的 4 维统计数据。
json
{
"gender": [{"name": "Male", "value": 2050}, {"name": "Female", "value": 1850}],
"category": [{"name": "Clothing", "value": 1500}, ...],
"season": [{"name": "Spring", "value": 980}, ...],
"age": [{"name": "18-25", "value": 650}, {"name": "26-35", "value": 800}, ...]
}
年龄区间划分:18-25, 26-35, 36-45, 46-55, 56-65, 65+
6.4.2 /api/purchase-analysis --- 消费分析
json
{
"category_amount": [
{"name": "Clothing", "total": 50000.00, "avg": 65.50}
],
"location_amount": [
{"name": "California", "value": 8500.00}
],
"payment": [
{"name": "Credit Card", "value": 1200}
]
}
category_amount:按品类统计总消费和平均消费location_amount:按地区统计消费总额,降序取 TOP 15payment:按支付方式统计订单数
6.4.3 /api/preference-analysis --- 偏好分析
json
{
"color": [{"name": "Olive", "value": 180}],
"size": [{"name": "M", "value": 1000}],
"shipping": [{"name": "Free Shipping", "value": 900}],
"item": [{"name": "Blouse", "value": 150}]
}
color:颜色偏好 TOP 10size:尺码分布(全量)shipping:配送方式分布(全量)item:商品偏好 TOP 10
6.4.4 /api/subscription-analysis --- 订阅分析
json
{
"subscription": [{"name": "Yes", "value": 1200}, {"name": "No", "value": 2700}],
"sub_gender": [
{"sub": "Yes", "gender": "Male", "count": 650},
{"sub": "Yes", "gender": "Female", "count": 550}
],
"discount": [{"name": "Yes", "value": 1800}],
"frequency": [{"name": "Monthly", "value": 800}]
}
6.4.5 /api/rating-analysis --- 评分分析
json
{
"rating_dist": [
{"name": "1-2", "value": 200},
{"name": "2-3", "value": 500},
{"name": "3-4", "value": 1800},
{"name": "4-5", "value": 1400}
],
"rating_category": [{"name": "Clothing", "value": 3.75}],
"rating_season": [{"name": "Spring", "value": 3.72}]
}
评分区间:1-2 (左闭右闭), 2-3 (左闭右开), 3-4 (左闭右开), 4-5 (左闭右闭)
6.4.6 /api/prediction-analysis --- 预测分析
json
{
"age_trend": [
{"name": "18-25", "avg_amount": 62.50, "count": 650}
],
"trend_line": [60.2, 62.8, 65.1, 67.3, 64.5, 63.0],
"season_trend": [
{"season": "Spring", "total": 45000.00, "count": 980}
],
"season_prediction": 47500.00,
"rfm": [
{"category": "Clothing", "avg_prev": 25.3, "avg_amount": 65.50, "count": 1500}
],
"bubble": [
{"category": "Clothing", "avg_rating": 3.75, "count": 1500, "total_amount": 98250.00}
]
}
6.4.7 /api/correlation-analysis --- 相关性分析
json
{
"matrix": [[0, 0, 1.0], [0, 1, 0.02], ...],
"labels": ["年龄", "消费金额", "评分", "历史购买"],
"categories": ["Accessories", "Clothing", "Footwear", "Outerwear"],
"male_data": [400, 800, 350, 500],
"female_data": [350, 700, 300, 450],
"payments": ["Bank Transfer", "Cash", "Credit Card", ...],
"season_labels": ["春季", "夏季", "秋季", "冬季"],
"cross_season": {
"Spring": [100, 120, 300, ...],
"Summer": [110, 130, 280, ...]
},
"box_data": {
"Clothing": {"min": 20.0, "q1": 40.0, "median": 60.0, "q3": 80.0, "max": 100.0, "count": 1500}
}
}
6.5 大屏专用 API
| 端点 | 功能 | 返回 |
|---|---|---|
/api/screen/summary |
KPI 指标 | total, total_amount, avg_rating, customers, subscribers, sub_rate, avg_age, avg_prev_purchases |
/api/screen/map-data |
地区消费数据 | [{name, count, total, avg}] 按 location 聚合 |
/api/screen/top-items |
热销商品 TOP10 | [{name, category, count, amount}] 按销量降序 |
/api/screen/recent-orders |
最近 20 条订单 | [{id, item, category, amount, location, gender, age, payment, season}] |
/api/screen/gender-age |
性别×年龄分布 | {male: [{age, count}], female: [{age, count}]} |
/api/screen/season-category |
季节×类别交叉 | [{season, category, count}] |
6.6 用户管理 API
| 端点 | 方法 | 功能 | 请求体 | 响应 |
|---|---|---|---|---|
/api/profile/update-password |
POST | 修改密码 | {old_password, new_password, confirm_password} |
{success, message} |
/api/profile/update-username |
POST | 修改用户名 | {new_username} |
{success, message} |
密码修改验证规则:
- 原密码必须正确
- 新密码长度 ≥ 6
- 两次输入一致
用户名修改验证规则:
- 长度 2-20 字符
- 不能与当前用户名相同
- 不能与已有用户名重复
7. 前端架构设计
7.1 模板继承体系
base.html
├── dashboard.html
├── data_manage.html
├── profile.html
└── analysis/
├── purchase.html
├── preference.html
├── subscription.html
├── rating.html
├── prediction.html
└── correlation.html
screen.html (独立,不继承 base.html)
login.html (独立)
register.html (独立)
7.2 base.html 模板
提供以下全局功能:
| 功能 | 实现方式 |
|---|---|
| CSS 框架 | Bootstrap 5.3.0 CDN |
| 图标库 | Bootstrap Icons 1.11.0 CDN |
| 图表库 | ECharts 5.4.3 CDN |
| 页面加载动画 | .page-loader + CSS 过渡 |
| 背景网格 | .bg-grid CSS 网格叠加 |
| 粒子效果 | JS 动态生成 30 个 .particle 元素 |
| 浮动几何图形 | JS 动态生成 12 个 .shape 元素(登录页) |
| 实时时钟 | updateClock() 每秒更新 #topbarTime |
| 数字滚动动画 | animateCounters() 使用 data-count 属性,缓动函数 1 - (1-p)^3 |
模板块(Block):
{% block title %}--- 页面标题{% block extra_css %}--- 额外 CSS{% block body %}--- 页面主体{% block extra_js %}--- 额外 JS
7.3 侧边栏组件
partials/sidebar.html 通过 active_page 变量控制高亮:
jinja2
<a class="nav-link {{ 'active' if active_page == 'purchase' }}" href="...">
导航结构:
| 分组 | 菜单项 | 图标 |
|---|---|---|
| 主导航 | 数据看板 | bi-grid-1x2-fill |
| 消费分析 | bi-cart-fill |
|
| 偏好分析 | bi-heart-fill |
|
| 订阅分析 | bi-bell-fill |
|
| 评分分析 | bi-star-fill |
|
| 预测分析 | bi-graph-up-arrow |
|
| 相关性矩阵 | bi-grid-3x3-gap |
|
| 可视化大屏 | bi-display (新窗口) |
|
| 数据 | 数据管理 | bi-database-fill |
| 账户 | 个人中心 | bi-person-gear |
| 底部 | 退出登录 | bi-box-arrow-left |
7.4 main.js --- 主图表引擎
文件 :static/js/main.js(1055 行)
职责:为 Dashboard 和 6 个分析页面渲染所有 ECharts 图表。
核心模块:
| 模块 | 函数 | 说明 |
|---|---|---|
| 加载状态 | showChartLoading(chartId, text) |
显示旋转加载器 |
clearChartLoading(chartId) |
清除加载器 | |
showBatchLoading(ids, text) |
批量显示加载状态 | |
| 中文映射 | ZH 对象 |
完整的英文→中文翻译字典 |
zh(type, val) |
查找翻译,找不到返回原值 | |
| 主题配置 | DARK_THEME |
ECharts 深色主题(背景、文字、提示框) |
COLORS |
10 色灰度调色板 | |
COLOR_GRADIENTS |
10 组渐变色对 | |
| 布局工具 | GRID, GRID_SMALL |
通用 grid 配置 |
axisStyle() |
通用轴样式(颜色、网格线) | |
makeGradient() |
创建线性渐变 | |
| 图表函数 | loadOverviewCharts() |
看板 4 图表 |
loadPurchaseAnalysis() |
消费 3 图表 | |
loadPreferenceAnalysis() |
偏好 4 图表 | |
loadSubscriptionAnalysis() |
订阅 4 图表 | |
loadRatingAnalysis() |
评分 3 图表 | |
loadPredictionAnalysis() |
预测 4 图表 | |
loadCorrelationAnalysis() |
相关性 4 图表 |
中文翻译字典覆盖范围:
| 类型 | 翻译条目数 | 示例 |
|---|---|---|
| gender | 2 | Male→男性, Female→女性 |
| season | 4 | Spring→春季, Summer→夏季... |
| subscription | 2 | Yes→已订阅, No→未订阅 |
| discount | 2 | Yes→使用折扣, No→未使用折扣 |
| size | 4 | S→小码, M→中码, L→大码, XL→加大码 |
| payment | 6 | Credit Card→信用卡, Cash→现金... |
| shipping | 6 | Free Shipping→免费配送, Express→快速配送... |
| frequency | 6 | Weekly→每周, Monthly→每月... |
| category | 4 | Clothing→服装, Footwear→鞋类... |
| color | 25 | Gray→灰色, Red→红色... |
| item | 25 | Blouse→女式衬衫, Jeans→牛仔裤... |
| location | 50 | California→加利福尼亚, New York→纽约... |
7.5 screen.js --- 大屏图表引擎
文件 :static/js/screen.js(483 行)
职责:为可视化大屏页面渲染 8 个图表 + KPI 动态刷新 + 订单滚动。
核心流程:
initScreen()
├── initParticles() // 生成 25 个粒子
├── updateClock() // 启动时钟
├── animateCounters() // KPI 数字动画
├── loadAllCharts() // 并行请求 8 个 API,渲染 8 个图表
│ ├── Promise.all([8 fetch])
│ ├── renderGenderChart()
│ ├── renderAgeChart()
│ ├── renderCategoryChart()
│ ├── renderPaymentChart()
│ ├── renderMapChart()
│ ├── renderGenderAgeChart()
│ ├── renderSeasonCategoryChart()
│ ├── renderTopItemsChart()
│ └── refreshKPI()
└── loadOrders() // 加载并渲染滚动订单
大屏页面 8 个图表:
| 图表 ID | 类型 | 数据源 | 说明 |
|---|---|---|---|
screenGenderChart |
环形饼图 | /api/overview-stats |
性别分布 |
screenAgeChart |
折线图 | /api/overview-stats |
年龄段分布 |
screenCategoryChart |
南丁格尔玫瑰图 | /api/overview-stats |
类别占比 |
screenPaymentChart |
环形饼图 | /api/purchase-analysis |
支付方式 |
screenMapChart |
水平柱状图 | /api/screen/map-data |
地区消费 TOP20 |
screenGenderAgeChart |
人口金字塔 | /api/screen/gender-age |
性别×年龄 |
screenSeasonChart |
堆叠柱状图 | /api/screen/season-category |
季节×类别 |
screenItemChart |
水平柱状图 | /api/screen/top-items |
热销商品 TOP10 |
6 个 KPI 指标:
| ID | 数据字段 | 前缀 | 后缀 | 小数位 |
|---|---|---|---|---|
kpiTotal |
total | - | - | 0 |
kpiAmount |
total_amount | $ | - | 0 |
kpiRating |
avg_rating | - | - | 2 |
kpiCustomers |
customers | - | - | 0 |
kpiSubRate |
sub_rate | - | % | 1 |
kpiAvgAge |
avg_age | - | - | 1 |
8. 页面功能详解
8.1 登录/注册页
- 登录页 (
login.html):浮动几何图形背景 + 毛玻璃登录卡片,POST 到/login - 注册页 (
register.html):同风格,POST 到/register,包含密码确认 - Flash 消息分类:
error(红色)、success(绿色)、warning(黄色)
8.2 数据看板 (dashboard.html)
布局:侧边栏 + 主内容区
内容:
- 轮播图(4 张 SVG,自动播放间隔 4 秒)
- 4 个统计卡片:数据总量、总消费金额、平均评分、客户数量
- 4 个图表(2×2 网格):性别饼图、类别柱状图、季节柱状图、年龄折线图
数据加载 :页面加载后调用 loadOverviewCharts() → fetch('/api/overview-stats')
8.3 数据管理 (data_manage.html)
功能:
- 搜索框:支持按商品名、地区、类别模糊搜索
- 分页:每页 20 条,使用 Flask-SQLAlchemy 的
paginate() - 数据表格:显示全部 17 个字段
- 新增弹窗:模态框表单,17 个输入字段
- 编辑弹窗:通过
/api/record/<id>获取数据回填表单 - 删除确认:二次确认弹窗
8.4 可视化大屏 (screen.html)
独立布局 :不继承 base.html,使用专用 screen.css
三列布局:
| 列 | 面板 |
|---|---|
| 左列 | 核心指标 KPI(6 个)、性别分布、年龄分布、性别-年龄金字塔 |
| 中列 | 地区消费热力分布(TOP20 水平柱状图)、季节×类别消费、商品类别占比玫瑰图 |
| 右列 | 支付方式分布、热销商品 TOP10、实时订单滚动 |
特性:
- 全屏切换(Fullscreen API)
- 实时时钟(顶部+底部)
- KPI 数字滚动动画
- 订单无缝滚动(数据复制一份实现循环)
- 底部状态栏:系统状态、数据总量、更新时间
8.5 分析页面
每个分析页面结构相同:
- 继承
base.html - 包含
partials/sidebar.html - 顶部栏(标题 + 时钟 + 用户名)
- 图表区域(chart-card 容器,带圆角装饰)
- 引入
main.js,调用对应的loadXxxAnalysis()函数
各页面图表详情:
消费分析 (analysis/purchase.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
categoryAmountChart |
分组柱状图 | 各品类总消费 vs 平均消费(双系列) |
locationChart |
水平柱状图 | 地区消费 TOP15(绿色渐变) |
paymentChart |
南丁格尔玫瑰图 | 支付方式分布 |
偏好分析 (analysis/preference.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
colorChart |
柱状图 | 颜色偏好 TOP10 |
sizeChart |
饼图 | 尺码分布 |
shippingChart |
环形图 | 配送方式分布 |
itemChart |
水平柱状图 | 热门商品 TOP10(橙色渐变) |
订阅分析 (analysis/subscription.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
subscriptionChart |
环形图 | 订阅状态(绿色=已订阅,红色=未订阅) |
subGenderChart |
堆叠柱状图 | 订阅×性别交叉分析 |
discountChart |
饼图 | 折扣使用情况 |
frequencyChart |
柱状图 | 购买频率分布 |
评分分析 (analysis/rating.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
ratingDistChart |
环形图 | 评分区间分布(红/橙/灰/绿 四色) |
ratingCategoryChart |
柱状图 | 各品类平均评分(颜色编码:≥4绿,≥3橙,<3红) |
ratingSeasonChart |
折线图 | 各季节平均评分 |
预测分析 (analysis/prediction.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
ageTrendChart |
柱状图+折线 | 年龄段消费趋势 + 线性回归趋势线 |
seasonPredictChart |
柱状图 | 季节实际消费 + 下季度预测值 |
rfmChart |
双轴图 | 客户价值分层(柱状=历史购买,折线=平均消费) |
bubbleChart |
散点图/气泡图 | 品类增长潜力(X=评分,Y=销量,气泡大小=金额) |
相关性分析 (analysis/correlation.html)
| 图表 ID | 类型 | 说明 |
|---|---|---|
heatmapChart |
热力图 | 4 变量 Pearson 相关系数矩阵 |
crossGenderChart |
分组柱状图 | 性别×品类交叉分析 |
crossSeasonChart |
堆叠柱状图 | 季节×支付方式交叉分析 |
boxplotChart |
箱线图 | 各品类消费金额分布(min/Q1/median/Q3/max) |
8.6 个人中心 (profile.html)
展示信息:
- 用户头像(首字母圆形)
- 用户名、注册时间
- 管理的数据记录数
操作:
- 修改用户名:JSON POST 到
/api/profile/update-username - 修改密码:JSON POST 到
/api/profile/update-password - Toast 通知反馈操作结果
9. 数据流与交互流程
9.1 页面加载数据流
用户访问页面
│
▼
Flask 路由处理
│
├── 渲染模板(服务端注入初始数据:统计卡片数值)
│
▼
浏览器加载页面
│
├── 加载 base.html(Bootstrap + ECharts + 粒子 + 时钟)
│
├── 加载页面 JS(main.js 或 screen.js)
│
▼
DOMContentLoaded 事件
│
├── 调用 loadXxxAnalysis()
│
├── fetch('/api/xxx-analysis')
│
▼
Flask API 处理
│
├── SQLAlchemy 查询 → 聚合计算
│
├── 返回 JSON 响应
│
▼
前端 JS 处理
│
├── 清除加载状态
│
├── 中文翻译 (zh())
│
├── ECharts 渲染图表
│
└── 注册 resize 事件监听
9.2 数据管理 CRUD 流程
新增:
表单 POST → /data-manage/add → 自动生成 customer_id → db.session.add() → redirect
编辑:
点击编辑 → fetch('/api/record/<id>') → 回填模态框 → 表单 POST → /data-manage/edit/<id> → redirect
删除:
点击删除 → 确认弹窗 → 表单 POST → /data-manage/delete/<id> → db.session.delete() → redirect
搜索:
输入关键词 → 表单 GET → /data-manage?search=xxx → SQLAlchemy LIKE 过滤 → 渲染结果
9.3 大屏数据加载流程
initScreen()
│
├── Promise.all([
│ fetch('/api/overview-stats'),
│ fetch('/api/purchase-analysis'),
│ fetch('/api/preference-analysis'),
│ fetch('/api/screen/map-data'),
│ fetch('/api/screen/gender-age'),
│ fetch('/api/screen/season-category'),
│ fetch('/api/screen/top-items'),
│ fetch('/api/screen/summary')
│ ])
│
├── 并行渲染 8 个图表
│
├── refreshKPI(summary) // KPI 数字动画
│
└── loadOrders() // 独立请求,滚动订单
10. 核心算法实现
10.1 线性回归(预测分析)
在 prediction_analysis() 中实现,用于拟合年龄段消费趋势线:
python
n = len(age_trend)
x_vals = list(range(n)) # [0, 1, 2, 3, 4, 5]
y_vals = [d['avg_amount'] for d in age_trend]
x_mean = sum(x_vals) / n
y_mean = sum(y_vals) / n
ss_xy = sum((x_vals[i] - x_mean) * (y_vals[i] - y_mean) for i in range(n))
ss_xx = sum((x_vals[i] - x_mean) ** 2 for i in range(n))
slope = ss_xy / ss_xx if ss_xx != 0 else 0
intercept = y_mean - slope * x_mean
trend_line = [round(slope * x + intercept, 2) for x in range(n)]
公式:y = slope * x + intercept,其中 slope = Σ(xi - x̄)(yi - ȳ) / Σ(xi - x̄)²
10.2 移动平均预测(季节预测)
python
season_order = ['Spring', 'Summer', 'Fall', 'Winter']
# 获取各季节消费总额
totals = [season_map[s]['total'] for s in season_order]
# 预测 = 全季节平均值
avg_prediction = round(sum(totals) / len(totals), 2)
使用简单平均法预测下一季度消费额。
10.3 Pearson 相关系数
在 correlation_analysis() 中实现,计算 4 个变量(年龄、消费金额、评分、历史购买)之间的相关矩阵:
python
def pearson(x, y):
n = len(x)
x_mean = sum(x) / n
y_mean = sum(y) / n
ss_xy = sum((x[i] - x_mean) * (y[i] - y_mean) for i in range(n))
ss_xx = sum((x[i] - x_mean) ** 2 for i in range(n))
ss_yy = sum((y[i] - y_mean) ** 2 for i in range(n))
denom = math.sqrt(ss_xx * ss_yy)
return round(ss_xy / denom, 4) if denom != 0 else 0
公式:r = Σ(xi - x̄)(yi - ȳ) / √[Σ(xi - x̄)² × Σ(yi - ȳ)²]
结果范围 [-1, 1],前端通过热力图 visualMap 映射到颜色。
10.4 箱线图数据计算
python
cat_amounts.sort()
n = len(cat_amounts)
q1_idx = n // 4
q3_idx = 3 * n // 4
med_idx = n // 2
box_data = {
'min': cat_amounts[0],
'q1': cat_amounts[q1_idx],
'median': cat_amounts[med_idx],
'q3': cat_amounts[q3_idx],
'max': cat_amounts[-1]
}
使用位置索引法计算五数概括(Min, Q1, Median, Q3, Max)。
10.5 RFM 简化模型
python
rfm_data = db.session.query(
ShoppingData.category,
func.avg(ShoppingData.previous_purchases), # R (Recency 近似)
func.avg(ShoppingData.purchase_amount), # M (Monetary)
func.count(ShoppingData.id) # F (Frequency 近似)
).group_by(ShoppingData.category).all()
按品类聚合,使用 previous_purchases 近似 Recency,purchase_amount 作为 Monetary,记录数近似 Frequency。
11. 主题与视觉系统
11.1 CSS 变量体系
css
:root {
--bg-primary: #0a0e1a; /* 主背景色(深蓝黑) */
--bg-secondary: #111827; /* 次背景色 */
--bg-card: #1a1f35; /* 卡片背景 */
--text-primary: #e8e8e8; /* 主文字色 */
--text-secondary: #808890; /* 次文字色 */
--border-color: rgba(255, 255, 255, 0.08); /* 边框色 */
--accent-blue: #3b82f6; /* 强调色 */
--accent-green: #10b981; /* 成功色 */
--accent-yellow: #f59e0b; /* 警告色 */
--accent-red: #ef4444; /* 错误色 */
}
11.2 ECharts 暗色主题
javascript
const DARK_THEME = {
backgroundColor: 'transparent',
textStyle: { color: '#808890', fontFamily: '-apple-system, PingFang SC, Microsoft YaHei, sans-serif' },
title: { textStyle: { color: '#e8e8e8' } },
legend: { textStyle: { color: '#808890' } },
tooltip: {
backgroundColor: 'rgba(10, 14, 26, 0.95)',
borderColor: 'rgba(255, 255, 255, 0.12)',
textStyle: { color: '#e8e8e8', fontSize: 13 },
extraCssText: 'box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); border-radius: 8px;'
}
};
11.3 调色板
主调色板(10 色灰度系):
#c8ccd4, #a0a8b4, #788090, #b8c0cc, #606878,
#d0d4dc, #909aa8, #505868, #e0e4ec, #404858
特殊配色:
- 男性:
#a0a8b4 → #c8ccd4(灰色渐变) - 女性:
#c490a0 → #d4a0b0(粉灰渐变) - 季节:春
#10b981(绿), 夏#f59e0b(黄), 秋#f97316(橙), 冬#98a0a8(灰) - 评分:1-2 红, 2-3 橙, 3-4 灰, 4-5 绿
- 订阅:已订阅绿
#059669→#10b981, 未订阅红#dc2626→#ef4444
11.4 动画效果
| 效果 | 实现 | 说明 |
|---|---|---|
| 页面加载 | CSS @keyframes + .loaded 类 |
旋转加载器 → 渐隐 |
| 数字滚动 | requestAnimationFrame + 缓动 |
1 - (1-progress)^3 三次方缓出 |
| 卡片入场 | CSS @keyframes fadeUp + delay |
各卡片依次从下方滑入 |
| 粒子背景 | CSS @keyframes float |
30 个粒子缓慢上浮 |
| 图表强调 | ECharts emphasis + shadowBlur |
hover 时发光效果 |
| 订单滚动 | CSS @keyframes scroll |
无缝循环滚动 |
12. 部署与运行指南
12.1 环境要求
- Python 3.8+
- pip
12.2 安装步骤
bash
# 1. 克隆/下载项目
cd shop
# 2. 安装依赖
pip install -r requirements.txt
# 3. 初始化数据库(创建表 + 导入数据 + 创建管理员)
python init_db.py
# 4. 启动应用
python app.py
12.3 访问地址
- 应用地址:
http://localhost:5000 - 默认管理员:
admin/123456
12.4 数据库重置
bash
# 删除数据库文件
rm instance/shopping.db
# 重新初始化
python init_db.py
12.5 生产环境部署建议
bash
# 使用 Gunicorn(Linux)
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 "app:app"
# 使用 Waitress(Windows)
pip install waitress
waitress-serve --port=5000 "app:app"
生产环境还需:
- 修改
SECRET_KEY为随机强密钥 - 关闭
debug=True - 使用 PostgreSQL/MySQL 替代 SQLite
- 配置反向代理(Nginx)
- 启用 HTTPS
13. 安全设计
13.1 已实现的安全措施
| 措施 | 实现 |
|---|---|
| 密码加密 | Werkzeug pbkdf2:sha256 哈希 |
| 路由保护 | @login_required 装饰器保护所有业务路由和 API |
| 用户隔离 | 所有用户共享数据(无多租户隔离) |
| SQL 注入防护 | SQLAlchemy ORM 参数化查询 |
| 密码强度 | 修改密码时要求 ≥ 6 位 |
13.2 安全风险与改进建议
| 风险 | 当前状态 | 建议 |
|---|---|---|
| CSRF | 无保护 | 引入 Flask-WTF,所有表单添加 CSRF token |
| XSS | Jinja2 默认转义 | 已有基本防护,注意 ` |
| SECRET_KEY | 硬编码 | 使用环境变量:os.environ.get('SECRET_KEY') |
| 默认密码 | admin/123456 | 首次登录强制修改密码 |
| 速率限制 | 无 | 引入 Flask-Limiter 防暴力破解 |
| 输入验证 | 基本类型转换 | 引入 WTForms 或 JSON Schema 验证 |
14. 已知问题与优化建议
14.1 代码架构
| 问题 | 说明 | 建议 |
|---|---|---|
| 单文件后端 | app.py 733 行,所有路由集中 |
拆分为 Flask Blueprints(auth, analysis, data, screen) |
| JS 重复代码 | main.js 和 screen.js 各有独立的 ZH、主题配置 |
抽取共享模块 common.js |
| 遗留模板 | analysis.html 仍存在,已被 6 个独立页面替代 |
删除 templates/analysis.html |
14.2 性能优化
| 问题 | 说明 | 建议 |
|---|---|---|
| 相关性分析 | 全量加载 3900 条记录到内存计算 | 使用 SQL 聚合或 numpy 向量化 |
| 箱线图 | 逐品类全量查询 + Python 排序 | 使用 SQL 窗口函数或 pandas |
| 大屏 API | 8 个独立 API 调用 | 已用 Promise.all 并行,可考虑合并为 1 个聚合 API |
| 无缓存 | 每次页面加载都重新查询 | 引入 Flask-Caching(Redis 或内存缓存) |
14.3 功能扩展建议
| 方向 | 说明 |
|---|---|
| 数据导入 | 支持用户上传 CSV/Excel 自定义数据集 |
| 数据导出 | 图表导出为 PNG,数据导出为 CSV |
| 筛选器 | 全局时间范围、品类、地区筛选器联动所有图表 |
| 权限管理 | 区分管理员和普通用户角色 |
| API 文档 | 引入 Flask-RESTX 生成 Swagger 文档 |
| 国际化 | 支持中英文切换 |
| 移动端 | 优化响应式布局,大屏适配平板 |
附录 A:前后端字段一致性验证
通过系统性扫描,对比所有后端 API 返回字段与前端消费代码:
| API 端点 | 后端字段 | 前端使用 | 状态 |
|---|---|---|---|
/api/overview-stats |
gender[].name/value | zh('gender', item.name) | 匹配 |
/api/overview-stats |
category[].name/value | zh('category', item.name) | 匹配 |
/api/overview-stats |
season[].name/value | zh('season', item.name) | 匹配 |
/api/overview-stats |
age[].name/value | item.name + '岁' | 匹配 |
/api/purchase-analysis |
category_amount[].name/total/avg | 全部使用 | 匹配 |
/api/purchase-analysis |
location_amount[].name/value | zh('location', item.name) | 匹配 |
/api/purchase-analysis |
payment[].name/value | zh('payment', item.name) | 匹配 |
/api/preference-analysis |
color/size/shipping/item | 全部映射正确 | 匹配 |
/api/subscription-analysis |
subscription/sub_gender/discount/frequency | 全部映射正确 | 匹配 |
/api/rating-analysis |
rating_dist/rating_category/rating_season | 全部映射正确 | 匹配 |
/api/prediction-analysis |
age_trend/trend_line/season_trend/season_prediction/rfm/bubble | 全部映射正确 | 匹配 |
/api/correlation-analysis |
matrix/labels/categories/male_data/female_data/payments/season_labels/cross_season/box_data | 全部映射正确 | 匹配 |
/api/screen/* |
summary/map-data/top-items/recent-orders/gender-age/season-category | 全部映射正确 | 匹配 |
结论:当前系统前后端字段完全匹配,无数据不一致问题。
附录 B:模板-容器 ID 对照表
| 模板 | 容器 ID | JS 函数 | 状态 |
|---|---|---|---|
| dashboard.html | genderChart, categoryChart, seasonChart, ageChart | loadOverviewCharts() | 匹配 |
| analysis/purchase.html | categoryAmountChart, locationChart, paymentChart | loadPurchaseAnalysis() | 匹配 |
| analysis/preference.html | colorChart, sizeChart, shippingChart, itemChart | loadPreferenceAnalysis() | 匹配 |
| analysis/subscription.html | subscriptionChart, subGenderChart, discountChart, frequencyChart | loadSubscriptionAnalysis() | 匹配 |
| analysis/rating.html | ratingDistChart, ratingCategoryChart, ratingSeasonChart | loadRatingAnalysis() | 匹配 |
| analysis/prediction.html | ageTrendChart, seasonPredictChart, rfmChart, bubbleChart | loadPredictionAnalysis() | 匹配 |
| analysis/correlation.html | heatmapChart, crossGenderChart, crossSeasonChart, boxplotChart | loadCorrelationAnalysis() | 匹配 |
| screen.html | screenGenderChart, screenAgeChart, screenCategoryChart, screenPaymentChart, screenMapChart, screenGenderAgeChart, screenSeasonChart, screenItemChart | renderXxxChart() | 匹配 |
文档版本:v2.0
更新日期:2026-05-17
基于源代码实际分析生成