feat: redesign db admin import flow
This commit is contained in:
parent
fd82b757fe
commit
66cc871e47
|
|
@ -6,7 +6,7 @@ import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from flask import Blueprint, jsonify, request, send_file
|
from flask import Blueprint, jsonify, request, send_file
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from lawrisk.api.auth import login_required, get_current_user
|
from lawrisk.api.auth import login_required, get_current_user
|
||||||
from lawrisk.services.lawrisk_v2_service import search_v2, list_regions
|
from lawrisk.services.lawrisk_v2_service import search_v2, list_regions
|
||||||
|
|
@ -14,6 +14,7 @@ from lawrisk.services.licensing_repo import (
|
||||||
list_permits_for_region,
|
list_permits_for_region,
|
||||||
load_permits_and_risks,
|
load_permits_and_risks,
|
||||||
list_region_theme_options,
|
list_region_theme_options,
|
||||||
|
list_region_permit_catalog,
|
||||||
load_theme_payload,
|
load_theme_payload,
|
||||||
create_checkpoint,
|
create_checkpoint,
|
||||||
list_checkpoints,
|
list_checkpoints,
|
||||||
|
|
@ -26,6 +27,8 @@ from lawrisk.services.licensing_repo import (
|
||||||
start_permit_import_session,
|
start_permit_import_session,
|
||||||
commit_permit_import_session,
|
commit_permit_import_session,
|
||||||
fetch_permit_file,
|
fetch_permit_file,
|
||||||
|
describe_permit_import_session,
|
||||||
|
resolve_region_permit_theme,
|
||||||
)
|
)
|
||||||
from lawrisk.services.lawrisk_service import suggest_questions_embed
|
from lawrisk.services.lawrisk_service import suggest_questions_embed
|
||||||
|
|
||||||
|
|
@ -220,27 +223,35 @@ def admin_themes():
|
||||||
|
|
||||||
@v2_bp.route('/admin/permits', methods=['GET'])
|
@v2_bp.route('/admin/permits', methods=['GET'])
|
||||||
def admin_permits():
|
def admin_permits():
|
||||||
"""Get permits for a specific region-theme combination."""
|
"""Get permits for a region. Optional theme filter keeps backward compatibility."""
|
||||||
region_value = request.args.get("region") or request.args.get("region_id")
|
region_value = request.args.get("region") or request.args.get("region_id")
|
||||||
theme_value = request.args.get("theme") or request.args.get("theme_id")
|
theme_value = request.args.get("theme") or request.args.get("theme_id")
|
||||||
|
|
||||||
if not region_value or not theme_value:
|
if not region_value or (isinstance(region_value, str) and not region_value.strip()):
|
||||||
return jsonify({"success": False, "message": "region and theme are required", "data": {}}), 400
|
return jsonify({"success": False, "message": "region is required", "data": {}}), 400
|
||||||
|
|
||||||
region_token = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
region_token = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
||||||
theme_token = theme_value.strip() if isinstance(theme_value, str) else str(theme_value)
|
theme_token = (
|
||||||
|
theme_value.strip()
|
||||||
|
if theme_value and isinstance(theme_value, str)
|
||||||
|
else (str(theme_value) if theme_value is not None else None)
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if theme_token:
|
||||||
permits = load_permits_and_risks(region_token, theme_token)
|
permits = load_permits_and_risks(region_token, theme_token)
|
||||||
|
data = {
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"data": {
|
|
||||||
"region": region_token,
|
"region": region_token,
|
||||||
"theme": theme_token,
|
"theme": theme_token,
|
||||||
"permits": permits
|
"permits": permits,
|
||||||
}
|
}
|
||||||
})
|
else:
|
||||||
|
catalog = list_region_permit_catalog(region_token)
|
||||||
|
data = {
|
||||||
|
"region": region_token,
|
||||||
|
"permits": catalog,
|
||||||
|
}
|
||||||
|
return jsonify({"success": True, "data": data})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f"admin_permits error: {exc}")
|
print(f"admin_permits error: {exc}")
|
||||||
return jsonify({"success": False, "message": str(exc)}), 500
|
return jsonify({"success": False, "message": str(exc)}), 500
|
||||||
|
|
@ -297,6 +308,35 @@ def admin_permit_import_template():
|
||||||
return jsonify({"success": False, "message": "模板文件暂时无法下载"}), 500
|
return jsonify({"success": False, "message": "模板文件暂时无法下载"}), 500
|
||||||
|
|
||||||
|
|
||||||
|
def _build_import_preview_response(session_token: str):
|
||||||
|
"""Internal helper to build preview response JSON."""
|
||||||
|
try:
|
||||||
|
data = describe_permit_import_session(session_token)
|
||||||
|
return jsonify({"success": True, "data": data})
|
||||||
|
except ValueError as exc:
|
||||||
|
return jsonify({"success": False, "message": str(exc)}), 400
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"admin_permit_import_preview error: {exc}")
|
||||||
|
return jsonify({"success": False, "message": "无法加载预览数据"}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@v2_bp.route('/admin/permit-import/session/<session_id>/preview', methods=['GET'])
|
||||||
|
def admin_permit_import_preview(session_id: str):
|
||||||
|
"""Return parsed workbook preview along with theme options (path param)."""
|
||||||
|
if not session_id:
|
||||||
|
return jsonify({"success": False, "message": "session_id 不能为空"}), 400
|
||||||
|
return _build_import_preview_response(session_id)
|
||||||
|
|
||||||
|
|
||||||
|
@v2_bp.route('/admin/permit-import/preview', methods=['GET'])
|
||||||
|
def admin_permit_import_preview_query():
|
||||||
|
"""Return preview via query string for compatibility."""
|
||||||
|
session_id = request.args.get("session_id") or request.args.get("sessionId")
|
||||||
|
if not session_id:
|
||||||
|
return jsonify({"success": False, "message": "session_id 不能为空"}), 400
|
||||||
|
return _build_import_preview_response(session_id)
|
||||||
|
|
||||||
|
|
||||||
@v2_bp.route('/admin/permit-import/commit', methods=['POST'])
|
@v2_bp.route('/admin/permit-import/commit', methods=['POST'])
|
||||||
def admin_permit_import_commit():
|
def admin_permit_import_commit():
|
||||||
"""Commit an import session with selected sheets."""
|
"""Commit an import session with selected sheets."""
|
||||||
|
|
@ -306,6 +346,7 @@ def admin_permit_import_commit():
|
||||||
overrides = payload.get('overrides') or {}
|
overrides = payload.get('overrides') or {}
|
||||||
edited_by = payload.get('edited_by') or payload.get('editedBy')
|
edited_by = payload.get('edited_by') or payload.get('editedBy')
|
||||||
change_summary = payload.get('change_summary') or payload.get('changeSummary')
|
change_summary = payload.get('change_summary') or payload.get('changeSummary')
|
||||||
|
theme_bindings = payload.get('theme_bindings') or payload.get('themeBindings') or {}
|
||||||
|
|
||||||
if isinstance(sheet_names, str):
|
if isinstance(sheet_names, str):
|
||||||
sheet_names = [sheet_names]
|
sheet_names = [sheet_names]
|
||||||
|
|
@ -317,6 +358,7 @@ def admin_permit_import_commit():
|
||||||
overrides=overrides,
|
overrides=overrides,
|
||||||
edited_by=edited_by,
|
edited_by=edited_by,
|
||||||
change_summary=change_summary,
|
change_summary=change_summary,
|
||||||
|
theme_bindings=theme_bindings,
|
||||||
)
|
)
|
||||||
return jsonify({"success": True, "data": data})
|
return jsonify({"success": True, "data": data})
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
|
|
@ -366,27 +408,58 @@ def admin_permit_details():
|
||||||
theme_value = request.args.get("theme") or request.args.get("theme_id")
|
theme_value = request.args.get("theme") or request.args.get("theme_id")
|
||||||
permit_value = request.args.get("permit") or request.args.get("permit_id")
|
permit_value = request.args.get("permit") or request.args.get("permit_id")
|
||||||
|
|
||||||
if not region_value or not theme_value or not permit_value:
|
if not region_value or not permit_value:
|
||||||
return jsonify({"success": False, "message": "region, theme, and permit are required", "data": {}}), 400
|
return jsonify({"success": False, "message": "region and permit are required", "data": {}}), 400
|
||||||
|
|
||||||
region_token = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
region_token = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
||||||
theme_token = theme_value.strip() if isinstance(theme_value, str) else str(theme_value)
|
|
||||||
permit_token = permit_value.strip() if isinstance(permit_value, str) else str(permit_value)
|
permit_token = permit_value.strip() if isinstance(permit_value, str) else str(permit_value)
|
||||||
|
theme_token: Optional[str]
|
||||||
|
theme_display = None
|
||||||
|
if theme_value is None or (isinstance(theme_value, str) and not theme_value.strip()):
|
||||||
|
resolved = resolve_region_permit_theme(region_token, permit_token)
|
||||||
|
if not resolved or not resolved.get("id"):
|
||||||
|
return jsonify({"success": False, "message": "未找到许可所属主题", "data": {}}), 404
|
||||||
|
theme_token = resolved["id"]
|
||||||
|
theme_display = resolved
|
||||||
|
else:
|
||||||
|
theme_token = theme_value.strip() if isinstance(theme_value, str) else str(theme_value)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
permits = load_permits_and_risks(region_token, theme_token, permit_token)
|
# 始终加载全部主题,详情页需要展示主题列表并高亮当前主题
|
||||||
|
permits = load_permits_and_risks(region_token, None, permit_token)
|
||||||
|
|
||||||
if not permits:
|
if not permits:
|
||||||
return jsonify({"success": False, "message": "Permit not found", "data": {}}), 404
|
return jsonify({"success": False, "message": "Permit not found", "data": {}}), 404
|
||||||
|
|
||||||
return jsonify({
|
permit_payload = permits[0]
|
||||||
"success": True,
|
payload = {
|
||||||
"data": {
|
|
||||||
"region": region_token,
|
"region": region_token,
|
||||||
"theme": theme_token,
|
"theme": theme_token,
|
||||||
"permit": permits[0]
|
"permit": permit_payload,
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
selected_theme_meta = None
|
||||||
|
theme_list = permit_payload.get("themes") or []
|
||||||
|
if theme_token:
|
||||||
|
for candidate in theme_list:
|
||||||
|
if candidate.get("id") == theme_token:
|
||||||
|
selected_theme_meta = candidate
|
||||||
|
break
|
||||||
|
if not selected_theme_meta and theme_display:
|
||||||
|
selected_theme_meta = theme_display
|
||||||
|
if not selected_theme_meta:
|
||||||
|
selected_theme_meta = permit_payload.get("theme")
|
||||||
|
if not selected_theme_meta and theme_list:
|
||||||
|
selected_theme_meta = theme_list[0]
|
||||||
|
|
||||||
|
if selected_theme_meta:
|
||||||
|
permit_payload["theme"] = selected_theme_meta
|
||||||
|
payload["theme_display"] = selected_theme_meta
|
||||||
|
payload["selected_theme_id"] = selected_theme_meta.get("id") or ""
|
||||||
|
elif theme_display:
|
||||||
|
payload["theme_display"] = theme_display
|
||||||
|
|
||||||
|
return jsonify({"success": True, "data": payload})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f"admin_permit_details error: {exc}")
|
print(f"admin_permit_details error: {exc}")
|
||||||
return jsonify({"success": False, "message": str(exc)}), 500
|
return jsonify({"success": False, "message": str(exc)}), 500
|
||||||
|
|
@ -426,12 +499,18 @@ def admin_delete_permit():
|
||||||
if not change_summary:
|
if not change_summary:
|
||||||
change_summary = None
|
change_summary = None
|
||||||
|
|
||||||
if not region_value or not theme_value or not permit_value:
|
if not region_value or not permit_value:
|
||||||
return jsonify({"success": False, "message": "region_id, theme_id, permit_id 均为必填"}), 400
|
return jsonify({"success": False, "message": "region_id 和 permit_id 均为必填"}), 400
|
||||||
|
|
||||||
region_id = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
region_id = region_value.strip() if isinstance(region_value, str) else str(region_value)
|
||||||
theme_id = theme_value.strip() if isinstance(theme_value, str) else str(theme_value)
|
|
||||||
permit_id = permit_value.strip() if isinstance(permit_value, str) else str(permit_value)
|
permit_id = permit_value.strip() if isinstance(permit_value, str) else str(permit_value)
|
||||||
|
if theme_value:
|
||||||
|
theme_id = theme_value.strip() if isinstance(theme_value, str) else str(theme_value)
|
||||||
|
else:
|
||||||
|
resolved_theme = resolve_region_permit_theme(region_id, permit_id)
|
||||||
|
if not resolved_theme or not resolved_theme.get("id"):
|
||||||
|
return jsonify({"success": False, "message": "未找到许可所属主题,无法删除"}), 400
|
||||||
|
theme_id = resolved_theme["id"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = delete_region_permit(
|
result = delete_region_permit(
|
||||||
|
|
|
||||||
1091
static/db_admin.html
1091
static/db_admin.html
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue