diff --git a/app.py b/app.py index e2525cb..6e4169d 100644 --- a/app.py +++ b/app.py @@ -700,6 +700,133 @@ def generate_document(): return error_response(3001, f"文档生成失败: {str(e)}") +@app.route('/fPolicTask/getDocument', methods=['POST']) +def get_document_by_task(): + """ + 通过taskId获取文档(兼容接口) + 支持通过taskId查询关联的文件列表,或直接使用提供的文件列表 + """ + try: + data = request.get_json() + + # 验证请求参数 + if not data: + return error_response(400, "请求参数不能为空") + + task_id = data.get('taskId') + input_data = data.get('inputData', []) + file_list = data.get('fpolicFieldParamFileList', []) + + # 如果没有提供file_list,尝试通过taskId查询 + if not file_list and task_id: + try: + conn = document_service.get_connection() + cursor = conn.cursor(pymysql.cursors.DictCursor) + + try: + # 尝试从f_polic_task表查询关联的文件列表 + # 注意:这里需要根据实际表结构调整SQL + sql = """ + SELECT file_id, file_name + FROM f_polic_task_file + WHERE task_id = %s + AND tenant_id = %s + AND state = 1 + """ + cursor.execute(sql, (task_id, document_service.tenant_id)) + task_files = cursor.fetchall() + + if task_files: + file_list = [] + for tf in task_files: + file_list.append({ + 'fileId': tf['file_id'], + 'fileName': tf.get('file_name', '') + }) + except Exception as e: + # 如果表不存在或查询失败,记录日志但不报错 + print(f"[WARN] 无法通过taskId查询文件列表: {str(e)}") + finally: + cursor.close() + conn.close() + except Exception as e: + print(f"[WARN] 查询taskId关联文件时出错: {str(e)}") + + # 如果仍然没有file_list,返回错误 + if not file_list: + return error_response(400, "缺少fpolicFieldParamFileList参数,且无法通过taskId查询到关联文件。请提供fpolicFieldParamFileList参数,格式: [{'fileId': 文件ID, 'fileName': '文件名'}]") + + if not input_data or not isinstance(input_data, list): + return error_response(400, "inputData参数必须是非空数组") + + if not file_list or not isinstance(file_list, list): + return error_response(400, "fpolicFieldParamFileList参数必须是非空数组") + + # 将input_data转换为字典格式(用于生成文档名称) + field_data = {} + for item in input_data: + field_code = item.get('fieldCode', '') + field_value = item.get('fieldValue', '') + if field_code: + field_data[field_code] = field_value or '' + + # 生成文档ID + document_id = document_service.generate_document_id() + + # 处理每个文件 + result_file_list = [] + first_document_name = None # 用于存储第一个生成的文档名 + + for file_info in file_list: + file_id = file_info.get('fileId') + file_name = file_info.get('fileName', '') + + if not file_id: + return error_response(1001, f"文件 {file_name} 缺少fileId参数") + + try: + # 生成文档(使用fileId而不是templateCode) + result = document_service.generate_document( + file_id=file_id, + input_data=input_data, + file_info=file_info + ) + + # 使用生成的文档名称(.docx格式),而不是原始文件名 + generated_file_name = result.get('fileName', file_name) + + # 保存第一个文档名作为 documentName + if first_document_name is None: + first_document_name = generated_file_name + + result_file_list.append({ + 'fileId': file_id, + 'fileName': generated_file_name, # 使用生成的文档名 + 'filePath': result['filePath'] + }) + + except Exception as e: + error_msg = str(e) + if '不存在' in error_msg or '模板' in error_msg: + return error_response(1001, error_msg) + elif '生成' in error_msg or '填充' in error_msg: + return error_response(3001, error_msg) + elif '上传' in error_msg or '保存' in error_msg: + return error_response(3002, error_msg) + else: + return error_response(3001, f"文件生成失败: {error_msg}") + + # 构建返回数据(不包含inputData,只返回生成的文档信息) + return success_response({ + 'documentId': document_id, + 'documentName': first_document_name or 'generated.docx', # 使用第一个生成的文档名 + 'fpolicFieldParamFileList': result_file_list + }) + + except Exception as e: + return error_response(3001, f"文档生成失败: {str(e)}") + + if __name__ == '__main__': # 确保static目录存在 os.makedirs('static', exist_ok=True) diff --git a/services/document_service.py b/services/document_service.py index cacc49a..239340c 100644 --- a/services/document_service.py +++ b/services/document_service.py @@ -134,28 +134,43 @@ class DocumentService: # 打开模板文档 doc = Document(template_path) - # 替换占位符 {{field_code}} 为实际值 - for paragraph in doc.paragraphs: - # 替换段落文本中的占位符 + def replace_placeholder_in_paragraph(paragraph): + """在段落中替换占位符(处理跨run的情况)""" + # 获取段落完整文本 + full_text = paragraph.text + if not full_text: + return + + # 检查是否有占位符需要替换 + has_placeholder = False + replaced_text = full_text + for field_code, field_value in field_data.items(): placeholder = f"{{{{{field_code}}}}}" - if placeholder in paragraph.text: - # 替换占位符 - for run in paragraph.runs: - if placeholder in run.text: - run.text = run.text.replace(placeholder, field_value or '') + if placeholder in replaced_text: + has_placeholder = True + replaced_text = replaced_text.replace(placeholder, field_value or '') + + # 如果有替换,更新段落文本 + if has_placeholder: + # 清空所有run + paragraph.clear() + # 添加新的run并设置替换后的文本 + if replaced_text: + paragraph.add_run(replaced_text) + + # 替换段落中的占位符 + for paragraph in doc.paragraphs: + replace_placeholder_in_paragraph(paragraph) # 替换表格中的占位符 for table in doc.tables: for row in table.rows: for cell in row.cells: - for paragraph in cell.paragraphs: - for field_code, field_value in field_data.items(): - placeholder = f"{{{{{field_code}}}}}" - if placeholder in paragraph.text: - for run in paragraph.runs: - if placeholder in run.text: - run.text = run.text.replace(placeholder, field_value or '') + # 检查cell是否有paragraphs属性且不为空 + if hasattr(cell, 'paragraphs') and cell.paragraphs: + for paragraph in cell.paragraphs: + replace_placeholder_in_paragraph(paragraph) # 保存到临时文件 temp_dir = tempfile.gettempdir()