初始化

This commit is contained in:
zg
2026-07-15 16:08:17 +08:00
parent f0d70aded4
commit 4e0057ece5
89 changed files with 13512 additions and 0 deletions

130
backend/file_service.py Normal file
View File

@@ -0,0 +1,130 @@
"""文件对象存储服务客户端 — https://file.wg.zgitm.com
认证方式:一次性 Token每次操作前获取
系统编码mokeetext-edit
"""
import requests
BASE_URL = "https://file.wg.zgitm.com"
SYSTEM_CODE = "mokeetext-edit"
FOLDER_PATH = "/mokeetext-images/" # 图片统一存放目录
def get_token(system_code: str = SYSTEM_CODE) -> str:
"""获取一次性 Token"""
resp = requests.post(
f"{BASE_URL}/api/token",
json={"systemCode": system_code},
timeout=15,
)
data = resp.json()
if data.get("code") != 200:
raise RuntimeError(f"获取文件服务 Token 失败: {data.get('message')}")
return data["data"]["token"]
def upload_file(
file_data: bytes,
filename: str,
content_type: str,
upload_user: str = "",
) -> dict:
"""
上传文件到文件服务
返回: {"fileId": "...", "fileName": "...", "fileSize": 123}
"""
token = get_token()
resp = requests.post(
f"{BASE_URL}/api/upload",
headers={"Authorization": f"Bearer {token}"},
files={"file": (filename, file_data, content_type)},
data={
"folderPath": FOLDER_PATH,
"uploadUser": upload_user,
},
timeout=60,
)
data = resp.json()
if data.get("code") != 200:
raise RuntimeError(f"上传文件失败: {data.get('message')}")
return data["data"]
def download_file(file_id: str) -> tuple[bytes, str, str]:
"""
从文件服务下载文件
返回: (binary_data, content_type, filename)
"""
token = get_token()
resp = requests.get(
f"{BASE_URL}/api/download/{file_id}",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
if resp.status_code == 404:
raise FileNotFoundError(f"文件不存在: {file_id}")
if resp.status_code != 200:
try:
err = resp.json()
raise RuntimeError(f"下载文件失败: {err.get('message', resp.text)}")
except ValueError:
raise RuntimeError(f"下载文件失败: HTTP {resp.status_code}")
content_type = resp.headers.get("Content-Type", "application/octet-stream")
# 从 Content-Disposition 提取文件名
filename = file_id
disposition = resp.headers.get("Content-Disposition", "")
if "filename*=" in disposition:
# filename*=UTF-8''原始文件名
parts = disposition.split("filename*=")
if len(parts) > 1:
fname = parts[1].strip()
if "''" in fname:
filename = fname.split("''", 1)[1]
elif 'filename="' in disposition:
filename = disposition.split('filename="')[1].rstrip('"')
return resp.content, content_type, filename
def delete_file(file_id: str) -> bool:
"""删除文件服务中的文件"""
token = get_token()
resp = requests.get(
f"{BASE_URL}/api/delete/{file_id}",
headers={"Authorization": f"Bearer {token}"},
timeout=15,
)
data = resp.json()
if data.get("code") == 404:
return False # 文件已不存在,也算删除成功
if data.get("code") != 200:
raise RuntimeError(f"删除文件失败: {data.get('message')}")
return True
def ensure_folder() -> bool:
"""确保图片存放目录存在"""
token = get_token()
resp = requests.post(
f"{BASE_URL}/api/folder/create",
headers={"Authorization": f"Bearer {token}"},
json={
"folderPath": FOLDER_PATH,
"createdBy": SYSTEM_CODE,
},
timeout=15,
)
data = resp.json()
if data.get("code") == 400 and "已存在" in data.get("message", ""):
return True # 文件夹已存在,没问题
if data.get("code") != 200:
raise RuntimeError(f"创建文件夹失败: {data.get('message')}")
return True