diff --git a/elastic/templates/elastic/manage.html b/elastic/templates/elastic/manage.html index 1440ca2..76b1e48 100644 --- a/elastic/templates/elastic/manage.html +++ b/elastic/templates/elastic/manage.html @@ -445,6 +445,11 @@ async function generateReport() { try { const params = buildReportParams(); const resp = await fetch(`/elastic/report/?${params.toString()}`, { credentials: 'same-origin' }); + const ct = (resp.headers.get('content-type') || '').toLowerCase(); + if (!ct.includes('application/json')) { + const text = await resp.text(); + throw new Error(text ? String(text).slice(0, 200) : `HTTP ${resp.status}`); + } const data = await resp.json(); if (data.status !== 'success') { reportBox.className = 'search-result error'; diff --git a/elastic/views.py b/elastic/views.py index 121bb0d..b2eba6b 100644 --- a/elastic/views.py +++ b/elastic/views.py @@ -8,6 +8,7 @@ import base64 import json import csv import io +from datetime import datetime, timezone, timedelta import tempfile import concurrent.futures from django.conf import settings @@ -1580,104 +1581,107 @@ def _dt_label(dt, interval: str): @require_http_methods(["GET"]) def report_view(request): - session_user_id = request.session.get("user_id") - if session_user_id is None: - return JsonResponse({"status": "error", "message": "未登录"}, status=401) - is_admin = int(request.session.get("permission", 1)) == 0 - me = get_user_by_id(session_user_id) or {} - has_manage_key = bool(me.get("manage_key") or []) - if (not is_admin) and (not has_manage_key): - return JsonResponse({"status": "error", "message": "无权限"}, status=403) + try: + session_user_id = request.session.get("user_id") + if session_user_id is None: + return JsonResponse({"status": "error", "message": "未登录"}, status=401) + is_admin = int(request.session.get("permission", 1)) == 0 + me = get_user_by_id(session_user_id) or {} + has_manage_key = bool(me.get("manage_key") or []) + if (not is_admin) and (not has_manage_key): + return JsonResponse({"status": "error", "message": "无权限"}, status=403) - gte = (request.GET.get("from") or "").strip() - lte = (request.GET.get("to") or "").strip() - interval = (request.GET.get("interval") or "day").strip() - key = (request.GET.get("key") or "").strip() - typ = (request.GET.get("type") or "").strip() + gte = (request.GET.get("from") or "").strip() + lte = (request.GET.get("to") or "").strip() + interval = (request.GET.get("interval") or "day").strip() + key = (request.GET.get("key") or "").strip() + typ = (request.GET.get("type") or "").strip() - gte_dt = _parse_dt(gte) if gte else None - lte_dt = _parse_dt(lte) if lte else None + gte_dt = _parse_dt(gte) if gte else None + lte_dt = _parse_dt(lte) if lte else None - results = search_all() - results = _filter_results_for_user(request, results) - filtered = list(results or []) + results = search_all() + results = _filter_results_for_user(request, results) + filtered = list(results or []) - if key: - selected = str(key).strip() - try: - users = get_all_users() or [] - except Exception: - users = [] - writer_keys_by_id = {} - for u in users: + if key: + selected = str(key).strip() try: - u_id = str(u.get("user_id", "")).strip() + users = get_all_users() or [] except Exception: - u_id = "" - if not u_id: - continue - try: - u_keys = {str(k).strip() for k in (u.get("key") or []) if str(k).strip()} - except Exception: - u_keys = set() - writer_keys_by_id[u_id] = u_keys + users = [] + writer_keys_by_id = {} + for u in users: + try: + u_id = str(u.get("user_id", "")).strip() + except Exception: + u_id = "" + if not u_id: + continue + try: + u_keys = {str(k).strip() for k in (u.get("key") or []) if str(k).strip()} + except Exception: + u_keys = set() + writer_keys_by_id[u_id] = u_keys - tmp = [] + tmp = [] + for r in filtered: + writer_id = str(r.get("writer_id", "")).strip() + writer_keys = writer_keys_by_id.get(writer_id) + if writer_keys and selected in writer_keys: + tmp.append(r) + continue + if selected and selected in str(r.get("data", "")): + tmp.append(r) + filtered = tmp + + if typ: + tsel = str(typ).strip() + filtered = [r for r in filtered if _extract_type_from_data(r.get("data")) == tsel] + + ranged = [] for r in filtered: - writer_id = str(r.get("writer_id", "")).strip() - writer_keys = writer_keys_by_id.get(writer_id) - if writer_keys and selected in writer_keys: - tmp.append(r) + t = _parse_dt(r.get("time")) + if (gte_dt or lte_dt) and (t is None): continue - if selected and selected in str(r.get("data", "")): - tmp.append(r) - filtered = tmp + if gte_dt and t and t < gte_dt: + continue + if lte_dt and t and t > lte_dt: + continue + rr = dict(r) + rr["_time_dt"] = t + ranged.append(rr) - if typ: - tsel = str(typ).strip() - filtered = [r for r in filtered if _extract_type_from_data(r.get("data")) == tsel] + by_type = {} + by_bucket = {} + for r in ranged: + tval = _extract_type_from_data(r.get("data")) + if tval: + by_type[tval] = by_type.get(tval, 0) + 1 + bucket_dt = _floor_dt(r.get("_time_dt"), interval) + if bucket_dt: + label = _dt_label(bucket_dt, interval) + if label: + by_bucket[label] = by_bucket.get(label, 0) + 1 - ranged = [] - for r in filtered: - t = _parse_dt(r.get("time")) - if (gte_dt or lte_dt) and (t is None): - continue - if gte_dt and t and t < gte_dt: - continue - if lte_dt and t and t > lte_dt: - continue - rr = dict(r) - rr["_time_dt"] = t - ranged.append(rr) + by_type_arr = [{"type": k, "count": int(v)} for k, v in sorted(by_type.items(), key=lambda x: (-x[1], x[0]))] + by_time_arr = [{"bucket": k, "count": int(v)} for k, v in sorted(by_bucket.items(), key=lambda x: x[0])] - by_type = {} - by_bucket = {} - for r in ranged: - tval = _extract_type_from_data(r.get("data")) - if tval: - by_type[tval] = by_type.get(tval, 0) + 1 - bucket_dt = _floor_dt(r.get("_time_dt"), interval) - if bucket_dt: - label = _dt_label(bucket_dt, interval) - if label: - by_bucket[label] = by_bucket.get(label, 0) + 1 - - by_type_arr = [{"type": k, "count": int(v)} for k, v in sorted(by_type.items(), key=lambda x: (-x[1], x[0]))] - by_time_arr = [{"bucket": k, "count": int(v)} for k, v in sorted(by_bucket.items(), key=lambda x: x[0])] - - return JsonResponse( - { - "status": "success", - "data": { - "generated_at": datetime.now(timezone.utc).isoformat(), - "range": {"from": gte or "", "to": lte or ""}, - "filters": {"key": key or "", "type": typ or "", "interval": interval or "day"}, - "total": len(ranged), - "by_type": by_type_arr, - "by_time": by_time_arr, - }, - } - ) + return JsonResponse( + { + "status": "success", + "data": { + "generated_at": datetime.now(timezone.utc).isoformat(), + "range": {"from": gte or "", "to": lte or ""}, + "filters": {"key": key or "", "type": typ or "", "interval": interval or "day"}, + "total": len(ranged), + "by_type": by_type_arr, + "by_time": by_time_arr, + }, + } + ) + except Exception as e: + return JsonResponse({"status": "error", "message": str(e) or "生成失败"}, status=500) @require_http_methods(["GET"])