景点热度数据可视化分析系统 --- 技术文档
1. 项目概述
1.1 项目简介
本系统是一个基于 Python 的景点热度数据可视化分析平台,用于对全国各城市旅游景点的热度、游客量、票价、好评率等多维度数据进行采集、存储、分析和可视化展示。系统采用 B/S 架构,后端使用 FastAPI 框架,前端采用 Jinja2 模板引擎 + jQuery + ECharts/ApexCharts 实现交互式数据可视化。
1.2 核心功能
| 功能模块 | 说明 |
|---|---|
| 用户认证 | 注册、登录、JWT Cookie 鉴权、密码修改、头像上传 |
| 数据看板 | 4 个 KPI 卡片 + 20+ 交互式图表(地图、漏斗、桑基、仪表盘、树状图等) |
| 数据管理 | DataTable 表格展示、筛选、增删改查(管理员专属) |
| 数据分析 | 5 个专题分析页面(概览、城市、价格、游客、季节) |
| 用户管理 | 管理员可查看、删除、设置/取消管理员权限 |
| 个人中心 | 修改昵称、邮箱、密码、头像 |
1.3 技术栈
| 层次 | 技术 | 版本 |
|---|---|---|
| 后端框架 | FastAPI | 0.104.1 |
| ASGI 服务器 | Uvicorn | 0.24.0 |
| 模板引擎 | Jinja2 | 3.1.2 |
| 数据处理 | Pandas + OpenPyXL | 2.1.4 / 3.1.2 |
| 数据库 | SQLite3 | 内置 |
| JWT 认证 | python-jose | 3.3.0 |
| 前端框架 | jQuery + Bootstrap 4 | 3.x / 4.x |
| 图表库 | ECharts 5.4.3 + ApexCharts | - |
| UI 模板 | Molon Admin Template | - |
| 图标库 | Material Design Icons + Remix Icons | 本地化 |























