Files
UploaderHui/NAS图片上传系统_开发文档.md
2026-04-18 15:08:57 +08:00

11 KiB
Raw Permalink Blame History

NAS图片上传系统 - 开发文档

版本v0.3
日期2026-04-17
状态:需求已确认,待开发


1. 项目概述

1.1 项目背景

需要搭建一个简单的Web应用允许用户通过手机或电脑访问网站将图片上传到本地NAS存储中。网站部署在公网实例上通过内网穿透转发请求到本地NAS。

1.2 核心需求

  • 用户通过手机/电脑浏览器访问网站,选择目标文件夹后上传图片
  • 支持多选图片上传,带上传进度条显示
  • 上传完成后显示成功上传的图片列表,方便用户确认是否全部上传成功
  • 文件夹结构训练营N期 → 25个班级文件夹用户只能选择不能创建
  • 文件夹自动创建:首次上传时若目标文件夹不存在则自动创建
  • 每个训练营文件夹下有一个MD文档统计图片数量
  • 无需登录,公开使用(后续考虑加密码保护)
  • 仅上传功能,不提供图片浏览/下载
  • 图片主要为屏幕截图

1.3 网络架构

公网实例通过内网穿透frp将请求转发到本地NAS上的服务。服务端直接运行在群晖NAS上。

用户手机/电脑 → 公网实例frp → 内网穿透 → NAS服务端

2. 技术方案

2.1 技术栈

层次 技术选型 说明
后端框架 Python + Flask 轻量、开发快、文件操作方便NAS环境通常支持Python
前端 HTML + CSS + JavaScript 纯静态页面,无需前端构建工具,部署简单
图片上传 XMLHttpRequest 原生支持上传进度事件
文件存储 NAS本地文件系统 直接读写NAS磁盘目录
内网穿透 frp 将公网请求转发到内网服务
配置管理 .env 文件 部署时填写NAS路径、端口等配置

3. 系统架构

3.1 整体架构

┬── 用户手机/电脑(浏览器)
│
├── 公网实例frp server
│
├── frp client → 内网穿透
│
└── 群晖 NASFlask + 静态文件)
     ├── /api/folders      获取文件夹列表
     ├── /api/upload        上传图片
     ├── /static/           前端静态资源
     └── {NAS_DATA_PATH}/   NAS存储目录.env配置

3.2 NAS目录结构

{NAS_DATA_PATH}/                    ← 通过 .env 配置
├── 训练营13期/
│   ├── 统计.md                  ← 图片数量统计文档
│   ├── 1班/
│   ├── 2班/
│   ├── ...
│   └── 25班/
├── 训练营14期/
│   ├── 统计.md
│   ├── 1班/
│   ├── ...
│   └── 25班/
└── ...

3.3 服务端项目结构

nas-uploader/
├── app.py                  ← Flask主应用
├── config.py               ← 读取 .env 配置
├── .env                    ← 部署配置NAS路径、端口等
├── .env.example            ← 配置示例文件
├── requirements.txt        ← Python依赖
├── static/
│   ├── css/style.css      ← 样式文件
│   ├── js/app.js          ← 前端逻辑
│   └── img/               ← 图标等静态资源
├── templates/
│   └── index.html         ← 主页面
└── start.sh               ← 启动脚本

3.4 .env 配置文件

# NAS图片存储根目录部署时修改为实际路径
NAS_DATA_PATH=/volume1/nas_data

# 服务端口
PORT=5000

# 允许的图片格式(小写,逗号分隔)
ALLOWED_EXTENSIONS=jpg,jpeg,png,gif,webp

# 单次上传最大文件数量
MAX_FILES_COUNT=100

# 单张图片最大大小MB
MAX_FILE_SIZE_MB=20

4. 功能设计

4.1 文件夹选择功能

4.1.1 文件夹获取规则

  • 后端扫描NAS根目录NAS_DATA_PATH),读取所有"训练营*期"格式的文件夹
  • 每个训练营文件夹下,读取所有"*班"格式的子文件夹
  • 前端以两级联动选择器展示:第一级选训练营,第二级选班级
  • 文件夹列表按名称排序(数字自然排序)
  • 不显示各班级已有图片数量

4.1.2 文件夹自动创建

  • 当用户选择某个班级并上传图片时,若对应的文件夹不存在,则自动创建
  • 创建逻辑:检查训练营文件夹 → 检查班级文件夹 → 不存在则创建
  • 同时创建对应的统计.md文档若训练营文件夹是新建的
  • 新的"训练营N期"文件夹由管理员在NAS上手动创建,用户不能通过网页创建新训练营

4.2 图片上传功能

4.2.1 上传流程

用户选择文件夹 → 点击"选择图片"按钮 → 多选图片 → 点击"开始上传"
  • 支持的图片格式JPG、JPEG、PNG、GIF、WEBP不支持HEIC
  • 单次上传数量限制最多100张
  • 单张大小限制20MB
  • 采用逐张上传策略,每张图片独立显示进度,同时显示总体进度

4.2.2 图片命名规则

上传后图片按以下格式重命名:

训练营{n}期-{x}班-{时间戳}-{随机数}.{扩展名}

示例:

训练营13期-1班-20260417143022-a3f8b2.png
训练营13期-1班-20260417143022-7c2e91.jpg
  • {n}:训练营期数
  • {x}:班级编号
  • {时间戳}:精确到秒,格式 YYYYMMDDHHmmss
  • {随机数}6位十六进制随机字符串
  • {扩展名}:保留原始文件的扩展名
  • 若文件名已存在(极低概率),自动在末尾追加序号:-a3f8b2-1.png

