更新生成下载链接的逻辑,添加Windows平台的UTF-8编码支持,优化输出信息格式,确保错误信息和状态提示更加清晰。同时,更新文档服务中的文件路径生成逻辑,确保文件名唯一性并增强调试信息的详细性。

This commit is contained in:
python 2025-12-11 10:16:38 +08:00
parent b0360cc15b
commit 4084cb1819
2 changed files with 67 additions and 19 deletions

View File

@ -1,9 +1,16 @@
""" """
为指定的文件路径生成 MinIO 预签名下载 URL 为指定的文件路径生成 MinIO 预签名下载 URL
""" """
import sys
import io
from minio import Minio from minio import Minio
from datetime import timedelta from datetime import timedelta
# 设置输出编码为UTF-8避免Windows控制台编码问题
if sys.platform == 'win32':
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
# MinIO连接配置 # MinIO连接配置
MINIO_CONFIG = { MINIO_CONFIG = {
'endpoint': 'minio.datacubeworld.com:9000', 'endpoint': 'minio.datacubeworld.com:9000',
@ -16,8 +23,8 @@ BUCKET_NAME = 'finyx'
# 文件相对路径列表 # 文件相对路径列表
FILE_PATHS = [ FILE_PATHS = [
'/615873064429507639/20251210155041/初步核实审批表_张三.docx', '/615873064429507639/20251211101046/1_张三.docx',
'/615873064429507639/20251210155041/请示报告卡_张三.docx' '/615873064429507639/20251211101046/1_张三.docx'
] ]
def generate_download_urls(): def generate_download_urls():
@ -52,7 +59,7 @@ def generate_download_urls():
try: try:
# 检查文件是否存在 # 检查文件是否存在
stat = client.stat_object(BUCKET_NAME, object_name) stat = client.stat_object(BUCKET_NAME, object_name)
print(f" 文件存在") print(f"[OK] 文件存在")
print(f" 文件大小: {stat.size:,} 字节") print(f" 文件大小: {stat.size:,} 字节")
print(f" 最后修改: {stat.last_modified}") print(f" 最后修改: {stat.last_modified}")
@ -63,7 +70,7 @@ def generate_download_urls():
expires=timedelta(days=7) expires=timedelta(days=7)
) )
print(f" 预签名URL生成成功7天有效") print(f"[OK] 预签名URL生成成功7天有效")
print(f"\n下载链接:") print(f"\n下载链接:")
print(f"{url}\n") print(f"{url}\n")
@ -76,7 +83,7 @@ def generate_download_urls():
}) })
except Exception as e: except Exception as e:
print(f" 错误: {e}\n") print(f"[ERROR] 错误: {e}\n")
results.append({ results.append({
'file_path': file_path, 'file_path': file_path,
'object_name': object_name, 'object_name': object_name,
@ -93,10 +100,10 @@ def generate_download_urls():
for i, result in enumerate(results, 1): for i, result in enumerate(results, 1):
print(f"\n{i}. {result['file_path']}") print(f"\n{i}. {result['file_path']}")
if result['exists']: if result['exists']:
print(f" 文件存在") print(f" [OK] 文件存在")
print(f" 下载链接: {result['url']}") print(f" 下载链接: {result['url']}")
else: else:
print(f" 文件不存在或无法访问") print(f" [ERROR] 文件不存在或无法访问")
if 'error' in result: if 'error' in result:
print(f" 错误: {result['error']}") print(f" 错误: {result['error']}")
@ -107,7 +114,7 @@ def generate_download_urls():
return results return results
except Exception as e: except Exception as e:
print(f"\n 连接MinIO失败: {e}") print(f"\n[ERROR] 连接MinIO失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return None return None

View File

@ -303,8 +303,9 @@ class DocumentService:
try: try:
# 生成MinIO对象路径相对路径 # 生成MinIO对象路径相对路径
now = datetime.now() now = datetime.now()
# 使用日期路径组织文件 # 使用日期路径组织文件,添加微秒确保唯一性
object_name = f"{self.tenant_id}/{now.strftime('%Y%m%d%H%M%S')}/{file_name}" timestamp = f"{now.strftime('%Y%m%d%H%M%S')}{now.microsecond:06d}"
object_name = f"{self.tenant_id}/{timestamp}/{file_name}"
# 上传文件 # 上传文件
client.fput_object( client.fput_object(
@ -366,11 +367,14 @@ class DocumentService:
# 生成文档名称(.docx格式 # 生成文档名称(.docx格式
# 优先使用file_info中的fileName如果没有则使用数据库中的name # 优先使用file_info中的fileName如果没有则使用数据库中的name
# 确保每个文件都使用自己的文件名
original_file_name = file_info.get('fileName') or file_info.get('name') or file_config.get('name', 'generated.doc') original_file_name = file_info.get('fileName') or file_info.get('name') or file_config.get('name', 'generated.doc')
print(f"[DEBUG] 原始文件名: {original_file_name}") print(f"[DEBUG] 文件ID: {file_id}, 原始文件名: {original_file_name}")
print(f"[DEBUG] file_info内容: {file_info}")
print(f"[DEBUG] file_config内容: {file_config}")
print(f"[DEBUG] 字段数据用于生成文档名: {field_data}") print(f"[DEBUG] 字段数据用于生成文档名: {field_data}")
generated_file_name = self.generate_document_name(original_file_name, field_data) generated_file_name = self.generate_document_name(original_file_name, field_data)
print(f"[DEBUG] 生成的文档名: {generated_file_name}") print(f"[DEBUG] 文件ID: {file_id}, 生成的文档名: {generated_file_name}")
# 上传到MinIO使用生成的文档名 # 上传到MinIO使用生成的文档名
file_path = self.upload_to_minio(filled_doc_path, generated_file_name) file_path = self.upload_to_minio(filled_doc_path, generated_file_name)
@ -407,17 +411,54 @@ class DocumentService:
field_data: 字段数据 field_data: 字段数据
Returns: Returns:
生成的文档名称 "初步核实审批表_张三.docx" 生成的文档名称 "请示报告卡_张三.docx"
""" """
import re
# 提取文件基础名称(不含扩展名) # 提取文件基础名称(不含扩展名)
# 处理可能包含路径的情况 # 处理可能包含路径的情况
base_name = Path(original_file_name).stem # 先移除路径,只保留文件名
file_name_only = Path(original_file_name).name
# 清理文件名中的特殊字符(如括号等,但保留中文) # 判断是否有扩展名(.doc, .docx等
# 移除常见的模板标记,如 "XXX"、"(初核谈话)" 等 # 如果最后有常见的文档扩展名则提取stem
import re if file_name_only.lower().endswith(('.doc', '.docx', '.txt', '.pdf')):
base_name = re.sub(r'[(].*?[)]', '', base_name) # 移除括号及其内容 base_name = Path(file_name_only).stem
base_name = base_name.strip() else:
# 如果没有扩展名,直接使用文件名
base_name = file_name_only
print(f"[DEBUG] 原始文件名: '{original_file_name}'")
print(f"[DEBUG] 提取的基础名称(清理前): '{base_name}'")
# 清理文件名中的特殊标记
# 1. 移除开头的数字和点(如 "1."、"2." 等),但保留后面的内容
# 使用非贪婪匹配,只匹配开头的数字和点
base_name = re.sub(r'^\d+\.\s*', '', base_name)
# 2. 移除括号及其内容(如 "XXX"、"(初核谈话)" 等)
base_name = re.sub(r'[(].*?[)]', '', base_name)
# 3. 清理首尾空白字符和多余的点
base_name = base_name.strip().strip('.')
# 4. 如果清理后为空或只有数字,使用原始文件名重新处理
if not base_name or base_name.isdigit():
print(f"[DEBUG] 清理后为空或只有数字,重新处理原始文件名")
# 从原始文件名中提取,但保留更多内容
temp_name = file_name_only
# 只移除括号,保留数字前缀(但格式化为更友好的形式)
temp_name = re.sub(r'[(].*?[)]', '', temp_name)
# 移除扩展名(如果存在)
if temp_name.lower().endswith(('.doc', '.docx', '.txt', '.pdf')):
temp_name = Path(temp_name).stem
temp_name = temp_name.strip().strip('.')
if temp_name:
base_name = temp_name
else:
base_name = "文档" # 最后的备选方案
print(f"[DEBUG] 清理后的基础名称: '{base_name}'")
# 尝试从字段数据中提取被核查人姓名作为后缀 # 尝试从字段数据中提取被核查人姓名作为后缀
suffix = '' suffix = ''