diff --git a/generate_download_urls.py b/generate_download_urls.py index 0ae87f1..342dc0d 100644 --- a/generate_download_urls.py +++ b/generate_download_urls.py @@ -1,9 +1,16 @@ """ 为指定的文件路径生成 MinIO 预签名下载 URL """ +import sys +import io from minio import Minio 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_CONFIG = { 'endpoint': 'minio.datacubeworld.com:9000', @@ -16,8 +23,8 @@ BUCKET_NAME = 'finyx' # 文件相对路径列表 FILE_PATHS = [ - '/615873064429507639/20251210155041/初步核实审批表_张三.docx', - '/615873064429507639/20251210155041/请示报告卡_张三.docx' + '/615873064429507639/20251211101046/1_张三.docx', + '/615873064429507639/20251211101046/1_张三.docx' ] def generate_download_urls(): @@ -52,7 +59,7 @@ def generate_download_urls(): try: # 检查文件是否存在 stat = client.stat_object(BUCKET_NAME, object_name) - print(f"✓ 文件存在") + print(f"[OK] 文件存在") print(f" 文件大小: {stat.size:,} 字节") print(f" 最后修改: {stat.last_modified}") @@ -63,7 +70,7 @@ def generate_download_urls(): expires=timedelta(days=7) ) - print(f"✓ 预签名URL生成成功(7天有效)") + print(f"[OK] 预签名URL生成成功(7天有效)") print(f"\n下载链接:") print(f"{url}\n") @@ -76,7 +83,7 @@ def generate_download_urls(): }) except Exception as e: - print(f"✗ 错误: {e}\n") + print(f"[ERROR] 错误: {e}\n") results.append({ 'file_path': file_path, 'object_name': object_name, @@ -93,10 +100,10 @@ def generate_download_urls(): for i, result in enumerate(results, 1): print(f"\n{i}. {result['file_path']}") if result['exists']: - print(f" ✓ 文件存在") + print(f" [OK] 文件存在") print(f" 下载链接: {result['url']}") else: - print(f" ✗ 文件不存在或无法访问") + print(f" [ERROR] 文件不存在或无法访问") if 'error' in result: print(f" 错误: {result['error']}") @@ -107,7 +114,7 @@ def generate_download_urls(): return results except Exception as e: - print(f"\n✗ 连接MinIO失败: {e}") + print(f"\n[ERROR] 连接MinIO失败: {e}") import traceback traceback.print_exc() return None diff --git a/services/document_service.py b/services/document_service.py index 322a065..7bfdaab 100644 --- a/services/document_service.py +++ b/services/document_service.py @@ -303,8 +303,9 @@ class DocumentService: try: # 生成MinIO对象路径(相对路径) 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( @@ -366,11 +367,14 @@ class DocumentService: # 生成文档名称(.docx格式) # 优先使用file_info中的fileName,如果没有则使用数据库中的name + # 确保每个文件都使用自己的文件名 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}") 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(使用生成的文档名) file_path = self.upload_to_minio(filled_doc_path, generated_file_name) @@ -407,17 +411,54 @@ class DocumentService: field_data: 字段数据 Returns: - 生成的文档名称,如 "初步核实审批表_张三.docx" + 生成的文档名称,如 "请示报告卡_张三.docx" """ + import re + # 提取文件基础名称(不含扩展名) # 处理可能包含路径的情况 - base_name = Path(original_file_name).stem + # 先移除路径,只保留文件名 + file_name_only = Path(original_file_name).name - # 清理文件名中的特殊字符(如括号等,但保留中文) - # 移除常见的模板标记,如 "(XXX)"、"(初核谈话)" 等 - import re - base_name = re.sub(r'[((].*?[))]', '', base_name) # 移除括号及其内容 - base_name = base_name.strip() + # 判断是否有扩展名(.doc, .docx等) + # 如果最后有常见的文档扩展名,则提取stem + if file_name_only.lower().endswith(('.doc', '.docx', '.txt', '.pdf')): + base_name = Path(file_name_only).stem + 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 = ''