Files
wenchuanyi/需求文档.md
T
fanhongcai 01c9cc2330 docs: 鏇存柊闇€姹傛枃妗h嚦v0.5骞跺綊妗e紑鍙戣繘搴︼紱淇澶ф枃浠朵笂浼犱笌浜岀淮鐮佹捣鎶?
- 闇€姹傛枃妗e崌绾у埌 v0.5锛氳ˉ鍏呬簩缁寸爜娴锋姤淇濆瓨鏂囦欢鍚嶉粯璁ゆ牸寮忋€佸ぇ鏂囦欢涓婁紶涓夊眰闄愬埗锛圛IS+ASP.NET+鍓嶇锛夐儴缃茬害鏉熴€佹柊澧炵11绔犲紑鍙戣繘搴︾姸鎬佸綊妗o紙宸蹭笂绾垮姛鑳?宸蹭慨澶嶇己闄?宸茬煡闄愬埗/鍚庣画浼樺寲锛?- 鍚庣 FileController.Upload 澧炲姞 [RequestFormLimits(MultipartBodyLengthLimit=220_200_960)]锛屼慨澶?128MB multipart 涓婁紶琚嫆
- 鍓嶇 UploadView 浜岀淮鐮佹捣鎶ワ細淇 drawImage 缂╂斁閿欎綅銆侀《閮╨ogo/鏍囬鍨傜洿灞呬腑銆佸垎鍖烘爣棰橀棿璺濄€佸ぇ灏忎笌鏈夋晥鏈熷垎琛屾樉绀猴紱淇濆瓨鏂囦欢鍚嶆敼涓?鏂囦紶鏄撳彇浠剁爜-鍙栦欢鐮?鍘熸枃浠跺悕)-娴佹按鍙?png
- 鏂板閮ㄧ讲鑴氭湰锛歛pply_backend.ps1 / force_dll.ps1锛坅pp_offline 瑙i攣DLL锛? ftp_fe.ps1 / ftp_diag.ps1 / ftp_apply.ps1 / _diag/check_dll.ps1

(閮ㄧ讲鎵嬪唽 IIS閮ㄧ讲涓嶧TP鍙戝竷.md 浠呭惈缂栫爜/BOM 宸紓锛屾湭绾冲叆鏈鎻愪氦)
2026-08-24 01:59:27 +08:00

