增加了代理平台和日志
This commit is contained in:
+2
-2
@@ -17,10 +17,10 @@ from utils import setup_logger
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# 初始化日志(控制台 + 文件)
|
||||
# 初始化日志(控制台 + 按天命名文件)
|
||||
_log_level = os.getenv("LOG_LEVEL", "DEBUG")
|
||||
_log_dir = Path(__file__).resolve().parents[2] / "logs"
|
||||
setup_logger(level=_log_level, log_file=str(_log_dir / "app.log"))
|
||||
setup_logger(level=_log_level, log_dir=str(_log_dir))
|
||||
|
||||
init_db()
|
||||
yield
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""代理白名单平台抽象:新增 whitelist_platform / whitelist_credentials 字段
|
||||
|
||||
Revision ID: 20260624_0003
|
||||
Revises: 20260624_0002
|
||||
Create Date: 2026-06-24
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = "20260624_0003"
|
||||
down_revision: Union[str, None] = "20260624_0002"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
with op.batch_alter_table("proxy_config") as batch:
|
||||
batch.add_column(
|
||||
sa.Column("whitelist_platform", sa.String(32), server_default="xiequ")
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column("whitelist_credentials", sa.JSON(), nullable=True)
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
with op.batch_alter_table("proxy_config") as batch:
|
||||
batch.drop_column("whitelist_credentials")
|
||||
batch.drop_column("whitelist_platform")
|
||||
@@ -81,6 +81,9 @@ class ProxyConfig(Base):
|
||||
https = Column(EncryptedText(), default="")
|
||||
# 白名单
|
||||
whitelist_enabled = Column(Boolean, default=False)
|
||||
whitelist_platform = Column(String(32), default="xiequ")
|
||||
whitelist_credentials = Column(JSON, nullable=True)
|
||||
# 旧字段保留(向后兼容双写)
|
||||
whitelist_uid = Column(EncryptedText(), default="")
|
||||
whitelist_ukey = Column(EncryptedText(), default="")
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from ..database import get_db
|
||||
from ..models import User
|
||||
from ..schemas import ProxyConfigOut, ProxyConfigUpdate
|
||||
from ..schemas import ProxyConfigOut, ProxyConfigUpdate, PlatformInfo, PlatformFieldDef
|
||||
from ..deps import require_permission, authenticate_websocket
|
||||
from ..services.proxy_service import proxy_service
|
||||
from core.douyu.proxy_platforms import (
|
||||
get_platform_names, get_platform_labels, get_credential_fields,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/proxy", tags=["代理与白名单"])
|
||||
|
||||
@@ -30,17 +33,34 @@ def update_proxy_config(
|
||||
):
|
||||
return proxy_service.update_config(
|
||||
db,
|
||||
enabled=req.enabled,
|
||||
api_url=req.api_url,
|
||||
http=req.http,
|
||||
https=req.https,
|
||||
whitelist_enabled=req.whitelist_enabled,
|
||||
enabled=req.enabled if req.enabled is not None else False,
|
||||
api_url=req.api_url if req.api_url is not None else "",
|
||||
http=req.http if req.http is not None else "",
|
||||
https=req.https if req.https is not None else "",
|
||||
whitelist_enabled=req.whitelist_enabled if req.whitelist_enabled is not None else False,
|
||||
whitelist_platform=req.whitelist_platform or "xiequ",
|
||||
whitelist_credentials=req.whitelist_credentials,
|
||||
whitelist_uid=req.whitelist_uid,
|
||||
whitelist_ukey=req.whitelist_ukey,
|
||||
current_user=current,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/platforms", response_model=list[PlatformInfo])
|
||||
def list_platforms():
|
||||
"""获取所有可用的代理白名单平台及其凭据字段定义。"""
|
||||
labels = get_platform_labels()
|
||||
result = []
|
||||
for name in get_platform_names():
|
||||
fields = get_credential_fields(name)
|
||||
result.append(PlatformInfo(
|
||||
name=name,
|
||||
label=labels.get(name, name),
|
||||
credential_fields=[PlatformFieldDef(**f) for f in fields],
|
||||
))
|
||||
return result
|
||||
|
||||
|
||||
# ---- WebSocket 日志推送 ----
|
||||
|
||||
@router.websocket("/ws/test/{test_id}")
|
||||
|
||||
+29
-2
@@ -167,12 +167,39 @@ class ProxyConfigOut(BaseModel):
|
||||
http: str = ""
|
||||
https: str = ""
|
||||
whitelist_enabled: bool = False
|
||||
whitelist_platform: str = "xiequ"
|
||||
whitelist_credentials: Optional[dict] = None
|
||||
# 旧字段保留(向后兼容)
|
||||
whitelist_uid: str = ""
|
||||
whitelist_ukey: str = ""
|
||||
|
||||
|
||||
class ProxyConfigUpdate(ProxyConfigOut):
|
||||
pass
|
||||
class ProxyConfigUpdate(BaseModel):
|
||||
enabled: Optional[bool] = None
|
||||
api_url: Optional[str] = None
|
||||
http: Optional[str] = None
|
||||
https: Optional[str] = None
|
||||
whitelist_enabled: Optional[bool] = None
|
||||
whitelist_platform: Optional[str] = "xiequ"
|
||||
whitelist_credentials: Optional[dict] = None
|
||||
# 旧字段保留(向后兼容)
|
||||
whitelist_uid: Optional[str] = None
|
||||
whitelist_ukey: Optional[str] = None
|
||||
|
||||
|
||||
# ---- 代理平台元信息 ----
|
||||
class PlatformFieldDef(BaseModel):
|
||||
"""平台凭据字段定义。"""
|
||||
key: str
|
||||
label: str
|
||||
placeholder: str = ""
|
||||
|
||||
|
||||
class PlatformInfo(BaseModel):
|
||||
"""平台元信息。"""
|
||||
name: str
|
||||
label: str
|
||||
credential_fields: list[PlatformFieldDef]
|
||||
|
||||
|
||||
# ---- 通用 ----
|
||||
|
||||
@@ -55,12 +55,20 @@ class LoginBatchRunner:
|
||||
# 共享代理管理器(带锁,避免并发白名单限流;极验失败时可刷新代理)
|
||||
self._shared_proxy_manager = None
|
||||
if proxy_config and proxy_config.enabled and proxy_config.api_url:
|
||||
wl_uid = proxy_config.whitelist_uid or "" if proxy_config.whitelist_enabled else ""
|
||||
wl_ukey = proxy_config.whitelist_ukey or "" if proxy_config.whitelist_enabled else ""
|
||||
wl_platform = "xiequ"
|
||||
wl_credentials = None
|
||||
if proxy_config.whitelist_enabled:
|
||||
wl_platform = getattr(proxy_config, 'whitelist_platform', None) or "xiequ"
|
||||
wl_credentials = getattr(proxy_config, 'whitelist_credentials', None)
|
||||
# 向后兼容:旧字段有值但新字段为空
|
||||
if not wl_credentials and proxy_config.whitelist_uid and proxy_config.whitelist_ukey:
|
||||
wl_platform = "xiequ"
|
||||
wl_credentials = {"uid": proxy_config.whitelist_uid, "ukey": proxy_config.whitelist_ukey}
|
||||
|
||||
self._shared_proxy_manager = get_proxy_manager(
|
||||
proxy_config.api_url,
|
||||
whitelist_uid=wl_uid,
|
||||
whitelist_ukey=wl_ukey,
|
||||
whitelist_platform=wl_platform,
|
||||
whitelist_credentials=wl_credentials,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
|
||||
@@ -9,9 +9,31 @@ from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.douyu.proxy import resolve_working_proxy, verify_proxy_url, parse_proxy_response
|
||||
from core.douyu.proxy_platforms import create_adapter, get_platform_labels
|
||||
from core.douyu.proxy_platforms.base import _get_local_exit_ip
|
||||
from ..models import ProxyConfig as ProxyConfigModel, AuditLog
|
||||
|
||||
|
||||
def _build_whitelist_params(cfg: ProxyConfigModel) -> dict:
|
||||
"""从 ProxyConfig 构建白名单参数,自动处理新旧字段兼容。
|
||||
|
||||
Returns:
|
||||
{"whitelist_platform": str, "whitelist_credentials": dict|None}
|
||||
"""
|
||||
platform = getattr(cfg, 'whitelist_platform', None) or "xiequ"
|
||||
credentials = getattr(cfg, 'whitelist_credentials', None)
|
||||
|
||||
# 向后兼容:旧字段有值但新字段为空时,自动迁移
|
||||
if not credentials and cfg.whitelist_uid and cfg.whitelist_ukey:
|
||||
platform = "xiequ"
|
||||
credentials = {"uid": cfg.whitelist_uid, "ukey": cfg.whitelist_ukey}
|
||||
|
||||
return {
|
||||
"whitelist_platform": platform,
|
||||
"whitelist_credentials": credentials if cfg.whitelist_enabled else None,
|
||||
}
|
||||
|
||||
|
||||
class ProxyService:
|
||||
"""代理 & 白名单服务:管理代理配置、执行测试。"""
|
||||
|
||||
@@ -31,12 +53,26 @@ class ProxyService:
|
||||
db.add(cfg)
|
||||
db.commit()
|
||||
db.refresh(cfg)
|
||||
|
||||
# 应用层自动迁移:旧字段有值但新字段为空时,填充新字段
|
||||
if cfg.whitelist_uid and cfg.whitelist_ukey and not cfg.whitelist_credentials:
|
||||
cfg.whitelist_platform = "xiequ"
|
||||
cfg.whitelist_credentials = {"uid": cfg.whitelist_uid, "ukey": cfg.whitelist_ukey}
|
||||
db.commit()
|
||||
|
||||
return cfg
|
||||
|
||||
@staticmethod
|
||||
def update_config(db: Session, enabled, api_url, http, https,
|
||||
whitelist_enabled, whitelist_uid, whitelist_ukey,
|
||||
current_user) -> ProxyConfigModel:
|
||||
def update_config(
|
||||
db: Session,
|
||||
enabled, api_url, http, https,
|
||||
whitelist_enabled,
|
||||
whitelist_platform="xiequ",
|
||||
whitelist_credentials=None,
|
||||
whitelist_uid=None,
|
||||
whitelist_ukey=None,
|
||||
current_user=None,
|
||||
) -> ProxyConfigModel:
|
||||
"""更新代理配置并记录审计日志。"""
|
||||
cfg = ProxyService.get_or_create(db)
|
||||
cfg.enabled = enabled
|
||||
@@ -44,18 +80,29 @@ class ProxyService:
|
||||
cfg.http = http
|
||||
cfg.https = https
|
||||
cfg.whitelist_enabled = whitelist_enabled
|
||||
cfg.whitelist_uid = whitelist_uid
|
||||
cfg.whitelist_ukey = whitelist_ukey
|
||||
cfg.whitelist_platform = whitelist_platform
|
||||
cfg.whitelist_credentials = whitelist_credentials
|
||||
|
||||
# 双写:协固平台同步到旧字段,其他平台清空旧字段
|
||||
if whitelist_platform == "xiequ" and whitelist_credentials:
|
||||
cfg.whitelist_uid = whitelist_credentials.get("uid", "")
|
||||
cfg.whitelist_ukey = whitelist_credentials.get("ukey", "")
|
||||
else:
|
||||
# 非协固平台,旧字段使用传入值或清空
|
||||
cfg.whitelist_uid = whitelist_uid or ""
|
||||
cfg.whitelist_ukey = whitelist_ukey or ""
|
||||
|
||||
db.commit()
|
||||
db.refresh(cfg)
|
||||
|
||||
db.add(AuditLog(
|
||||
user_id=current_user.id,
|
||||
username=current_user.username,
|
||||
action="proxy:update",
|
||||
target="proxy_config",
|
||||
))
|
||||
db.commit()
|
||||
if current_user:
|
||||
db.add(AuditLog(
|
||||
user_id=current_user.id,
|
||||
username=current_user.username,
|
||||
action="proxy:update",
|
||||
target="proxy_config",
|
||||
))
|
||||
db.commit()
|
||||
return cfg
|
||||
|
||||
# ---- 测试任务管理 ----
|
||||
@@ -112,13 +159,12 @@ class ProxyService:
|
||||
|
||||
# API代理
|
||||
if cfg.api_url:
|
||||
whitelist_uid = cfg.whitelist_uid if cfg.whitelist_enabled else ""
|
||||
whitelist_ukey = cfg.whitelist_ukey if cfg.whitelist_enabled else ""
|
||||
wl_params = _build_whitelist_params(cfg)
|
||||
|
||||
proxy_url, msg = resolve_working_proxy(
|
||||
api_url=cfg.api_url,
|
||||
whitelist_uid=whitelist_uid,
|
||||
whitelist_ukey=whitelist_ukey,
|
||||
whitelist_platform=wl_params["whitelist_platform"],
|
||||
whitelist_credentials=wl_params["whitelist_credentials"],
|
||||
max_attempts=3,
|
||||
log_func=push,
|
||||
)
|
||||
@@ -145,7 +191,6 @@ class ProxyService:
|
||||
):
|
||||
"""在线程中执行白名单测试。"""
|
||||
import requests as req_lib
|
||||
from core.douyu.whitelist import WhitelistManager
|
||||
|
||||
def push(level, message):
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
@@ -158,16 +203,28 @@ class ProxyService:
|
||||
push("error", "白名单未启用")
|
||||
push("result", "")
|
||||
return
|
||||
if not cfg.whitelist_uid or not cfg.whitelist_ukey:
|
||||
push("error", "未配置白名单UID/UKEY")
|
||||
|
||||
# 构建适配器
|
||||
wl_params = _build_whitelist_params(cfg)
|
||||
credentials = wl_params["whitelist_credentials"]
|
||||
platform = wl_params["whitelist_platform"]
|
||||
|
||||
if not credentials:
|
||||
push("error", "未配置白名单凭据")
|
||||
push("result", "")
|
||||
return
|
||||
|
||||
manager = WhitelistManager(cfg.whitelist_uid, cfg.whitelist_ukey)
|
||||
adapter = create_adapter(platform, credentials)
|
||||
if not adapter:
|
||||
push("error", f"不支持的白名单平台: {platform}")
|
||||
push("result", "")
|
||||
return
|
||||
|
||||
push("info", f"当前白名单平台: {adapter.platform_label}")
|
||||
|
||||
# 1. 测试API连接
|
||||
push("info", "测试白名单API连接...")
|
||||
ok, msg = manager.test_connection()
|
||||
ok, msg = adapter.test_connection()
|
||||
push("info" if ok else "error", f"白名单API: {msg}")
|
||||
if not ok:
|
||||
push("result", "")
|
||||
@@ -190,19 +247,7 @@ class ProxyService:
|
||||
|
||||
if not local_ip:
|
||||
push("info", "通过IP检测服务获取本机公网IP...")
|
||||
for url in [
|
||||
'https://qifu-api.baidubce.com/ip/local/geo/v1/district',
|
||||
'https://myip.ipip.net',
|
||||
'https://4.ipw.cn',
|
||||
]:
|
||||
try:
|
||||
resp = req_lib.get(url, timeout=6, headers={"User-Agent": "Mozilla/5.0"})
|
||||
match = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', resp.text)
|
||||
if match:
|
||||
local_ip = match.group(1)
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
local_ip = _get_local_exit_ip()
|
||||
|
||||
if not local_ip:
|
||||
push("error", "无法获取本机公网IP")
|
||||
@@ -212,22 +257,24 @@ class ProxyService:
|
||||
push("info", f"本机公网IP: {local_ip}")
|
||||
|
||||
# 3. 检查并同步白名单
|
||||
records = manager.get_whitelist_json()
|
||||
in_list = any(r.get('IP') == local_ip for r in records)
|
||||
push("info", f"白名单共 {len(records)} 条记录")
|
||||
records = adapter.get_whitelist()
|
||||
in_list = any(r.get('ip') == local_ip for r in records)
|
||||
|
||||
if records:
|
||||
push("info", f"白名单共 {len(records)} 条记录")
|
||||
|
||||
if in_list:
|
||||
record = next((r for r in records if r.get('IP') == local_ip), {})
|
||||
memo = record.get('MEMO', '')
|
||||
if memo == manager.memo:
|
||||
record = next((r for r in records if r.get('ip') == local_ip), {})
|
||||
memo = record.get('memo', '')
|
||||
if memo == adapter.memo:
|
||||
push("success", f"本机IP {local_ip} 已在白名单中 (备注正确)")
|
||||
else:
|
||||
push("warning", f'本机IP {local_ip} 备注不匹配 (当前: "{memo}"),更新中...')
|
||||
sync_ok, sync_msg = manager.sync_ip(local_ip)
|
||||
sync_ok, sync_msg = adapter.sync_ip(local_ip)
|
||||
push("success" if sync_ok else "error", f"白名单更新: {sync_msg}")
|
||||
else:
|
||||
push("info", f"正在将 {local_ip} 添加到白名单...")
|
||||
sync_ok, sync_msg = manager.sync_ip(local_ip)
|
||||
sync_ok, sync_msg = adapter.sync_ip(local_ip)
|
||||
push("success" if sync_ok else "error", f"白名单同步: {sync_msg}")
|
||||
|
||||
push("result", "")
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import api from './client';
|
||||
import type { ProxyConfig, ProxyTestResult } from './types';
|
||||
import type { ProxyConfig, ProxyTestResult, PlatformInfo } from './types';
|
||||
|
||||
export const proxyApi = {
|
||||
get: () => api.get<ProxyConfig, ProxyConfig>('/proxy'),
|
||||
update: (data: ProxyConfig) => api.put<ProxyConfig, ProxyConfig>('/proxy', data),
|
||||
test: () => api.post<ProxyTestResult, ProxyTestResult>('/proxy/test'),
|
||||
testWhitelist: () => api.post<ProxyTestResult, ProxyTestResult>('/proxy/whitelist/test'),
|
||||
getPlatforms: () => api.get<PlatformInfo[], PlatformInfo[]>('/proxy/platforms'),
|
||||
};
|
||||
|
||||
@@ -112,6 +112,9 @@ export interface ProxyConfig {
|
||||
http: string;
|
||||
https: string;
|
||||
whitelist_enabled: boolean;
|
||||
whitelist_platform: string;
|
||||
whitelist_credentials: Record<string, string> | null;
|
||||
// 旧字段保留(向后兼容)
|
||||
whitelist_uid: string;
|
||||
whitelist_ukey: string;
|
||||
}
|
||||
@@ -121,6 +124,18 @@ export interface ProxyTestResult {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface PlatformFieldDef {
|
||||
key: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
}
|
||||
|
||||
export interface PlatformInfo {
|
||||
name: string;
|
||||
label: string;
|
||||
credential_fields: PlatformFieldDef[];
|
||||
}
|
||||
|
||||
// ==================== Permissions ====================
|
||||
|
||||
export interface PermissionsListResult {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { Form, Input, Switch, Button, Card, message, Row, Col } from 'antd';
|
||||
import { proxyApi, type ProxyConfig } from '../api/modules';
|
||||
import { Form, Input, Switch, Button, Card, Select, message, Row, Col } from 'antd';
|
||||
import { proxyApi, type ProxyConfig, type PlatformInfo } from '../api/modules';
|
||||
import RealtimeLogPanel from '../components/RealtimeLogPanel';
|
||||
import { useWebSocketLogs } from '../hooks/useWebSocketLogs';
|
||||
import { getErrorMessage } from '../utils/error';
|
||||
@@ -13,6 +13,19 @@ export default function ProxyPage() {
|
||||
const [configLoaded, setConfigLoaded] = useState(false);
|
||||
const { logs, connect: connectLogs, close: closeLogs } = useWebSocketLogs();
|
||||
|
||||
// 平台相关状态
|
||||
const [platforms, setPlatforms] = useState<PlatformInfo[]>([]);
|
||||
const [selectedPlatform, setSelectedPlatform] = useState<string>('xiequ');
|
||||
const [credentials, setCredentials] = useState<Record<string, string>>({});
|
||||
|
||||
// 加载平台列表
|
||||
useEffect(() => {
|
||||
proxyApi.getPlatforms().then(setPlatforms).catch(() => {});
|
||||
}, []);
|
||||
|
||||
// 当前平台的凭据字段定义
|
||||
const currentPlatformFields = platforms.find(p => p.name === selectedPlatform)?.credential_fields ?? [];
|
||||
|
||||
const loadConfig = useCallback(async () => {
|
||||
try {
|
||||
const data = await proxyApi.get();
|
||||
@@ -22,9 +35,19 @@ export default function ProxyPage() {
|
||||
http: data.http ?? '',
|
||||
https: data.https ?? '',
|
||||
whitelist_enabled: data.whitelist_enabled ?? false,
|
||||
whitelist_uid: data.whitelist_uid ?? '',
|
||||
whitelist_ukey: data.whitelist_ukey ?? '',
|
||||
});
|
||||
|
||||
// 恢复平台和凭据
|
||||
const platform = data.whitelist_platform || 'xiequ';
|
||||
setSelectedPlatform(platform);
|
||||
if (data.whitelist_credentials && Object.keys(data.whitelist_credentials).length > 0) {
|
||||
setCredentials(data.whitelist_credentials);
|
||||
} else if (data.whitelist_uid || data.whitelist_ukey) {
|
||||
// 向后兼容:旧字段迁移到凭据
|
||||
setCredentials({ uid: data.whitelist_uid || '', ukey: data.whitelist_ukey || '' });
|
||||
} else {
|
||||
setCredentials({});
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
message.error(getErrorMessage(e));
|
||||
} finally {
|
||||
@@ -56,7 +79,15 @@ export default function ProxyPage() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
await proxyApi.update(values as ProxyConfig);
|
||||
const submitData: ProxyConfig = {
|
||||
...values,
|
||||
whitelist_platform: selectedPlatform,
|
||||
whitelist_credentials: credentials,
|
||||
// 旧字段:协固平台双写,其他平台清空
|
||||
whitelist_uid: selectedPlatform === 'xiequ' ? (credentials.uid || '') : '',
|
||||
whitelist_ukey: selectedPlatform === 'xiequ' ? (credentials.ukey || '') : '',
|
||||
};
|
||||
await proxyApi.update(submitData);
|
||||
message.success('已保存');
|
||||
} catch (e: unknown) {
|
||||
message.error(getErrorMessage(e));
|
||||
@@ -87,6 +118,15 @@ export default function ProxyPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePlatformChange = (value: string) => {
|
||||
setSelectedPlatform(value);
|
||||
setCredentials({});
|
||||
};
|
||||
|
||||
const handleCredentialChange = (key: string, value: string) => {
|
||||
setCredentials(prev => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', gap: 8 }}>
|
||||
@@ -106,8 +146,6 @@ export default function ProxyPage() {
|
||||
api_url: '',
|
||||
http: '',
|
||||
https: '',
|
||||
whitelist_uid: '',
|
||||
whitelist_ukey: '',
|
||||
}}
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
@@ -118,7 +156,7 @@ export default function ProxyPage() {
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item name="api_url" label="代理API地址" style={{ marginBottom: 8 }}>
|
||||
<Input placeholder="http://op.xiequ.cn/...?act=get" />
|
||||
<Input placeholder="代理提取API地址" />
|
||||
</Form.Item>
|
||||
<Form.Item name="http" label="静态HTTP代理" style={{ marginBottom: 8 }}>
|
||||
<Input placeholder="http://ip:port" />
|
||||
@@ -134,12 +172,30 @@ export default function ProxyPage() {
|
||||
<Form.Item name="whitelist_enabled" label="启用白名单自动管理" valuePropName="checked" style={{ marginBottom: 8 }}>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item name="whitelist_uid" label="协固UID" style={{ marginBottom: 8 }}>
|
||||
<Input placeholder="如: 99769" />
|
||||
</Form.Item>
|
||||
<Form.Item name="whitelist_ukey" label="协固UKEY" style={{ marginBottom: 8 }}>
|
||||
<Input placeholder="如: C99371082B965B70F46DCAA87A04618B" />
|
||||
</Form.Item>
|
||||
|
||||
{/* 平台选择 */}
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<div style={{ marginBottom: 4, fontSize: 13, color: 'rgba(0,0,0,0.88)' }}>代理平台</div>
|
||||
<Select
|
||||
value={selectedPlatform}
|
||||
onChange={handlePlatformChange}
|
||||
style={{ width: '100%' }}
|
||||
options={platforms.map(p => ({ value: p.name, label: p.label }))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 动态凭据字段 */}
|
||||
{currentPlatformFields.map(field => (
|
||||
<div key={field.key} style={{ marginBottom: 8 }}>
|
||||
<div style={{ marginBottom: 4, fontSize: 13, color: 'rgba(0,0,0,0.88)' }}>{field.label}</div>
|
||||
<Input
|
||||
placeholder={field.placeholder}
|
||||
value={credentials[field.key] || ''}
|
||||
onChange={(e) => handleCredentialChange(field.key, e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button size="small" onClick={handleTestWhitelist} loading={testingWl}>测试白名单</Button>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
Reference in New Issue
Block a user