diff --git a/admin-frontend/src/api/client.js b/admin-frontend/src/api/client.js index 7dbf594..4d8ad90 100644 --- a/admin-frontend/src/api/client.js +++ b/admin-frontend/src/api/client.js @@ -4,6 +4,10 @@ import { ElMessage, ElMessageBox } from 'element-plus' let lastToastKey = '' let lastToastAt = 0 +const RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]) +const MAX_RETRY_COUNT = 1 +const RETRY_BASE_DELAY_MS = 300 + function toastErrorOnce(key, message, minIntervalMs = 1500) { const now = Date.now() if (key === lastToastKey && now - lastToastAt < minIntervalMs) return @@ -18,6 +22,41 @@ function getCookie(name) { return match ? decodeURIComponent(match[1]) : '' } +function isIdempotentMethod(method) { + return ['GET', 'HEAD', 'OPTIONS'].includes(String(method || 'GET').toUpperCase()) +} + +function shouldRetryRequest(error) { + const config = error?.config + if (!config || config.__no_retry) return false + if (!isIdempotentMethod(config.method)) return false + + const retried = Number(config.__retry_count || 0) + if (retried >= MAX_RETRY_COUNT) return false + + const code = String(error?.code || '') + if (code === 'ECONNABORTED' || code === 'ERR_NETWORK') return true + + const status = Number(error?.response?.status || 0) + return RETRYABLE_STATUS.has(status) +} + +function delay(ms) { + return new Promise((resolve) => { + window.setTimeout(resolve, Math.max(0, Number(ms || 0))) + }) +} + +async function retryRequestOnce(error, client) { + const config = error?.config || {} + const retried = Number(config.__retry_count || 0) + config.__retry_count = retried + 1 + + const backoffMs = RETRY_BASE_DELAY_MS * (retried + 1) + await delay(backoffMs) + return client.request(config) +} + export const api = axios.create({ baseURL: '/yuyx/api', timeout: 30_000, @@ -76,6 +115,10 @@ api.interceptors.response.use( } } + if (shouldRetryRequest(error)) { + return retryRequestOnce(error, api) + } + if (status === 401) { toastErrorOnce('401', message || '登录已过期,请重新登录', 3000) const pathname = window.location?.pathname || '' diff --git a/admin-frontend/src/layouts/AdminLayout.vue b/admin-frontend/src/layouts/AdminLayout.vue index d4ee171..8d1135b 100644 --- a/admin-frontend/src/layouts/AdminLayout.vue +++ b/admin-frontend/src/layouts/AdminLayout.vue @@ -34,7 +34,11 @@ async function refreshStats() { const loadingBadges = ref(false) const pendingFeedbackCount = ref(0) -let badgeTimer + +const BADGE_POLL_ACTIVE_MS = 60_000 +const BADGE_POLL_HIDDEN_MS = 180_000 + +let badgeTimer = null async function refreshNavBadges(partial = null) { if (partial && typeof partial === 'object') { @@ -55,6 +59,34 @@ async function refreshNavBadges(partial = null) { } } +function isPageHidden() { + if (typeof document === 'undefined') return false + return document.visibilityState === 'hidden' +} + +function currentBadgePollDelay() { + return isPageHidden() ? BADGE_POLL_HIDDEN_MS : BADGE_POLL_ACTIVE_MS +} + +function stopBadgePolling() { + if (!badgeTimer) return + window.clearTimeout(badgeTimer) + badgeTimer = null +} + +function scheduleBadgePolling() { + stopBadgePolling() + badgeTimer = window.setTimeout(async () => { + badgeTimer = null + await refreshNavBadges().catch(() => {}) + scheduleBadgePolling() + }, currentBadgePollDelay()) +} + +function onVisibilityChange() { + scheduleBadgePolling() +} + provide('refreshStats', refreshStats) provide('adminStats', stats) provide('refreshNavBadges', refreshNavBadges) @@ -75,12 +107,14 @@ onMounted(async () => { await refreshStats() await refreshNavBadges() - badgeTimer = window.setInterval(refreshNavBadges, 60_000) + scheduleBadgePolling() + window.addEventListener('visibilitychange', onVisibilityChange) }) onBeforeUnmount(() => { mediaQuery?.removeEventListener?.('change', syncIsMobile) - window.clearInterval(badgeTimer) + stopBadgePolling() + window.removeEventListener('visibilitychange', onVisibilityChange) }) const menuItems = [ diff --git a/app-frontend/src/api/http.js b/app-frontend/src/api/http.js index a7a0120..ffab18d 100644 --- a/app-frontend/src/api/http.js +++ b/app-frontend/src/api/http.js @@ -4,6 +4,10 @@ import { ElMessage } from 'element-plus' let lastToastKey = '' let lastToastAt = 0 +const RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]) +const MAX_RETRY_COUNT = 1 +const RETRY_BASE_DELAY_MS = 300 + function toastErrorOnce(key, message, minIntervalMs = 1500) { const now = Date.now() if (key === lastToastKey && now - lastToastAt < minIntervalMs) return @@ -18,6 +22,41 @@ function getCookie(name) { return match ? decodeURIComponent(match[1]) : '' } +function isIdempotentMethod(method) { + return ['GET', 'HEAD', 'OPTIONS'].includes(String(method || 'GET').toUpperCase()) +} + +function shouldRetryRequest(error) { + const config = error?.config + if (!config || config.__no_retry) return false + if (!isIdempotentMethod(config.method)) return false + + const retried = Number(config.__retry_count || 0) + if (retried >= MAX_RETRY_COUNT) return false + + const code = String(error?.code || '') + if (code === 'ECONNABORTED' || code === 'ERR_NETWORK') return true + + const status = Number(error?.response?.status || 0) + return RETRYABLE_STATUS.has(status) +} + +function delay(ms) { + return new Promise((resolve) => { + window.setTimeout(resolve, Math.max(0, Number(ms || 0))) + }) +} + +async function retryRequestOnce(error, client) { + const config = error?.config || {} + const retried = Number(config.__retry_count || 0) + config.__retry_count = retried + 1 + + const backoffMs = RETRY_BASE_DELAY_MS * (retried + 1) + await delay(backoffMs) + return client.request(config) +} + export const publicApi = axios.create({ baseURL: '/api', timeout: 30_000, @@ -39,6 +78,10 @@ publicApi.interceptors.request.use((config) => { publicApi.interceptors.response.use( (response) => response, (error) => { + if (shouldRetryRequest(error)) { + return retryRequestOnce(error, publicApi) + } + const status = error?.response?.status const payload = error?.response?.data const message = payload?.error || payload?.message || error?.message || '请求失败' diff --git a/app.py b/app.py index 4fcfee3..9683b35 100644 --- a/app.py +++ b/app.py @@ -17,8 +17,9 @@ import os import signal import sys import threading +import time -from flask import Flask, jsonify, redirect, request, send_from_directory, session, url_for +from flask import Flask, g, jsonify, redirect, request, send_from_directory, session, url_for from flask_login import LoginManager, current_user from flask_socketio import SocketIO @@ -35,6 +36,7 @@ from routes import register_blueprints from security import init_security_middleware from services.checkpoints import init_checkpoint_manager from services.maintenance import start_cleanup_scheduler, start_kdocs_monitor +from services.request_metrics import record_request_metric from services.models import User from services.runtime import init_runtime from services.scheduler import scheduled_task_worker @@ -98,6 +100,20 @@ init_logging(log_level=config.LOG_LEVEL, log_file=config.LOG_FILE) logger = get_logger("app") init_runtime(socketio=socketio, logger=logger) +_API_DIAGNOSTIC_LOG = str(os.environ.get("API_DIAGNOSTIC_LOG", "0")).strip().lower() in { + "1", + "true", + "yes", + "on", +} +_API_DIAGNOSTIC_SLOW_MS = max(0.0, float(os.environ.get("API_DIAGNOSTIC_SLOW_MS", "0") or 0.0)) + + +def _is_api_or_health_path(path: str) -> bool: + raw = str(path or "") + return raw.startswith("/api/") or raw.startswith("/yuyx/api/") or raw == "/health" + + # 初始化安全中间件(需在其他中间件/Blueprint 之前注册) init_security_middleware(app) @@ -131,6 +147,11 @@ def unauthorized(): return redirect(url_for("pages.login_page", next=request.url)) +@app.before_request +def track_request_start_time(): + g.request_start_perf = time.perf_counter() + + @app.before_request def enforce_csrf_protection(): if request.method in {"GET", "HEAD", "OPTIONS"}: @@ -148,20 +169,52 @@ def enforce_csrf_protection(): return jsonify({"error": "CSRF token missing or invalid"}), 403 +def _record_request_metric_after_response(response) -> None: + try: + started = float(getattr(g, "request_start_perf", 0.0) or 0.0) + if started <= 0: + return + + duration_ms = max(0.0, (time.perf_counter() - started) * 1000.0) + path = request.path or "/" + method = request.method or "GET" + status_code = int(getattr(response, "status_code", 0) or 0) + is_api = _is_api_or_health_path(path) + + record_request_metric( + path=path, + method=method, + status_code=status_code, + duration_ms=duration_ms, + is_api=is_api, + ) + + if _API_DIAGNOSTIC_LOG and is_api: + is_slow = _API_DIAGNOSTIC_SLOW_MS > 0 and duration_ms >= _API_DIAGNOSTIC_SLOW_MS + is_server_error = status_code >= 500 + if is_slow or is_server_error: + logger.warning( + f"[API-DIAG] {method} {path} -> {status_code} ({duration_ms:.1f}ms)" + ) + except Exception: + pass + + @app.after_request def ensure_csrf_cookie(response): - if request.path.startswith("/static/"): - return response - token = session.get("csrf_token") - if not token: - token = generate_csrf_token() - response.set_cookie( - "csrf_token", - token, - httponly=False, - secure=bool(config.SESSION_COOKIE_SECURE), - samesite=config.SESSION_COOKIE_SAMESITE, - ) + if not request.path.startswith("/static/"): + token = session.get("csrf_token") + if not token: + token = generate_csrf_token() + response.set_cookie( + "csrf_token", + token, + httponly=False, + secure=bool(config.SESSION_COOKIE_SECURE), + samesite=config.SESSION_COOKIE_SAMESITE, + ) + + _record_request_metric_after_response(response) return response diff --git a/routes/health.py b/routes/health.py index c1dc202..5dfe5e9 100644 --- a/routes/health.py +++ b/routes/health.py @@ -9,6 +9,7 @@ from flask import Blueprint, jsonify import database import db_pool +from services.request_metrics import get_request_metrics_snapshot from services.time_utils import get_beijing_now health_bp = Blueprint("health", __name__) @@ -57,6 +58,11 @@ def _build_runtime_metrics() -> dict: except Exception: pass + try: + metrics["requests"] = get_request_metrics_snapshot() + except Exception: + pass + return metrics diff --git a/services/request_metrics.py b/services/request_metrics.py new file mode 100644 index 0000000..6b71c06 --- /dev/null +++ b/services/request_metrics.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +请求级运行指标(轻量内存版) +- 记录请求总量、状态分布、耗时 +- 记录慢请求样本(环形队列) +- 输出健康检查可读快照 +""" + +from __future__ import annotations + +import os +import threading +import time +from collections import deque +from typing import Dict + +_SLOW_REQUEST_MS = max(0.0, float(os.environ.get("REQUEST_METRICS_SLOW_MS", "1200") or 1200)) +_PATH_STATS_LIMIT = max(20, int(os.environ.get("REQUEST_METRICS_PATH_LIMIT", "120") or 120)) +_RECENT_SLOW_LIMIT = max(10, int(os.environ.get("REQUEST_METRICS_RECENT_SLOW_LIMIT", "20") or 20)) + +_lock = threading.Lock() + +_state = { + "start_ts": time.time(), + "last_request_ts": 0.0, + "total_requests": 0, + "api_requests": 0, + "error_requests": 0, + "slow_requests": 0, + "duration_total_ms": 0.0, + "max_duration_ms": 0.0, + "status_counts": {}, + "path_stats": {}, + "recent_slow": deque(maxlen=_RECENT_SLOW_LIMIT), +} + + +def _status_bucket(status_code: int) -> str: + code = int(status_code or 0) + if code <= 0: + return "unknown" + head = code // 100 + if head in (1, 2, 3, 4, 5): + return f"{head}xx" + return str(code) + + +def _normalize_path(path: str) -> str: + text = str(path or "/") + if len(text) > 160: + return f"{text[:157]}..." + return text + + +def _prune_path_stats(path_stats: Dict[str, dict]) -> None: + if len(path_stats) < _PATH_STATS_LIMIT: + return + + # 删除最不活跃的路径,避免无限增长 + removable_key = None + removable_score = None + for key, item in path_stats.items(): + count = int(item.get("count", 0) or 0) + max_ms = float(item.get("max_ms", 0.0) or 0.0) + score = (count, max_ms) + if removable_score is None or score < removable_score: + removable_key = key + removable_score = score + + if removable_key: + path_stats.pop(removable_key, None) + + +def record_request_metric(*, path: str, method: str, status_code: int, duration_ms: float, is_api: bool = False) -> None: + duration = max(0.0, float(duration_ms or 0.0)) + code = int(status_code or 0) + method_name = str(method or "GET").upper() + normalized_path = _normalize_path(path) + route_key = f"{method_name} {normalized_path}" + now = time.time() + + with _lock: + _state["total_requests"] += 1 + if is_api: + _state["api_requests"] += 1 + if code >= 500: + _state["error_requests"] += 1 + + _state["last_request_ts"] = now + _state["duration_total_ms"] += duration + if duration > _state["max_duration_ms"]: + _state["max_duration_ms"] = duration + + bucket = _status_bucket(code) + status_counts = _state["status_counts"] + status_counts[bucket] = int(status_counts.get(bucket, 0) or 0) + 1 + + path_stats = _state["path_stats"] + if route_key not in path_stats: + _prune_path_stats(path_stats) + path_stats[route_key] = { + "count": 0, + "total_ms": 0.0, + "max_ms": 0.0, + "status_5xx": 0, + } + + item = path_stats[route_key] + item["count"] = int(item.get("count", 0) or 0) + 1 + item["total_ms"] = float(item.get("total_ms", 0.0) or 0.0) + duration + if duration > float(item.get("max_ms", 0.0) or 0.0): + item["max_ms"] = duration + if code >= 500: + item["status_5xx"] = int(item.get("status_5xx", 0) or 0) + 1 + + if _SLOW_REQUEST_MS > 0 and duration >= _SLOW_REQUEST_MS: + _state["slow_requests"] += 1 + _state["recent_slow"].append( + { + "path": normalized_path, + "method": method_name, + "status": code, + "duration_ms": round(duration, 2), + "time": int(now), + } + ) + + +def get_request_metrics_snapshot() -> dict: + with _lock: + total_requests = int(_state["total_requests"]) + duration_total_ms = float(_state["duration_total_ms"]) + avg_duration_ms = round((duration_total_ms / total_requests), 2) if total_requests > 0 else 0.0 + + path_rows = [] + for key, item in _state["path_stats"].items(): + count = int(item.get("count", 0) or 0) + total_ms = float(item.get("total_ms", 0.0) or 0.0) + avg_ms = round((total_ms / count), 2) if count > 0 else 0.0 + path_rows.append( + { + "path": key, + "count": count, + "avg_ms": avg_ms, + "max_ms": round(float(item.get("max_ms", 0.0) or 0.0), 2), + "status_5xx": int(item.get("status_5xx", 0) or 0), + } + ) + + top_paths = sorted( + path_rows, + key=lambda row: (float(row.get("max_ms", 0.0)), float(row.get("avg_ms", 0.0)), int(row.get("count", 0))), + reverse=True, + )[:8] + + return { + "since_ts": int(_state["start_ts"]), + "uptime_seconds": max(0, int(time.time() - float(_state["start_ts"]))), + "last_request_ts": int(_state["last_request_ts"] or 0), + "total_requests": total_requests, + "api_requests": int(_state["api_requests"]), + "error_requests": int(_state["error_requests"]), + "slow_requests": int(_state["slow_requests"]), + "avg_duration_ms": avg_duration_ms, + "max_duration_ms": round(float(_state["max_duration_ms"]), 2), + "status_counts": dict(_state["status_counts"]), + "top_paths": top_paths, + "recent_slow": list(_state["recent_slow"]), + "slow_threshold_ms": _SLOW_REQUEST_MS, + } diff --git a/static/admin/.vite/manifest.json b/static/admin/.vite/manifest.json index c3ebd75..fb9a11f 100644 --- a/static/admin/.vite/manifest.json +++ b/static/admin/.vite/manifest.json @@ -1,6 +1,6 @@ { - "_MetricGrid-Cbhb9OGV.js": { - "file": "assets/MetricGrid-Cbhb9OGV.js", + "_MetricGrid-D-x_tNsK.js": { + "file": "assets/MetricGrid-D-x_tNsK.js", "name": "MetricGrid", "imports": [ "index.html", @@ -14,29 +14,29 @@ "file": "assets/MetricGrid-yP_dkP6X.css", "src": "_MetricGrid-yP_dkP6X.css" }, - "_email-CqsrP_Ts.js": { - "file": "assets/email-CqsrP_Ts.js", + "_email-BYiWDIoy.js": { + "file": "assets/email-BYiWDIoy.js", "name": "email", "imports": [ "index.html" ] }, - "_system-In7Gh8x7.js": { - "file": "assets/system-In7Gh8x7.js", + "_system-Bvj77zeB.js": { + "file": "assets/system-Bvj77zeB.js", "name": "system", "imports": [ "index.html" ] }, - "_tasks-DZnsc1fC.js": { - "file": "assets/tasks-DZnsc1fC.js", + "_tasks-BZsqSMnk.js": { + "file": "assets/tasks-BZsqSMnk.js", "name": "tasks", "imports": [ "index.html" ] }, - "_users-CTuo5Ynz.js": { - "file": "assets/users-CTuo5Ynz.js", + "_users-Kctz2ziD.js": { + "file": "assets/users-Kctz2ziD.js", "name": "users", "imports": [ "index.html" @@ -74,7 +74,7 @@ ] }, "index.html": { - "file": "assets/index-D8t2quK2.js", + "file": "assets/index-iyjFO6XY.js", "name": "index", "src": "index.html", "isEntry": true, @@ -96,11 +96,11 @@ "src/pages/SettingsPage.vue" ], "css": [ - "assets/index-Tk47UJAg.css" + "assets/index-a3a11Ghn.css" ] }, "src/pages/AnnouncementsPage.vue": { - "file": "assets/AnnouncementsPage-CaSWhmIw.js", + "file": "assets/AnnouncementsPage-BZGpQqUL.js", "name": "AnnouncementsPage", "src": "src/pages/AnnouncementsPage.vue", "isDynamicEntry": true, @@ -116,14 +116,14 @@ ] }, "src/pages/EmailPage.vue": { - "file": "assets/EmailPage-DlOkUKzK.js", + "file": "assets/EmailPage-CfIczE0i.js", "name": "EmailPage", "src": "src/pages/EmailPage.vue", "isDynamicEntry": true, "imports": [ - "_email-CqsrP_Ts.js", + "_email-BYiWDIoy.js", "index.html", - "_MetricGrid-Cbhb9OGV.js", + "_MetricGrid-D-x_tNsK.js", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", "_vendor-vue-CWkOjFoA.js", @@ -134,13 +134,13 @@ ] }, "src/pages/FeedbacksPage.vue": { - "file": "assets/FeedbacksPage-B8rr6rHD.js", + "file": "assets/FeedbacksPage-yGzwD6JV.js", "name": "FeedbacksPage", "src": "src/pages/FeedbacksPage.vue", "isDynamicEntry": true, "imports": [ "index.html", - "_MetricGrid-Cbhb9OGV.js", + "_MetricGrid-D-x_tNsK.js", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", "_vendor-vue-CWkOjFoA.js", @@ -151,13 +151,13 @@ ] }, "src/pages/LogsPage.vue": { - "file": "assets/LogsPage-WfvkzS-6.js", + "file": "assets/LogsPage-WmQFhJZO.js", "name": "LogsPage", "src": "src/pages/LogsPage.vue", "isDynamicEntry": true, "imports": [ - "_users-CTuo5Ynz.js", - "_tasks-DZnsc1fC.js", + "_users-Kctz2ziD.js", + "_tasks-BZsqSMnk.js", "index.html", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", @@ -169,17 +169,17 @@ ] }, "src/pages/ReportPage.vue": { - "file": "assets/ReportPage-GPt5J1Db.js", + "file": "assets/ReportPage-BkIhdzJa.js", "name": "ReportPage", "src": "src/pages/ReportPage.vue", "isDynamicEntry": true, "imports": [ "_vendor-element-CJoVtPsD.js", "index.html", - "_email-CqsrP_Ts.js", - "_tasks-DZnsc1fC.js", - "_system-In7Gh8x7.js", - "_MetricGrid-Cbhb9OGV.js", + "_email-BYiWDIoy.js", + "_tasks-BZsqSMnk.js", + "_system-Bvj77zeB.js", + "_MetricGrid-D-x_tNsK.js", "_vendor-sLgkZK1v.js", "_vendor-vue-CWkOjFoA.js", "_vendor-axios-B9ygI19o.js" @@ -189,13 +189,13 @@ ] }, "src/pages/SecurityPage.vue": { - "file": "assets/SecurityPage-BWFFA3z9.js", + "file": "assets/SecurityPage-Ay9lQdJs.js", "name": "SecurityPage", "src": "src/pages/SecurityPage.vue", "isDynamicEntry": true, "imports": [ "index.html", - "_MetricGrid-Cbhb9OGV.js", + "_MetricGrid-D-x_tNsK.js", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", "_vendor-vue-CWkOjFoA.js", @@ -206,7 +206,7 @@ ] }, "src/pages/SettingsPage.vue": { - "file": "assets/SettingsPage-3cNfdgGx.js", + "file": "assets/SettingsPage-D1k6_4Nn.js", "name": "SettingsPage", "src": "src/pages/SettingsPage.vue", "isDynamicEntry": true, @@ -222,12 +222,12 @@ ] }, "src/pages/SystemPage.vue": { - "file": "assets/SystemPage-CJ2F6_EU.js", + "file": "assets/SystemPage-wAMFferr.js", "name": "SystemPage", "src": "src/pages/SystemPage.vue", "isDynamicEntry": true, "imports": [ - "_system-In7Gh8x7.js", + "_system-Bvj77zeB.js", "index.html", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", @@ -239,12 +239,12 @@ ] }, "src/pages/UsersPage.vue": { - "file": "assets/UsersPage-KZ5WSZrO.js", + "file": "assets/UsersPage-B5MDfX7T.js", "name": "UsersPage", "src": "src/pages/UsersPage.vue", "isDynamicEntry": true, "imports": [ - "_users-CTuo5Ynz.js", + "_users-Kctz2ziD.js", "index.html", "_vendor-element-CJoVtPsD.js", "_vendor-sLgkZK1v.js", diff --git a/static/admin/assets/AnnouncementsPage-CaSWhmIw.js b/static/admin/assets/AnnouncementsPage-BZGpQqUL.js similarity index 99% rename from static/admin/assets/AnnouncementsPage-CaSWhmIw.js rename to static/admin/assets/AnnouncementsPage-BZGpQqUL.js index b03cfd6..842374f 100644 --- a/static/admin/assets/AnnouncementsPage-CaSWhmIw.js +++ b/static/admin/assets/AnnouncementsPage-BZGpQqUL.js @@ -1 +1 @@ -import{B as j,f as r,E as C}from"./vendor-element-CJoVtPsD.js";import{a as w,_ as q}from"./index-D8t2quK2.js";import{r as v,v as G,aW as p,b7 as J,z as B,A as f,B as u,S as n,L as t,N as I,K as x,u as O,P as c,Q as $,M as X,as as D}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Y(){const{data:o}=await w.get("/announcements");return o}async function Z(o){const{data:s}=await w.post("/announcements",o);return s}async function ee(o){const s=new FormData;s.append("file",o);const{data:_}=await w.post("/announcements/upload_image",s);return _}async function te(o){const{data:s}=await w.post(`/announcements/${o}/activate`);return s}async function ne(o){const{data:s}=await w.post(`/announcements/${o}/deactivate`);return s}async function ae(o){const{data:s}=await w.delete(`/announcements/${o}`);return s}const le={class:"page-stack"},se={class:"image-upload-row"},oe={key:1,class:"image-url"},ie={key:0,class:"image-preview"},re=["src"],ue={class:"actions"},ce={class:"table-wrap"},de=["title"],me={key:1,class:"app-muted"},fe={class:"actions"},pe={__name:"AnnouncementsPage",setup(o){const s=v(""),_=v(""),m=v(""),g=v(null),h=v(!1),A=v(!1),T=v([]);async function k(){A.value=!0;try{T.value=await Y()}catch{T.value=[]}finally{A.value=!1}}function z(){s.value="",_.value="",m.value="",g.value&&(g.value.value="")}function P(){g.value?.click()}function U(){m.value="",g.value&&(g.value.value="")}async function F(l){const e=l.target?.files?.[0];if(e){if(e.type&&!e.type.startsWith("image/")){r.error("请选择图片文件"),l.target.value="";return}h.value=!0;try{const d=await ee(e);if(!d?.success||!d?.url){r.error(d?.error||"上传失败");return}m.value=d.url,r.success("上传成功")}catch{}finally{h.value=!1,l.target.value=""}}}async function M(l){const e=s.value.trim(),d=_.value.trim(),b=m.value.trim();if(!e||!d){r.error("标题和内容不能为空");return}try{const i=await Z({title:e,content:d,image_url:b,is_active:!!l});if(!i?.success){r.error(i?.error||"保存失败");return}r.success("保存成功"),z(),await k()}catch{}}async function S(l){const e=D("div",{class:"announcement-view"},[l.content?D("div",{class:"announcement-view-text"},l.content):null,l.image_url?D("img",{class:"announcement-view-image",src:l.image_url,alt:"公告图片"}):null]);await C.alert(e,l.title||"公告",{confirmButtonText:"关闭",dangerouslyUseHTMLString:!1})}async function L(l){try{await C.confirm("确定启用该公告吗?启用后将自动停用其他公告。","启用公告",{confirmButtonText:"启用",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await te(l.id);if(!e?.success){r.error(e?.error||"启用失败");return}r.success("已启用"),await k()}catch{}}async function R(l){try{await C.confirm("确定停用该公告吗?","停用公告",{confirmButtonText:"停用",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await ne(l.id);if(!e?.success){r.error(e?.error||"停用失败");return}r.success("已停用"),await k()}catch{}}async function W(l){try{await C.confirm("确定删除该公告吗?删除后无法恢复。","删除公告",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const e=await ae(l.id);if(!e?.success){r.error(e?.error||"删除失败");return}r.success("已删除"),await k()}catch{}}return G(k),(l,e)=>{const d=p("el-input"),b=p("el-form-item"),i=p("el-button"),H=p("el-form"),N=p("el-card"),y=p("el-table-column"),E=p("el-tag"),K=p("el-table"),Q=J("loading");return f(),B("div",le,[e[17]||(e[17]=u("div",{class:"app-page-title"},[u("h2",null,"公告管理")],-1)),n(N,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:t(()=>[e[9]||(e[9]=u("h3",{class:"section-title"},"创建公告",-1)),n(H,{"label-width":"90px"},{default:t(()=>[n(b,{label:"公告标题"},{default:t(()=>[n(d,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=a=>s.value=a),placeholder:"请输入公告标题",maxlength:"100","show-word-limit":""},null,8,["modelValue"])]),_:1}),n(b,{label:"公告内容"},{default:t(()=>[n(d,{modelValue:_.value,"onUpdate:modelValue":e[1]||(e[1]=a=>_.value=a),type:"textarea",rows:5,placeholder:"请输入公告内容(将以弹窗形式展示)",maxlength:"2000","show-word-limit":""},null,8,["modelValue"])]),_:1}),n(b,{label:"公告图片"},{default:t(()=>[u("div",se,[n(i,{icon:O(j),loading:h.value,onClick:P},{default:t(()=>[...e[4]||(e[4]=[c("上传图片",-1)])]),_:1},8,["icon","loading"]),m.value?(f(),x(i,{key:0,onClick:U},{default:t(()=>[...e[5]||(e[5]=[c("移除",-1)])]),_:1})):I("",!0),m.value?(f(),B("span",oe,$(m.value),1)):I("",!0),u("input",{ref_key:"imageInputRef",ref:g,class:"image-input",type:"file",accept:"image/*",onChange:F},null,544)])]),_:1})]),_:1}),m.value?(f(),B("div",ie,[u("img",{src:m.value,alt:"公告图片预览"},null,8,re)])):I("",!0),u("div",ue,[n(i,{type:"primary",onClick:e[2]||(e[2]=a=>M(!0))},{default:t(()=>[...e[6]||(e[6]=[c("发布并启用",-1)])]),_:1}),n(i,{onClick:e[3]||(e[3]=a=>M(!1))},{default:t(()=>[...e[7]||(e[7]=[c("保存但不启用",-1)])]),_:1}),n(i,{onClick:z},{default:t(()=>[...e[8]||(e[8]=[c("清空",-1)])]),_:1})]),e[10]||(e[10]=u("div",{class:"help"}," 说明:启用公告后,用户登录进入系统将弹窗提示;用户可选择“当次关闭”或“永久关闭本次公告”。 ",-1))]),_:1}),n(N,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:t(()=>[e[16]||(e[16]=u("h3",{class:"section-title"},"公告列表",-1)),u("div",ce,[X((f(),x(K,{data:T.value,style:{width:"100%"}},{default:t(()=>[n(y,{prop:"id",label:"ID",width:"80"}),n(y,{label:"标题","min-width":"240"},{default:t(({row:a})=>[u("span",{class:"ellipsis",title:a.title},$(a.title),9,de)]),_:1}),n(y,{label:"状态",width:"120"},{default:t(({row:a})=>[n(E,{type:a.is_active?"success":"info",effect:"light"},{default:t(()=>[c($(a.is_active?"启用":"停用"),1)]),_:2},1032,["type"])]),_:1}),n(y,{label:"图片",width:"100"},{default:t(({row:a})=>[a.image_url?(f(),x(E,{key:0,type:"success",effect:"light"},{default:t(()=>[...e[11]||(e[11]=[c("有图",-1)])]),_:1})):(f(),B("span",me,"-"))]),_:1}),n(y,{prop:"created_at",label:"创建时间",width:"180"}),n(y,{label:"操作",width:"260",fixed:"right"},{default:t(({row:a})=>[u("div",fe,[n(i,{size:"small",onClick:V=>S(a)},{default:t(()=>[...e[12]||(e[12]=[c("查看",-1)])]),_:1},8,["onClick"]),a.is_active?(f(),x(i,{key:0,size:"small",onClick:V=>R(a)},{default:t(()=>[...e[13]||(e[13]=[c("停用",-1)])]),_:1},8,["onClick"])):(f(),x(i,{key:1,type:"success",size:"small",onClick:V=>L(a)},{default:t(()=>[...e[14]||(e[14]=[c("启用",-1)])]),_:1},8,["onClick"])),n(i,{type:"danger",size:"small",onClick:V=>W(a)},{default:t(()=>[...e[15]||(e[15]=[c("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[Q,A.value]])])]),_:1})])}}},ke=q(pe,[["__scopeId","data-v-6f55521c"]]);export{ke as default}; +import{B as j,f as r,E as C}from"./vendor-element-CJoVtPsD.js";import{a as w,_ as q}from"./index-iyjFO6XY.js";import{r as v,v as G,aW as p,b7 as J,z as B,A as f,B as u,S as n,L as t,N as I,K as x,u as O,P as c,Q as $,M as X,as as D}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Y(){const{data:o}=await w.get("/announcements");return o}async function Z(o){const{data:s}=await w.post("/announcements",o);return s}async function ee(o){const s=new FormData;s.append("file",o);const{data:_}=await w.post("/announcements/upload_image",s);return _}async function te(o){const{data:s}=await w.post(`/announcements/${o}/activate`);return s}async function ne(o){const{data:s}=await w.post(`/announcements/${o}/deactivate`);return s}async function ae(o){const{data:s}=await w.delete(`/announcements/${o}`);return s}const le={class:"page-stack"},se={class:"image-upload-row"},oe={key:1,class:"image-url"},ie={key:0,class:"image-preview"},re=["src"],ue={class:"actions"},ce={class:"table-wrap"},de=["title"],me={key:1,class:"app-muted"},fe={class:"actions"},pe={__name:"AnnouncementsPage",setup(o){const s=v(""),_=v(""),m=v(""),g=v(null),h=v(!1),A=v(!1),T=v([]);async function k(){A.value=!0;try{T.value=await Y()}catch{T.value=[]}finally{A.value=!1}}function z(){s.value="",_.value="",m.value="",g.value&&(g.value.value="")}function P(){g.value?.click()}function U(){m.value="",g.value&&(g.value.value="")}async function F(l){const e=l.target?.files?.[0];if(e){if(e.type&&!e.type.startsWith("image/")){r.error("请选择图片文件"),l.target.value="";return}h.value=!0;try{const d=await ee(e);if(!d?.success||!d?.url){r.error(d?.error||"上传失败");return}m.value=d.url,r.success("上传成功")}catch{}finally{h.value=!1,l.target.value=""}}}async function M(l){const e=s.value.trim(),d=_.value.trim(),b=m.value.trim();if(!e||!d){r.error("标题和内容不能为空");return}try{const i=await Z({title:e,content:d,image_url:b,is_active:!!l});if(!i?.success){r.error(i?.error||"保存失败");return}r.success("保存成功"),z(),await k()}catch{}}async function S(l){const e=D("div",{class:"announcement-view"},[l.content?D("div",{class:"announcement-view-text"},l.content):null,l.image_url?D("img",{class:"announcement-view-image",src:l.image_url,alt:"公告图片"}):null]);await C.alert(e,l.title||"公告",{confirmButtonText:"关闭",dangerouslyUseHTMLString:!1})}async function L(l){try{await C.confirm("确定启用该公告吗?启用后将自动停用其他公告。","启用公告",{confirmButtonText:"启用",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await te(l.id);if(!e?.success){r.error(e?.error||"启用失败");return}r.success("已启用"),await k()}catch{}}async function R(l){try{await C.confirm("确定停用该公告吗?","停用公告",{confirmButtonText:"停用",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await ne(l.id);if(!e?.success){r.error(e?.error||"停用失败");return}r.success("已停用"),await k()}catch{}}async function W(l){try{await C.confirm("确定删除该公告吗?删除后无法恢复。","删除公告",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const e=await ae(l.id);if(!e?.success){r.error(e?.error||"删除失败");return}r.success("已删除"),await k()}catch{}}return G(k),(l,e)=>{const d=p("el-input"),b=p("el-form-item"),i=p("el-button"),H=p("el-form"),N=p("el-card"),y=p("el-table-column"),E=p("el-tag"),K=p("el-table"),Q=J("loading");return f(),B("div",le,[e[17]||(e[17]=u("div",{class:"app-page-title"},[u("h2",null,"公告管理")],-1)),n(N,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:t(()=>[e[9]||(e[9]=u("h3",{class:"section-title"},"创建公告",-1)),n(H,{"label-width":"90px"},{default:t(()=>[n(b,{label:"公告标题"},{default:t(()=>[n(d,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=a=>s.value=a),placeholder:"请输入公告标题",maxlength:"100","show-word-limit":""},null,8,["modelValue"])]),_:1}),n(b,{label:"公告内容"},{default:t(()=>[n(d,{modelValue:_.value,"onUpdate:modelValue":e[1]||(e[1]=a=>_.value=a),type:"textarea",rows:5,placeholder:"请输入公告内容(将以弹窗形式展示)",maxlength:"2000","show-word-limit":""},null,8,["modelValue"])]),_:1}),n(b,{label:"公告图片"},{default:t(()=>[u("div",se,[n(i,{icon:O(j),loading:h.value,onClick:P},{default:t(()=>[...e[4]||(e[4]=[c("上传图片",-1)])]),_:1},8,["icon","loading"]),m.value?(f(),x(i,{key:0,onClick:U},{default:t(()=>[...e[5]||(e[5]=[c("移除",-1)])]),_:1})):I("",!0),m.value?(f(),B("span",oe,$(m.value),1)):I("",!0),u("input",{ref_key:"imageInputRef",ref:g,class:"image-input",type:"file",accept:"image/*",onChange:F},null,544)])]),_:1})]),_:1}),m.value?(f(),B("div",ie,[u("img",{src:m.value,alt:"公告图片预览"},null,8,re)])):I("",!0),u("div",ue,[n(i,{type:"primary",onClick:e[2]||(e[2]=a=>M(!0))},{default:t(()=>[...e[6]||(e[6]=[c("发布并启用",-1)])]),_:1}),n(i,{onClick:e[3]||(e[3]=a=>M(!1))},{default:t(()=>[...e[7]||(e[7]=[c("保存但不启用",-1)])]),_:1}),n(i,{onClick:z},{default:t(()=>[...e[8]||(e[8]=[c("清空",-1)])]),_:1})]),e[10]||(e[10]=u("div",{class:"help"}," 说明:启用公告后,用户登录进入系统将弹窗提示;用户可选择“当次关闭”或“永久关闭本次公告”。 ",-1))]),_:1}),n(N,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:t(()=>[e[16]||(e[16]=u("h3",{class:"section-title"},"公告列表",-1)),u("div",ce,[X((f(),x(K,{data:T.value,style:{width:"100%"}},{default:t(()=>[n(y,{prop:"id",label:"ID",width:"80"}),n(y,{label:"标题","min-width":"240"},{default:t(({row:a})=>[u("span",{class:"ellipsis",title:a.title},$(a.title),9,de)]),_:1}),n(y,{label:"状态",width:"120"},{default:t(({row:a})=>[n(E,{type:a.is_active?"success":"info",effect:"light"},{default:t(()=>[c($(a.is_active?"启用":"停用"),1)]),_:2},1032,["type"])]),_:1}),n(y,{label:"图片",width:"100"},{default:t(({row:a})=>[a.image_url?(f(),x(E,{key:0,type:"success",effect:"light"},{default:t(()=>[...e[11]||(e[11]=[c("有图",-1)])]),_:1})):(f(),B("span",me,"-"))]),_:1}),n(y,{prop:"created_at",label:"创建时间",width:"180"}),n(y,{label:"操作",width:"260",fixed:"right"},{default:t(({row:a})=>[u("div",fe,[n(i,{size:"small",onClick:V=>S(a)},{default:t(()=>[...e[12]||(e[12]=[c("查看",-1)])]),_:1},8,["onClick"]),a.is_active?(f(),x(i,{key:0,size:"small",onClick:V=>R(a)},{default:t(()=>[...e[13]||(e[13]=[c("停用",-1)])]),_:1},8,["onClick"])):(f(),x(i,{key:1,type:"success",size:"small",onClick:V=>L(a)},{default:t(()=>[...e[14]||(e[14]=[c("启用",-1)])]),_:1},8,["onClick"])),n(i,{type:"danger",size:"small",onClick:V=>W(a)},{default:t(()=>[...e[15]||(e[15]=[c("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[Q,A.value]])])]),_:1})])}}},ke=q(pe,[["__scopeId","data-v-6f55521c"]]);export{ke as default}; diff --git a/static/admin/assets/EmailPage-DlOkUKzK.js b/static/admin/assets/EmailPage-CfIczE0i.js similarity index 99% rename from static/admin/assets/EmailPage-DlOkUKzK.js rename to static/admin/assets/EmailPage-CfIczE0i.js index 522a254..6dca5df 100644 --- a/static/admin/assets/EmailPage-DlOkUKzK.js +++ b/static/admin/assets/EmailPage-CfIczE0i.js @@ -1 +1 @@ -import{a as Ne,c as De,b as He,f as ze,u as Qe}from"./email-CqsrP_Ts.js";import{a as U,_ as Fe}from"./index-D8t2quK2.js";import{M as me}from"./MetricGrid-Cbhb9OGV.js";import{E as B,f as d}from"./vendor-element-CJoVtPsD.js";import{r as m,a2 as pe,a1 as Ie,c as j,v as Ke,aW as c,b7 as je,z as x,A as f,B as u,M as G,S as t,K as M,L as n,P as p,Q as _,N as P,R as te,ak as ce}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ge(){const{data:b}=await U.get("/smtp/configs");return b}async function Oe(b){const{data:v}=await U.post("/smtp/configs",b);return v}async function Re(b,v){const{data:g}=await U.put(`/smtp/configs/${b}`,v);return g}async function We(b){const{data:v}=await U.delete(`/smtp/configs/${b}`);return v}async function Je(b,v){const{data:g}=await U.post(`/smtp/configs/${b}/test`,{email:v});return g}async function Xe(b){const{data:v}=await U.post(`/smtp/configs/${b}/primary`);return v}async function Ye(){const{data:b}=await U.post("/smtp/configs/primary/clear");return b}const Ze={class:"page-stack"},el={class:"help app-muted"},ll={class:"section-head"},tl={class:"table-wrap"},al={class:"sub-stats"},sl={class:"help app-muted"},nl={class:"section-head"},ol={class:"toolbar"},il={class:"table-wrap"},ul=["title"],rl=["title"],dl=["title"],ml={class:"pagination"},pl={class:"page-hint app-muted"},cl={style:{width:"100%"}},fl={key:0,class:"help"},_l={key:0},bl={key:0},vl={key:0},yl={class:"dialog-actions"},fe=15,gl={__name:"EmailPage",setup(b){const v=m(!1),g=m(!1),o=pe({enabled:!1,failover_enabled:!0,register_verify_enabled:!1,login_alert_enabled:!0,task_notify_enabled:!1,base_url:"",updated_at:null});let L=null;async function ae(){v.value=!0;try{const s=await He();o.enabled=!!s.enabled,o.failover_enabled=!!s.failover_enabled,o.register_verify_enabled=!!s.register_verify_enabled,o.login_alert_enabled=s.login_alert_enabled===void 0?!0:!!s.login_alert_enabled,o.task_notify_enabled=!!s.task_notify_enabled,o.base_url=s.base_url||"",o.updated_at=s.updated_at||null}catch{}finally{v.value=!1}}async function _e(){if(!v.value){g.value=!0;try{const s=await Qe({enabled:o.enabled,failover_enabled:o.failover_enabled,register_verify_enabled:o.register_verify_enabled,login_alert_enabled:o.login_alert_enabled,task_notify_enabled:o.task_notify_enabled,base_url:(o.base_url||"").trim()});if(!s?.success){d.error(s?.error||"更新失败");return}d.success("邮件设置已更新"),await ae()}catch{}finally{g.value=!1}}}function E(){L&&window.clearTimeout(L),L=window.setTimeout(_e,300)}Ie(()=>{L&&window.clearTimeout(L),L=null});const O=m(!1),R=m([]),S=m(!1),k=m(!1),W=m(!1),D=m(!1),a=pe({id:null,name:"默认配置",enabled:!0,host:"",port:465,username:"",password:"",use_ssl:!0,use_tls:!1,sender_name:"自动化学习",sender_email:"",daily_limit:0,priority:0}),H=[{key:"custom",label:"自定义(手动填写)",defaults:null,note:"适用于其他邮箱/自建SMTP",links:[]},{key:"gmail",label:"Gmail",defaults:{host:"smtp.gmail.com",port:465,use_ssl:!0,use_tls:!1},note:"通常需要开启两步验证并创建应用专用密码(App Password)",links:[{label:"SMTP 设置说明",url:"https://support.google.com/mail/answer/7126229?hl=zh-Hans"},{label:"App Password",url:"https://myaccount.google.com/apppasswords"}]},{key:"qq",label:"QQ 邮箱",defaults:{host:"smtp.qq.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并获取授权码(不是QQ登录密码)",links:[{label:"QQ邮箱 SMTP 帮助",url:"https://service.mail.qq.com/cgi-bin/help?subtype=1&id=28&no=1001256"}]},{key:"163",label:"163 邮箱",defaults:{host:"smtp.163.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并使用授权码/客户端授权密码",links:[{label:"网易邮箱 SMTP 帮助",url:"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471a22b76"}]},{key:"126",label:"126 邮箱",defaults:{host:"smtp.126.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并使用授权码/客户端授权密码",links:[{label:"网易邮箱帮助",url:"https://help.mail.163.com/"}]},{key:"outlook",label:"Outlook/Hotmail",defaults:{host:"smtp-mail.outlook.com",port:587,use_ssl:!1,use_tls:!0},note:"建议使用 TLS 587(部分账号需开启 SMTP AUTH)",links:[{label:"微软 SMTP 设置",url:"https://support.microsoft.com/office/pop-imap-and-smtp-settings-for-outlook-com-d088b0b7-0d38-4f9a-bc5d-509f9e4c6d3d"}]},{key:"office365",label:"Microsoft 365/Exchange",defaults:{host:"smtp.office365.com",port:587,use_ssl:!1,use_tls:!0},note:"企业邮箱常用配置(需启用 SMTP AUTH)",links:[{label:"微软官方说明",url:"https://learn.microsoft.com/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission"}]},{key:"icloud",label:"iCloud",defaults:{host:"smtp.mail.me.com",port:587,use_ssl:!1,use_tls:!0},note:"需要在 Apple ID 中生成“App 专用密码”",links:[{label:"Apple 邮件服务器设置",url:"https://support.apple.com/zh-cn/HT202304"}]},{key:"tencent_exmail",label:"腾讯企业邮箱",defaults:{host:"smtp.exmail.qq.com",port:465,use_ssl:!0,use_tls:!1},note:"企业邮箱常用配置",links:[{label:"腾讯企业邮箱帮助",url:"https://service.exmail.qq.com/cgi-bin/help?subtype=1&id=23&no=1001068"}]},{key:"aliyun_exmail",label:"阿里企业邮箱",defaults:{host:"smtp.mxhichina.com",port:465,use_ssl:!0,use_tls:!1},note:"企业邮箱常用配置",links:[{label:"阿里云文档",url:"https://help.aliyun.com/document_detail/50652.html"}]}],$=m("custom"),V=j(()=>H.find(s=>s.key===$.value)||H[0]),be=j(()=>k.value&&W.value?"留空保持不变":"SMTP密码或授权码");function ve(s){const e=String(s?.host||"").trim().toLowerCase();return e&&{"smtp.gmail.com":"gmail","smtp.qq.com":"qq","smtp.163.com":"163","smtp.126.com":"126","smtp-mail.outlook.com":"outlook","smtp.office365.com":"office365","smtp.mail.me.com":"icloud","smtp.exmail.qq.com":"tencent_exmail","smtp.mxhichina.com":"aliyun_exmail"}[e]||"custom"}function ye(s){const e=H.find(i=>i.key===s);!e||!e.defaults||(a.host=e.defaults.host,a.port=e.defaults.port,a.use_ssl=e.defaults.use_ssl,a.use_tls=e.defaults.use_tls)}function se(){a.id=null,a.name="默认配置",a.enabled=!0,a.host="",a.port=465,a.username="",a.password="",a.use_ssl=!0,a.use_tls=!1,a.sender_name="自动化学习",a.sender_email="",a.daily_limit=0,a.priority=0,W.value=!1,D.value=!1,$.value="custom"}async function q(){O.value=!0;try{R.value=await Ge()}catch{R.value=[]}finally{O.value=!1}}function ge(){k.value=!1,se(),$.value="custom",S.value=!0}function ke(s){k.value=!0,se(),a.id=s.id,a.name=s.name||"默认配置",a.enabled=!!s.enabled,a.host=s.host||"",a.port=s.port||465,a.username=s.username||"",a.password="",a.use_ssl=!!s.use_ssl,a.use_tls=!!s.use_tls,a.sender_name=s.sender_name||"自动化学习",a.sender_email=s.sender_email||"",a.daily_limit=s.daily_limit??0,a.priority=s.priority??0,W.value=!!s.has_password,D.value=!!s.is_primary,$.value=ve(s),S.value=!0}function ne(s){return s.is_primary?{label:"主",type:"warning"}:s.enabled?{label:"备用",type:"success"}:{label:"禁用",type:"info"}}function he(s){return s.daily_limit&&s.daily_limit>0?`${s.daily_sent}/${s.daily_limit}`:`${s.daily_sent}/∞`}async function Ve(){if(!a.host.trim()){d.error("SMTP服务器地址不能为空");return}if(!a.username.trim()){d.error("SMTP用户名不能为空");return}const s={name:a.name.trim()||"默认配置",enabled:!!a.enabled,priority:Number(a.priority)||0,host:a.host.trim(),port:Number(a.port)||465,username:a.username.trim(),use_ssl:!!a.use_ssl,use_tls:!!a.use_tls,sender_name:(a.sender_name||"").trim(),sender_email:(a.sender_email||"").trim(),daily_limit:Number(a.daily_limit)||0};try{if(k.value){const e={...s};a.password&&(e.password=a.password);const i=await Re(a.id,e);if(!i?.success){d.error(i?.error||"更新失败");return}d.success("保存成功")}else{const e={...s};a.password&&(e.password=a.password);const i=await Oe(e);if(!i?.success){d.error(i?.error||"创建失败");return}d.success("创建成功")}S.value=!1,await q()}catch{}}async function we(){if(!k.value||!a.id){d.error("请先保存配置后再测试");return}let s;try{const e=await B.prompt("请输入测试收件邮箱","测试连接",{inputPlaceholder:"name@example.com",confirmButtonText:"发送测试邮件",cancelButtonText:"取消",inputValidator:i=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(i||"").trim()),inputErrorMessage:"邮箱格式不正确"});s=String(e.value||"").trim()}catch{return}try{const e=await Je(a.id,s);e?.success?(d.success("测试成功,邮件已发送"),await q()):await B.alert(e?.error||"测试失败","测试失败",{confirmButtonText:"知道了"})}catch{}}async function Se(){if(!(!k.value||!a.id)){try{await B.confirm("确定将该配置设为主配置吗?","设为主配置",{confirmButtonText:"设为主配置",cancelButtonText:"取消",type:"warning"})}catch{return}try{const s=await Xe(a.id);if(!s?.success){d.error(s?.error||"设置失败");return}d.success("已设为主配置"),S.value=!1,await q()}catch{}}}async function Te(){if(k.value){try{await B.confirm("确定取消主配置吗?取消后将按优先级选择可用SMTP。","取消主配置",{confirmButtonText:"取消主配置",cancelButtonText:"保留",type:"warning"})}catch{return}try{const s=await Ye();if(!s?.success){d.error(s?.error||"操作失败");return}d.success("已取消主配置"),S.value=!1,await q()}catch{}}}async function xe(){if(!(!k.value||!a.id)){try{await B.confirm("确定删除该SMTP配置吗?此操作不可恢复。","删除配置",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const s=await We(a.id);if(!s?.success){d.error(s?.error||"删除失败");return}d.success("已删除"),S.value=!1,await q()}catch{}}}const A=m(!1),h=m({}),J=m(!1),z=m(""),Q=m(""),F=m(1),X=m([]),Y=m(0),Z=m(1);function Pe(s){return{register:"注册验证",reset:"密码重置",bind:"邮箱绑定",task_complete:"任务完成",security_alert:"安全告警"}[s]||s}function oe(s){return s?.username&&s?.user_id?`${s.username} (#${s.user_id})`:s?.user_id?`用户#${s.user_id}`:"系统"}const Ce=j(()=>[{key:"total_sent",label:"总发送",value:h.value?.total_sent||0,tone:"blue"},{key:"total_success",label:"成功",value:h.value?.total_success||0,tone:"green"},{key:"total_failed",label:"失败",value:h.value?.total_failed||0,tone:"red"},{key:"success_rate",label:"成功率",value:`${h.value?.success_rate||0}%`,tone:"purple"}]),Be=j(()=>[{key:"register_sent",label:"注册验证",value:h.value?.register_sent||0,tone:"cyan"},{key:"reset_sent",label:"密码重置",value:h.value?.reset_sent||0,tone:"orange"},{key:"bind_sent",label:"邮箱绑定",value:h.value?.bind_sent||0,tone:"purple"},{key:"task_complete_sent",label:"任务完成",value:h.value?.task_complete_sent||0,tone:"green"}]);async function Me(){A.value=!0;try{h.value=await ze()}catch{h.value={}}finally{A.value=!1}}async function N(s=1){J.value=!0;try{const e={page:s,page_size:fe};z.value&&(e.type=z.value),Q.value&&(e.status=Q.value);const i=await Ne(e);X.value=i?.logs||[],Y.value=i?.total||0,F.value=i?.page||s,Z.value=i?.total_pages||1}catch{X.value=[],Y.value=0,Z.value=1}finally{J.value=!1}}async function Ue(){let s;try{const e=await B.prompt("请输入保留天数(将删除该天数之前的日志)","清理日志",{inputValue:"30",confirmButtonText:"清理",cancelButtonText:"取消",inputValidator:i=>{const r=parseInt(String(i),10);return Number.isFinite(r)&&r>=7},inputErrorMessage:"天数必须大于等于7"});s=parseInt(String(e.value),10)}catch{return}try{await B.confirm(`确定删除 ${s} 天之前的邮件日志吗?`,"二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await De(s);if(!e?.success){d.error(e?.error||"清理失败");return}d.success(`已清理 ${e.deleted} 条日志`),await N(1)}catch{}}async function Le(){await Promise.all([ae(),q(),Me(),N(1)])}return Ke(Le),(s,e)=>{const i=c("el-switch"),r=c("el-form-item"),Ee=c("el-divider"),C=c("el-input"),ie=c("el-form"),I=c("el-card"),T=c("el-button"),ue=c("el-tag"),y=c("el-table-column"),re=c("el-table"),w=c("el-option"),ee=c("el-select"),$e=c("el-pagination"),qe=c("el-link"),le=c("el-input-number"),Ae=c("el-dialog"),K=je("loading");return f(),x("div",Ze,[e[43]||(e[43]=u("div",{class:"app-page-title"},[u("h2",null,"邮件配置")],-1)),G((f(),M(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[e[29]||(e[29]=u("h3",{class:"section-title"},"全局设置",-1)),t(ie,{"label-width":"140px"},{default:n(()=>[t(r,{label:"启用邮件功能"},{default:n(()=>[t(i,{modelValue:o.enabled,"onUpdate:modelValue":e[0]||(e[0]=l=>o.enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"启用故障转移"},{default:n(()=>[t(i,{modelValue:o.failover_enabled,"onUpdate:modelValue":e[1]||(e[1]=l=>o.failover_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"启用注册邮箱验证"},{default:n(()=>[t(i,{modelValue:o.register_verify_enabled,"onUpdate:modelValue":e[2]||(e[2]=l=>o.register_verify_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(Ee,{"content-position":"left"},{default:n(()=>[...e[26]||(e[26]=[p("通知设置",-1)])]),_:1}),t(r,{label:"启用任务完成通知"},{default:n(()=>[t(i,{modelValue:o.task_notify_enabled,"onUpdate:modelValue":e[3]||(e[3]=l=>o.task_notify_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"新设备登录提醒"},{default:n(()=>[t(i,{modelValue:o.login_alert_enabled,"onUpdate:modelValue":e[4]||(e[4]=l=>o.login_alert_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"]),e[27]||(e[27]=u("div",{class:"help"},"当检测到新设备或新IP登录时,发送邮件提醒用户",-1))]),_:1}),t(r,{label:"网站基础URL"},{default:n(()=>[t(C,{modelValue:o.base_url,"onUpdate:modelValue":e[5]||(e[5]=l=>o.base_url=l),placeholder:"例如: https://example.com",disabled:g.value,onBlur:E},null,8,["modelValue","disabled"]),e[28]||(e[28]=u("div",{class:"help"},"用于生成邮件中的验证链接,留空则使用默认配置。",-1))]),_:1})]),_:1}),u("div",el,"最近更新时间:"+_(o.updated_at||"-"),1)]),_:1})),[[K,v.value]]),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[u("div",ll,[e[31]||(e[31]=u("h3",{class:"section-title"},"SMTP配置列表",-1)),t(T,{type:"primary",onClick:ge},{default:n(()=>[...e[30]||(e[30]=[p("+ 添加配置",-1)])]),_:1})]),u("div",tl,[G((f(),M(re,{data:R.value,style:{width:"100%"}},{default:n(()=>[t(y,{label:"状态",width:"90"},{default:n(({row:l})=>[t(ue,{type:ne(l).type,effect:"light"},{default:n(()=>[p(_(ne(l).label),1)]),_:2},1032,["type"])]),_:1}),t(y,{prop:"name",label:"名称","min-width":"160"}),t(y,{label:"服务器","min-width":"200"},{default:n(({row:l})=>[p(_(l.host)+":"+_(l.port),1)]),_:1}),t(y,{label:"今日/限额",width:"110"},{default:n(({row:l})=>[p(_(he(l)),1)]),_:1}),t(y,{label:"成功率",width:"100"},{default:n(({row:l})=>[p(_(l.success_rate)+"%",1)]),_:1}),t(y,{label:"操作",width:"120",fixed:"right"},{default:n(({row:l})=>[t(T,{size:"small",onClick:de=>ke(l)},{default:n(()=>[...e[32]||(e[32]=[p("编辑",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[K,O.value]])])]),_:1}),G((f(),M(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[e[33]||(e[33]=u("h3",{class:"section-title"},"邮件发送统计",-1)),t(me,{items:Ce.value,loading:A.value,"min-width":160},null,8,["items","loading"]),u("div",al,[t(me,{items:Be.value,loading:A.value,"min-width":150},null,8,["items","loading"])]),u("div",sl,"最后更新:"+_(h.value.last_updated||"-"),1)]),_:1})),[[K,A.value]]),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[u("div",nl,[e[35]||(e[35]=u("h3",{class:"section-title"},"邮件发送日志",-1)),u("div",ol,[t(ee,{modelValue:z.value,"onUpdate:modelValue":e[6]||(e[6]=l=>z.value=l),style:{width:"140px"},onChange:e[7]||(e[7]=l=>N(1))},{default:n(()=>[t(w,{label:"全部类型",value:""}),t(w,{label:"注册验证",value:"register"}),t(w,{label:"密码重置",value:"reset"}),t(w,{label:"邮箱绑定",value:"bind"}),t(w,{label:"任务完成",value:"task_complete"}),t(w,{label:"安全告警",value:"security_alert"})]),_:1},8,["modelValue"]),t(ee,{modelValue:Q.value,"onUpdate:modelValue":e[8]||(e[8]=l=>Q.value=l),style:{width:"120px"},onChange:e[9]||(e[9]=l=>N(1))},{default:n(()=>[t(w,{label:"全部状态",value:""}),t(w,{label:"成功",value:"success"}),t(w,{label:"失败",value:"failed"})]),_:1},8,["modelValue"]),t(T,{type:"danger",plain:"",onClick:Ue},{default:n(()=>[...e[34]||(e[34]=[p("清理日志",-1)])]),_:1})])]),u("div",il,[G((f(),M(re,{data:X.value,style:{width:"100%"}},{default:n(()=>[t(y,{prop:"created_at",label:"时间",width:"180"}),t(y,{prop:"email_to",label:"收件人","min-width":"180"}),t(y,{label:"来源用户","min-width":"160"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:oe(l)},_(oe(l)),9,ul)]),_:1}),t(y,{label:"类型",width:"120"},{default:n(({row:l})=>[p(_(Pe(l.email_type)),1)]),_:1}),t(y,{label:"主题","min-width":"220"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:l.subject},_(l.subject),9,rl)]),_:1}),t(y,{label:"状态",width:"90"},{default:n(({row:l})=>[t(ue,{type:l.status==="success"?"success":"danger",effect:"light"},{default:n(()=>[p(_(l.status==="success"?"成功":"失败"),1)]),_:2},1032,["type"])]),_:1}),t(y,{label:"错误","min-width":"200"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:l.error_message||""},_(l.error_message||"-"),9,dl)]),_:1})]),_:1},8,["data"])),[[K,J.value]])]),u("div",ml,[t($e,{"current-page":F.value,"onUpdate:currentPage":e[10]||(e[10]=l=>F.value=l),"page-size":fe,total:Y.value,layout:"prev, pager, next, ->, total",onCurrentChange:N},null,8,["current-page","total"]),u("div",pl,"第 "+_(F.value)+" / "+_(Z.value)+" 页",1)])]),_:1}),t(Ae,{modelValue:S.value,"onUpdate:modelValue":e[25]||(e[25]=l=>S.value=l),title:k.value?"编辑SMTP配置":"添加SMTP配置",width:"min(560px, 92vw)"},{footer:n(()=>[u("div",yl,[t(T,{onClick:we},{default:n(()=>[...e[36]||(e[36]=[p("测试连接",-1)])]),_:1}),k.value&&D.value?(f(),M(T,{key:0,type:"warning",plain:"",onClick:Te},{default:n(()=>[...e[37]||(e[37]=[p("取消主配置",-1)])]),_:1})):P("",!0),k.value&&!D.value?(f(),M(T,{key:1,onClick:Se},{default:n(()=>[...e[38]||(e[38]=[p("设为主配置",-1)])]),_:1})):P("",!0),k.value?(f(),M(T,{key:2,type:"danger",plain:"",onClick:xe},{default:n(()=>[...e[39]||(e[39]=[p("删除配置",-1)])]),_:1})):P("",!0),e[42]||(e[42]=u("div",{class:"spacer"},null,-1)),t(T,{onClick:e[24]||(e[24]=l=>S.value=!1)},{default:n(()=>[...e[40]||(e[40]=[p("取消",-1)])]),_:1}),t(T,{type:"primary",onClick:Ve},{default:n(()=>[...e[41]||(e[41]=[p("保存",-1)])]),_:1})])]),default:n(()=>[t(ie,{"label-width":"120px"},{default:n(()=>[t(r,{label:"名称"},{default:n(()=>[t(C,{modelValue:a.name,"onUpdate:modelValue":e[11]||(e[11]=l=>a.name=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"启用"},{default:n(()=>[t(i,{modelValue:a.enabled,"onUpdate:modelValue":e[12]||(e[12]=l=>a.enabled=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"邮箱模板"},{default:n(()=>[u("div",cl,[t(ee,{modelValue:$.value,"onUpdate:modelValue":e[13]||(e[13]=l=>$.value=l),placeholder:"选择常用邮箱模板",style:{width:"100%"},onChange:ye},{default:n(()=>[(f(),x(te,null,ce(H,l=>t(w,{key:l.key,label:l.label,value:l.key},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),V.value.note||V.value.links&&V.value.links.length?(f(),x("div",fl,[V.value.note?(f(),x("span",_l,_(V.value.note),1)):P("",!0),V.value.links&&V.value.links.length?(f(),x(te,{key:1},[V.value.note?(f(),x("span",bl," · ")):P("",!0),(f(!0),x(te,null,ce(V.value.links,(l,de)=>(f(),x("span",{key:l.url},[t(qe,{href:l.url,target:"_blank",type:"primary",underline:!1},{default:n(()=>[p(_(l.label),1)]),_:2},1032,["href"]),de[t(C,{modelValue:a.host,"onUpdate:modelValue":e[14]||(e[14]=l=>a.host=l),placeholder:"smtp.example.com"},null,8,["modelValue"])]),_:1}),t(r,{label:"端口"},{default:n(()=>[t(le,{modelValue:a.port,"onUpdate:modelValue":e[15]||(e[15]=l=>a.port=l),min:1,max:65535},null,8,["modelValue"])]),_:1}),t(r,{label:"用户名"},{default:n(()=>[t(C,{modelValue:a.username,"onUpdate:modelValue":e[16]||(e[16]=l=>a.username=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"密码"},{default:n(()=>[t(C,{modelValue:a.password,"onUpdate:modelValue":e[17]||(e[17]=l=>a.password=l),type:"password","show-password":"",placeholder:be.value},null,8,["modelValue","placeholder"])]),_:1}),t(r,{label:"SSL"},{default:n(()=>[t(i,{modelValue:a.use_ssl,"onUpdate:modelValue":e[18]||(e[18]=l=>a.use_ssl=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"TLS"},{default:n(()=>[t(i,{modelValue:a.use_tls,"onUpdate:modelValue":e[19]||(e[19]=l=>a.use_tls=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"发件人名称"},{default:n(()=>[t(C,{modelValue:a.sender_name,"onUpdate:modelValue":e[20]||(e[20]=l=>a.sender_name=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"发件人邮箱"},{default:n(()=>[t(C,{modelValue:a.sender_email,"onUpdate:modelValue":e[21]||(e[21]=l=>a.sender_email=l),placeholder:"可选"},null,8,["modelValue"])]),_:1}),t(r,{label:"每日限额"},{default:n(()=>[t(le,{modelValue:a.daily_limit,"onUpdate:modelValue":e[22]||(e[22]=l=>a.daily_limit=l),min:0,max:1e6},null,8,["modelValue"])]),_:1}),t(r,{label:"优先级"},{default:n(()=>[t(le,{modelValue:a.priority,"onUpdate:modelValue":e[23]||(e[23]=l=>a.priority=l),min:0,max:1e3},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"])])}}},Pl=Fe(gl,[["__scopeId","data-v-4f511165"]]);export{Pl as default}; +import{a as Ne,c as De,b as He,f as ze,u as Qe}from"./email-BYiWDIoy.js";import{a as U,_ as Fe}from"./index-iyjFO6XY.js";import{M as me}from"./MetricGrid-D-x_tNsK.js";import{E as B,f as d}from"./vendor-element-CJoVtPsD.js";import{r as m,a2 as pe,a1 as Ie,c as j,v as Ke,aW as c,b7 as je,z as x,A as f,B as u,M as G,S as t,K as M,L as n,P as p,Q as _,N as P,R as te,ak as ce}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ge(){const{data:b}=await U.get("/smtp/configs");return b}async function Oe(b){const{data:v}=await U.post("/smtp/configs",b);return v}async function Re(b,v){const{data:g}=await U.put(`/smtp/configs/${b}`,v);return g}async function We(b){const{data:v}=await U.delete(`/smtp/configs/${b}`);return v}async function Je(b,v){const{data:g}=await U.post(`/smtp/configs/${b}/test`,{email:v});return g}async function Xe(b){const{data:v}=await U.post(`/smtp/configs/${b}/primary`);return v}async function Ye(){const{data:b}=await U.post("/smtp/configs/primary/clear");return b}const Ze={class:"page-stack"},el={class:"help app-muted"},ll={class:"section-head"},tl={class:"table-wrap"},al={class:"sub-stats"},sl={class:"help app-muted"},nl={class:"section-head"},ol={class:"toolbar"},il={class:"table-wrap"},ul=["title"],rl=["title"],dl=["title"],ml={class:"pagination"},pl={class:"page-hint app-muted"},cl={style:{width:"100%"}},fl={key:0,class:"help"},_l={key:0},bl={key:0},vl={key:0},yl={class:"dialog-actions"},fe=15,gl={__name:"EmailPage",setup(b){const v=m(!1),g=m(!1),o=pe({enabled:!1,failover_enabled:!0,register_verify_enabled:!1,login_alert_enabled:!0,task_notify_enabled:!1,base_url:"",updated_at:null});let L=null;async function ae(){v.value=!0;try{const s=await He();o.enabled=!!s.enabled,o.failover_enabled=!!s.failover_enabled,o.register_verify_enabled=!!s.register_verify_enabled,o.login_alert_enabled=s.login_alert_enabled===void 0?!0:!!s.login_alert_enabled,o.task_notify_enabled=!!s.task_notify_enabled,o.base_url=s.base_url||"",o.updated_at=s.updated_at||null}catch{}finally{v.value=!1}}async function _e(){if(!v.value){g.value=!0;try{const s=await Qe({enabled:o.enabled,failover_enabled:o.failover_enabled,register_verify_enabled:o.register_verify_enabled,login_alert_enabled:o.login_alert_enabled,task_notify_enabled:o.task_notify_enabled,base_url:(o.base_url||"").trim()});if(!s?.success){d.error(s?.error||"更新失败");return}d.success("邮件设置已更新"),await ae()}catch{}finally{g.value=!1}}}function E(){L&&window.clearTimeout(L),L=window.setTimeout(_e,300)}Ie(()=>{L&&window.clearTimeout(L),L=null});const O=m(!1),R=m([]),S=m(!1),k=m(!1),W=m(!1),D=m(!1),a=pe({id:null,name:"默认配置",enabled:!0,host:"",port:465,username:"",password:"",use_ssl:!0,use_tls:!1,sender_name:"自动化学习",sender_email:"",daily_limit:0,priority:0}),H=[{key:"custom",label:"自定义(手动填写)",defaults:null,note:"适用于其他邮箱/自建SMTP",links:[]},{key:"gmail",label:"Gmail",defaults:{host:"smtp.gmail.com",port:465,use_ssl:!0,use_tls:!1},note:"通常需要开启两步验证并创建应用专用密码(App Password)",links:[{label:"SMTP 设置说明",url:"https://support.google.com/mail/answer/7126229?hl=zh-Hans"},{label:"App Password",url:"https://myaccount.google.com/apppasswords"}]},{key:"qq",label:"QQ 邮箱",defaults:{host:"smtp.qq.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并获取授权码(不是QQ登录密码)",links:[{label:"QQ邮箱 SMTP 帮助",url:"https://service.mail.qq.com/cgi-bin/help?subtype=1&id=28&no=1001256"}]},{key:"163",label:"163 邮箱",defaults:{host:"smtp.163.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并使用授权码/客户端授权密码",links:[{label:"网易邮箱 SMTP 帮助",url:"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471a22b76"}]},{key:"126",label:"126 邮箱",defaults:{host:"smtp.126.com",port:465,use_ssl:!0,use_tls:!1},note:"需要在邮箱设置中开启 SMTP 并使用授权码/客户端授权密码",links:[{label:"网易邮箱帮助",url:"https://help.mail.163.com/"}]},{key:"outlook",label:"Outlook/Hotmail",defaults:{host:"smtp-mail.outlook.com",port:587,use_ssl:!1,use_tls:!0},note:"建议使用 TLS 587(部分账号需开启 SMTP AUTH)",links:[{label:"微软 SMTP 设置",url:"https://support.microsoft.com/office/pop-imap-and-smtp-settings-for-outlook-com-d088b0b7-0d38-4f9a-bc5d-509f9e4c6d3d"}]},{key:"office365",label:"Microsoft 365/Exchange",defaults:{host:"smtp.office365.com",port:587,use_ssl:!1,use_tls:!0},note:"企业邮箱常用配置(需启用 SMTP AUTH)",links:[{label:"微软官方说明",url:"https://learn.microsoft.com/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission"}]},{key:"icloud",label:"iCloud",defaults:{host:"smtp.mail.me.com",port:587,use_ssl:!1,use_tls:!0},note:"需要在 Apple ID 中生成“App 专用密码”",links:[{label:"Apple 邮件服务器设置",url:"https://support.apple.com/zh-cn/HT202304"}]},{key:"tencent_exmail",label:"腾讯企业邮箱",defaults:{host:"smtp.exmail.qq.com",port:465,use_ssl:!0,use_tls:!1},note:"企业邮箱常用配置",links:[{label:"腾讯企业邮箱帮助",url:"https://service.exmail.qq.com/cgi-bin/help?subtype=1&id=23&no=1001068"}]},{key:"aliyun_exmail",label:"阿里企业邮箱",defaults:{host:"smtp.mxhichina.com",port:465,use_ssl:!0,use_tls:!1},note:"企业邮箱常用配置",links:[{label:"阿里云文档",url:"https://help.aliyun.com/document_detail/50652.html"}]}],$=m("custom"),V=j(()=>H.find(s=>s.key===$.value)||H[0]),be=j(()=>k.value&&W.value?"留空保持不变":"SMTP密码或授权码");function ve(s){const e=String(s?.host||"").trim().toLowerCase();return e&&{"smtp.gmail.com":"gmail","smtp.qq.com":"qq","smtp.163.com":"163","smtp.126.com":"126","smtp-mail.outlook.com":"outlook","smtp.office365.com":"office365","smtp.mail.me.com":"icloud","smtp.exmail.qq.com":"tencent_exmail","smtp.mxhichina.com":"aliyun_exmail"}[e]||"custom"}function ye(s){const e=H.find(i=>i.key===s);!e||!e.defaults||(a.host=e.defaults.host,a.port=e.defaults.port,a.use_ssl=e.defaults.use_ssl,a.use_tls=e.defaults.use_tls)}function se(){a.id=null,a.name="默认配置",a.enabled=!0,a.host="",a.port=465,a.username="",a.password="",a.use_ssl=!0,a.use_tls=!1,a.sender_name="自动化学习",a.sender_email="",a.daily_limit=0,a.priority=0,W.value=!1,D.value=!1,$.value="custom"}async function q(){O.value=!0;try{R.value=await Ge()}catch{R.value=[]}finally{O.value=!1}}function ge(){k.value=!1,se(),$.value="custom",S.value=!0}function ke(s){k.value=!0,se(),a.id=s.id,a.name=s.name||"默认配置",a.enabled=!!s.enabled,a.host=s.host||"",a.port=s.port||465,a.username=s.username||"",a.password="",a.use_ssl=!!s.use_ssl,a.use_tls=!!s.use_tls,a.sender_name=s.sender_name||"自动化学习",a.sender_email=s.sender_email||"",a.daily_limit=s.daily_limit??0,a.priority=s.priority??0,W.value=!!s.has_password,D.value=!!s.is_primary,$.value=ve(s),S.value=!0}function ne(s){return s.is_primary?{label:"主",type:"warning"}:s.enabled?{label:"备用",type:"success"}:{label:"禁用",type:"info"}}function he(s){return s.daily_limit&&s.daily_limit>0?`${s.daily_sent}/${s.daily_limit}`:`${s.daily_sent}/∞`}async function Ve(){if(!a.host.trim()){d.error("SMTP服务器地址不能为空");return}if(!a.username.trim()){d.error("SMTP用户名不能为空");return}const s={name:a.name.trim()||"默认配置",enabled:!!a.enabled,priority:Number(a.priority)||0,host:a.host.trim(),port:Number(a.port)||465,username:a.username.trim(),use_ssl:!!a.use_ssl,use_tls:!!a.use_tls,sender_name:(a.sender_name||"").trim(),sender_email:(a.sender_email||"").trim(),daily_limit:Number(a.daily_limit)||0};try{if(k.value){const e={...s};a.password&&(e.password=a.password);const i=await Re(a.id,e);if(!i?.success){d.error(i?.error||"更新失败");return}d.success("保存成功")}else{const e={...s};a.password&&(e.password=a.password);const i=await Oe(e);if(!i?.success){d.error(i?.error||"创建失败");return}d.success("创建成功")}S.value=!1,await q()}catch{}}async function we(){if(!k.value||!a.id){d.error("请先保存配置后再测试");return}let s;try{const e=await B.prompt("请输入测试收件邮箱","测试连接",{inputPlaceholder:"name@example.com",confirmButtonText:"发送测试邮件",cancelButtonText:"取消",inputValidator:i=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(i||"").trim()),inputErrorMessage:"邮箱格式不正确"});s=String(e.value||"").trim()}catch{return}try{const e=await Je(a.id,s);e?.success?(d.success("测试成功,邮件已发送"),await q()):await B.alert(e?.error||"测试失败","测试失败",{confirmButtonText:"知道了"})}catch{}}async function Se(){if(!(!k.value||!a.id)){try{await B.confirm("确定将该配置设为主配置吗?","设为主配置",{confirmButtonText:"设为主配置",cancelButtonText:"取消",type:"warning"})}catch{return}try{const s=await Xe(a.id);if(!s?.success){d.error(s?.error||"设置失败");return}d.success("已设为主配置"),S.value=!1,await q()}catch{}}}async function Te(){if(k.value){try{await B.confirm("确定取消主配置吗?取消后将按优先级选择可用SMTP。","取消主配置",{confirmButtonText:"取消主配置",cancelButtonText:"保留",type:"warning"})}catch{return}try{const s=await Ye();if(!s?.success){d.error(s?.error||"操作失败");return}d.success("已取消主配置"),S.value=!1,await q()}catch{}}}async function xe(){if(!(!k.value||!a.id)){try{await B.confirm("确定删除该SMTP配置吗?此操作不可恢复。","删除配置",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const s=await We(a.id);if(!s?.success){d.error(s?.error||"删除失败");return}d.success("已删除"),S.value=!1,await q()}catch{}}}const A=m(!1),h=m({}),J=m(!1),z=m(""),Q=m(""),F=m(1),X=m([]),Y=m(0),Z=m(1);function Pe(s){return{register:"注册验证",reset:"密码重置",bind:"邮箱绑定",task_complete:"任务完成",security_alert:"安全告警"}[s]||s}function oe(s){return s?.username&&s?.user_id?`${s.username} (#${s.user_id})`:s?.user_id?`用户#${s.user_id}`:"系统"}const Ce=j(()=>[{key:"total_sent",label:"总发送",value:h.value?.total_sent||0,tone:"blue"},{key:"total_success",label:"成功",value:h.value?.total_success||0,tone:"green"},{key:"total_failed",label:"失败",value:h.value?.total_failed||0,tone:"red"},{key:"success_rate",label:"成功率",value:`${h.value?.success_rate||0}%`,tone:"purple"}]),Be=j(()=>[{key:"register_sent",label:"注册验证",value:h.value?.register_sent||0,tone:"cyan"},{key:"reset_sent",label:"密码重置",value:h.value?.reset_sent||0,tone:"orange"},{key:"bind_sent",label:"邮箱绑定",value:h.value?.bind_sent||0,tone:"purple"},{key:"task_complete_sent",label:"任务完成",value:h.value?.task_complete_sent||0,tone:"green"}]);async function Me(){A.value=!0;try{h.value=await ze()}catch{h.value={}}finally{A.value=!1}}async function N(s=1){J.value=!0;try{const e={page:s,page_size:fe};z.value&&(e.type=z.value),Q.value&&(e.status=Q.value);const i=await Ne(e);X.value=i?.logs||[],Y.value=i?.total||0,F.value=i?.page||s,Z.value=i?.total_pages||1}catch{X.value=[],Y.value=0,Z.value=1}finally{J.value=!1}}async function Ue(){let s;try{const e=await B.prompt("请输入保留天数(将删除该天数之前的日志)","清理日志",{inputValue:"30",confirmButtonText:"清理",cancelButtonText:"取消",inputValidator:i=>{const r=parseInt(String(i),10);return Number.isFinite(r)&&r>=7},inputErrorMessage:"天数必须大于等于7"});s=parseInt(String(e.value),10)}catch{return}try{await B.confirm(`确定删除 ${s} 天之前的邮件日志吗?`,"二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await De(s);if(!e?.success){d.error(e?.error||"清理失败");return}d.success(`已清理 ${e.deleted} 条日志`),await N(1)}catch{}}async function Le(){await Promise.all([ae(),q(),Me(),N(1)])}return Ke(Le),(s,e)=>{const i=c("el-switch"),r=c("el-form-item"),Ee=c("el-divider"),C=c("el-input"),ie=c("el-form"),I=c("el-card"),T=c("el-button"),ue=c("el-tag"),y=c("el-table-column"),re=c("el-table"),w=c("el-option"),ee=c("el-select"),$e=c("el-pagination"),qe=c("el-link"),le=c("el-input-number"),Ae=c("el-dialog"),K=je("loading");return f(),x("div",Ze,[e[43]||(e[43]=u("div",{class:"app-page-title"},[u("h2",null,"邮件配置")],-1)),G((f(),M(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[e[29]||(e[29]=u("h3",{class:"section-title"},"全局设置",-1)),t(ie,{"label-width":"140px"},{default:n(()=>[t(r,{label:"启用邮件功能"},{default:n(()=>[t(i,{modelValue:o.enabled,"onUpdate:modelValue":e[0]||(e[0]=l=>o.enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"启用故障转移"},{default:n(()=>[t(i,{modelValue:o.failover_enabled,"onUpdate:modelValue":e[1]||(e[1]=l=>o.failover_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"启用注册邮箱验证"},{default:n(()=>[t(i,{modelValue:o.register_verify_enabled,"onUpdate:modelValue":e[2]||(e[2]=l=>o.register_verify_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(Ee,{"content-position":"left"},{default:n(()=>[...e[26]||(e[26]=[p("通知设置",-1)])]),_:1}),t(r,{label:"启用任务完成通知"},{default:n(()=>[t(i,{modelValue:o.task_notify_enabled,"onUpdate:modelValue":e[3]||(e[3]=l=>o.task_notify_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"])]),_:1}),t(r,{label:"新设备登录提醒"},{default:n(()=>[t(i,{modelValue:o.login_alert_enabled,"onUpdate:modelValue":e[4]||(e[4]=l=>o.login_alert_enabled=l),disabled:g.value,onChange:E},null,8,["modelValue","disabled"]),e[27]||(e[27]=u("div",{class:"help"},"当检测到新设备或新IP登录时,发送邮件提醒用户",-1))]),_:1}),t(r,{label:"网站基础URL"},{default:n(()=>[t(C,{modelValue:o.base_url,"onUpdate:modelValue":e[5]||(e[5]=l=>o.base_url=l),placeholder:"例如: https://example.com",disabled:g.value,onBlur:E},null,8,["modelValue","disabled"]),e[28]||(e[28]=u("div",{class:"help"},"用于生成邮件中的验证链接,留空则使用默认配置。",-1))]),_:1})]),_:1}),u("div",el,"最近更新时间:"+_(o.updated_at||"-"),1)]),_:1})),[[K,v.value]]),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[u("div",ll,[e[31]||(e[31]=u("h3",{class:"section-title"},"SMTP配置列表",-1)),t(T,{type:"primary",onClick:ge},{default:n(()=>[...e[30]||(e[30]=[p("+ 添加配置",-1)])]),_:1})]),u("div",tl,[G((f(),M(re,{data:R.value,style:{width:"100%"}},{default:n(()=>[t(y,{label:"状态",width:"90"},{default:n(({row:l})=>[t(ue,{type:ne(l).type,effect:"light"},{default:n(()=>[p(_(ne(l).label),1)]),_:2},1032,["type"])]),_:1}),t(y,{prop:"name",label:"名称","min-width":"160"}),t(y,{label:"服务器","min-width":"200"},{default:n(({row:l})=>[p(_(l.host)+":"+_(l.port),1)]),_:1}),t(y,{label:"今日/限额",width:"110"},{default:n(({row:l})=>[p(_(he(l)),1)]),_:1}),t(y,{label:"成功率",width:"100"},{default:n(({row:l})=>[p(_(l.success_rate)+"%",1)]),_:1}),t(y,{label:"操作",width:"120",fixed:"right"},{default:n(({row:l})=>[t(T,{size:"small",onClick:de=>ke(l)},{default:n(()=>[...e[32]||(e[32]=[p("编辑",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[K,O.value]])])]),_:1}),G((f(),M(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[e[33]||(e[33]=u("h3",{class:"section-title"},"邮件发送统计",-1)),t(me,{items:Ce.value,loading:A.value,"min-width":160},null,8,["items","loading"]),u("div",al,[t(me,{items:Be.value,loading:A.value,"min-width":150},null,8,["items","loading"])]),u("div",sl,"最后更新:"+_(h.value.last_updated||"-"),1)]),_:1})),[[K,A.value]]),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:n(()=>[u("div",nl,[e[35]||(e[35]=u("h3",{class:"section-title"},"邮件发送日志",-1)),u("div",ol,[t(ee,{modelValue:z.value,"onUpdate:modelValue":e[6]||(e[6]=l=>z.value=l),style:{width:"140px"},onChange:e[7]||(e[7]=l=>N(1))},{default:n(()=>[t(w,{label:"全部类型",value:""}),t(w,{label:"注册验证",value:"register"}),t(w,{label:"密码重置",value:"reset"}),t(w,{label:"邮箱绑定",value:"bind"}),t(w,{label:"任务完成",value:"task_complete"}),t(w,{label:"安全告警",value:"security_alert"})]),_:1},8,["modelValue"]),t(ee,{modelValue:Q.value,"onUpdate:modelValue":e[8]||(e[8]=l=>Q.value=l),style:{width:"120px"},onChange:e[9]||(e[9]=l=>N(1))},{default:n(()=>[t(w,{label:"全部状态",value:""}),t(w,{label:"成功",value:"success"}),t(w,{label:"失败",value:"failed"})]),_:1},8,["modelValue"]),t(T,{type:"danger",plain:"",onClick:Ue},{default:n(()=>[...e[34]||(e[34]=[p("清理日志",-1)])]),_:1})])]),u("div",il,[G((f(),M(re,{data:X.value,style:{width:"100%"}},{default:n(()=>[t(y,{prop:"created_at",label:"时间",width:"180"}),t(y,{prop:"email_to",label:"收件人","min-width":"180"}),t(y,{label:"来源用户","min-width":"160"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:oe(l)},_(oe(l)),9,ul)]),_:1}),t(y,{label:"类型",width:"120"},{default:n(({row:l})=>[p(_(Pe(l.email_type)),1)]),_:1}),t(y,{label:"主题","min-width":"220"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:l.subject},_(l.subject),9,rl)]),_:1}),t(y,{label:"状态",width:"90"},{default:n(({row:l})=>[t(ue,{type:l.status==="success"?"success":"danger",effect:"light"},{default:n(()=>[p(_(l.status==="success"?"成功":"失败"),1)]),_:2},1032,["type"])]),_:1}),t(y,{label:"错误","min-width":"200"},{default:n(({row:l})=>[u("span",{class:"ellipsis",title:l.error_message||""},_(l.error_message||"-"),9,dl)]),_:1})]),_:1},8,["data"])),[[K,J.value]])]),u("div",ml,[t($e,{"current-page":F.value,"onUpdate:currentPage":e[10]||(e[10]=l=>F.value=l),"page-size":fe,total:Y.value,layout:"prev, pager, next, ->, total",onCurrentChange:N},null,8,["current-page","total"]),u("div",pl,"第 "+_(F.value)+" / "+_(Z.value)+" 页",1)])]),_:1}),t(Ae,{modelValue:S.value,"onUpdate:modelValue":e[25]||(e[25]=l=>S.value=l),title:k.value?"编辑SMTP配置":"添加SMTP配置",width:"min(560px, 92vw)"},{footer:n(()=>[u("div",yl,[t(T,{onClick:we},{default:n(()=>[...e[36]||(e[36]=[p("测试连接",-1)])]),_:1}),k.value&&D.value?(f(),M(T,{key:0,type:"warning",plain:"",onClick:Te},{default:n(()=>[...e[37]||(e[37]=[p("取消主配置",-1)])]),_:1})):P("",!0),k.value&&!D.value?(f(),M(T,{key:1,onClick:Se},{default:n(()=>[...e[38]||(e[38]=[p("设为主配置",-1)])]),_:1})):P("",!0),k.value?(f(),M(T,{key:2,type:"danger",plain:"",onClick:xe},{default:n(()=>[...e[39]||(e[39]=[p("删除配置",-1)])]),_:1})):P("",!0),e[42]||(e[42]=u("div",{class:"spacer"},null,-1)),t(T,{onClick:e[24]||(e[24]=l=>S.value=!1)},{default:n(()=>[...e[40]||(e[40]=[p("取消",-1)])]),_:1}),t(T,{type:"primary",onClick:Ve},{default:n(()=>[...e[41]||(e[41]=[p("保存",-1)])]),_:1})])]),default:n(()=>[t(ie,{"label-width":"120px"},{default:n(()=>[t(r,{label:"名称"},{default:n(()=>[t(C,{modelValue:a.name,"onUpdate:modelValue":e[11]||(e[11]=l=>a.name=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"启用"},{default:n(()=>[t(i,{modelValue:a.enabled,"onUpdate:modelValue":e[12]||(e[12]=l=>a.enabled=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"邮箱模板"},{default:n(()=>[u("div",cl,[t(ee,{modelValue:$.value,"onUpdate:modelValue":e[13]||(e[13]=l=>$.value=l),placeholder:"选择常用邮箱模板",style:{width:"100%"},onChange:ye},{default:n(()=>[(f(),x(te,null,ce(H,l=>t(w,{key:l.key,label:l.label,value:l.key},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),V.value.note||V.value.links&&V.value.links.length?(f(),x("div",fl,[V.value.note?(f(),x("span",_l,_(V.value.note),1)):P("",!0),V.value.links&&V.value.links.length?(f(),x(te,{key:1},[V.value.note?(f(),x("span",bl," · ")):P("",!0),(f(!0),x(te,null,ce(V.value.links,(l,de)=>(f(),x("span",{key:l.url},[t(qe,{href:l.url,target:"_blank",type:"primary",underline:!1},{default:n(()=>[p(_(l.label),1)]),_:2},1032,["href"]),de[t(C,{modelValue:a.host,"onUpdate:modelValue":e[14]||(e[14]=l=>a.host=l),placeholder:"smtp.example.com"},null,8,["modelValue"])]),_:1}),t(r,{label:"端口"},{default:n(()=>[t(le,{modelValue:a.port,"onUpdate:modelValue":e[15]||(e[15]=l=>a.port=l),min:1,max:65535},null,8,["modelValue"])]),_:1}),t(r,{label:"用户名"},{default:n(()=>[t(C,{modelValue:a.username,"onUpdate:modelValue":e[16]||(e[16]=l=>a.username=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"密码"},{default:n(()=>[t(C,{modelValue:a.password,"onUpdate:modelValue":e[17]||(e[17]=l=>a.password=l),type:"password","show-password":"",placeholder:be.value},null,8,["modelValue","placeholder"])]),_:1}),t(r,{label:"SSL"},{default:n(()=>[t(i,{modelValue:a.use_ssl,"onUpdate:modelValue":e[18]||(e[18]=l=>a.use_ssl=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"TLS"},{default:n(()=>[t(i,{modelValue:a.use_tls,"onUpdate:modelValue":e[19]||(e[19]=l=>a.use_tls=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"发件人名称"},{default:n(()=>[t(C,{modelValue:a.sender_name,"onUpdate:modelValue":e[20]||(e[20]=l=>a.sender_name=l)},null,8,["modelValue"])]),_:1}),t(r,{label:"发件人邮箱"},{default:n(()=>[t(C,{modelValue:a.sender_email,"onUpdate:modelValue":e[21]||(e[21]=l=>a.sender_email=l),placeholder:"可选"},null,8,["modelValue"])]),_:1}),t(r,{label:"每日限额"},{default:n(()=>[t(le,{modelValue:a.daily_limit,"onUpdate:modelValue":e[22]||(e[22]=l=>a.daily_limit=l),min:0,max:1e6},null,8,["modelValue"])]),_:1}),t(r,{label:"优先级"},{default:n(()=>[t(le,{modelValue:a.priority,"onUpdate:modelValue":e[23]||(e[23]=l=>a.priority=l),min:0,max:1e3},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"])])}}},Pl=Fe(gl,[["__scopeId","data-v-4f511165"]]);export{Pl as default}; diff --git a/static/admin/assets/FeedbacksPage-B8rr6rHD.js b/static/admin/assets/FeedbacksPage-yGzwD6JV.js similarity index 97% rename from static/admin/assets/FeedbacksPage-B8rr6rHD.js rename to static/admin/assets/FeedbacksPage-yGzwD6JV.js index 0aea459..c50ec72 100644 --- a/static/admin/assets/FeedbacksPage-B8rr6rHD.js +++ b/static/admin/assets/FeedbacksPage-yGzwD6JV.js @@ -1 +1 @@ -import{_ as $,b as L,r as R,c as j,d as A}from"./index-D8t2quK2.js";import{M as G}from"./MetricGrid-Cbhb9OGV.js";import{E as k,f as w}from"./vendor-element-CJoVtPsD.js";import{i as K,r as f,c as O,v as Q,aW as i,b7 as U,z as x,A as v,B as s,S as t,L as l,R as F,ak as W,Q as d,M as q,K as H,P as p,N as J}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";const X={class:"page-stack"},Y={class:"app-page-title"},Z={class:"toolbar"},ee={class:"section-head"},te={class:"app-muted"},ae={class:"table-wrap"},le={class:"ellipsis"},ne={class:"ellipsis"},se={class:"ellipsis"},oe={class:"actions"},ie={__name:"FeedbacksPage",setup(ce){const M=K("refreshNavBadges",null),u=f(!1),b=f(""),c=f({total:0,pending:0,replied:0,closed:0}),_=f([]),T=[{label:"全部状态",value:""},{label:"待处理",value:"pending"},{label:"已回复",value:"replied"},{label:"已关闭",value:"closed"}],V=O(()=>[{key:"total",label:"总反馈",value:c.value.total||0,tone:"blue"},{key:"pending",label:"待处理",value:c.value.pending||0,tone:"orange"},{key:"replied",label:"已回复",value:c.value.replied||0,tone:"green"},{key:"closed",label:"已关闭",value:c.value.closed||0,tone:"purple"}]);function B(n){return n==="pending"?{label:"待处理",type:"warning"}:n==="replied"?{label:"已回复",type:"success"}:n==="closed"?{label:"已关闭",type:"info"}:{label:n||"-",type:"info"}}async function r(){u.value=!0;try{const n=await L(b.value);_.value=n?.feedbacks||[],c.value=n?.stats||{total:0,pending:0,replied:0,closed:0}}catch{_.value=[],c.value={total:0,pending:0,replied:0,closed:0}}finally{u.value=!1}await M?.({pendingFeedbacks:c.value.pending||0})}async function N(n){let a;try{a=(await k.prompt("请输入回复内容","回复反馈",{inputType:"textarea",inputPlaceholder:"回复内容",confirmButtonText:"提交",cancelButtonText:"取消",inputValidator:g=>!!String(g||"").trim(),inputErrorMessage:"回复内容不能为空"})).value}catch{return}try{const m=await R(n.id,String(a||"").trim());w.success(m?.message||"回复成功"),await r()}catch{}}async function D(n){try{await k.confirm("确定要关闭这个反馈吗?","关闭反馈",{confirmButtonText:"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}try{const a=await j(n.id);w.success(a?.message||"反馈已关闭"),await r()}catch{}}async function E(n){try{await k.confirm("确定要删除这个反馈吗?此操作不可恢复!","删除反馈",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const a=await A(n.id);w.success(a?.message||"反馈已删除"),await r()}catch{}}return Q(r),(n,a)=>{const m=i("el-option"),g=i("el-select"),o=i("el-table-column"),y=i("el-tooltip"),z=i("el-tag"),h=i("el-button"),P=i("el-table"),S=i("el-card"),I=U("loading");return v(),x("div",X,[s("div",Y,[a[1]||(a[1]=s("h2",null,"反馈管理",-1)),s("div",Z,[t(g,{modelValue:b.value,"onUpdate:modelValue":a[0]||(a[0]=e=>b.value=e),style:{width:"160px"},onChange:r},{default:l(()=>[(v(),x(F,null,W(T,e=>t(m,{key:e.value,label:e.label,value:e.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"])])]),t(G,{items:V.value,loading:u.value,"min-width":165},null,8,["items","loading"]),t(S,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[s("div",ee,[a[2]||(a[2]=s("h3",{class:"section-title"},"反馈列表",-1)),s("div",te,"共 "+d(_.value.length)+" 条(当前筛选)",1)]),s("div",ae,[q((v(),H(P,{data:_.value,style:{width:"100%"}},{default:l(()=>[t(o,{prop:"id",label:"ID",width:"80"}),t(o,{prop:"username",label:"用户",width:"140"}),t(o,{label:"标题","min-width":"180"},{default:l(({row:e})=>[t(y,{content:e.title,placement:"top","show-after":300},{default:l(()=>[s("span",le,d(e.title),1)]),_:2},1032,["content"])]),_:1}),t(o,{label:"描述","min-width":"220"},{default:l(({row:e})=>[t(y,{content:e.description,placement:"top","show-after":300},{default:l(()=>[s("span",ne,d(e.description),1)]),_:2},1032,["content"])]),_:1}),t(o,{prop:"contact",label:"联系方式","min-width":"160"},{default:l(({row:e})=>[p(d(e.contact||"-"),1)]),_:1}),t(o,{label:"状态",width:"110"},{default:l(({row:e})=>[t(z,{type:B(e.status).type,effect:"light"},{default:l(()=>[p(d(B(e.status).label),1)]),_:2},1032,["type"])]),_:1}),t(o,{prop:"created_at",label:"提交时间",width:"180"}),t(o,{label:"回复","min-width":"180"},{default:l(({row:e})=>[t(y,{content:e.admin_reply||"",placement:"top","show-after":300},{default:l(()=>[s("span",se,d(e.admin_reply||"-"),1)]),_:2},1032,["content"])]),_:1}),t(o,{label:"操作",width:"220",fixed:"right"},{default:l(({row:e})=>[s("div",oe,[e.status!=="closed"?(v(),x(F,{key:0},[t(h,{type:"primary",size:"small",onClick:C=>N(e)},{default:l(()=>[...a[3]||(a[3]=[p("回复",-1)])]),_:1},8,["onClick"]),t(h,{size:"small",onClick:C=>D(e)},{default:l(()=>[...a[4]||(a[4]=[p("关闭",-1)])]),_:1},8,["onClick"])],64)):J("",!0),t(h,{type:"danger",size:"small",onClick:C=>E(e)},{default:l(()=>[...a[5]||(a[5]=[p("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[I,u.value]])])]),_:1})])}}},fe=$(ie,[["__scopeId","data-v-910fe89b"]]);export{fe as default}; +import{_ as $,b as L,r as R,c as j,d as A}from"./index-iyjFO6XY.js";import{M as G}from"./MetricGrid-D-x_tNsK.js";import{E as k,f as w}from"./vendor-element-CJoVtPsD.js";import{i as K,r as f,c as O,v as Q,aW as i,b7 as U,z as x,A as v,B as s,S as t,L as l,R as F,ak as W,Q as d,M as q,K as H,P as p,N as J}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";const X={class:"page-stack"},Y={class:"app-page-title"},Z={class:"toolbar"},ee={class:"section-head"},te={class:"app-muted"},ae={class:"table-wrap"},le={class:"ellipsis"},ne={class:"ellipsis"},se={class:"ellipsis"},oe={class:"actions"},ie={__name:"FeedbacksPage",setup(ce){const M=K("refreshNavBadges",null),u=f(!1),b=f(""),c=f({total:0,pending:0,replied:0,closed:0}),_=f([]),T=[{label:"全部状态",value:""},{label:"待处理",value:"pending"},{label:"已回复",value:"replied"},{label:"已关闭",value:"closed"}],V=O(()=>[{key:"total",label:"总反馈",value:c.value.total||0,tone:"blue"},{key:"pending",label:"待处理",value:c.value.pending||0,tone:"orange"},{key:"replied",label:"已回复",value:c.value.replied||0,tone:"green"},{key:"closed",label:"已关闭",value:c.value.closed||0,tone:"purple"}]);function B(n){return n==="pending"?{label:"待处理",type:"warning"}:n==="replied"?{label:"已回复",type:"success"}:n==="closed"?{label:"已关闭",type:"info"}:{label:n||"-",type:"info"}}async function r(){u.value=!0;try{const n=await L(b.value);_.value=n?.feedbacks||[],c.value=n?.stats||{total:0,pending:0,replied:0,closed:0}}catch{_.value=[],c.value={total:0,pending:0,replied:0,closed:0}}finally{u.value=!1}await M?.({pendingFeedbacks:c.value.pending||0})}async function N(n){let a;try{a=(await k.prompt("请输入回复内容","回复反馈",{inputType:"textarea",inputPlaceholder:"回复内容",confirmButtonText:"提交",cancelButtonText:"取消",inputValidator:g=>!!String(g||"").trim(),inputErrorMessage:"回复内容不能为空"})).value}catch{return}try{const m=await R(n.id,String(a||"").trim());w.success(m?.message||"回复成功"),await r()}catch{}}async function D(n){try{await k.confirm("确定要关闭这个反馈吗?","关闭反馈",{confirmButtonText:"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}try{const a=await j(n.id);w.success(a?.message||"反馈已关闭"),await r()}catch{}}async function E(n){try{await k.confirm("确定要删除这个反馈吗?此操作不可恢复!","删除反馈",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{const a=await A(n.id);w.success(a?.message||"反馈已删除"),await r()}catch{}}return Q(r),(n,a)=>{const m=i("el-option"),g=i("el-select"),o=i("el-table-column"),y=i("el-tooltip"),z=i("el-tag"),h=i("el-button"),P=i("el-table"),S=i("el-card"),I=U("loading");return v(),x("div",X,[s("div",Y,[a[1]||(a[1]=s("h2",null,"反馈管理",-1)),s("div",Z,[t(g,{modelValue:b.value,"onUpdate:modelValue":a[0]||(a[0]=e=>b.value=e),style:{width:"160px"},onChange:r},{default:l(()=>[(v(),x(F,null,W(T,e=>t(m,{key:e.value,label:e.label,value:e.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"])])]),t(G,{items:V.value,loading:u.value,"min-width":165},null,8,["items","loading"]),t(S,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[s("div",ee,[a[2]||(a[2]=s("h3",{class:"section-title"},"反馈列表",-1)),s("div",te,"共 "+d(_.value.length)+" 条(当前筛选)",1)]),s("div",ae,[q((v(),H(P,{data:_.value,style:{width:"100%"}},{default:l(()=>[t(o,{prop:"id",label:"ID",width:"80"}),t(o,{prop:"username",label:"用户",width:"140"}),t(o,{label:"标题","min-width":"180"},{default:l(({row:e})=>[t(y,{content:e.title,placement:"top","show-after":300},{default:l(()=>[s("span",le,d(e.title),1)]),_:2},1032,["content"])]),_:1}),t(o,{label:"描述","min-width":"220"},{default:l(({row:e})=>[t(y,{content:e.description,placement:"top","show-after":300},{default:l(()=>[s("span",ne,d(e.description),1)]),_:2},1032,["content"])]),_:1}),t(o,{prop:"contact",label:"联系方式","min-width":"160"},{default:l(({row:e})=>[p(d(e.contact||"-"),1)]),_:1}),t(o,{label:"状态",width:"110"},{default:l(({row:e})=>[t(z,{type:B(e.status).type,effect:"light"},{default:l(()=>[p(d(B(e.status).label),1)]),_:2},1032,["type"])]),_:1}),t(o,{prop:"created_at",label:"提交时间",width:"180"}),t(o,{label:"回复","min-width":"180"},{default:l(({row:e})=>[t(y,{content:e.admin_reply||"",placement:"top","show-after":300},{default:l(()=>[s("span",se,d(e.admin_reply||"-"),1)]),_:2},1032,["content"])]),_:1}),t(o,{label:"操作",width:"220",fixed:"right"},{default:l(({row:e})=>[s("div",oe,[e.status!=="closed"?(v(),x(F,{key:0},[t(h,{type:"primary",size:"small",onClick:C=>N(e)},{default:l(()=>[...a[3]||(a[3]=[p("回复",-1)])]),_:1},8,["onClick"]),t(h,{size:"small",onClick:C=>D(e)},{default:l(()=>[...a[4]||(a[4]=[p("关闭",-1)])]),_:1},8,["onClick"])],64)):J("",!0),t(h,{type:"danger",size:"small",onClick:C=>E(e)},{default:l(()=>[...a[5]||(a[5]=[p("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[I,u.value]])])]),_:1})])}}},fe=$(ie,[["__scopeId","data-v-910fe89b"]]);export{fe as default}; diff --git a/static/admin/assets/LogsPage-WfvkzS-6.js b/static/admin/assets/LogsPage-WmQFhJZO.js similarity index 98% rename from static/admin/assets/LogsPage-WfvkzS-6.js rename to static/admin/assets/LogsPage-WmQFhJZO.js index 32f48b1..969fd3c 100644 --- a/static/admin/assets/LogsPage-WfvkzS-6.js +++ b/static/admin/assets/LogsPage-WmQFhJZO.js @@ -1 +1 @@ -import{f as q}from"./users-CTuo5Ynz.js";import{d as G,e as H}from"./tasks-DZnsc1fC.js";import{_ as J}from"./index-D8t2quK2.js";import{E as P,f as X}from"./vendor-element-CJoVtPsD.js";import{r as u,c as Z,v as ee,aW as r,b7 as te,z as E,A as b,B as f,S as t,L as l,R as ae,ak as le,K as B,P as m,M as oe,Q as d}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";function ne(p){return String(p||"").trim()}function se(p){return!p.startsWith("user_scheduled")||!p.includes(":")?"":p.split(":",2)[1]||""}function ue(p){const s=ne(p);if(!s||s==="manual")return{group:"manual",label:"手动",type:"success",tooltip:""};if(s==="scheduled")return{group:"scheduled",label:"定时任务",type:"primary",tooltip:"系统定时"};if(s.startsWith("user_scheduled")){const i=se(s),v=String(i||"").replace(/^batch_/,"");return{group:"scheduled",label:"定时任务",type:"primary",tooltip:v?`用户定时批次:${v}`:"用户定时"}}return{group:"manual",label:"手动",type:"success",tooltip:{batch:"手动批量",manual_screenshot:"手动截图",immediate:"立即执行",resumed:"断点恢复"}[s]||s}}const re={class:"page-stack"},ie={class:"filters"},ce={class:"table-wrap"},de={class:"ellipsis"},pe={class:"pagination"},me={class:"page-hint app-muted"},F=20,fe={__name:"LogsPage",setup(p){const s=u(!1),S=u([]),y=u(0),i=u(1),v=u(!1),T=u([]),h=u(""),w=u(""),V=u(""),x=u(""),k=u(""),$=Z(()=>Math.max(1,Math.ceil((y.value||0)/F)));function z(o){if(o==null)return"-";const e=Number(o);return Number.isFinite(e)?e<60?`${e}秒`:`${Math.floor(e/60)}分${e%60}秒`:"-"}function _(o){const e=ue(o);return{key:e.group,label:e.label,type:e.type,tooltip:e.tooltip}}function D(o){return o==="success"?{label:"成功",type:"success"}:o==="failed"?{label:"失败",type:"danger"}:{label:o||"-",type:"info"}}async function Y(){v.value=!0;try{const o=await q();T.value=(o||[]).map(e=>({id:e.id,username:e.username}))}catch{T.value=[]}finally{v.value=!1}}async function M(){s.value=!0;try{const o=(i.value-1)*F,e={limit:F,offset:o};h.value&&(e.date=h.value),w.value&&(e.status=w.value),V.value&&(e.source=V.value),x.value&&(e.user_id=x.value),k.value&&(e.account=k.value);const g=await G(e);S.value=g?.logs||[],y.value=g?.total||0}catch{S.value=[],y.value=0}finally{s.value=!1}}function O(){i.value=1,M()}function R(){h.value="",w.value="",V.value="",x.value="",k.value="",i.value=1,M()}async function W(){let o;try{const e=await P.prompt("请输入要清理多少天前的日志(默认30天)","清理旧日志",{inputValue:"30",confirmButtonText:"下一步",cancelButtonText:"取消",inputValidator:g=>{const n=parseInt(String(g),10);return Number.isFinite(n)&&n>=1},inputErrorMessage:"请输入有效的天数(大于0的整数)"});o=parseInt(String(e.value),10)}catch{return}try{await P.confirm(`确定要删除 ${o} 天前的所有日志吗?此操作不可恢复!`,"二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await H(o);X.success(e?.message||"清理成功"),i.value=1,await M()}catch{}}return ee(async()=>{await Y(),await M()}),(o,e)=>{const g=r("el-date-picker"),n=r("el-option"),U=r("el-select"),A=r("el-input"),C=r("el-button"),I=r("el-card"),c=r("el-table-column"),L=r("el-tag"),N=r("el-tooltip"),j=r("el-table"),K=r("el-pagination"),Q=te("loading");return b(),E("div",re,[e[9]||(e[9]=f("div",{class:"app-page-title"},[f("h2",null,"任务日志")],-1)),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[f("div",ie,[t(g,{modelValue:h.value,"onUpdate:modelValue":e[0]||(e[0]=a=>h.value=a),type:"date","value-format":"YYYY-MM-DD",placeholder:"日期",style:{width:"150px"}},null,8,["modelValue"]),t(U,{modelValue:w.value,"onUpdate:modelValue":e[1]||(e[1]=a=>w.value=a),placeholder:"状态",style:{width:"120px"}},{default:l(()=>[t(n,{label:"全部",value:""}),t(n,{label:"成功",value:"success"}),t(n,{label:"失败",value:"failed"})]),_:1},8,["modelValue"]),t(U,{modelValue:V.value,"onUpdate:modelValue":e[2]||(e[2]=a=>V.value=a),placeholder:"来源",style:{width:"120px"}},{default:l(()=>[t(n,{label:"全部",value:""}),t(n,{label:"手动",value:"manual"}),t(n,{label:"定时任务(系统)",value:"scheduled"}),t(n,{label:"定时任务(用户)",value:"user_scheduled"}),t(n,{label:"手动(批量)",value:"batch"}),t(n,{label:"手动(截图)",value:"manual_screenshot"}),t(n,{label:"手动(立即)",value:"immediate"}),t(n,{label:"手动(恢复)",value:"resumed"})]),_:1},8,["modelValue"]),t(U,{modelValue:x.value,"onUpdate:modelValue":e[3]||(e[3]=a=>x.value=a),placeholder:"用户",style:{width:"140px"},loading:v.value,filterable:"",clearable:""},{default:l(()=>[t(n,{label:"全部",value:""}),(b(!0),E(ae,null,le(T.value,a=>(b(),B(n,{key:a.id,label:a.username,value:String(a.id)},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"]),t(A,{modelValue:k.value,"onUpdate:modelValue":e[4]||(e[4]=a=>k.value=a),placeholder:"账号关键字",style:{width:"170px"},clearable:""},null,8,["modelValue"]),t(C,{type:"primary",onClick:O},{default:l(()=>[...e[6]||(e[6]=[m("筛选",-1)])]),_:1}),t(C,{onClick:R},{default:l(()=>[...e[7]||(e[7]=[m("重置",-1)])]),_:1}),t(C,{type:"danger",plain:"",onClick:W},{default:l(()=>[...e[8]||(e[8]=[m("清理旧日志",-1)])]),_:1})])]),_:1}),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[f("div",ce,[oe((b(),B(j,{data:S.value,style:{width:"100%"}},{default:l(()=>[t(c,{prop:"created_at",label:"时间",width:"180"}),t(c,{label:"来源",width:"110"},{default:l(({row:a})=>[_(a.source).tooltip?(b(),B(N,{key:0,content:_(a.source).tooltip,placement:"top","show-after":300},{default:l(()=>[t(L,{type:_(a.source).type,effect:"light"},{default:l(()=>[m(d(_(a.source).label),1)]),_:2},1032,["type"])]),_:2},1032,["content"])):(b(),B(L,{key:1,type:_(a.source).type,effect:"light"},{default:l(()=>[m(d(_(a.source).label),1)]),_:2},1032,["type"]))]),_:1}),t(c,{prop:"user_username",label:"用户",width:"140"}),t(c,{prop:"username",label:"账号",width:"160"}),t(c,{prop:"browse_type",label:"浏览类型",width:"120"}),t(c,{label:"状态",width:"90"},{default:l(({row:a})=>[t(L,{type:D(a.status).type,effect:"light"},{default:l(()=>[m(d(D(a.status).label),1)]),_:2},1032,["type"])]),_:1}),t(c,{label:"内容/附件",width:"110"},{default:l(({row:a})=>[m(d(a.total_items)+" / "+d(a.total_attachments),1)]),_:1}),t(c,{label:"用时",width:"90"},{default:l(({row:a})=>[m(d(z(a.duration)),1)]),_:1}),t(c,{label:"失败原因","min-width":"220"},{default:l(({row:a})=>[t(N,{content:a.error_message||"",placement:"top","show-after":300},{default:l(()=>[f("span",de,d(a.error_message||"-"),1)]),_:2},1032,["content"])]),_:1})]),_:1},8,["data"])),[[Q,s.value]])]),f("div",pe,[t(K,{"current-page":i.value,"onUpdate:currentPage":e[5]||(e[5]=a=>i.value=a),"page-size":F,total:y.value,layout:"prev, pager, next, jumper, ->, total",onCurrentChange:M},null,8,["current-page","total"]),f("div",me,"第 "+d(i.value)+" / "+d($.value)+" 页",1)])]),_:1})])}}},Ve=J(fe,[["__scopeId","data-v-8803eb08"]]);export{Ve as default}; +import{f as q}from"./users-Kctz2ziD.js";import{d as G,e as H}from"./tasks-BZsqSMnk.js";import{_ as J}from"./index-iyjFO6XY.js";import{E as P,f as X}from"./vendor-element-CJoVtPsD.js";import{r as u,c as Z,v as ee,aW as r,b7 as te,z as E,A as b,B as f,S as t,L as l,R as ae,ak as le,K as B,P as m,M as oe,Q as d}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";function ne(p){return String(p||"").trim()}function se(p){return!p.startsWith("user_scheduled")||!p.includes(":")?"":p.split(":",2)[1]||""}function ue(p){const s=ne(p);if(!s||s==="manual")return{group:"manual",label:"手动",type:"success",tooltip:""};if(s==="scheduled")return{group:"scheduled",label:"定时任务",type:"primary",tooltip:"系统定时"};if(s.startsWith("user_scheduled")){const i=se(s),v=String(i||"").replace(/^batch_/,"");return{group:"scheduled",label:"定时任务",type:"primary",tooltip:v?`用户定时批次:${v}`:"用户定时"}}return{group:"manual",label:"手动",type:"success",tooltip:{batch:"手动批量",manual_screenshot:"手动截图",immediate:"立即执行",resumed:"断点恢复"}[s]||s}}const re={class:"page-stack"},ie={class:"filters"},ce={class:"table-wrap"},de={class:"ellipsis"},pe={class:"pagination"},me={class:"page-hint app-muted"},F=20,fe={__name:"LogsPage",setup(p){const s=u(!1),S=u([]),y=u(0),i=u(1),v=u(!1),T=u([]),h=u(""),w=u(""),V=u(""),x=u(""),k=u(""),$=Z(()=>Math.max(1,Math.ceil((y.value||0)/F)));function z(o){if(o==null)return"-";const e=Number(o);return Number.isFinite(e)?e<60?`${e}秒`:`${Math.floor(e/60)}分${e%60}秒`:"-"}function _(o){const e=ue(o);return{key:e.group,label:e.label,type:e.type,tooltip:e.tooltip}}function D(o){return o==="success"?{label:"成功",type:"success"}:o==="failed"?{label:"失败",type:"danger"}:{label:o||"-",type:"info"}}async function Y(){v.value=!0;try{const o=await q();T.value=(o||[]).map(e=>({id:e.id,username:e.username}))}catch{T.value=[]}finally{v.value=!1}}async function M(){s.value=!0;try{const o=(i.value-1)*F,e={limit:F,offset:o};h.value&&(e.date=h.value),w.value&&(e.status=w.value),V.value&&(e.source=V.value),x.value&&(e.user_id=x.value),k.value&&(e.account=k.value);const g=await G(e);S.value=g?.logs||[],y.value=g?.total||0}catch{S.value=[],y.value=0}finally{s.value=!1}}function O(){i.value=1,M()}function R(){h.value="",w.value="",V.value="",x.value="",k.value="",i.value=1,M()}async function W(){let o;try{const e=await P.prompt("请输入要清理多少天前的日志(默认30天)","清理旧日志",{inputValue:"30",confirmButtonText:"下一步",cancelButtonText:"取消",inputValidator:g=>{const n=parseInt(String(g),10);return Number.isFinite(n)&&n>=1},inputErrorMessage:"请输入有效的天数(大于0的整数)"});o=parseInt(String(e.value),10)}catch{return}try{await P.confirm(`确定要删除 ${o} 天前的所有日志吗?此操作不可恢复!`,"二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await H(o);X.success(e?.message||"清理成功"),i.value=1,await M()}catch{}}return ee(async()=>{await Y(),await M()}),(o,e)=>{const g=r("el-date-picker"),n=r("el-option"),U=r("el-select"),A=r("el-input"),C=r("el-button"),I=r("el-card"),c=r("el-table-column"),L=r("el-tag"),N=r("el-tooltip"),j=r("el-table"),K=r("el-pagination"),Q=te("loading");return b(),E("div",re,[e[9]||(e[9]=f("div",{class:"app-page-title"},[f("h2",null,"任务日志")],-1)),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[f("div",ie,[t(g,{modelValue:h.value,"onUpdate:modelValue":e[0]||(e[0]=a=>h.value=a),type:"date","value-format":"YYYY-MM-DD",placeholder:"日期",style:{width:"150px"}},null,8,["modelValue"]),t(U,{modelValue:w.value,"onUpdate:modelValue":e[1]||(e[1]=a=>w.value=a),placeholder:"状态",style:{width:"120px"}},{default:l(()=>[t(n,{label:"全部",value:""}),t(n,{label:"成功",value:"success"}),t(n,{label:"失败",value:"failed"})]),_:1},8,["modelValue"]),t(U,{modelValue:V.value,"onUpdate:modelValue":e[2]||(e[2]=a=>V.value=a),placeholder:"来源",style:{width:"120px"}},{default:l(()=>[t(n,{label:"全部",value:""}),t(n,{label:"手动",value:"manual"}),t(n,{label:"定时任务(系统)",value:"scheduled"}),t(n,{label:"定时任务(用户)",value:"user_scheduled"}),t(n,{label:"手动(批量)",value:"batch"}),t(n,{label:"手动(截图)",value:"manual_screenshot"}),t(n,{label:"手动(立即)",value:"immediate"}),t(n,{label:"手动(恢复)",value:"resumed"})]),_:1},8,["modelValue"]),t(U,{modelValue:x.value,"onUpdate:modelValue":e[3]||(e[3]=a=>x.value=a),placeholder:"用户",style:{width:"140px"},loading:v.value,filterable:"",clearable:""},{default:l(()=>[t(n,{label:"全部",value:""}),(b(!0),E(ae,null,le(T.value,a=>(b(),B(n,{key:a.id,label:a.username,value:String(a.id)},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"]),t(A,{modelValue:k.value,"onUpdate:modelValue":e[4]||(e[4]=a=>k.value=a),placeholder:"账号关键字",style:{width:"170px"},clearable:""},null,8,["modelValue"]),t(C,{type:"primary",onClick:O},{default:l(()=>[...e[6]||(e[6]=[m("筛选",-1)])]),_:1}),t(C,{onClick:R},{default:l(()=>[...e[7]||(e[7]=[m("重置",-1)])]),_:1}),t(C,{type:"danger",plain:"",onClick:W},{default:l(()=>[...e[8]||(e[8]=[m("清理旧日志",-1)])]),_:1})])]),_:1}),t(I,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[f("div",ce,[oe((b(),B(j,{data:S.value,style:{width:"100%"}},{default:l(()=>[t(c,{prop:"created_at",label:"时间",width:"180"}),t(c,{label:"来源",width:"110"},{default:l(({row:a})=>[_(a.source).tooltip?(b(),B(N,{key:0,content:_(a.source).tooltip,placement:"top","show-after":300},{default:l(()=>[t(L,{type:_(a.source).type,effect:"light"},{default:l(()=>[m(d(_(a.source).label),1)]),_:2},1032,["type"])]),_:2},1032,["content"])):(b(),B(L,{key:1,type:_(a.source).type,effect:"light"},{default:l(()=>[m(d(_(a.source).label),1)]),_:2},1032,["type"]))]),_:1}),t(c,{prop:"user_username",label:"用户",width:"140"}),t(c,{prop:"username",label:"账号",width:"160"}),t(c,{prop:"browse_type",label:"浏览类型",width:"120"}),t(c,{label:"状态",width:"90"},{default:l(({row:a})=>[t(L,{type:D(a.status).type,effect:"light"},{default:l(()=>[m(d(D(a.status).label),1)]),_:2},1032,["type"])]),_:1}),t(c,{label:"内容/附件",width:"110"},{default:l(({row:a})=>[m(d(a.total_items)+" / "+d(a.total_attachments),1)]),_:1}),t(c,{label:"用时",width:"90"},{default:l(({row:a})=>[m(d(z(a.duration)),1)]),_:1}),t(c,{label:"失败原因","min-width":"220"},{default:l(({row:a})=>[t(N,{content:a.error_message||"",placement:"top","show-after":300},{default:l(()=>[f("span",de,d(a.error_message||"-"),1)]),_:2},1032,["content"])]),_:1})]),_:1},8,["data"])),[[Q,s.value]])]),f("div",pe,[t(K,{"current-page":i.value,"onUpdate:currentPage":e[5]||(e[5]=a=>i.value=a),"page-size":F,total:y.value,layout:"prev, pager, next, jumper, ->, total",onCurrentChange:M},null,8,["current-page","total"]),f("div",me,"第 "+d(i.value)+" / "+d($.value)+" 页",1)])]),_:1})])}}},Ve=J(fe,[["__scopeId","data-v-8803eb08"]]);export{Ve as default}; diff --git a/static/admin/assets/MetricGrid-Cbhb9OGV.js b/static/admin/assets/MetricGrid-D-x_tNsK.js similarity index 94% rename from static/admin/assets/MetricGrid-Cbhb9OGV.js rename to static/admin/assets/MetricGrid-D-x_tNsK.js index fbe052d..61f0855 100644 --- a/static/admin/assets/MetricGrid-Cbhb9OGV.js +++ b/static/admin/assets/MetricGrid-D-x_tNsK.js @@ -1 +1 @@ -import{_}from"./index-D8t2quK2.js";import{aW as c,z as s,A as t,R as r,ak as u,E as p,B as o,N as l,S as y,L as h,K as i,O as k,Q as n,P as v,D as f}from"./vendor-sLgkZK1v.js";const b={class:"metric-top"},x={key:0,class:"metric-icon"},B={class:"metric-label"},N={class:"metric-value"},g={key:0,class:"metric-hint app-muted"},C={__name:"MetricGrid",props:{items:{type:Array,default:()=>[]},loading:{type:Boolean,default:!1},minWidth:{type:Number,default:180}},setup(a){return(V,z)=>{const d=c("el-icon"),m=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(r,null,u(a.items,e=>(t(),s("div",{key:e?.key||e?.label,class:p(["metric-card",`metric-tone--${e?.tone||"blue"}`])},[o("div",b,[e?.icon?(t(),s("div",x,[y(d,null,{default:h(()=>[(t(),i(k(e.icon)))]),_:2},1024)])):l("",!0),o("div",B,n(e?.label||"-"),1)]),o("div",N,[a.loading?(t(),i(m,{key:0,rows:1,animated:""})):(t(),s(r,{key:1},[v(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",g,n(e?.hint||e?.sub),1)):l("",!0)],2))),128))],4)}}},S=_(C,[["__scopeId","data-v-00e217d4"]]);export{S as M}; +import{_}from"./index-iyjFO6XY.js";import{aW as c,z as s,A as t,R as r,ak as u,E as p,B as o,N as l,S as y,L as h,K as i,O as k,Q as n,P as v,D as f}from"./vendor-sLgkZK1v.js";const b={class:"metric-top"},x={key:0,class:"metric-icon"},B={class:"metric-label"},N={class:"metric-value"},g={key:0,class:"metric-hint app-muted"},C={__name:"MetricGrid",props:{items:{type:Array,default:()=>[]},loading:{type:Boolean,default:!1},minWidth:{type:Number,default:180}},setup(a){return(V,z)=>{const d=c("el-icon"),m=c("el-skeleton");return t(),s("div",{class:"metric-grid",style:f({"--metric-min":`${a.minWidth}px`})},[(t(!0),s(r,null,u(a.items,e=>(t(),s("div",{key:e?.key||e?.label,class:p(["metric-card",`metric-tone--${e?.tone||"blue"}`])},[o("div",b,[e?.icon?(t(),s("div",x,[y(d,null,{default:h(()=>[(t(),i(k(e.icon)))]),_:2},1024)])):l("",!0),o("div",B,n(e?.label||"-"),1)]),o("div",N,[a.loading?(t(),i(m,{key:0,rows:1,animated:""})):(t(),s(r,{key:1},[v(n(e?.value??0),1)],64))]),e?.hint||e?.sub?(t(),s("div",g,n(e?.hint||e?.sub),1)):l("",!0)],2))),128))],4)}}},S=_(C,[["__scopeId","data-v-00e217d4"]]);export{S as M}; diff --git a/static/admin/assets/ReportPage-GPt5J1Db.js b/static/admin/assets/ReportPage-BkIhdzJa.js similarity index 97% rename from static/admin/assets/ReportPage-GPt5J1Db.js rename to static/admin/assets/ReportPage-BkIhdzJa.js index 3bc4f36..9ded76f 100644 --- a/static/admin/assets/ReportPage-GPt5J1Db.js +++ b/static/admin/assets/ReportPage-BkIhdzJa.js @@ -1 +1 @@ -import{q as Pe,r as Re,v as $e,x as Ce,y as Le,l as Me,A as Te}from"./vendor-element-CJoVtPsD.js";import{a as We,_ as Ie,f as Ee}from"./index-D8t2quK2.js";import{f as qe}from"./email-CqsrP_Ts.js";import{f as Ae,a as Ne,b as Be,c as ze}from"./tasks-DZnsc1fC.js";import{f as De}from"./system-In7Gh8x7.js";import{M as Ve}from"./MetricGrid-Cbhb9OGV.js";import{i as K,r,c as l,v as Fe,Y as Oe,aW as Ue,z as m,A as b,B as i,S as Ge,N as I,Q as g,R as Y,ak as Z,K as je,L as He,E as Qe}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ke(){const{data:E}=await We.get("/browser_pool/stats");return E}const Ye={class:"page-stack"},Ze={class:"report-hero"},Je={class:"hero-head"},Xe={class:"hero-main"},el={class:"hero-meta app-muted"},ll={key:0},al={key:1,class:"hero-dot"},tl={key:2},ul={class:"mobile-report"},sl={class:"mobile-module-head"},nl={class:"mobile-module-title"},ol={class:"mobile-module-desc app-muted"},rl={class:"mobile-metrics"},il={class:"mobile-metric-label app-muted"},cl={class:"mobile-metric-value"},vl=5e3,dl=2e4,_l={__name:"ReportPage",setup(E){const J=K("refreshStats",null),X=K("adminStats",null),x=r(!1),P=r(!1),p=r(""),R=r(null),o=r(null),n=r(null),_=r(null),d=r(null),w=r(null),h=r(null),c=r(null);r("running");function ee(){try{p.value=new Date().toLocaleString("zh-CN",{hour12:!1,timeZone:"Asia/Shanghai"})}catch{p.value=""}}function e(a){const t=Number(a);return Number.isFinite(t)?t:0}function le(a){const t=String(a??"").trim();if(!t)return 0;const s=t.endsWith("%")?t.slice(0,-1):t,u=Number(s);return!Number.isFinite(u)||u<0?0:u>1e3?1e3:u}function $(a){return`${Math.round(le(a))}%`}function ae(a){const t=String(a??"").trim();return!t||t==="manual"?"手动":t==="scheduled"?"系统定时":t==="batch"?"批量执行":t==="resumed"?"断点续跑":t.startsWith("user_scheduled:")?"用户定时":t}const q=l(()=>{const a=X?.value||{},t=e(o.value?.max_concurrent);return[{label:"总用户数",value:e(a.total_users),icon:Pe,tone:"blue"},{label:"今日注册",value:e(a.new_users_today),icon:Re,tone:"green"},{label:"近7天注册",value:e(a.new_users_7d),icon:$e,tone:"purple"},{label:"总账号数",value:e(a.total_accounts),icon:Ce,tone:"cyan"},{label:"VIP用户",value:e(a.vip_users),icon:Le,tone:"orange"},{label:"运行中任务",value:e(o.value?.running_count),icon:Me,tone:"green",sub:t?`并发上限 ${t}`:""},{label:"排队任务",value:e(o.value?.queuing_count),icon:Te,tone:"purple"}]}),v=l(()=>R.value?.today||{}),f=l(()=>R.value?.total||{});l(()=>o.value?.running||[]);const S=l(()=>o.value?.queuing||[]),te=l(()=>e(o.value?.running_count)),ue=l(()=>e(o.value?.queuing_count)),se=l(()=>{const a=h.value?.workers;return Array.isArray(a)?[...a].sort((t,s)=>e(t?.worker_id)-e(s?.worker_id)):[]}),A=l(()=>e(h.value?.total_workers)),C=l(()=>se.value.filter(a=>!!a?.has_browser).length),N=l(()=>e(h.value?.idle_workers)),B=l(()=>e(h.value?.queue_size)),L=l(()=>e(h.value?.active_workers)),z=l(()=>{const a=e(v.value.success_tasks),t=e(v.value.failed_tasks),s=a+t;return s>0?Math.round(a/s*1e3)/10:0}),M=l(()=>e(n.value?.success_rate));l(()=>[{label:"总任务",value:e(v.value.total_tasks),tone:"blue"},{label:"成功",value:e(v.value.success_tasks),tone:"green"},{label:"失败",value:e(v.value.failed_tasks),tone:"red"},{label:"浏览内容",value:e(v.value.total_items),tone:"purple"},{label:"查看附件",value:e(v.value.total_attachments),tone:"cyan"}]),l(()=>[{label:"总任务",value:e(f.value.total_tasks),tone:"blue"},{label:"成功",value:e(f.value.success_tasks),tone:"green"},{label:"失败",value:e(f.value.failed_tasks),tone:"red"},{label:"浏览内容",value:e(f.value.total_items),tone:"purple"},{label:"查看附件",value:e(f.value.total_attachments),tone:"cyan"}]),l(()=>[{label:"总发送",value:e(n.value?.total_sent),tone:"blue"},{label:"成功",value:e(n.value?.total_success),tone:"green"},{label:"失败",value:e(n.value?.total_failed),tone:"red"},{label:"成功率",value:`${M.value}%`,tone:"purple"}]),l(()=>[{label:"注册验证",value:e(n.value?.register_sent),tone:"cyan"},{label:"密码重置",value:e(n.value?.reset_sent),tone:"orange"},{label:"邮箱绑定",value:e(n.value?.bind_sent),tone:"purple"},{label:"任务完成",value:e(n.value?.task_complete_sent),tone:"green"}]),l(()=>[{label:"总反馈",value:e(_.value?.total),tone:"blue"},{label:"待处理",value:e(_.value?.pending),tone:"orange"},{label:"已回复",value:e(_.value?.replied),tone:"green"}]),l(()=>[{label:"总 Worker",value:A.value,tone:"blue"},{label:"活跃 Worker",value:C.value,tone:"green"},{label:"空闲 Worker",value:N.value,tone:"cyan"},{label:"忙碌 Worker",value:L.value,tone:"orange"},{label:"队列",value:B.value,tone:"purple"}]);const ne=l(()=>(c.value?.schedule_enabled??0)===1),oe=l(()=>c.value?.schedule_time||"-"),re=l(()=>c.value?.schedule_browse_type||"-"),ie=l(()=>String(c.value?.schedule_weekdays||"").trim());l(()=>{const a=ie.value;if(!a)return"";const t={1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"},s=a.split(",").map(u=>u.trim()).filter(Boolean);return s.length?s.map(u=>t[Number(u)]||u).join("、"):a});const ce=l(()=>(c.value?.proxy_enabled??0)===1);l(()=>c.value?.proxy_api_url||"");const D=l(()=>e(c.value?.proxy_expire_minutes)),T=l(()=>e(c.value?.max_concurrent_global)),ve=l(()=>e(c.value?.max_concurrent_per_account)),de=l(()=>e(c.value?.max_screenshot_concurrent)),_e=l(()=>{const a=e(o.value?.running_count),t=e(o.value?.queuing_count),s=e(o.value?.max_concurrent);return`运行中 ${a} / 排队 ${t} / 并发上限 ${s||T.value||"-"}`}),be=l(()=>q.value.map(a=>({label:a.label,value:a.sub?`${a.value}(${a.sub})`:a.value}))),fe=l(()=>[{label:"今日总任务",value:e(v.value.total_tasks)},{label:"今日成功",value:e(v.value.success_tasks)},{label:"今日失败",value:e(v.value.failed_tasks)},{label:"今日成功率",value:`${z.value}%`},{label:"累计任务",value:e(f.value.total_tasks)},{label:"累计成功",value:e(f.value.success_tasks)}]),me=l(()=>[{label:"运行中",value:te.value},{label:"排队中",value:ue.value},{label:"并发上限",value:e(o.value?.max_concurrent)||T.value||"-"},{label:"排队首条来源",value:ae(S.value[0]?.source)},{label:"排队首条状态",value:S.value[0]?.detail_status||S.value[0]?.status||"-"},{label:"最长等待",value:S.value[0]?.elapsed_display||"-"}]),pe=l(()=>[{label:"总发送",value:e(n.value?.total_sent)},{label:"成功",value:e(n.value?.total_success)},{label:"失败",value:e(n.value?.total_failed)},{label:"成功率",value:`${M.value}%`},{label:"注册验证",value:e(n.value?.register_sent)},{label:"重置密码",value:e(n.value?.reset_sent)}]),he=l(()=>[{label:"总反馈",value:e(_.value?.total)},{label:"待处理",value:e(_.value?.pending)},{label:"已回复",value:e(_.value?.replied)}]),ke=l(()=>[{label:"CPU",value:$(d.value?.cpu_percent)},{label:"内存",value:$(d.value?.memory_percent)},{label:"磁盘",value:$(d.value?.disk_percent)},{label:"容器状态",value:w.value?.status||"-"},{label:"容器名",value:w.value?.container_name||"-"},{label:"容器运行",value:w.value?.uptime||"-"}]),ge=l(()=>[{label:"总 Worker",value:A.value},{label:"活跃 Worker",value:C.value},{label:"忙碌 Worker",value:L.value},{label:"空闲 Worker",value:N.value},{label:"任务队列",value:B.value}]),ye=l(()=>[{label:"定时任务",value:ne.value?"启用":"关闭"},{label:"执行时间",value:oe.value||"-"},{label:"浏览类型",value:re.value||"-"},{label:"代理",value:ce.value?"启用":"关闭"},{label:"代理有效期",value:D.value?`${D.value} 分钟`:"-"},{label:"全局并发",value:T.value||"-"},{label:"单账号并发",value:ve.value||"-"},{label:"截图并发",value:de.value||"-"}]),we=l(()=>[{key:"overview",title:"平台概览",desc:p.value?`更新 ${p.value}`:"核心指标",tone:"blue",items:be.value},{key:"task",title:"任务概览",desc:e(v.value.total_tasks)>0?`今日成功率 ${z.value}%`:"今日暂无任务",tone:"purple",items:fe.value},{key:"queue",title:"队列监控",desc:_e.value,tone:"blue",items:me.value},{key:"email",title:"邮件报表",desc:`成功率 ${M.value}%`,tone:"cyan",items:pe.value},{key:"feedback",title:"反馈概览",desc:`待处理 ${e(_.value?.pending)} 条`,tone:"orange",items:he.value},{key:"resource",title:"系统资源",desc:d.value?.uptime?`运行 ${d.value.uptime}`:"运行状态获取中",tone:"green",items:ke.value},{key:"worker",title:"截图线程池",desc:`活跃 ${C.value} · 忙碌 ${L.value}`,tone:"cyan",items:ge.value},{key:"config",title:"配置概览",desc:"并发 / 代理 / 定时任务",tone:"red",items:ye.value}]);async function V(a={}){const t=a.showLoading??!0;if(!P.value){P.value=!0,t&&(x.value=!0);try{const[s,u,k,U,G,j,H,Q]=await Promise.allSettled([Ae(),Ne(),qe(),Ee(),Be(),ze(),Ke(),De()]);s.status==="fulfilled"&&(R.value=s.value),u.status==="fulfilled"&&(o.value=u.value),k.status==="fulfilled"&&(n.value=k.value),U.status==="fulfilled"&&(_.value=U.value),G.status==="fulfilled"&&(d.value=G.value),j.status==="fulfilled"&&(w.value=j.value),H.status==="fulfilled"&&(h.value=H.value),Q.status==="fulfilled"&&(c.value=Q.value),await J?.(),ee()}finally{P.value=!1,t&&(x.value=!1)}}}let y=null;function Se(){return typeof document>"u"?!1:document.visibilityState==="hidden"}function xe(){return Se()?dl:vl}function F(){y&&(clearTimeout(y),y=null)}function W(){F(),y=window.setTimeout(async()=>{y=null,await V({showLoading:!1}).catch(()=>{}),W()},xe())}function O(){W()}return Fe(()=>{V({showLoading:!1}).catch(()=>{}).finally(()=>{W()}),window.addEventListener("visibilitychange",O)}),Oe(()=>{F(),window.removeEventListener("visibilitychange",O)}),(a,t)=>{const s=Ue("el-card");return b(),m("div",Ye,[i("section",Ze,[i("div",Je,[i("div",Xe,[t[0]||(t[0]=i("h2",null,"报表中心",-1)),i("div",el,[p.value?(b(),m("span",ll,"更新时间:"+g(p.value),1)):I("",!0),d.value?.uptime?(b(),m("span",al,"·")):I("",!0),d.value?.uptime?(b(),m("span",tl,"运行 "+g(d.value.uptime),1)):I("",!0)])])]),Ge(Ve,{class:"hero-overview-grid",items:q.value,loading:x.value,"min-width":165},null,8,["items","loading"])]),i("section",ul,[(b(!0),m(Y,null,Z(we.value,u=>(b(),je(s,{key:u.key,shadow:"never",class:Qe(["mobile-module-card",`mobile-tone-${u.tone}`]),"body-style":{padding:"12px"}},{default:He(()=>[i("div",sl,[i("div",nl,g(u.title),1),i("div",ol,g(u.desc),1)]),i("div",rl,[(b(!0),m(Y,null,Z(u.items,k=>(b(),m("div",{key:`${u.key}-${k.label}`,class:"mobile-metric-item"},[i("div",il,g(k.label),1),i("div",cl,g(k.value),1)]))),128))])]),_:2},1032,["class"]))),128))])])}}},Sl=Ie(_l,[["__scopeId","data-v-59b81fef"]]);export{Sl as default}; +import{q as Pe,r as Re,v as $e,x as Ce,y as Le,l as Me,A as Te}from"./vendor-element-CJoVtPsD.js";import{a as We,_ as Ie,f as Ee}from"./index-iyjFO6XY.js";import{f as qe}from"./email-BYiWDIoy.js";import{f as Ae,a as Ne,b as Be,c as ze}from"./tasks-BZsqSMnk.js";import{f as De}from"./system-Bvj77zeB.js";import{M as Ve}from"./MetricGrid-D-x_tNsK.js";import{i as K,r,c as l,v as Fe,Y as Oe,aW as Ue,z as m,A as b,B as i,S as Ge,N as I,Q as g,R as Y,ak as Z,K as je,L as He,E as Qe}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ke(){const{data:E}=await We.get("/browser_pool/stats");return E}const Ye={class:"page-stack"},Ze={class:"report-hero"},Je={class:"hero-head"},Xe={class:"hero-main"},el={class:"hero-meta app-muted"},ll={key:0},al={key:1,class:"hero-dot"},tl={key:2},ul={class:"mobile-report"},sl={class:"mobile-module-head"},nl={class:"mobile-module-title"},ol={class:"mobile-module-desc app-muted"},rl={class:"mobile-metrics"},il={class:"mobile-metric-label app-muted"},cl={class:"mobile-metric-value"},vl=5e3,dl=2e4,_l={__name:"ReportPage",setup(E){const J=K("refreshStats",null),X=K("adminStats",null),x=r(!1),P=r(!1),p=r(""),R=r(null),o=r(null),n=r(null),_=r(null),d=r(null),w=r(null),h=r(null),c=r(null);r("running");function ee(){try{p.value=new Date().toLocaleString("zh-CN",{hour12:!1,timeZone:"Asia/Shanghai"})}catch{p.value=""}}function e(a){const t=Number(a);return Number.isFinite(t)?t:0}function le(a){const t=String(a??"").trim();if(!t)return 0;const s=t.endsWith("%")?t.slice(0,-1):t,u=Number(s);return!Number.isFinite(u)||u<0?0:u>1e3?1e3:u}function $(a){return`${Math.round(le(a))}%`}function ae(a){const t=String(a??"").trim();return!t||t==="manual"?"手动":t==="scheduled"?"系统定时":t==="batch"?"批量执行":t==="resumed"?"断点续跑":t.startsWith("user_scheduled:")?"用户定时":t}const q=l(()=>{const a=X?.value||{},t=e(o.value?.max_concurrent);return[{label:"总用户数",value:e(a.total_users),icon:Pe,tone:"blue"},{label:"今日注册",value:e(a.new_users_today),icon:Re,tone:"green"},{label:"近7天注册",value:e(a.new_users_7d),icon:$e,tone:"purple"},{label:"总账号数",value:e(a.total_accounts),icon:Ce,tone:"cyan"},{label:"VIP用户",value:e(a.vip_users),icon:Le,tone:"orange"},{label:"运行中任务",value:e(o.value?.running_count),icon:Me,tone:"green",sub:t?`并发上限 ${t}`:""},{label:"排队任务",value:e(o.value?.queuing_count),icon:Te,tone:"purple"}]}),v=l(()=>R.value?.today||{}),f=l(()=>R.value?.total||{});l(()=>o.value?.running||[]);const S=l(()=>o.value?.queuing||[]),te=l(()=>e(o.value?.running_count)),ue=l(()=>e(o.value?.queuing_count)),se=l(()=>{const a=h.value?.workers;return Array.isArray(a)?[...a].sort((t,s)=>e(t?.worker_id)-e(s?.worker_id)):[]}),A=l(()=>e(h.value?.total_workers)),C=l(()=>se.value.filter(a=>!!a?.has_browser).length),N=l(()=>e(h.value?.idle_workers)),B=l(()=>e(h.value?.queue_size)),L=l(()=>e(h.value?.active_workers)),z=l(()=>{const a=e(v.value.success_tasks),t=e(v.value.failed_tasks),s=a+t;return s>0?Math.round(a/s*1e3)/10:0}),M=l(()=>e(n.value?.success_rate));l(()=>[{label:"总任务",value:e(v.value.total_tasks),tone:"blue"},{label:"成功",value:e(v.value.success_tasks),tone:"green"},{label:"失败",value:e(v.value.failed_tasks),tone:"red"},{label:"浏览内容",value:e(v.value.total_items),tone:"purple"},{label:"查看附件",value:e(v.value.total_attachments),tone:"cyan"}]),l(()=>[{label:"总任务",value:e(f.value.total_tasks),tone:"blue"},{label:"成功",value:e(f.value.success_tasks),tone:"green"},{label:"失败",value:e(f.value.failed_tasks),tone:"red"},{label:"浏览内容",value:e(f.value.total_items),tone:"purple"},{label:"查看附件",value:e(f.value.total_attachments),tone:"cyan"}]),l(()=>[{label:"总发送",value:e(n.value?.total_sent),tone:"blue"},{label:"成功",value:e(n.value?.total_success),tone:"green"},{label:"失败",value:e(n.value?.total_failed),tone:"red"},{label:"成功率",value:`${M.value}%`,tone:"purple"}]),l(()=>[{label:"注册验证",value:e(n.value?.register_sent),tone:"cyan"},{label:"密码重置",value:e(n.value?.reset_sent),tone:"orange"},{label:"邮箱绑定",value:e(n.value?.bind_sent),tone:"purple"},{label:"任务完成",value:e(n.value?.task_complete_sent),tone:"green"}]),l(()=>[{label:"总反馈",value:e(_.value?.total),tone:"blue"},{label:"待处理",value:e(_.value?.pending),tone:"orange"},{label:"已回复",value:e(_.value?.replied),tone:"green"}]),l(()=>[{label:"总 Worker",value:A.value,tone:"blue"},{label:"活跃 Worker",value:C.value,tone:"green"},{label:"空闲 Worker",value:N.value,tone:"cyan"},{label:"忙碌 Worker",value:L.value,tone:"orange"},{label:"队列",value:B.value,tone:"purple"}]);const ne=l(()=>(c.value?.schedule_enabled??0)===1),oe=l(()=>c.value?.schedule_time||"-"),re=l(()=>c.value?.schedule_browse_type||"-"),ie=l(()=>String(c.value?.schedule_weekdays||"").trim());l(()=>{const a=ie.value;if(!a)return"";const t={1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"},s=a.split(",").map(u=>u.trim()).filter(Boolean);return s.length?s.map(u=>t[Number(u)]||u).join("、"):a});const ce=l(()=>(c.value?.proxy_enabled??0)===1);l(()=>c.value?.proxy_api_url||"");const D=l(()=>e(c.value?.proxy_expire_minutes)),T=l(()=>e(c.value?.max_concurrent_global)),ve=l(()=>e(c.value?.max_concurrent_per_account)),de=l(()=>e(c.value?.max_screenshot_concurrent)),_e=l(()=>{const a=e(o.value?.running_count),t=e(o.value?.queuing_count),s=e(o.value?.max_concurrent);return`运行中 ${a} / 排队 ${t} / 并发上限 ${s||T.value||"-"}`}),be=l(()=>q.value.map(a=>({label:a.label,value:a.sub?`${a.value}(${a.sub})`:a.value}))),fe=l(()=>[{label:"今日总任务",value:e(v.value.total_tasks)},{label:"今日成功",value:e(v.value.success_tasks)},{label:"今日失败",value:e(v.value.failed_tasks)},{label:"今日成功率",value:`${z.value}%`},{label:"累计任务",value:e(f.value.total_tasks)},{label:"累计成功",value:e(f.value.success_tasks)}]),me=l(()=>[{label:"运行中",value:te.value},{label:"排队中",value:ue.value},{label:"并发上限",value:e(o.value?.max_concurrent)||T.value||"-"},{label:"排队首条来源",value:ae(S.value[0]?.source)},{label:"排队首条状态",value:S.value[0]?.detail_status||S.value[0]?.status||"-"},{label:"最长等待",value:S.value[0]?.elapsed_display||"-"}]),pe=l(()=>[{label:"总发送",value:e(n.value?.total_sent)},{label:"成功",value:e(n.value?.total_success)},{label:"失败",value:e(n.value?.total_failed)},{label:"成功率",value:`${M.value}%`},{label:"注册验证",value:e(n.value?.register_sent)},{label:"重置密码",value:e(n.value?.reset_sent)}]),he=l(()=>[{label:"总反馈",value:e(_.value?.total)},{label:"待处理",value:e(_.value?.pending)},{label:"已回复",value:e(_.value?.replied)}]),ke=l(()=>[{label:"CPU",value:$(d.value?.cpu_percent)},{label:"内存",value:$(d.value?.memory_percent)},{label:"磁盘",value:$(d.value?.disk_percent)},{label:"容器状态",value:w.value?.status||"-"},{label:"容器名",value:w.value?.container_name||"-"},{label:"容器运行",value:w.value?.uptime||"-"}]),ge=l(()=>[{label:"总 Worker",value:A.value},{label:"活跃 Worker",value:C.value},{label:"忙碌 Worker",value:L.value},{label:"空闲 Worker",value:N.value},{label:"任务队列",value:B.value}]),ye=l(()=>[{label:"定时任务",value:ne.value?"启用":"关闭"},{label:"执行时间",value:oe.value||"-"},{label:"浏览类型",value:re.value||"-"},{label:"代理",value:ce.value?"启用":"关闭"},{label:"代理有效期",value:D.value?`${D.value} 分钟`:"-"},{label:"全局并发",value:T.value||"-"},{label:"单账号并发",value:ve.value||"-"},{label:"截图并发",value:de.value||"-"}]),we=l(()=>[{key:"overview",title:"平台概览",desc:p.value?`更新 ${p.value}`:"核心指标",tone:"blue",items:be.value},{key:"task",title:"任务概览",desc:e(v.value.total_tasks)>0?`今日成功率 ${z.value}%`:"今日暂无任务",tone:"purple",items:fe.value},{key:"queue",title:"队列监控",desc:_e.value,tone:"blue",items:me.value},{key:"email",title:"邮件报表",desc:`成功率 ${M.value}%`,tone:"cyan",items:pe.value},{key:"feedback",title:"反馈概览",desc:`待处理 ${e(_.value?.pending)} 条`,tone:"orange",items:he.value},{key:"resource",title:"系统资源",desc:d.value?.uptime?`运行 ${d.value.uptime}`:"运行状态获取中",tone:"green",items:ke.value},{key:"worker",title:"截图线程池",desc:`活跃 ${C.value} · 忙碌 ${L.value}`,tone:"cyan",items:ge.value},{key:"config",title:"配置概览",desc:"并发 / 代理 / 定时任务",tone:"red",items:ye.value}]);async function V(a={}){const t=a.showLoading??!0;if(!P.value){P.value=!0,t&&(x.value=!0);try{const[s,u,k,U,G,j,H,Q]=await Promise.allSettled([Ae(),Ne(),qe(),Ee(),Be(),ze(),Ke(),De()]);s.status==="fulfilled"&&(R.value=s.value),u.status==="fulfilled"&&(o.value=u.value),k.status==="fulfilled"&&(n.value=k.value),U.status==="fulfilled"&&(_.value=U.value),G.status==="fulfilled"&&(d.value=G.value),j.status==="fulfilled"&&(w.value=j.value),H.status==="fulfilled"&&(h.value=H.value),Q.status==="fulfilled"&&(c.value=Q.value),await J?.(),ee()}finally{P.value=!1,t&&(x.value=!1)}}}let y=null;function Se(){return typeof document>"u"?!1:document.visibilityState==="hidden"}function xe(){return Se()?dl:vl}function F(){y&&(clearTimeout(y),y=null)}function W(){F(),y=window.setTimeout(async()=>{y=null,await V({showLoading:!1}).catch(()=>{}),W()},xe())}function O(){W()}return Fe(()=>{V({showLoading:!1}).catch(()=>{}).finally(()=>{W()}),window.addEventListener("visibilitychange",O)}),Oe(()=>{F(),window.removeEventListener("visibilitychange",O)}),(a,t)=>{const s=Ue("el-card");return b(),m("div",Ye,[i("section",Ze,[i("div",Je,[i("div",Xe,[t[0]||(t[0]=i("h2",null,"报表中心",-1)),i("div",el,[p.value?(b(),m("span",ll,"更新时间:"+g(p.value),1)):I("",!0),d.value?.uptime?(b(),m("span",al,"·")):I("",!0),d.value?.uptime?(b(),m("span",tl,"运行 "+g(d.value.uptime),1)):I("",!0)])])]),Ge(Ve,{class:"hero-overview-grid",items:q.value,loading:x.value,"min-width":165},null,8,["items","loading"])]),i("section",ul,[(b(!0),m(Y,null,Z(we.value,u=>(b(),je(s,{key:u.key,shadow:"never",class:Qe(["mobile-module-card",`mobile-tone-${u.tone}`]),"body-style":{padding:"12px"}},{default:He(()=>[i("div",sl,[i("div",nl,g(u.title),1),i("div",ol,g(u.desc),1)]),i("div",rl,[(b(!0),m(Y,null,Z(u.items,k=>(b(),m("div",{key:`${u.key}-${k.label}`,class:"mobile-metric-item"},[i("div",il,g(k.label),1),i("div",cl,g(k.value),1)]))),128))])]),_:2},1032,["class"]))),128))])])}}},Sl=Ie(_l,[["__scopeId","data-v-59b81fef"]]);export{Sl as default}; diff --git a/static/admin/assets/SecurityPage-BWFFA3z9.js b/static/admin/assets/SecurityPage-Ay9lQdJs.js similarity index 99% rename from static/admin/assets/SecurityPage-BWFFA3z9.js rename to static/admin/assets/SecurityPage-Ay9lQdJs.js index 5d398a8..ec4a159 100644 --- a/static/admin/assets/SecurityPage-BWFFA3z9.js +++ b/static/admin/assets/SecurityPage-Ay9lQdJs.js @@ -1,4 +1,4 @@ -import{a as g,_ as ze}from"./index-D8t2quK2.js";import{M as qe}from"./MetricGrid-Cbhb9OGV.js";import{E as ee,f as w}from"./vendor-element-CJoVtPsD.js";import{r as d,c as oe,v as Ee,aW as v,b7 as Ae,z as T,A as c,B as p,S as a,L as l,P as i,R as Ke,ak as Oe,K as b,M as te,Q as f,N as ue}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ge(){const{data:u}=await g.get("/admin/security/dashboard");return u}async function He(u){const{data:m}=await g.get("/admin/security/threats",{params:u});return m}async function Qe(){const{data:u}=await g.get("/admin/security/banned-ips");return u}async function We(){const{data:u}=await g.get("/admin/security/banned-users");return u}async function Je(u){const{data:m}=await g.post("/admin/security/ban-ip",u);return m}async function Xe(u){const{data:m}=await g.post("/admin/security/unban-ip",{ip:u});return m}async function Ye(u){const{data:m}=await g.post("/admin/security/ban-user",u);return m}async function Ze(u){const{data:m}=await g.post("/admin/security/unban-user",{user_id:u});return m}async function et(u){const m=encodeURIComponent(String(u||"").trim()),{data:V}=await g.get(`/admin/security/ip-risk/${m}`);return V}async function tt(u){const{data:m}=await g.post("/admin/security/ip-risk/clear",{ip:u});return m}async function at(u){const m=encodeURIComponent(String(u||"").trim()),{data:V}=await g.get(`/admin/security/user-risk/${m}`);return V}async function lt(){const{data:u}=await g.post("/admin/security/cleanup",{});return u}const nt={class:"page-stack"},it={class:"app-page-title"},st={class:"toolbar"},ot={class:"filters"},ut={class:"table-wrap"},rt={key:1},dt={key:1},pt={class:"mono ellipsis"},ct={class:"ellipsis"},ft={class:"pagination"},mt={class:"page-hint app-muted"},vt={class:"toolbar"},_t={class:"table-wrap"},yt={class:"table-wrap"},bt={class:"filters"},gt={class:"filters"},kt={class:"risk-head"},ht={class:"risk-title"},wt={key:0},It={key:1},Vt={class:"toolbar"},xt={class:"table-wrap"},Ct={class:"mono ellipsis"},St={class:"ellipsis"},Pt={class:"dialog-actions"},re=20,Tt={__name:"SecurityPage",setup(u){const m=d("threats"),V=d(!1),j=d(null),ae=d(!1),z=d([]),q=d(0),C=d(1),U=d(""),B=d(""),$=d(!1),de=d([]),pe=d([]),ce=d("ips"),S=d(!1),R=d(!1),o=d({kind:"ip",ip:"",user_id:"",reason:"",duration_hours:24,permanent:!1}),E=d("ip"),k=d(!1),A=d(""),K=d(""),_=d(null),h=d(""),Ie=["sql_injection","xss","path_traversal","command_injection","ssrf","scanner","bruteforce","csrf","xxe","file_upload"];function le(n){const e=Number(n);return Number.isFinite(e)?e:0}function N(n){const e=Number(n||0);return e>=80?{label:"高",type:"danger"}:e>=50?{label:"中",type:"warning"}:{label:"低",type:"success"}}function fe(n){const e=String(n||"").trim();return e||"永久"}function me(n){const e=[];return n?.field_name&&e.push(`字段: ${n.field_name}`),n?.rule&&e.push(`规则: ${n.rule}`),n?.matched&&e.push(`匹配: ${n.matched}`),n?.value_preview&&e.push(`值: ${n.value_preview}`),e.length?e.join(" · "):"-"}function O(n){const e=String(n?.request_method||"").trim(),s=String(n?.request_path||"").trim();return`${e} ${s}`.trim()||"-"}const Ve=oe(()=>{const n=new Set(Ie),e=j.value?.recent_threat_events||[];for(const s of e){const y=String(s?.threat_type||"").trim();y&&n.add(y)}for(const s of z.value||[]){const y=String(s?.threat_type||"").trim();y&&n.add(y)}return Array.from(n).sort((s,y)=>s.localeCompare(y)).map(s=>({label:s,value:s}))}),xe=oe(()=>{const n=j.value||{};return[{key:"threat_events_24h",label:"最近24小时威胁事件",value:le(n.threat_events_24h),tone:"red",hint:"用于衡量当前攻击面活跃度"},{key:"banned_ip_count",label:"当前封禁 IP 数",value:le(n.banned_ip_count),tone:"orange",hint:"自动与人工封禁总量"},{key:"banned_user_count",label:"当前封禁用户数",value:le(n.banned_user_count),tone:"purple",hint:"高风险账户拦截情况"}]}),Ce=oe(()=>Math.max(1,Math.ceil((q.value||0)/re)));async function D(){V.value=!0;try{j.value=await Ge()}catch{j.value=null}finally{V.value=!1}}async function G(){ae.value=!0;try{const n={page:C.value,per_page:re};U.value&&(n.event_type=U.value),B.value&&(n.severity=B.value);const e=await He(n);z.value=e?.items||[],q.value=e?.total||0}catch{z.value=[],q.value=0}finally{ae.value=!1}}async function F(){if(!$.value){$.value=!0;try{const[n,e]=await Promise.allSettled([Qe(),We()]);de.value=n.status==="fulfilled"?n.value?.items||[]:[],pe.value=e.status==="fulfilled"?e.value?.items||[]:[]}finally{$.value=!1}}}async function ve(){await Promise.allSettled([D(),G(),F()])}function Se(){C.value=1,G()}function Pe(){U.value="",B.value="",C.value=1,G()}function _e(){o.value={kind:"ip",ip:"",user_id:"",reason:"",duration_hours:24,permanent:!1}}function H(n="ip",e={}){_e(),o.value.kind=n==="user"?"user":"ip",o.value.kind==="ip"?o.value.ip=String(e.ip||"").trim():o.value.user_id=String(e.user_id||"").trim(),e.reason&&(o.value.reason=String(e.reason||"").trim()),S.value=!0}async function Te(){const n=o.value.kind,e=String(o.value.reason||"").trim(),s=!!o.value.permanent,y=Number(o.value.duration_hours||24);if(!e){w.error("原因不能为空");return}if(n==="ip"){const I=String(o.value.ip||"").trim();if(!I){w.error("IP不能为空");return}R.value=!0;try{await Je({ip:I,reason:e,duration_hours:y,permanent:s}),w.success("IP已封禁"),S.value=!1,await Promise.allSettled([D(),F()])}catch{}finally{R.value=!1}return}const W=String(o.value.user_id||"").trim(),r=Number.parseInt(W,10);if(!Number.isFinite(r)){w.error("用户ID无效");return}R.value=!0;try{await Ye({user_id:r,reason:e,duration_hours:y,permanent:s}),w.success("用户已封禁"),S.value=!1,await Promise.allSettled([D(),F()])}catch{}finally{R.value=!1}}async function ye(n){const e=String(n||"").trim();if(e){try{await ee.confirm(`确定解除对 IP ${e} 的封禁吗?`,"解除封禁",{confirmButtonText:"解除",cancelButtonText:"取消",type:"warning"})}catch{return}try{await Xe(e),w.success("已解除IP封禁"),await Promise.allSettled([D(),F()])}catch{}}}async function be(n){const e=Number.parseInt(String(n||"").trim(),10);if(Number.isFinite(e)){try{await ee.confirm(`确定解除对 用户ID ${e} 的封禁吗?`,"解除封禁",{confirmButtonText:"解除",cancelButtonText:"取消",type:"warning"})}catch{return}try{await Ze(e),w.success("已解除用户封禁"),await Promise.allSettled([D(),F()])}catch{}}}function ge(n){const e=String(n||"").trim();e&&(m.value="risk",E.value="ip",A.value=e,Q())}function ke(n){const e=String(n||"").trim();e&&(m.value="risk",E.value="user",K.value=e,ne())}async function Q(){const n=String(A.value||"").trim();if(!n){w.error("请输入IP");return}k.value=!0;try{_.value=await et(n),h.value="ip"}catch{_.value=null,h.value=""}finally{k.value=!1}}async function ne(){const n=String(K.value||"").trim(),e=Number.parseInt(n,10);if(!Number.isFinite(e)){w.error("请输入有效的用户ID");return}k.value=!0;try{_.value=await at(e),h.value="user"}catch{_.value=null,h.value=""}finally{k.value=!1}}function Ue(){!_.value||!h.value||(h.value==="ip"?H("ip",{ip:_.value?.ip,reason:"风险查询手动封禁"}):H("user",{user_id:_.value?.user_id,reason:"风险查询手动封禁"}))}async function Be(){!_.value||!h.value||(h.value==="ip"?(await ye(_.value?.ip),await Q()):(await be(_.value?.user_id),await ne()))}async function $e(){if(h.value!=="ip")return;const n=String(_.value?.ip||"").trim();if(n){try{await ee.confirm(`确定清除 IP ${n} 的风险分吗? +import{a as g,_ as ze}from"./index-iyjFO6XY.js";import{M as qe}from"./MetricGrid-D-x_tNsK.js";import{E as ee,f as w}from"./vendor-element-CJoVtPsD.js";import{r as d,c as oe,v as Ee,aW as v,b7 as Ae,z as T,A as c,B as p,S as a,L as l,P as i,R as Ke,ak as Oe,K as b,M as te,Q as f,N as ue}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function Ge(){const{data:u}=await g.get("/admin/security/dashboard");return u}async function He(u){const{data:m}=await g.get("/admin/security/threats",{params:u});return m}async function Qe(){const{data:u}=await g.get("/admin/security/banned-ips");return u}async function We(){const{data:u}=await g.get("/admin/security/banned-users");return u}async function Je(u){const{data:m}=await g.post("/admin/security/ban-ip",u);return m}async function Xe(u){const{data:m}=await g.post("/admin/security/unban-ip",{ip:u});return m}async function Ye(u){const{data:m}=await g.post("/admin/security/ban-user",u);return m}async function Ze(u){const{data:m}=await g.post("/admin/security/unban-user",{user_id:u});return m}async function et(u){const m=encodeURIComponent(String(u||"").trim()),{data:V}=await g.get(`/admin/security/ip-risk/${m}`);return V}async function tt(u){const{data:m}=await g.post("/admin/security/ip-risk/clear",{ip:u});return m}async function at(u){const m=encodeURIComponent(String(u||"").trim()),{data:V}=await g.get(`/admin/security/user-risk/${m}`);return V}async function lt(){const{data:u}=await g.post("/admin/security/cleanup",{});return u}const nt={class:"page-stack"},it={class:"app-page-title"},st={class:"toolbar"},ot={class:"filters"},ut={class:"table-wrap"},rt={key:1},dt={key:1},pt={class:"mono ellipsis"},ct={class:"ellipsis"},ft={class:"pagination"},mt={class:"page-hint app-muted"},vt={class:"toolbar"},_t={class:"table-wrap"},yt={class:"table-wrap"},bt={class:"filters"},gt={class:"filters"},kt={class:"risk-head"},ht={class:"risk-title"},wt={key:0},It={key:1},Vt={class:"toolbar"},xt={class:"table-wrap"},Ct={class:"mono ellipsis"},St={class:"ellipsis"},Pt={class:"dialog-actions"},re=20,Tt={__name:"SecurityPage",setup(u){const m=d("threats"),V=d(!1),j=d(null),ae=d(!1),z=d([]),q=d(0),C=d(1),U=d(""),B=d(""),$=d(!1),de=d([]),pe=d([]),ce=d("ips"),S=d(!1),R=d(!1),o=d({kind:"ip",ip:"",user_id:"",reason:"",duration_hours:24,permanent:!1}),E=d("ip"),k=d(!1),A=d(""),K=d(""),_=d(null),h=d(""),Ie=["sql_injection","xss","path_traversal","command_injection","ssrf","scanner","bruteforce","csrf","xxe","file_upload"];function le(n){const e=Number(n);return Number.isFinite(e)?e:0}function N(n){const e=Number(n||0);return e>=80?{label:"高",type:"danger"}:e>=50?{label:"中",type:"warning"}:{label:"低",type:"success"}}function fe(n){const e=String(n||"").trim();return e||"永久"}function me(n){const e=[];return n?.field_name&&e.push(`字段: ${n.field_name}`),n?.rule&&e.push(`规则: ${n.rule}`),n?.matched&&e.push(`匹配: ${n.matched}`),n?.value_preview&&e.push(`值: ${n.value_preview}`),e.length?e.join(" · "):"-"}function O(n){const e=String(n?.request_method||"").trim(),s=String(n?.request_path||"").trim();return`${e} ${s}`.trim()||"-"}const Ve=oe(()=>{const n=new Set(Ie),e=j.value?.recent_threat_events||[];for(const s of e){const y=String(s?.threat_type||"").trim();y&&n.add(y)}for(const s of z.value||[]){const y=String(s?.threat_type||"").trim();y&&n.add(y)}return Array.from(n).sort((s,y)=>s.localeCompare(y)).map(s=>({label:s,value:s}))}),xe=oe(()=>{const n=j.value||{};return[{key:"threat_events_24h",label:"最近24小时威胁事件",value:le(n.threat_events_24h),tone:"red",hint:"用于衡量当前攻击面活跃度"},{key:"banned_ip_count",label:"当前封禁 IP 数",value:le(n.banned_ip_count),tone:"orange",hint:"自动与人工封禁总量"},{key:"banned_user_count",label:"当前封禁用户数",value:le(n.banned_user_count),tone:"purple",hint:"高风险账户拦截情况"}]}),Ce=oe(()=>Math.max(1,Math.ceil((q.value||0)/re)));async function D(){V.value=!0;try{j.value=await Ge()}catch{j.value=null}finally{V.value=!1}}async function G(){ae.value=!0;try{const n={page:C.value,per_page:re};U.value&&(n.event_type=U.value),B.value&&(n.severity=B.value);const e=await He(n);z.value=e?.items||[],q.value=e?.total||0}catch{z.value=[],q.value=0}finally{ae.value=!1}}async function F(){if(!$.value){$.value=!0;try{const[n,e]=await Promise.allSettled([Qe(),We()]);de.value=n.status==="fulfilled"?n.value?.items||[]:[],pe.value=e.status==="fulfilled"?e.value?.items||[]:[]}finally{$.value=!1}}}async function ve(){await Promise.allSettled([D(),G(),F()])}function Se(){C.value=1,G()}function Pe(){U.value="",B.value="",C.value=1,G()}function _e(){o.value={kind:"ip",ip:"",user_id:"",reason:"",duration_hours:24,permanent:!1}}function H(n="ip",e={}){_e(),o.value.kind=n==="user"?"user":"ip",o.value.kind==="ip"?o.value.ip=String(e.ip||"").trim():o.value.user_id=String(e.user_id||"").trim(),e.reason&&(o.value.reason=String(e.reason||"").trim()),S.value=!0}async function Te(){const n=o.value.kind,e=String(o.value.reason||"").trim(),s=!!o.value.permanent,y=Number(o.value.duration_hours||24);if(!e){w.error("原因不能为空");return}if(n==="ip"){const I=String(o.value.ip||"").trim();if(!I){w.error("IP不能为空");return}R.value=!0;try{await Je({ip:I,reason:e,duration_hours:y,permanent:s}),w.success("IP已封禁"),S.value=!1,await Promise.allSettled([D(),F()])}catch{}finally{R.value=!1}return}const W=String(o.value.user_id||"").trim(),r=Number.parseInt(W,10);if(!Number.isFinite(r)){w.error("用户ID无效");return}R.value=!0;try{await Ye({user_id:r,reason:e,duration_hours:y,permanent:s}),w.success("用户已封禁"),S.value=!1,await Promise.allSettled([D(),F()])}catch{}finally{R.value=!1}}async function ye(n){const e=String(n||"").trim();if(e){try{await ee.confirm(`确定解除对 IP ${e} 的封禁吗?`,"解除封禁",{confirmButtonText:"解除",cancelButtonText:"取消",type:"warning"})}catch{return}try{await Xe(e),w.success("已解除IP封禁"),await Promise.allSettled([D(),F()])}catch{}}}async function be(n){const e=Number.parseInt(String(n||"").trim(),10);if(Number.isFinite(e)){try{await ee.confirm(`确定解除对 用户ID ${e} 的封禁吗?`,"解除封禁",{confirmButtonText:"解除",cancelButtonText:"取消",type:"warning"})}catch{return}try{await Ze(e),w.success("已解除用户封禁"),await Promise.allSettled([D(),F()])}catch{}}}function ge(n){const e=String(n||"").trim();e&&(m.value="risk",E.value="ip",A.value=e,Q())}function ke(n){const e=String(n||"").trim();e&&(m.value="risk",E.value="user",K.value=e,ne())}async function Q(){const n=String(A.value||"").trim();if(!n){w.error("请输入IP");return}k.value=!0;try{_.value=await et(n),h.value="ip"}catch{_.value=null,h.value=""}finally{k.value=!1}}async function ne(){const n=String(K.value||"").trim(),e=Number.parseInt(n,10);if(!Number.isFinite(e)){w.error("请输入有效的用户ID");return}k.value=!0;try{_.value=await at(e),h.value="user"}catch{_.value=null,h.value=""}finally{k.value=!1}}function Ue(){!_.value||!h.value||(h.value==="ip"?H("ip",{ip:_.value?.ip,reason:"风险查询手动封禁"}):H("user",{user_id:_.value?.user_id,reason:"风险查询手动封禁"}))}async function Be(){!_.value||!h.value||(h.value==="ip"?(await ye(_.value?.ip),await Q()):(await be(_.value?.user_id),await ne()))}async function $e(){if(h.value!=="ip")return;const n=String(_.value?.ip||"").trim();if(n){try{await ee.confirm(`确定清除 IP ${n} 的风险分吗? 清除风险分不会删除威胁历史,也不会解除封禁。`,"清除风险分",{confirmButtonText:"清除",cancelButtonText:"取消",type:"warning"})}catch{return}if(!k.value){k.value=!0;try{await tt(n),w.success("IP风险分已清零")}catch{}finally{k.value=!1}await Q()}}}const ie=d(!1);async function Re(){try{await ee.confirm(`确定清理过期封禁记录,并衰减风险分吗? diff --git a/static/admin/assets/SettingsPage-3cNfdgGx.js b/static/admin/assets/SettingsPage-D1k6_4Nn.js similarity index 98% rename from static/admin/assets/SettingsPage-3cNfdgGx.js rename to static/admin/assets/SettingsPage-D1k6_4Nn.js index d00edcd..baba9b3 100644 --- a/static/admin/assets/SettingsPage-3cNfdgGx.js +++ b/static/admin/assets/SettingsPage-D1k6_4Nn.js @@ -1 +1 @@ -import{a as m,_ as h}from"./index-D8t2quK2.js";import{f as u,E as x}from"./vendor-element-CJoVtPsD.js";import{r as p,aW as i,z as T,A as P,B as r,S as a,L as o,P as b}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function S(l){const{data:s}=await m.put("/admin/username",{new_username:l});return s}async function A(l){const{data:s}=await m.put("/admin/password",{new_password:l});return s}async function C(){const{data:l}=await m.post("/logout");return l}const E={class:"page-stack"},U={__name:"SettingsPage",setup(l){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await C()}catch{}finally{window.location.href="/yuyx"}}async function B(){const t=s.value.trim();if(!t){u.error("请输入新用户名");return}try{await x.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),u.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function V(){const t=d.value;if(!t){u.error("请输入新密码");return}const e=k(t);if(!e.ok){u.error(e.message);return}try{await x.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await A(t),u.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=i("el-input"),v=i("el-form-item"),w=i("el-form"),y=i("el-button"),_=i("el-card");return P(),T("div",E,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新用户名"},{default:o(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:B},{default:o(()=>[...e[2]||(e[2]=[b("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新密码"},{default:o(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:o(()=>[...e[4]||(e[4]=[b("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码(至少8位且包含字母与数字)。",-1))]),_:1})])}}},W=h(U,[["__scopeId","data-v-83d3840a"]]);export{W as default}; +import{a as m,_ as h}from"./index-iyjFO6XY.js";import{f as u,E as x}from"./vendor-element-CJoVtPsD.js";import{r as p,aW as i,z as T,A as P,B as r,S as a,L as o,P as b}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function S(l){const{data:s}=await m.put("/admin/username",{new_username:l});return s}async function A(l){const{data:s}=await m.put("/admin/password",{new_password:l});return s}async function C(){const{data:l}=await m.post("/logout");return l}const E={class:"page-stack"},U={__name:"SettingsPage",setup(l){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await C()}catch{}finally{window.location.href="/yuyx"}}async function B(){const t=s.value.trim();if(!t){u.error("请输入新用户名");return}try{await x.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),u.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function V(){const t=d.value;if(!t){u.error("请输入新密码");return}const e=k(t);if(!e.ok){u.error(e.message);return}try{await x.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await A(t),u.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=i("el-input"),v=i("el-form-item"),w=i("el-form"),y=i("el-button"),_=i("el-card");return P(),T("div",E,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新用户名"},{default:o(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:B},{default:o(()=>[...e[2]||(e[2]=[b("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:o(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(w,{"label-width":"120px"},{default:o(()=>[a(v,{label:"新密码"},{default:o(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:o(()=>[...e[4]||(e[4]=[b("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码(至少8位且包含字母与数字)。",-1))]),_:1})])}}},W=h(U,[["__scopeId","data-v-83d3840a"]]);export{W as default}; diff --git a/static/admin/assets/SystemPage-CJ2F6_EU.js b/static/admin/assets/SystemPage-wAMFferr.js similarity index 99% rename from static/admin/assets/SystemPage-CJ2F6_EU.js rename to static/admin/assets/SystemPage-wAMFferr.js index fc5da95..40c80e0 100644 --- a/static/admin/assets/SystemPage-CJ2F6_EU.js +++ b/static/admin/assets/SystemPage-wAMFferr.js @@ -1,4 +1,4 @@ -import{f as Ve,u as Y}from"./system-In7Gh8x7.js";import{a as P,_ as ge}from"./index-D8t2quK2.js";import{E as ne,f as m}from"./vendor-element-CJoVtPsD.js";import{r as n,c as ke,w as xe,a1 as be,v as we,aW as v,b7 as Ue,M as Ce,A as V,z as g,B as s,S as l,L as t,P as k,N as Z,Q as ee}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function le(r={}){const{data:c}=await P.get("/kdocs/status",{params:r});return c}async function Pe(r={}){const c={force:!0,...r},{data:x}=await P.post("/kdocs/qr",c);return x}async function Ie(){const{data:r}=await P.post("/kdocs/clear-login",{});return r}async function Ae(){const{data:r}=await P.get("/proxy/config");return r}async function Ne(r){const{data:c}=await P.post("/proxy/config",r);return c}async function Se(r){const{data:c}=await P.post("/proxy/test",r);return c}const De={class:"page-stack"},Ke={class:"config-grid"},Ee={class:"row-actions"},Be={class:"row-actions"},Te={class:"row-actions"},Le={class:"section-head"},Qe={class:"status-inline app-muted"},$e={key:0},he={key:1},qe={key:2},Me={class:"kdocs-inline"},Re={class:"kdocs-range"},ze={class:"row-actions"},Fe={key:0,class:"help"},He={key:1,class:"help"},Oe={class:"kdocs-qr"},Ge=["src"],We={__name:"SystemPage",setup(r){const c=n(!1),x=n(2),A=n(1),N=n(3),I=n(!1),f=n(""),S=n(3),D=n(!1),K=n(10),E=n(7),B=n(!1),T=n(""),L=n(""),Q=n(""),$=n(0),h=n("A"),q=n("D"),M=n(0),R=n(0),z=n(!1),F=n(""),p=n({}),b=n(!1),w=n(""),ae=n(!1),H=n(!1),U=n(!1),C=n(!1),O=n("");let G=null;const oe=ke(()=>H.value||U.value||C.value);function d(a){if(!a){O.value="";return}const e=new Date().toLocaleTimeString("zh-CN",{hour12:!1});O.value=`${a} (${e})`}async function ue(){c.value=!0;try{const[a,e,i]=await Promise.all([Ve(),Ae(),le().catch(()=>({}))]);x.value=a.max_concurrent_global??2,A.value=a.max_concurrent_per_account??1,N.value=a.max_screenshot_concurrent??3,D.value=(a.auto_approve_enabled??0)===1,K.value=a.auto_approve_hourly_limit??10,E.value=a.auto_approve_vip_days??7,I.value=(e.proxy_enabled??0)===1,f.value=e.proxy_api_url||"",S.value=e.proxy_expire_minutes??3,B.value=(a.kdocs_enabled??0)===1,T.value=a.kdocs_doc_url||"",L.value=a.kdocs_default_unit||"",Q.value=a.kdocs_sheet_name||"",$.value=a.kdocs_sheet_index??0,h.value=(a.kdocs_unit_column||"A").toUpperCase(),q.value=(a.kdocs_image_column||"D").toUpperCase(),M.value=a.kdocs_row_start??0,R.value=a.kdocs_row_end??0,z.value=(a.kdocs_admin_notify_enabled??0)===1,F.value=a.kdocs_admin_notify_email||"",p.value=i||{}}catch{}finally{c.value=!1}}async function de(){const a={max_concurrent_global:Number(x.value),max_concurrent_per_account:Number(A.value),max_screenshot_concurrent:Number(N.value)};try{await ne.confirm(`确定更新并发配置吗? +import{f as Ve,u as Y}from"./system-Bvj77zeB.js";import{a as P,_ as ge}from"./index-iyjFO6XY.js";import{E as ne,f as m}from"./vendor-element-CJoVtPsD.js";import{r as n,c as ke,w as xe,a1 as be,v as we,aW as v,b7 as Ue,M as Ce,A as V,z as g,B as s,S as l,L as t,P as k,N as Z,Q as ee}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";async function le(r={}){const{data:c}=await P.get("/kdocs/status",{params:r});return c}async function Pe(r={}){const c={force:!0,...r},{data:x}=await P.post("/kdocs/qr",c);return x}async function Ie(){const{data:r}=await P.post("/kdocs/clear-login",{});return r}async function Ae(){const{data:r}=await P.get("/proxy/config");return r}async function Ne(r){const{data:c}=await P.post("/proxy/config",r);return c}async function Se(r){const{data:c}=await P.post("/proxy/test",r);return c}const De={class:"page-stack"},Ke={class:"config-grid"},Ee={class:"row-actions"},Be={class:"row-actions"},Te={class:"row-actions"},Le={class:"section-head"},Qe={class:"status-inline app-muted"},$e={key:0},he={key:1},qe={key:2},Me={class:"kdocs-inline"},Re={class:"kdocs-range"},ze={class:"row-actions"},Fe={key:0,class:"help"},He={key:1,class:"help"},Oe={class:"kdocs-qr"},Ge=["src"],We={__name:"SystemPage",setup(r){const c=n(!1),x=n(2),A=n(1),N=n(3),I=n(!1),f=n(""),S=n(3),D=n(!1),K=n(10),E=n(7),B=n(!1),T=n(""),L=n(""),Q=n(""),$=n(0),h=n("A"),q=n("D"),M=n(0),R=n(0),z=n(!1),F=n(""),p=n({}),b=n(!1),w=n(""),ae=n(!1),H=n(!1),U=n(!1),C=n(!1),O=n("");let G=null;const oe=ke(()=>H.value||U.value||C.value);function d(a){if(!a){O.value="";return}const e=new Date().toLocaleTimeString("zh-CN",{hour12:!1});O.value=`${a} (${e})`}async function ue(){c.value=!0;try{const[a,e,i]=await Promise.all([Ve(),Ae(),le().catch(()=>({}))]);x.value=a.max_concurrent_global??2,A.value=a.max_concurrent_per_account??1,N.value=a.max_screenshot_concurrent??3,D.value=(a.auto_approve_enabled??0)===1,K.value=a.auto_approve_hourly_limit??10,E.value=a.auto_approve_vip_days??7,I.value=(e.proxy_enabled??0)===1,f.value=e.proxy_api_url||"",S.value=e.proxy_expire_minutes??3,B.value=(a.kdocs_enabled??0)===1,T.value=a.kdocs_doc_url||"",L.value=a.kdocs_default_unit||"",Q.value=a.kdocs_sheet_name||"",$.value=a.kdocs_sheet_index??0,h.value=(a.kdocs_unit_column||"A").toUpperCase(),q.value=(a.kdocs_image_column||"D").toUpperCase(),M.value=a.kdocs_row_start??0,R.value=a.kdocs_row_end??0,z.value=(a.kdocs_admin_notify_enabled??0)===1,F.value=a.kdocs_admin_notify_email||"",p.value=i||{}}catch{}finally{c.value=!1}}async function de(){const a={max_concurrent_global:Number(x.value),max_concurrent_per_account:Number(A.value),max_screenshot_concurrent:Number(N.value)};try{await ne.confirm(`确定更新并发配置吗? 全局并发数: ${a.max_concurrent_global} 单账号并发数: ${a.max_concurrent_per_account} diff --git a/static/admin/assets/UsersPage-KZ5WSZrO.js b/static/admin/assets/UsersPage-B5MDfX7T.js similarity index 99% rename from static/admin/assets/UsersPage-KZ5WSZrO.js rename to static/admin/assets/UsersPage-B5MDfX7T.js index d47968a..9b6b15f 100644 --- a/static/admin/assets/UsersPage-KZ5WSZrO.js +++ b/static/admin/assets/UsersPage-B5MDfX7T.js @@ -1 +1 @@ -import{a as Z,r as q,s as K,b as Q,c as F,d as G,f as H}from"./users-CTuo5Ynz.js";import{_ as J}from"./index-D8t2quK2.js";import{E as v,f as h}from"./vendor-element-CJoVtPsD.js";import{i as O,r as P,v as X,aW as _,b7 as Y,z as V,A as r,B as y,S as o,L as s,M as ee,K as f,N as m,Q as b,P as c}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";function I(g){if(!g)return null;if(g instanceof Date)return g;let a=String(g).trim();if(!a)return null;/^\d{4}-\d{2}-\d{2}$/.test(a)&&(a=`${a}T00:00:00`);let l=a.includes("T")?a:a.replace(" ","T");l=l.replace(/\.(\d{3})\d+/,".$1"),/([zZ]|[+-]\d{2}:\d{2})$/.test(l)||(l=`${l}+08:00`);const u=new Date(l);return Number.isNaN(u.getTime())?null:u}function D(g){const a=String(g||"");if(!a)return{ok:!1,message:"密码不能为空"};if(a.length<8)return{ok:!1,message:"密码长度不能少于8个字符"};if(a.length>128)return{ok:!1,message:"密码长度不能超过128个字符"};const l=/[a-zA-Z]/.test(a),x=/\d/.test(a);return!l||!x?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}const te={class:"page-stack"},ne={class:"table-wrap"},se={class:"user-block"},ae={class:"user-main"},ie={key:0,class:"app-muted user-sub"},re={key:1,class:"vip-sub"},le={key:0,class:"app-muted"},oe={class:"actions"},ce={__name:"UsersPage",setup(g){const a=O("refreshStats",null),l=P(!1),x=P([]);function u(n){const e=n?.vip_expire_time;if(!e)return!1;if(String(e).startsWith("2099-12-31"))return!0;const i=I(e);return i?i.getTime()>Date.now():!1}function C(n){const e=n?.vip_expire_time;if(!e||!u(n))return"";if(String(e).startsWith("2099-12-31"))return"永久VIP";const i=I(e);if(!i)return`到期: ${e}`;const d=Math.ceil((i.getTime()-Date.now())/(1e3*60*60*24));return`到期: ${e}(剩${d}天)`}function B(n){return n==="rejected"?{label:"禁用",type:"danger"}:{label:"正常",type:"success"}}async function w(){l.value=!0;try{x.value=await H()}catch{x.value=[]}finally{l.value=!1}}async function U(){await w()}async function z(n){try{await v.confirm(`确定启用用户「${n.username}」吗?启用后用户可正常登录。`,"启用用户",{confirmButtonText:"启用",cancelButtonText:"取消",type:"success"})}catch{return}try{await Z(n.id),h.success("用户已启用"),await w(),await a?.()}catch{}}async function S(n){try{await v.confirm(`确定禁用用户「${n.username}」吗?禁用后用户将无法登录。`,"禁用用户",{confirmButtonText:"禁用",cancelButtonText:"取消",type:"warning"})}catch{return}try{await q(n.id),h.success("用户已禁用"),await w(),await a?.()}catch{}}async function N(n){try{await v.confirm(`确定删除用户「${n.username}」吗?此操作将删除该用户的所有数据,不可恢复!`,"删除用户",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{await G(n.id),h.success("用户已删除"),await w(),await a?.()}catch{}}async function $(n,e){const i={7:"一周",30:"一个月",365:"一年",999999:"永久"}[e]||`${e}天`;try{await v.confirm(`确定为用户「${n.username}」开通 ${i} VIP 吗?`,"设置VIP",{confirmButtonText:"确认",cancelButtonText:"取消",type:"warning"})}catch{return}try{const d=await K(n.id,e);h.success(d?.message||"VIP设置成功"),await w(),await a?.()}catch{}}async function M(n){try{await v.confirm(`确定移除用户「${n.username}」的 VIP 吗?`,"移除VIP",{confirmButtonText:"移除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Q(n.id);h.success(e?.message||"VIP已移除"),await w(),await a?.()}catch{}}async function E(n){let e;try{e=(await v.prompt("请输入新密码(至少8位且包含字母和数字)","重置密码",{confirmButtonText:"提交",cancelButtonText:"取消",inputType:"password",inputPlaceholder:"新密码",inputValidator:k=>D(k).ok,inputErrorMessage:"密码至少8位且包含字母和数字"})).value}catch{return}const i=D(e);if(!i.ok){h.error(i.message);return}try{await v.confirm(`确定将用户「${n.username}」的密码重置为该新密码吗?`,"二次确认",{confirmButtonText:"确认重置",cancelButtonText:"取消",type:"warning"})}catch{return}try{const d=await F(n.id,e);h.success(d?.message||"密码重置成功")}catch{}}return X(U),(n,e)=>{const i=_("el-table-column"),d=_("el-tag"),k=_("el-button"),T=_("el-dropdown-item"),j=_("el-dropdown-menu"),A=_("el-dropdown"),L=_("el-table"),R=_("el-card"),W=Y("loading");return r(),V("div",te,[e[11]||(e[11]=y("div",{class:"app-page-title"},[y("h2",null,"用户")],-1)),o(R,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:s(()=>[y("div",ne,[ee((r(),f(L,{data:x.value,style:{width:"100%"}},{default:s(()=>[o(i,{prop:"id",label:"ID",width:"80"}),o(i,{label:"用户","min-width":"240"},{default:s(({row:t})=>[y("div",se,[y("div",ae,[y("strong",null,b(t.username),1),u(t)?(r(),f(d,{key:0,type:"warning",effect:"light",size:"small"},{default:s(()=>[...e[0]||(e[0]=[c("VIP",-1)])]),_:1})):m("",!0)]),t.email?(r(),V("div",ie,b(t.email),1)):m("",!0),C(t)?(r(),V("div",re,b(C(t)),1)):m("",!0)])]),_:1}),o(i,{label:"状态",width:"120"},{default:s(({row:t})=>[o(d,{type:B(t.status).type,effect:"light"},{default:s(()=>[c(b(B(t.status).label),1)]),_:2},1032,["type"])]),_:1}),o(i,{label:"时间","min-width":"220"},{default:s(({row:t})=>[y("div",null,b(t.created_at),1),t.vip_expire_time?(r(),V("div",le,"VIP到期: "+b(t.vip_expire_time),1)):m("",!0)]),_:1}),o(i,{label:"操作",width:"280",fixed:"right"},{default:s(({row:t})=>[y("div",oe,[t.status==="rejected"?(r(),f(k,{key:0,type:"success",size:"small",onClick:p=>z(t)},{default:s(()=>[...e[1]||(e[1]=[c("启用",-1)])]),_:1},8,["onClick"])):(r(),f(k,{key:1,type:"warning",size:"small",onClick:p=>S(t)},{default:s(()=>[...e[2]||(e[2]=[c("禁用",-1)])]),_:1},8,["onClick"])),o(A,{trigger:"click"},{dropdown:s(()=>[o(j,null,{default:s(()=>[u(t)?m("",!0):(r(),f(T,{key:0,onClick:p=>$(t,7)},{default:s(()=>[...e[4]||(e[4]=[c("开通一周",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:1,onClick:p=>$(t,30)},{default:s(()=>[...e[5]||(e[5]=[c("开通一月",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:2,onClick:p=>$(t,365)},{default:s(()=>[...e[6]||(e[6]=[c("开通一年",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:3,onClick:p=>$(t,999999)},{default:s(()=>[...e[7]||(e[7]=[c("永久VIP",-1)])]),_:1},8,["onClick"])),u(t)?(r(),f(T,{key:4,onClick:p=>M(t)},{default:s(()=>[...e[8]||(e[8]=[c("移除VIP",-1)])]),_:1},8,["onClick"])):m("",!0)]),_:2},1024)]),default:s(()=>[o(k,{size:"small"},{default:s(()=>[...e[3]||(e[3]=[c("VIP",-1)])]),_:1})]),_:2},1024),o(k,{size:"small",onClick:p=>E(t)},{default:s(()=>[...e[9]||(e[9]=[c("重置密码",-1)])]),_:1},8,["onClick"]),o(k,{type:"danger",size:"small",onClick:p=>N(t)},{default:s(()=>[...e[10]||(e[10]=[c("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[W,l.value]])])]),_:1})])}}},ye=J(ce,[["__scopeId","data-v-9e917879"]]);export{ye as default}; +import{a as Z,r as q,s as K,b as Q,c as F,d as G,f as H}from"./users-Kctz2ziD.js";import{_ as J}from"./index-iyjFO6XY.js";import{E as v,f as h}from"./vendor-element-CJoVtPsD.js";import{i as O,r as P,v as X,aW as _,b7 as Y,z as V,A as r,B as y,S as o,L as s,M as ee,K as f,N as m,Q as b,P as c}from"./vendor-sLgkZK1v.js";import"./vendor-vue-CWkOjFoA.js";import"./vendor-axios-B9ygI19o.js";function I(g){if(!g)return null;if(g instanceof Date)return g;let a=String(g).trim();if(!a)return null;/^\d{4}-\d{2}-\d{2}$/.test(a)&&(a=`${a}T00:00:00`);let l=a.includes("T")?a:a.replace(" ","T");l=l.replace(/\.(\d{3})\d+/,".$1"),/([zZ]|[+-]\d{2}:\d{2})$/.test(l)||(l=`${l}+08:00`);const u=new Date(l);return Number.isNaN(u.getTime())?null:u}function D(g){const a=String(g||"");if(!a)return{ok:!1,message:"密码不能为空"};if(a.length<8)return{ok:!1,message:"密码长度不能少于8个字符"};if(a.length>128)return{ok:!1,message:"密码长度不能超过128个字符"};const l=/[a-zA-Z]/.test(a),x=/\d/.test(a);return!l||!x?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}const te={class:"page-stack"},ne={class:"table-wrap"},se={class:"user-block"},ae={class:"user-main"},ie={key:0,class:"app-muted user-sub"},re={key:1,class:"vip-sub"},le={key:0,class:"app-muted"},oe={class:"actions"},ce={__name:"UsersPage",setup(g){const a=O("refreshStats",null),l=P(!1),x=P([]);function u(n){const e=n?.vip_expire_time;if(!e)return!1;if(String(e).startsWith("2099-12-31"))return!0;const i=I(e);return i?i.getTime()>Date.now():!1}function C(n){const e=n?.vip_expire_time;if(!e||!u(n))return"";if(String(e).startsWith("2099-12-31"))return"永久VIP";const i=I(e);if(!i)return`到期: ${e}`;const d=Math.ceil((i.getTime()-Date.now())/(1e3*60*60*24));return`到期: ${e}(剩${d}天)`}function B(n){return n==="rejected"?{label:"禁用",type:"danger"}:{label:"正常",type:"success"}}async function w(){l.value=!0;try{x.value=await H()}catch{x.value=[]}finally{l.value=!1}}async function U(){await w()}async function z(n){try{await v.confirm(`确定启用用户「${n.username}」吗?启用后用户可正常登录。`,"启用用户",{confirmButtonText:"启用",cancelButtonText:"取消",type:"success"})}catch{return}try{await Z(n.id),h.success("用户已启用"),await w(),await a?.()}catch{}}async function S(n){try{await v.confirm(`确定禁用用户「${n.username}」吗?禁用后用户将无法登录。`,"禁用用户",{confirmButtonText:"禁用",cancelButtonText:"取消",type:"warning"})}catch{return}try{await q(n.id),h.success("用户已禁用"),await w(),await a?.()}catch{}}async function N(n){try{await v.confirm(`确定删除用户「${n.username}」吗?此操作将删除该用户的所有数据,不可恢复!`,"删除用户",{confirmButtonText:"删除",cancelButtonText:"取消",type:"error"})}catch{return}try{await G(n.id),h.success("用户已删除"),await w(),await a?.()}catch{}}async function $(n,e){const i={7:"一周",30:"一个月",365:"一年",999999:"永久"}[e]||`${e}天`;try{await v.confirm(`确定为用户「${n.username}」开通 ${i} VIP 吗?`,"设置VIP",{confirmButtonText:"确认",cancelButtonText:"取消",type:"warning"})}catch{return}try{const d=await K(n.id,e);h.success(d?.message||"VIP设置成功"),await w(),await a?.()}catch{}}async function M(n){try{await v.confirm(`确定移除用户「${n.username}」的 VIP 吗?`,"移除VIP",{confirmButtonText:"移除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Q(n.id);h.success(e?.message||"VIP已移除"),await w(),await a?.()}catch{}}async function E(n){let e;try{e=(await v.prompt("请输入新密码(至少8位且包含字母和数字)","重置密码",{confirmButtonText:"提交",cancelButtonText:"取消",inputType:"password",inputPlaceholder:"新密码",inputValidator:k=>D(k).ok,inputErrorMessage:"密码至少8位且包含字母和数字"})).value}catch{return}const i=D(e);if(!i.ok){h.error(i.message);return}try{await v.confirm(`确定将用户「${n.username}」的密码重置为该新密码吗?`,"二次确认",{confirmButtonText:"确认重置",cancelButtonText:"取消",type:"warning"})}catch{return}try{const d=await F(n.id,e);h.success(d?.message||"密码重置成功")}catch{}}return X(U),(n,e)=>{const i=_("el-table-column"),d=_("el-tag"),k=_("el-button"),T=_("el-dropdown-item"),j=_("el-dropdown-menu"),A=_("el-dropdown"),L=_("el-table"),R=_("el-card"),W=Y("loading");return r(),V("div",te,[e[11]||(e[11]=y("div",{class:"app-page-title"},[y("h2",null,"用户")],-1)),o(R,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:s(()=>[y("div",ne,[ee((r(),f(L,{data:x.value,style:{width:"100%"}},{default:s(()=>[o(i,{prop:"id",label:"ID",width:"80"}),o(i,{label:"用户","min-width":"240"},{default:s(({row:t})=>[y("div",se,[y("div",ae,[y("strong",null,b(t.username),1),u(t)?(r(),f(d,{key:0,type:"warning",effect:"light",size:"small"},{default:s(()=>[...e[0]||(e[0]=[c("VIP",-1)])]),_:1})):m("",!0)]),t.email?(r(),V("div",ie,b(t.email),1)):m("",!0),C(t)?(r(),V("div",re,b(C(t)),1)):m("",!0)])]),_:1}),o(i,{label:"状态",width:"120"},{default:s(({row:t})=>[o(d,{type:B(t.status).type,effect:"light"},{default:s(()=>[c(b(B(t.status).label),1)]),_:2},1032,["type"])]),_:1}),o(i,{label:"时间","min-width":"220"},{default:s(({row:t})=>[y("div",null,b(t.created_at),1),t.vip_expire_time?(r(),V("div",le,"VIP到期: "+b(t.vip_expire_time),1)):m("",!0)]),_:1}),o(i,{label:"操作",width:"280",fixed:"right"},{default:s(({row:t})=>[y("div",oe,[t.status==="rejected"?(r(),f(k,{key:0,type:"success",size:"small",onClick:p=>z(t)},{default:s(()=>[...e[1]||(e[1]=[c("启用",-1)])]),_:1},8,["onClick"])):(r(),f(k,{key:1,type:"warning",size:"small",onClick:p=>S(t)},{default:s(()=>[...e[2]||(e[2]=[c("禁用",-1)])]),_:1},8,["onClick"])),o(A,{trigger:"click"},{dropdown:s(()=>[o(j,null,{default:s(()=>[u(t)?m("",!0):(r(),f(T,{key:0,onClick:p=>$(t,7)},{default:s(()=>[...e[4]||(e[4]=[c("开通一周",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:1,onClick:p=>$(t,30)},{default:s(()=>[...e[5]||(e[5]=[c("开通一月",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:2,onClick:p=>$(t,365)},{default:s(()=>[...e[6]||(e[6]=[c("开通一年",-1)])]),_:1},8,["onClick"])),u(t)?m("",!0):(r(),f(T,{key:3,onClick:p=>$(t,999999)},{default:s(()=>[...e[7]||(e[7]=[c("永久VIP",-1)])]),_:1},8,["onClick"])),u(t)?(r(),f(T,{key:4,onClick:p=>M(t)},{default:s(()=>[...e[8]||(e[8]=[c("移除VIP",-1)])]),_:1},8,["onClick"])):m("",!0)]),_:2},1024)]),default:s(()=>[o(k,{size:"small"},{default:s(()=>[...e[3]||(e[3]=[c("VIP",-1)])]),_:1})]),_:2},1024),o(k,{size:"small",onClick:p=>E(t)},{default:s(()=>[...e[9]||(e[9]=[c("重置密码",-1)])]),_:1},8,["onClick"]),o(k,{type:"danger",size:"small",onClick:p=>N(t)},{default:s(()=>[...e[10]||(e[10]=[c("删除",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data"])),[[W,l.value]])])]),_:1})])}}},ye=J(ce,[["__scopeId","data-v-9e917879"]]);export{ye as default}; diff --git a/static/admin/assets/email-CqsrP_Ts.js b/static/admin/assets/email-BYiWDIoy.js similarity index 86% rename from static/admin/assets/email-CqsrP_Ts.js rename to static/admin/assets/email-BYiWDIoy.js index 4185dd2..2d88b15 100644 --- a/static/admin/assets/email-CqsrP_Ts.js +++ b/static/admin/assets/email-BYiWDIoy.js @@ -1 +1 @@ -import{a as n}from"./index-D8t2quK2.js";async function i(){const{data:a}=await n.get("/email/settings");return a}async function e(a){const{data:t}=await n.post("/email/settings",a);return t}async function c(){const{data:a}=await n.get("/email/stats");return a}async function o(a){const{data:t}=await n.get("/email/logs",{params:a});return t}async function l(a){const{data:t}=await n.post("/email/logs/cleanup",{days:a});return t}export{o as a,i as b,l as c,c as f,e as u}; +import{a as n}from"./index-iyjFO6XY.js";async function i(){const{data:a}=await n.get("/email/settings");return a}async function e(a){const{data:t}=await n.post("/email/settings",a);return t}async function c(){const{data:a}=await n.get("/email/stats");return a}async function o(a){const{data:t}=await n.get("/email/logs",{params:a});return t}async function l(a){const{data:t}=await n.post("/email/logs/cleanup",{days:a});return t}export{o as a,i as b,l as c,c as f,e as u}; diff --git a/static/admin/assets/index-D8t2quK2.js b/static/admin/assets/index-D8t2quK2.js deleted file mode 100644 index e1c67c5..0000000 --- a/static/admin/assets/index-D8t2quK2.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./ReportPage-GPt5J1Db.js","./vendor-element-CJoVtPsD.js","./vendor-sLgkZK1v.js","./vendor-vue-CWkOjFoA.js","./vendor-element-C68yOrAy.css","./email-CqsrP_Ts.js","./tasks-DZnsc1fC.js","./system-In7Gh8x7.js","./MetricGrid-Cbhb9OGV.js","./MetricGrid-yP_dkP6X.css","./vendor-axios-B9ygI19o.js","./ReportPage-CnNjCmpq.css","./UsersPage-KZ5WSZrO.js","./users-CTuo5Ynz.js","./UsersPage-Cow_LicY.css","./FeedbacksPage-B8rr6rHD.js","./FeedbacksPage-mrXjCiV2.css","./LogsPage-WfvkzS-6.js","./LogsPage-D1bozCEo.css","./AnnouncementsPage-CaSWhmIw.js","./AnnouncementsPage-DOwZaaOu.css","./EmailPage-DlOkUKzK.js","./EmailPage-BmPCDPYC.css","./SecurityPage-BWFFA3z9.js","./SecurityPage-DN76ndc_.css","./SystemPage-CJ2F6_EU.js","./SystemPage-DMyNBO3N.css","./SettingsPage-3cNfdgGx.js","./SettingsPage-DaB8PeRL.css"])))=>i.map(i=>d[i]); -import{aW as p,K as w,A as h,r as S,c as U,v as le,a1 as ce,L as o,N as q,S as m,B as d,z as V,R as j,ak as K,O as z,Q as L,P as W,by as ie,p as N,bu as ue}from"./vendor-sLgkZK1v.js";import{u as de,p as me,q as pe,r as fe}from"./vendor-vue-CWkOjFoA.js";import{E as X,f as J,g as _e,u as he,h as ye,j as be,k as ge,m as ve,n as we,t as ke,o as Ee,p as Pe,z as xe}from"./vendor-element-CJoVtPsD.js";import{a as Re}from"./vendor-axios-B9ygI19o.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))s(n);new MutationObserver(n=>{for(const c of n)if(c.type==="childList")for(const u of c.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&s(u)}).observe(document,{childList:!0,subtree:!0});function a(n){const c={};return n.integrity&&(c.integrity=n.integrity),n.referrerPolicy&&(c.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?c.credentials="include":n.crossOrigin==="anonymous"?c.credentials="omit":c.credentials="same-origin",c}function s(n){if(n.ep)return;n.ep=!0;const c=a(n);fetch(n.href,c)}})();const Y=(e,t)=>{const a=e.__vccOpts||e;for(const[s,n]of t)a[s]=n;return a},Se={};function Le(e,t){const a=p("RouterView");return h(),w(a)}const Oe=Y(Se,[["render",Le]]),Te="modulepreload",Ae=function(e,t){return new URL(e,t).href},H={},k=function(t,a,s){let n=Promise.resolve();if(a&&a.length>0){let R=function(i){return Promise.all(i.map(_=>Promise.resolve(_).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};const u=document.getElementsByTagName("link"),f=document.querySelector("meta[property=csp-nonce]"),x=f?.nonce||f?.getAttribute("nonce");n=R(a.map(i=>{if(i=Ae(i,s),i in H)return;H[i]=!0;const _=i.endsWith(".css"),g=_?'[rel="stylesheet"]':"";if(s)for(let E=u.length-1;E>=0;E--){const P=u[E];if(P.href===i&&(!_||P.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${i}"]${g}`))return;const y=document.createElement("link");if(y.rel=_?"stylesheet":Te,_||(y.as="script"),y.crossOrigin="",y.href=i,x&&y.setAttribute("nonce",x),document.head.appendChild(y),_)return new Promise((E,P)=>{y.addEventListener("load",E),y.addEventListener("error",()=>P(new Error(`Unable to preload CSS for ${i}`)))})}))}function c(u){const f=new Event("vite:preloadError",{cancelable:!0});if(f.payload=u,window.dispatchEvent(f),!f.defaultPrevented)throw u}return n.then(u=>{for(const f of u||[])f.status==="rejected"&&c(f.reason);return t().catch(c)})};let G="",Q=0;function O(e,t,a=1500){const s=Date.now();e===G&&s-Q!!String(e||"").trim(),inputErrorMessage:"密码不能为空"}).then(async e=>{const t=String(e.value||"").trim();await b.post("/admin/reauth",{password:t}),J.success("已通过安全确认")}).finally(()=>{T=null}),T)}b.interceptors.request.use(e=>{const t=String(e?.method||"GET").toUpperCase();if(!["GET","HEAD","OPTIONS"].includes(t)){const a=Ve("csrf_token");a&&(e.headers=e.headers||{},e.headers["X-CSRF-Token"]=a)}return e});b.interceptors.response.use(e=>e,async e=>{const t=e?.response?.status,a=e?.response?.data,s=a?.error||a?.message||e?.message||"请求失败";if(a?.code==="reauth_required"&&e?.config&&!e.config.__reauth_retry)try{return e.config.__reauth_retry=!0,await Ne(),b.request(e.config)}catch{return Promise.reject(e)}return t===401?(O("401",s,3e3),(window.location?.pathname||"").startsWith("/yuyx")||(window.location.href="/yuyx")):t===403?O("403",s,5e3):t?O(`http:${t}:${s}`,s):e?.code==="ECONNABORTED"?O("timeout","请求超时",3e3):O(`net:${s}`,s,3e3),Promise.reject(e)});async function lt(e=""){const{data:t}=await b.get("/feedbacks",{params:e?{status:e}:{}});return t}async function Be(){const{data:e}=await b.get("/feedbacks",{params:{limit:1,offset:0}});return e?.stats}async function ct(e,t){const{data:a}=await b.post(`/feedbacks/${e}/reply`,{reply:t});return a}async function it(e){const{data:t}=await b.post(`/feedbacks/${e}/close`);return t}async function ut(e){const{data:t}=await b.delete(`/feedbacks/${e}`);return t}async function Ce(){const{data:e}=await b.get("/stats");return e}const Ie={class:"menu-label"},$e={key:1,class:"menu-label"},De={class:"header-left"},Fe={class:"header-right"},Me={class:"admin-name"},Ue={class:"main-shell"},qe={class:"menu-label"},je={key:1,class:"menu-label"},Ke={__name:"AdminLayout",setup(e){const t=de(),a=me(),s=S({}),n=U(()=>s.value?.admin_username||"");async function c(){try{s.value=await Ce()}finally{}}const u=S(!1),f=S(0);let x;async function R(v=null){if(v&&typeof v=="object"){Object.prototype.hasOwnProperty.call(v,"pendingFeedbacks")&&(f.value=Number(v.pendingFeedbacks||0));return}if(!u.value){u.value=!0;try{const r=await Be();f.value=Number(r?.pending||0)}finally{u.value=!1}}}N("refreshStats",c),N("adminStats",s),N("refreshNavBadges",R);const i=S(!1),_=S(!1);let g;function y(){i.value=!!g?.matches,i.value||(_.value=!1)}le(async()=>{g=window.matchMedia("(max-width: 768px)"),g.addEventListener?.("change",y),y(),await c(),await R(),x=window.setInterval(R,6e4)}),ce(()=>{g?.removeEventListener?.("change",y),window.clearInterval(x)});const E=[{path:"/reports",label:"报表",icon:_e},{path:"/users",label:"用户",icon:he},{path:"/feedbacks",label:"反馈",icon:ye,badgeKey:"feedbacks"},{path:"/logs",label:"任务日志",icon:be},{path:"/announcements",label:"公告",icon:ge},{path:"/email",label:"邮件",icon:ve},{path:"/security",label:"安全防护",icon:we},{path:"/system",label:"系统配置",icon:ke},{path:"/settings",label:"设置",icon:Ee}],P=U(()=>t.path);function A(v){return v?.badgeKey&&v.badgeKey==="feedbacks"?Number(f.value||0):0}async function Z(){try{await X.confirm("确定退出管理员登录吗?","退出登录",{confirmButtonText:"退出",cancelButtonText:"取消",type:"warning"})}catch{return}try{await b.post("/logout")}finally{window.location.href="/yuyx"}}async function B(v){await a.push(v),_.value=!1}return(v,r)=>{const C=p("el-icon"),I=p("el-badge"),$=p("el-menu-item"),D=p("el-menu"),ee=p("el-aside"),F=p("el-button"),te=p("el-header"),ae=p("RouterView"),ne=p("el-skeleton"),se=p("el-card"),oe=p("el-main"),M=p("el-container"),re=p("el-drawer");return h(),w(M,{class:"layout-root"},{default:o(()=>[i.value?q("",!0):(h(),w(ee,{key:0,width:"220px",class:"layout-aside"},{default:o(()=>[r[2]||(r[2]=d("div",{class:"brand"},[d("div",{class:"brand-title"},"后台管理"),d("div",{class:"brand-sub app-muted"},"知识管理平台")],-1)),m(D,{"default-active":P.value,class:"aside-menu",router:"",onSelect:B},{default:o(()=>[(h(),V(j,null,K(E,l=>m($,{key:l.path,index:l.path},{default:o(()=>[m(C,null,{default:o(()=>[(h(),w(z(l.icon)))]),_:2},1024),A(l)>0?(h(),w(I,{key:0,value:A(l),max:99,class:"menu-badge"},{default:o(()=>[d("span",Ie,L(l.label),1)]),_:2},1032,["value"])):(h(),V("span",$e,L(l.label),1))]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1})),m(M,null,{default:o(()=>[m(te,{class:"layout-header"},{default:o(()=>[d("div",De,[i.value?(h(),w(F,{key:0,text:"",class:"header-menu-btn",onClick:r[0]||(r[0]=l=>_.value=!0)},{default:o(()=>[...r[3]||(r[3]=[W(" 菜单 ",-1)])]),_:1})):q("",!0),r[4]||(r[4]=d("div",{class:"header-title"},"后台管理系统",-1))]),d("div",Fe,[d("div",Me,[r[5]||(r[5]=d("span",{class:"app-muted"},"管理员",-1)),d("strong",null,L(n.value||"-"),1)]),m(F,{type:"primary",plain:"",class:"logout-btn",onClick:Z},{default:o(()=>[...r[6]||(r[6]=[W("退出",-1)])]),_:1})])]),_:1}),m(oe,{class:"layout-main"},{default:o(()=>[d("div",Ue,[(h(),w(ie,null,{default:o(()=>[m(ae)]),fallback:o(()=>[m(se,{shadow:"never","body-style":{padding:"16px"},class:"fallback-card"},{default:o(()=>[m(ne,{rows:5,animated:""})]),_:1})]),_:1}))])]),_:1})]),_:1}),m(re,{modelValue:_.value,"onUpdate:modelValue":r[1]||(r[1]=l=>_.value=l),size:"min(82vw, 280px)",direction:"ltr","with-header":!1},{default:o(()=>[r[7]||(r[7]=d("div",{class:"drawer-brand"},[d("div",{class:"brand-title"},"后台管理"),d("div",{class:"brand-sub app-muted"},"知识管理平台")],-1)),m(D,{"default-active":P.value,class:"aside-menu",router:"",onSelect:B},{default:o(()=>[(h(),V(j,null,K(E,l=>m($,{key:l.path,index:l.path},{default:o(()=>[m(C,null,{default:o(()=>[(h(),w(z(l.icon)))]),_:2},1024),A(l)>0?(h(),w(I,{key:0,value:A(l),max:99,class:"menu-badge"},{default:o(()=>[d("span",qe,L(l.label),1)]),_:2},1032,["value"])):(h(),V("span",je,L(l.label),1))]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1},8,["modelValue"])]),_:1})}}},ze=Y(Ke,[["__scopeId","data-v-465abc4b"]]),We=()=>k(()=>import("./ReportPage-GPt5J1Db.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11]),import.meta.url),He=()=>k(()=>import("./UsersPage-KZ5WSZrO.js"),__vite__mapDeps([12,13,1,2,3,4,10,14]),import.meta.url),Ge=()=>k(()=>import("./FeedbacksPage-B8rr6rHD.js"),__vite__mapDeps([15,8,2,9,1,3,4,10,16]),import.meta.url),Qe=()=>k(()=>import("./LogsPage-WfvkzS-6.js"),__vite__mapDeps([17,13,6,1,2,3,4,10,18]),import.meta.url),Xe=()=>k(()=>import("./AnnouncementsPage-CaSWhmIw.js"),__vite__mapDeps([19,1,2,3,4,10,20]),import.meta.url),Je=()=>k(()=>import("./EmailPage-DlOkUKzK.js"),__vite__mapDeps([21,5,8,2,9,1,3,4,10,22]),import.meta.url),Ye=()=>k(()=>import("./SecurityPage-BWFFA3z9.js"),__vite__mapDeps([23,8,2,9,1,3,4,10,24]),import.meta.url),Ze=()=>k(()=>import("./SystemPage-CJ2F6_EU.js"),__vite__mapDeps([25,7,1,2,3,4,10,26]),import.meta.url),et=()=>k(()=>import("./SettingsPage-3cNfdgGx.js"),__vite__mapDeps([27,1,2,3,4,10,28]),import.meta.url),tt=[{path:"/",component:ze,children:[{path:"",redirect:"/reports"},{path:"/pending",redirect:"/reports"},{path:"/stats",redirect:"/reports"},{path:"/reports",name:"reports",component:We},{path:"/users",name:"users",component:He},{path:"/feedbacks",name:"feedbacks",component:Ge},{path:"/logs",name:"logs",component:Qe},{path:"/announcements",name:"announcements",component:Xe},{path:"/email",name:"email",component:Je},{path:"/security",name:"security",component:Ye},{path:"/system",name:"system",component:Ze},{path:"/settings",name:"settings",component:et}]}],at=pe({history:fe(),routes:tt});ue(Oe).use(at).use(Pe,{locale:xe}).mount("#app");export{Y as _,b as a,lt as b,it as c,ut as d,Be as f,ct as r}; diff --git a/static/admin/assets/index-Tk47UJAg.css b/static/admin/assets/index-a3a11Ghn.css similarity index 66% rename from static/admin/assets/index-Tk47UJAg.css rename to static/admin/assets/index-a3a11Ghn.css index 44856ee..2537052 100644 --- a/static/admin/assets/index-Tk47UJAg.css +++ b/static/admin/assets/index-a3a11Ghn.css @@ -1 +1 @@ -.layout-root[data-v-465abc4b]{height:100%}.layout-aside[data-v-465abc4b]{background:linear-gradient(180deg,#fffffffa,#f8fafcf0);border-right:1px solid var(--app-border);box-shadow:4px 0 16px #0f172a0a}.brand[data-v-465abc4b],.drawer-brand[data-v-465abc4b]{padding:18px 16px 14px}.brand[data-v-465abc4b]{border-bottom:1px solid rgba(15,23,42,.06)}.brand-title[data-v-465abc4b]{font-size:16px;font-weight:800;letter-spacing:.2px}.brand-sub[data-v-465abc4b]{margin-top:4px;font-size:12px}.aside-menu[data-v-465abc4b]{border-right:none;padding:8px;background:transparent}.aside-menu[data-v-465abc4b] .el-menu-item{height:42px;line-height:42px;margin:3px 0;border-radius:10px;color:#334155;font-weight:600}.aside-menu[data-v-465abc4b] .el-menu-item .el-icon{margin-right:10px}.aside-menu[data-v-465abc4b] .el-menu-item:hover{background:#3b82f614;color:#1d4ed8}.aside-menu[data-v-465abc4b] .el-menu-item.is-active{background:linear-gradient(135deg,#2563eb1f,#7c3aed1a);color:#1e40af}.menu-label[data-v-465abc4b]{display:inline-flex;align-items:center;min-width:0}.menu-badge[data-v-465abc4b]{display:inline-flex;align-items:center}.fallback-card[data-v-465abc4b]{min-height:160px;border-radius:var(--app-radius-lg);border:1px solid var(--app-border)}.layout-header[data-v-465abc4b]{position:sticky;top:0;z-index:20;display:flex;align-items:center;justify-content:space-between;gap:12px;height:58px;padding:0 18px;background:#ffffffc7;-webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);border-bottom:1px solid var(--app-border)}.header-left[data-v-465abc4b]{display:flex;align-items:center;gap:10px;min-width:0}.header-title[data-v-465abc4b]{font-size:15px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.header-menu-btn[data-v-465abc4b]{padding-left:0;padding-right:0}.header-right[data-v-465abc4b]{display:flex;align-items:center;gap:12px}.admin-name[data-v-465abc4b]{display:flex;align-items:baseline;gap:8px;font-size:13px;color:#334155}.admin-name strong[data-v-465abc4b]{color:#0f172a;font-weight:800}.logout-btn[data-v-465abc4b]{min-width:74px}.layout-main[data-v-465abc4b]{padding:18px}.main-shell[data-v-465abc4b]{width:100%;max-width:1600px;margin:0 auto}@media(max-width:768px){.layout-header[data-v-465abc4b]{flex-wrap:wrap;height:auto;padding:10px 12px}.header-right[data-v-465abc4b]{width:100%;justify-content:flex-end}.admin-name .app-muted[data-v-465abc4b],.admin-name strong[data-v-465abc4b]{display:none}.layout-main[data-v-465abc4b]{padding:12px}}:root{--app-bg: #f4f6fb;--app-text: #111827;--app-muted: #6b7280;--app-border: rgba(15, 23, 42, .1);--app-border-strong: rgba(15, 23, 42, .14);--app-radius: 12px;--app-radius-lg: 14px;--app-shadow-soft: 0 8px 24px rgba(15, 23, 42, .05);--app-shadow: 0 12px 30px rgba(15, 23, 42, .08);--app-card-bg: rgba(255, 255, 255, .94);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}html,body,#app{height:100%}*{box-sizing:border-box}body{margin:0;color:var(--app-text);background:radial-gradient(1200px 500px at -10% -10%,rgba(59,130,246,.12),transparent 55%),radial-gradient(1000px 420px at 110% 0%,rgba(139,92,246,.1),transparent 50%),var(--app-bg)}a{color:inherit;text-decoration:none}.app-page-title{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 14px}.app-page-title h2{margin:0;font-size:19px;font-weight:800;letter-spacing:.2px}.app-muted{color:var(--app-muted)}.page-stack{display:flex;flex-direction:column;gap:14px;min-width:0}.el-card{border-radius:var(--app-radius-lg);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.el-button{border-radius:10px;font-weight:600}.el-input__wrapper,.el-textarea__inner,.el-select__wrapper,.el-input-number,.el-picker__wrapper{border-radius:10px}.el-table{border-radius:10px;overflow:hidden}.el-table th.el-table__cell{background:#f8fafc;color:#334155;font-weight:700}.el-table td.el-table__cell,.el-table th.el-table__cell{padding-top:11px;padding-bottom:11px}.el-table .el-table__row:hover>td.el-table__cell{background:#f8fbff}.el-tag{border-radius:999px}.el-dialog{border-radius:var(--app-radius-lg)}@media(max-width:768px){.app-page-title{flex-wrap:wrap;align-items:flex-start}.app-page-title h2{font-size:17px}.el-dialog{max-width:92vw}.el-form-item{flex-direction:column;align-items:stretch}.el-form-item__label{width:auto!important;justify-content:flex-start!important;padding:0 0 6px!important;line-height:1.4;text-align:left!important}.el-form-item__content{margin-left:0!important;width:100%}}.section-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.section-title{margin:0;font-size:15px;font-weight:800;letter-spacing:.2px}.toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.table-wrap{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.pagination{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint{font-size:12px}.el-tabs__item{font-weight:700}.el-form-item{margin-bottom:18px}@media(max-width:768px){.pagination{justify-content:flex-start}}@media(max-width:900px){.toolbar{width:100%}.toolbar>*{min-width:0}}@media(max-width:768px){.app-page-title>div{width:100%}.app-page-title .toolbar{width:100%}.toolbar>*{flex:1 1 calc(50% - 6px)}.toolbar .el-button,.toolbar .el-select,.toolbar .el-input,.toolbar .el-input-number{width:100%!important}.section-head{align-items:flex-start}.section-head>*{width:100%}.table-wrap{-webkit-overflow-scrolling:touch}.table-wrap .el-table{min-width:700px}.el-pagination{width:100%;justify-content:flex-start}}@media(max-width:520px){.toolbar>*{flex-basis:100%}.table-wrap .el-table{min-width:620px}} +.layout-root[data-v-ce83ce8c]{height:100%}.layout-aside[data-v-ce83ce8c]{background:linear-gradient(180deg,#fffffffa,#f8fafcf0);border-right:1px solid var(--app-border);box-shadow:4px 0 16px #0f172a0a}.brand[data-v-ce83ce8c],.drawer-brand[data-v-ce83ce8c]{padding:18px 16px 14px}.brand[data-v-ce83ce8c]{border-bottom:1px solid rgba(15,23,42,.06)}.brand-title[data-v-ce83ce8c]{font-size:16px;font-weight:800;letter-spacing:.2px}.brand-sub[data-v-ce83ce8c]{margin-top:4px;font-size:12px}.aside-menu[data-v-ce83ce8c]{border-right:none;padding:8px;background:transparent}.aside-menu[data-v-ce83ce8c] .el-menu-item{height:42px;line-height:42px;margin:3px 0;border-radius:10px;color:#334155;font-weight:600}.aside-menu[data-v-ce83ce8c] .el-menu-item .el-icon{margin-right:10px}.aside-menu[data-v-ce83ce8c] .el-menu-item:hover{background:#3b82f614;color:#1d4ed8}.aside-menu[data-v-ce83ce8c] .el-menu-item.is-active{background:linear-gradient(135deg,#2563eb1f,#7c3aed1a);color:#1e40af}.menu-label[data-v-ce83ce8c]{display:inline-flex;align-items:center;min-width:0}.menu-badge[data-v-ce83ce8c]{display:inline-flex;align-items:center}.fallback-card[data-v-ce83ce8c]{min-height:160px;border-radius:var(--app-radius-lg);border:1px solid var(--app-border)}.layout-header[data-v-ce83ce8c]{position:sticky;top:0;z-index:20;display:flex;align-items:center;justify-content:space-between;gap:12px;height:58px;padding:0 18px;background:#ffffffc7;-webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);border-bottom:1px solid var(--app-border)}.header-left[data-v-ce83ce8c]{display:flex;align-items:center;gap:10px;min-width:0}.header-title[data-v-ce83ce8c]{font-size:15px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.header-menu-btn[data-v-ce83ce8c]{padding-left:0;padding-right:0}.header-right[data-v-ce83ce8c]{display:flex;align-items:center;gap:12px}.admin-name[data-v-ce83ce8c]{display:flex;align-items:baseline;gap:8px;font-size:13px;color:#334155}.admin-name strong[data-v-ce83ce8c]{color:#0f172a;font-weight:800}.logout-btn[data-v-ce83ce8c]{min-width:74px}.layout-main[data-v-ce83ce8c]{padding:18px}.main-shell[data-v-ce83ce8c]{width:100%;max-width:1600px;margin:0 auto}@media(max-width:768px){.layout-header[data-v-ce83ce8c]{flex-wrap:wrap;height:auto;padding:10px 12px}.header-right[data-v-ce83ce8c]{width:100%;justify-content:flex-end}.admin-name .app-muted[data-v-ce83ce8c],.admin-name strong[data-v-ce83ce8c]{display:none}.layout-main[data-v-ce83ce8c]{padding:12px}}:root{--app-bg: #f4f6fb;--app-text: #111827;--app-muted: #6b7280;--app-border: rgba(15, 23, 42, .1);--app-border-strong: rgba(15, 23, 42, .14);--app-radius: 12px;--app-radius-lg: 14px;--app-shadow-soft: 0 8px 24px rgba(15, 23, 42, .05);--app-shadow: 0 12px 30px rgba(15, 23, 42, .08);--app-card-bg: rgba(255, 255, 255, .94);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}html,body,#app{height:100%}*{box-sizing:border-box}body{margin:0;color:var(--app-text);background:radial-gradient(1200px 500px at -10% -10%,rgba(59,130,246,.12),transparent 55%),radial-gradient(1000px 420px at 110% 0%,rgba(139,92,246,.1),transparent 50%),var(--app-bg)}a{color:inherit;text-decoration:none}.app-page-title{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 14px}.app-page-title h2{margin:0;font-size:19px;font-weight:800;letter-spacing:.2px}.app-muted{color:var(--app-muted)}.page-stack{display:flex;flex-direction:column;gap:14px;min-width:0}.el-card{border-radius:var(--app-radius-lg);border:1px solid var(--app-border);background:var(--app-card-bg);box-shadow:var(--app-shadow-soft)}.el-button{border-radius:10px;font-weight:600}.el-input__wrapper,.el-textarea__inner,.el-select__wrapper,.el-input-number,.el-picker__wrapper{border-radius:10px}.el-table{border-radius:10px;overflow:hidden}.el-table th.el-table__cell{background:#f8fafc;color:#334155;font-weight:700}.el-table td.el-table__cell,.el-table th.el-table__cell{padding-top:11px;padding-bottom:11px}.el-table .el-table__row:hover>td.el-table__cell{background:#f8fbff}.el-tag{border-radius:999px}.el-dialog{border-radius:var(--app-radius-lg)}@media(max-width:768px){.app-page-title{flex-wrap:wrap;align-items:flex-start}.app-page-title h2{font-size:17px}.el-dialog{max-width:92vw}.el-form-item{flex-direction:column;align-items:stretch}.el-form-item__label{width:auto!important;justify-content:flex-start!important;padding:0 0 6px!important;line-height:1.4;text-align:left!important}.el-form-item__content{margin-left:0!important;width:100%}}.section-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.section-title{margin:0;font-size:15px;font-weight:800;letter-spacing:.2px}.toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.table-wrap{overflow-x:auto;border-radius:10px;border:1px solid var(--app-border);background:#fff}.pagination{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint{font-size:12px}.el-tabs__item{font-weight:700}.el-form-item{margin-bottom:18px}@media(max-width:768px){.pagination{justify-content:flex-start}}@media(max-width:900px){.toolbar{width:100%}.toolbar>*{min-width:0}}@media(max-width:768px){.app-page-title>div{width:100%}.app-page-title .toolbar{width:100%}.toolbar>*{flex:1 1 calc(50% - 6px)}.toolbar .el-button,.toolbar .el-select,.toolbar .el-input,.toolbar .el-input-number{width:100%!important}.section-head{align-items:flex-start}.section-head>*{width:100%}.table-wrap{-webkit-overflow-scrolling:touch}.table-wrap .el-table{min-width:700px}.el-pagination{width:100%;justify-content:flex-start}}@media(max-width:520px){.toolbar>*{flex-basis:100%}.table-wrap .el-table{min-width:620px}} diff --git a/static/admin/assets/index-iyjFO6XY.js b/static/admin/assets/index-iyjFO6XY.js new file mode 100644 index 0000000..f47c002 --- /dev/null +++ b/static/admin/assets/index-iyjFO6XY.js @@ -0,0 +1,2 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./ReportPage-BkIhdzJa.js","./vendor-element-CJoVtPsD.js","./vendor-sLgkZK1v.js","./vendor-vue-CWkOjFoA.js","./vendor-element-C68yOrAy.css","./email-BYiWDIoy.js","./tasks-BZsqSMnk.js","./system-Bvj77zeB.js","./MetricGrid-D-x_tNsK.js","./MetricGrid-yP_dkP6X.css","./vendor-axios-B9ygI19o.js","./ReportPage-CnNjCmpq.css","./UsersPage-B5MDfX7T.js","./users-Kctz2ziD.js","./UsersPage-Cow_LicY.css","./FeedbacksPage-yGzwD6JV.js","./FeedbacksPage-mrXjCiV2.css","./LogsPage-WmQFhJZO.js","./LogsPage-D1bozCEo.css","./AnnouncementsPage-BZGpQqUL.js","./AnnouncementsPage-DOwZaaOu.css","./EmailPage-CfIczE0i.js","./EmailPage-BmPCDPYC.css","./SecurityPage-Ay9lQdJs.js","./SecurityPage-DN76ndc_.css","./SystemPage-wAMFferr.js","./SystemPage-DMyNBO3N.css","./SettingsPage-D1k6_4Nn.js","./SettingsPage-DaB8PeRL.css"])))=>i.map(i=>d[i]); +import{aW as m,K as w,A as _,r as O,c as H,v as me,a1 as fe,L as o,N as W,S as d,B as u,z as V,R as z,ak as Y,O as Q,Q as L,P as X,by as pe,p as D,bu as _e}from"./vendor-sLgkZK1v.js";import{u as he,p as ye,q as ge,r as be}from"./vendor-vue-CWkOjFoA.js";import{E as te,f as ne,g as ve,u as we,h as Ee,j as ke,k as Pe,m as Re,n as Te,t as Se,o as Oe,p as Le,z as Ae}from"./vendor-element-CJoVtPsD.js";import{a as xe}from"./vendor-axios-B9ygI19o.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))a(s);new MutationObserver(s=>{for(const l of s)if(l.type==="childList")for(const i of l.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&a(i)}).observe(document,{childList:!0,subtree:!0});function n(s){const l={};return s.integrity&&(l.integrity=s.integrity),s.referrerPolicy&&(l.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?l.credentials="include":s.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function a(s){if(s.ep)return;s.ep=!0;const l=n(s);fetch(s.href,l)}})();const ae=(e,t)=>{const n=e.__vccOpts||e;for(const[a,s]of t)n[a]=s;return n},Ne={};function Be(e,t){const n=m("RouterView");return _(),w(n)}const Ve=ae(Ne,[["render",Be]]),Ce="modulepreload",De=function(e,t){return new URL(e,t).href},J={},E=function(t,n,a){let s=Promise.resolve();if(n&&n.length>0){let T=function(p){return Promise.all(p.map(b=>Promise.resolve(b).then(P=>({status:"fulfilled",value:P}),P=>({status:"rejected",reason:P}))))};const i=document.getElementsByTagName("link"),f=document.querySelector("meta[property=csp-nonce]"),k=f?.nonce||f?.getAttribute("nonce");s=T(n.map(p=>{if(p=De(p,a),p in J)return;J[p]=!0;const b=p.endsWith(".css"),P=b?'[rel="stylesheet"]':"";if(a)for(let R=i.length-1;R>=0;R--){const v=i[R];if(v.href===p&&(!b||v.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${p}"]${P}`))return;const h=document.createElement("link");if(h.rel=b?"stylesheet":Ce,b||(h.as="script"),h.crossOrigin="",h.href=p,k&&h.setAttribute("nonce",k),document.head.appendChild(h),b)return new Promise((R,v)=>{h.addEventListener("load",R),h.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${p}`)))})}))}function l(i){const f=new Event("vite:preloadError",{cancelable:!0});if(f.payload=i,window.dispatchEvent(f),!f.defaultPrevented)throw i}return s.then(i=>{for(const f of i||[])f.status==="rejected"&&l(f.reason);return t().catch(l)})};let Z="",ee=0;const Ie=new Set([408,425,429,500,502,503,504]),Me=1,$e=300;function A(e,t,n=1500){const a=Date.now();e===Z&&a-ee=Me)return!1;const a=String(e?.code||"");if(a==="ECONNABORTED"||a==="ERR_NETWORK")return!0;const s=Number(e?.response?.status||0);return Ie.has(s)}function je(e){return new Promise(t=>{window.setTimeout(t,Math.max(0,Number(e||0)))})}async function Ke(e,t){const n=e?.config||{},a=Number(n.__retry_count||0);n.__retry_count=a+1;const s=$e*(a+1);return await je(s),t.request(n)}const y=xe.create({baseURL:"/yuyx/api",timeout:3e4,withCredentials:!0});let x=null;async function Ge(){return x||(x=te.prompt("请输入管理员密码进行二次确认","安全确认",{inputType:"password",inputPlaceholder:"管理员密码",confirmButtonText:"确认",cancelButtonText:"取消",inputValidator:e=>!!String(e||"").trim(),inputErrorMessage:"密码不能为空"}).then(async e=>{const t=String(e.value||"").trim();await y.post("/admin/reauth",{password:t}),ne.success("已通过安全确认")}).finally(()=>{x=null}),x)}y.interceptors.request.use(e=>{const t=String(e?.method||"GET").toUpperCase();if(!["GET","HEAD","OPTIONS"].includes(t)){const n=Fe("csrf_token");n&&(e.headers=e.headers||{},e.headers["X-CSRF-Token"]=n)}return e});y.interceptors.response.use(e=>e,async e=>{const t=e?.response?.status,n=e?.response?.data,a=n?.error||n?.message||e?.message||"请求失败";if(n?.code==="reauth_required"&&e?.config&&!e.config.__reauth_retry)try{return e.config.__reauth_retry=!0,await Ge(),y.request(e.config)}catch{return Promise.reject(e)}return qe(e)?Ke(e,y):(t===401?(A("401",a,3e3),(window.location?.pathname||"").startsWith("/yuyx")||(window.location.href="/yuyx")):t===403?A("403",a,5e3):t?A(`http:${t}:${a}`,a):e?.code==="ECONNABORTED"?A("timeout","请求超时",3e3):A(`net:${a}`,a,3e3),Promise.reject(e))});async function wt(e=""){const{data:t}=await y.get("/feedbacks",{params:e?{status:e}:{}});return t}async function He(){const{data:e}=await y.get("/feedbacks",{params:{limit:1,offset:0}});return e?.stats}async function Et(e,t){const{data:n}=await y.post(`/feedbacks/${e}/reply`,{reply:t});return n}async function kt(e){const{data:t}=await y.post(`/feedbacks/${e}/close`);return t}async function Pt(e){const{data:t}=await y.delete(`/feedbacks/${e}`);return t}async function We(){const{data:e}=await y.get("/stats");return e}const ze={class:"menu-label"},Ye={key:1,class:"menu-label"},Qe={class:"header-left"},Xe={class:"header-right"},Je={class:"admin-name"},Ze={class:"main-shell"},et={class:"menu-label"},tt={key:1,class:"menu-label"},nt=6e4,at=18e4,st={__name:"AdminLayout",setup(e){const t=he(),n=ye(),a=O({}),s=H(()=>a.value?.admin_username||"");async function l(){try{a.value=await We()}finally{}}const i=O(!1),f=O(0);let k=null;async function T(g=null){if(g&&typeof g=="object"){Object.prototype.hasOwnProperty.call(g,"pendingFeedbacks")&&(f.value=Number(g.pendingFeedbacks||0));return}if(!i.value){i.value=!0;try{const r=await He();f.value=Number(r?.pending||0)}finally{i.value=!1}}}function p(){return typeof document>"u"?!1:document.visibilityState==="hidden"}function b(){return p()?at:nt}function P(){k&&(window.clearTimeout(k),k=null)}function h(){P(),k=window.setTimeout(async()=>{k=null,await T().catch(()=>{}),h()},b())}function R(){h()}D("refreshStats",l),D("adminStats",a),D("refreshNavBadges",T);const v=O(!1),S=O(!1);let N;function C(){v.value=!!N?.matches,v.value||(S.value=!1)}me(async()=>{N=window.matchMedia("(max-width: 768px)"),N.addEventListener?.("change",C),C(),await l(),await T(),h(),window.addEventListener("visibilitychange",R)}),fe(()=>{N?.removeEventListener?.("change",C),P(),window.removeEventListener("visibilitychange",R)});const I=[{path:"/reports",label:"报表",icon:ve},{path:"/users",label:"用户",icon:we},{path:"/feedbacks",label:"反馈",icon:Ee,badgeKey:"feedbacks"},{path:"/logs",label:"任务日志",icon:ke},{path:"/announcements",label:"公告",icon:Pe},{path:"/email",label:"邮件",icon:Re},{path:"/security",label:"安全防护",icon:Te},{path:"/system",label:"系统配置",icon:Se},{path:"/settings",label:"设置",icon:Oe}],M=H(()=>t.path);function B(g){return g?.badgeKey&&g.badgeKey==="feedbacks"?Number(f.value||0):0}async function se(){try{await te.confirm("确定退出管理员登录吗?","退出登录",{confirmButtonText:"退出",cancelButtonText:"取消",type:"warning"})}catch{return}try{await y.post("/logout")}finally{window.location.href="/yuyx"}}async function $(g){await n.push(g),S.value=!1}return(g,r)=>{const F=m("el-icon"),U=m("el-badge"),q=m("el-menu-item"),j=m("el-menu"),oe=m("el-aside"),K=m("el-button"),re=m("el-header"),ce=m("RouterView"),le=m("el-skeleton"),ie=m("el-card"),ue=m("el-main"),G=m("el-container"),de=m("el-drawer");return _(),w(G,{class:"layout-root"},{default:o(()=>[v.value?W("",!0):(_(),w(oe,{key:0,width:"220px",class:"layout-aside"},{default:o(()=>[r[2]||(r[2]=u("div",{class:"brand"},[u("div",{class:"brand-title"},"后台管理"),u("div",{class:"brand-sub app-muted"},"知识管理平台")],-1)),d(j,{"default-active":M.value,class:"aside-menu",router:"",onSelect:$},{default:o(()=>[(_(),V(z,null,Y(I,c=>d(q,{key:c.path,index:c.path},{default:o(()=>[d(F,null,{default:o(()=>[(_(),w(Q(c.icon)))]),_:2},1024),B(c)>0?(_(),w(U,{key:0,value:B(c),max:99,class:"menu-badge"},{default:o(()=>[u("span",ze,L(c.label),1)]),_:2},1032,["value"])):(_(),V("span",Ye,L(c.label),1))]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1})),d(G,null,{default:o(()=>[d(re,{class:"layout-header"},{default:o(()=>[u("div",Qe,[v.value?(_(),w(K,{key:0,text:"",class:"header-menu-btn",onClick:r[0]||(r[0]=c=>S.value=!0)},{default:o(()=>[...r[3]||(r[3]=[X(" 菜单 ",-1)])]),_:1})):W("",!0),r[4]||(r[4]=u("div",{class:"header-title"},"后台管理系统",-1))]),u("div",Xe,[u("div",Je,[r[5]||(r[5]=u("span",{class:"app-muted"},"管理员",-1)),u("strong",null,L(s.value||"-"),1)]),d(K,{type:"primary",plain:"",class:"logout-btn",onClick:se},{default:o(()=>[...r[6]||(r[6]=[X("退出",-1)])]),_:1})])]),_:1}),d(ue,{class:"layout-main"},{default:o(()=>[u("div",Ze,[(_(),w(pe,null,{default:o(()=>[d(ce)]),fallback:o(()=>[d(ie,{shadow:"never","body-style":{padding:"16px"},class:"fallback-card"},{default:o(()=>[d(le,{rows:5,animated:""})]),_:1})]),_:1}))])]),_:1})]),_:1}),d(de,{modelValue:S.value,"onUpdate:modelValue":r[1]||(r[1]=c=>S.value=c),size:"min(82vw, 280px)",direction:"ltr","with-header":!1},{default:o(()=>[r[7]||(r[7]=u("div",{class:"drawer-brand"},[u("div",{class:"brand-title"},"后台管理"),u("div",{class:"brand-sub app-muted"},"知识管理平台")],-1)),d(j,{"default-active":M.value,class:"aside-menu",router:"",onSelect:$},{default:o(()=>[(_(),V(z,null,Y(I,c=>d(q,{key:c.path,index:c.path},{default:o(()=>[d(F,null,{default:o(()=>[(_(),w(Q(c.icon)))]),_:2},1024),B(c)>0?(_(),w(U,{key:0,value:B(c),max:99,class:"menu-badge"},{default:o(()=>[u("span",et,L(c.label),1)]),_:2},1032,["value"])):(_(),V("span",tt,L(c.label),1))]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1},8,["modelValue"])]),_:1})}}},ot=ae(st,[["__scopeId","data-v-ce83ce8c"]]),rt=()=>E(()=>import("./ReportPage-BkIhdzJa.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11]),import.meta.url),ct=()=>E(()=>import("./UsersPage-B5MDfX7T.js"),__vite__mapDeps([12,13,1,2,3,4,10,14]),import.meta.url),lt=()=>E(()=>import("./FeedbacksPage-yGzwD6JV.js"),__vite__mapDeps([15,8,2,9,1,3,4,10,16]),import.meta.url),it=()=>E(()=>import("./LogsPage-WmQFhJZO.js"),__vite__mapDeps([17,13,6,1,2,3,4,10,18]),import.meta.url),ut=()=>E(()=>import("./AnnouncementsPage-BZGpQqUL.js"),__vite__mapDeps([19,1,2,3,4,10,20]),import.meta.url),dt=()=>E(()=>import("./EmailPage-CfIczE0i.js"),__vite__mapDeps([21,5,8,2,9,1,3,4,10,22]),import.meta.url),mt=()=>E(()=>import("./SecurityPage-Ay9lQdJs.js"),__vite__mapDeps([23,8,2,9,1,3,4,10,24]),import.meta.url),ft=()=>E(()=>import("./SystemPage-wAMFferr.js"),__vite__mapDeps([25,7,1,2,3,4,10,26]),import.meta.url),pt=()=>E(()=>import("./SettingsPage-D1k6_4Nn.js"),__vite__mapDeps([27,1,2,3,4,10,28]),import.meta.url),_t=[{path:"/",component:ot,children:[{path:"",redirect:"/reports"},{path:"/pending",redirect:"/reports"},{path:"/stats",redirect:"/reports"},{path:"/reports",name:"reports",component:rt},{path:"/users",name:"users",component:ct},{path:"/feedbacks",name:"feedbacks",component:lt},{path:"/logs",name:"logs",component:it},{path:"/announcements",name:"announcements",component:ut},{path:"/email",name:"email",component:dt},{path:"/security",name:"security",component:mt},{path:"/system",name:"system",component:ft},{path:"/settings",name:"settings",component:pt}]}],ht=ge({history:be(),routes:_t});_e(Ve).use(ht).use(Le,{locale:Ae}).mount("#app");export{ae as _,y as a,wt as b,kt as c,Pt as d,He as f,Et as r}; diff --git a/static/admin/assets/system-In7Gh8x7.js b/static/admin/assets/system-Bvj77zeB.js similarity index 68% rename from static/admin/assets/system-In7Gh8x7.js rename to static/admin/assets/system-Bvj77zeB.js index e4495e5..284e1ee 100644 --- a/static/admin/assets/system-In7Gh8x7.js +++ b/static/admin/assets/system-Bvj77zeB.js @@ -1 +1 @@ -import{a}from"./index-D8t2quK2.js";async function o(){const{data:t}=await a.get("/system/config");return t}async function e(t){const{data:n}=await a.post("/system/config",t);return n}export{o as f,e as u}; +import{a}from"./index-iyjFO6XY.js";async function o(){const{data:t}=await a.get("/system/config");return t}async function e(t){const{data:n}=await a.post("/system/config",t);return n}export{o as f,e as u}; diff --git a/static/admin/assets/tasks-DZnsc1fC.js b/static/admin/assets/tasks-BZsqSMnk.js similarity index 87% rename from static/admin/assets/tasks-DZnsc1fC.js rename to static/admin/assets/tasks-BZsqSMnk.js index 07f853a..3e771e8 100644 --- a/static/admin/assets/tasks-DZnsc1fC.js +++ b/static/admin/assets/tasks-BZsqSMnk.js @@ -1 +1 @@ -import{a}from"./index-D8t2quK2.js";async function c(){const{data:t}=await a.get("/server/info");return t}async function e(){const{data:t}=await a.get("/docker_stats");return t}async function o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f}; +import{a}from"./index-iyjFO6XY.js";async function c(){const{data:t}=await a.get("/server/info");return t}async function e(){const{data:t}=await a.get("/docker_stats");return t}async function o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f}; diff --git a/static/admin/assets/users-CTuo5Ynz.js b/static/admin/assets/users-Kctz2ziD.js similarity index 90% rename from static/admin/assets/users-CTuo5Ynz.js rename to static/admin/assets/users-Kctz2ziD.js index 436c58e..491b8b0 100644 --- a/static/admin/assets/users-CTuo5Ynz.js +++ b/static/admin/assets/users-Kctz2ziD.js @@ -1 +1 @@ -import{a as t}from"./index-D8t2quK2.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s}; +import{a as t}from"./index-iyjFO6XY.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s}; diff --git a/static/admin/index.html b/static/admin/index.html index 9863960..91c0afc 100644 --- a/static/admin/index.html +++ b/static/admin/index.html @@ -5,13 +5,13 @@ 后台管理 - 知识管理平台 - + - +
diff --git a/static/app/.vite/manifest.json b/static/app/.vite/manifest.json index 0ad48cf..b6a923e 100644 --- a/static/app/.vite/manifest.json +++ b/static/app/.vite/manifest.json @@ -1,13 +1,13 @@ { - "_accounts-DpRp0y7G.js": { - "file": "assets/accounts-DpRp0y7G.js", + "_accounts-DWKsGalm.js": { + "file": "assets/accounts-DWKsGalm.js", "name": "accounts", "imports": [ "index.html" ] }, - "_auth-CtTBVBJk.js": { - "file": "assets/auth-CtTBVBJk.js", + "_auth-3qca7BnL.js": { + "file": "assets/auth-3qca7BnL.js", "name": "auth", "imports": [ "index.html" @@ -52,7 +52,7 @@ ] }, "index.html": { - "file": "assets/index-C4rfJ09l.js", + "file": "assets/index-DIRUAu3R.js", "name": "index", "src": "index.html", "isEntry": true, @@ -76,12 +76,12 @@ ] }, "src/pages/AccountsPage.vue": { - "file": "assets/AccountsPage-Cj2MTk-l.js", + "file": "assets/AccountsPage-BsKyQ62c.js", "name": "AccountsPage", "src": "src/pages/AccountsPage.vue", "isDynamicEntry": true, "imports": [ - "_accounts-DpRp0y7G.js", + "_accounts-DWKsGalm.js", "index.html", "_vendor-socket-ciQGyZ7q.js", "_vendor-element-D5SbqSD5.js", @@ -94,14 +94,14 @@ ] }, "src/pages/LoginPage.vue": { - "file": "assets/LoginPage-B4Cm3mBQ.js", + "file": "assets/LoginPage-DjXmnzTj.js", "name": "LoginPage", "src": "src/pages/LoginPage.vue", "isDynamicEntry": true, "imports": [ "_vendor-DR-vtVVc.js", "_vendor-vue-l2lnRGj2.js", - "_auth-CtTBVBJk.js", + "_auth-3qca7BnL.js", "index.html", "_vendor-element-D5SbqSD5.js", "_vendor-axios-B9ygI19o.js" @@ -111,14 +111,14 @@ ] }, "src/pages/RegisterPage.vue": { - "file": "assets/RegisterPage-DDkEhw5Z.js", + "file": "assets/RegisterPage-Nvd-XHp4.js", "name": "RegisterPage", "src": "src/pages/RegisterPage.vue", "isDynamicEntry": true, "imports": [ "_vendor-DR-vtVVc.js", "_vendor-vue-l2lnRGj2.js", - "_auth-CtTBVBJk.js", + "_auth-3qca7BnL.js", "index.html", "_vendor-element-D5SbqSD5.js", "_vendor-axios-B9ygI19o.js" @@ -128,14 +128,14 @@ ] }, "src/pages/ResetPasswordPage.vue": { - "file": "assets/ResetPasswordPage-DTBT5Kre.js", + "file": "assets/ResetPasswordPage-DluVIq7o.js", "name": "ResetPasswordPage", "src": "src/pages/ResetPasswordPage.vue", "isDynamicEntry": true, "imports": [ "_vendor-DR-vtVVc.js", "_vendor-vue-l2lnRGj2.js", - "_auth-CtTBVBJk.js", + "_auth-3qca7BnL.js", "index.html", "_vendor-element-D5SbqSD5.js", "_vendor-axios-B9ygI19o.js" @@ -145,12 +145,12 @@ ] }, "src/pages/SchedulesPage.vue": { - "file": "assets/SchedulesPage-DtRro62b.js", + "file": "assets/SchedulesPage-DglS5EqW.js", "name": "SchedulesPage", "src": "src/pages/SchedulesPage.vue", "isDynamicEntry": true, "imports": [ - "_accounts-DpRp0y7G.js", + "_accounts-DWKsGalm.js", "index.html", "_vendor-element-D5SbqSD5.js", "_vendor-DR-vtVVc.js", @@ -162,7 +162,7 @@ ] }, "src/pages/ScreenshotsPage.vue": { - "file": "assets/ScreenshotsPage-BMPLt3Or.js", + "file": "assets/ScreenshotsPage-L5gmloAw.js", "name": "ScreenshotsPage", "src": "src/pages/ScreenshotsPage.vue", "isDynamicEntry": true, @@ -178,7 +178,7 @@ ] }, "src/pages/VerifyResultPage.vue": { - "file": "assets/VerifyResultPage-CdTQeWQk.js", + "file": "assets/VerifyResultPage-CSJomZjC.js", "name": "VerifyResultPage", "src": "src/pages/VerifyResultPage.vue", "isDynamicEntry": true, diff --git a/static/app/assets/AccountsPage-Cj2MTk-l.js b/static/app/assets/AccountsPage-BsKyQ62c.js similarity index 99% rename from static/app/assets/AccountsPage-Cj2MTk-l.js rename to static/app/assets/AccountsPage-BsKyQ62c.js index 16ecd11..6841dbd 100644 --- a/static/app/assets/AccountsPage-Cj2MTk-l.js +++ b/static/app/assets/AccountsPage-BsKyQ62c.js @@ -1 +1 @@ -import{f as ot,b as Ve,a as Te,c as lt,s as rt,d as it,t as ut,e as dt,g as ct,u as pt,h as ft}from"./accounts-DpRp0y7G.js";import{p as mt,_ as _t,u as vt,f as yt,a as gt,b as wt}from"./index-C4rfJ09l.js";import{l as bt}from"./vendor-socket-ciQGyZ7q.js";import{E as r,h as R}from"./vendor-element-D5SbqSD5.js";import{r as w,a1 as N,w as ae,c as x,v as kt,a0 as ht,z as b,Q as a,I as q,L as O,J as n,aY as f,A as m,B as l,O as c,N as u,u as St,P as J,aj as ne}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function xt(){const{data:oe}=await mt.get("/run_stats");return oe}let Q=null;function Vt(){return Q||(Q=bt({transports:["websocket","polling"],withCredentials:!0}),Q)}const Tt={class:"page"},Ct={class:"stat-value"},At={class:"stat-value"},Pt={class:"stat-value"},Bt={class:"stat-value"},Ut={class:"stat-value"},It={class:"stat-value"},Et={class:"stat-suffix app-muted"},Lt={class:"upgrade-actions"},Nt={class:"panel-head"},Ot={class:"panel-actions"},$t={class:"toolbar"},zt={class:"toolbar-left"},Kt={class:"app-muted"},Dt={class:"toolbar-middle"},Mt={class:"toolbar-right"},Rt={key:1,class:"grid"},qt={class:"card-top"},Ht={class:"card-main"},jt={class:"card-title"},Ft={class:"card-name"},Gt={class:"card-sub app-muted"},Yt={key:0},Jt={key:1},Qt={key:2},Wt={key:3},Xt={key:0,class:"progress"},Zt={class:"progress-meta app-muted"},es={class:"card-controls"},ts={class:"card-buttons"},Ce="zsglpt:accounts:enable_screenshot",ss=1e4,as=3e4,ns=6e4,os=18e4,ls={__name:"AccountsPage",setup(oe){const V=vt(),S=Vt(),H=w(!1),le=w(!1),k=N({today_completed:0,today_failed:0,current_running:0,today_items:0,today_attachments:0}),T=N({}),v=w([]),C=N({}),j=w("应读");function Ae(){try{const t=window.localStorage.getItem(Ce);if(t==="0"||t==="false")return!1;if(t==="1"||t==="true")return!0}catch{}return!0}const A=w(Ae());ae(A,t=>{try{window.localStorage.setItem(Ce,t?"1":"0")}catch{}});const $=w(!1),z=w(!1),h=N({enabled:!1,online:!1,message:""}),re=w(!1),K=w(!1),P=w(!1),D=w(!1),_=N({username:"",password:"",remark:""}),d=N({id:"",username:"",password:"",remark:"",originalRemark:""}),ie=[{label:"应读",value:"应读"},{label:"注册前未读",value:"注册前未读"}],y=x(()=>Object.values(T).sort((t,e)=>String(t.username||"").localeCompare(String(e.username||""),"zh-CN"))),W=x(()=>y.value.length),Pe=x(()=>V.isVip?999:3),ue=x(()=>v.value.length),Be=x(()=>W.value>0&&ue.value===W.value),Ue=x(()=>!V.isVip);function M(t){const e=T[t.id]||{};T[t.id]={...e,...t}}function X(t){const e=Array.isArray(t)?t:[],o=new Set(e.map(i=>String(i?.id||"")));for(const i of Object.keys(T))o.has(i)||delete T[i];for(const i of e)M(i)}function Ie(){for(const t of y.value)C[t.id]||(C[t.id]="应读")}ae(y,Ie,{immediate:!0});function Ee(t){t?v.value=y.value.map(e=>e.id):v.value=[]}function F(t){return V.isVip?!0:(r.warning(`${t}是VIP专属功能`),D.value=!0,!1)}function Le(t){const e=Number(t.total_items||0),o=Number(t.progress_items||0);return e?Math.max(0,Math.min(100,Math.round(o/e*100))):0}function Ne(t=""){const e=String(t);return e.includes("已完成")||e.includes("完成")?"success":e.includes("失败")||e.includes("错误")||e.includes("异常")||e.includes("登录失败")||e.includes("上传截图")?"danger":e.includes("等待上传")||e.includes("排队")||e.includes("运行")||e.includes("截图")?"warning":"info"}function G(t){if(!t?.is_running)return!1;const e=String(t.status||""),o=String(t.detail_status||"");return!(!e||e==="未开始"||!e.includes("运行")||e.includes("截图")||e.includes("等待截图")||o.includes("截图")||o.includes("等待截图")||o.includes("浏览完成")||o.includes("任务完成")||e.includes("已完成"))}async function B(t={}){const e=!!t?.silent;e||(le.value=!0);try{const o=await xt();k.today_completed=Number(o?.today_completed||0),k.today_failed=Number(o?.today_failed||0),k.current_running=Number(o?.current_running||0),k.today_items=Number(o?.today_items||0),k.today_attachments=Number(o?.today_attachments||0)}catch(o){o?.response?.status===401&&(window.location.href="/login")}finally{e||(le.value=!1)}}async function de(){H.value=!0;try{const t=await ot({refresh:!0});X(t)}catch(t){t?.response?.status===401&&(window.location.href="/login")}finally{H.value=!1}}async function Oe(){z.value=!0;try{const t=await yt();$.value=Number(t?.kdocs_auto_upload||0)===1}catch{$.value=!1}finally{z.value=!1}}async function ce(){re.value=!0;try{const t=await gt();h.enabled=!!t?.enabled,h.online=!!t?.online,h.message=t?.message||""}catch{h.enabled=!1,h.online=!1,h.message=""}finally{re.value=!1}}async function $e(t){z.value=!0;try{await wt({kdocs_auto_upload:t?1:0}),r.success(t?"已开启自动上传(测试)":"已关闭自动上传")}catch{$.value=!t}finally{z.value=!1}}async function ze(t){try{await rt(t.id,{browse_type:C[t.id]||"应读",enable_screenshot:A.value})}catch(e){const o=e?.response?.data;r.error(o?.error||"启动失败")}}async function Ke(t){try{await it(t.id)}catch(e){const o=e?.response?.data;r.error(o?.error||"停止失败")}}async function De(t){try{await ut(t.id,{browse_type:C[t.id]||"应读"}),r.success("已提交截图")}catch(e){const o=e?.response?.data;r.error(o?.error||"截图失败")}}async function Me(t){try{await R.confirm(`确定要删除账号「${t.username}」吗?`,"删除账号",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await dt(t.id);e?.success?(delete T[t.id],v.value=v.value.filter(o=>o!==t.id),r.success("已删除"),await B()):r.error(e?.error||"删除失败")}catch(e){const o=e?.response?.data;r.error(o?.error||"删除失败")}}function Re(){_.username="",_.password="",_.remark="",K.value=!0}async function qe(){const t=_.username.trim();if(!t||!_.password.trim()){r.error("用户名和密码不能为空");return}try{await ct({username:t,password:_.password,remember:!0,remark:_.remark.trim()}),r.success("添加成功"),K.value=!1,await B()}catch(e){const o=e?.response?.data;r.error(o?.error||"添加失败")}}function He(t){d.id=t.id,d.username=t.username,d.password="",d.remark=String(t.remark||""),d.originalRemark=String(t.remark||""),P.value=!0}async function je(){if(!d.id)return;const t=d.password.trim(),e=d.remark.trim();if(!t&&e===d.originalRemark){r.info("没有修改"),P.value=!1;return}try{if(t){const o=await pt(d.id,{password:t,remember:!0});o?.account&&M(o.account)}e!==d.originalRemark&&(await ft(d.id,{remark:e}),M({id:d.id,remark:e})),r.success("已更新"),P.value=!1}catch(o){const i=o?.response?.data;r.error(i?.error||"更新失败")}}async function Fe(){if(F("批量操作")){if(v.value.length===0){r.warning("请先选择账号");return}try{const t=await Ve({account_ids:v.value,browse_type:j.value,enable_screenshot:A.value});r.success(`已启动 ${t?.started_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Ge(){if(F("批量操作")){if(v.value.length===0){r.warning("请先选择账号");return}try{const t=await Te({account_ids:v.value});r.success(`已停止 ${t?.stopped_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Ye(){if(F("全部启动")){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要启动全部账号吗?","全部启动",{confirmButtonText:"启动",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await Ve({account_ids:y.value.map(e=>e.id),browse_type:j.value,enable_screenshot:A.value});r.success(`已启动 ${t?.started_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Je(){if(F("全部停止")){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要停止全部账号吗?","全部停止",{confirmButtonText:"停止",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await Te({account_ids:y.value.map(e=>e.id)});r.success(`已停止 ${t?.stopped_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Qe(){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要清空所有账号吗?此操作不可恢复!","清空账号",{confirmButtonText:"继续",cancelButtonText:"取消",type:"warning"}),await R.confirm("再次确认:真的要删除所有账号吗?","二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await lt();if(t?.success){X([]),v.value=[],r.success("已清空所有账号"),await B();return}r.error(t?.error||"操作失败")}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}function We(){const t=i=>{X(i)},e=i=>{M(i)},o=i=>{i?.account_id&&M({id:i.account_id,detail_status:i.stage||"",total_items:i.total_items,progress_items:i.browsed_items,total_attachments:i.total_attachments,progress_attachments:i.viewed_attachments,elapsed_seconds:i.elapsed_seconds,elapsed_display:i.elapsed_display})};return S.on("accounts_list",t),S.on("account_update",e),S.on("task_progress",o),S.connected||S.connect(),()=>{S.off("accounts_list",t),S.off("account_update",e),S.off("task_progress",o)}}let Z=null,U=null,I=null;function pe(){return typeof document>"u"?!1:document.visibilityState==="hidden"}const Y=x(()=>y.value.some(t=>!(!t?.is_running||String(t.status||"").includes("排队"))));function Xe(){return pe()?as:ss}function ee(){U&&(window.clearTimeout(U),U=null)}function fe(){U||!Y.value||(U=window.setTimeout(async()=>{U=null,await B({silent:!0}).catch(()=>{}),fe()},Xe()))}function me(){fe()}function _e(t=null){const e=Y.value;t===!0&&e===!1&&B({silent:!0}).catch(()=>{}),e?me():ee()}ae(Y,(t,e)=>{_e(e)});function Ze(){return pe()?os:ns}function ve(){I&&(window.clearTimeout(I),I=null)}function te(){I||(I=window.setTimeout(async()=>{I=null,await ce().catch(()=>{}),te()},Ze()))}function ye(){Y.value&&(ee(),me()),ve(),te()}return kt(async()=>{V.vipInfo||V.refreshVipInfo().catch(()=>{window.location.href="/login"}),Z=We(),await de(),await Oe(),await ce(),await B(),_e(),te(),window.addEventListener("visibilitychange",ye)}),ht(()=>{Z&&Z(),ee(),ve(),window.removeEventListener("visibilitychange",ye)}),(t,e)=>{const o=f("el-card"),i=f("el-col"),et=f("el-row"),p=f("el-button"),ge=f("el-alert"),we=f("el-checkbox"),be=f("el-option"),ke=f("el-select"),he=f("el-switch"),Se=f("el-tag"),tt=f("el-skeleton"),st=f("el-empty"),at=f("el-checkbox-group"),nt=f("el-progress"),E=f("el-input"),L=f("el-form-item"),xe=f("el-form"),se=f("el-dialog");return m(),b("div",Tt,[a(et,{gutter:12,class:"stats-row"},{default:n(()=>[a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[17]||(e[17]=l("div",{class:"stat-label app-muted"},"今日完成",-1)),l("div",Ct,c(k.today_completed),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[18]||(e[18]=l("div",{class:"stat-label app-muted"},"今日失败",-1)),l("div",At,c(k.today_failed),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[19]||(e[19]=l("div",{class:"stat-label app-muted"},"运行中",-1)),l("div",Pt,c(k.current_running),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[20]||(e[20]=l("div",{class:"stat-label app-muted"},"浏览内容",-1)),l("div",Bt,c(k.today_items),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[21]||(e[21]=l("div",{class:"stat-label app-muted"},"查看附件",-1)),l("div",Ut,c(k.today_attachments),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[22]||(e[22]=l("div",{class:"stat-label app-muted"},"账号数",-1)),l("div",It,[u(c(W.value),1),l("span",Et,"/ "+c(St(V).isVip?"∞":Pe.value),1)])]),_:1})]),_:1})]),_:1}),Ue.value?(m(),q(ge,{key:0,type:"info","show-icon":"",closable:!1,class:"upgrade-banner",title:"升级 VIP,解锁更多功能:无限账号 · 优先排队 · 定时任务 · 批量操作"},{default:n(()=>[l("div",Lt,[a(p,{type:"primary",plain:"",onClick:e[0]||(e[0]=s=>D.value=!0)},{default:n(()=>[...e[23]||(e[23]=[u("了解VIP特权",-1)])]),_:1})])]),_:1})):O("",!0),a(o,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:n(()=>[l("div",Nt,[e[26]||(e[26]=l("div",{class:"panel-title"},"账号管理",-1)),l("div",Ot,[a(p,{loading:H.value,onClick:de},{default:n(()=>[...e[24]||(e[24]=[u("刷新",-1)])]),_:1},8,["loading"]),a(p,{type:"primary",onClick:Re},{default:n(()=>[...e[25]||(e[25]=[u("添加账号",-1)])]),_:1})])]),l("div",$t,[l("div",zt,[a(we,{"model-value":Be.value,onChange:Ee},{default:n(()=>[...e[27]||(e[27]=[u("全选",-1)])]),_:1},8,["model-value"]),l("span",Kt,"已选 "+c(ue.value)+" 个",1)]),l("div",Dt,[a(ke,{modelValue:j.value,"onUpdate:modelValue":e[1]||(e[1]=s=>j.value=s),size:"small",style:{width:"120px"}},{default:n(()=>[(m(),b(J,null,ne(ie,s=>a(be,{key:s.value,label:s.label,value:s.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),a(he,{modelValue:A.value,"onUpdate:modelValue":e[2]||(e[2]=s=>A.value=s),"inline-prompt":"","active-text":"截图","inactive-text":"不截图"},null,8,["modelValue"]),a(he,{modelValue:$.value,"onUpdate:modelValue":e[3]||(e[3]=s=>$.value=s),disabled:z.value,"inline-prompt":"","active-text":"上传","inactive-text":"不传",onChange:$e},null,8,["modelValue","disabled"]),e[28]||(e[28]=l("span",{class:"app-muted"},"表格(测试)",-1)),h.enabled?(m(),q(Se,{key:0,type:h.online?"success":"warning",size:"small",effect:"plain"},{default:n(()=>[u(c(h.online?"✅ 就绪":"⚠️ 离线"),1)]),_:1},8,["type"])):O("",!0)]),l("div",Mt,[a(p,{type:"primary",onClick:Fe},{default:n(()=>[...e[29]||(e[29]=[u("批量启动",-1)])]),_:1}),a(p,{onClick:Ge},{default:n(()=>[...e[30]||(e[30]=[u("批量停止",-1)])]),_:1}),a(p,{type:"success",plain:"",onClick:Ye},{default:n(()=>[...e[31]||(e[31]=[u("全部启动",-1)])]),_:1}),a(p,{type:"danger",plain:"",onClick:Je},{default:n(()=>[...e[32]||(e[32]=[u("全部停止",-1)])]),_:1}),a(p,{type:"danger",text:"",onClick:Qe},{default:n(()=>[...e[33]||(e[33]=[u("清空",-1)])]),_:1})])]),H.value?(m(),q(tt,{key:0,rows:5,animated:""})):(m(),b(J,{key:1},[y.value.length===0?(m(),q(st,{key:0,description:"暂无账号,点击右上角添加"})):(m(),b("div",Rt,[(m(!0),b(J,null,ne(y.value,s=>(m(),q(o,{key:s.id,shadow:"never",class:"account-card","body-style":{padding:"14px"}},{default:n(()=>[l("div",qt,[a(at,{modelValue:v.value,"onUpdate:modelValue":e[4]||(e[4]=g=>v.value=g),class:"card-check"},{default:n(()=>[a(we,{value:s.id},null,8,["value"])]),_:2},1032,["modelValue"]),l("div",Ht,[l("div",jt,[l("span",Ft,c(s.username),1),a(Se,{size:"small",type:Ne(s.status),effect:"light"},{default:n(()=>[u(c(s.status),1)]),_:2},1032,["type"])]),l("div",Gt,[u(c(s.remark||"—")+" ",1),G(s)&&s.detail_status?(m(),b("span",Yt," · "+c(s.detail_status),1)):O("",!0),G(s)&&s.elapsed_display?(m(),b("span",Jt," · "+c(s.elapsed_display),1)):O("",!0),String(s.status||"").includes("排队")&&s.queue_ahead!=null?(m(),b("span",Qt," · 前面 "+c(s.queue_ahead)+" 个 · 运行中 "+c(s.queue_running_total??0)+" 个 ",1)):G(s)&&(s.queue_pending_total!=null||s.queue_running_total!=null)?(m(),b("span",Wt," · 排队 "+c(s.queue_pending_total??0)+" 个 · 运行中 "+c(s.queue_running_total??0)+" 个 ",1)):O("",!0)])])]),G(s)?(m(),b("div",Xt,[a(nt,{percentage:Le(s),"stroke-width":10,"show-text":!1},null,8,["percentage"]),l("div",Zt,[l("span",null,"内容 "+c(s.progress_items||0),1)])])):O("",!0),l("div",es,[a(ke,{modelValue:C[s.id],"onUpdate:modelValue":g=>C[s.id]=g,size:"small",style:{width:"130px"}},{default:n(()=>[(m(),b(J,null,ne(ie,g=>a(be,{key:g.value,label:g.label,value:g.value},null,8,["label","value"])),64))]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",ts,[a(p,{size:"small",type:"primary",disabled:s.is_running,onClick:g=>ze(s)},{default:n(()=>[...e[34]||(e[34]=[u("启动",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:!s.is_running,onClick:g=>Ke(s)},{default:n(()=>[...e[35]||(e[35]=[u("停止",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:s.is_running,onClick:g=>De(s)},{default:n(()=>[...e[36]||(e[36]=[u("截图",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:s.is_running,onClick:g=>He(s)},{default:n(()=>[...e[37]||(e[37]=[u("编辑",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",type:"danger",text:"",onClick:g=>Me(s)},{default:n(()=>[...e[38]||(e[38]=[u("删除",-1)])]),_:1},8,["onClick"])])])]),_:2},1024))),128))]))],64))]),_:1}),a(se,{modelValue:K.value,"onUpdate:modelValue":e[9]||(e[9]=s=>K.value=s),title:"添加账号",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{onClick:e[8]||(e[8]=s=>K.value=!1)},{default:n(()=>[...e[39]||(e[39]=[u("取消",-1)])]),_:1}),a(p,{type:"primary",onClick:qe},{default:n(()=>[...e[40]||(e[40]=[u("添加",-1)])]),_:1})]),default:n(()=>[a(xe,{"label-position":"top"},{default:n(()=>[a(L,{label:"账号"},{default:n(()=>[a(E,{modelValue:_.username,"onUpdate:modelValue":e[5]||(e[5]=s=>_.username=s),placeholder:"请输入账号",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"密码"},{default:n(()=>[a(E,{modelValue:_.password,"onUpdate:modelValue":e[6]||(e[6]=s=>_.password=s),type:"password","show-password":"",placeholder:"请输入密码",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"备注(可选,最多200字)"},{default:n(()=>[a(E,{modelValue:_.remark,"onUpdate:modelValue":e[7]||(e[7]=s=>_.remark=s),type:"textarea",rows:3,maxlength:"200","show-word-limit":"",placeholder:"例如:部门/用途"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"]),a(se,{modelValue:P.value,"onUpdate:modelValue":e[14]||(e[14]=s=>P.value=s),title:"编辑账号",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{onClick:e[13]||(e[13]=s=>P.value=!1)},{default:n(()=>[...e[41]||(e[41]=[u("取消",-1)])]),_:1}),a(p,{type:"primary",onClick:je},{default:n(()=>[...e[42]||(e[42]=[u("保存",-1)])]),_:1})]),default:n(()=>[a(xe,{"label-position":"top"},{default:n(()=>[a(L,{label:"账号"},{default:n(()=>[a(E,{modelValue:d.username,"onUpdate:modelValue":e[10]||(e[10]=s=>d.username=s),disabled:""},null,8,["modelValue"])]),_:1}),a(L,{label:"新密码(可选)"},{default:n(()=>[a(E,{modelValue:d.password,"onUpdate:modelValue":e[11]||(e[11]=s=>d.password=s),type:"password","show-password":"",placeholder:"留空表示不修改密码",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"备注(可选,最多200字)"},{default:n(()=>[a(E,{modelValue:d.remark,"onUpdate:modelValue":e[12]||(e[12]=s=>d.remark=s),type:"textarea",rows:3,maxlength:"200","show-word-limit":"",placeholder:"例如:部门/用途"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"]),a(se,{modelValue:D.value,"onUpdate:modelValue":e[16]||(e[16]=s=>D.value=s),title:"VIP 特权",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{type:"primary",onClick:e[15]||(e[15]=s=>D.value=!1)},{default:n(()=>[...e[43]||(e[43]=[u("我知道了",-1)])]),_:1})]),default:n(()=>[a(ge,{type:"info",closable:!1,title:"升级 VIP 后可解锁:无限账号、优先排队、定时任务、批量操作。","show-icon":""}),e[44]||(e[44]=l("div",{class:"vip-body"},[l("div",{class:"vip-tip app-muted"},"升级方式:请通过“反馈”联系管理员开通(与后台一致)。")],-1))]),_:1},8,["modelValue"])])}}},ms=_t(ls,[["__scopeId","data-v-a3d05837"]]);export{ms as default}; +import{f as ot,b as Ve,a as Te,c as lt,s as rt,d as it,t as ut,e as dt,g as ct,u as pt,h as ft}from"./accounts-DWKsGalm.js";import{p as mt,_ as _t,u as vt,f as yt,a as gt,b as wt}from"./index-DIRUAu3R.js";import{l as bt}from"./vendor-socket-ciQGyZ7q.js";import{E as r,h as R}from"./vendor-element-D5SbqSD5.js";import{r as w,a1 as N,w as ae,c as x,v as kt,a0 as ht,z as b,Q as a,I as q,L as O,J as n,aY as f,A as m,B as l,O as c,N as u,u as St,P as J,aj as ne}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function xt(){const{data:oe}=await mt.get("/run_stats");return oe}let Q=null;function Vt(){return Q||(Q=bt({transports:["websocket","polling"],withCredentials:!0}),Q)}const Tt={class:"page"},Ct={class:"stat-value"},At={class:"stat-value"},Pt={class:"stat-value"},Bt={class:"stat-value"},Ut={class:"stat-value"},It={class:"stat-value"},Et={class:"stat-suffix app-muted"},Lt={class:"upgrade-actions"},Nt={class:"panel-head"},Ot={class:"panel-actions"},$t={class:"toolbar"},zt={class:"toolbar-left"},Kt={class:"app-muted"},Dt={class:"toolbar-middle"},Mt={class:"toolbar-right"},Rt={key:1,class:"grid"},qt={class:"card-top"},Ht={class:"card-main"},jt={class:"card-title"},Ft={class:"card-name"},Gt={class:"card-sub app-muted"},Yt={key:0},Jt={key:1},Qt={key:2},Wt={key:3},Xt={key:0,class:"progress"},Zt={class:"progress-meta app-muted"},es={class:"card-controls"},ts={class:"card-buttons"},Ce="zsglpt:accounts:enable_screenshot",ss=1e4,as=3e4,ns=6e4,os=18e4,ls={__name:"AccountsPage",setup(oe){const V=vt(),S=Vt(),H=w(!1),le=w(!1),k=N({today_completed:0,today_failed:0,current_running:0,today_items:0,today_attachments:0}),T=N({}),v=w([]),C=N({}),j=w("应读");function Ae(){try{const t=window.localStorage.getItem(Ce);if(t==="0"||t==="false")return!1;if(t==="1"||t==="true")return!0}catch{}return!0}const A=w(Ae());ae(A,t=>{try{window.localStorage.setItem(Ce,t?"1":"0")}catch{}});const $=w(!1),z=w(!1),h=N({enabled:!1,online:!1,message:""}),re=w(!1),K=w(!1),P=w(!1),D=w(!1),_=N({username:"",password:"",remark:""}),d=N({id:"",username:"",password:"",remark:"",originalRemark:""}),ie=[{label:"应读",value:"应读"},{label:"注册前未读",value:"注册前未读"}],y=x(()=>Object.values(T).sort((t,e)=>String(t.username||"").localeCompare(String(e.username||""),"zh-CN"))),W=x(()=>y.value.length),Pe=x(()=>V.isVip?999:3),ue=x(()=>v.value.length),Be=x(()=>W.value>0&&ue.value===W.value),Ue=x(()=>!V.isVip);function M(t){const e=T[t.id]||{};T[t.id]={...e,...t}}function X(t){const e=Array.isArray(t)?t:[],o=new Set(e.map(i=>String(i?.id||"")));for(const i of Object.keys(T))o.has(i)||delete T[i];for(const i of e)M(i)}function Ie(){for(const t of y.value)C[t.id]||(C[t.id]="应读")}ae(y,Ie,{immediate:!0});function Ee(t){t?v.value=y.value.map(e=>e.id):v.value=[]}function F(t){return V.isVip?!0:(r.warning(`${t}是VIP专属功能`),D.value=!0,!1)}function Le(t){const e=Number(t.total_items||0),o=Number(t.progress_items||0);return e?Math.max(0,Math.min(100,Math.round(o/e*100))):0}function Ne(t=""){const e=String(t);return e.includes("已完成")||e.includes("完成")?"success":e.includes("失败")||e.includes("错误")||e.includes("异常")||e.includes("登录失败")||e.includes("上传截图")?"danger":e.includes("等待上传")||e.includes("排队")||e.includes("运行")||e.includes("截图")?"warning":"info"}function G(t){if(!t?.is_running)return!1;const e=String(t.status||""),o=String(t.detail_status||"");return!(!e||e==="未开始"||!e.includes("运行")||e.includes("截图")||e.includes("等待截图")||o.includes("截图")||o.includes("等待截图")||o.includes("浏览完成")||o.includes("任务完成")||e.includes("已完成"))}async function B(t={}){const e=!!t?.silent;e||(le.value=!0);try{const o=await xt();k.today_completed=Number(o?.today_completed||0),k.today_failed=Number(o?.today_failed||0),k.current_running=Number(o?.current_running||0),k.today_items=Number(o?.today_items||0),k.today_attachments=Number(o?.today_attachments||0)}catch(o){o?.response?.status===401&&(window.location.href="/login")}finally{e||(le.value=!1)}}async function de(){H.value=!0;try{const t=await ot({refresh:!0});X(t)}catch(t){t?.response?.status===401&&(window.location.href="/login")}finally{H.value=!1}}async function Oe(){z.value=!0;try{const t=await yt();$.value=Number(t?.kdocs_auto_upload||0)===1}catch{$.value=!1}finally{z.value=!1}}async function ce(){re.value=!0;try{const t=await gt();h.enabled=!!t?.enabled,h.online=!!t?.online,h.message=t?.message||""}catch{h.enabled=!1,h.online=!1,h.message=""}finally{re.value=!1}}async function $e(t){z.value=!0;try{await wt({kdocs_auto_upload:t?1:0}),r.success(t?"已开启自动上传(测试)":"已关闭自动上传")}catch{$.value=!t}finally{z.value=!1}}async function ze(t){try{await rt(t.id,{browse_type:C[t.id]||"应读",enable_screenshot:A.value})}catch(e){const o=e?.response?.data;r.error(o?.error||"启动失败")}}async function Ke(t){try{await it(t.id)}catch(e){const o=e?.response?.data;r.error(o?.error||"停止失败")}}async function De(t){try{await ut(t.id,{browse_type:C[t.id]||"应读"}),r.success("已提交截图")}catch(e){const o=e?.response?.data;r.error(o?.error||"截图失败")}}async function Me(t){try{await R.confirm(`确定要删除账号「${t.username}」吗?`,"删除账号",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await dt(t.id);e?.success?(delete T[t.id],v.value=v.value.filter(o=>o!==t.id),r.success("已删除"),await B()):r.error(e?.error||"删除失败")}catch(e){const o=e?.response?.data;r.error(o?.error||"删除失败")}}function Re(){_.username="",_.password="",_.remark="",K.value=!0}async function qe(){const t=_.username.trim();if(!t||!_.password.trim()){r.error("用户名和密码不能为空");return}try{await ct({username:t,password:_.password,remember:!0,remark:_.remark.trim()}),r.success("添加成功"),K.value=!1,await B()}catch(e){const o=e?.response?.data;r.error(o?.error||"添加失败")}}function He(t){d.id=t.id,d.username=t.username,d.password="",d.remark=String(t.remark||""),d.originalRemark=String(t.remark||""),P.value=!0}async function je(){if(!d.id)return;const t=d.password.trim(),e=d.remark.trim();if(!t&&e===d.originalRemark){r.info("没有修改"),P.value=!1;return}try{if(t){const o=await pt(d.id,{password:t,remember:!0});o?.account&&M(o.account)}e!==d.originalRemark&&(await ft(d.id,{remark:e}),M({id:d.id,remark:e})),r.success("已更新"),P.value=!1}catch(o){const i=o?.response?.data;r.error(i?.error||"更新失败")}}async function Fe(){if(F("批量操作")){if(v.value.length===0){r.warning("请先选择账号");return}try{const t=await Ve({account_ids:v.value,browse_type:j.value,enable_screenshot:A.value});r.success(`已启动 ${t?.started_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Ge(){if(F("批量操作")){if(v.value.length===0){r.warning("请先选择账号");return}try{const t=await Te({account_ids:v.value});r.success(`已停止 ${t?.stopped_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Ye(){if(F("全部启动")){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要启动全部账号吗?","全部启动",{confirmButtonText:"启动",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await Ve({account_ids:y.value.map(e=>e.id),browse_type:j.value,enable_screenshot:A.value});r.success(`已启动 ${t?.started_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Je(){if(F("全部停止")){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要停止全部账号吗?","全部停止",{confirmButtonText:"停止",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await Te({account_ids:y.value.map(e=>e.id)});r.success(`已停止 ${t?.stopped_count||0} 个账号`)}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}}async function Qe(){if(y.value.length===0){r.warning("没有账号");return}try{await R.confirm("确定要清空所有账号吗?此操作不可恢复!","清空账号",{confirmButtonText:"继续",cancelButtonText:"取消",type:"warning"}),await R.confirm("再次确认:真的要删除所有账号吗?","二次确认",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await lt();if(t?.success){X([]),v.value=[],r.success("已清空所有账号"),await B();return}r.error(t?.error||"操作失败")}catch(t){const e=t?.response?.data;r.error(e?.error||"操作失败")}}function We(){const t=i=>{X(i)},e=i=>{M(i)},o=i=>{i?.account_id&&M({id:i.account_id,detail_status:i.stage||"",total_items:i.total_items,progress_items:i.browsed_items,total_attachments:i.total_attachments,progress_attachments:i.viewed_attachments,elapsed_seconds:i.elapsed_seconds,elapsed_display:i.elapsed_display})};return S.on("accounts_list",t),S.on("account_update",e),S.on("task_progress",o),S.connected||S.connect(),()=>{S.off("accounts_list",t),S.off("account_update",e),S.off("task_progress",o)}}let Z=null,U=null,I=null;function pe(){return typeof document>"u"?!1:document.visibilityState==="hidden"}const Y=x(()=>y.value.some(t=>!(!t?.is_running||String(t.status||"").includes("排队"))));function Xe(){return pe()?as:ss}function ee(){U&&(window.clearTimeout(U),U=null)}function fe(){U||!Y.value||(U=window.setTimeout(async()=>{U=null,await B({silent:!0}).catch(()=>{}),fe()},Xe()))}function me(){fe()}function _e(t=null){const e=Y.value;t===!0&&e===!1&&B({silent:!0}).catch(()=>{}),e?me():ee()}ae(Y,(t,e)=>{_e(e)});function Ze(){return pe()?os:ns}function ve(){I&&(window.clearTimeout(I),I=null)}function te(){I||(I=window.setTimeout(async()=>{I=null,await ce().catch(()=>{}),te()},Ze()))}function ye(){Y.value&&(ee(),me()),ve(),te()}return kt(async()=>{V.vipInfo||V.refreshVipInfo().catch(()=>{window.location.href="/login"}),Z=We(),await de(),await Oe(),await ce(),await B(),_e(),te(),window.addEventListener("visibilitychange",ye)}),ht(()=>{Z&&Z(),ee(),ve(),window.removeEventListener("visibilitychange",ye)}),(t,e)=>{const o=f("el-card"),i=f("el-col"),et=f("el-row"),p=f("el-button"),ge=f("el-alert"),we=f("el-checkbox"),be=f("el-option"),ke=f("el-select"),he=f("el-switch"),Se=f("el-tag"),tt=f("el-skeleton"),st=f("el-empty"),at=f("el-checkbox-group"),nt=f("el-progress"),E=f("el-input"),L=f("el-form-item"),xe=f("el-form"),se=f("el-dialog");return m(),b("div",Tt,[a(et,{gutter:12,class:"stats-row"},{default:n(()=>[a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[17]||(e[17]=l("div",{class:"stat-label app-muted"},"今日完成",-1)),l("div",Ct,c(k.today_completed),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[18]||(e[18]=l("div",{class:"stat-label app-muted"},"今日失败",-1)),l("div",At,c(k.today_failed),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[19]||(e[19]=l("div",{class:"stat-label app-muted"},"运行中",-1)),l("div",Pt,c(k.current_running),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[20]||(e[20]=l("div",{class:"stat-label app-muted"},"浏览内容",-1)),l("div",Bt,c(k.today_items),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[21]||(e[21]=l("div",{class:"stat-label app-muted"},"查看附件",-1)),l("div",Ut,c(k.today_attachments),1)]),_:1})]),_:1}),a(i,{xs:12,sm:8,md:4},{default:n(()=>[a(o,{shadow:"never",class:"stat-card","body-style":{padding:"14px"}},{default:n(()=>[e[22]||(e[22]=l("div",{class:"stat-label app-muted"},"账号数",-1)),l("div",It,[u(c(W.value),1),l("span",Et,"/ "+c(St(V).isVip?"∞":Pe.value),1)])]),_:1})]),_:1})]),_:1}),Ue.value?(m(),q(ge,{key:0,type:"info","show-icon":"",closable:!1,class:"upgrade-banner",title:"升级 VIP,解锁更多功能:无限账号 · 优先排队 · 定时任务 · 批量操作"},{default:n(()=>[l("div",Lt,[a(p,{type:"primary",plain:"",onClick:e[0]||(e[0]=s=>D.value=!0)},{default:n(()=>[...e[23]||(e[23]=[u("了解VIP特权",-1)])]),_:1})])]),_:1})):O("",!0),a(o,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:n(()=>[l("div",Nt,[e[26]||(e[26]=l("div",{class:"panel-title"},"账号管理",-1)),l("div",Ot,[a(p,{loading:H.value,onClick:de},{default:n(()=>[...e[24]||(e[24]=[u("刷新",-1)])]),_:1},8,["loading"]),a(p,{type:"primary",onClick:Re},{default:n(()=>[...e[25]||(e[25]=[u("添加账号",-1)])]),_:1})])]),l("div",$t,[l("div",zt,[a(we,{"model-value":Be.value,onChange:Ee},{default:n(()=>[...e[27]||(e[27]=[u("全选",-1)])]),_:1},8,["model-value"]),l("span",Kt,"已选 "+c(ue.value)+" 个",1)]),l("div",Dt,[a(ke,{modelValue:j.value,"onUpdate:modelValue":e[1]||(e[1]=s=>j.value=s),size:"small",style:{width:"120px"}},{default:n(()=>[(m(),b(J,null,ne(ie,s=>a(be,{key:s.value,label:s.label,value:s.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),a(he,{modelValue:A.value,"onUpdate:modelValue":e[2]||(e[2]=s=>A.value=s),"inline-prompt":"","active-text":"截图","inactive-text":"不截图"},null,8,["modelValue"]),a(he,{modelValue:$.value,"onUpdate:modelValue":e[3]||(e[3]=s=>$.value=s),disabled:z.value,"inline-prompt":"","active-text":"上传","inactive-text":"不传",onChange:$e},null,8,["modelValue","disabled"]),e[28]||(e[28]=l("span",{class:"app-muted"},"表格(测试)",-1)),h.enabled?(m(),q(Se,{key:0,type:h.online?"success":"warning",size:"small",effect:"plain"},{default:n(()=>[u(c(h.online?"✅ 就绪":"⚠️ 离线"),1)]),_:1},8,["type"])):O("",!0)]),l("div",Mt,[a(p,{type:"primary",onClick:Fe},{default:n(()=>[...e[29]||(e[29]=[u("批量启动",-1)])]),_:1}),a(p,{onClick:Ge},{default:n(()=>[...e[30]||(e[30]=[u("批量停止",-1)])]),_:1}),a(p,{type:"success",plain:"",onClick:Ye},{default:n(()=>[...e[31]||(e[31]=[u("全部启动",-1)])]),_:1}),a(p,{type:"danger",plain:"",onClick:Je},{default:n(()=>[...e[32]||(e[32]=[u("全部停止",-1)])]),_:1}),a(p,{type:"danger",text:"",onClick:Qe},{default:n(()=>[...e[33]||(e[33]=[u("清空",-1)])]),_:1})])]),H.value?(m(),q(tt,{key:0,rows:5,animated:""})):(m(),b(J,{key:1},[y.value.length===0?(m(),q(st,{key:0,description:"暂无账号,点击右上角添加"})):(m(),b("div",Rt,[(m(!0),b(J,null,ne(y.value,s=>(m(),q(o,{key:s.id,shadow:"never",class:"account-card","body-style":{padding:"14px"}},{default:n(()=>[l("div",qt,[a(at,{modelValue:v.value,"onUpdate:modelValue":e[4]||(e[4]=g=>v.value=g),class:"card-check"},{default:n(()=>[a(we,{value:s.id},null,8,["value"])]),_:2},1032,["modelValue"]),l("div",Ht,[l("div",jt,[l("span",Ft,c(s.username),1),a(Se,{size:"small",type:Ne(s.status),effect:"light"},{default:n(()=>[u(c(s.status),1)]),_:2},1032,["type"])]),l("div",Gt,[u(c(s.remark||"—")+" ",1),G(s)&&s.detail_status?(m(),b("span",Yt," · "+c(s.detail_status),1)):O("",!0),G(s)&&s.elapsed_display?(m(),b("span",Jt," · "+c(s.elapsed_display),1)):O("",!0),String(s.status||"").includes("排队")&&s.queue_ahead!=null?(m(),b("span",Qt," · 前面 "+c(s.queue_ahead)+" 个 · 运行中 "+c(s.queue_running_total??0)+" 个 ",1)):G(s)&&(s.queue_pending_total!=null||s.queue_running_total!=null)?(m(),b("span",Wt," · 排队 "+c(s.queue_pending_total??0)+" 个 · 运行中 "+c(s.queue_running_total??0)+" 个 ",1)):O("",!0)])])]),G(s)?(m(),b("div",Xt,[a(nt,{percentage:Le(s),"stroke-width":10,"show-text":!1},null,8,["percentage"]),l("div",Zt,[l("span",null,"内容 "+c(s.progress_items||0),1)])])):O("",!0),l("div",es,[a(ke,{modelValue:C[s.id],"onUpdate:modelValue":g=>C[s.id]=g,size:"small",style:{width:"130px"}},{default:n(()=>[(m(),b(J,null,ne(ie,g=>a(be,{key:g.value,label:g.label,value:g.value},null,8,["label","value"])),64))]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",ts,[a(p,{size:"small",type:"primary",disabled:s.is_running,onClick:g=>ze(s)},{default:n(()=>[...e[34]||(e[34]=[u("启动",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:!s.is_running,onClick:g=>Ke(s)},{default:n(()=>[...e[35]||(e[35]=[u("停止",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:s.is_running,onClick:g=>De(s)},{default:n(()=>[...e[36]||(e[36]=[u("截图",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",disabled:s.is_running,onClick:g=>He(s)},{default:n(()=>[...e[37]||(e[37]=[u("编辑",-1)])]),_:1},8,["disabled","onClick"]),a(p,{size:"small",type:"danger",text:"",onClick:g=>Me(s)},{default:n(()=>[...e[38]||(e[38]=[u("删除",-1)])]),_:1},8,["onClick"])])])]),_:2},1024))),128))]))],64))]),_:1}),a(se,{modelValue:K.value,"onUpdate:modelValue":e[9]||(e[9]=s=>K.value=s),title:"添加账号",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{onClick:e[8]||(e[8]=s=>K.value=!1)},{default:n(()=>[...e[39]||(e[39]=[u("取消",-1)])]),_:1}),a(p,{type:"primary",onClick:qe},{default:n(()=>[...e[40]||(e[40]=[u("添加",-1)])]),_:1})]),default:n(()=>[a(xe,{"label-position":"top"},{default:n(()=>[a(L,{label:"账号"},{default:n(()=>[a(E,{modelValue:_.username,"onUpdate:modelValue":e[5]||(e[5]=s=>_.username=s),placeholder:"请输入账号",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"密码"},{default:n(()=>[a(E,{modelValue:_.password,"onUpdate:modelValue":e[6]||(e[6]=s=>_.password=s),type:"password","show-password":"",placeholder:"请输入密码",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"备注(可选,最多200字)"},{default:n(()=>[a(E,{modelValue:_.remark,"onUpdate:modelValue":e[7]||(e[7]=s=>_.remark=s),type:"textarea",rows:3,maxlength:"200","show-word-limit":"",placeholder:"例如:部门/用途"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"]),a(se,{modelValue:P.value,"onUpdate:modelValue":e[14]||(e[14]=s=>P.value=s),title:"编辑账号",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{onClick:e[13]||(e[13]=s=>P.value=!1)},{default:n(()=>[...e[41]||(e[41]=[u("取消",-1)])]),_:1}),a(p,{type:"primary",onClick:je},{default:n(()=>[...e[42]||(e[42]=[u("保存",-1)])]),_:1})]),default:n(()=>[a(xe,{"label-position":"top"},{default:n(()=>[a(L,{label:"账号"},{default:n(()=>[a(E,{modelValue:d.username,"onUpdate:modelValue":e[10]||(e[10]=s=>d.username=s),disabled:""},null,8,["modelValue"])]),_:1}),a(L,{label:"新密码(可选)"},{default:n(()=>[a(E,{modelValue:d.password,"onUpdate:modelValue":e[11]||(e[11]=s=>d.password=s),type:"password","show-password":"",placeholder:"留空表示不修改密码",autocomplete:"off"},null,8,["modelValue"])]),_:1}),a(L,{label:"备注(可选,最多200字)"},{default:n(()=>[a(E,{modelValue:d.remark,"onUpdate:modelValue":e[12]||(e[12]=s=>d.remark=s),type:"textarea",rows:3,maxlength:"200","show-word-limit":"",placeholder:"例如:部门/用途"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"]),a(se,{modelValue:D.value,"onUpdate:modelValue":e[16]||(e[16]=s=>D.value=s),title:"VIP 特权",width:"min(560px, 92vw)"},{footer:n(()=>[a(p,{type:"primary",onClick:e[15]||(e[15]=s=>D.value=!1)},{default:n(()=>[...e[43]||(e[43]=[u("我知道了",-1)])]),_:1})]),default:n(()=>[a(ge,{type:"info",closable:!1,title:"升级 VIP 后可解锁:无限账号、优先排队、定时任务、批量操作。","show-icon":""}),e[44]||(e[44]=l("div",{class:"vip-body"},[l("div",{class:"vip-tip app-muted"},"升级方式:请通过“反馈”联系管理员开通(与后台一致)。")],-1))]),_:1},8,["modelValue"])])}}},ms=_t(ls,[["__scopeId","data-v-a3d05837"]]);export{ms as default}; diff --git a/static/app/assets/LoginPage-B4Cm3mBQ.js b/static/app/assets/LoginPage-DjXmnzTj.js similarity index 98% rename from static/app/assets/LoginPage-B4Cm3mBQ.js rename to static/app/assets/LoginPage-DjXmnzTj.js index 3d454ce..3fdf74d 100644 --- a/static/app/assets/LoginPage-B4Cm3mBQ.js +++ b/static/app/assets/LoginPage-DjXmnzTj.js @@ -1 +1 @@ -import{a1 as W,r,c as Z,w as H,v as ee,z as _,B as s,Q as t,L as b,aY as V,aD as J,O as ae,J as n,A as m,I as D,N as k}from"./vendor-DR-vtVVc.js";import{p as te}from"./vendor-vue-l2lnRGj2.js";import{f as se,g as M,l as le,a as oe,r as ne}from"./auth-CtTBVBJk.js";import{_ as re}from"./index-C4rfJ09l.js";import{E as u}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const ie={class:"login-page"},ue={class:"login-container"},ce={class:"form-group"},de={class:"form-group"},pe={key:0,class:"form-group"},me={class:"captcha-row"},fe=["src"],ve=["disabled"],ge={class:"action-links"},he={class:"captcha-row"},we=["src"],ye={class:"captcha-row"},_e=["src"],be={__name:"LoginPage",setup(Ve){const $=te(),i=W({username:"",password:"",captcha:""}),C=r(!1),B=r(""),N=r(""),E=r(!1),f=r(!1),P=r(!1),v=r(!1),g=r(!1),d=W({username:"",captcha:""}),x=r(""),I=r(""),F=r(!1),U=r(""),p=W({email:"",captcha:""}),S=r(""),T=r(""),K=r(!1),Q=Z(()=>!!P.value);async function L(){try{const a=await M();N.value=a?.session_id||"",B.value=a?.captcha_image||"",i.captcha=""}catch{N.value="",B.value=""}}async function h(){try{const a=await M();I.value=a?.session_id||"",x.value=a?.captcha_image||"",d.captcha=""}catch{I.value="",x.value=""}}async function w(){try{const a=await M();T.value=a?.session_id||"",S.value=a?.captcha_image||"",p.captcha=""}catch{T.value="",S.value=""}}async function O(){if(!i.username.trim()||!i.password.trim()){u.error("用户名和密码不能为空");return}if(C.value&&!i.captcha.trim()){u.error("请输入验证码");return}E.value=!0;try{await le({username:i.username.trim(),password:i.password,captcha_session:N.value,captcha:i.captcha.trim(),need_captcha:C.value}),u.success("登录成功,正在跳转...");const a=new URLSearchParams(window.location.search||""),e=String(a.get("next")||"").trim(),o=e&&e.startsWith("/")&&!e.startsWith("//")&&!e.startsWith("/\\")?e:"";setTimeout(()=>{const c=o||"/app";$.push(c).catch(()=>{window.location.href=c})},300)}catch(a){const e=a?.response?.status,o=a?.response?.data,c=o?.error||o?.message||"登录失败";u.error(c),o?.need_captcha?(C.value=!0,await L()):C.value&&e===400&&await L()}finally{E.value=!1}}async function Y(){v.value=!0,U.value="",d.username="",d.captcha="",await h()}async function j(){if(U.value="",!f.value){u.warning("邮件功能未启用,请联系管理员重置密码。");return}const a=d.username.trim();if(!a){u.error("请输入用户名");return}if(!d.captcha.trim()){u.error("请输入验证码");return}F.value=!0;try{const e=await oe({username:a,captcha_session:I.value,captcha:d.captcha.trim()});u.success(e?.message||"已发送重置邮件"),setTimeout(()=>{v.value=!1},800)}catch(e){const o=e?.response?.data,c=o?.error||"发送失败";o?.code==="email_not_bound"?U.value=c:u.error(c),await h()}finally{F.value=!1}}async function q(){g.value=!0,p.email="",p.captcha="",await w()}async function G(){const a=p.email.trim();if(!a){u.error("请输入邮箱");return}if(!p.captcha.trim()){u.error("请输入验证码");return}K.value=!0;try{const e=await ne({email:a,captcha_session:T.value,captcha:p.captcha.trim()});u.success(e?.message||"验证邮件已发送,请查收"),setTimeout(()=>{g.value=!1},800)}catch(e){const o=e?.response?.data;u.error(o?.error||"发送失败"),await w()}finally{K.value=!1}}function X(){$.push("/register")}return H(v,async a=>{a&&!x.value&&await h()}),H(g,async a=>{a&&!S.value&&await w()}),ee(async()=>{try{const a=await se();f.value=!!a?.email_enabled,P.value=!!a?.register_verify_enabled}catch{f.value=!1,P.value=!1}f.value&&await Promise.allSettled([h(),w()])}),(a,e)=>{const o=V("el-input"),c=V("el-alert"),R=V("el-form-item"),y=V("el-button"),z=V("el-form"),A=V("el-dialog");return m(),_("div",ie,[s("div",ue,[e[15]||(e[15]=s("div",{class:"login-header"},[s("span",{class:"login-badge"},"用户登录"),s("h1",null,"用户登录系统"),s("p",null,"知识管理平台")],-1)),s("div",ce,[e[11]||(e[11]=s("label",{for:"username"},"用户账号",-1)),t(o,{id:"username",modelValue:i.username,"onUpdate:modelValue":e[0]||(e[0]=l=>i.username=l),class:"login-input",placeholder:"请输入用户名",autocomplete:"username"},null,8,["modelValue"])]),s("div",de,[e[12]||(e[12]=s("label",{for:"password"},"密码",-1)),t(o,{id:"password",modelValue:i.password,"onUpdate:modelValue":e[1]||(e[1]=l=>i.password=l),class:"login-input",type:"password","show-password":"",placeholder:"请输入密码",autocomplete:"current-password",onKeyup:J(O,["enter"])},null,8,["modelValue"])]),C.value?(m(),_("div",pe,[e[13]||(e[13]=s("label",{for:"captcha"},"验证码",-1)),s("div",me,[t(o,{id:"captcha",modelValue:i.captcha,"onUpdate:modelValue":e[2]||(e[2]=l=>i.captcha=l),class:"login-input captcha-input",placeholder:"请输入验证码",onKeyup:J(O,["enter"])},null,8,["modelValue"]),B.value?(m(),_("img",{key:0,class:"captcha-img",src:B.value,alt:"验证码",title:"点击刷新",onClick:L},null,8,fe)):b("",!0),s("button",{type:"button",class:"captcha-refresh",onClick:L},"刷新")])])):b("",!0),s("button",{type:"button",class:"btn-login",disabled:E.value,onClick:O},ae(E.value?"登录中...":"登录系统"),9,ve),s("div",ge,[s("button",{type:"button",class:"link-btn",onClick:Y},"忘记密码?"),Q.value?(m(),_("button",{key:0,type:"button",class:"link-btn",onClick:q},"重发验证邮件")):b("",!0)]),s("div",{class:"register-row"},[e[14]||(e[14]=s("span",null,"还没有账号?",-1)),s("button",{type:"button",class:"link-btn",onClick:X},"立即注册")])]),t(A,{modelValue:v.value,"onUpdate:modelValue":e[6]||(e[6]=l=>v.value=l),title:"找回密码",width:"min(560px, 92vw)"},{footer:n(()=>[t(y,{onClick:e[5]||(e[5]=l=>v.value=!1)},{default:n(()=>[...e[17]||(e[17]=[k("取消",-1)])]),_:1}),t(y,{type:"primary",loading:F.value,disabled:!f.value,onClick:j},{default:n(()=>[...e[18]||(e[18]=[k(" 发送重置邮件 ",-1)])]),_:1},8,["loading","disabled"])]),default:n(()=>[f.value?(m(),D(c,{key:1,type:"info",closable:!1,title:"通过邮箱找回密码",description:"输入用户名并完成验证码,我们将向该账号绑定的邮箱发送重置链接。","show-icon":""})):(m(),D(c,{key:0,type:"warning",closable:!1,title:"邮件功能未启用",description:"无法通过邮箱找回密码,请联系管理员重置密码。","show-icon":""})),U.value?(m(),D(c,{key:2,type:"warning",closable:!1,title:"无法通过邮箱找回密码",description:U.value,"show-icon":"",class:"alert"},null,8,["description"])):b("",!0),t(z,{"label-position":"top",class:"dialog-form"},{default:n(()=>[t(R,{label:"用户名"},{default:n(()=>[t(o,{modelValue:d.username,"onUpdate:modelValue":e[3]||(e[3]=l=>d.username=l),placeholder:"请输入用户名"},null,8,["modelValue"])]),_:1}),t(R,{label:"验证码"},{default:n(()=>[s("div",he,[t(o,{modelValue:d.captcha,"onUpdate:modelValue":e[4]||(e[4]=l=>d.captcha=l),placeholder:"请输入验证码"},null,8,["modelValue"]),x.value?(m(),_("img",{key:0,class:"captcha-img",src:x.value,alt:"验证码",title:"点击刷新",onClick:h},null,8,we)):b("",!0),t(y,{onClick:h},{default:n(()=>[...e[16]||(e[16]=[k("刷新",-1)])]),_:1})])]),_:1})]),_:1})]),_:1},8,["modelValue"]),t(A,{modelValue:g.value,"onUpdate:modelValue":e[10]||(e[10]=l=>g.value=l),title:"重发验证邮件",width:"min(520px, 92vw)"},{footer:n(()=>[t(y,{onClick:e[9]||(e[9]=l=>g.value=!1)},{default:n(()=>[...e[20]||(e[20]=[k("取消",-1)])]),_:1}),t(y,{type:"primary",loading:K.value,onClick:G},{default:n(()=>[...e[21]||(e[21]=[k("发送",-1)])]),_:1},8,["loading"])]),default:n(()=>[t(c,{type:"info",closable:!1,title:"用于注册邮箱验证:请输入邮箱并完成验证码。","show-icon":""}),t(z,{"label-position":"top",class:"dialog-form"},{default:n(()=>[t(R,{label:"邮箱"},{default:n(()=>[t(o,{modelValue:p.email,"onUpdate:modelValue":e[7]||(e[7]=l=>p.email=l),placeholder:"name@example.com"},null,8,["modelValue"])]),_:1}),t(R,{label:"验证码"},{default:n(()=>[s("div",ye,[t(o,{modelValue:p.captcha,"onUpdate:modelValue":e[8]||(e[8]=l=>p.captcha=l),placeholder:"请输入验证码"},null,8,["modelValue"]),S.value?(m(),_("img",{key:0,class:"captcha-img",src:S.value,alt:"验证码",title:"点击刷新",onClick:w},null,8,_e)):b("",!0),t(y,{onClick:w},{default:n(()=>[...e[19]||(e[19]=[k("刷新",-1)])]),_:1})])]),_:1})]),_:1})]),_:1},8,["modelValue"])])}}},Ee=re(be,[["__scopeId","data-v-dc51a501"]]);export{Ee as default}; +import{a1 as W,r,c as Z,w as H,v as ee,z as _,B as s,Q as t,L as b,aY as V,aD as J,O as ae,J as n,A as m,I as D,N as k}from"./vendor-DR-vtVVc.js";import{p as te}from"./vendor-vue-l2lnRGj2.js";import{f as se,g as M,l as le,a as oe,r as ne}from"./auth-3qca7BnL.js";import{_ as re}from"./index-DIRUAu3R.js";import{E as u}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const ie={class:"login-page"},ue={class:"login-container"},ce={class:"form-group"},de={class:"form-group"},pe={key:0,class:"form-group"},me={class:"captcha-row"},fe=["src"],ve=["disabled"],ge={class:"action-links"},he={class:"captcha-row"},we=["src"],ye={class:"captcha-row"},_e=["src"],be={__name:"LoginPage",setup(Ve){const $=te(),i=W({username:"",password:"",captcha:""}),C=r(!1),B=r(""),N=r(""),E=r(!1),f=r(!1),P=r(!1),v=r(!1),g=r(!1),d=W({username:"",captcha:""}),x=r(""),I=r(""),F=r(!1),U=r(""),p=W({email:"",captcha:""}),S=r(""),T=r(""),K=r(!1),Q=Z(()=>!!P.value);async function L(){try{const a=await M();N.value=a?.session_id||"",B.value=a?.captcha_image||"",i.captcha=""}catch{N.value="",B.value=""}}async function h(){try{const a=await M();I.value=a?.session_id||"",x.value=a?.captcha_image||"",d.captcha=""}catch{I.value="",x.value=""}}async function w(){try{const a=await M();T.value=a?.session_id||"",S.value=a?.captcha_image||"",p.captcha=""}catch{T.value="",S.value=""}}async function O(){if(!i.username.trim()||!i.password.trim()){u.error("用户名和密码不能为空");return}if(C.value&&!i.captcha.trim()){u.error("请输入验证码");return}E.value=!0;try{await le({username:i.username.trim(),password:i.password,captcha_session:N.value,captcha:i.captcha.trim(),need_captcha:C.value}),u.success("登录成功,正在跳转...");const a=new URLSearchParams(window.location.search||""),e=String(a.get("next")||"").trim(),o=e&&e.startsWith("/")&&!e.startsWith("//")&&!e.startsWith("/\\")?e:"";setTimeout(()=>{const c=o||"/app";$.push(c).catch(()=>{window.location.href=c})},300)}catch(a){const e=a?.response?.status,o=a?.response?.data,c=o?.error||o?.message||"登录失败";u.error(c),o?.need_captcha?(C.value=!0,await L()):C.value&&e===400&&await L()}finally{E.value=!1}}async function Y(){v.value=!0,U.value="",d.username="",d.captcha="",await h()}async function j(){if(U.value="",!f.value){u.warning("邮件功能未启用,请联系管理员重置密码。");return}const a=d.username.trim();if(!a){u.error("请输入用户名");return}if(!d.captcha.trim()){u.error("请输入验证码");return}F.value=!0;try{const e=await oe({username:a,captcha_session:I.value,captcha:d.captcha.trim()});u.success(e?.message||"已发送重置邮件"),setTimeout(()=>{v.value=!1},800)}catch(e){const o=e?.response?.data,c=o?.error||"发送失败";o?.code==="email_not_bound"?U.value=c:u.error(c),await h()}finally{F.value=!1}}async function q(){g.value=!0,p.email="",p.captcha="",await w()}async function G(){const a=p.email.trim();if(!a){u.error("请输入邮箱");return}if(!p.captcha.trim()){u.error("请输入验证码");return}K.value=!0;try{const e=await ne({email:a,captcha_session:T.value,captcha:p.captcha.trim()});u.success(e?.message||"验证邮件已发送,请查收"),setTimeout(()=>{g.value=!1},800)}catch(e){const o=e?.response?.data;u.error(o?.error||"发送失败"),await w()}finally{K.value=!1}}function X(){$.push("/register")}return H(v,async a=>{a&&!x.value&&await h()}),H(g,async a=>{a&&!S.value&&await w()}),ee(async()=>{try{const a=await se();f.value=!!a?.email_enabled,P.value=!!a?.register_verify_enabled}catch{f.value=!1,P.value=!1}f.value&&await Promise.allSettled([h(),w()])}),(a,e)=>{const o=V("el-input"),c=V("el-alert"),R=V("el-form-item"),y=V("el-button"),z=V("el-form"),A=V("el-dialog");return m(),_("div",ie,[s("div",ue,[e[15]||(e[15]=s("div",{class:"login-header"},[s("span",{class:"login-badge"},"用户登录"),s("h1",null,"用户登录系统"),s("p",null,"知识管理平台")],-1)),s("div",ce,[e[11]||(e[11]=s("label",{for:"username"},"用户账号",-1)),t(o,{id:"username",modelValue:i.username,"onUpdate:modelValue":e[0]||(e[0]=l=>i.username=l),class:"login-input",placeholder:"请输入用户名",autocomplete:"username"},null,8,["modelValue"])]),s("div",de,[e[12]||(e[12]=s("label",{for:"password"},"密码",-1)),t(o,{id:"password",modelValue:i.password,"onUpdate:modelValue":e[1]||(e[1]=l=>i.password=l),class:"login-input",type:"password","show-password":"",placeholder:"请输入密码",autocomplete:"current-password",onKeyup:J(O,["enter"])},null,8,["modelValue"])]),C.value?(m(),_("div",pe,[e[13]||(e[13]=s("label",{for:"captcha"},"验证码",-1)),s("div",me,[t(o,{id:"captcha",modelValue:i.captcha,"onUpdate:modelValue":e[2]||(e[2]=l=>i.captcha=l),class:"login-input captcha-input",placeholder:"请输入验证码",onKeyup:J(O,["enter"])},null,8,["modelValue"]),B.value?(m(),_("img",{key:0,class:"captcha-img",src:B.value,alt:"验证码",title:"点击刷新",onClick:L},null,8,fe)):b("",!0),s("button",{type:"button",class:"captcha-refresh",onClick:L},"刷新")])])):b("",!0),s("button",{type:"button",class:"btn-login",disabled:E.value,onClick:O},ae(E.value?"登录中...":"登录系统"),9,ve),s("div",ge,[s("button",{type:"button",class:"link-btn",onClick:Y},"忘记密码?"),Q.value?(m(),_("button",{key:0,type:"button",class:"link-btn",onClick:q},"重发验证邮件")):b("",!0)]),s("div",{class:"register-row"},[e[14]||(e[14]=s("span",null,"还没有账号?",-1)),s("button",{type:"button",class:"link-btn",onClick:X},"立即注册")])]),t(A,{modelValue:v.value,"onUpdate:modelValue":e[6]||(e[6]=l=>v.value=l),title:"找回密码",width:"min(560px, 92vw)"},{footer:n(()=>[t(y,{onClick:e[5]||(e[5]=l=>v.value=!1)},{default:n(()=>[...e[17]||(e[17]=[k("取消",-1)])]),_:1}),t(y,{type:"primary",loading:F.value,disabled:!f.value,onClick:j},{default:n(()=>[...e[18]||(e[18]=[k(" 发送重置邮件 ",-1)])]),_:1},8,["loading","disabled"])]),default:n(()=>[f.value?(m(),D(c,{key:1,type:"info",closable:!1,title:"通过邮箱找回密码",description:"输入用户名并完成验证码,我们将向该账号绑定的邮箱发送重置链接。","show-icon":""})):(m(),D(c,{key:0,type:"warning",closable:!1,title:"邮件功能未启用",description:"无法通过邮箱找回密码,请联系管理员重置密码。","show-icon":""})),U.value?(m(),D(c,{key:2,type:"warning",closable:!1,title:"无法通过邮箱找回密码",description:U.value,"show-icon":"",class:"alert"},null,8,["description"])):b("",!0),t(z,{"label-position":"top",class:"dialog-form"},{default:n(()=>[t(R,{label:"用户名"},{default:n(()=>[t(o,{modelValue:d.username,"onUpdate:modelValue":e[3]||(e[3]=l=>d.username=l),placeholder:"请输入用户名"},null,8,["modelValue"])]),_:1}),t(R,{label:"验证码"},{default:n(()=>[s("div",he,[t(o,{modelValue:d.captcha,"onUpdate:modelValue":e[4]||(e[4]=l=>d.captcha=l),placeholder:"请输入验证码"},null,8,["modelValue"]),x.value?(m(),_("img",{key:0,class:"captcha-img",src:x.value,alt:"验证码",title:"点击刷新",onClick:h},null,8,we)):b("",!0),t(y,{onClick:h},{default:n(()=>[...e[16]||(e[16]=[k("刷新",-1)])]),_:1})])]),_:1})]),_:1})]),_:1},8,["modelValue"]),t(A,{modelValue:g.value,"onUpdate:modelValue":e[10]||(e[10]=l=>g.value=l),title:"重发验证邮件",width:"min(520px, 92vw)"},{footer:n(()=>[t(y,{onClick:e[9]||(e[9]=l=>g.value=!1)},{default:n(()=>[...e[20]||(e[20]=[k("取消",-1)])]),_:1}),t(y,{type:"primary",loading:K.value,onClick:G},{default:n(()=>[...e[21]||(e[21]=[k("发送",-1)])]),_:1},8,["loading"])]),default:n(()=>[t(c,{type:"info",closable:!1,title:"用于注册邮箱验证:请输入邮箱并完成验证码。","show-icon":""}),t(z,{"label-position":"top",class:"dialog-form"},{default:n(()=>[t(R,{label:"邮箱"},{default:n(()=>[t(o,{modelValue:p.email,"onUpdate:modelValue":e[7]||(e[7]=l=>p.email=l),placeholder:"name@example.com"},null,8,["modelValue"])]),_:1}),t(R,{label:"验证码"},{default:n(()=>[s("div",ye,[t(o,{modelValue:p.captcha,"onUpdate:modelValue":e[8]||(e[8]=l=>p.captcha=l),placeholder:"请输入验证码"},null,8,["modelValue"]),S.value?(m(),_("img",{key:0,class:"captcha-img",src:S.value,alt:"验证码",title:"点击刷新",onClick:w},null,8,_e)):b("",!0),t(y,{onClick:w},{default:n(()=>[...e[19]||(e[19]=[k("刷新",-1)])]),_:1})])]),_:1})]),_:1})]),_:1},8,["modelValue"])])}}},Ee=re(be,[["__scopeId","data-v-dc51a501"]]);export{Ee as default}; diff --git a/static/app/assets/RegisterPage-DDkEhw5Z.js b/static/app/assets/RegisterPage-Nvd-XHp4.js similarity index 97% rename from static/app/assets/RegisterPage-DDkEhw5Z.js rename to static/app/assets/RegisterPage-Nvd-XHp4.js index f3f0f72..c1d64b6 100644 --- a/static/app/assets/RegisterPage-DDkEhw5Z.js +++ b/static/app/assets/RegisterPage-Nvd-XHp4.js @@ -1 +1 @@ -import{a1 as A,r as d,c as S,v as M,z as N,Q as l,J as o,aY as v,A as b,B as n,I as U,L as B,aD as P,O as z,N as E}from"./vendor-DR-vtVVc.js";import{p as H}from"./vendor-vue-l2lnRGj2.js";import{g as J,f as O,b as Q}from"./auth-CtTBVBJk.js";import{_ as Y,v as j}from"./index-C4rfJ09l.js";import{E as c}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const q={class:"auth-wrap"},F={class:"hint app-muted"},G={class:"captcha-row"},W=["src"],X={class:"actions"},Z={__name:"RegisterPage",setup($){const T=H(),a=A({username:"",password:"",confirm_password:"",email:"",captcha:""}),f=d(!1),w=d(""),h=d(""),V=d(!1),t=d(""),_=d(""),k=d(""),D=S(()=>f.value?"邮箱 *":"邮箱(可选)"),I=S(()=>f.value?"必填,用于账号验证":"选填,用于找回密码和接收通知");async function y(){try{const u=await J();h.value=u?.session_id||"",w.value=u?.captcha_image||"",a.captcha=""}catch{h.value="",w.value=""}}async function K(){try{const u=await O();f.value=!!u?.register_verify_enabled}catch{f.value=!1}}function L(){t.value="",_.value="",k.value=""}async function C(){L();const u=a.username.trim(),e=a.password,g=a.confirm_password,s=a.email.trim(),i=a.captcha.trim();if(u.length<3){t.value="用户名至少3个字符",c.error(t.value);return}const p=j(e);if(!p.ok){t.value=p.message||"密码格式不正确",c.error(t.value);return}if(e!==g){t.value="两次输入的密码不一致",c.error(t.value);return}if(f.value&&!s){t.value="请填写邮箱地址用于账号验证",c.error(t.value);return}if(s&&!s.includes("@")){t.value="邮箱格式不正确",c.error(t.value);return}if(!i){t.value="请输入验证码",c.error(t.value);return}V.value=!0;try{const m=await Q({username:u,password:e,email:s,captcha_session:h.value,captcha:i});_.value=m?.message||"注册成功",k.value=m?.need_verify?"请检查您的邮箱(包括垃圾邮件文件夹)":"",c.success("注册成功"),a.username="",a.password="",a.confirm_password="",a.email="",a.captcha="",setTimeout(()=>{window.location.href="/login"},3e3)}catch(m){const x=m?.response?.data;t.value=x?.error||"注册失败",c.error(t.value),await y()}finally{V.value=!1}}function R(){T.push("/login")}return M(async()=>{await y(),await K()}),(u,e)=>{const g=v("el-alert"),s=v("el-input"),i=v("el-form-item"),p=v("el-button"),m=v("el-form"),x=v("el-card");return b(),N("div",q,[l(x,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:o(()=>[e[11]||(e[11]=n("div",{class:"brand"},[n("div",{class:"brand-title"},"知识管理平台"),n("div",{class:"brand-sub app-muted"},"用户注册")],-1)),t.value?(b(),U(g,{key:0,type:"error",closable:!1,title:t.value,"show-icon":"",class:"alert"},null,8,["title"])):B("",!0),_.value?(b(),U(g,{key:1,type:"success",closable:!1,title:_.value,description:k.value,"show-icon":"",class:"alert"},null,8,["title","description"])):B("",!0),l(m,{"label-position":"top"},{default:o(()=>[l(i,{label:"用户名 *"},{default:o(()=>[l(s,{modelValue:a.username,"onUpdate:modelValue":e[0]||(e[0]=r=>a.username=r),placeholder:"至少3个字符",autocomplete:"username"},null,8,["modelValue"]),e[5]||(e[5]=n("div",{class:"hint app-muted"},"至少3个字符",-1))]),_:1}),l(i,{label:"密码 *"},{default:o(()=>[l(s,{modelValue:a.password,"onUpdate:modelValue":e[1]||(e[1]=r=>a.password=r),type:"password","show-password":"",placeholder:"至少8位且包含字母和数字",autocomplete:"new-password"},null,8,["modelValue"]),e[6]||(e[6]=n("div",{class:"hint app-muted"},"至少8位且包含字母和数字",-1))]),_:1}),l(i,{label:"确认密码 *"},{default:o(()=>[l(s,{modelValue:a.confirm_password,"onUpdate:modelValue":e[2]||(e[2]=r=>a.confirm_password=r),type:"password","show-password":"",placeholder:"请再次输入密码",autocomplete:"new-password",onKeyup:P(C,["enter"])},null,8,["modelValue"])]),_:1}),l(i,{label:D.value},{default:o(()=>[l(s,{modelValue:a.email,"onUpdate:modelValue":e[3]||(e[3]=r=>a.email=r),placeholder:"name@example.com",autocomplete:"email"},null,8,["modelValue"]),n("div",F,z(I.value),1)]),_:1},8,["label"]),l(i,{label:"验证码 *"},{default:o(()=>[n("div",G,[l(s,{modelValue:a.captcha,"onUpdate:modelValue":e[4]||(e[4]=r=>a.captcha=r),placeholder:"请输入验证码",onKeyup:P(C,["enter"])},null,8,["modelValue"]),w.value?(b(),N("img",{key:0,class:"captcha-img",src:w.value,alt:"验证码",title:"点击刷新",onClick:y},null,8,W)):B("",!0),l(p,{onClick:y},{default:o(()=>[...e[7]||(e[7]=[E("刷新",-1)])]),_:1})])]),_:1})]),_:1}),l(p,{type:"primary",class:"submit-btn",loading:V.value,onClick:C},{default:o(()=>[...e[8]||(e[8]=[E("注册",-1)])]),_:1},8,["loading"]),n("div",X,[e[10]||(e[10]=n("span",{class:"app-muted"},"已有账号?",-1)),l(p,{link:"",type:"primary",onClick:R},{default:o(()=>[...e[9]||(e[9]=[E("立即登录",-1)])]),_:1})])]),_:1})])}}},re=Y(Z,[["__scopeId","data-v-a9d7804f"]]);export{re as default}; +import{a1 as A,r as d,c as S,v as M,z as N,Q as l,J as o,aY as v,A as b,B as n,I as U,L as B,aD as P,O as z,N as E}from"./vendor-DR-vtVVc.js";import{p as H}from"./vendor-vue-l2lnRGj2.js";import{g as J,f as O,b as Q}from"./auth-3qca7BnL.js";import{_ as Y,v as j}from"./index-DIRUAu3R.js";import{E as c}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const q={class:"auth-wrap"},F={class:"hint app-muted"},G={class:"captcha-row"},W=["src"],X={class:"actions"},Z={__name:"RegisterPage",setup($){const T=H(),a=A({username:"",password:"",confirm_password:"",email:"",captcha:""}),f=d(!1),w=d(""),h=d(""),V=d(!1),t=d(""),_=d(""),k=d(""),D=S(()=>f.value?"邮箱 *":"邮箱(可选)"),I=S(()=>f.value?"必填,用于账号验证":"选填,用于找回密码和接收通知");async function y(){try{const u=await J();h.value=u?.session_id||"",w.value=u?.captcha_image||"",a.captcha=""}catch{h.value="",w.value=""}}async function K(){try{const u=await O();f.value=!!u?.register_verify_enabled}catch{f.value=!1}}function L(){t.value="",_.value="",k.value=""}async function C(){L();const u=a.username.trim(),e=a.password,g=a.confirm_password,s=a.email.trim(),i=a.captcha.trim();if(u.length<3){t.value="用户名至少3个字符",c.error(t.value);return}const p=j(e);if(!p.ok){t.value=p.message||"密码格式不正确",c.error(t.value);return}if(e!==g){t.value="两次输入的密码不一致",c.error(t.value);return}if(f.value&&!s){t.value="请填写邮箱地址用于账号验证",c.error(t.value);return}if(s&&!s.includes("@")){t.value="邮箱格式不正确",c.error(t.value);return}if(!i){t.value="请输入验证码",c.error(t.value);return}V.value=!0;try{const m=await Q({username:u,password:e,email:s,captcha_session:h.value,captcha:i});_.value=m?.message||"注册成功",k.value=m?.need_verify?"请检查您的邮箱(包括垃圾邮件文件夹)":"",c.success("注册成功"),a.username="",a.password="",a.confirm_password="",a.email="",a.captcha="",setTimeout(()=>{window.location.href="/login"},3e3)}catch(m){const x=m?.response?.data;t.value=x?.error||"注册失败",c.error(t.value),await y()}finally{V.value=!1}}function R(){T.push("/login")}return M(async()=>{await y(),await K()}),(u,e)=>{const g=v("el-alert"),s=v("el-input"),i=v("el-form-item"),p=v("el-button"),m=v("el-form"),x=v("el-card");return b(),N("div",q,[l(x,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:o(()=>[e[11]||(e[11]=n("div",{class:"brand"},[n("div",{class:"brand-title"},"知识管理平台"),n("div",{class:"brand-sub app-muted"},"用户注册")],-1)),t.value?(b(),U(g,{key:0,type:"error",closable:!1,title:t.value,"show-icon":"",class:"alert"},null,8,["title"])):B("",!0),_.value?(b(),U(g,{key:1,type:"success",closable:!1,title:_.value,description:k.value,"show-icon":"",class:"alert"},null,8,["title","description"])):B("",!0),l(m,{"label-position":"top"},{default:o(()=>[l(i,{label:"用户名 *"},{default:o(()=>[l(s,{modelValue:a.username,"onUpdate:modelValue":e[0]||(e[0]=r=>a.username=r),placeholder:"至少3个字符",autocomplete:"username"},null,8,["modelValue"]),e[5]||(e[5]=n("div",{class:"hint app-muted"},"至少3个字符",-1))]),_:1}),l(i,{label:"密码 *"},{default:o(()=>[l(s,{modelValue:a.password,"onUpdate:modelValue":e[1]||(e[1]=r=>a.password=r),type:"password","show-password":"",placeholder:"至少8位且包含字母和数字",autocomplete:"new-password"},null,8,["modelValue"]),e[6]||(e[6]=n("div",{class:"hint app-muted"},"至少8位且包含字母和数字",-1))]),_:1}),l(i,{label:"确认密码 *"},{default:o(()=>[l(s,{modelValue:a.confirm_password,"onUpdate:modelValue":e[2]||(e[2]=r=>a.confirm_password=r),type:"password","show-password":"",placeholder:"请再次输入密码",autocomplete:"new-password",onKeyup:P(C,["enter"])},null,8,["modelValue"])]),_:1}),l(i,{label:D.value},{default:o(()=>[l(s,{modelValue:a.email,"onUpdate:modelValue":e[3]||(e[3]=r=>a.email=r),placeholder:"name@example.com",autocomplete:"email"},null,8,["modelValue"]),n("div",F,z(I.value),1)]),_:1},8,["label"]),l(i,{label:"验证码 *"},{default:o(()=>[n("div",G,[l(s,{modelValue:a.captcha,"onUpdate:modelValue":e[4]||(e[4]=r=>a.captcha=r),placeholder:"请输入验证码",onKeyup:P(C,["enter"])},null,8,["modelValue"]),w.value?(b(),N("img",{key:0,class:"captcha-img",src:w.value,alt:"验证码",title:"点击刷新",onClick:y},null,8,W)):B("",!0),l(p,{onClick:y},{default:o(()=>[...e[7]||(e[7]=[E("刷新",-1)])]),_:1})])]),_:1})]),_:1}),l(p,{type:"primary",class:"submit-btn",loading:V.value,onClick:C},{default:o(()=>[...e[8]||(e[8]=[E("注册",-1)])]),_:1},8,["loading"]),n("div",X,[e[10]||(e[10]=n("span",{class:"app-muted"},"已有账号?",-1)),l(p,{link:"",type:"primary",onClick:R},{default:o(()=>[...e[9]||(e[9]=[E("立即登录",-1)])]),_:1})])]),_:1})])}}},re=Y(Z,[["__scopeId","data-v-a9d7804f"]]);export{re as default}; diff --git a/static/app/assets/ResetPasswordPage-DTBT5Kre.js b/static/app/assets/ResetPasswordPage-DluVIq7o.js similarity index 96% rename from static/app/assets/ResetPasswordPage-DTBT5Kre.js rename to static/app/assets/ResetPasswordPage-DluVIq7o.js index 1c276aa..faad7a9 100644 --- a/static/app/assets/ResetPasswordPage-DTBT5Kre.js +++ b/static/app/assets/ResetPasswordPage-DluVIq7o.js @@ -1 +1 @@ -import{r as n,a1 as L,c as M,v as U,a0 as D,z as v,Q as s,J as a,aY as l,A as m,B as w,P as h,N as k,I as K,L as B,aD as j,O as z}from"./vendor-DR-vtVVc.js";import{u as F,p as J}from"./vendor-vue-l2lnRGj2.js";import{c as O}from"./auth-CtTBVBJk.js";import{_ as Q,v as Y}from"./index-C4rfJ09l.js";import{E as y}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const q={class:"auth-wrap"},G={class:"actions"},H={class:"actions"},W={key:0,class:"app-muted"},X={__name:"ResetPasswordPage",setup(Z){const x=F(),A=J(),r=n(String(x.params.token||"")),i=n(!0),b=n(""),t=L({newPassword:"",confirmPassword:""}),P=n(!1),f=n(""),d=n(0);let u=null;function N(){if(typeof window>"u")return null;const o=window.__APP_INITIAL_STATE__;return!o||typeof o!="object"?null:(window.__APP_INITIAL_STATE__=null,o)}const I=M(()=>!!(i.value&&r.value&&!f.value));function S(){A.push("/login")}function C(){d.value=3,u=window.setInterval(()=>{d.value-=1,d.value<=0&&(window.clearInterval(u),u=null,window.location.href="/login")},1e3)}async function V(){if(!I.value)return;const o=t.newPassword,e=t.confirmPassword,c=Y(o);if(!c.ok){y.error(c.message);return}if(o!==e){y.error("两次输入的密码不一致");return}P.value=!0;try{await O({token:r.value,new_password:o}),f.value="密码重置成功!3秒后跳转到登录页面...",y.success("密码重置成功"),C()}catch(p){const _=p?.response?.data;y.error(_?.error||"重置失败")}finally{P.value=!1}}return U(()=>{const o=N();o?.page==="reset_password"?(r.value=String(o?.token||r.value||""),i.value=!!o?.valid,b.value=o?.error_message||(i.value?"":"重置链接无效或已过期,请重新申请密码重置")):r.value||(i.value=!1,b.value="重置链接无效或已过期,请重新申请密码重置")}),D(()=>{u&&window.clearInterval(u)}),(o,e)=>{const c=l("el-alert"),p=l("el-button"),_=l("el-input"),T=l("el-form-item"),R=l("el-form"),E=l("el-card");return m(),v("div",q,[s(E,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:a(()=>[e[5]||(e[5]=w("div",{class:"brand"},[w("div",{class:"brand-title"},"知识管理平台"),w("div",{class:"brand-sub app-muted"},"重置密码")],-1)),i.value?(m(),v(h,{key:1},[f.value?(m(),K(c,{key:0,type:"success",closable:!1,title:"重置成功",description:f.value,"show-icon":"",class:"alert"},null,8,["description"])):B("",!0),s(R,{"label-position":"top"},{default:a(()=>[s(T,{label:"新密码(至少8位且包含字母和数字)"},{default:a(()=>[s(_,{modelValue:t.newPassword,"onUpdate:modelValue":e[0]||(e[0]=g=>t.newPassword=g),type:"password","show-password":"",placeholder:"请输入新密码",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(T,{label:"确认密码"},{default:a(()=>[s(_,{modelValue:t.confirmPassword,"onUpdate:modelValue":e[1]||(e[1]=g=>t.confirmPassword=g),type:"password","show-password":"",placeholder:"请再次输入新密码",autocomplete:"new-password",onKeyup:j(V,["enter"])},null,8,["modelValue"])]),_:1})]),_:1}),s(p,{type:"primary",class:"submit-btn",loading:P.value,disabled:!I.value,onClick:V},{default:a(()=>[...e[3]||(e[3]=[k(" 确认重置 ",-1)])]),_:1},8,["loading","disabled"]),w("div",H,[s(p,{link:"",type:"primary",onClick:S},{default:a(()=>[...e[4]||(e[4]=[k("返回登录",-1)])]),_:1}),d.value>0?(m(),v("span",W,z(d.value)+" 秒后自动跳转…",1)):B("",!0)])],64)):(m(),v(h,{key:0},[s(c,{type:"error",closable:!1,title:"链接已失效",description:b.value,"show-icon":""},null,8,["description"]),w("div",G,[s(p,{type:"primary",onClick:S},{default:a(()=>[...e[2]||(e[2]=[k("返回登录",-1)])]),_:1})])],64))]),_:1})])}}},ne=Q(X,[["__scopeId","data-v-0bbb511c"]]);export{ne as default}; +import{r as n,a1 as L,c as M,v as U,a0 as D,z as v,Q as s,J as a,aY as l,A as m,B as w,P as h,N as k,I as K,L as B,aD as j,O as z}from"./vendor-DR-vtVVc.js";import{u as F,p as J}from"./vendor-vue-l2lnRGj2.js";import{c as O}from"./auth-3qca7BnL.js";import{_ as Q,v as Y}from"./index-DIRUAu3R.js";import{E as y}from"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const q={class:"auth-wrap"},G={class:"actions"},H={class:"actions"},W={key:0,class:"app-muted"},X={__name:"ResetPasswordPage",setup(Z){const x=F(),A=J(),r=n(String(x.params.token||"")),i=n(!0),b=n(""),t=L({newPassword:"",confirmPassword:""}),P=n(!1),f=n(""),d=n(0);let u=null;function N(){if(typeof window>"u")return null;const o=window.__APP_INITIAL_STATE__;return!o||typeof o!="object"?null:(window.__APP_INITIAL_STATE__=null,o)}const I=M(()=>!!(i.value&&r.value&&!f.value));function S(){A.push("/login")}function C(){d.value=3,u=window.setInterval(()=>{d.value-=1,d.value<=0&&(window.clearInterval(u),u=null,window.location.href="/login")},1e3)}async function V(){if(!I.value)return;const o=t.newPassword,e=t.confirmPassword,c=Y(o);if(!c.ok){y.error(c.message);return}if(o!==e){y.error("两次输入的密码不一致");return}P.value=!0;try{await O({token:r.value,new_password:o}),f.value="密码重置成功!3秒后跳转到登录页面...",y.success("密码重置成功"),C()}catch(p){const _=p?.response?.data;y.error(_?.error||"重置失败")}finally{P.value=!1}}return U(()=>{const o=N();o?.page==="reset_password"?(r.value=String(o?.token||r.value||""),i.value=!!o?.valid,b.value=o?.error_message||(i.value?"":"重置链接无效或已过期,请重新申请密码重置")):r.value||(i.value=!1,b.value="重置链接无效或已过期,请重新申请密码重置")}),D(()=>{u&&window.clearInterval(u)}),(o,e)=>{const c=l("el-alert"),p=l("el-button"),_=l("el-input"),T=l("el-form-item"),R=l("el-form"),E=l("el-card");return m(),v("div",q,[s(E,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:a(()=>[e[5]||(e[5]=w("div",{class:"brand"},[w("div",{class:"brand-title"},"知识管理平台"),w("div",{class:"brand-sub app-muted"},"重置密码")],-1)),i.value?(m(),v(h,{key:1},[f.value?(m(),K(c,{key:0,type:"success",closable:!1,title:"重置成功",description:f.value,"show-icon":"",class:"alert"},null,8,["description"])):B("",!0),s(R,{"label-position":"top"},{default:a(()=>[s(T,{label:"新密码(至少8位且包含字母和数字)"},{default:a(()=>[s(_,{modelValue:t.newPassword,"onUpdate:modelValue":e[0]||(e[0]=g=>t.newPassword=g),type:"password","show-password":"",placeholder:"请输入新密码",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(T,{label:"确认密码"},{default:a(()=>[s(_,{modelValue:t.confirmPassword,"onUpdate:modelValue":e[1]||(e[1]=g=>t.confirmPassword=g),type:"password","show-password":"",placeholder:"请再次输入新密码",autocomplete:"new-password",onKeyup:j(V,["enter"])},null,8,["modelValue"])]),_:1})]),_:1}),s(p,{type:"primary",class:"submit-btn",loading:P.value,disabled:!I.value,onClick:V},{default:a(()=>[...e[3]||(e[3]=[k(" 确认重置 ",-1)])]),_:1},8,["loading","disabled"]),w("div",H,[s(p,{link:"",type:"primary",onClick:S},{default:a(()=>[...e[4]||(e[4]=[k("返回登录",-1)])]),_:1}),d.value>0?(m(),v("span",W,z(d.value)+" 秒后自动跳转…",1)):B("",!0)])],64)):(m(),v(h,{key:0},[s(c,{type:"error",closable:!1,title:"链接已失效",description:b.value,"show-icon":""},null,8,["description"]),w("div",G,[s(p,{type:"primary",onClick:S},{default:a(()=>[...e[2]||(e[2]=[k("返回登录",-1)])]),_:1})])],64))]),_:1})])}}},ne=Q(X,[["__scopeId","data-v-0bbb511c"]]);export{ne as default}; diff --git a/static/app/assets/SchedulesPage-DtRro62b.js b/static/app/assets/SchedulesPage-DglS5EqW.js similarity index 99% rename from static/app/assets/SchedulesPage-DtRro62b.js rename to static/app/assets/SchedulesPage-DglS5EqW.js index 307a1af..fe0b68c 100644 --- a/static/app/assets/SchedulesPage-DtRro62b.js +++ b/static/app/assets/SchedulesPage-DglS5EqW.js @@ -1 +1 @@ -import{f as fe}from"./accounts-DpRp0y7G.js";import{p as h,_ as _e,u as ye}from"./index-C4rfJ09l.js";import{E as p,h as G}from"./vendor-element-D5SbqSD5.js";import{r as y,a1 as be,c as we,v as ge,z as b,I as g,L as D,Q as n,J as s,aY as v,A as u,B as i,N as f,P as V,aj as B,O as _}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function he(){const{data:c}=await h.get("/schedules");return c}async function ke(c){const{data:d}=await h.post("/schedules",c);return d}async function Ve(c,d){const{data:w}=await h.put(`/schedules/${c}`,d);return w}async function Se(c){const{data:d}=await h.delete(`/schedules/${c}`);return d}async function xe(c,d){const{data:w}=await h.post(`/schedules/${c}/toggle`,d);return w}async function $e(c){const{data:d}=await h.post(`/schedules/${c}/run`,{});return d}async function Ce(c,d={}){const{data:w}=await h.get(`/schedules/${c}/logs`,{params:d});return w}async function Ne(c){const{data:d}=await h.delete(`/schedules/${c}/logs`);return d}const Be={class:"page"},Te={class:"vip-actions"},Ue={class:"panel-head"},ze={class:"panel-actions"},Ie={key:1,class:"grid"},Me={class:"schedule-top"},Ae={class:"schedule-main"},He={class:"schedule-title"},Le={class:"schedule-name"},Pe={class:"schedule-meta app-muted"},Ee={class:"schedule-meta app-muted"},Oe={key:0},je={class:"schedule-switch"},De={class:"schedule-actions"},Fe={class:"switch-row"},Je={key:1,class:"logs"},Qe={class:"log-head"},Re={class:"app-muted"},Ye={class:"log-body"},qe={key:0,class:"log-error"},Ge={__name:"SchedulesPage",setup(c){const d=ye(),w=y(!1),T=y([]),M=y(!1),A=y([]),S=y(!1),H=y(!1),C=y(null),U=y(!1),L=y(!1),x=y([]),z=y(null),k=y(!1),a=be({name:"",schedule_time:"08:00",weekdays:["1","2","3","4","5"],browse_type:"应读",enable_screenshot:!0,random_delay:!1,account_ids:[]}),K=[{label:"应读",value:"应读"},{label:"注册前未读",value:"注册前未读"}];function F(t){return String(t)==="注册前未读"?"注册前未读":"应读"}const J=[{label:"周一",value:"1"},{label:"周二",value:"2"},{label:"周三",value:"3"},{label:"周四",value:"4"},{label:"周五",value:"5"},{label:"周六",value:"6"},{label:"周日",value:"7"}],r=we(()=>d.isVip);function P(t){const e=String(t||"").match(/^(\d{1,2}):(\d{2})$/);if(!e)return null;const o=Number(e[1]),m=Number(e[2]);return Number.isNaN(o)||Number.isNaN(m)||o<0||o>23||m<0||m>59?null:`${String(o).padStart(2,"0")}:${String(m).padStart(2,"0")}`}function W(t){const e=Array.isArray(t)?t:String(t||"").split(",").filter(Boolean),o=Object.fromEntries(J.map(m=>[m.value,m.label]));return e.map(m=>o[String(m)]||String(m)).join(" ")}async function X(){M.value=!0;try{const t=await fe({refresh:!1});A.value=(t||[]).map(e=>({label:e.username,value:e.id}))}catch{A.value=[]}finally{M.value=!1}}async function I(){w.value=!0;try{const t=await he();T.value=(Array.isArray(t)?t:[]).map(e=>({...e,browse_type:F(e?.browse_type)}))}catch(t){t?.response?.status===401&&(window.location.href="/login"),T.value=[]}finally{w.value=!1}}function Z(){C.value=null,a.name="",a.schedule_time="08:00",a.weekdays=["1","2","3","4","5"],a.browse_type="应读",a.enable_screenshot=!0,a.random_delay=!1,a.account_ids=[],S.value=!0}function ee(t){C.value=t.id,a.name=t.name||"",a.schedule_time=P(t.schedule_time)||"08:00",a.weekdays=String(t.weekdays||"").split(",").filter(Boolean).map(e=>String(e)),a.weekdays.length===0&&(a.weekdays=["1","2","3","4","5"]),a.browse_type=F(t.browse_type),a.enable_screenshot=Number(t.enable_screenshot??1)!==0,a.random_delay=Number(t.random_delay??0)!==0,a.account_ids=Array.isArray(t.account_ids)?t.account_ids.slice():[],S.value=!0}async function le(){if(!r.value){k.value=!0;return}const t=P(a.schedule_time);if(!t){p.error("时间格式错误,请使用 HH:MM");return}if(!a.weekdays||a.weekdays.length===0){p.warning("请选择至少一个执行日期");return}H.value=!0;try{const e={name:a.name.trim()||"我的定时任务",schedule_time:t,weekdays:a.weekdays.join(","),browse_type:a.browse_type,enable_screenshot:a.enable_screenshot?1:0,random_delay:a.random_delay?1:0,account_ids:a.account_ids};C.value?(await Ve(C.value,e),p.success("保存成功")):(await ke(e),p.success("创建成功")),S.value=!1,await I()}catch(e){const o=e?.response?.data;p.error(o?.error||"保存失败")}finally{H.value=!1}}async function te(t){try{await G.confirm(`确定要删除定时任务「${t.name||"未命名任务"}」吗?`,"删除任务",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Se(t.id);e?.success?(p.success("已删除"),await I()):p.error(e?.error||"删除失败")}catch(e){const o=e?.response?.data;p.error(o?.error||"删除失败")}}async function ae(t,e){if(!r.value){k.value=!0;return}try{(await xe(t.id,{enabled:e}))?.success&&(t.enabled=e?1:0,p.success(e?"已启用":"已禁用"))}catch{p.error("操作失败")}}async function ne(t){if(!r.value){k.value=!0;return}try{const e=await $e(t.id);e?.success?p.success(e?.message||"已开始执行"):p.error(e?.error||"执行失败")}catch(e){const o=e?.response?.data;p.error(o?.error||"执行失败")}}async function se(t){z.value=t,U.value=!0,L.value=!0;try{x.value=await Ce(t.id,{limit:20})}catch{x.value=[]}finally{L.value=!1}}async function oe(){const t=z.value;if(t){try{await G.confirm("确定要清空该任务的所有执行日志吗?","清空日志",{confirmButtonText:"清空",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Ne(t.id);e?.success?(p.success(`已清空 ${e?.deleted||0} 条日志`),x.value=[]):p.error(e?.error||"操作失败")}catch{p.error("操作失败")}}}function ie(t){const e=String(t||"");return e==="success"||e==="completed"?"success":e==="failed"?"danger":"info"}function ue(t){const e=Number(t||0),o=Math.floor(e/60),m=e%60;return o<=0?`${m} 秒`:`${o} 分 ${m} 秒`}return ge(async()=>{d.vipInfo||d.refreshVipInfo().catch(()=>{window.location.href="/login"}),await Promise.all([X(),I()])}),(t,e)=>{const o=v("el-button"),m=v("el-alert"),Q=v("el-skeleton"),R=v("el-empty"),E=v("el-switch"),O=v("el-card"),de=v("el-input"),$=v("el-form-item"),re=v("el-time-picker"),ce=v("el-checkbox"),me=v("el-checkbox-group"),Y=v("el-option"),q=v("el-select"),pe=v("el-form"),j=v("el-dialog"),ve=v("el-tag");return u(),b("div",Be,[r.value?D("",!0):(u(),g(m,{key:0,type:"warning","show-icon":"",closable:!1,title:"定时任务为 VIP 专属功能,升级后可使用。",class:"vip-alert"},{default:s(()=>[i("div",Te,[n(o,{type:"primary",plain:"",onClick:e[0]||(e[0]=l=>k.value=!0)},{default:s(()=>[...e[14]||(e[14]=[f("了解VIP特权",-1)])]),_:1})])]),_:1})),n(O,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:s(()=>[i("div",Ue,[e[17]||(e[17]=i("div",{class:"panel-title"},"定时任务",-1)),i("div",ze,[n(o,{loading:w.value,onClick:I},{default:s(()=>[...e[15]||(e[15]=[f("刷新",-1)])]),_:1},8,["loading"]),n(o,{type:"primary",disabled:!r.value,onClick:Z},{default:s(()=>[...e[16]||(e[16]=[f("新建任务",-1)])]),_:1},8,["disabled"])])]),w.value?(u(),g(Q,{key:0,rows:6,animated:""})):(u(),b(V,{key:1},[T.value.length===0?(u(),g(R,{key:0,description:"暂无定时任务"})):(u(),b("div",Ie,[(u(!0),b(V,null,B(T.value,l=>(u(),g(O,{key:l.id,shadow:"never",class:"schedule-card","body-style":{padding:"14px"}},{default:s(()=>[i("div",Me,[i("div",Ae,[i("div",He,[i("span",Le,_(l.name||"未命名任务"),1)]),i("div",Pe,[i("span",null,"⏰ "+_(P(l.schedule_time)||l.schedule_time),1),i("span",null,"📅 "+_(W(l.weekdays)),1)]),i("div",Ee,[i("span",null,"📋 "+_(l.browse_type||"应读"),1),i("span",null,"👥 "+_((l.account_ids||[]).length)+" 个账号",1),i("span",null,_(Number(l.enable_screenshot??1)!==0?"📸 截图":"📷 不截图"),1),Number(l.random_delay??0)!==0?(u(),b("span",Oe,"🎲 随机±15分钟")):D("",!0)])]),i("div",je,[n(E,{"model-value":!!Number(l.enabled),disabled:!r.value,"inline-prompt":"","active-text":"启用","inactive-text":"停用",onChange:N=>ae(l,N)},null,8,["model-value","disabled","onChange"])])]),i("div",De,[n(o,{size:"small",type:"primary",disabled:!r.value,onClick:N=>ne(l)},{default:s(()=>[...e[18]||(e[18]=[f("立即执行",-1)])]),_:1},8,["disabled","onClick"]),n(o,{size:"small",onClick:N=>se(l)},{default:s(()=>[...e[19]||(e[19]=[f("日志",-1)])]),_:1},8,["onClick"]),n(o,{size:"small",disabled:!r.value,onClick:N=>ee(l)},{default:s(()=>[...e[20]||(e[20]=[f("编辑",-1)])]),_:1},8,["disabled","onClick"]),n(o,{size:"small",type:"danger",text:"",disabled:!r.value,onClick:N=>te(l)},{default:s(()=>[...e[21]||(e[21]=[f("删除",-1)])]),_:1},8,["disabled","onClick"])])]),_:2},1024))),128))]))],64))]),_:1}),n(j,{modelValue:S.value,"onUpdate:modelValue":e[9]||(e[9]=l=>S.value=l),title:C.value?"编辑定时任务":"新建定时任务",width:"min(720px, 92vw)"},{footer:s(()=>[n(o,{onClick:e[8]||(e[8]=l=>S.value=!1)},{default:s(()=>[...e[22]||(e[22]=[f("取消",-1)])]),_:1}),n(o,{type:"primary",loading:H.value,disabled:!r.value,onClick:le},{default:s(()=>[...e[23]||(e[23]=[f("保存",-1)])]),_:1},8,["loading","disabled"])]),default:s(()=>[n(pe,{"label-position":"top"},{default:s(()=>[n($,{label:"任务名称"},{default:s(()=>[n(de,{modelValue:a.name,"onUpdate:modelValue":e[1]||(e[1]=l=>a.name=l),placeholder:"我的定时任务",disabled:!r.value},null,8,["modelValue","disabled"])]),_:1}),n($,{label:"执行时间(HH:MM)"},{default:s(()=>[n(re,{modelValue:a.schedule_time,"onUpdate:modelValue":e[2]||(e[2]=l=>a.schedule_time=l),placeholder:"选择时间",format:"HH:mm","value-format":"HH:mm",style:{width:"180px"},disabled:!r.value},null,8,["modelValue","disabled"])]),_:1}),n($,{label:"执行日期"},{default:s(()=>[n(me,{modelValue:a.weekdays,"onUpdate:modelValue":e[3]||(e[3]=l=>a.weekdays=l),disabled:!r.value},{default:s(()=>[(u(),b(V,null,B(J,l=>n(ce,{key:l.value,label:l.value},{default:s(()=>[f(_(l.label),1)]),_:2},1032,["label"])),64))]),_:1},8,["modelValue","disabled"])]),_:1}),n($,{label:"浏览类型"},{default:s(()=>[n(q,{modelValue:a.browse_type,"onUpdate:modelValue":e[4]||(e[4]=l=>a.browse_type=l),style:{width:"160px"},disabled:!r.value},{default:s(()=>[(u(),b(V,null,B(K,l=>n(Y,{key:l.value,label:l.label,value:l.value},null,8,["label","value"])),64))]),_:1},8,["modelValue","disabled"])]),_:1}),n($,{label:"截图"},{default:s(()=>[i("div",Fe,[n(E,{modelValue:a.enable_screenshot,"onUpdate:modelValue":e[5]||(e[5]=l=>a.enable_screenshot=l),disabled:!r.value,"inline-prompt":"","active-text":"截图","inactive-text":"不截图"},null,8,["modelValue","disabled"]),n(E,{modelValue:a.random_delay,"onUpdate:modelValue":e[6]||(e[6]=l=>a.random_delay=l),disabled:!r.value,"inline-prompt":"","active-text":"随机±15分钟","inactive-text":"固定时间"},null,8,["modelValue","disabled"])])]),_:1}),n($,{label:"参与账号"},{default:s(()=>[n(q,{modelValue:a.account_ids,"onUpdate:modelValue":e[7]||(e[7]=l=>a.account_ids=l),multiple:"",filterable:"","collapse-tags":"","collapse-tags-tooltip":"",placeholder:"选择账号(可多选)",style:{width:"100%"},loading:M.value,disabled:!r.value},{default:s(()=>[(u(!0),b(V,null,B(A.value,l=>(u(),g(Y,{key:l.value,label:l.label,value:l.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading","disabled"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"]),n(j,{modelValue:U.value,"onUpdate:modelValue":e[11]||(e[11]=l=>U.value=l),title:z.value?`【${z.value.name||"未命名任务"}】执行日志`:"执行日志",width:"min(760px, 92vw)"},{footer:s(()=>[n(o,{onClick:e[10]||(e[10]=l=>U.value=!1)},{default:s(()=>[...e[24]||(e[24]=[f("关闭",-1)])]),_:1}),n(o,{type:"danger",plain:"",disabled:x.value.length===0,onClick:oe},{default:s(()=>[...e[25]||(e[25]=[f("清空日志",-1)])]),_:1},8,["disabled"])]),default:s(()=>[L.value?(u(),g(Q,{key:0,rows:6,animated:""})):(u(),b(V,{key:1},[x.value.length===0?(u(),g(R,{key:0,description:"暂无执行日志"})):(u(),b("div",Je,[(u(!0),b(V,null,B(x.value,l=>(u(),g(O,{key:l.id,shadow:"never",class:"log-card","body-style":{padding:"12px"}},{default:s(()=>[i("div",Qe,[n(ve,{size:"small",effect:"light",type:ie(l.status)},{default:s(()=>[f(_(l.status==="failed"?"失败":l.status==="running"?"进行中":"成功"),1)]),_:2},1032,["type"]),i("span",Re,_(l.created_at||""),1)]),i("div",Ye,[i("div",null,"账号数:"+_(l.total_accounts||0)+" 个",1),i("div",null,"成功:"+_(l.success_count||0)+" 个 · 失败:"+_(l.failed_count||0)+" 个",1),i("div",null,"耗时:"+_(ue(l.duration||0)),1),l.error_message?(u(),b("div",qe,"错误:"+_(l.error_message),1)):D("",!0)])]),_:2},1024))),128))]))],64))]),_:1},8,["modelValue","title"]),n(j,{modelValue:k.value,"onUpdate:modelValue":e[13]||(e[13]=l=>k.value=l),title:"VIP 特权",width:"min(560px, 92vw)"},{footer:s(()=>[n(o,{type:"primary",onClick:e[12]||(e[12]=l=>k.value=!1)},{default:s(()=>[...e[26]||(e[26]=[f("我知道了",-1)])]),_:1})]),default:s(()=>[n(m,{type:"info",closable:!1,title:"升级 VIP 后可解锁:无限账号、优先排队、定时任务、批量操作。","show-icon":""}),e[27]||(e[27]=i("div",{class:"vip-body"},[i("div",{class:"vip-tip app-muted"},"升级方式:请通过“反馈”联系管理员开通。")],-1))]),_:1},8,["modelValue"])])}}},tl=_e(Ge,[["__scopeId","data-v-e7d93ff5"]]);export{tl as default}; +import{f as fe}from"./accounts-DWKsGalm.js";import{p as h,_ as _e,u as ye}from"./index-DIRUAu3R.js";import{E as p,h as G}from"./vendor-element-D5SbqSD5.js";import{r as y,a1 as be,c as we,v as ge,z as b,I as g,L as D,Q as n,J as s,aY as v,A as u,B as i,N as f,P as V,aj as B,O as _}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function he(){const{data:c}=await h.get("/schedules");return c}async function ke(c){const{data:d}=await h.post("/schedules",c);return d}async function Ve(c,d){const{data:w}=await h.put(`/schedules/${c}`,d);return w}async function Se(c){const{data:d}=await h.delete(`/schedules/${c}`);return d}async function xe(c,d){const{data:w}=await h.post(`/schedules/${c}/toggle`,d);return w}async function $e(c){const{data:d}=await h.post(`/schedules/${c}/run`,{});return d}async function Ce(c,d={}){const{data:w}=await h.get(`/schedules/${c}/logs`,{params:d});return w}async function Ne(c){const{data:d}=await h.delete(`/schedules/${c}/logs`);return d}const Be={class:"page"},Te={class:"vip-actions"},Ue={class:"panel-head"},ze={class:"panel-actions"},Ie={key:1,class:"grid"},Me={class:"schedule-top"},Ae={class:"schedule-main"},He={class:"schedule-title"},Le={class:"schedule-name"},Pe={class:"schedule-meta app-muted"},Ee={class:"schedule-meta app-muted"},Oe={key:0},je={class:"schedule-switch"},De={class:"schedule-actions"},Fe={class:"switch-row"},Je={key:1,class:"logs"},Qe={class:"log-head"},Re={class:"app-muted"},Ye={class:"log-body"},qe={key:0,class:"log-error"},Ge={__name:"SchedulesPage",setup(c){const d=ye(),w=y(!1),T=y([]),M=y(!1),A=y([]),S=y(!1),H=y(!1),C=y(null),U=y(!1),L=y(!1),x=y([]),z=y(null),k=y(!1),a=be({name:"",schedule_time:"08:00",weekdays:["1","2","3","4","5"],browse_type:"应读",enable_screenshot:!0,random_delay:!1,account_ids:[]}),K=[{label:"应读",value:"应读"},{label:"注册前未读",value:"注册前未读"}];function F(t){return String(t)==="注册前未读"?"注册前未读":"应读"}const J=[{label:"周一",value:"1"},{label:"周二",value:"2"},{label:"周三",value:"3"},{label:"周四",value:"4"},{label:"周五",value:"5"},{label:"周六",value:"6"},{label:"周日",value:"7"}],r=we(()=>d.isVip);function P(t){const e=String(t||"").match(/^(\d{1,2}):(\d{2})$/);if(!e)return null;const o=Number(e[1]),m=Number(e[2]);return Number.isNaN(o)||Number.isNaN(m)||o<0||o>23||m<0||m>59?null:`${String(o).padStart(2,"0")}:${String(m).padStart(2,"0")}`}function W(t){const e=Array.isArray(t)?t:String(t||"").split(",").filter(Boolean),o=Object.fromEntries(J.map(m=>[m.value,m.label]));return e.map(m=>o[String(m)]||String(m)).join(" ")}async function X(){M.value=!0;try{const t=await fe({refresh:!1});A.value=(t||[]).map(e=>({label:e.username,value:e.id}))}catch{A.value=[]}finally{M.value=!1}}async function I(){w.value=!0;try{const t=await he();T.value=(Array.isArray(t)?t:[]).map(e=>({...e,browse_type:F(e?.browse_type)}))}catch(t){t?.response?.status===401&&(window.location.href="/login"),T.value=[]}finally{w.value=!1}}function Z(){C.value=null,a.name="",a.schedule_time="08:00",a.weekdays=["1","2","3","4","5"],a.browse_type="应读",a.enable_screenshot=!0,a.random_delay=!1,a.account_ids=[],S.value=!0}function ee(t){C.value=t.id,a.name=t.name||"",a.schedule_time=P(t.schedule_time)||"08:00",a.weekdays=String(t.weekdays||"").split(",").filter(Boolean).map(e=>String(e)),a.weekdays.length===0&&(a.weekdays=["1","2","3","4","5"]),a.browse_type=F(t.browse_type),a.enable_screenshot=Number(t.enable_screenshot??1)!==0,a.random_delay=Number(t.random_delay??0)!==0,a.account_ids=Array.isArray(t.account_ids)?t.account_ids.slice():[],S.value=!0}async function le(){if(!r.value){k.value=!0;return}const t=P(a.schedule_time);if(!t){p.error("时间格式错误,请使用 HH:MM");return}if(!a.weekdays||a.weekdays.length===0){p.warning("请选择至少一个执行日期");return}H.value=!0;try{const e={name:a.name.trim()||"我的定时任务",schedule_time:t,weekdays:a.weekdays.join(","),browse_type:a.browse_type,enable_screenshot:a.enable_screenshot?1:0,random_delay:a.random_delay?1:0,account_ids:a.account_ids};C.value?(await Ve(C.value,e),p.success("保存成功")):(await ke(e),p.success("创建成功")),S.value=!1,await I()}catch(e){const o=e?.response?.data;p.error(o?.error||"保存失败")}finally{H.value=!1}}async function te(t){try{await G.confirm(`确定要删除定时任务「${t.name||"未命名任务"}」吗?`,"删除任务",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Se(t.id);e?.success?(p.success("已删除"),await I()):p.error(e?.error||"删除失败")}catch(e){const o=e?.response?.data;p.error(o?.error||"删除失败")}}async function ae(t,e){if(!r.value){k.value=!0;return}try{(await xe(t.id,{enabled:e}))?.success&&(t.enabled=e?1:0,p.success(e?"已启用":"已禁用"))}catch{p.error("操作失败")}}async function ne(t){if(!r.value){k.value=!0;return}try{const e=await $e(t.id);e?.success?p.success(e?.message||"已开始执行"):p.error(e?.error||"执行失败")}catch(e){const o=e?.response?.data;p.error(o?.error||"执行失败")}}async function se(t){z.value=t,U.value=!0,L.value=!0;try{x.value=await Ce(t.id,{limit:20})}catch{x.value=[]}finally{L.value=!1}}async function oe(){const t=z.value;if(t){try{await G.confirm("确定要清空该任务的所有执行日志吗?","清空日志",{confirmButtonText:"清空",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Ne(t.id);e?.success?(p.success(`已清空 ${e?.deleted||0} 条日志`),x.value=[]):p.error(e?.error||"操作失败")}catch{p.error("操作失败")}}}function ie(t){const e=String(t||"");return e==="success"||e==="completed"?"success":e==="failed"?"danger":"info"}function ue(t){const e=Number(t||0),o=Math.floor(e/60),m=e%60;return o<=0?`${m} 秒`:`${o} 分 ${m} 秒`}return ge(async()=>{d.vipInfo||d.refreshVipInfo().catch(()=>{window.location.href="/login"}),await Promise.all([X(),I()])}),(t,e)=>{const o=v("el-button"),m=v("el-alert"),Q=v("el-skeleton"),R=v("el-empty"),E=v("el-switch"),O=v("el-card"),de=v("el-input"),$=v("el-form-item"),re=v("el-time-picker"),ce=v("el-checkbox"),me=v("el-checkbox-group"),Y=v("el-option"),q=v("el-select"),pe=v("el-form"),j=v("el-dialog"),ve=v("el-tag");return u(),b("div",Be,[r.value?D("",!0):(u(),g(m,{key:0,type:"warning","show-icon":"",closable:!1,title:"定时任务为 VIP 专属功能,升级后可使用。",class:"vip-alert"},{default:s(()=>[i("div",Te,[n(o,{type:"primary",plain:"",onClick:e[0]||(e[0]=l=>k.value=!0)},{default:s(()=>[...e[14]||(e[14]=[f("了解VIP特权",-1)])]),_:1})])]),_:1})),n(O,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:s(()=>[i("div",Ue,[e[17]||(e[17]=i("div",{class:"panel-title"},"定时任务",-1)),i("div",ze,[n(o,{loading:w.value,onClick:I},{default:s(()=>[...e[15]||(e[15]=[f("刷新",-1)])]),_:1},8,["loading"]),n(o,{type:"primary",disabled:!r.value,onClick:Z},{default:s(()=>[...e[16]||(e[16]=[f("新建任务",-1)])]),_:1},8,["disabled"])])]),w.value?(u(),g(Q,{key:0,rows:6,animated:""})):(u(),b(V,{key:1},[T.value.length===0?(u(),g(R,{key:0,description:"暂无定时任务"})):(u(),b("div",Ie,[(u(!0),b(V,null,B(T.value,l=>(u(),g(O,{key:l.id,shadow:"never",class:"schedule-card","body-style":{padding:"14px"}},{default:s(()=>[i("div",Me,[i("div",Ae,[i("div",He,[i("span",Le,_(l.name||"未命名任务"),1)]),i("div",Pe,[i("span",null,"⏰ "+_(P(l.schedule_time)||l.schedule_time),1),i("span",null,"📅 "+_(W(l.weekdays)),1)]),i("div",Ee,[i("span",null,"📋 "+_(l.browse_type||"应读"),1),i("span",null,"👥 "+_((l.account_ids||[]).length)+" 个账号",1),i("span",null,_(Number(l.enable_screenshot??1)!==0?"📸 截图":"📷 不截图"),1),Number(l.random_delay??0)!==0?(u(),b("span",Oe,"🎲 随机±15分钟")):D("",!0)])]),i("div",je,[n(E,{"model-value":!!Number(l.enabled),disabled:!r.value,"inline-prompt":"","active-text":"启用","inactive-text":"停用",onChange:N=>ae(l,N)},null,8,["model-value","disabled","onChange"])])]),i("div",De,[n(o,{size:"small",type:"primary",disabled:!r.value,onClick:N=>ne(l)},{default:s(()=>[...e[18]||(e[18]=[f("立即执行",-1)])]),_:1},8,["disabled","onClick"]),n(o,{size:"small",onClick:N=>se(l)},{default:s(()=>[...e[19]||(e[19]=[f("日志",-1)])]),_:1},8,["onClick"]),n(o,{size:"small",disabled:!r.value,onClick:N=>ee(l)},{default:s(()=>[...e[20]||(e[20]=[f("编辑",-1)])]),_:1},8,["disabled","onClick"]),n(o,{size:"small",type:"danger",text:"",disabled:!r.value,onClick:N=>te(l)},{default:s(()=>[...e[21]||(e[21]=[f("删除",-1)])]),_:1},8,["disabled","onClick"])])]),_:2},1024))),128))]))],64))]),_:1}),n(j,{modelValue:S.value,"onUpdate:modelValue":e[9]||(e[9]=l=>S.value=l),title:C.value?"编辑定时任务":"新建定时任务",width:"min(720px, 92vw)"},{footer:s(()=>[n(o,{onClick:e[8]||(e[8]=l=>S.value=!1)},{default:s(()=>[...e[22]||(e[22]=[f("取消",-1)])]),_:1}),n(o,{type:"primary",loading:H.value,disabled:!r.value,onClick:le},{default:s(()=>[...e[23]||(e[23]=[f("保存",-1)])]),_:1},8,["loading","disabled"])]),default:s(()=>[n(pe,{"label-position":"top"},{default:s(()=>[n($,{label:"任务名称"},{default:s(()=>[n(de,{modelValue:a.name,"onUpdate:modelValue":e[1]||(e[1]=l=>a.name=l),placeholder:"我的定时任务",disabled:!r.value},null,8,["modelValue","disabled"])]),_:1}),n($,{label:"执行时间(HH:MM)"},{default:s(()=>[n(re,{modelValue:a.schedule_time,"onUpdate:modelValue":e[2]||(e[2]=l=>a.schedule_time=l),placeholder:"选择时间",format:"HH:mm","value-format":"HH:mm",style:{width:"180px"},disabled:!r.value},null,8,["modelValue","disabled"])]),_:1}),n($,{label:"执行日期"},{default:s(()=>[n(me,{modelValue:a.weekdays,"onUpdate:modelValue":e[3]||(e[3]=l=>a.weekdays=l),disabled:!r.value},{default:s(()=>[(u(),b(V,null,B(J,l=>n(ce,{key:l.value,label:l.value},{default:s(()=>[f(_(l.label),1)]),_:2},1032,["label"])),64))]),_:1},8,["modelValue","disabled"])]),_:1}),n($,{label:"浏览类型"},{default:s(()=>[n(q,{modelValue:a.browse_type,"onUpdate:modelValue":e[4]||(e[4]=l=>a.browse_type=l),style:{width:"160px"},disabled:!r.value},{default:s(()=>[(u(),b(V,null,B(K,l=>n(Y,{key:l.value,label:l.label,value:l.value},null,8,["label","value"])),64))]),_:1},8,["modelValue","disabled"])]),_:1}),n($,{label:"截图"},{default:s(()=>[i("div",Fe,[n(E,{modelValue:a.enable_screenshot,"onUpdate:modelValue":e[5]||(e[5]=l=>a.enable_screenshot=l),disabled:!r.value,"inline-prompt":"","active-text":"截图","inactive-text":"不截图"},null,8,["modelValue","disabled"]),n(E,{modelValue:a.random_delay,"onUpdate:modelValue":e[6]||(e[6]=l=>a.random_delay=l),disabled:!r.value,"inline-prompt":"","active-text":"随机±15分钟","inactive-text":"固定时间"},null,8,["modelValue","disabled"])])]),_:1}),n($,{label:"参与账号"},{default:s(()=>[n(q,{modelValue:a.account_ids,"onUpdate:modelValue":e[7]||(e[7]=l=>a.account_ids=l),multiple:"",filterable:"","collapse-tags":"","collapse-tags-tooltip":"",placeholder:"选择账号(可多选)",style:{width:"100%"},loading:M.value,disabled:!r.value},{default:s(()=>[(u(!0),b(V,null,B(A.value,l=>(u(),g(Y,{key:l.value,label:l.label,value:l.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading","disabled"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"]),n(j,{modelValue:U.value,"onUpdate:modelValue":e[11]||(e[11]=l=>U.value=l),title:z.value?`【${z.value.name||"未命名任务"}】执行日志`:"执行日志",width:"min(760px, 92vw)"},{footer:s(()=>[n(o,{onClick:e[10]||(e[10]=l=>U.value=!1)},{default:s(()=>[...e[24]||(e[24]=[f("关闭",-1)])]),_:1}),n(o,{type:"danger",plain:"",disabled:x.value.length===0,onClick:oe},{default:s(()=>[...e[25]||(e[25]=[f("清空日志",-1)])]),_:1},8,["disabled"])]),default:s(()=>[L.value?(u(),g(Q,{key:0,rows:6,animated:""})):(u(),b(V,{key:1},[x.value.length===0?(u(),g(R,{key:0,description:"暂无执行日志"})):(u(),b("div",Je,[(u(!0),b(V,null,B(x.value,l=>(u(),g(O,{key:l.id,shadow:"never",class:"log-card","body-style":{padding:"12px"}},{default:s(()=>[i("div",Qe,[n(ve,{size:"small",effect:"light",type:ie(l.status)},{default:s(()=>[f(_(l.status==="failed"?"失败":l.status==="running"?"进行中":"成功"),1)]),_:2},1032,["type"]),i("span",Re,_(l.created_at||""),1)]),i("div",Ye,[i("div",null,"账号数:"+_(l.total_accounts||0)+" 个",1),i("div",null,"成功:"+_(l.success_count||0)+" 个 · 失败:"+_(l.failed_count||0)+" 个",1),i("div",null,"耗时:"+_(ue(l.duration||0)),1),l.error_message?(u(),b("div",qe,"错误:"+_(l.error_message),1)):D("",!0)])]),_:2},1024))),128))]))],64))]),_:1},8,["modelValue","title"]),n(j,{modelValue:k.value,"onUpdate:modelValue":e[13]||(e[13]=l=>k.value=l),title:"VIP 特权",width:"min(560px, 92vw)"},{footer:s(()=>[n(o,{type:"primary",onClick:e[12]||(e[12]=l=>k.value=!1)},{default:s(()=>[...e[26]||(e[26]=[f("我知道了",-1)])]),_:1})]),default:s(()=>[n(m,{type:"info",closable:!1,title:"升级 VIP 后可解锁:无限账号、优先排队、定时任务、批量操作。","show-icon":""}),e[27]||(e[27]=i("div",{class:"vip-body"},[i("div",{class:"vip-tip app-muted"},"升级方式:请通过“反馈”联系管理员开通。")],-1))]),_:1},8,["modelValue"])])}}},tl=_e(Ge,[["__scopeId","data-v-e7d93ff5"]]);export{tl as default}; diff --git a/static/app/assets/ScreenshotsPage-BMPLt3Or.js b/static/app/assets/ScreenshotsPage-L5gmloAw.js similarity index 99% rename from static/app/assets/ScreenshotsPage-BMPLt3Or.js rename to static/app/assets/ScreenshotsPage-L5gmloAw.js index 5132f4a..2127cee 100644 --- a/static/app/assets/ScreenshotsPage-BMPLt3Or.js +++ b/static/app/assets/ScreenshotsPage-L5gmloAw.js @@ -1 +1 @@ -import{p as x,_ as W}from"./index-C4rfJ09l.js";import{h as U,E as r}from"./vendor-element-D5SbqSD5.js";import{r as g,v as D,I as _,J as s,aY as y,A as c,B as i,z as k,Q as d,N as w,P as $,aj as H,O as P}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function F(){const{data:u}=await x.get("/screenshots");return u}async function J(u){const{data:f}=await x.delete(`/screenshots/${encodeURIComponent(u)}`);return f}async function Q(){const{data:u}=await x.post("/screenshots/clear",{});return u}const Y={class:"panel-head"},q={class:"panel-actions"},G={key:1,class:"grid"},K=["src","alt","onError","onClick"],X={class:"shot-body"},Z=["title"],ee={class:"shot-meta app-muted"},te={class:"shot-actions"},ne={class:"preview"},ae=["src","alt"],oe={__name:"ScreenshotsPage",setup(u){const f=g(!1),l=g([]),p=g(!1),b=g(""),C=g("");function h(e){return`/screenshots/${encodeURIComponent(e)}`}function L(e){return`/screenshots/thumb/${encodeURIComponent(e)}`}async function B(){f.value=!0;try{const e=await F();l.value=Array.isArray(e)?e:[]}catch(e){e?.response?.status===401&&(window.location.href="/login"),l.value=[]}finally{f.value=!1}}function R(e){C.value=e.display_name||e.filename||"截图预览",b.value=h(e.filename),p.value=!0}function S(e,t){const n=e?.target;n&&n.dataset.fullLoaded!=="1"&&(n.dataset.fullLoaded="1",n.src=h(t.filename))}function T(e){return new Promise((t,n)=>{e.toBlob(o=>o?t(o):n(new Error("toBlob_failed")),"image/png")})}async function V(e){if(!e)throw new Error("no_image");(!e.complete||e.naturalWidth<=0)&&(typeof e.decode=="function"?await e.decode():await new Promise((o,m)=>{e.addEventListener("load",o,{once:!0}),e.addEventListener("error",m,{once:!0})}));const t=document.createElement("canvas");t.width=e.naturalWidth,t.height=e.naturalHeight;const n=t.getContext("2d");if(!n)throw new Error("no_canvas");return n.drawImage(e,0,0),await T(t)}async function z(e){if(!e)throw new Error("no_blob");if(e.type==="image/png")return e;if(typeof createImageBitmap=="function"){const n=await createImageBitmap(e),o=document.createElement("canvas");o.width=n.width,o.height=n.height;const m=o.getContext("2d");if(!m)throw new Error("no_canvas");return m.drawImage(n,0,0),await T(o)}const t=URL.createObjectURL(e);try{const n=new Image;return n.src=t,typeof n.decode=="function"&&await n.decode(),await V(n)}finally{URL.revokeObjectURL(t)}}async function I(e){const t=await fetch(e,{credentials:"include",cache:"no-store"});if(!t.ok)throw new Error("fetch_failed");const n=await t.blob();if(!(t.headers.get("Content-Type")||n.type||"").startsWith("image/"))throw new Error("not_image");return await z(n)}async function A(){try{await U.confirm("确定要清空全部截图吗?","清空截图",{confirmButtonText:"清空",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Q();if(e?.success){r.success(`已清空(删除 ${e?.deleted||0} 张)`),l.value=[],p.value=!1;return}r.error(e?.error||"操作失败")}catch(e){const t=e?.response?.data;r.error(t?.error||"操作失败")}}async function N(e){try{await U.confirm(`确定要删除截图「${e.display_name||e.filename}」吗?`,"删除截图",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await J(e.filename);if(t?.success){l.value=l.value.filter(n=>n.filename!==e.filename),b.value.includes(encodeURIComponent(e.filename))&&(p.value=!1),r.success("已删除");return}r.error(t?.error||"删除失败")}catch(t){const n=t?.response?.data;r.error(n?.error||"删除失败")}}async function O(e){const t=h(e.filename);if(!navigator.clipboard||typeof navigator.clipboard.write!="function"||typeof window.ClipboardItem>"u"){r.warning("当前环境不支持复制图片(建议使用 Chrome/Edge 并通过 HTTPS 访问);可用“下载”。");return}try{try{await navigator.clipboard.write([new ClipboardItem({"image/png":I(t)})])}catch{const n=await I(t);await navigator.clipboard.write([new ClipboardItem({"image/png":n})])}r.success("图片已复制到剪贴板")}catch{try{if(navigator.clipboard&&typeof navigator.clipboard.writeText=="function"){await navigator.clipboard.writeText(`${window.location.origin}${t}`),r.warning("复制图片失败,已复制图片链接(可直接粘贴到浏览器打开)");return}}catch{}r.warning("复制图片失败:请确认允许剪贴板权限;可用“下载”。")}}function j(e){const t=document.createElement("a");t.href=h(e.filename),t.download=e.display_name||e.filename,document.body.appendChild(t),t.click(),t.remove()}return D(B),(e,t)=>{const n=y("el-button"),o=y("el-skeleton"),m=y("el-empty"),E=y("el-card"),M=y("el-dialog");return c(),_(E,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:s(()=>[i("div",Y,[t[4]||(t[4]=i("div",{class:"panel-title"},"截图管理",-1)),i("div",q,[d(n,{loading:f.value,onClick:B},{default:s(()=>[...t[2]||(t[2]=[w("刷新",-1)])]),_:1},8,["loading"]),d(n,{type:"danger",plain:"",disabled:l.value.length===0,onClick:A},{default:s(()=>[...t[3]||(t[3]=[w("清空全部",-1)])]),_:1},8,["disabled"])])]),f.value?(c(),_(o,{key:0,rows:6,animated:""})):(c(),k($,{key:1},[l.value.length===0?(c(),_(m,{key:0,description:"暂无截图"})):(c(),k("div",G,[(c(!0),k($,null,H(l.value,a=>(c(),_(E,{key:a.filename,shadow:"never",class:"shot-card","body-style":{padding:"0"}},{default:s(()=>[i("img",{class:"shot-img",src:L(a.filename),alt:a.display_name||a.filename,loading:"lazy",onError:v=>S(v,a),onClick:v=>R(a)},null,40,K),i("div",X,[i("div",{class:"shot-name",title:a.display_name||a.filename},P(a.display_name||a.filename),9,Z),i("div",ee,P(a.created||""),1),i("div",te,[d(n,{size:"small",text:"",type:"primary",onClick:v=>O(a)},{default:s(()=>[...t[5]||(t[5]=[w("复制图片",-1)])]),_:1},8,["onClick"]),d(n,{size:"small",text:"",onClick:v=>j(a)},{default:s(()=>[...t[6]||(t[6]=[w("下载",-1)])]),_:1},8,["onClick"]),d(n,{size:"small",text:"",type:"danger",onClick:v=>N(a)},{default:s(()=>[...t[7]||(t[7]=[w("删除",-1)])]),_:1},8,["onClick"])])])]),_:2},1024))),128))]))],64)),d(M,{modelValue:p.value,"onUpdate:modelValue":t[1]||(t[1]=a=>p.value=a),title:C.value,width:"min(920px, 94vw)"},{footer:s(()=>[d(n,{onClick:t[0]||(t[0]=a=>p.value=!1)},{default:s(()=>[...t[8]||(t[8]=[w("关闭",-1)])]),_:1})]),default:s(()=>[i("div",ne,[i("img",{src:b.value,alt:C.value,class:"preview-img"},null,8,ae)])]),_:1},8,["modelValue","title"])]),_:1})}}},de=W(oe,[["__scopeId","data-v-76fa8f53"]]);export{de as default}; +import{p as x,_ as W}from"./index-DIRUAu3R.js";import{h as U,E as r}from"./vendor-element-D5SbqSD5.js";import{r as g,v as D,I as _,J as s,aY as y,A as c,B as i,z as k,Q as d,N as w,P as $,aj as H,O as P}from"./vendor-DR-vtVVc.js";import"./vendor-vue-l2lnRGj2.js";import"./vendor-axios-B9ygI19o.js";async function F(){const{data:u}=await x.get("/screenshots");return u}async function J(u){const{data:f}=await x.delete(`/screenshots/${encodeURIComponent(u)}`);return f}async function Q(){const{data:u}=await x.post("/screenshots/clear",{});return u}const Y={class:"panel-head"},q={class:"panel-actions"},G={key:1,class:"grid"},K=["src","alt","onError","onClick"],X={class:"shot-body"},Z=["title"],ee={class:"shot-meta app-muted"},te={class:"shot-actions"},ne={class:"preview"},ae=["src","alt"],oe={__name:"ScreenshotsPage",setup(u){const f=g(!1),l=g([]),p=g(!1),b=g(""),C=g("");function h(e){return`/screenshots/${encodeURIComponent(e)}`}function L(e){return`/screenshots/thumb/${encodeURIComponent(e)}`}async function B(){f.value=!0;try{const e=await F();l.value=Array.isArray(e)?e:[]}catch(e){e?.response?.status===401&&(window.location.href="/login"),l.value=[]}finally{f.value=!1}}function R(e){C.value=e.display_name||e.filename||"截图预览",b.value=h(e.filename),p.value=!0}function S(e,t){const n=e?.target;n&&n.dataset.fullLoaded!=="1"&&(n.dataset.fullLoaded="1",n.src=h(t.filename))}function T(e){return new Promise((t,n)=>{e.toBlob(o=>o?t(o):n(new Error("toBlob_failed")),"image/png")})}async function V(e){if(!e)throw new Error("no_image");(!e.complete||e.naturalWidth<=0)&&(typeof e.decode=="function"?await e.decode():await new Promise((o,m)=>{e.addEventListener("load",o,{once:!0}),e.addEventListener("error",m,{once:!0})}));const t=document.createElement("canvas");t.width=e.naturalWidth,t.height=e.naturalHeight;const n=t.getContext("2d");if(!n)throw new Error("no_canvas");return n.drawImage(e,0,0),await T(t)}async function z(e){if(!e)throw new Error("no_blob");if(e.type==="image/png")return e;if(typeof createImageBitmap=="function"){const n=await createImageBitmap(e),o=document.createElement("canvas");o.width=n.width,o.height=n.height;const m=o.getContext("2d");if(!m)throw new Error("no_canvas");return m.drawImage(n,0,0),await T(o)}const t=URL.createObjectURL(e);try{const n=new Image;return n.src=t,typeof n.decode=="function"&&await n.decode(),await V(n)}finally{URL.revokeObjectURL(t)}}async function I(e){const t=await fetch(e,{credentials:"include",cache:"no-store"});if(!t.ok)throw new Error("fetch_failed");const n=await t.blob();if(!(t.headers.get("Content-Type")||n.type||"").startsWith("image/"))throw new Error("not_image");return await z(n)}async function A(){try{await U.confirm("确定要清空全部截图吗?","清空截图",{confirmButtonText:"清空",cancelButtonText:"取消",type:"warning"})}catch{return}try{const e=await Q();if(e?.success){r.success(`已清空(删除 ${e?.deleted||0} 张)`),l.value=[],p.value=!1;return}r.error(e?.error||"操作失败")}catch(e){const t=e?.response?.data;r.error(t?.error||"操作失败")}}async function N(e){try{await U.confirm(`确定要删除截图「${e.display_name||e.filename}」吗?`,"删除截图",{confirmButtonText:"删除",cancelButtonText:"取消",type:"warning"})}catch{return}try{const t=await J(e.filename);if(t?.success){l.value=l.value.filter(n=>n.filename!==e.filename),b.value.includes(encodeURIComponent(e.filename))&&(p.value=!1),r.success("已删除");return}r.error(t?.error||"删除失败")}catch(t){const n=t?.response?.data;r.error(n?.error||"删除失败")}}async function O(e){const t=h(e.filename);if(!navigator.clipboard||typeof navigator.clipboard.write!="function"||typeof window.ClipboardItem>"u"){r.warning("当前环境不支持复制图片(建议使用 Chrome/Edge 并通过 HTTPS 访问);可用“下载”。");return}try{try{await navigator.clipboard.write([new ClipboardItem({"image/png":I(t)})])}catch{const n=await I(t);await navigator.clipboard.write([new ClipboardItem({"image/png":n})])}r.success("图片已复制到剪贴板")}catch{try{if(navigator.clipboard&&typeof navigator.clipboard.writeText=="function"){await navigator.clipboard.writeText(`${window.location.origin}${t}`),r.warning("复制图片失败,已复制图片链接(可直接粘贴到浏览器打开)");return}}catch{}r.warning("复制图片失败:请确认允许剪贴板权限;可用“下载”。")}}function j(e){const t=document.createElement("a");t.href=h(e.filename),t.download=e.display_name||e.filename,document.body.appendChild(t),t.click(),t.remove()}return D(B),(e,t)=>{const n=y("el-button"),o=y("el-skeleton"),m=y("el-empty"),E=y("el-card"),M=y("el-dialog");return c(),_(E,{shadow:"never",class:"panel","body-style":{padding:"14px"}},{default:s(()=>[i("div",Y,[t[4]||(t[4]=i("div",{class:"panel-title"},"截图管理",-1)),i("div",q,[d(n,{loading:f.value,onClick:B},{default:s(()=>[...t[2]||(t[2]=[w("刷新",-1)])]),_:1},8,["loading"]),d(n,{type:"danger",plain:"",disabled:l.value.length===0,onClick:A},{default:s(()=>[...t[3]||(t[3]=[w("清空全部",-1)])]),_:1},8,["disabled"])])]),f.value?(c(),_(o,{key:0,rows:6,animated:""})):(c(),k($,{key:1},[l.value.length===0?(c(),_(m,{key:0,description:"暂无截图"})):(c(),k("div",G,[(c(!0),k($,null,H(l.value,a=>(c(),_(E,{key:a.filename,shadow:"never",class:"shot-card","body-style":{padding:"0"}},{default:s(()=>[i("img",{class:"shot-img",src:L(a.filename),alt:a.display_name||a.filename,loading:"lazy",onError:v=>S(v,a),onClick:v=>R(a)},null,40,K),i("div",X,[i("div",{class:"shot-name",title:a.display_name||a.filename},P(a.display_name||a.filename),9,Z),i("div",ee,P(a.created||""),1),i("div",te,[d(n,{size:"small",text:"",type:"primary",onClick:v=>O(a)},{default:s(()=>[...t[5]||(t[5]=[w("复制图片",-1)])]),_:1},8,["onClick"]),d(n,{size:"small",text:"",onClick:v=>j(a)},{default:s(()=>[...t[6]||(t[6]=[w("下载",-1)])]),_:1},8,["onClick"]),d(n,{size:"small",text:"",type:"danger",onClick:v=>N(a)},{default:s(()=>[...t[7]||(t[7]=[w("删除",-1)])]),_:1},8,["onClick"])])])]),_:2},1024))),128))]))],64)),d(M,{modelValue:p.value,"onUpdate:modelValue":t[1]||(t[1]=a=>p.value=a),title:C.value,width:"min(920px, 94vw)"},{footer:s(()=>[d(n,{onClick:t[0]||(t[0]=a=>p.value=!1)},{default:s(()=>[...t[8]||(t[8]=[w("关闭",-1)])]),_:1})]),default:s(()=>[i("div",ne,[i("img",{src:b.value,alt:C.value,class:"preview-img"},null,8,ae)])]),_:1},8,["modelValue","title"])]),_:1})}}},de=W(oe,[["__scopeId","data-v-76fa8f53"]]);export{de as default}; diff --git a/static/app/assets/VerifyResultPage-CdTQeWQk.js b/static/app/assets/VerifyResultPage-CSJomZjC.js similarity index 97% rename from static/app/assets/VerifyResultPage-CdTQeWQk.js rename to static/app/assets/VerifyResultPage-CSJomZjC.js index dbc15a8..487deb2 100644 --- a/static/app/assets/VerifyResultPage-CdTQeWQk.js +++ b/static/app/assets/VerifyResultPage-CSJomZjC.js @@ -1 +1 @@ -import{p as U}from"./vendor-vue-l2lnRGj2.js";import{_ as E}from"./index-C4rfJ09l.js";import{r as o,c as h,v as R,a0 as z,z as B,Q as i,J as s,aY as d,A as _,B as l,L as k,I as W,N,O as v}from"./vendor-DR-vtVVc.js";import"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const $={class:"auth-wrap"},j={class:"actions"},D={key:0,class:"countdown app-muted"},J={__name:"VerifyResultPage",setup(M){const T=U(),p=o(!1),f=o(""),m=o(""),w=o(""),y=o(""),r=o(""),u=o(""),c=o(""),n=o(0);let a=null;function x(){if(typeof window>"u")return null;const e=window.__APP_INITIAL_STATE__;return!e||typeof e!="object"?null:(window.__APP_INITIAL_STATE__=null,e)}function A(e){const t=!!e?.success;p.value=t,f.value=e?.title||(t?"验证成功":"验证失败"),m.value=e?.message||e?.error_message||(t?"操作已完成,现在可以继续使用系统。":"操作失败,请稍后重试。"),w.value=e?.primary_label||(t?"立即登录":"重新注册"),y.value=e?.primary_url||(t?"/login":"/register"),r.value=e?.secondary_label||(t?"":"返回登录"),u.value=e?.secondary_url||(t?"":"/login"),c.value=e?.redirect_url||(t?"/login":""),n.value=Number(e?.redirect_seconds||(t?5:0))||0}const C=h(()=>!!(r.value&&u.value)),b=h(()=>!!(c.value&&n.value>0));async function g(e){if(e){if(e.startsWith("http://")||e.startsWith("https://")){window.location.href=e;return}await T.push(e)}}function L(){b.value&&(a=window.setInterval(()=>{n.value-=1,n.value<=0&&(window.clearInterval(a),a=null,window.location.href=c.value)},1e3))}return R(()=>{const e=x();A(e),L()}),z(()=>{a&&window.clearInterval(a)}),(e,t)=>{const I=d("el-button"),P=d("el-result"),V=d("el-card");return _(),B("div",$,[i(V,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:s(()=>[t[2]||(t[2]=l("div",{class:"brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"验证结果")],-1)),i(P,{icon:p.value?"success":"error",title:f.value,"sub-title":m.value,class:"result"},{extra:s(()=>[l("div",j,[i(I,{type:"primary",onClick:t[0]||(t[0]=S=>g(y.value))},{default:s(()=>[N(v(w.value),1)]),_:1}),C.value?(_(),W(I,{key:0,onClick:t[1]||(t[1]=S=>g(u.value))},{default:s(()=>[N(v(r.value),1)]),_:1})):k("",!0)]),b.value?(_(),B("div",D,v(n.value)+" 秒后自动跳转... ",1)):k("",!0)]),_:1},8,["icon","title","sub-title"])]),_:1})])}}},G=E(J,[["__scopeId","data-v-1fc6b081"]]);export{G as default}; +import{p as U}from"./vendor-vue-l2lnRGj2.js";import{_ as E}from"./index-DIRUAu3R.js";import{r as o,c as h,v as R,a0 as z,z as B,Q as i,J as s,aY as d,A as _,B as l,L as k,I as W,N,O as v}from"./vendor-DR-vtVVc.js";import"./vendor-element-D5SbqSD5.js";import"./vendor-axios-B9ygI19o.js";const $={class:"auth-wrap"},j={class:"actions"},D={key:0,class:"countdown app-muted"},J={__name:"VerifyResultPage",setup(M){const T=U(),p=o(!1),f=o(""),m=o(""),w=o(""),y=o(""),r=o(""),u=o(""),c=o(""),n=o(0);let a=null;function x(){if(typeof window>"u")return null;const e=window.__APP_INITIAL_STATE__;return!e||typeof e!="object"?null:(window.__APP_INITIAL_STATE__=null,e)}function A(e){const t=!!e?.success;p.value=t,f.value=e?.title||(t?"验证成功":"验证失败"),m.value=e?.message||e?.error_message||(t?"操作已完成,现在可以继续使用系统。":"操作失败,请稍后重试。"),w.value=e?.primary_label||(t?"立即登录":"重新注册"),y.value=e?.primary_url||(t?"/login":"/register"),r.value=e?.secondary_label||(t?"":"返回登录"),u.value=e?.secondary_url||(t?"":"/login"),c.value=e?.redirect_url||(t?"/login":""),n.value=Number(e?.redirect_seconds||(t?5:0))||0}const C=h(()=>!!(r.value&&u.value)),b=h(()=>!!(c.value&&n.value>0));async function g(e){if(e){if(e.startsWith("http://")||e.startsWith("https://")){window.location.href=e;return}await T.push(e)}}function L(){b.value&&(a=window.setInterval(()=>{n.value-=1,n.value<=0&&(window.clearInterval(a),a=null,window.location.href=c.value)},1e3))}return R(()=>{const e=x();A(e),L()}),z(()=>{a&&window.clearInterval(a)}),(e,t)=>{const I=d("el-button"),P=d("el-result"),V=d("el-card");return _(),B("div",$,[i(V,{shadow:"never",class:"auth-card","body-style":{padding:"22px"}},{default:s(()=>[t[2]||(t[2]=l("div",{class:"brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"验证结果")],-1)),i(P,{icon:p.value?"success":"error",title:f.value,"sub-title":m.value,class:"result"},{extra:s(()=>[l("div",j,[i(I,{type:"primary",onClick:t[0]||(t[0]=S=>g(y.value))},{default:s(()=>[N(v(w.value),1)]),_:1}),C.value?(_(),W(I,{key:0,onClick:t[1]||(t[1]=S=>g(u.value))},{default:s(()=>[N(v(r.value),1)]),_:1})):k("",!0)]),b.value?(_(),B("div",D,v(n.value)+" 秒后自动跳转... ",1)):k("",!0)]),_:1},8,["icon","title","sub-title"])]),_:1})])}}},G=E(J,[["__scopeId","data-v-1fc6b081"]]);export{G as default}; diff --git a/static/app/assets/accounts-DpRp0y7G.js b/static/app/assets/accounts-DWKsGalm.js similarity index 93% rename from static/app/assets/accounts-DpRp0y7G.js rename to static/app/assets/accounts-DWKsGalm.js index 6b660c2..0937ce6 100644 --- a/static/app/assets/accounts-DpRp0y7G.js +++ b/static/app/assets/accounts-DWKsGalm.js @@ -1 +1 @@ -import{p as c}from"./index-C4rfJ09l.js";async function o(t={}){const{data:a}=await c.get("/accounts",{params:t});return a}async function u(t){const{data:a}=await c.post("/accounts",t);return a}async function r(t,a){const{data:n}=await c.put(`/accounts/${t}`,a);return n}async function e(t){const{data:a}=await c.delete(`/accounts/${t}`);return a}async function i(t,a){const{data:n}=await c.put(`/accounts/${t}/remark`,a);return n}async function p(t,a){const{data:n}=await c.post(`/accounts/${t}/start`,a);return n}async function d(t){const{data:a}=await c.post(`/accounts/${t}/stop`,{});return a}async function f(t){const{data:a}=await c.post("/accounts/batch/start",t);return a}async function w(t){const{data:a}=await c.post("/accounts/batch/stop",t);return a}async function y(){const{data:t}=await c.post("/accounts/clear",{});return t}async function A(t,a={}){const{data:n}=await c.post(`/accounts/${t}/screenshot`,a);return n}export{w as a,f as b,y as c,d,e,o as f,u as g,i as h,p as s,A as t,r as u}; +import{p as c}from"./index-DIRUAu3R.js";async function o(t={}){const{data:a}=await c.get("/accounts",{params:t});return a}async function u(t){const{data:a}=await c.post("/accounts",t);return a}async function r(t,a){const{data:n}=await c.put(`/accounts/${t}`,a);return n}async function e(t){const{data:a}=await c.delete(`/accounts/${t}`);return a}async function i(t,a){const{data:n}=await c.put(`/accounts/${t}/remark`,a);return n}async function p(t,a){const{data:n}=await c.post(`/accounts/${t}/start`,a);return n}async function d(t){const{data:a}=await c.post(`/accounts/${t}/stop`,{});return a}async function f(t){const{data:a}=await c.post("/accounts/batch/start",t);return a}async function w(t){const{data:a}=await c.post("/accounts/batch/stop",t);return a}async function y(){const{data:t}=await c.post("/accounts/clear",{});return t}async function A(t,a={}){const{data:n}=await c.post(`/accounts/${t}/screenshot`,a);return n}export{w as a,f as b,y as c,d,e,o as f,u as g,i as h,p as s,A as t,r as u}; diff --git a/static/app/assets/auth-CtTBVBJk.js b/static/app/assets/auth-3qca7BnL.js similarity index 89% rename from static/app/assets/auth-CtTBVBJk.js rename to static/app/assets/auth-3qca7BnL.js index 9757402..09fba5f 100644 --- a/static/app/assets/auth-CtTBVBJk.js +++ b/static/app/assets/auth-3qca7BnL.js @@ -1 +1 @@ -import{p as s}from"./index-C4rfJ09l.js";async function r(){const{data:a}=await s.get("/email/verify-status");return a}async function o(){const{data:a}=await s.post("/generate_captcha",{});return a}async function e(a){const{data:t}=await s.post("/login",a);return t}async function i(a){const{data:t}=await s.post("/register",a);return t}async function c(a){const{data:t}=await s.post("/resend-verify-email",a);return t}async function f(a){const{data:t}=await s.post("/forgot-password",a);return t}async function u(a){const{data:t}=await s.post("/reset-password-confirm",a);return t}export{f as a,i as b,u as c,r as f,o as g,e as l,c as r}; +import{p as s}from"./index-DIRUAu3R.js";async function r(){const{data:a}=await s.get("/email/verify-status");return a}async function o(){const{data:a}=await s.post("/generate_captcha",{});return a}async function e(a){const{data:t}=await s.post("/login",a);return t}async function i(a){const{data:t}=await s.post("/register",a);return t}async function c(a){const{data:t}=await s.post("/resend-verify-email",a);return t}async function f(a){const{data:t}=await s.post("/forgot-password",a);return t}async function u(a){const{data:t}=await s.post("/reset-password-confirm",a);return t}export{f as a,i as b,u as c,r as f,o as g,e as l,c as r}; diff --git a/static/app/assets/index-C4rfJ09l.js b/static/app/assets/index-C4rfJ09l.js deleted file mode 100644 index d167396..0000000 --- a/static/app/assets/index-C4rfJ09l.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./LoginPage-B4Cm3mBQ.js","./vendor-DR-vtVVc.js","./vendor-vue-l2lnRGj2.js","./vendor-element-D5SbqSD5.js","./vendor-element-BaI2aKL6.css","./auth-CtTBVBJk.js","./vendor-axios-B9ygI19o.js","./LoginPage-DKpbim43.css","./RegisterPage-DDkEhw5Z.js","./RegisterPage-BOcNcW5D.css","./ResetPasswordPage-DTBT5Kre.js","./ResetPasswordPage-DybfLMAw.css","./VerifyResultPage-CdTQeWQk.js","./VerifyResultPage-CG6ZYNrm.css","./AccountsPage-Cj2MTk-l.js","./accounts-DpRp0y7G.js","./vendor-socket-ciQGyZ7q.js","./AccountsPage-CRlBbogn.css","./SchedulesPage-DtRro62b.js","./SchedulesPage-DwfusXou.css","./ScreenshotsPage-BMPLt3Or.js","./ScreenshotsPage-ByqUbmUI.css"])))=>i.map(i=>d[i]); -import{aY as d,I as y,A as u,r as v,a1 as ve,v as lt,a0 as it,c as rt,ba as ut,J as n,L as U,Q as s,B as l,z as A,P as te,aj as _e,M as Le,O as P,N as m,u as S,K as ye,aD as ct,bv as dt}from"./vendor-DR-vtVVc.js";import{o as ft,u as mt,p as pt,q as vt,r as _t,s as yt}from"./vendor-vue-l2lnRGj2.js";import{E as p,u as wt,f as gt,g as bt,h as Ae,j as ht,z as kt}from"./vendor-element-D5SbqSD5.js";import{a as Vt}from"./vendor-axios-B9ygI19o.js";(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))r(c);new MutationObserver(c=>{for(const _ of c)if(_.type==="childList")for(const b of _.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&r(b)}).observe(document,{childList:!0,subtree:!0});function f(c){const _={};return c.integrity&&(_.integrity=c.integrity),c.referrerPolicy&&(_.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?_.credentials="include":c.crossOrigin==="anonymous"?_.credentials="omit":_.credentials="same-origin",_}function r(c){if(c.ep)return;c.ep=!0;const _=f(c);fetch(c.href,_)}})();const Ue=(t,i)=>{const f=t.__vccOpts||t;for(const[r,c]of i)f[r]=c;return f},Et={};function Pt(t,i){const f=d("RouterView");return u(),y(f)}const xt=Ue(Et,[["render",Pt]]),Ct="modulepreload",St=function(t,i){return new URL(t,i).href},Ie={},M=function(i,f,r){let c=Promise.resolve();if(f&&f.length>0){let j=function(E){return Promise.all(E.map(O=>Promise.resolve(O).then(N=>({status:"fulfilled",value:N}),N=>({status:"rejected",reason:N}))))};const b=document.getElementsByTagName("link"),h=document.querySelector("meta[property=csp-nonce]"),I=h?.nonce||h?.getAttribute("nonce");c=j(f.map(E=>{if(E=St(E,r),E in Ie)return;Ie[E]=!0;const O=E.endsWith(".css"),N=O?'[rel="stylesheet"]':"";if(r)for(let $=b.length-1;$>=0;$--){const K=b[$];if(K.href===E&&(!O||K.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${E}"]${N}`))return;const T=document.createElement("link");if(T.rel=O?"stylesheet":Ct,O||(T.as="script"),T.crossOrigin="",T.href=E,I&&T.setAttribute("nonce",I),document.head.appendChild(T),O)return new Promise(($,K)=>{T.addEventListener("load",$),T.addEventListener("error",()=>K(new Error(`Unable to preload CSS for ${E}`)))})}))}function _(b){const h=new Event("vite:preloadError",{cancelable:!0});if(h.payload=b,window.dispatchEvent(h),!h.defaultPrevented)throw b}return c.then(b=>{for(const h of b||[])h.status==="rejected"&&_(h.reason);return i().catch(_)})};let Oe="",Te=0;function ne(t,i,f=1500){const r=Date.now();t===Oe&&r-Te{const i=String(t?.method||"GET").toUpperCase();if(!["GET","HEAD","OPTIONS"].includes(i)){const f=Lt("csrf_token");f&&(t.headers=t.headers||{},t.headers["X-CSRF-Token"]=f)}return t});g.interceptors.response.use(t=>t,t=>{const i=t?.response?.status,f=t?.response?.data,r=f?.error||f?.message||t?.message||"请求失败";return i===401?(window.location?.pathname||"").startsWith("/login")||(ne("401",r,3e3),window.location.href="/login"):i===403?ne("403",r,5e3):t?.code==="ECONNABORTED"?ne("timeout","请求超时",3e3):i||ne(`net:${r}`,r,3e3),Promise.reject(t)});async function At(){const{data:t}=await g.get("/announcements/active");return t}async function It(t){const{data:i}=await g.post(`/announcements/${t}/dismiss`,{});return i}async function Ot(t){const{data:i}=await g.post("/feedback",t);return i}async function Tt(){const{data:t}=await g.get("/feedback");return t}async function Rt(){const{data:t}=await g.get("/user/email");return t}async function Ut(t){const{data:i}=await g.post("/user/bind-email",t);return i}async function Nt(){const{data:t}=await g.post("/user/unbind-email",{});return t}async function Dt(){const{data:t}=await g.get("/user/email-notify");return t}async function Bt(t){const{data:i}=await g.post("/user/email-notify",t);return i}async function $t(t){const{data:i}=await g.post("/user/password",t);return i}async function Ft(){const{data:t}=await g.get("/user/kdocs");return t}async function Mt(t){const{data:i}=await g.post("/user/kdocs",t);return i}async function Bn(){const{data:t}=await g.get("/kdocs/status");return t}async function Kt(){const{data:t}=await g.get("/user/vip");return t}async function zt(){const{data:t}=await g.post("/logout",{});return t}const jt=ft("user",{state:()=>({vipInfo:null,loading:!1}),getters:{username:t=>t.vipInfo?.username||"",isVip:t=>!!t.vipInfo?.is_vip,vipDaysLeft:t=>Number(t.vipInfo?.days_left||0),vipExpireTime:t=>t.vipInfo?.expire_time||""},actions:{async refreshVipInfo(){this.loading=!0;try{this.vipInfo=await Kt()}finally{this.loading=!1}},async logout(){try{await zt()}catch{}}}});function qt(t){const i=String(t||"");return i.length<8?{ok:!1,message:"密码长度至少8位"}:!/[a-zA-Z]/.test(i)||!/\d/.test(i)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}const Wt={class:"header-left"},Gt={class:"header-right"},Ht={class:"user-meta"},Qt={class:"user-name"},Jt={key:2,class:"vip-warn"},Xt={class:"drawer-user"},Yt={class:"user-name"},Zt={class:"drawer-actions"},en={class:"announcement-body"},tn={class:"announcement-content"},nn={key:0,class:"announcement-image"},an=["src"],sn={class:"feedback-title"},on={class:"feedback-title-text"},ln={class:"feedback-time app-muted"},rn={class:"feedback-body"},un={class:"feedback-section"},cn={class:"feedback-text"},dn={key:0,class:"feedback-section"},fn={class:"feedback-text"},mn={class:"settings-section"},pn={class:"email-row"},vn={class:"email-value"},_n={class:"notify-row"},yn={class:"settings-section"},wn={class:"settings-section"},gn={class:"settings-section"},bn={key:0,class:"vip-info"},hn={class:"vip-line"},kn={class:"vip-line"},Vn={key:1,class:"vip-info"},En={__name:"AppLayout",setup(t){const i=mt(),f=pt(),r=jt(),c=v(!1),_=v(!1);let b;const h=v(!1),I=v(null),j=v(!1),E=(()=>{try{const a=window.performance?.timeOrigin;if(typeof a=="number"&&Number.isFinite(a))return String(a)}catch{}return String(Date.now())})();function O(a){return`announcement_closed_once_${a}`}function N(a){return`announcement_closed_${a}`}function T(a){try{return window.sessionStorage.getItem(O(a))===E}catch{return!1}}function $(a){try{return window.localStorage.getItem(N(a))==="1"}catch{return!1}}function K(a){try{window.sessionStorage.setItem(O(a),E)}catch{}}function Ne(a){try{window.localStorage.setItem(N(a),"1")}catch{}}const q=v(!1),W=v("new"),ae=v(!1),se=v(!1),Y=v([]),V=ve({title:"",description:"",contact:""}),Z=v(!1),oe=v("email"),le=v(!1),ie=v(!1),x=ve({email:"",email_verified:!1}),G=v(""),H=v(!1),F=v(!0),re=v(!1),L=ve({current_password:"",new_password:"",confirm_password:""}),ue=v(!1),ce=v(!1),Q=v("");function de(){c.value=!!b?.matches,c.value||(_.value=!1)}lt(()=>{b=window.matchMedia("(max-width: 768px)"),b.addEventListener?.("change",de),de(),r.refreshVipInfo().catch(()=>{window.location.href="/login"}),Ge()}),it(()=>{b?.removeEventListener?.("change",de)});const we=[{path:"/app/accounts",label:"账号管理",icon:wt},{path:"/app/schedules",label:"定时任务",icon:gt},{path:"/app/screenshots",label:"截图管理",icon:bt}],ge=rt(()=>i.path);async function be(a){await f.push(a),_.value=!1}async function he(){try{await Ae.confirm("确定退出登录吗?","退出登录",{confirmButtonText:"退出",cancelButtonText:"取消",type:"warning"})}catch{return}await r.logout(),window.location.href="/login"}function ke(){W.value="new",V.title="",V.description="",V.contact="",q.value=!0}async function Ve(){se.value=!0;try{const a=await Tt();Y.value=Array.isArray(a)?a:[]}catch{Y.value=[]}finally{se.value=!1}}function De(a){return a==="replied"?"已回复":a==="closed"?"已关闭":"待处理"}function Be(a){return a==="replied"?"success":a==="closed"?"info":"warning"}async function $e(){const a=V.title.trim(),e=V.description.trim(),k=V.contact.trim();if(!a||!e){p.error("标题和描述不能为空");return}ae.value=!0;try{const C=await Ot({title:a,description:e,contact:k});p.success(C?.message||"反馈提交成功"),q.value=!1,V.title="",V.description="",V.contact=""}catch(C){const R=C?.response?.data;p.error(R?.error||"提交失败")}finally{ae.value=!1}}async function Ee(){Z.value=!0,oe.value="email",await Fe()}async function Fe(){await Promise.all([Pe(),Me(),Ke()])}async function Pe(){le.value=!0;try{const a=await Rt();x.email=a?.email||"",x.email_verified=!!a?.email_verified,G.value=x.email||""}catch{x.email="",x.email_verified=!1,G.value=""}finally{le.value=!1}}async function Me(){H.value=!0;try{const a=await Dt();F.value=!!a?.enabled}catch{F.value=!0}finally{H.value=!1}}async function Ke(){ue.value=!0;try{const a=await Ft();Q.value=a?.kdocs_unit||""}catch{Q.value=""}finally{ue.value=!1}}async function ze(){ce.value=!0;try{await Mt({kdocs_unit:Q.value.trim()}),p.success("已更新表格县区设置")}catch{}finally{ce.value=!1}}async function je(){const a=G.value.trim().toLowerCase();if(!a){p.error("请输入邮箱地址");return}if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a)){p.error("邮箱格式不正确");return}ie.value=!0;try{const k=await Ut({email:a});p.success(k?.message||"验证邮件已发送"),x.email=a,x.email_verified=!1}catch(k){const C=k?.response?.data;p.error(C?.error||"绑定失败")}finally{ie.value=!1}}async function qe(){try{await Ae.confirm("确定要解绑当前邮箱吗?","解绑邮箱",{confirmButtonText:"解绑",cancelButtonText:"取消",type:"warning"})}catch{return}try{const a=await Nt();if(a?.success){p.success(a?.message||"邮箱已解绑"),await Pe();return}p.error(a?.error||"解绑失败")}catch(a){const e=a?.response?.data;p.error(e?.error||"解绑失败")}}async function We(a){const e=F.value;F.value=!!a,H.value=!0;try{const k=await Bt({enabled:!!a});if(k?.success){p.success("已更新");return}F.value=e,p.error(k?.error||"更新失败")}catch(k){F.value=e;const C=k?.response?.data;p.error(C?.error||"更新失败")}finally{H.value=!1}}async function xe(){const a=L.current_password,e=L.new_password,k=L.confirm_password;if(!a||!e||!k){p.error("请填写完整信息");return}const C=qt(e);if(!C.ok){p.error(C.message);return}if(e!==k){p.error("两次输入的新密码不一致");return}re.value=!0;try{const R=await $t({current_password:a,new_password:e});if(R?.success){p.success("密码修改成功"),L.current_password="",L.new_password="",L.confirm_password="";return}p.error(R?.error||"修改失败")}catch(R){const fe=R?.response?.data;p.error(fe?.error||"修改失败")}finally{re.value=!1}}async function Ge(){j.value=!0;try{const e=(await At())?.announcement;if(!e?.id||$(e.id)||T(e.id))return;I.value=e,h.value=!0}catch{}finally{j.value=!1}}function He(){const a=I.value;a?.id&&K(a.id),h.value=!1}async function Qe(){const a=I.value;if(!a?.id){h.value=!1;return}Ne(a.id);try{(await It(a.id))?.success&&p.success("已永久关闭")}catch{}finally{h.value=!1}}return(a,e)=>{const k=d("el-icon"),C=d("el-menu-item"),R=d("el-menu"),fe=d("el-aside"),w=d("el-button"),J=d("el-tag"),Je=d("el-header"),Xe=d("RouterView"),Ye=d("el-main"),Ce=d("el-container"),Ze=d("el-drawer"),me=d("el-dialog"),D=d("el-input"),B=d("el-form-item"),ee=d("el-form"),z=d("el-tab-pane"),et=d("el-skeleton"),tt=d("el-empty"),nt=d("el-collapse-item"),at=d("el-collapse"),Se=d("el-tabs"),X=d("el-alert"),st=d("el-divider"),ot=d("el-switch"),pe=ut("loading");return u(),y(Ce,{class:"layout-root"},{default:n(()=>[c.value?U("",!0):(u(),y(fe,{key:0,width:"220px",class:"layout-aside"},{default:n(()=>[e[18]||(e[18]=l("div",{class:"brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"用户中心")],-1)),s(R,{"default-active":ge.value,class:"aside-menu",router:"",onSelect:be},{default:n(()=>[(u(),A(te,null,_e(we,o=>s(C,{key:o.path,index:o.path},{default:n(()=>[s(k,null,{default:n(()=>[(u(),y(Le(o.icon)))]),_:2},1024),l("span",null,P(o.label),1)]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1})),s(Ce,null,{default:n(()=>[s(Je,{class:"layout-header"},{default:n(()=>[l("div",Wt,[c.value?(u(),y(w,{key:0,text:"",class:"header-menu-btn",onClick:e[0]||(e[0]=o=>_.value=!0)},{default:n(()=>[...e[19]||(e[19]=[m(" 菜单 ",-1)])]),_:1})):U("",!0),e[20]||(e[20]=l("div",{class:"header-title"},"用户控制台",-1))]),l("div",Gt,[l("div",Ht,[S(r).isVip?(u(),y(J,{key:0,type:"success",size:"small",effect:"light"},{default:n(()=>[...e[21]||(e[21]=[m("VIP",-1)])]),_:1})):(u(),y(J,{key:1,type:"info",size:"small",effect:"light"},{default:n(()=>[...e[22]||(e[22]=[m("普通",-1)])]),_:1})),l("span",Qt,P(S(r).username||"用户"),1),S(r).isVip&&S(r).vipDaysLeft<=7&&S(r).vipDaysLeft>0?(u(),A("span",Jt," ("+P(S(r).vipDaysLeft)+"天后到期) ",1)):U("",!0)]),s(w,{text:"",type:"primary",onClick:ke},{default:n(()=>[...e[23]||(e[23]=[m("反馈",-1)])]),_:1}),s(w,{text:"",onClick:Ee},{default:n(()=>[...e[24]||(e[24]=[m("设置",-1)])]),_:1}),s(w,{type:"primary",plain:"",onClick:he},{default:n(()=>[...e[25]||(e[25]=[m("退出",-1)])]),_:1})])]),_:1}),s(Ye,{class:"layout-main"},{default:n(()=>[s(Xe)]),_:1})]),_:1}),s(Ze,{modelValue:_.value,"onUpdate:modelValue":e[1]||(e[1]=o=>_.value=o),size:"240px","with-header":!1},{default:n(()=>[e[31]||(e[31]=l("div",{class:"drawer-brand"},[l("div",{class:"brand-title"},"知识管理平台"),l("div",{class:"brand-sub app-muted"},"用户中心")],-1)),l("div",Xt,[S(r).isVip?(u(),y(J,{key:0,type:"success",size:"small",effect:"light"},{default:n(()=>[...e[26]||(e[26]=[m("VIP",-1)])]),_:1})):(u(),y(J,{key:1,type:"info",size:"small",effect:"light"},{default:n(()=>[...e[27]||(e[27]=[m("普通",-1)])]),_:1})),l("span",Yt,P(S(r).username||"用户"),1)]),s(R,{"default-active":ge.value,class:"aside-menu",router:"",onSelect:be},{default:n(()=>[(u(),A(te,null,_e(we,o=>s(C,{key:o.path,index:o.path},{default:n(()=>[s(k,null,{default:n(()=>[(u(),y(Le(o.icon)))]),_:2},1024),l("span",null,P(o.label),1)]),_:2},1032,["index"])),64))]),_:1},8,["default-active"]),l("div",Zt,[s(w,{text:"",type:"primary",style:{width:"100%"},onClick:ke},{default:n(()=>[...e[28]||(e[28]=[m("问题反馈",-1)])]),_:1}),s(w,{text:"",style:{width:"100%"},onClick:Ee},{default:n(()=>[...e[29]||(e[29]=[m("个人设置",-1)])]),_:1}),s(w,{type:"primary",plain:"",style:{width:"100%"},onClick:he},{default:n(()=>[...e[30]||(e[30]=[m("退出登录",-1)])]),_:1})])]),_:1},8,["modelValue"]),s(me,{modelValue:h.value,"onUpdate:modelValue":e[2]||(e[2]=o=>h.value=o),width:"min(560px, 92vw)",title:I.value?.title||"系统公告"},{footer:n(()=>[s(w,{onClick:He},{default:n(()=>[...e[32]||(e[32]=[m("当次关闭",-1)])]),_:1}),s(w,{type:"primary",onClick:Qe},{default:n(()=>[...e[33]||(e[33]=[m("永久关闭",-1)])]),_:1})]),default:n(()=>[ye((u(),A("div",en,[l("div",tn,P(I.value?.content||""),1),I.value?.image_url?(u(),A("div",nn,[l("img",{src:I.value.image_url,alt:"公告图片",loading:"lazy"},null,8,an)])):U("",!0)])),[[pe,j.value]])]),_:1},8,["modelValue","title"]),s(me,{modelValue:q.value,"onUpdate:modelValue":e[9]||(e[9]=o=>q.value=o),title:"问题反馈",width:"min(720px, 92vw)"},{footer:n(()=>[s(w,{onClick:e[8]||(e[8]=o=>q.value=!1)},{default:n(()=>[...e[36]||(e[36]=[m("关闭",-1)])]),_:1}),W.value==="list"?(u(),y(w,{key:0,onClick:Ve},{default:n(()=>[...e[37]||(e[37]=[m("刷新",-1)])]),_:1})):U("",!0),W.value==="new"?(u(),y(w,{key:1,type:"primary",loading:ae.value,onClick:$e},{default:n(()=>[...e[38]||(e[38]=[m("提交",-1)])]),_:1},8,["loading"])):U("",!0)]),default:n(()=>[s(Se,{modelValue:W.value,"onUpdate:modelValue":e[6]||(e[6]=o=>W.value=o),onTabChange:e[7]||(e[7]=o=>o==="list"&&Ve())},{default:n(()=>[s(z,{label:"提交反馈",name:"new"},{default:n(()=>[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"标题"},{default:n(()=>[s(D,{modelValue:V.title,"onUpdate:modelValue":e[3]||(e[3]=o=>V.title=o),placeholder:"简要描述问题",maxlength:"100","show-word-limit":""},null,8,["modelValue"])]),_:1}),s(B,{label:"详细描述"},{default:n(()=>[s(D,{modelValue:V.description,"onUpdate:modelValue":e[4]||(e[4]=o=>V.description=o),type:"textarea",rows:5,placeholder:"请详细描述您遇到的问题",maxlength:"2000","show-word-limit":""},null,8,["modelValue"])]),_:1}),s(B,{label:"联系方式(可选)"},{default:n(()=>[s(D,{modelValue:V.contact,"onUpdate:modelValue":e[5]||(e[5]=o=>V.contact=o),placeholder:"方便我们联系您"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1}),s(z,{label:"我的反馈",name:"list"},{default:n(()=>[se.value?(u(),y(et,{key:0,rows:6,animated:""})):(u(),A(te,{key:1},[Y.value.length===0?(u(),y(tt,{key:0,description:"暂无反馈"})):(u(),y(at,{key:1,accordion:""},{default:n(()=>[(u(!0),A(te,null,_e(Y.value,o=>(u(),y(nt,{key:o.id,name:String(o.id)},{title:n(()=>[l("div",sn,[l("span",on,P(o.title),1),s(J,{size:"small",effect:"light",type:Be(o.status)},{default:n(()=>[m(P(De(o.status)),1)]),_:2},1032,["type"]),l("span",ln,P(o.created_at||""),1)])]),default:n(()=>[l("div",rn,[l("div",un,[e[34]||(e[34]=l("div",{class:"feedback-label app-muted"},"描述",-1)),l("div",cn,P(o.description),1)]),o.admin_reply?(u(),A("div",dn,[e[35]||(e[35]=l("div",{class:"feedback-label app-muted"},"管理员回复",-1)),l("div",fn,P(o.admin_reply),1)])):U("",!0)])]),_:2},1032,["name"]))),128))]),_:1}))],64))]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["modelValue"]),s(me,{modelValue:Z.value,"onUpdate:modelValue":e[17]||(e[17]=o=>Z.value=o),title:"个人设置",width:"min(720px, 92vw)"},{footer:n(()=>[s(w,{onClick:e[16]||(e[16]=o=>Z.value=!1)},{default:n(()=>[...e[47]||(e[47]=[m("关闭",-1)])]),_:1})]),default:n(()=>[s(Se,{modelValue:oe.value,"onUpdate:modelValue":e[15]||(e[15]=o=>oe.value=o)},{default:n(()=>[s(z,{label:"邮箱绑定",name:"email"},{default:n(()=>[ye((u(),A("div",mn,[x.email&&x.email_verified?(u(),y(X,{key:0,type:"success",closable:!1,title:"邮箱已绑定并验证","show-icon":"",class:"settings-alert"},{default:n(()=>[l("div",pn,[l("div",vn,P(x.email),1),s(w,{type:"danger",text:"",onClick:qe},{default:n(()=>[...e[39]||(e[39]=[m("解绑",-1)])]),_:1})])]),_:1})):x.email?(u(),y(X,{key:1,type:"warning",closable:!1,title:"邮箱待验证:请查收验证邮件(含垃圾箱)","show-icon":"",class:"settings-alert"})):U("",!0),s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"邮箱地址"},{default:n(()=>[s(D,{modelValue:G.value,"onUpdate:modelValue":e[10]||(e[10]=o=>G.value=o),placeholder:"name@example.com"},null,8,["modelValue"])]),_:1}),s(w,{type:"primary",loading:ie.value,onClick:je},{default:n(()=>[...e[40]||(e[40]=[m("发送验证邮件",-1)])]),_:1},8,["loading"])]),_:1}),s(st),l("div",_n,[e[41]||(e[41]=l("div",null,[l("div",{class:"notify-title"},"任务完成通知"),l("div",{class:"app-muted notify-desc"},"定时任务完成后发送邮件")],-1)),s(ot,{"model-value":F.value,disabled:!x.email_verified||H.value,"inline-prompt":"","active-text":"开","inactive-text":"关",onChange:We},null,8,["model-value","disabled"])]),x.email_verified?U("",!0):(u(),y(X,{key:2,type:"info",closable:!1,title:"绑定并验证邮箱后可开启邮件通知。","show-icon":"",class:"settings-hint"}))])),[[pe,le.value]])]),_:1}),s(z,{label:"修改密码",name:"password"},{default:n(()=>[l("div",yn,[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"当前密码"},{default:n(()=>[s(D,{modelValue:L.current_password,"onUpdate:modelValue":e[11]||(e[11]=o=>L.current_password=o),type:"password","show-password":"",autocomplete:"current-password"},null,8,["modelValue"])]),_:1}),s(B,{label:"新密码(至少8位且包含字母和数字)"},{default:n(()=>[s(D,{modelValue:L.new_password,"onUpdate:modelValue":e[12]||(e[12]=o=>L.new_password=o),type:"password","show-password":"",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(B,{label:"确认新密码"},{default:n(()=>[s(D,{modelValue:L.confirm_password,"onUpdate:modelValue":e[13]||(e[13]=o=>L.confirm_password=o),type:"password","show-password":"",autocomplete:"new-password",onKeyup:ct(xe,["enter"])},null,8,["modelValue"])]),_:1}),s(w,{type:"primary",loading:re.value,onClick:xe},{default:n(()=>[...e[42]||(e[42]=[m("确认修改",-1)])]),_:1},8,["loading"])]),_:1})])]),_:1}),s(z,{label:"表格上传",name:"kdocs"},{default:n(()=>[ye((u(),A("div",wn,[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"县区(可选)"},{default:n(()=>[s(D,{modelValue:Q.value,"onUpdate:modelValue":e[14]||(e[14]=o=>Q.value=o),placeholder:"留空使用系统默认县区"},null,8,["modelValue"])]),_:1}),s(w,{type:"primary",loading:ce.value,onClick:ze},{default:n(()=>[...e[43]||(e[43]=[m("保存",-1)])]),_:1},8,["loading"])]),_:1}),s(X,{type:"info",closable:!1,title:"自动上传开关在“账号管理”页面设置(测试功能)。","show-icon":"",class:"settings-hint"})])),[[pe,ue.value]])]),_:1}),s(z,{label:"VIP信息",name:"vip"},{default:n(()=>[l("div",gn,[s(X,{type:S(r).isVip?"success":"info",closable:!1,title:S(r).isVip?"当前为 VIP 会员":"当前为普通用户","show-icon":"",class:"settings-alert"},null,8,["type","title"]),S(r).isVip?(u(),A("div",bn,[l("div",hn,[e[44]||(e[44]=l("span",{class:"app-muted"},"到期时间",-1)),l("span",null,P(S(r).vipExpireTime||"未知"),1)]),l("div",kn,[e[45]||(e[45]=l("span",{class:"app-muted"},"剩余天数",-1)),l("span",null,P(S(r).vipDaysLeft),1)])])):(u(),A("div",Vn,[...e[46]||(e[46]=[l("div",{class:"app-muted"},"升级方式:请通过“反馈”联系管理员开通。",-1)])]))])]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])]),_:1})}}},Pn=Ue(En,[["__scopeId","data-v-7ce33baa"]]),xn=()=>M(()=>import("./LoginPage-B4Cm3mBQ.js"),__vite__mapDeps([0,1,2,3,4,5,6,7]),import.meta.url),Cn=()=>M(()=>import("./RegisterPage-DDkEhw5Z.js"),__vite__mapDeps([8,1,2,3,4,5,6,9]),import.meta.url),Sn=()=>M(()=>import("./ResetPasswordPage-DTBT5Kre.js"),__vite__mapDeps([10,1,2,3,4,5,6,11]),import.meta.url),Re=()=>M(()=>import("./VerifyResultPage-CdTQeWQk.js"),__vite__mapDeps([12,2,1,3,4,6,13]),import.meta.url),Ln=()=>M(()=>import("./AccountsPage-Cj2MTk-l.js"),__vite__mapDeps([14,15,16,1,3,2,4,6,17]),import.meta.url),An=()=>M(()=>import("./SchedulesPage-DtRro62b.js"),__vite__mapDeps([18,15,3,1,2,4,6,19]),import.meta.url),In=()=>M(()=>import("./ScreenshotsPage-BMPLt3Or.js"),__vite__mapDeps([20,3,1,2,4,6,21]),import.meta.url),On=[{path:"/",redirect:"/login"},{path:"/login",name:"login",component:xn},{path:"/register",name:"register",component:Cn},{path:"/reset-password/:token",name:"reset_password",component:Sn},{path:"/api/verify-email/:token",name:"verify_email",component:Re},{path:"/api/verify-bind-email/:token",name:"verify_bind_email",component:Re},{path:"/app",component:Pn,children:[{path:"",redirect:"/app/accounts"},{path:"accounts",name:"accounts",component:Ln},{path:"schedules",name:"schedules",component:An},{path:"screenshots",name:"screenshots",component:In}]},{path:"/:pathMatch(.*)*",redirect:"/login"}],Tn=vt({history:_t(),routes:On});dt(xt).use(yt()).use(Tn).use(ht,{locale:kt}).mount("#app");export{Ue as _,Bn as a,Mt as b,Ft as f,g as p,jt as u,qt as v}; diff --git a/static/app/assets/index-DIRUAu3R.js b/static/app/assets/index-DIRUAu3R.js new file mode 100644 index 0000000..f51d0ef --- /dev/null +++ b/static/app/assets/index-DIRUAu3R.js @@ -0,0 +1,2 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./LoginPage-DjXmnzTj.js","./vendor-DR-vtVVc.js","./vendor-vue-l2lnRGj2.js","./vendor-element-D5SbqSD5.js","./vendor-element-BaI2aKL6.css","./auth-3qca7BnL.js","./vendor-axios-B9ygI19o.js","./LoginPage-DKpbim43.css","./RegisterPage-Nvd-XHp4.js","./RegisterPage-BOcNcW5D.css","./ResetPasswordPage-DluVIq7o.js","./ResetPasswordPage-DybfLMAw.css","./VerifyResultPage-CSJomZjC.js","./VerifyResultPage-CG6ZYNrm.css","./AccountsPage-BsKyQ62c.js","./accounts-DWKsGalm.js","./vendor-socket-ciQGyZ7q.js","./AccountsPage-CRlBbogn.css","./SchedulesPage-DglS5EqW.js","./SchedulesPage-DwfusXou.css","./ScreenshotsPage-L5gmloAw.js","./ScreenshotsPage-ByqUbmUI.css"])))=>i.map(i=>d[i]); +import{aY as f,I as y,A as u,r as _,a1 as _e,v as lt,a0 as it,c as rt,ba as ut,J as n,L as N,Q as s,B as i,z as A,P as te,aj as ve,M as Te,O as P,N as m,u as C,K as ye,aD as ct,bv as dt}from"./vendor-DR-vtVVc.js";import{o as ft,u as mt,p as pt,q as _t,r as vt,s as yt}from"./vendor-vue-l2lnRGj2.js";import{E as p,u as wt,f as gt,g as bt,h as Ae,j as ht,z as kt}from"./vendor-element-D5SbqSD5.js";import{a as Vt}from"./vendor-axios-B9ygI19o.js";(function(){const l=document.createElement("link").relList;if(l&&l.supports&&l.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))r(c);new MutationObserver(c=>{for(const v of c)if(v.type==="childList")for(const b of v.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&r(b)}).observe(document,{childList:!0,subtree:!0});function d(c){const v={};return c.integrity&&(v.integrity=c.integrity),c.referrerPolicy&&(v.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?v.credentials="include":c.crossOrigin==="anonymous"?v.credentials="omit":v.credentials="same-origin",v}function r(c){if(c.ep)return;c.ep=!0;const v=d(c);fetch(c.href,v)}})();const Ne=(t,l)=>{const d=t.__vccOpts||t;for(const[r,c]of l)d[r]=c;return d},Et={};function Pt(t,l){const d=f("RouterView");return u(),y(d)}const St=Ne(Et,[["render",Pt]]),xt="modulepreload",Ct=function(t,l){return new URL(t,l).href},Le={},F=function(l,d,r){let c=Promise.resolve();if(d&&d.length>0){let q=function(E){return Promise.all(E.map(R=>Promise.resolve(R).then(U=>({status:"fulfilled",value:U}),U=>({status:"rejected",reason:U}))))};const b=document.getElementsByTagName("link"),h=document.querySelector("meta[property=csp-nonce]"),L=h?.nonce||h?.getAttribute("nonce");c=q(d.map(E=>{if(E=Ct(E,r),E in Le)return;Le[E]=!0;const R=E.endsWith(".css"),U=R?'[rel="stylesheet"]':"";if(r)for(let M=b.length-1;M>=0;M--){const K=b[M];if(K.href===E&&(!R||K.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${E}"]${U}`))return;const O=document.createElement("link");if(O.rel=R?"stylesheet":xt,R||(O.as="script"),O.crossOrigin="",O.href=E,L&&O.setAttribute("nonce",L),document.head.appendChild(O),R)return new Promise((M,K)=>{O.addEventListener("load",M),O.addEventListener("error",()=>K(new Error(`Unable to preload CSS for ${E}`)))})}))}function v(b){const h=new Event("vite:preloadError",{cancelable:!0});if(h.payload=b,window.dispatchEvent(h),!h.defaultPrevented)throw b}return c.then(b=>{for(const h of b||[])h.status==="rejected"&&v(h.reason);return l().catch(v)})};let Re="",Oe=0;const Tt=new Set([408,425,429,500,502,503,504]),At=1,Lt=300;function ne(t,l,d=1500){const r=Date.now();t===Re&&r-Oe=At)return!1;const r=String(t?.code||"");if(r==="ECONNABORTED"||r==="ERR_NETWORK")return!0;const c=Number(t?.response?.status||0);return Tt.has(c)}function Nt(t){return new Promise(l=>{window.setTimeout(l,Math.max(0,Number(t||0)))})}async function Ut(t,l){const d=t?.config||{},r=Number(d.__retry_count||0);d.__retry_count=r+1;const c=Lt*(r+1);return await Nt(c),l.request(d)}const w=Vt.create({baseURL:"/api",timeout:3e4,withCredentials:!0});w.interceptors.request.use(t=>{const l=String(t?.method||"GET").toUpperCase();if(!["GET","HEAD","OPTIONS"].includes(l)){const d=Rt("csrf_token");d&&(t.headers=t.headers||{},t.headers["X-CSRF-Token"]=d)}return t});w.interceptors.response.use(t=>t,t=>{if(It(t))return Ut(t,w);const l=t?.response?.status,d=t?.response?.data,r=d?.error||d?.message||t?.message||"请求失败";return l===401?(window.location?.pathname||"").startsWith("/login")||(ne("401",r,3e3),window.location.href="/login"):l===403?ne("403",r,5e3):t?.code==="ECONNABORTED"?ne("timeout","请求超时",3e3):l||ne(`net:${r}`,r,3e3),Promise.reject(t)});async function Dt(){const{data:t}=await w.get("/announcements/active");return t}async function Bt(t){const{data:l}=await w.post(`/announcements/${t}/dismiss`,{});return l}async function Mt(t){const{data:l}=await w.post("/feedback",t);return l}async function $t(){const{data:t}=await w.get("/feedback");return t}async function Ft(){const{data:t}=await w.get("/user/email");return t}async function Kt(t){const{data:l}=await w.post("/user/bind-email",t);return l}async function zt(){const{data:t}=await w.post("/user/unbind-email",{});return t}async function qt(){const{data:t}=await w.get("/user/email-notify");return t}async function jt(t){const{data:l}=await w.post("/user/email-notify",t);return l}async function Yt(t){const{data:l}=await w.post("/user/password",t);return l}async function Gt(){const{data:t}=await w.get("/user/kdocs");return t}async function Wt(t){const{data:l}=await w.post("/user/kdocs",t);return l}async function jn(){const{data:t}=await w.get("/kdocs/status");return t}async function Ht(){const{data:t}=await w.get("/user/vip");return t}async function Qt(){const{data:t}=await w.post("/logout",{});return t}const Xt=ft("user",{state:()=>({vipInfo:null,loading:!1}),getters:{username:t=>t.vipInfo?.username||"",isVip:t=>!!t.vipInfo?.is_vip,vipDaysLeft:t=>Number(t.vipInfo?.days_left||0),vipExpireTime:t=>t.vipInfo?.expire_time||""},actions:{async refreshVipInfo(){this.loading=!0;try{this.vipInfo=await Ht()}finally{this.loading=!1}},async logout(){try{await Qt()}catch{}}}});function Jt(t){const l=String(t||"");return l.length<8?{ok:!1,message:"密码长度至少8位"}:!/[a-zA-Z]/.test(l)||!/\d/.test(l)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}const Zt={class:"header-left"},en={class:"header-right"},tn={class:"user-meta"},nn={class:"user-name"},an={key:2,class:"vip-warn"},sn={class:"drawer-user"},on={class:"user-name"},ln={class:"drawer-actions"},rn={class:"announcement-body"},un={class:"announcement-content"},cn={key:0,class:"announcement-image"},dn=["src"],fn={class:"feedback-title"},mn={class:"feedback-title-text"},pn={class:"feedback-time app-muted"},_n={class:"feedback-body"},vn={class:"feedback-section"},yn={class:"feedback-text"},wn={key:0,class:"feedback-section"},gn={class:"feedback-text"},bn={class:"settings-section"},hn={class:"email-row"},kn={class:"email-value"},Vn={class:"notify-row"},En={class:"settings-section"},Pn={class:"settings-section"},Sn={class:"settings-section"},xn={key:0,class:"vip-info"},Cn={class:"vip-line"},Tn={class:"vip-line"},An={key:1,class:"vip-info"},Ln={__name:"AppLayout",setup(t){const l=mt(),d=pt(),r=Xt(),c=_(!1),v=_(!1);let b;const h=_(!1),L=_(null),q=_(!1),E=(()=>{try{const a=window.performance?.timeOrigin;if(typeof a=="number"&&Number.isFinite(a))return String(a)}catch{}return String(Date.now())})();function R(a){return`announcement_closed_once_${a}`}function U(a){return`announcement_closed_${a}`}function O(a){try{return window.sessionStorage.getItem(R(a))===E}catch{return!1}}function M(a){try{return window.localStorage.getItem(U(a))==="1"}catch{return!1}}function K(a){try{window.sessionStorage.setItem(R(a),E)}catch{}}function Ue(a){try{window.localStorage.setItem(U(a),"1")}catch{}}const j=_(!1),Y=_("new"),ae=_(!1),se=_(!1),J=_([]),V=_e({title:"",description:"",contact:""}),Z=_(!1),oe=_("email"),le=_(!1),ie=_(!1),S=_e({email:"",email_verified:!1}),G=_(""),W=_(!1),$=_(!0),re=_(!1),T=_e({current_password:"",new_password:"",confirm_password:""}),ue=_(!1),ce=_(!1),H=_("");function de(){c.value=!!b?.matches,c.value||(v.value=!1)}lt(()=>{b=window.matchMedia("(max-width: 768px)"),b.addEventListener?.("change",de),de(),r.refreshVipInfo().catch(()=>{window.location.href="/login"}),Ge()}),it(()=>{b?.removeEventListener?.("change",de)});const we=[{path:"/app/accounts",label:"账号管理",icon:wt},{path:"/app/schedules",label:"定时任务",icon:gt},{path:"/app/screenshots",label:"截图管理",icon:bt}],ge=rt(()=>l.path);async function be(a){await d.push(a),v.value=!1}async function he(){try{await Ae.confirm("确定退出登录吗?","退出登录",{confirmButtonText:"退出",cancelButtonText:"取消",type:"warning"})}catch{return}await r.logout(),window.location.href="/login"}function ke(){Y.value="new",V.title="",V.description="",V.contact="",j.value=!0}async function Ve(){se.value=!0;try{const a=await $t();J.value=Array.isArray(a)?a:[]}catch{J.value=[]}finally{se.value=!1}}function De(a){return a==="replied"?"已回复":a==="closed"?"已关闭":"待处理"}function Be(a){return a==="replied"?"success":a==="closed"?"info":"warning"}async function Me(){const a=V.title.trim(),e=V.description.trim(),k=V.contact.trim();if(!a||!e){p.error("标题和描述不能为空");return}ae.value=!0;try{const x=await Mt({title:a,description:e,contact:k});p.success(x?.message||"反馈提交成功"),j.value=!1,V.title="",V.description="",V.contact=""}catch(x){const I=x?.response?.data;p.error(I?.error||"提交失败")}finally{ae.value=!1}}async function Ee(){Z.value=!0,oe.value="email",await $e()}async function $e(){await Promise.all([Pe(),Fe(),Ke()])}async function Pe(){le.value=!0;try{const a=await Ft();S.email=a?.email||"",S.email_verified=!!a?.email_verified,G.value=S.email||""}catch{S.email="",S.email_verified=!1,G.value=""}finally{le.value=!1}}async function Fe(){W.value=!0;try{const a=await qt();$.value=!!a?.enabled}catch{$.value=!0}finally{W.value=!1}}async function Ke(){ue.value=!0;try{const a=await Gt();H.value=a?.kdocs_unit||""}catch{H.value=""}finally{ue.value=!1}}async function ze(){ce.value=!0;try{await Wt({kdocs_unit:H.value.trim()}),p.success("已更新表格县区设置")}catch{}finally{ce.value=!1}}async function qe(){const a=G.value.trim().toLowerCase();if(!a){p.error("请输入邮箱地址");return}if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a)){p.error("邮箱格式不正确");return}ie.value=!0;try{const k=await Kt({email:a});p.success(k?.message||"验证邮件已发送"),S.email=a,S.email_verified=!1}catch(k){const x=k?.response?.data;p.error(x?.error||"绑定失败")}finally{ie.value=!1}}async function je(){try{await Ae.confirm("确定要解绑当前邮箱吗?","解绑邮箱",{confirmButtonText:"解绑",cancelButtonText:"取消",type:"warning"})}catch{return}try{const a=await zt();if(a?.success){p.success(a?.message||"邮箱已解绑"),await Pe();return}p.error(a?.error||"解绑失败")}catch(a){const e=a?.response?.data;p.error(e?.error||"解绑失败")}}async function Ye(a){const e=$.value;$.value=!!a,W.value=!0;try{const k=await jt({enabled:!!a});if(k?.success){p.success("已更新");return}$.value=e,p.error(k?.error||"更新失败")}catch(k){$.value=e;const x=k?.response?.data;p.error(x?.error||"更新失败")}finally{W.value=!1}}async function Se(){const a=T.current_password,e=T.new_password,k=T.confirm_password;if(!a||!e||!k){p.error("请填写完整信息");return}const x=Jt(e);if(!x.ok){p.error(x.message);return}if(e!==k){p.error("两次输入的新密码不一致");return}re.value=!0;try{const I=await Yt({current_password:a,new_password:e});if(I?.success){p.success("密码修改成功"),T.current_password="",T.new_password="",T.confirm_password="";return}p.error(I?.error||"修改失败")}catch(I){const fe=I?.response?.data;p.error(fe?.error||"修改失败")}finally{re.value=!1}}async function Ge(){q.value=!0;try{const e=(await Dt())?.announcement;if(!e?.id||M(e.id)||O(e.id))return;L.value=e,h.value=!0}catch{}finally{q.value=!1}}function We(){const a=L.value;a?.id&&K(a.id),h.value=!1}async function He(){const a=L.value;if(!a?.id){h.value=!1;return}Ue(a.id);try{(await Bt(a.id))?.success&&p.success("已永久关闭")}catch{}finally{h.value=!1}}return(a,e)=>{const k=f("el-icon"),x=f("el-menu-item"),I=f("el-menu"),fe=f("el-aside"),g=f("el-button"),Q=f("el-tag"),Qe=f("el-header"),Xe=f("RouterView"),Je=f("el-main"),xe=f("el-container"),Ze=f("el-drawer"),me=f("el-dialog"),D=f("el-input"),B=f("el-form-item"),ee=f("el-form"),z=f("el-tab-pane"),et=f("el-skeleton"),tt=f("el-empty"),nt=f("el-collapse-item"),at=f("el-collapse"),Ce=f("el-tabs"),X=f("el-alert"),st=f("el-divider"),ot=f("el-switch"),pe=ut("loading");return u(),y(xe,{class:"layout-root"},{default:n(()=>[c.value?N("",!0):(u(),y(fe,{key:0,width:"220px",class:"layout-aside"},{default:n(()=>[e[18]||(e[18]=i("div",{class:"brand"},[i("div",{class:"brand-title"},"知识管理平台"),i("div",{class:"brand-sub app-muted"},"用户中心")],-1)),s(I,{"default-active":ge.value,class:"aside-menu",router:"",onSelect:be},{default:n(()=>[(u(),A(te,null,ve(we,o=>s(x,{key:o.path,index:o.path},{default:n(()=>[s(k,null,{default:n(()=>[(u(),y(Te(o.icon)))]),_:2},1024),i("span",null,P(o.label),1)]),_:2},1032,["index"])),64))]),_:1},8,["default-active"])]),_:1})),s(xe,null,{default:n(()=>[s(Qe,{class:"layout-header"},{default:n(()=>[i("div",Zt,[c.value?(u(),y(g,{key:0,text:"",class:"header-menu-btn",onClick:e[0]||(e[0]=o=>v.value=!0)},{default:n(()=>[...e[19]||(e[19]=[m(" 菜单 ",-1)])]),_:1})):N("",!0),e[20]||(e[20]=i("div",{class:"header-title"},"用户控制台",-1))]),i("div",en,[i("div",tn,[C(r).isVip?(u(),y(Q,{key:0,type:"success",size:"small",effect:"light"},{default:n(()=>[...e[21]||(e[21]=[m("VIP",-1)])]),_:1})):(u(),y(Q,{key:1,type:"info",size:"small",effect:"light"},{default:n(()=>[...e[22]||(e[22]=[m("普通",-1)])]),_:1})),i("span",nn,P(C(r).username||"用户"),1),C(r).isVip&&C(r).vipDaysLeft<=7&&C(r).vipDaysLeft>0?(u(),A("span",an," ("+P(C(r).vipDaysLeft)+"天后到期) ",1)):N("",!0)]),s(g,{text:"",type:"primary",onClick:ke},{default:n(()=>[...e[23]||(e[23]=[m("反馈",-1)])]),_:1}),s(g,{text:"",onClick:Ee},{default:n(()=>[...e[24]||(e[24]=[m("设置",-1)])]),_:1}),s(g,{type:"primary",plain:"",onClick:he},{default:n(()=>[...e[25]||(e[25]=[m("退出",-1)])]),_:1})])]),_:1}),s(Je,{class:"layout-main"},{default:n(()=>[s(Xe)]),_:1})]),_:1}),s(Ze,{modelValue:v.value,"onUpdate:modelValue":e[1]||(e[1]=o=>v.value=o),size:"240px","with-header":!1},{default:n(()=>[e[31]||(e[31]=i("div",{class:"drawer-brand"},[i("div",{class:"brand-title"},"知识管理平台"),i("div",{class:"brand-sub app-muted"},"用户中心")],-1)),i("div",sn,[C(r).isVip?(u(),y(Q,{key:0,type:"success",size:"small",effect:"light"},{default:n(()=>[...e[26]||(e[26]=[m("VIP",-1)])]),_:1})):(u(),y(Q,{key:1,type:"info",size:"small",effect:"light"},{default:n(()=>[...e[27]||(e[27]=[m("普通",-1)])]),_:1})),i("span",on,P(C(r).username||"用户"),1)]),s(I,{"default-active":ge.value,class:"aside-menu",router:"",onSelect:be},{default:n(()=>[(u(),A(te,null,ve(we,o=>s(x,{key:o.path,index:o.path},{default:n(()=>[s(k,null,{default:n(()=>[(u(),y(Te(o.icon)))]),_:2},1024),i("span",null,P(o.label),1)]),_:2},1032,["index"])),64))]),_:1},8,["default-active"]),i("div",ln,[s(g,{text:"",type:"primary",style:{width:"100%"},onClick:ke},{default:n(()=>[...e[28]||(e[28]=[m("问题反馈",-1)])]),_:1}),s(g,{text:"",style:{width:"100%"},onClick:Ee},{default:n(()=>[...e[29]||(e[29]=[m("个人设置",-1)])]),_:1}),s(g,{type:"primary",plain:"",style:{width:"100%"},onClick:he},{default:n(()=>[...e[30]||(e[30]=[m("退出登录",-1)])]),_:1})])]),_:1},8,["modelValue"]),s(me,{modelValue:h.value,"onUpdate:modelValue":e[2]||(e[2]=o=>h.value=o),width:"min(560px, 92vw)",title:L.value?.title||"系统公告"},{footer:n(()=>[s(g,{onClick:We},{default:n(()=>[...e[32]||(e[32]=[m("当次关闭",-1)])]),_:1}),s(g,{type:"primary",onClick:He},{default:n(()=>[...e[33]||(e[33]=[m("永久关闭",-1)])]),_:1})]),default:n(()=>[ye((u(),A("div",rn,[i("div",un,P(L.value?.content||""),1),L.value?.image_url?(u(),A("div",cn,[i("img",{src:L.value.image_url,alt:"公告图片",loading:"lazy"},null,8,dn)])):N("",!0)])),[[pe,q.value]])]),_:1},8,["modelValue","title"]),s(me,{modelValue:j.value,"onUpdate:modelValue":e[9]||(e[9]=o=>j.value=o),title:"问题反馈",width:"min(720px, 92vw)"},{footer:n(()=>[s(g,{onClick:e[8]||(e[8]=o=>j.value=!1)},{default:n(()=>[...e[36]||(e[36]=[m("关闭",-1)])]),_:1}),Y.value==="list"?(u(),y(g,{key:0,onClick:Ve},{default:n(()=>[...e[37]||(e[37]=[m("刷新",-1)])]),_:1})):N("",!0),Y.value==="new"?(u(),y(g,{key:1,type:"primary",loading:ae.value,onClick:Me},{default:n(()=>[...e[38]||(e[38]=[m("提交",-1)])]),_:1},8,["loading"])):N("",!0)]),default:n(()=>[s(Ce,{modelValue:Y.value,"onUpdate:modelValue":e[6]||(e[6]=o=>Y.value=o),onTabChange:e[7]||(e[7]=o=>o==="list"&&Ve())},{default:n(()=>[s(z,{label:"提交反馈",name:"new"},{default:n(()=>[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"标题"},{default:n(()=>[s(D,{modelValue:V.title,"onUpdate:modelValue":e[3]||(e[3]=o=>V.title=o),placeholder:"简要描述问题",maxlength:"100","show-word-limit":""},null,8,["modelValue"])]),_:1}),s(B,{label:"详细描述"},{default:n(()=>[s(D,{modelValue:V.description,"onUpdate:modelValue":e[4]||(e[4]=o=>V.description=o),type:"textarea",rows:5,placeholder:"请详细描述您遇到的问题",maxlength:"2000","show-word-limit":""},null,8,["modelValue"])]),_:1}),s(B,{label:"联系方式(可选)"},{default:n(()=>[s(D,{modelValue:V.contact,"onUpdate:modelValue":e[5]||(e[5]=o=>V.contact=o),placeholder:"方便我们联系您"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1}),s(z,{label:"我的反馈",name:"list"},{default:n(()=>[se.value?(u(),y(et,{key:0,rows:6,animated:""})):(u(),A(te,{key:1},[J.value.length===0?(u(),y(tt,{key:0,description:"暂无反馈"})):(u(),y(at,{key:1,accordion:""},{default:n(()=>[(u(!0),A(te,null,ve(J.value,o=>(u(),y(nt,{key:o.id,name:String(o.id)},{title:n(()=>[i("div",fn,[i("span",mn,P(o.title),1),s(Q,{size:"small",effect:"light",type:Be(o.status)},{default:n(()=>[m(P(De(o.status)),1)]),_:2},1032,["type"]),i("span",pn,P(o.created_at||""),1)])]),default:n(()=>[i("div",_n,[i("div",vn,[e[34]||(e[34]=i("div",{class:"feedback-label app-muted"},"描述",-1)),i("div",yn,P(o.description),1)]),o.admin_reply?(u(),A("div",wn,[e[35]||(e[35]=i("div",{class:"feedback-label app-muted"},"管理员回复",-1)),i("div",gn,P(o.admin_reply),1)])):N("",!0)])]),_:2},1032,["name"]))),128))]),_:1}))],64))]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["modelValue"]),s(me,{modelValue:Z.value,"onUpdate:modelValue":e[17]||(e[17]=o=>Z.value=o),title:"个人设置",width:"min(720px, 92vw)"},{footer:n(()=>[s(g,{onClick:e[16]||(e[16]=o=>Z.value=!1)},{default:n(()=>[...e[47]||(e[47]=[m("关闭",-1)])]),_:1})]),default:n(()=>[s(Ce,{modelValue:oe.value,"onUpdate:modelValue":e[15]||(e[15]=o=>oe.value=o)},{default:n(()=>[s(z,{label:"邮箱绑定",name:"email"},{default:n(()=>[ye((u(),A("div",bn,[S.email&&S.email_verified?(u(),y(X,{key:0,type:"success",closable:!1,title:"邮箱已绑定并验证","show-icon":"",class:"settings-alert"},{default:n(()=>[i("div",hn,[i("div",kn,P(S.email),1),s(g,{type:"danger",text:"",onClick:je},{default:n(()=>[...e[39]||(e[39]=[m("解绑",-1)])]),_:1})])]),_:1})):S.email?(u(),y(X,{key:1,type:"warning",closable:!1,title:"邮箱待验证:请查收验证邮件(含垃圾箱)","show-icon":"",class:"settings-alert"})):N("",!0),s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"邮箱地址"},{default:n(()=>[s(D,{modelValue:G.value,"onUpdate:modelValue":e[10]||(e[10]=o=>G.value=o),placeholder:"name@example.com"},null,8,["modelValue"])]),_:1}),s(g,{type:"primary",loading:ie.value,onClick:qe},{default:n(()=>[...e[40]||(e[40]=[m("发送验证邮件",-1)])]),_:1},8,["loading"])]),_:1}),s(st),i("div",Vn,[e[41]||(e[41]=i("div",null,[i("div",{class:"notify-title"},"任务完成通知"),i("div",{class:"app-muted notify-desc"},"定时任务完成后发送邮件")],-1)),s(ot,{"model-value":$.value,disabled:!S.email_verified||W.value,"inline-prompt":"","active-text":"开","inactive-text":"关",onChange:Ye},null,8,["model-value","disabled"])]),S.email_verified?N("",!0):(u(),y(X,{key:2,type:"info",closable:!1,title:"绑定并验证邮箱后可开启邮件通知。","show-icon":"",class:"settings-hint"}))])),[[pe,le.value]])]),_:1}),s(z,{label:"修改密码",name:"password"},{default:n(()=>[i("div",En,[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"当前密码"},{default:n(()=>[s(D,{modelValue:T.current_password,"onUpdate:modelValue":e[11]||(e[11]=o=>T.current_password=o),type:"password","show-password":"",autocomplete:"current-password"},null,8,["modelValue"])]),_:1}),s(B,{label:"新密码(至少8位且包含字母和数字)"},{default:n(()=>[s(D,{modelValue:T.new_password,"onUpdate:modelValue":e[12]||(e[12]=o=>T.new_password=o),type:"password","show-password":"",autocomplete:"new-password"},null,8,["modelValue"])]),_:1}),s(B,{label:"确认新密码"},{default:n(()=>[s(D,{modelValue:T.confirm_password,"onUpdate:modelValue":e[13]||(e[13]=o=>T.confirm_password=o),type:"password","show-password":"",autocomplete:"new-password",onKeyup:ct(Se,["enter"])},null,8,["modelValue"])]),_:1}),s(g,{type:"primary",loading:re.value,onClick:Se},{default:n(()=>[...e[42]||(e[42]=[m("确认修改",-1)])]),_:1},8,["loading"])]),_:1})])]),_:1}),s(z,{label:"表格上传",name:"kdocs"},{default:n(()=>[ye((u(),A("div",Pn,[s(ee,{"label-position":"top"},{default:n(()=>[s(B,{label:"县区(可选)"},{default:n(()=>[s(D,{modelValue:H.value,"onUpdate:modelValue":e[14]||(e[14]=o=>H.value=o),placeholder:"留空使用系统默认县区"},null,8,["modelValue"])]),_:1}),s(g,{type:"primary",loading:ce.value,onClick:ze},{default:n(()=>[...e[43]||(e[43]=[m("保存",-1)])]),_:1},8,["loading"])]),_:1}),s(X,{type:"info",closable:!1,title:"自动上传开关在“账号管理”页面设置(测试功能)。","show-icon":"",class:"settings-hint"})])),[[pe,ue.value]])]),_:1}),s(z,{label:"VIP信息",name:"vip"},{default:n(()=>[i("div",Sn,[s(X,{type:C(r).isVip?"success":"info",closable:!1,title:C(r).isVip?"当前为 VIP 会员":"当前为普通用户","show-icon":"",class:"settings-alert"},null,8,["type","title"]),C(r).isVip?(u(),A("div",xn,[i("div",Cn,[e[44]||(e[44]=i("span",{class:"app-muted"},"到期时间",-1)),i("span",null,P(C(r).vipExpireTime||"未知"),1)]),i("div",Tn,[e[45]||(e[45]=i("span",{class:"app-muted"},"剩余天数",-1)),i("span",null,P(C(r).vipDaysLeft),1)])])):(u(),A("div",An,[...e[46]||(e[46]=[i("div",{class:"app-muted"},"升级方式:请通过“反馈”联系管理员开通。",-1)])]))])]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])]),_:1})}}},Rn=Ne(Ln,[["__scopeId","data-v-7ce33baa"]]),On=()=>F(()=>import("./LoginPage-DjXmnzTj.js"),__vite__mapDeps([0,1,2,3,4,5,6,7]),import.meta.url),In=()=>F(()=>import("./RegisterPage-Nvd-XHp4.js"),__vite__mapDeps([8,1,2,3,4,5,6,9]),import.meta.url),Nn=()=>F(()=>import("./ResetPasswordPage-DluVIq7o.js"),__vite__mapDeps([10,1,2,3,4,5,6,11]),import.meta.url),Ie=()=>F(()=>import("./VerifyResultPage-CSJomZjC.js"),__vite__mapDeps([12,2,1,3,4,6,13]),import.meta.url),Un=()=>F(()=>import("./AccountsPage-BsKyQ62c.js"),__vite__mapDeps([14,15,16,1,3,2,4,6,17]),import.meta.url),Dn=()=>F(()=>import("./SchedulesPage-DglS5EqW.js"),__vite__mapDeps([18,15,3,1,2,4,6,19]),import.meta.url),Bn=()=>F(()=>import("./ScreenshotsPage-L5gmloAw.js"),__vite__mapDeps([20,3,1,2,4,6,21]),import.meta.url),Mn=[{path:"/",redirect:"/login"},{path:"/login",name:"login",component:On},{path:"/register",name:"register",component:In},{path:"/reset-password/:token",name:"reset_password",component:Nn},{path:"/api/verify-email/:token",name:"verify_email",component:Ie},{path:"/api/verify-bind-email/:token",name:"verify_bind_email",component:Ie},{path:"/app",component:Rn,children:[{path:"",redirect:"/app/accounts"},{path:"accounts",name:"accounts",component:Un},{path:"schedules",name:"schedules",component:Dn},{path:"screenshots",name:"screenshots",component:Bn}]},{path:"/:pathMatch(.*)*",redirect:"/login"}],$n=_t({history:vt(),routes:Mn});dt(St).use(yt()).use($n).use(ht,{locale:kt}).mount("#app");export{Ne as _,jn as a,Wt as b,Gt as f,w as p,Xt as u,Jt as v}; diff --git a/static/app/index.html b/static/app/index.html index b2d1eaf..1e76cab 100644 --- a/static/app/index.html +++ b/static/app/index.html @@ -4,7 +4,7 @@ 知识管理平台 - +