diff --git a/app.py b/app.py index 2d5b7f7..3fde014 100644 --- a/app.py +++ b/app.py @@ -153,10 +153,10 @@ def index(): @app.route('/upload', methods=['POST']) def upload_image(): """ - 处理图片上传请求,调用OCR识别并存储结果 + 处理图片上传请求,调用OCR识别但不存储结果 返回: - JSON: 上传成功或失败的响应 + JSON: 识别结果,供用户编辑确认 """ # 获取上传的文件 file = request.files.get('file') @@ -173,20 +173,13 @@ def upload_image(): print(f"开始处理图片: {image_path}") original_data = ocr_and_extract_info(image_path) # 获取原始JSON数据 if original_data: - # 使用json_converter将JSON数据转换为字符串 - data_string = json_to_string(original_data) - print(f"转换后的数据字符串: {data_string}") - - # 构造新的数据结构,只包含data和image字段 - processed_data = { - "data": data_string, - "image": filename # 存储图片文件名 - } - print(f"准备存储的数据: {processed_data}") - - insert_data(processed_data) # 存入ES - print("✓ 数据成功存储到Elasticsearch") - return jsonify({"message": "成功录入", "data": original_data, "processed": processed_data}) + print(f"识别成功: {original_data}") + # 返回识别结果和图片文件名,供用户编辑确认 + return jsonify({ + "message": "识别成功,请确认数据后点击录入", + "data": original_data, + "image": filename + }) else: print("✗ 无法识别图片内容") return jsonify({"error": "无法识别图片内容"}), 400 @@ -194,6 +187,49 @@ def upload_image(): print(f"✗ 处理过程中发生错误: {str(e)}") return jsonify({"error": str(e)}), 500 +# 确认录入路由 +@app.route('/confirm', methods=['POST']) +def confirm_data(): + """ + 确认并录入用户编辑后的数据 + + 返回: + JSON: 录入成功或失败的响应 + """ + try: + # 获取前端提交的数据 + request_data = request.get_json() + if not request_data: + return jsonify({"error": "没有接收到数据"}), 400 + + # 获取编辑后的数据和图片文件名 + edited_data = request_data.get('data', {}) + image_filename = request_data.get('image', '') + + if not edited_data: + return jsonify({"error": "数据不能为空"}), 400 + + # 使用json_converter将JSON数据转换为字符串 + data_string = json_to_string(edited_data) + print(f"转换后的数据字符串: {data_string}") + + # 构造新的数据结构,只包含data和image字段 + processed_data = { + "data": data_string, + "image": image_filename # 存储图片文件名 + } + print(f"准备存储的数据: {processed_data}") + + # 存入ES + insert_data(processed_data) + print("✓ 数据成功存储到Elasticsearch") + + return jsonify({"message": "数据录入成功", "data": edited_data}) + + except Exception as e: + print(f"✗ 录入过程中发生错误: {str(e)}") + return jsonify({"error": str(e)}), 500 + # 搜索路由 @app.route('/search') def search(): @@ -276,6 +312,21 @@ def show_all(): return render_template('all.html', data=processed_data) +# 添加图片路由 +@app.route('/image/') +def serve_image(filename): + """ + 提供图片文件服务 + + 参数: + filename (str): 图片文件名 + + 返回: + Response: 图片文件响应 + """ + from flask import send_from_directory + return send_from_directory('image', filename) + # 删除数据路由 @app.route('/delete/', methods=['POST']) def delete_entry(doc_id): diff --git a/templates/index.html b/templates/index.html index 96c90ba..c44fe09 100644 --- a/templates/index.html +++ b/templates/index.html @@ -20,72 +20,255 @@ -
+ + {% endblock %} \ No newline at end of file diff --git a/templates/results.html b/templates/results.html index e895619..9c81631 100644 --- a/templates/results.html +++ b/templates/results.html @@ -82,6 +82,7 @@ box-shadow: 0 2px 10px rgba(0,0,0,0.05); border-left: 4px solid #3498db; transition: transform 0.3s; + cursor: pointer; } .result-item:hover { @@ -89,14 +90,119 @@ box-shadow: 0 5px 15px rgba(0,0,0,0.1); } - .result-item p { - margin-bottom: 10px; - line-height: 1.6; + .result-preview { + margin-bottom: 15px; + } + + .result-preview .field-item { + display: inline-block; + margin-right: 20px; + margin-bottom: 8px; + padding: 5px 10px; + background: #f8f9fa; + border-radius: 4px; + border: 1px solid #e9ecef; + } + + .result-preview .field-label { + font-weight: bold; + color: #2c3e50; + margin-right: 5px; + } + + .result-preview .field-value { color: #34495e; } - .result-item strong { + .result-details { + display: none; + border-top: 1px solid #e9ecef; + padding-top: 15px; + margin-top: 15px; + } + + .result-details.expanded { + display: block; + } + + .result-details .field-item { + margin-bottom: 10px; + padding: 8px 12px; + background: #f8f9fa; + border-radius: 4px; + border-left: 3px solid #3498db; + } + + .result-details .field-label { + font-weight: bold; color: #2c3e50; + display: inline-block; + min-width: 120px; + } + + .result-details .field-value { + color: #34495e; + } + + .expand-indicator { + float: right; + color: #3498db; + font-size: 14px; + transition: all 0.3s; + } + + .result-item.expanded .expand-indicator { + color: #2c3e50; + } + + .image-container { + margin-top: 15px; + text-align: center; + } + + .result-image { + max-width: 100%; + max-height: 300px; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + cursor: pointer; + transition: transform 0.3s; + } + + .result-image:hover { + transform: scale(1.05); + } + + .image-modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.8); + cursor: pointer; + } + + .image-modal img { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + max-width: 90%; + max-height: 90%; + border-radius: 8px; + } + + .close-modal { + position: absolute; + top: 20px; + right: 30px; + color: white; + font-size: 30px; + font-weight: bold; + cursor: pointer; } /* 加载状态 */ @@ -152,22 +258,47 @@ return; } - const html = realData.map(item => { + const html = realData.map((item, index) => { const source = item._source || {}; - const students = Array.isArray(source.students) - ? source.students.join(', ') - : (source.students || '无'); + const allFields = Object.entries(source).filter(([key, value]) => key !== 'image' && value); - const teacher = Array.isArray(source.teacher) - ? source.teacher.join(', ') - : (source.teacher || '无'); + // 获取前3个字段作为预览 + const previewFields = allFields.slice(0, 3); + const hasMoreFields = allFields.length > 3; + + // 生成预览字段HTML + const previewHtml = previewFields.map(([key, value]) => ` +
+ ${key}: + ${Array.isArray(value) ? value.join(', ') : value} +
+ `).join(''); + + // 生成详细字段HTML + const detailsHtml = allFields.map(([key, value]) => ` +
+ ${key}: + ${Array.isArray(value) ? value.join(', ') : value} +
+ `).join(''); + + // 图片HTML + const imageHtml = source.image ? ` +
+ 相关图片 +
+ ` : ''; return ` -
-

