fix(server, webhook): 添加 MongoDB 数据持久化和上传前去重功能
- 优化支付宝时间格式解析(支持无前导零格式) - 修复 webhook 服务编译错误 - 更新版本号至 1.0.5
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,5 +21,6 @@ server/billai-server
|
|||||||
server/uploads/
|
server/uploads/
|
||||||
server/outputs/
|
server/outputs/
|
||||||
*.log
|
*.log
|
||||||
|
*.exe
|
||||||
|
|
||||||
mongodata/
|
mongodata/
|
||||||
@@ -5,6 +5,14 @@
|
|||||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||||
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||||
|
|
||||||
|
## [1.0.5] - 2026-01-08
|
||||||
|
|
||||||
|
### 优化
|
||||||
|
- **支付宝时间格式解析** - 支持无前导零的日期格式
|
||||||
|
- 自动标准化 `2026/1/13 20:08` 为 `2026/01/13 20:08`
|
||||||
|
- 兼容支付宝账单的时间格式
|
||||||
|
- **Webhook 服务修复** - 移除未使用的 `fmt` 导入,修复编译错误
|
||||||
|
|
||||||
## [1.0.4] - 2026-01-13
|
## [1.0.4] - 2026-01-13
|
||||||
|
|
||||||
### 新增
|
### 新增
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
一个基于微服务架构的个人账单分析工具,支持微信和支付宝账单的自动解析、智能分类和可视化分析。
|
一个基于微服务架构的个人账单分析工具,支持微信和支付宝账单的自动解析、智能分类和可视化分析。
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@@ -16,6 +16,7 @@
|
|||||||
- 🏷️ **智能分类** - 基于关键词匹配的交易分类推断
|
- 🏷️ **智能分类** - 基于关键词匹配的交易分类推断
|
||||||
- 📈 **趋势图表** - 日/月消费趋势、分类排行、收支对比
|
- 📈 **趋势图表** - 日/月消费趋势、分类排行、收支对比
|
||||||
- 🔍 **复核修正** - 对不确定的分类进行人工复核
|
- 🔍 **复核修正** - 对不确定的分类进行人工复核
|
||||||
|
- 💾 **数据持久化** - MongoDB 存储原始数据和清洗后数据,支持去重检查
|
||||||
- 🐳 **一键部署** - Docker Compose 快速启动全部服务
|
- 🐳 **一键部署** - Docker Compose 快速启动全部服务
|
||||||
- 🚀 **自动部署** - Gitea Webhook 触发零停机热更新
|
- 🚀 **自动部署** - Gitea Webhook 触发零停机热更新
|
||||||
|
|
||||||
@@ -67,9 +68,11 @@ sequenceDiagram
|
|||||||
Note over U,D: 上传账单流程
|
Note over U,D: 上传账单流程
|
||||||
U->>W: 上传账单文件
|
U->>W: 上传账单文件
|
||||||
W->>S: POST /api/upload
|
W->>S: POST /api/upload
|
||||||
|
S->>D: 去重检查(原始数据集合)
|
||||||
|
D-->>S: 重复记录数
|
||||||
S->>A: POST /clean (清洗账单)
|
S->>A: POST /clean (清洗账单)
|
||||||
A-->>S: 清洗结果 + 分类
|
A-->>S: 清洗结果 + 分类
|
||||||
S->>D: 存储账单数据
|
S->>D: 存储原始数据 + 清洗后数据
|
||||||
D-->>S: 保存成功
|
D-->>S: 保存成功
|
||||||
S-->>W: 返回分析结果
|
S-->>W: 返回分析结果
|
||||||
W-->>U: 显示分析报表
|
W-->>U: 显示分析报表
|
||||||
@@ -228,6 +231,8 @@ python server.py
|
|||||||
| `ANALYZER_MODE` | `http` | 适配器模式: http/subprocess |
|
| `ANALYZER_MODE` | `http` | 适配器模式: http/subprocess |
|
||||||
| `MONGO_URI` | `mongodb://localhost:27017` | MongoDB 连接 URI |
|
| `MONGO_URI` | `mongodb://localhost:27017` | MongoDB 连接 URI |
|
||||||
| `MONGO_DATABASE` | `billai` | 数据库名称 |
|
| `MONGO_DATABASE` | `billai` | 数据库名称 |
|
||||||
|
| `MONGO_RAW_COLLECTION` | `bills_raw` | 原始数据集合名称 |
|
||||||
|
| `MONGO_CLEANED_COLLECTION` | `bills_cleaned` | 清洗后数据集合名称 |
|
||||||
| `JWT_SECRET` | - | JWT 加密密钥 |
|
| `JWT_SECRET` | - | JWT 加密密钥 |
|
||||||
| `TOKEN_EXPIRY` | `24` | Token 过期时间(小时) |
|
| `TOKEN_EXPIRY` | `24` | Token 过期时间(小时) |
|
||||||
| `ADMIN_USERNAME` | - | 管理员用户名(可选) |
|
| `ADMIN_USERNAME` | - | 管理员用户名(可选) |
|
||||||
@@ -268,6 +273,7 @@ python server.py
|
|||||||
|
|
||||||
| 版本 | 日期 | 主要更新 |
|
| 版本 | 日期 | 主要更新 |
|
||||||
|------|------|----------|
|
|------|------|----------|
|
||||||
|
| **v1.0.5** | 2026-01-08 | 🐛 修复支付宝时间格式解析错误,修复WebHook编译错误 |
|
||||||
| **v1.0.4** | 2026-01-13 | 🚀 Gitea Webhook 自动部署、零停机热更新 |
|
| **v1.0.4** | 2026-01-13 | 🚀 Gitea Webhook 自动部署、零停机热更新 |
|
||||||
| **v1.0.3** | 2026-01-13 | ✨ DateTimePicker 组件、收支分类动态切换 |
|
| **v1.0.3** | 2026-01-13 | ✨ DateTimePicker 组件、收支分类动态切换 |
|
||||||
| **v1.0.2** | 2026-01-11 | 🐛 修复时区和金额解析问题 |
|
| **v1.0.2** | 2026-01-11 | 🐛 修复时区和金额解析问题 |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# BillAI 服务器配置文件
|
# BillAI 服务器配置文件
|
||||||
|
|
||||||
# 应用版本
|
# 应用版本
|
||||||
version: "1.0.2"
|
version: "1.0.5"
|
||||||
|
|
||||||
# 服务配置
|
# 服务配置
|
||||||
server:
|
server:
|
||||||
|
|||||||
@@ -490,12 +490,44 @@ func saveCleanedBillsFromJSON(filePath, billType, sourceFile, uploadBatch string
|
|||||||
|
|
||||||
// parseTime 解析时间字符串
|
// parseTime 解析时间字符串
|
||||||
// 使用本地时区解析,返回 model.LocalTime 类型
|
// 使用本地时区解析,返回 model.LocalTime 类型
|
||||||
|
// 支持支付宝格式: 2026/1/13 20:08 (月份和日期可能没有前导零)
|
||||||
func parseTime(s string) model.LocalTime {
|
func parseTime(s string) model.LocalTime {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return model.LocalTime(time.Time{})
|
return model.LocalTime(time.Time{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先尝试标准化支付宝格式(将单数日期/月份补零)
|
||||||
|
// 例如: "2026/1/13 20:08" -> "2026/01/13 20:08"
|
||||||
|
if strings.Contains(s, "/") && !strings.Contains(s, "-") {
|
||||||
|
// 匹配格式: YYYY/M/D 或 YYYY/M/D HH:mm 或 YYYY/M/D HH:mm:ss
|
||||||
|
parts := strings.Split(s, " ")
|
||||||
|
if len(parts) > 0 {
|
||||||
|
datePart := parts[0]
|
||||||
|
// 使用正则表达式将单数日期/月份补零
|
||||||
|
// 例如: "2026/1/13" -> "2026/01/13"
|
||||||
|
dateParts := strings.Split(datePart, "/")
|
||||||
|
if len(dateParts) == 3 {
|
||||||
|
year := dateParts[0]
|
||||||
|
month := dateParts[1]
|
||||||
|
day := dateParts[2]
|
||||||
|
// 补零
|
||||||
|
if len(month) == 1 {
|
||||||
|
month = "0" + month
|
||||||
|
}
|
||||||
|
if len(day) == 1 {
|
||||||
|
day = "0" + day
|
||||||
|
}
|
||||||
|
datePart = year + "/" + month + "/" + day
|
||||||
|
if len(parts) > 1 {
|
||||||
|
s = datePart + " " + strings.Join(parts[1:], " ")
|
||||||
|
} else {
|
||||||
|
s = datePart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 尝试多种时间格式(使用本地时区)
|
// 尝试多种时间格式(使用本地时区)
|
||||||
formats := []string{
|
formats := []string{
|
||||||
"2006-01-02 15:04:05",
|
"2006-01-02 15:04:05",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|||||||
Reference in New Issue
Block a user