387 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 文传易 · 需求文档
> **文档版本**v0.5
> **创建日期**2026-08-23
> **更新日期**2026-08-24
> **文档状态**:已上线(前后端已实现、本地冒烟测试通过、已部署至正式站 `https://wenchuanyi.bbitcn.net`;累计修复:大文件上传 135MB 失败、二维码海报排版、保存文件名带原文件名)
> **技术栈**.NET 8 + FreeSql + MySQL(后端)| Vue 3 + Vite + TypeScript + TDesign(前端)
> **正式站**https://wenchuanyi.bbitcn.net(中文名「文传易」)
---
## 1. 项目概述
### 1.1 项目背景
「文传易」是一个匿名临时文件传输网站(类似文叔叔 / 奶牛快传 / tmp.link):
发送者无需注册登录即可上传文件,系统生成**取件凭证**;将凭证发给收件人后,收件人凭凭证即可下载文件。
适用于"想传文件给对方、但不想注册 / 登录 / 加好友"的场景。
### 1.2 项目目标
- 实现"上传 → 取件凭证 → 凭码下载"的完整闭环,全流程匿名、中文界面。
- 单文件传输,操作尽量简单:3 步完成(加入文件 → 上传 → 发码)。
- **二维码 + 取件码两种分享方式**:上传成功后生成二维码(内容为取件页链接,扫码自动进入下载页并填入取件码)——二维码发给新用户、取件码发给熟悉用户。
- 支持大段文字粘贴生成 txt 传递(**文件名 = 文字前 12 位 + 日期时间**);常见格式(文本/PDF/图片/音视频)支持在线预览与下载。
### 1.3 术语定义
| 术语 | 定义 |
| --- | --- |
| 发送者 | 上传文件的一方,匿名,不登录 |
| 收件人 | 凭取件凭证下载文件的一方,匿名,不登录 |
| 共享文件 | 不设密码/标签的文件类型,取件码为 **8 位纯数字** |
| 私密文件 | 设置 4-12 位密码的文件类型(**可同时设置标签**),取件码为 **6 位纯数字**,下载需校验密码 |
| 标签文件 | 设置标签的文件类型(**可同时设置密码**);**一个标签可关联多个文件**,输入标签后展示该标签下的文件列表;含标签的文件永久保存 |
| 取件码 | 上传成功后生成的下载凭证:共享文件 **8 位纯数字**、私密文件 **6 位纯数字**,输入时按位数实时识别(8 位 = 共享,6 位 = 私密) |
| 标签 | 标签文件的取件凭证,**仅允许英文(A-Za-z)与数字、不含任何符号**;纯数字须 >8 位(推荐 11 位手机号)、含英文字母须 >4 位;同一标签可关联多个文件,不要求唯一 |
| 管理码 | 发送者管理已上传文件的凭证,8 位字母数字;**不提供找回**,仅展示一次 |
| 有效期 | 文件可被下载的时间范围,**固定三档**:24 小时 / 7 天 / 永久 |
| 取件页链接 | 前端取件页地址,格式 `{BaseUrl}/#/pickup?code=xxx`,用于二维码/分享链接,扫码自动填入取件码 |
| 二维码 | 上传成功后前端本地生成的分享码,内容为取件页链接(仅含取件码、不含敏感信息),可下载/长按转发 |
---
## 2. 用户与角色
### 2.1 角色
| 角色 | 说明 | 是否登录 |
| --- | --- | --- |
| 发送者 | 上传文件、复制取件凭证/管理码、凭管理码管理 | 否(匿名) |
| 收件人 | 凭取件码/标签查询并下载文件 | 否(匿名) |
| 运维人员 | 部署 IIS、FTP 发布、配置数据库连接串与 OSS 凭据 | 系统后台 |
### 2.2 核心使用场景
1. **快速传文件**:同事/朋友间临时传文件,发送者上传后把**二维码**(新用户)或**取件码**(熟悉用户)通过微信/短信发给对方,对方扫码/输码下载。
2. **大段文字传递**:需要把一段很长的文字(如代码、会议纪要、账号信息)传给对方,直接粘贴文字生成 txt(文件名 = 文字前 12 位 + 日期时间)上传,对方在线阅读或下载。
3. **标签批量投递**:给同一对象传多个文件(如以手机号 `13800138000` 为标签),收件人输入该标签即可看到全部文件,逐个查看/下载。
4. **发送者管理**:想查看自己传过哪些文件、被下载几次(**仅统计、不限制**),或删除不再需要的文件,凭管理码操作。
---
## 3. 核心业务流程
### 3.1 发件流程(上传)
1. 发送者进入首页 → 通过任意方式加入文件:
- **拖拽**文件到上传区;
- **复制文件后 Ctrl+V 粘贴**上传;
- **点击选择**(打开文件夹直接选中文件);
- **粘贴一段文字** → 自动生成 .txt 文件上传,**文件名 = 文字前 12 位 + 日期时间**(`{文字前12位}_{yyyyMMdd_HHmmss}.txt`;剔除 `\/:*?"<>|` 等 Windows 非法文件名字符,剔除后为空用「文本」兜底),不提供自定义命名;
2. 选择有效期:**固定三档 24 小时 / 7 天 / 永久**(无自定义时长);
3. 按需设置**密码(4-12 位)**与**标签(仅英文+数字)**,**两者可同时设置、不互斥**;均不设置则默认为共享文件:
- **共享文件**:不设密码与标签 → **8 位数字取件码**
- **私密文件**:设置密码(可同时设置标签)→ **6 位数字取件码**(下载需密码);
- **标签文件**:设置标签(可同时设置密码)→ **标签即取件凭证**,同一标签可关联多个文件;
- **含标签的文件有效期强制「永久」**(无论是否同时设置密码);
4. 点击上传 → 系统保存文件并生成取件凭证 + 管理码:
- 无密码无标签 → **8 位数字取件码**(共享文件);
- 设密码(可有标签)→ **6 位数字取件码**(私密文件,下载需密码);
- 仅设标签 → **标签即取件凭证**(标签文件,可关联多个文件,永久保存);
5. 页面展示凭证卡片:**二维码**(取件页链接,扫码直达下载页并自动填码,可下载/长按转发)+ 大号取件凭证 + 一键复制;下方可收起的管理码 + 复制;并提示"二维码发给新用户、取件码发给熟悉用户"。
### 3.2 取件流程(下载)
1. 收件人进入取件页 → 输入取件凭证(取件码或标签),或直接扫码(URL `?code=` 参数自动填入并查询);
2. 系统识别类型并校验:8 位纯数字 → 共享文件;6 位纯数字 → 私密文件(需输入密码);**满 7 位纯数字 → 提示"取件码为 6 位或 8 位,请继续输入完整取件码",不自动查询、等用户继续输入或修正**;非纯数字 → 按**标签**查询文件列表;
3. 校验通过后展示文件信息(名称、大小、剩余有效期)→ 【在线预览】【下载】;标签查询展示该标签下文件列表(按上传时间倒序),逐项【在线预览】【下载】【删除】(列表项为私密文件时,下载/预览需输入该文件密码)。
### 3.3 管理流程(发送者)
1. 输入管理码 → 查看该管理码下的文件列表(文件名、大小、过期时间、下载次数、**上传 IP**);
2. 可删除指定文件(删除后取件凭证立即失效);标签文件也可在取件页标签列表凭管理码删除。
---
## 4. 功能需求
> 优先级:P0 = 必须|P1 = 应当|P2 = 可选
### 4.1 上传功能
- [P0] 文件格式**不限制**;对可执行/脚本类文件(如 .exe/.bat/.sh/.dll)上传时展示"可执行文件风险提示"
- [P0] 多种方式加入文件:
- 拖拽文件到上传区(拖入高亮);
- 复制文件后 **Ctrl+V 粘贴**上传;
- 点击打开文件夹选择**单个**文件;
- **粘贴一段文字** → 自动生成 .txt 文件上传,**文件名 = 文字前 12 位 + 日期时间**(`{文字前12位}_{yyyyMMdd_HHmmss}.txt`;剔除 `\/:*?"<>|` 等 Windows 非法文件名字符,剔除后为空用「文本」兜底),**不提供自定义命名**
- [P0] 上传前展示文件名、大小;超限文件前端拦截并提示
- [P0] 有效期选择:**固定三档**——默认 **24 小时**,可选 **7 天 / 永久**(无自定义时长);**设置标签(无论是否同时设置密码)时强制「永久」**(隐藏有效期选择器)
- [P0] 文件模式(**密码与标签可同时设置、不互斥**,上传时按设置自动识别):
| 模式 | 触发条件 | 取件凭证 | 下载要求 |
| --- | --- | --- | --- |
| 共享文件 | 不设密码与标签 | **8 位数字取件码**(全局唯一) | 输入取件码即可下载 |
| 私密文件 | 设置 **4-12 位密码**(可同时设置标签) | **6 位数字取件码**(全局唯一) | 取件码 + 密码校验 |
| 标签文件 | 设置**标签**(仅英文+数字,可同时设置密码) | **标签即取件凭证**,同一标签可关联多个文件 | 输入标签 → 展示该标签下的文件列表(带密码项需密码) |
> **同时设置密码与标签**:按私密文件识别(6 位取件码,下载需密码),且因含标签强制永久保存(`IsPermanent=true`)。
- [P0] **密码与标签不互斥、可同时设置**:密码与标签为两个独立输入项,互不影响;同时设置时按私密文件(6 位取件码)识别,且因含标签有效期强制永久
- [P0] **标签规则**:仅允许英文(A-Za-z)与数字,不含任何符号(中划线/下划线/空格/汉字等均不允许);**纯数字须 >8 位**(≥9,推荐 11 位手机号,输入时提示"建议使用手机号码");**含英文字母须 >4 位**(≥5);前端实时校验并给出中文提示,后端同规则兜底(400 明确报错)
- [P0] 通过取件码位数识别文件类型:**8 位 = 共享文件,6 位 = 私密文件**;取件码全局不重复
- [P0] 上传成功返回:取件凭证(取件码或标签)+ 管理码(8 位字母数字)+ 文件信息
- [P0] **二维码分享**:上传成功后前端用 `qrcode` 库本地生成二维码(内容为取件页链接 `{BaseUrl}/#/pickup?code=xxx`,仅含取件码、不含敏感信息),与取件码同卡片展示,可下载/长按转发
- [P0] **二维码海报保存**:点击"保存二维码"时前端将成功卡片合成为一张 PNG 海报(含品牌条、下载方式、文件信息卡、取件码、二维码);**保存文件名默认格式**为 `文传易取件码-取件码(原文件名)-流水号.png`(原文件名清洗 Windows 非法字符 `\/:*?"<>|`,空名兜底「未命名」)
- [P0] 取件码 / 管理码一键复制
- [P1] 上传进度百分比展示
- [P2] 上传失败一键重试
### 4.2 取件下载功能(输入时实时识别)
- [P0] 取件凭证输入框**实时联动识别**(输入内容为纯数字时):
- 输入满 **6 位** → 识别为**私密文件**,显示【密码输入框】;密码输入满 **4 位**后显示【下载】按钮;
- 继续输入到 **7 位** → 显示提示"**取件码为 6 位或 8 位,请继续输入完整取件码**",不自动查询,等用户继续输入或修正;
- 输入满 **8 位** → 识别为**共享文件**,显示【下载】按钮;单击后加载文件信息并启动下载;
- [P0] 非纯数字输入(英文 / 数字混合)→ 按**标签**查询:输入标签后点击查询/回车,加载**该标签下的文件列表**(按上传时间倒序),逐项展示文件名/大小/上传时间,可对任一项【在线预览】【下载】【删除】(**列表项为私密文件(带密码)时,下载/预览需输入该文件密码**);无文件时提示"该标签下暂无文件"
- [P0] 私密文件下载必须校验密码,密码错误提示"密码错误"
- [P0] 凭码下载还原原始文件名(含中文/特殊字符);**下载次数仅统计、不限制**(`download_count` 只累加展示,不拦截下载)
- [P0] 已过期提示"文件已过期";凭证不存在提示"取件码/标签无效"
- [P0] **在线预览**(取件结果提供【在线预览】【下载】双操作,预览不计下载次数):
- 文本类(txt / md / xml / json 等)→ 在线直接阅读文字 + 下载,**上限 2MB**(超限仅提供下载);
- PDF → 在线阅读 + 下载;
- 图片类(jpg / png / gif / webp 等)→ 在线查看 + 下载,**上限 30MB**(超限提示"文件过大,请下载后查看");
- 音视频 → 在线播放 + 下载,**不设大小上限**(流式播放);**格式白名单**:视频 mp4(H.264/AAC,兼容性最佳)/ webm,音频 mp3 / wav / m4a / aac / ogg;非白名单格式前端提示下载查看
- [P1] 展示剩余有效期、文件大小
- [P1] 展示下载次数(仅统计)
### 4.3 发送者管理功能
- [P0] 凭管理码查看自己的文件列表(文件名/大小/过期时间/下载次数/**上传 IP**)
- [P0] 删除文件(需二次确认);标签文件删除在取件页标签列表凭管理码触发
- [P1] 展示下载次数(**仅统计不限制**)/ 剩余有效期 / 上传时间
### 4.4 过期与清理
- [P0] 过期文件自动清理(**OSS 对象 + 数据库记录**,先删记录再删 OSS 对象),取件凭证失效**即时生效**(查询/下载时懒检查)
- [P1] 后台定时任务兜底清理(每 30 分钟,仅扫描 `IsPermanent = false` 且已过期的记录;**含标签的文件永久保存、不参与自动过期**)
- [P0] **含标签的文件永久保存**:设置标签(无论是否同时设置密码)上传时有效期强制「永久」(前端隐藏有效期选择器,后端落库 `IsPermanent=true``ExpiresAt=null`),由上传者凭管理码主动删除
---
## 5. 非功能需求
### 5.1 性能
- 单文件大小上限:**200MB**(前端上传前拦截 + 服务端双重校验,Kestrel 请求上限 210MB 留余量)
- 大文件上传依赖三道限制**一致放开**,否则请求在到达应用前被拦(日志无记录):
1. **前端**`axios` 配置 `maxContentLength` / `maxBodyLength` 放开(上传前另有 200MB 拦截提示);
2. **IIS 请求过滤**:站点 `web.config` 需含 `<security><requestFiltering><requestLimits maxAllowedContentLength="220200960"/></requestFiltering></security>`~210MBIIS 默认 30MB);
3. **ASP.NET Core multipart**`FileController.Upload` 需同时有 `[RequestSizeLimit(220_200_960)]``[RequestFormLimits(MultipartBodyLengthLimit = 220_200_960)]`multipart 默认 128MB,缺 `RequestFormLimits` 会拒 >128MB 上传)。
- 上传 / 下载全程流式 I/O,内存占用恒定,不整体读入内存
- 下载附带 `Content-Length` + `Accept-Ranges`,支持断点续传(`Range` 透传,OSS 原生支持 206
- 表查询走唯一索引(PickCode / AdminCode)与普通索引(Tag);标签列表按 CreatedAt 倒序,limit 100 防大列表
### 5.2 安全
- 匿名性:全流程无需注册登录,无手机号/邮箱绑定
- **OSS 后端中转模式**OSS AK/SK 仅存服务端 `appsettings.json`,前端始终只与后端 API 交互,不接触 OSS 凭据;对象键 `文传易2026/{yyyyMM}/{Guid}{ext}`,GUID 文件名杜绝重名与路径问题,原始文件名仅存数据库
- 取件码 / 管理码均全局唯一,取件码冲突自动重生成;**标签不唯一(一对多)**,同一标签可关联多个文件
- 管理码丢失**不提供找回**(只展示一次,UI 明确提示)
- 开放 API 的 `filePath` 入参必须位于配置白名单目录 `OpenApi:UploadRoot` 下(`Path.GetFullPath` 规范化后校验前缀,防路径穿越)
- 上传内容默认不做敏感/病毒扫描(如需可后续扩展)
- 文件格式不限制,但对可执行/脚本类文件(.exe/.bat/.sh/.dll 等)在上传与下载时展示"可执行文件风险提示",提醒谨慎运行
- 日志不打印 OSS 凭据与数据库密码明文
### 5.3 可用性
- 中文界面,核心操作 ≤3 步
- 所有错误均有友好提示(无效码 / 过期 / 文件不存在 / 网络错误 / 标签格式错误)
- **移动端优先**:桌面 + 手机浏览器均可用,手机端完整支持上传 / 取件 / 管理全流程
- **微信扫码可用**:正式站 `https://wenchuanyi.bbitcn.net` 有公网地址,手机微信扫码打开即可使用;**部署公网前先在本地跑通全流程测试**(浏览器自动化冒烟 + 局域网手机访问验证)
- **磁盘无需提醒**:本系统不实现磁盘空间监控与提醒功能
### 5.4 兼容性
- 浏览器:Chrome / Edge / Safari / **微信内置浏览器**(最新两个大版本)
- 微信内置浏览器中点击选择文件,可支持选择**微信聊天记录中的文件**(标准 `<input type="file">` 原生能力,真机验证)
- 前端构建目标保持 ES2018,兼容微信 X5 内核
- 不支持 IE
---
## 6. 技术方案
### 6.1 技术栈(已确认)
| 层 | 选型 |
| --- | --- |
| 后端 | ASP.NET Core Web API.NET 8 LTS,支持 IIS 托管)+ FreeSql.Provider.MySqlCodeFirst 自动建表) |
| 数据库 | 远程 MySQL 8.x`116.198.221.125:3306`,库 `wenchuanyi`,用户 `wenchuanyi` |
| 文件存储 | 阿里云 OSS`Aliyun.OSS` SDKEndpoint `oss-cn-chengdu.aliyuncs.com`Bucket `bbit-f8-web`STSEndpoint 预留备用) |
| 前端 | Vue 3 + Vite + TypeScript + TDesign + Vue Router + Axios + Tailwind CSS + qrcode |
| 部署 | Windows Server + IIS 10 + .NET 8 Hosting BundleFTP 发布(`ftp://116.198.221.125`,用户 `wenchuanyi` |
### 6.2 系统架构
```
Vue3 SPA ──REST/JSON──> ASP.NET Core Web API ──FreeSql──> 远程 MySQLfiles 表)
├── 阿里云 OSS bbit-f8-web(对象键 文传易2026/{yyyyMM}/{Guid}{ext}
└── BackgroundService 定时清理过期文件(先删记录再删 OSS 对象)
```
- Controller`FileController`(上传 / 查询 / 标签列表 / 预览 / 下载)、`AdminController`(管理列表 / 删除)、`OpenApiController`(公开接口)
- Service`CodeGeneratorService`(取件码/管理码生成)、`OssStorageService`(OSS 对象键构造、流式上传/下载/删除)
- 后台任务:`ExpiredFileCleanerService`(每 30 分钟,仅扫 `IsPermanent = false` 的过期文件)
- 生产部署:前端构建产物与后端发布输出**同目录放置于 IIS 站点物理路径**(默认文件夹或 wwwroot);后端 `UseStaticFiles` + `MapFallbackToFile("index.html")` 实现 SPA 路由与 `/api` 共存
### 6.3 数据表设计(files 表,FreeSql CodeFirst 自动建表)
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| Id | bigint 自增 | 主键 |
| PickCode | varchar(8) 唯一索引 | 取件码(共享 8 位 / 私密 6 位) |
| AdminCode | varchar(8) 唯一索引 | 管理码(8 位字母数字) |
| FileType | varchar(16) | 文件类型:standard(共享)/ private(私密)/ tagged(标签) |
| Password | varchar(12) 可空 | 私密文件密码(4-12 位);可与标签同时设置(不互斥) |
| Tag | varchar(64) 可空 普通索引(非唯一) | 标签(仅英文+数字),非空即为标签文件;可与密码同时设置(不互斥);同一标签可关联多个文件 |
| OriginalName | varchar(255) | 原始文件名(下载展示用) |
| ObjectKey | varchar(255) | OSS 对象键:文传易2026/{yyyyMM}/{Guid}{ext} |
| Size | bigint | 文件大小(字节) |
| MimeType | varchar(100) 可空 | Content-Type |
| DownloadCount | int 默认 0 | 下载次数(仅统计、不限制) |
| UploadIp | varchar(45) | 上传者 IP 地址(IPv4/IPv6,安全审计,仅管理列表可见,取件页不展示) |
| IsPermanent | bool | 是否永久保存(含标签的文件强制 true) |
| ExpiresAt | datetime 可空 | 过期时间(IsPermanent=true 时为 null |
| CreatedAt | datetime | 上传时间 |
### 6.4 接口清单
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/api/files/upload` | multipart 上传(file + expire + password + tag);**password 与 tag 可同时设置(不互斥)**、tag 格式校验(仅英文+数字、纯数字>8位/英文>4位)→ 返回取件凭证 + 管理码 + 文件信息(**自动记录上传者 IP**) |
| GET | `/api/files/{code}` | 查询文件信息(code 为取件码;私密文件需带密码校验;过期返回 410) |
| GET | `/api/files/by-tag/{tag}` | 按标签查询文件列表(按上传时间倒序;含标签均永久保存,仅返回未被删除记录;列表项带密码时下载/预览需密码) |
| GET | `/api/files/{code}/download` | 流式下载,下载计数 +1(仅统计不限制),还原原始文件名,支持 Range 断点续传(私密文件需密码) |
| GET | `/api/files/{code}/preview` | 在线预览:PDF/图片(≤30MB/音视频(白名单 mp4/webm/mp3/wav/m4a/aac/ogg,不限大小)以 inline 流返回(私密文件需密码),不计下载次数 |
| GET | `/api/files/{code}/content` | 文本类文件(txt/md/xml/json 等,≤2MB)内容,供在线阅读渲染(私密文件需密码) |
| GET | `/api/admin/files/{adminCode}` | 管理码查询文件列表(含上传 IP) |
| DELETE | `/api/admin/files/{adminCode}` | 删除指定文件(body 传文件 id/取件码,校验管理码);取件页标签列表删除复用此接口 |
| POST | `/api/open/upload-public` | 公开:body `{ filePath, expiresHours }`(long 有效期小时数,0=永久,缺省 24)→ `{ pickCode, pickUrl, downloadUrl }` |
| POST | `/api/open/upload-price` | 公开:body `{ filePath, pwd }``{ pickCode, pickUrl, downloadUrl }`(下载需密码) |
| POST | `/api/open/upload-tag` | 公开:body `{ filePath, tag }``{ pickCode, pickUrl, downloadUrl }`(标签文件永久保存) |
| GET | `/api/open/download/{pickCode}` | 公开:返回 `{ downloadUrl, pickUrl, needPassword }`;共享/标签为直接下载 URL,私密跳取件页手动输密码 |
> 开放 API 说明:入参 `filePath` 为服务端文件路径,必须位于配置白名单目录 `OpenApi:UploadRoot` 下(`Path.GetFullPath` 规范化后校验前缀,防路径穿越);响应含识别码、`pickUrl`(前端取件页链接,带 `?code=` 参数,点击进入下载页)、`downloadUrl`。
---
## 7. 页面与交互设计
### 7.1 页面清单
| 页面 | 路由 | 内容 |
| --- | --- | --- |
| 上传页(首页) | `/` | 品牌区(Logo + 标语「文传易,免登录,传文件,真容易」+ 三步使用提示) + 上传区(拖拽 / Ctrl+V 粘贴文件 / 点击选择 / 粘贴文字生成「文字前12位+日期时间」txt)+ 有效期固定三档(24小时/7天/永久,含标签强制永久)+ 密码(4-12 位)与标签(实时校验)**两个独立输入项、可同时设置** + 结果卡片(**二维码** + 大号取件凭证 + 复制 + 可收起管理码) |
| 取件页 | `/pickup` | 取件凭证输入框(实时识别:6 位→密码框、7 位→提示继续输入、8 位→下载按钮;非纯数字→按标签查询;URL `?code=` 自动填充)+ 单文件结果卡片或标签文件列表 + 预览层(文本/PDF/图片/音视频) |
| 管理页 | `/admin` | 管理码输入框 + 文件列表表格(名称/大小/上传时间/过期时间/下载次数/**上传 IP**)+ 每行删除按钮(二次确认) |
### 7.2 视觉风格
- 现代简约 + 清爽科技感:蓝青渐变主色(`#2D6CFF``#00B4FF`),浅色底 + 大圆角白色卡片 + 柔和阴影
- 导航:桌面顶部固定导航栏,移动端**底部固定 Tab**(上传 / 取件 / 管理)
- 微动效:拖拽高亮、hover 上浮、复制成功 Toast、页面淡入、凭证识别平滑过渡
---
## 8. 异常与边界情况
| 场景 | 处理 |
| --- | --- |
| 取件凭证不存在 | 提示"取件码/标签无效" |
| 标签查询无结果 | 提示"该标签下暂无文件" |
| 输入到 7 位数字 | 提示"取件码为 6 位或 8 位,请继续输入完整取件码",不自动查询 |
| 标签含符号 / 汉字 | 前端实时提示"仅支持英文+数字",后端返回 400 |
| 标签为纯 6/8 位数字 | 已被"纯数字须 >8 位"规则规避(纯数字 ≥9 位,不会与 6/8 位取件码冲突) |
| 标签列表项为私密文件(带密码) | 下载/预览前需输入该文件密码,密码错误提示"密码错误" |
| 私密文件密码错误 | 提示"密码错误",不泄露文件信息 |
| 可执行/脚本类文件 | 上传与下载时展示"可执行文件风险提示" |
| 文本文件超 2MB / PDF/图片超 30MB | 不提供在线预览,仅提供下载(提示"文件过大,请下载后查看") |
| 音视频非白名单格式 | 不提供在线播放,提示下载查看 |
| 文件已过期 | 提示"文件已过期",并触发懒清理 |
| 文件超过大小上限(200MB) | 前端上传前拦截 + 服务端双重校验;若超过 IIS(30MB 默认)或 ASP.NET multipart128MB 默认)限制,请求在到达应用前被拒(500.30/404.13/413,日志无记录),需按 §5.1 放开三层限制 |
| 上传中断 / 网络错误 | 前端提示并可重试 |
| OSS 写入/读取失败 | 记录日志,返回明确错误码 |
| 管理码错误 | 提示"管理码无效" |
| 下载时 OSS 对象已被清理 / 缺失 | 提示"文件已不存在" |
| 同一取件码被并发下载 | 下载计数原子自增,不丢失 |
---
## 9. 验收标准
1. 端到端流程:加入文件 → 上传 → 获得取件凭证 → 新会话输入凭证 → 下载成功,文件名与内容正确。
2. 三种文件模式端到端均可用:**共享文件**(输入 8 位取件码后显示下载按钮)、**私密文件**(输入 6 位后出现密码框,密码 4 位后显示下载按钮,密码错误无法下载)、**标签文件**(输入标签 → 展示该标签下文件列表 → 逐项预览/下载;同一标签可关联多个文件);**密码与标签可同时设置**(同时设置时按私密 6 位码识别,且强制永久保存)。
3. 取件码位数实时识别正确(6 位 → 私密,7 位 → 提示继续输入,8 位 → 共享);取件码全局不重复。
4. **二维码分享**:上传成功生成二维码,扫码打开取件页并自动填入取件码、直接查询到文件。
5. 在线预览:文本(≤2MB)/PDF/图片(≤30MB)可在线阅读查看、音视频(白名单格式)可在线播放,均可下载;超限/非白名单仅下载。
6. 多种上传方式可用:拖拽、Ctrl+V 粘贴文件、点击选择、粘贴文字生成「文字前 12 位 + 日期时间」txt。
7. 有效期固定三档(24小时/7天/永久);含标签的文件永久保存不自动过期;过期文件到期后无法下载且被自动清理(懒检查 + 定时任务)。
8. 管理码可查列表、可删除;删除后取件凭证立即失效;下载次数仅统计不限制;**上传自动记录上传者 IP(IPv4/IPv6,仅管理列表可见)**。
9. **标签规则**:仅英文+数字;纯数字 >8 位(推荐手机号)、含字母 >4 位;**密码与标签可同时设置(不互斥)**,前端提示 + 后端校验兜底。
10. 超过大小上限(200MB)的文件被正确拦截。
11. 手机浏览器与微信内置浏览器均可用;手机微信扫码可完成上传/取件,可选择微信聊天记录中的文件。
12. **部署**:本地全流程测试通过后,经 FTP 发布至 IIS 站点(`https://wenchuanyi.bbitcn.net`)访问正常。
13. 前后端代码可一键本地启动,数据库自动建表。
---
## 10. 里程碑与交付
| 阶段 | 内容 | 状态 |
| --- | --- | --- |
| M1 需求确认 | 本需求文档定稿、待确认问题全部拍板 | ✅ 已完成 |
| M2 开发 | 后端 API + 前端三页面 + 前后端联调 | ✅ 已完成 |
| M3 交付 | 本地测试通过、IIS+FTP 部署说明与脚本齐全 | ✅ 已完成 |
---
## 11. 开发进度状态(归档)
> 更新于:2026-08-24。以下为已上线功能与已修复缺陷的归档记录,便于后续迭代回溯。
### 11.1 已上线功能
- 完整匿名文件传输闭环:上传(拖拽 / Ctrl+V / 点击 / 粘贴文字生成 txt)→ 取件码/标签 → 取件下载。
- 三种文件模式:共享(8 位码)/ 私密(6 位码 + 密码)/ 标签(一对多、含标签强制永久)。
- 二维码分享 + 一键复制取件码/管理码;二维码海报保存(默认文件名 `文传易取件码-取件码(原文件名)-流水号.png`)。
- 在线预览:文本(≤2MB)/ PDF / 图片(≤30MB)/ 音视频(白名单格式,流式)。
- 发送者凭管理码查看列表、删除文件;管理列表展示上传 IP。
- 过期文件懒清理 + 后台定时任务(每 30 分钟)。
- 开放 APIpublic / price / tag)供外部系统直接生成取件链接。
- 已部署至正式站 `https://wenchuanyi.bbitcn.net`IIS + .NET 8 + 阿里云 OSS 中转)。
### 11.2 已修复缺陷(2026-08-23 ~ 08-24
| 日期 | 问题 | 根因 | 修复 |
| --- | --- | --- | --- |
| 08-23 | 135MB zip 上传失败 | 三层大小限制未全放开:①前端 axios 未放开;②IIS `web.config``maxAllowedContentLength`(默认 30MB);③`FileController.Upload``[RequestFormLimits]`multipart 默认 128MB | 前端放开 maxBodyLengthweb.config 加 `maxAllowedContentLength=220200960`Upload 加 `[RequestFormLimits(MultipartBodyLengthLimit=220_200_960)]` |
| 08-23 | 服务器 DLL 更新后仍跑旧版 | in-process 下 DLL 被 IIS 锁定,FTP 覆盖被 550;且**大小巧合相同(60416 字节)导致同步脚本按大小校验跳过上传** | 采用 `app_offline.htm` 方案:先放该文件触发 ANCM 优雅停止解锁 DLL → 覆盖 → 删除文件自动重启。脚本见 `deploy/apply_backend.ps1` / `deploy/force_dll.ps1` |
| 08-24 | 保存二维码海报"格式、文字错位"(底部大留白、二维码悬空) | 动态调高画布时 `drawImage(backup,0,0)` 未指定目标尺寸,浏览器按新高度缩放整张图 | `drawImage(backup,0,0,backup.width,backup.height)` 显式指定目标尺寸,仅裁剪底部空白 |
| 08-24 | 海报顶部 logo / 标题文字偏上 | canvas `textBaseline` 默认 `alphabetic`,文字顶贴品牌条顶 | 品牌条文字加 `textBaseline='middle'` 并按 logo 块中线定位 |
| 08-24 | 海报「下载方式/文件信息」小竖条贴住标题首字 | 竖条与文字间距仅 12px | 竖条 x 40→38、文字 x 62→66,间距扩至 24 |
| 08-24 | 海报「大小 / 有效期」挤在一行 | 单卡片内合并绘制 | 拆为「大小」一行 +「有效期」一行,卡片高度公式同步更新 |
| 08-24 | 保存二维码文件名不带原文件名 | 原文件名格式为 `文传易取件凭证_取件码.png` | 改为 `文传易取件码-取件码(原文件名)-流水号.png`,原文件名清洗非法字符 |
### 11.3 已知限制 / 注意事项
- **DLL 部署**:每次后端变更后必须核对服务器 DLL 是否真的更新(内容校验/时间戳),**不能只看大小**——大小可能巧合相同而漏传。
- **大文件配置**IIS 与 ASP.NET 两道限制务必同步放开,否则 >128MB 上传会在应用外被拒且无日志。
- **微信内置浏览器**:支持扫码取件/下载;华为鸿蒙微信内置浏览器中上传文件 **可能无法直接读取微信聊天文件、且点击上传不弹系统选择器**(华为自带浏览器正常)。可引导用户改用系统浏览器或华为浏览器上传。
- **二维码海报**为前端 canvas 合成,依赖浏览器字体渲染;个别机型字体度量差异可能导致细微间距偏差。
### 11.4 待办 / 后续可优化
- 微信内置浏览器上传取件(聊天文件读取 + 系统选择器弹窗)的兼容性进一步增强。
- 多文件上传(下载打包 zip)。
- 下载次数限制(本期仅统计)。
- 网盘容量与配额管理、界面中英文切换、前端 STS 直传 OSS。
---
## 12. 未来扩展(可选,本期不实现)
- 多文件上传(下载打包 zip
- 下载次数限制(本期仅统计不限制)
- 网盘容量与配额管理
- 界面中英文切换
- 前端 STS 直传 OSS(需提供 RAM RoleArn
---
## 13. 待确认问题清单(已全部确认)
> ✅ = 已确认(已更新到对应章节)
1. **单文件大小上限**:200MB(前后端双重校验,Kestrel 请求上限留余量)。✅
2. **文件类型**:格式不限;可执行/脚本类文件(.exe/.bat/.sh/.dll)展示风险提示。✅
3. **标签为"一对多"**:同一标签可关联多个文件,标签不要求唯一。✅
4. **标签文件取件方式**:以标签为取件凭证,输入标签 → 展示该标签下文件列表 → 逐项预览/下载。✅
5. **有效期档位**:固定三档 24 小时 / 7 天 / 永久,无自定义时长。✅
6. **下载次数**:不限次,仅统计。✅
7. **部署与微信扫码**:有公网;正式站 `https://wenchuanyi.bbitcn.net`;服务端支持 IIS 部署,FTP 发包(`ftp://116.198.221.125`,默认端口 21,用户 `wenchuanyi`),文件放 IIS 站点默认文件夹或 `wwwroot`**部署公网前先在本地测试**。✅
8. **磁盘策略**:无总容量上限、无单管理码文件数限制。✅
9. **运维告警**:磁盘空间无需提醒(不做磁盘监控/提醒功能)。✅
10. **密码与标签是否同时设置**:**不互斥、可同时设置**(同时设置时按私密文件识别 6 位取件码,且因含标签强制永久保存)。✅
11. **标签规则**:仅英文(A-Za-z)+ 数字、不含任何符号;纯数字须 >8 位(推荐 11 位手机号);含英文字母须 >4 位;大小写敏感(按原文存储匹配)。✅
12. **粘贴文字生成 txt 文件名**:**文字前 12 位 + 日期时间**(`{前12位}_{yyyyMMdd_HHmmss}.txt`,剔除 Windows 非法文件名字符,剔除后为空用「文本」兜底),不提供自定义。✅
13. **在线预览上限**:文本 2MB、PDF/图片 30MB、音视频不限大小(流式);超限仅下载。✅
14. **音视频预览格式**:仅浏览器原生播放格式——视频 mp4/webm,音频 mp3/wav/m4a/aac/ogg;不支持转码,非白名单提示下载。✅
15. **7 位数字输入的最终处理**:输入满 7 位时提示"取件码为 6 位或 8 位,请继续输入完整取件码",不自动查询,等用户继续输入或修正。✅
16. **品牌 Slogan**:**「文传易,免登录,传文件,真容易」**(上传页品牌区展示:Logo + 标语 + 三步使用提示)。✅
17. **私密文件密码长度****4-12 位**(≥4 且 ≤12,原 4-6 位扩展);前端校验 4-12 位,后端同规则兜底。✅
18. **标签为纯 6/8 位数字的冲突**:通过"纯数字标签须 >8 位(≥9)"规则规避,天然不与 6/8 位取件码冲突。✅
19. **记录上传者 IP**:上传(含开放 API)自动记录客户端 IP(IPv4/IPv6`RemoteIpAddress`varchar(45)),仅管理列表展示,取件页/公开接口不暴露;如后续引入反向代理需启用 `ForwardedHeaders`。✅