4.2.3 上传进度显示

  • 总体进度条:显示已上传完成的数量 / 总数量
  • 单张进度条:每张图片的上传百分比
  • 状态标识:等待中 / 上传中 / 成功 / 失败

4.2.4 上传完成反馈

  • 上传成功后,页面底部显示"已成功上传"图片缩略图列表
  • 每张图片显示:缩略图 + 新文件名 + 上传状态
  • 失败的图片明确标红,显示失败原因,支持"重试"操作
  • 显示摘要信息:"成功上传15张失败 1张"

4.3 图片统计功能

4.3.1 统计.md格式

每个训练营文件夹下的统计.md内容格式如下

# 训练营XX期 图片统计

更新时间2026-04-17 14:30:00
图片总数156

| 班级 | 图片数量 |
|------|----------|
| 1班  | 12       |
| 2班  | 8        |
| ...  | ...      |
| 25班 | 6        |

4.3.2 统计更新触发

  • 每次上传成功后,自动更新对应训练营的统计.md
  • 统计方式:扫描训练营文件夹及其所有子目录,统计图片文件数量
  • 图片文件判定根据文件扩展名jpg、jpeg、png、gif、webp
  • 更新时间记录在文档头部

5. API设计

5.1 获取文件夹列表

GET /api/folders

返回所有训练营及其下的班级文件夹。

响应示例:

{
  "folders": [
    {
      "name": "训练营13期",
      "classes": ["1班", "2班", "3班", "4班", "5班", "...", "25班"]
    },
    {
      "name": "训练营14期",
      "classes": ["1班", "3班"]
    }
  ]
}

5.2 上传图片

POST /api/upload

接受multipart/form-data格式的图片上传。

请求参数:

参数名 类型 必填 说明
folder string 训练营名称,如"训练营13期"
class string 班级名称,如"1班"
files File[] 图片文件数组,支持多文件

响应示例:

{
  "success": true,
  "uploaded": [
    { "filename": "训练营13期-1班-20260417143022-a3f8b2.png", "status": "success" },
    { "filename": "训练营13期-1班-20260417143023-7c2e91.jpg", "status": "success" }
  ],
  "failed": [
    { "filename": "photo3.bmp", "status": "failed", "reason": "文件格式不支持" }
  ]
}

6. 前端页面设计

6.1 页面布局

页面采用简洁的单页设计,适配手机和电脑访问(响应式布局)。

页面从上到下分为三个区域:

6.1.1 顶部:文件夹选择区

  • 第一行:下拉选择"训练营"(如"训练营13期"
  • 第二行:下拉选择"班级"(如"1班"
  • 班级列表根据选中的训练营动态加载

6.1.2 中部:图片选择和上传区

  • "选择图片"按钮:触发文件选择器,支持多选
  • 已选择的图片列表:显示缩略图、文件名、可删除
  • "开始上传"按钮:触发上传操作
  • 进度条:总体进度 + 单张进度

6.1.3 底部:上传结果区

  • 显示成功上传的图片缩略图网格
  • 失败的图片显示红色标记和"重试"按钮
  • 显示摘要信息:"成功上传15张失败 1张"

6.2 移动端适配

  • 采用响应式设计,自动适配手机和电脑屏幕
  • 手机端优化:按钮大小适中触摸操作,图片缩略图网格自动调整列数
  • 支持手机原生图片选择器accept="image/*"

7. 部署方案

7.1 frp内网穿透配置

详见 frp内网穿透_原理与部署指南.md

frpc.tomlNAS侧关键配置

serverAddr = "你的公网IP"
serverPort = 7000
auth.token = "你的认证密码"

[[proxies]]
name = "nas-uploader"
type = "tcp"
localIP = "127.0.0.1"
localPort = 5000
remotePort = 8080

7.2 服务启动

#!/bin/bash
# start.sh
cd /path/to/nas-uploader
source venv/bin/activate    # 可选:使用虚拟环境
python app.py

7.3 部署步骤

  1. 将项目文件上传到群晖NAS
  2. 复制 .env.example.env,修改 NAS_DATA_PATH 为实际的共享文件夹路径
  3. 安装Python依赖pip install -r requirements.txt
  4. 启动服务:bash start.sh
  5. 配置frpc客户端连接到公网服务器
  6. 浏览器访问 http://公网IP:8080 验证

8. 开发计划

阶段 内容 预估工时
第一阶段 后端基础Flask服务 + .env配置 + API + 文件操作 2-3小时
第二阶段 前端页面:文件夹选择 + 图片上传 + 进度条 + 结果展示 2-3小时
第三阶段 统计功能:自动更新统计.md 1小时
第四阶段 优化:移动端适配 + 异常处理 + 测试 1-2小时
第五阶段 部署frp配置 + 群晖NAS部署 + 服务上线 0.5小时

9. 风险与注意事项

  • 并发上传:多用户同时上传到同一文件夹时,文件名含时间戳+随机数,冲突概率极低;若冲突则自动追加序号
  • 存储空间需关注NAS磁盘空间建议在上传前检查剩余空间
  • 网络稳定性:内网穿透可能因网络波动导致上传中断,需支持失败重试
  • 安全性:当前公开访问无需登录,后续考虑加密码保护;后端必须验证文件类型防止恶意上传
  • 文件类型验证后端严格校验文件扩展名和MIME类型防止上传非图片文件

10. 后续规划(暂不实现)

  • 访问密码保护
  • HTTPS 加密传输
  • 图片浏览/下载功能
  • 管理后台