完善lsfx mock服务上传状态接口与部署文档
This commit is contained in:
@@ -0,0 +1,717 @@
|
||||
# 接口完整对齐实施计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** 根据 `兰溪-流水分析对接3.md` 文档,完整对齐 Mock 服务器的所有7个接口实现
|
||||
|
||||
**Architecture:** 保持无数据库架构,通过扩展内存数据模型支持完整字段,新增1个接口,完善6个现有接口的响应字段
|
||||
|
||||
**Tech Stack:** FastAPI, Python 3.8+, Pydantic
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 扩展 FileRecord 数据模型
|
||||
|
||||
**Files:**
|
||||
- Modify: `services/file_service.py`
|
||||
|
||||
**Step 1: 读取现有 file_service.py 文件**
|
||||
|
||||
先查看当前的 FileRecord 实现。
|
||||
|
||||
**Step 2: 扩展 FileRecord 类添加所有新字段**
|
||||
|
||||
在 `FileRecord` 类中添加以下字段:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
@dataclass
|
||||
class FileRecord:
|
||||
"""文件记录模型(扩展版)"""
|
||||
# 原有字段
|
||||
log_id: int
|
||||
group_id: int
|
||||
file_name: str
|
||||
status: int = -5 # -5 表示解析成功
|
||||
upload_status_desc: str = "data.wait.confirm.newaccount"
|
||||
parsing: bool = True # True表示正在解析
|
||||
|
||||
# 新增字段 - 账号和主体信息
|
||||
account_no_list: List[str] = field(default_factory=list)
|
||||
enterprise_name_list: List[str] = field(default_factory=list)
|
||||
|
||||
# 新增字段 - 银行和模板信息
|
||||
bank_name: str = "ZJRCU"
|
||||
real_bank_name: str = "ZJRCU"
|
||||
template_name: str = "ZJRCU_T251114"
|
||||
data_type_info: List[str] = field(default_factory=lambda: ["CSV", ","])
|
||||
|
||||
# 新增字段 - 文件元数据
|
||||
file_size: int = 50000
|
||||
download_file_name: str = ""
|
||||
file_package_id: str = field(default_factory=lambda: str(uuid.uuid4()).replace('-', ''))
|
||||
|
||||
# 新增字段 - 上传用户信息
|
||||
file_upload_by: int = 448
|
||||
file_upload_by_user_name: str = "admin@support.com"
|
||||
file_upload_time: str = field(default_factory=lambda: datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
# 新增字段 - 法律实体信息
|
||||
le_id: int = 10000
|
||||
login_le_id: int = 10000
|
||||
log_type: str = "bankstatement"
|
||||
log_meta: str = "{\"lostHeader\":[],\"balanceAmount\":true}"
|
||||
lost_header: List[str] = field(default_factory=list)
|
||||
|
||||
# 新增字段 - 记录统计
|
||||
rows: int = 0
|
||||
source: str = "http"
|
||||
total_records: int = 150
|
||||
is_split: int = 0
|
||||
|
||||
# 新增字段 - 交易日期范围
|
||||
trx_date_start_id: int = 20240101
|
||||
trx_date_end_id: int = 20241231
|
||||
```
|
||||
|
||||
**Step 3: 验证服务能正常启动**
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
预期:服务启动成功,无报错信息。
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 更新 upload_file 方法初始化所有字段
|
||||
|
||||
**Files:**
|
||||
- Modify: `services/file_service.py`
|
||||
|
||||
**Step 1: 读取 upload_file 方法**
|
||||
|
||||
查看当前的 `upload_file` 方法实现。
|
||||
|
||||
**Step 2: 根据文件名推断银行名称**
|
||||
|
||||
在 `upload_file` 方法中添加银行名称推断逻辑:
|
||||
|
||||
```python
|
||||
def _infer_bank_name(self, filename: str) -> tuple:
|
||||
"""根据文件名推断银行名称和模板名称"""
|
||||
if "支付宝" in filename or "alipay" in filename.lower():
|
||||
return "ALIPAY", "ALIPAY_T220708"
|
||||
elif "绍兴银行" in filename or "BSX" in filename:
|
||||
return "BSX", "BSX_T240925"
|
||||
else:
|
||||
return "ZJRCU", "ZJRCU_T251114"
|
||||
|
||||
async def upload_file(self, group_id: int, file: UploadFile, background_tasks: BackgroundTasks) -> dict:
|
||||
"""上传文件并初始化所有字段"""
|
||||
# 生成新的 log_id
|
||||
self.current_log_id += 1
|
||||
log_id = self.current_log_id
|
||||
|
||||
# 推断银行信息
|
||||
bank_name, template_name = self._infer_bank_name(file.filename)
|
||||
|
||||
# 生成合理的交易日期范围
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
end_date = datetime.now()
|
||||
start_date = end_date - timedelta(days=random.randint(90, 365))
|
||||
trx_date_start_id = int(start_date.strftime("%Y%m%d"))
|
||||
trx_date_end_id = int(end_date.strftime("%Y%m%d"))
|
||||
|
||||
# 生成随机账号和主体
|
||||
account_no = f"{random.randint(10000000000, 99999999999)}"
|
||||
enterprise_names = ["测试主体"] if random.random() > 0.3 else [""]
|
||||
|
||||
# 创建完整的文件记录
|
||||
file_record = FileRecord(
|
||||
log_id=log_id,
|
||||
group_id=group_id,
|
||||
file_name=file.filename,
|
||||
download_file_name=file.filename,
|
||||
bank_name=bank_name,
|
||||
real_bank_name=bank_name,
|
||||
template_name=template_name,
|
||||
account_no_list=[account_no],
|
||||
enterprise_name_list=enterprise_names,
|
||||
le_id=10000 + random.randint(0, 9999),
|
||||
login_le_id=10000 + random.randint(0, 9999),
|
||||
file_size=random.randint(10000, 100000),
|
||||
total_records=random.randint(100, 300),
|
||||
trx_date_start_id=trx_date_start_id,
|
||||
trx_date_end_id=trx_date_end_id,
|
||||
parsing=True,
|
||||
status=-5
|
||||
)
|
||||
|
||||
# 存储记录
|
||||
self.file_records[log_id] = file_record
|
||||
|
||||
# 添加后台任务(延迟解析)
|
||||
background_tasks.add_task(self._delayed_parse, log_id)
|
||||
|
||||
# 构建响应
|
||||
return self._build_upload_response(file_record)
|
||||
```
|
||||
|
||||
**Step 3: 实现 _build_upload_response 方法**
|
||||
|
||||
```python
|
||||
def _build_upload_response(self, file_record: FileRecord) -> dict:
|
||||
"""构建上传接口的完整响应"""
|
||||
return {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"accountsOfLog": {
|
||||
str(file_record.log_id): [
|
||||
{
|
||||
"bank": file_record.bank_name,
|
||||
"accountName": file_record.enterprise_name_list[0] if file_record.enterprise_name_list else "",
|
||||
"accountNo": file_record.account_no_list[0] if file_record.account_no_list else "",
|
||||
"currency": "CNY"
|
||||
}
|
||||
]
|
||||
},
|
||||
"uploadLogList": [
|
||||
{
|
||||
"accountNoList": file_record.account_no_list,
|
||||
"bankName": file_record.bank_name,
|
||||
"dataTypeInfo": file_record.data_type_info,
|
||||
"downloadFileName": file_record.download_file_name,
|
||||
"enterpriseNameList": file_record.enterprise_name_list,
|
||||
"filePackageId": file_record.file_package_id,
|
||||
"fileSize": file_record.file_size,
|
||||
"fileUploadBy": file_record.file_upload_by,
|
||||
"fileUploadByUserName": file_record.file_upload_by_user_name,
|
||||
"fileUploadTime": file_record.file_upload_time,
|
||||
"leId": file_record.le_id,
|
||||
"logId": file_record.log_id,
|
||||
"logMeta": file_record.log_meta,
|
||||
"logType": file_record.log_type,
|
||||
"loginLeId": file_record.login_le_id,
|
||||
"lostHeader": file_record.lost_header,
|
||||
"realBankName": file_record.real_bank_name,
|
||||
"rows": file_record.rows,
|
||||
"source": file_record.source,
|
||||
"status": file_record.status,
|
||||
"templateName": file_record.template_name,
|
||||
"totalRecords": file_record.total_records,
|
||||
"trxDateEndId": file_record.trx_date_end_id,
|
||||
"trxDateStartId": file_record.trx_date_start_id,
|
||||
"uploadFileName": file_record.file_name,
|
||||
"uploadStatusDesc": file_record.upload_status_desc
|
||||
}
|
||||
],
|
||||
"uploadStatus": 1
|
||||
},
|
||||
"status": "200",
|
||||
"successResponse": True
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: 验证上传接口返回完整字段**
|
||||
|
||||
重启服务并调用上传接口,检查响应是否包含所有字段。
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 添加 get_upload_status 方法
|
||||
|
||||
**Files:**
|
||||
- Modify: `services/file_service.py`
|
||||
|
||||
**Step 1: 实现 get_upload_status 方法**
|
||||
|
||||
在 `FileService` 类中添加新方法:
|
||||
|
||||
```python
|
||||
def get_upload_status(self, group_id: int, log_id: int = None) -> dict:
|
||||
"""获取文件上传状态(接口5)"""
|
||||
logs = []
|
||||
|
||||
if log_id:
|
||||
# 返回特定文件的状态
|
||||
if log_id in self.file_records:
|
||||
record = self.file_records[log_id]
|
||||
if record.group_id == group_id:
|
||||
logs.append(self._build_log_detail(record))
|
||||
else:
|
||||
# 返回该项目的所有文件状态
|
||||
for record in self.file_records.values():
|
||||
if record.group_id == group_id:
|
||||
logs.append(self._build_log_detail(record))
|
||||
|
||||
# 构建响应
|
||||
return {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"logs": logs,
|
||||
"status": "",
|
||||
"accountId": 8954,
|
||||
"currency": "CNY"
|
||||
},
|
||||
"status": "200",
|
||||
"successResponse": True
|
||||
}
|
||||
|
||||
def _build_log_detail(self, record: FileRecord) -> dict:
|
||||
"""构建日志详情对象"""
|
||||
return {
|
||||
"accountNoList": record.account_no_list,
|
||||
"bankName": record.bank_name,
|
||||
"dataTypeInfo": record.data_type_info,
|
||||
"downloadFileName": record.download_file_name,
|
||||
"enterpriseNameList": record.enterprise_name_list,
|
||||
"fileSize": record.file_size,
|
||||
"fileUploadBy": record.file_upload_by,
|
||||
"fileUploadByUserName": record.file_upload_by_user_name,
|
||||
"fileUploadTime": record.file_upload_time,
|
||||
"isSplit": record.is_split,
|
||||
"leId": record.le_id,
|
||||
"logId": record.log_id,
|
||||
"logMeta": record.log_meta,
|
||||
"logType": record.log_type,
|
||||
"loginLeId": record.login_le_id,
|
||||
"lostHeader": record.lost_header,
|
||||
"realBankName": record.real_bank_name,
|
||||
"rows": record.rows,
|
||||
"source": record.source,
|
||||
"status": record.status,
|
||||
"templateName": record.template_name,
|
||||
"totalRecords": record.total_records,
|
||||
"trxDateEndId": record.trx_date_end_id,
|
||||
"trxDateStartId": record.trx_date_start_id,
|
||||
"uploadFileName": record.file_name,
|
||||
"uploadStatusDesc": record.upload_status_desc
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证方法能正确查询文件记录**
|
||||
|
||||
在代码中确保 `file_records` 字典正确初始化和管理。
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 在 API 路由中添加新接口
|
||||
|
||||
**Files:**
|
||||
- Modify: `routers/api.py`
|
||||
|
||||
**Step 1: 读取现有 api.py 文件**
|
||||
|
||||
查看当前的路由定义。
|
||||
|
||||
**Step 2: 添加 GET 接口路由**
|
||||
|
||||
在接口5的位置(check_parse_status 和 delete_files 之间)添加:
|
||||
|
||||
```python
|
||||
# ==================== 接口5:获取文件上传状态 ====================
|
||||
@router.get("/watson/api/project/bs/upload")
|
||||
async def get_upload_status(
|
||||
groupId: int = Form(..., description="项目id"),
|
||||
logId: Optional[int] = Form(None, description="文件id"),
|
||||
):
|
||||
"""获取单个文件上传后的状态
|
||||
|
||||
如果不提供 logId,返回该项目的所有文件状态
|
||||
"""
|
||||
return file_service.get_upload_status(groupId, logId)
|
||||
```
|
||||
|
||||
**Step 3: 确认导入了 Optional**
|
||||
|
||||
在文件顶部确认:
|
||||
|
||||
```python
|
||||
from typing import List, Optional
|
||||
```
|
||||
|
||||
**Step 4: 验证新接口出现在 Swagger 文档中**
|
||||
|
||||
重启服务,访问 http://localhost:8000/docs,确认能看到新的 GET 接口。
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 更新 check_parse_status 响应字段
|
||||
|
||||
**Files:**
|
||||
- Modify: `services/file_service.py`
|
||||
|
||||
**Step 1: 修改 check_parse_status 方法**
|
||||
|
||||
确保返回的 pendingList 包含所有字段:
|
||||
|
||||
```python
|
||||
def check_parse_status(self, group_id: int, inprogress_list: str) -> dict:
|
||||
"""检查文件解析状态"""
|
||||
log_ids = [int(id.strip()) for id in inprogress_list.split(",")]
|
||||
|
||||
pending_list = []
|
||||
all_parsing_complete = True
|
||||
|
||||
for log_id in log_ids:
|
||||
if log_id in self.file_records:
|
||||
record = self.file_records[log_id]
|
||||
if record.parsing:
|
||||
all_parsing_complete = False
|
||||
|
||||
pending_list.append(self._build_log_detail(record))
|
||||
|
||||
return {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"parsing": not all_parsing_complete,
|
||||
"pendingList": pending_list
|
||||
},
|
||||
"status": "200",
|
||||
"successResponse": True
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证解析状态接口返回完整字段**
|
||||
|
||||
调用接口4,检查响应中的 pendingList 是否包含所有字段。
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 更新 delete_files 方法响应格式
|
||||
|
||||
**Files:**
|
||||
- Modify: `services/file_service.py`
|
||||
|
||||
**Step 1: 修改 delete_files 方法**
|
||||
|
||||
确保响应的 code 字段为 "200 OK":
|
||||
|
||||
```python
|
||||
def delete_files(self, group_id: int, log_ids: List[int], user_id: int) -> dict:
|
||||
"""批量删除文件"""
|
||||
deleted_count = 0
|
||||
for log_id in log_ids:
|
||||
if log_id in self.file_records:
|
||||
del self.file_records[log_id]
|
||||
deleted_count += 1
|
||||
|
||||
return {
|
||||
"code": "200 OK", # 注意:这里是 "200 OK" 不是 "200"
|
||||
"data": {
|
||||
"message": "delete.files.success"
|
||||
},
|
||||
"message": "delete.files.success",
|
||||
"status": "200",
|
||||
"successResponse": True
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证删除接口响应格式正确**
|
||||
|
||||
调用删除接口,检查响应的 code 字段是否为 "200 OK"。
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 更新 token.json 响应模板
|
||||
|
||||
**Files:**
|
||||
- Modify: `config/responses/token.json`
|
||||
|
||||
**Step 1: 确认 analysisType 为 Integer**
|
||||
|
||||
确保 token.json 中的 analysisType 字段类型正确:
|
||||
|
||||
```json
|
||||
{
|
||||
"success_response": {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.mock_token_{project_id}",
|
||||
"projectId": "{project_id}",
|
||||
"projectNo": "{project_no}",
|
||||
"entityName": "{entity_name}",
|
||||
"analysisType": 0
|
||||
},
|
||||
"message": "create.token.success",
|
||||
"status": "200",
|
||||
"successResponse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
确认 `analysisType` 的值是数字 0,不是字符串 "0"。
|
||||
|
||||
**Step 2: 验证接口1响应正确**
|
||||
|
||||
调用 getToken 接口,检查 analysisType 的类型。
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 创建 upload_status.json 响应模板
|
||||
|
||||
**Files:**
|
||||
- Create: `config/responses/upload_status.json`
|
||||
|
||||
**Step 1: 创建新的响应模板文件**
|
||||
|
||||
创建文件并添加内容(虽然实际响应在代码中构建,但保留模板作为参考):
|
||||
|
||||
```json
|
||||
{
|
||||
"success_response": {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"logs": [
|
||||
{
|
||||
"accountNoList": ["18785967364"],
|
||||
"bankName": "ALIPAY",
|
||||
"dataTypeInfo": ["CSV", ","],
|
||||
"downloadFileName": "支付宝.csv",
|
||||
"enterpriseNameList": ["曾孝成"],
|
||||
"fileSize": 16322,
|
||||
"fileUploadBy": 448,
|
||||
"fileUploadByUserName": "admin@support.com",
|
||||
"fileUploadTime": "2025-03-13 08:45:32",
|
||||
"isSplit": 0,
|
||||
"leId": 10741,
|
||||
"logId": 13994,
|
||||
"logMeta": "{\"lostHeader\":[],\"balanceAmount\":\"-1\"}",
|
||||
"logType": "bankstatement",
|
||||
"loginLeId": 10741,
|
||||
"lostHeader": [],
|
||||
"realBankName": "ALIPAY",
|
||||
"rows": 0,
|
||||
"source": "http",
|
||||
"status": -5,
|
||||
"templateName": "ALIPAY_T220708",
|
||||
"totalRecords": 127,
|
||||
"trxDateEndId": 20231231,
|
||||
"trxDateStartId": 20230102,
|
||||
"uploadFileName": "支付宝.pdf",
|
||||
"uploadStatusDesc": "data.wait.confirm.newaccount"
|
||||
}
|
||||
],
|
||||
"status": "",
|
||||
"accountId": 8954,
|
||||
"currency": "CNY"
|
||||
},
|
||||
"status": "200",
|
||||
"successResponse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 9: 更新 bank_statement.json 响应模板
|
||||
|
||||
**Files:**
|
||||
- Modify: `config/responses/bank_statement.json`
|
||||
|
||||
**Step 1: 补充流水记录的所有字段**
|
||||
|
||||
确保 bank_statement.json 包含所有50+个字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"success_response": {
|
||||
"code": "200",
|
||||
"data": {
|
||||
"bankStatementList": [
|
||||
{
|
||||
"accountId": 0,
|
||||
"accountMaskNo": "101015251071645",
|
||||
"accountingDate": "2024-02-01",
|
||||
"accountingDateId": 20240201,
|
||||
"archivingFlag": 0,
|
||||
"attachments": 0,
|
||||
"balanceAmount": 4814.82,
|
||||
"bank": "ZJRCU",
|
||||
"bankComments": "",
|
||||
"bankStatementId": 12847662,
|
||||
"bankTrxNumber": "1a10458dd5c3366d7272285812d434fc",
|
||||
"batchId": 19135,
|
||||
"cashType": "1",
|
||||
"commentsNum": 0,
|
||||
"crAmount": 0,
|
||||
"cretNo": "230902199012261247",
|
||||
"currency": "CNY",
|
||||
"customerAccountMaskNo": "597671502",
|
||||
"customerBank": "",
|
||||
"customerId": -1,
|
||||
"customerName": "小店",
|
||||
"customerReference": "",
|
||||
"downPaymentFlag": 0,
|
||||
"drAmount": 245.8,
|
||||
"exceptionType": "",
|
||||
"groupId": 16238,
|
||||
"internalFlag": 0,
|
||||
"leId": 16308,
|
||||
"leName": "张传伟",
|
||||
"overrideBsId": 0,
|
||||
"paymentMethod": "",
|
||||
"sourceCatalogId": 0,
|
||||
"split": 0,
|
||||
"subBankstatementId": 0,
|
||||
"toDoFlag": 0,
|
||||
"transAmount": 245.8,
|
||||
"transFlag": "P",
|
||||
"transTypeId": 0,
|
||||
"transformAmount": 0,
|
||||
"transformCrAmount": 0,
|
||||
"transformDrAmount": 0,
|
||||
"transfromBalanceAmount": 0,
|
||||
"trxBalance": 0,
|
||||
"trxDate": "2024-02-01 10:33:44",
|
||||
"userMemo": "财付通消费_小店"
|
||||
}
|
||||
],
|
||||
"totalCount": 131
|
||||
},
|
||||
"status": "200",
|
||||
"successResponse": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证流水查询接口返回所有字段**
|
||||
|
||||
调用 getBSByLogId 接口,检查响应是否包含所有字段。
|
||||
|
||||
---
|
||||
|
||||
## Task 10: 添加 40100 错误码
|
||||
|
||||
**Files:**
|
||||
- Modify: `utils/error_simulator.py`
|
||||
|
||||
**Step 1: 在 ERROR_CODES 字典中添加新错误码**
|
||||
|
||||
```python
|
||||
ERROR_CODES = {
|
||||
"40100": {"code": "40100", "message": "未知异常"},
|
||||
"40101": {"code": "40101", "message": "appId错误"},
|
||||
"40102": {"code": "40102", "message": "appSecretCode错误"},
|
||||
"40104": {"code": "40104", "message": "可使用项目次数为0,无法创建项目"},
|
||||
"40105": {"code": "40105", "message": "只读模式下无法新建项目"},
|
||||
"40106": {"code": "40106", "message": "错误的分析类型,不在规定的取值范围内"},
|
||||
"40107": {"code": "40107", "message": "当前系统不支持的分析类型"},
|
||||
"40108": {"code": "40108", "message": "当前用户所属行社无权限"},
|
||||
"501014": {"code": "501014", "message": "无行内流水文件"},
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证错误码能正确触发**
|
||||
|
||||
调用任意接口,在参数中包含 `error_40100`,检查是否返回对应错误。
|
||||
|
||||
---
|
||||
|
||||
## Task 11: 更新 CLAUDE.md 文档
|
||||
|
||||
**Files:**
|
||||
- Modify: `CLAUDE.md`
|
||||
|
||||
**Step 1: 更新接口列表说明**
|
||||
|
||||
在 "API 接口说明" 部分更新为:
|
||||
|
||||
```markdown
|
||||
## API 接口说明
|
||||
|
||||
7个核心接口:
|
||||
|
||||
1. `/account/common/getToken` (POST) - 创建项目并获取 Token
|
||||
2. `/watson/api/project/remoteUploadSplitFile` (POST) - 上传流水文件(multipart/form-data)
|
||||
3. `/watson/api/project/getJZFileOrZjrcuFile` (POST) - 拉取行内流水
|
||||
4. `/watson/api/project/upload/getpendings` (POST) - 检查文件解析状态
|
||||
5. `/watson/api/project/bs/upload` (GET) - 获取单个文件上传后的状态
|
||||
6. `/watson/api/project/batchDeleteUploadFile` (POST) - 批量删除文件
|
||||
7. `/watson/api/project/getBSByLogId` (POST) - 获取银行流水(分页)
|
||||
|
||||
详细接口文档请访问 Swagger UI (`/docs`) 或查看 `assets/兰溪-流水分析对接3.md`。
|
||||
```
|
||||
|
||||
**Step 2: 更新注意事项**
|
||||
|
||||
添加关于响应字段完整性的说明:
|
||||
|
||||
```markdown
|
||||
## 注意事项
|
||||
|
||||
- **数据持久化**: 所有数据存储在内存中,服务重启后数据丢失
|
||||
- **响应字段完整性**: 所有接口响应字段完全对齐接口文档示例
|
||||
- **并发安全**: 当前实现未考虑多线程安全,生产环境需要加锁
|
||||
- **文件存储**: 上传的文件不实际保存,仅模拟元数据
|
||||
- **错误标记**: 错误触发通过字符串匹配实现,确保测试数据唯一性
|
||||
- **后台任务**: FastAPI BackgroundTasks 在同一进程内执行,不会阻塞响应
|
||||
- **请求头处理**: X-Xencio-Client-Id 请求头不验证,接受任意值
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 12: 最终验证
|
||||
|
||||
**Files:**
|
||||
- All modified files
|
||||
|
||||
**Step 1: 启动服务**
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
预期:服务正常启动,无报错。
|
||||
|
||||
**Step 2: 访问 Swagger 文档**
|
||||
|
||||
访问 http://localhost:8000/docs
|
||||
|
||||
预期:能看到所有7个接口,包括新增的 GET 接口。
|
||||
|
||||
**Step 3: 测试所有7个接口**
|
||||
|
||||
使用 Swagger UI 或 curl 测试每个接口,确保:
|
||||
1. 接口1:返回包含 analysisType (Integer) 的响应
|
||||
2. 接口2:返回包含 accountsOfLog 和完整 uploadLogList 的响应
|
||||
3. 接口3:返回 logId 数组
|
||||
4. 接口4:返回包含完整字段的 pendingList
|
||||
5. 接口5:返回包含完整字段的 logs 数组
|
||||
6. 接口6:返回 code 为 "200 OK" 的响应
|
||||
7. 接口7:返回包含所有50+字段的 bankStatementList
|
||||
|
||||
**Step 4: 测试错误码**
|
||||
|
||||
调用接口1,使用参数 `projectNo: "test_error_40100"`
|
||||
|
||||
预期:返回 40100 错误。
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] FileRecord 包含所有必需字段
|
||||
- [x] upload_file 方法正确初始化所有字段
|
||||
- [x] get_upload_status 方法正确实现
|
||||
- [x] 新接口出现在 /docs 中
|
||||
- [x] 所有响应字段完全对齐文档示例
|
||||
- [x] 40100 错误码能正确触发
|
||||
- [x] 服务启动无报错
|
||||
- [x] 所有7个接口都能正常调用
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- 所有代码修改都保持向后兼容
|
||||
- 无需数据库迁移(使用内存存储)
|
||||
- 错误处理机制保持不变
|
||||
- 请求头 X-Xencio-Client-Id 不验证
|
||||
Reference in New Issue
Block a user