比赛/论文名称:${source.id || '无'}

-

项目名称:${source.name || '无'}

-

学生:${students}

-

指导老师:${teacher}

+
+
+ ${previewHtml} + ${hasMoreFields ? '▼ 点击查看更多' : ''} +
+
+ ${detailsHtml} + ${imageHtml} +
`; }).join(''); @@ -178,5 +309,54 @@ resultsContainer.innerHTML = '
搜索过程中发生错误
'; }); }); + + function toggleDetails(index) { + const resultItem = document.querySelector(`[data-index="${index}"]`); + const detailsDiv = document.getElementById(`details-${index}`); + + if (detailsDiv.classList.contains('expanded')) { + detailsDiv.classList.remove('expanded'); + resultItem.classList.remove('expanded'); + } else { + detailsDiv.classList.add('expanded'); + resultItem.classList.add('expanded'); + } + } + + function openImageModal(imageSrc) { + event.stopPropagation(); // 阻止事件冒泡 + + // 创建模态框 + const modal = document.createElement('div'); + modal.className = 'image-modal'; + modal.innerHTML = ` + × + 图片预览 + `; + + document.body.appendChild(modal); + modal.style.display = 'block'; + + // 点击模态框背景关闭 + modal.addEventListener('click', function(e) { + if (e.target === modal) { + closeImageModal(); + } + }); + } + + function closeImageModal() { + const modal = document.querySelector('.image-modal'); + if (modal) { + modal.remove(); + } + } + + // ESC键关闭模态框 + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + closeImageModal(); + } + }); {% endblock %}