2. 项目目录结构
tourism/
├── main.py # 应用入口,FastAPI 实例创建与路由注册
├── config.py # 全局配置(路径、密钥、过期时间)
├── database.py # SQLite 数据库操作(用户 CRUD)
├── requirements.txt # Python 依赖
├── package.json # Node.js 依赖(仅 ECharts)
├── 基于Python的景点热度分析.xlsx # 原始数据源(Excel)
├── users.db # SQLite 用户数据库
│
├── data/
│ ├── __init__.py
│ ├── loader.py # Excel 数据加载与持久化
│ └── processor.py # 30+ 个数据分析/聚合函数
│
├── models/
│ ├── __init__.py
│ └── schemas.py # Pydantic 数据模型定义
│
├── routers/
│ ├── __init__.py
│ ├── pages.py # 页面路由(HTML 模板渲染)
│ ├── api_users.py # 用户 API(登录/注册/个人中心/管理)
│ ├── api_attractions.py # 景点 CRUD API
│ └── api_charts.py # 图表数据 API(31 个端点)
│
├── templates/ # Jinja2 HTML 模板
│ ├── base.html # 基础布局(侧边栏、顶栏、脚本加载)
│ ├── login.html # 登录页
│ ├── register.html # 注册页
│ ├── dashboard.html # 数据看板(20+ 图表)
│ ├── data_table.html # 数据管理页(DataTable)
│ ├── profile.html # 个人中心
│ ├── admin_users.html # 用户管理(管理员)
│ ├── analysis_overview.html # 概览分析
│ ├── analysis_city.html # 城市分析
│ ├── analysis_price.html # 价格分析
│ ├── analysis_visitor.html # 游客分析
│ └── analysis_season.html # 季节分析
│
├── static/
│ ├── css/
│ │ ├── bootstrap.min.css # Bootstrap 4
│ │ ├── app.min.css # Molon 模板样式
│ │ ├── icons-local.min.css # 本地化图标字体 CSS
│ │ ├── tourism-custom.css # 自定义设计系统(CSS 变量、KPI/图表/表格样式)
│ │ ├── tourism-enhance.css # 补充增强样式
│ │ └── ... # 其他第三方 CSS
│ │
│ ├── js/
│ │ ├── common.js # TourismApp 全局工具对象(API 封装、通知、格式化)
│ │ ├── app.js # Molon 模板初始化脚本(侧边栏、主题切换)
│ │ ├── dashboard-tourism.js # 看板图表渲染(ECharts + ApexCharts,~750 行)
│ │ ├── datatable-tourism.js # DataTable 配置与 CRUD 交互
│ │ ├── analysis-overview.js # 概览分析图表
│ │ ├── analysis-city.js # 城市分析图表
│ │ ├── analysis-price.js # 价格分析图表
│ │ ├── analysis-visitor.js # 游客分析图表
│ │ ├── analysis-season.js # 季节分析图表
│ │ ├── echarts.min.js # ECharts 5.4.3(本地)
│ │ ├── apexcharts.min.js # ApexCharts(本地)
│ │ ├── jquery.min.js # jQuery
│ │ ├── bootstrap.bundle.min.js # Bootstrap Bundle
│ │ ├── jquery.dataTables.min.js # DataTables 核心
│ │ └── ... # 其他第三方 JS
│ │
│ ├── font/ # 本地字体文件(MDI、Remix、Inter 等)
│ ├── picture/ # Logo、头像占位图
│ └── uploads/ # 用户上传的头像文件
│
└── moban6127/ # Molon 模板原始文件(参考用,不参与运行)
3. 系统架构
3.1 架构图
┌─────────────────────────────────────────────────────────────┐
│ 浏览器 (Client) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ 登录页面 │ │ 数据看板 │ │ 数据管理 │ │ 分析页面 ×5 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
│ │ │ │ │ │
│ jQuery + Bootstrap + ECharts + ApexCharts + DataTables │
└───────┼────────────┼────────────┼───────────────┼───────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ FastAPI (Uvicorn) │
│ │
│ ┌──────────────┐ ┌───────────────┐ ┌──────────────────┐ │
│ │ pages.py │ │ api_users.py │ │ api_charts.py │ │
│ │ (HTML 路由) │ │ (用户 API) │ │ (图表数据 API) │ │
│ └──────┬───────┘ └───────┬───────┘ └────────┬─────────┘ │
│ │ │ │ │
│ ┌──────┴───────┐ ┌──────┴───────┐ ┌────────┴─────────┐ │
│ │ Jinja2 模板 │ │ database.py │ │ processor.py │ │
│ │ (templates/) │ │ (SQLite) │ │ (Pandas 聚合) │ │
│ └──────────────┘ └──────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌───────┴─────────┐ │
│ │ loader.py │ │
│ │ (Excel 读写) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌─────────────────────┐
│ users.db │ │ 基于Python的景点 │
│ (SQLite) │ │ 热度分析.xlsx │
└──────────────┘ └─────────────────────┘
3.2 数据流
- 启动阶段 :
main.py启动时调用init_db()初始化 SQLite 数据库,调用load_data()将 Excel 数据加载到内存中的 Pandas DataFrame。 - 页面请求 :浏览器请求页面路由 →
pages.py验证 JWT Cookie → 渲染 Jinja2 模板返回 HTML。 - API 请求 :前端 JS 通过
TourismApp.apiGet/apiPost发起 fetch 请求 → 路由处理函数从 DataFrame 或 SQLite 读取数据 → 返回 JSON。 - 数据持久化 :景点数据的增删改操作直接修改内存中的 DataFrame 并调用
save_to_excel()写回 Excel 文件。
4. 后端详细设计
4.1 入口文件 main.py
python
app = FastAPI(title="景点热度数据可视化分析系统")
- 配置 CORS 中间件(允许所有来源)
- 挂载
/static静态文件目录 - 注册 4 个路由模块:
pages、api_users、api_charts、api_attractions - 启动事件中初始化数据库和加载数据
4.2 配置文件 config.py
| 配置项 | 值 | 说明 |
|---|---|---|
DATA_FILE_PATH |
./基于Python的景点热度分析.xlsx |
景点数据源 |
DATABASE_PATH |
./users.db |
SQLite 数据库路径 |
SECRET_KEY |
tourism-analysis-secret-key-2024 |
JWT 签名密钥 |
TOKEN_ALGORITHM |
HS256 |
JWT 算法 |
TOKEN_EXPIRE_HOURS |
24 |
Token 过期时间(小时) |
4.3 数据库模块 database.py
使用 SQLite3 存储用户信息,提供以下操作函数:
| 函数 | 说明 |
|---|---|
init_db() |
创建 users 表,自动迁移 is_admin 列,首用户设为管理员 |
create_user() |
创建用户(SHA256 哈希密码) |
verify_password() |
验证用户名密码 |
get_user_by_id() / get_user_by_username() |
查询用户 |
update_user_profile() |
更新昵称和邮箱 |
update_password() |
修改密码 |
update_avatar() |
更新头像路径 |
is_user_admin() |
判断是否管理员 |
get_all_users() |
获取所有用户列表 |
delete_user() |
删除用户 |
set_user_admin() |
设置/取消管理员权限 |
users 表结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INTEGER PK | 自增主键 |
| username | TEXT UNIQUE | 用户名 |
| password_hash | TEXT | SHA256 密码哈希 |
| TEXT | 邮箱(可选) | |
| nickname | TEXT | 昵称(可选) |
| avatar | TEXT | 头像路径(默认占位图) |
| is_admin | INTEGER | 是否管理员(0/1) |
| created_at | TIMESTAMP | 创建时间 |
4.4 数据加载模块 data/loader.py
- 使用
pd.read_excel()读取 Excel 文件到全局_df变量 get_dataframe():返回 DataFrame 副本(用于分析,不影响原始数据)get_raw_dataframe():返回原始 DataFrame 引用(用于 CRUD 操作)save_to_excel():将当前 DataFrame 写回 Excel 文件refresh_data():重新从 Excel 加载数据
4.5 数据分析模块 data/processor.py
包含 30+ 个 Pandas 聚合分析函数,全部接受 DataFrame 参数,返回字典格式数据。按功能分类:
基础统计:
| 函数 | 返回内容 |
|---|---|
get_summary_stats() |
KPI 数据(景点总数、月均游客、好评率、门票均价) |
get_city_distribution() |
各城市游客量和景点数量 |
get_type_distribution() |
景点类型分布 |
get_heat_level_distribution() |
热度等级分布(顶流/热门/一般) |
get_season_distribution() |
适宜游玩季节分布 |
get_top_attractions() |
Top N 景点(按月均游客排序) |
get_star_distribution() |
星级分布 |
关联分析:
| 函数 | 返回内容 |
|---|---|
get_price_visitor_data() |
门票价格 vs 游客量散点数据 |
get_city_avg_metrics() |
各城市好评率和网红指数对比 |
get_influencer_vs_review() |
网红指数 vs 好评率气泡图数据 |
get_age_group_data() |
游客年龄段分布 |
get_city_map_data() |
地图散点数据(含经纬度坐标) |
get_radar_data() |
Top 5 景点六维雷达图数据 |
深度分析:
| 函数 | 返回内容 |
|---|---|
get_city_total_visitors() |
城市游客总量排行 |
get_manager_attraction_count() |
负责人管理景点数量 |
get_open_days_vs_visitors() |
开放天数 vs 游客量散点 |
get_guide_mentions_top() |
攻略提及次数 Top N |
get_influencer_distribution() |
网红打卡指数区间分布 |
get_price_distribution() |
门票价格区间分布 |
get_daily_tickets_top() |
日均门票销量 Top N |
get_facilities_analysis() |
周边配套设施(酒店+餐厅) |
get_review_influencer_bubble() |
好评率 vs 网红指数气泡图 |
get_city_type_stacked() |
各城市景点类型堆叠柱图 |
get_heat_star_cross() |
热度等级 x 星级交叉分析 |
get_age_group_city() |
游客年龄段城市对比 |
get_season_heat_heatmap() |
季节 x 热度等级热力图 |
get_price_by_type() |
门票价格按类型分布(分组柱图) |
get_composite_score_top() |
综合评分 Top N(多维加权) |
新增图表:
| 函数 | 返回内容 |
|---|---|
get_city_attraction_count() |
各城市景点数量排行 |
get_price_review_scatter() |
门票价格 vs 好评率散点 |
get_visitors_by_type() |
各类型景点平均游客量 |
get_hotel_restaurant_scatter() |
酒店 vs 餐厅数量散点 |
get_sankey_data() |
城市→类型→热度 桑基图 |
get_type_visitor_treemap() |
类型×城市 游客量树状图 |
get_price_box_data() |
各类型门票价格箱线图数据 |
4.6 Pydantic 模型 models/schemas.py
| 模型 | 用途 |
|---|---|
UserLogin |
登录请求体(username, password) |
UserRegister |
注册请求体(username, password, email) |
UserResponse |
用户信息响应体 |
UserProfileUpdate |
个人资料更新(nickname, email) |
PasswordChange |
密码修改(old_password, new_password) |
AttractionCreate |
景点创建(17 个字段) |
AttractionUpdate |
景点更新(所有字段可选) |
4.7 路由模块
4.7.1 页面路由 routers/pages.py
| 路径 | 模板 | 权限 | 说明 |
|---|---|---|---|
GET / |
dashboard.html / login.html | 可选 | 首页(已登录跳看板,否则登录页) |
GET /login |
login.html | 无 | 登录页 |
GET /register |
register.html | 无 | 注册页 |
GET /dashboard |
dashboard.html | 登录 | 数据看板 |
GET /data |
data_table.html | 管理员 | 数据管理 |
GET /profile |
profile.html | 登录 | 个人中心 |
GET /admin/users |
admin_users.html | 管理员 | 用户管理 |
GET /analysis/overview |
analysis_overview.html | 登录 | 概览分析 |
GET /analysis/city |
analysis_city.html | 登录 | 城市分析 |
GET /analysis/price |
analysis_price.html | 登录 | 价格分析 |
GET /analysis/visitor |
analysis_visitor.html | 登录 | 游客分析 |
GET /analysis/season |
analysis_season.html | 登录 | 季节分析 |
鉴权逻辑 :读取 Cookie 中的 access_token,JWT 解析获取 user_id,查询数据库获取用户信息。未登录返回登录页,非管理员访问管理页面重定向到看板。
4.7.2 用户 API routers/api_users.py
| 端点 | 方法 | 说明 |
|---|---|---|
/api/login |
POST | 用户登录,设置 JWT Cookie |
/api/register |
POST | 用户注册 |
/api/user/profile |
GET | 获取当前用户信息 |
/api/user/profile |
PUT | 更新昵称/邮箱 |
/api/user/password |
PUT | 修改密码 |
/api/user/avatar |
POST | 上传头像(multipart/form-data) |
/api/logout |
POST | 退出登录(清除 Cookie) |
/api/admin/users |
GET | 获取所有用户列表(管理员) |
/api/admin/users/{id} |
DELETE | 删除用户(管理员) |
/api/admin/users/{id}/admin |
PUT | 切换管理员权限 |
JWT 认证流程:
- 登录成功后,服务端生成 JWT Token(含 user_id、过期时间)
- Token 写入
access_tokenCookie(httponly,24 小时过期) - 后续请求通过
get_current_user()从 Cookie 读取 Token 并解码验证
4.7.3 景点 CRUD API routers/api_attractions.py
| 端点 | 方法 | 说明 |
|---|---|---|
/api/attractions |
GET | 获取景点列表(支持 city/type/heat_level 筛选) |
/api/attractions/{id} |
GET | 获取单个景点详情 |
/api/attractions |
POST | 添加景点 |
/api/attractions/{id} |
PUT | 更新景点 |
/api/attractions/{id} |
DELETE | 删除景点 |
数据存储说明 :景点数据存储在 Excel 文件中,通过 Pandas DataFrame 在内存中操作。增删改操作会同步修改内存 DataFrame 并写回 Excel。行索引 index 作为唯一标识。
4.7.4 图表数据 API routers/api_charts.py
31 个 GET 端点,全部返回 JSON 数据:
| 端点 | 说明 |
|---|---|
/api/charts/summary |
KPI 汇总数据 |
/api/charts/city-visitors |
城市游客分布 |
/api/charts/city-map |
地图散点数据 |
/api/charts/type-distribution |
景点类型分布 |
/api/charts/heat-level |
热度等级分布 |
/api/charts/season |
季节分布 |
/api/charts/top-attractions |
Top 10 景点 |
/api/charts/price-visitors |
价格 vs 游客散点 |
/api/charts/city-metrics |
城市指标对比 |
/api/charts/star-distribution |
星级分布 |
/api/charts/influencer-review |
网红 vs 好评气泡 |
/api/charts/age-group |
年龄段分布 |
/api/charts/radar |
雷达图数据 |
/api/charts/city-total-visitors |
城市游客总量排行 |
/api/charts/manager-count |
负责人管理数量 |
/api/charts/open-days-visitors |
开放天数 vs 游客 |
/api/charts/guide-mentions |
攻略提及 Top N |
/api/charts/influencer-distribution |
网红指数分布 |
/api/charts/price-distribution |
价格区间分布 |
/api/charts/daily-tickets |
日均门票 Top N |
/api/charts/facilities |
配套设施分析 |
/api/charts/review-influencer-bubble |
好评 vs 网红气泡 |
/api/charts/city-type-stacked |
城市类型堆叠 |
/api/charts/heat-star-cross |
热度 x 星级交叉 |
/api/charts/age-group-city |
年龄段城市对比 |
/api/charts/season-heatmap |
季节热度热力图 |
/api/charts/price-by-type |
价格按类型分布 |
/api/charts/composite-score |
综合评分 Top N |
/api/charts/city-attraction-count |
城市景点数量 |
/api/charts/price-review-scatter |
价格 vs 好评散点 |
/api/charts/visitors-by-type |
类型游客量 |
/api/charts/hotel-restaurant-scatter |
酒店餐厅散点 |
/api/charts/sankey |
桑基图数据 |
/api/charts/type-visitor-treemap |
树状图数据 |
/api/charts/price-box |
箱线图数据 |
5. 前端详细设计
5.1 基础布局 base.html
采用 Molon Admin Template 的垂直布局:
- 顶栏(Topbar):Logo、全屏按钮、用户头像下拉菜单、设置按钮
- 侧边栏(Sidebar):用户头像卡片、导航菜单(数据看板、数据管理、数据分析子菜单、个人中心、用户管理)
- 主内容区 (Main Content):通过
{% block content %}子模板填充 - 右侧面板(Right Bar):亮色/暗色模式切换
脚本加载顺序:
- jQuery
- Bootstrap Bundle
- MetisMenu(侧边栏菜单)
- SimpleBar(自定义滚动条)
- Waves(点击波纹效果)
- Toastr(通知提示)
- SweetAlert2(确认对话框)
- common.js(TourismApp 全局对象)
- app.js(模板初始化)
- 子模板自定义脚本
5.2 全局工具对象 common.js
javascript
const TourismApp = {
getCookie(name) // 读取 Cookie
async apiGet(url) // GET 请求封装(自动处理 401 跳转)
async apiPost(url, data) // POST 请求封装
async apiPut(url, data) // PUT 请求封装
async apiDelete(url) // DELETE 请求封装
notify(type, message) // Toastr 通知
formatNumber(n) // 数字千分位格式化
chartColors // 图表调色板(10 色)
}
5.3 登录/注册页面
- 纯 CSS 渐变背景 + SVG 山水装饰
- 表单验证(前端):用户名至少 3 字符,密码至少 6 字符
- 密码可见性切换:点击眼睛图标在
type="password"和type="text"之间切换 - 注册成功后自动跳转登录页
- 登录成功后自动跳转看板页
5.4 数据看板 dashboard.html + dashboard-tourism.js
看板包含 13 行共 20+ 个图表:
| 行 | 图表 | 类型 | 库 | 容器 ID |
|---|---|---|---|---|
| KPI | 景点总数、月均游客、好评率、门票均价 | 数字卡片 | - | kpi-* |
| 2 | 景点分布地图 | 散点地图 | ECharts | chart_city_map |
| 2 | 热度等级分布 | 环形图 | ApexCharts | chart_heat_level |
| 3 | Top 10 景点 | 横向柱图 | ApexCharts | chart_top_attractions |
| 3 | 景点类型分布 | 饼图 | ApexCharts | chart_type_dist |
| 4 | 门票价格 vs 游客量 | 散点图 | ApexCharts | chart_price_visitors |
| 4 | 城市指标对比 | 双轴柱图 | ApexCharts | chart_city_metrics |
| 5 | Top 5 景点多维度分析 | 雷达图(改为柱图) | ECharts | chart_radar |
| 6 | 适宜游玩季节分布 | 柱图 | ApexCharts | chart_season |
| 6 | 景点星级分布 | 柱图 | ApexCharts | chart_star |
| 7 | 游客年龄段分布 | 饼图 | ApexCharts | chart_age_group |
| 7 | 各城市景点数量 | 柱图 | ApexCharts | chart_city_count |
| 8 | 各类型景点游客量 | 双轴图 | ApexCharts | chart_visitors_type |
| 8 | 门票价格 vs 好评率 | 散点图 | ApexCharts | chart_price_review |
| 9 | 各城市景点类型分布 | 堆叠柱图 | ECharts | chart_city_type_stacked |
| 9 | 季节 x 热度等级热力图 | 热力图 | ECharts | chart_season_heatmap |
| 10 | 综合评分 Top 10 | 柱图 | ECharts | chart_composite_score |
| 10 | 城市配套设施 | 气泡图 | ECharts | chart_hotel_restaurant |
| 11 | 景点热度等级漏斗 | 漏斗图 | ECharts | chart_funnel |
| 11 | 平均好评率仪表盘 | 仪表盘 | ECharts | chart_gauge |
| 12 | 城市→类型→热度 桑基图 | 桑基图 | ECharts | chart_sankey |
| 13 | 类型×城市 游客量树状图 | 树状图 | ECharts | chart_treemap |
| 13 | 各类型门票价格分布 | 分组柱图 | ECharts | chart_price_by_type |
图表配色方案:
javascript
const C = {
blue: '#0f9cf3', green: '#1cbb8c', gold: '#fcb92c',
red: '#f32f53', purple: '#6f42c1', teal: '#17a2b8',
orange: '#fd7e14', pink: '#e83e8c', blueL: '#4aa3ff', greenL: '#6fd088'
};
热度等级颜色:顶流 = 绿色,热门 = 红色,一般 = 金色
5.5 数据管理页面 data_table.html + datatable-tourism.js
- DataTables 配置:14 列(含隐藏索引列和操作按钮列)
- 筛选功能:城市、景点类型、热度等级三个下拉框
- 分页:每页 15 条,支持 10/15/25/50 切换
- 操作按钮:编辑(弹出 Modal)、删除(SweetAlert2 确认)
- 添加/编辑 Modal:17 个表单字段,包含下拉选择和数字输入
- 所有数据变更后自动从后端重新加载完整数据
DataTable 列定义:
| 列 | 字段 | 说明 |
|---|---|---|
| 0 | 景点名称 | 文本 |
| 1 | 景点类型 | 文本 |
| 2 | 所在城市 | 文本 |
| 3 | 负责人 | 文本 |
| 4 | 星级 | 数字 + "星" 后缀 |
| 5 | 月均游客 | 千分位格式化 |
| 6 | 日均门票 | 千分位格式化 |
| 7 | 好评率 | 数字 + "%" 后缀 |
| 8 | 门票价格 | "¥" 前缀 |
| 9 | 热度 | Badge 标签(绿/红/黄) |
| 10 | 季节 | 文本 |
| 11 | 网红指数 | 数字 |
| 12 | 索引 | 隐藏列 |
| 13 | 操作 | 编辑/删除按钮 |
5.6 分析页面
5 个专题分析页面,每个页面有独立的 JS 文件:
| 页面 | 文件 | 分析内容 |
|---|---|---|
| 概览分析 | analysis-overview.js | KPI + 类型分布 + 热度分布 + 星级分布 |
| 城市分析 | analysis-city.js | 城市游客量 + 城市景点数 + 城市指标 |
| 价格分析 | analysis-price.js | 价格分布 + 价格 vs 游客 + 按类型价格 |
| 游客分析 | analysis-visitor.js | 年龄段 + 网红指数 + 好评率分析 |
| 季节分析 | analysis-season.js | 季节分布 + 季节热力图 |
5.7 CSS 设计系统 tourism-custom.css
采用"云山意境"设计语言:
CSS 变量:
- 翡翠色系(Jade):
--jade-900~--jade-100,用于主色调 - 金色系(Gold):
--gold-600~--gold-200,用于强调色 - 奶油色系(Cream):
--cream-100~--cream-400,用于背景 - 墨色系(Ink):
--ink-900~--ink-300,用于文字
组件样式:
- KPI 卡片:玻璃态背景 + 渐变边框动画 + 悬停上浮
- 图表卡片:简洁白底 + 渐变顶栏装饰 + 悬停阴影
- 数据表格:暖色调行悬停 + 圆角分页
- 按钮:翡翠绿主色 + 金色强调
- 表单:奶油色背景 + 焦点翡翠色边框
- 登录页:深翡翠渐变背景 + SVG 山水装饰
- 侧边栏:深林渐变 + 山脉剪影 + 光晕装饰
- 顶栏:毛玻璃效果 + 半透明白色
6. 数据结构
6.1 景点数据字段(Excel)
| 字段名 | 类型 | 说明 |
|---|---|---|
| 景点名称 | str | 景点唯一名称 |
| 景点类型 | str | 自然景观/古镇古村/历史古迹/主题乐园/现代建筑 |
| 所在城市 | str | 北京/上海/成都/重庆/大理/厦门/青岛/西安/杭州/三亚 |
| 景点负责人 | str | 负责人姓名 |
| 景点星级 | int | 1-5 星 |
| 月均游览人次 | int | 月均游客数量 |
| 日均门票销量 | int | 日均门票销售数量 |
| 游客好评率 | int | 好评百分比(0-100) |
| 门票价格 | int | 人民币元 |
| 周边酒店数量 | int | 周边酒店数量 |
| 周边餐厅数量 | int | 周边餐厅数量 |
| 月开放天数 | int | 每月开放天数(1-31) |
| 攻略提及次数 | int | 旅游攻略中被提及次数 |
| 网红打卡指数 | float | 网红打卡指数(0-10) |
| 适宜游玩季节 | str | 春季适宜/夏季适宜/秋季适宜/冬季适宜/四季适宜 |
| 游客年龄段占比 | int | 主力年龄段占比 |
| 热度等级 | str | 顶流/热门/一般 |
6.2 城市坐标映射
python
city_coords = {
"北京": [116.46, 39.92],
"上海": [121.48, 31.22],
"成都": [104.06, 30.67],
"重庆": [106.54, 29.59],
"大理": [100.19, 25.69],
"厦门": [118.10, 24.46],
"青岛": [120.33, 36.07],
"西安": [108.95, 34.27],
"杭州": [120.19, 30.26],
"三亚": [109.51, 18.25],
}
7. 安全设计
7.1 认证机制
- JWT Token:登录成功后生成 HS256 签名的 JWT,包含 user_id 和过期时间
- Cookie 存储:Token 存储在 httponly Cookie 中,防止 XSS 窃取
- 过期控制:Token 24 小时过期,过期后自动跳转登录页
- 密码存储:使用 SHA256 哈希(注意:生产环境建议使用 bcrypt)
7.2 权限控制
- 普通用户:可访问看板、分析页面、个人中心
- 管理员:额外可访问数据管理、用户管理
- 页面级 :
pages.py中每个路由检查登录状态和管理员权限 - API 级 :
require_admin()函数验证管理员权限
7.3 数据安全
- Excel 文件直接读写(适合小型项目,生产环境建议使用数据库)
- 文件上传限制为图片类型
- CORS 配置允许所有来源(开发环境,生产环境应限制)
8. 部署与运行
8.1 环境要求
- Python 3.9+
- pip(Python 包管理)
- Node.js(可选,仅用于 ECharts npm 包)
8.2 安装依赖
bash
pip install -r requirements.txt
依赖清单:
fastapi==0.104.1
uvicorn[standard]==0.24.0
jinja2==3.1.2
python-multipart==0.0.6
pandas==2.1.4
openpyxl==3.1.2
python-jose[cryptography]==3.3.0
8.3 启动服务
bash
cd tourism
python main.py
服务默认运行在 http://localhost:8000,支持热重载(reload=True)。
8.4 访问系统
- 浏览器打开
http://localhost:8000 - 首次使用需注册账号(第一个注册的用户自动成为管理员)
- 登录后进入数据看板
9. 外部资源依赖
9.1 已本地化的资源
| 资源 | 原始来源 | 本地路径 |
|---|---|---|
| Material Design Icons CSS | themesdesign.in | /static/css/icons-local.min.css |
| Material Design Icons 字体 | cdnjs.cloudflare.com | /static/font/materialdesignicons-webfont.* |
| ECharts 5.4.3 | cdn.jsdelivr.net | /static/js/echarts.min.js |
| ApexCharts | cdn.jsdelivr.net | /static/js/apexcharts.min.js |
9.2 本地静态文件
| 文件 | 说明 |
|---|---|
/static/css/bootstrap.min.css |
Bootstrap 4 |
/static/css/app.min.css |
Molon 模板样式 |
/static/js/jquery.min.js |
jQuery |
/static/js/bootstrap.bundle.min.js |
Bootstrap Bundle |
/static/js/metisMenu.min.js |
侧边栏菜单 |
/static/js/simplebar.min.js |
自定义滚动条 |
/static/js/waves.min.js |
点击波纹 |
/static/js/toastr.min.js |
通知提示 |
/static/js/sweetalert2.min.js |
确认对话框 |
/static/js/jquery.dataTables.min.js |
DataTables |
10. 已知问题与优化建议
10.1 已知问题
| 问题 | 说明 |
|---|---|
| 密码哈希使用 SHA256 | 生产环境建议改用 bcrypt |
| Excel 作为数据存储 | 不支持并发写入,建议迁移到 SQLite 或 PostgreSQL |
| CORS 全开 | 生产环境应限制允许的来源 |
| 无单元测试 | 建议添加 pytest 测试用例 |
10.2 优化建议
| 方向 | 建议 |
|---|---|
| 数据存储 | 将 Excel 迁移到 SQLite/PostgreSQL,支持并发和事务 |
| 缓存 | 对图表数据 API 添加 Redis 缓存,减少重复计算 |
| 前端 | 考虑迁移到 Vue.js/React 实现 SPA |
| 部署 | 使用 Docker 容器化,配合 Nginx 反向代理 |
| 监控 | 添加日志记录和错误监控 |
| 测试 | 添加后端 API 测试和前端 E2E 测试 |
11. 关键设计决策记录
| 决策 | 原因 |
|---|---|
| 使用 FastAPI 而非 Flask | FastAPI 原生支持 async、自动文档生成、Pydantic 校验 |
| Excel 而非数据库存储景点数据 | 数据量小、方便非技术人员直接编辑 |
| ECharts + ApexCharts 混用 | ECharts 擅长地图/桑基/漏斗等复杂图表,ApexCharts 擅长常规统计图表 |
| JWT Cookie 而非 localStorage | httponly Cookie 防止 XSS 攻击 |
| 全部本地化静态资源 | 避免外部 CDN 访问慢或不可用导致页面加载失败 |
| SHA256 密码哈希 | 实现简单,适合演示项目(生产环境应使用 bcrypt) |
| 首用户自动成为管理员 | 简化初始化流程,无需手动配置 |