Add default remote proxy support for Sub2API services.
Let Sub2API service settings store and load a default remote proxy so uploads can reuse the target service's remote proxy bindings without forcing users to pick one each time.
This commit is contained in:
1 parent
dfebd9a780
commit
6a875bfced
10 files changed
+240
-24
No files matched your search
@@ -596,13 +596,15 @@ def create_sub2api_service(
|
||||
api_url: str,
|
||||
api_key: str,
|
||||
enabled: bool = True,
|
||||
priority: int = 0
|
||||
priority: int = 0,
|
||||
default_remote_proxy_id: Optional[int] = None,
|
||||
) -> Sub2ApiService:
|
||||
"""创建 Sub2API 服务配置"""
|
||||
svc = Sub2ApiService(
|
||||
name=name,
|
||||
api_url=api_url,
|
||||
api_key=api_key,
|
||||
default_remote_proxy_id=default_remote_proxy_id,
|
||||
enabled=enabled,
|
||||
priority=priority,
|
||||
)
|
||||
|
||||
@@ -152,6 +152,7 @@ class Sub2ApiService(Base):
|
||||
name = Column(String(100), nullable=False) # 服务名称
|
||||
api_url = Column(String(500), nullable=False) # API URL (host)
|
||||
api_key = Column(Text, nullable=False) # x-api-key
|
||||
default_remote_proxy_id = Column(Integer, nullable=True) # 默认远端代理 ID
|
||||
enabled = Column(Boolean, default=True)
|
||||
priority = Column(Integer, default=0) # 优先级
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
@@ -111,6 +111,7 @@ class DatabaseSessionManager:
|
||||
("accounts", "subscription_at", "DATETIME"),
|
||||
("accounts", "cookies", "TEXT"),
|
||||
("proxies", "is_default", "BOOLEAN DEFAULT 0"),
|
||||
("sub2api_services", "default_remote_proxy_id", "INTEGER"),
|
||||
]
|
||||
|
||||
# 确保新表存在(create_tables 已处理,此处兜底)
|
||||
|
||||
@@ -819,6 +819,7 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
# 解析指定的 Sub2API 服务
|
||||
api_url = None
|
||||
api_key = None
|
||||
svc = None
|
||||
if request.service_id:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, request.service_id)
|
||||
@@ -830,10 +831,11 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
with get_db() as db:
|
||||
svcs = crud.get_sub2api_services(db, enabled=True)
|
||||
if svcs:
|
||||
api_url = svcs[0].api_url
|
||||
api_key = svcs[0].api_key
|
||||
svc = svcs[0]
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
if not api_url or not api_key:
|
||||
if not api_url or not api_key or not svc:
|
||||
raise HTTPException(status_code=400, detail="未找到可用的 Sub2API 服务,请先在设置中配置")
|
||||
|
||||
with get_db() as db:
|
||||
@@ -842,11 +844,13 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
request.status_filter, request.email_service_filter, request.search_filter
|
||||
)
|
||||
|
||||
selected_proxy_id = request.proxy_id if "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id
|
||||
|
||||
results = batch_upload_to_sub2api(
|
||||
ids, api_url, api_key,
|
||||
concurrency=request.concurrency,
|
||||
priority=request.priority,
|
||||
proxy_id=request.proxy_id,
|
||||
proxy_id=selected_proxy_id,
|
||||
)
|
||||
return results
|
||||
|
||||
@@ -858,10 +862,11 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
service_id = request.service_id if request else None
|
||||
concurrency = request.concurrency if request else 3
|
||||
priority = request.priority if request else 50
|
||||
proxy_id = request.proxy_id if request else None
|
||||
proxy_id = request.proxy_id if request and "proxy_id" in request.model_fields_set else None
|
||||
|
||||
api_url = None
|
||||
api_key = None
|
||||
svc = None
|
||||
if service_id:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, service_id)
|
||||
@@ -873,10 +878,11 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
with get_db() as db:
|
||||
svcs = crud.get_sub2api_services(db, enabled=True)
|
||||
if svcs:
|
||||
api_url = svcs[0].api_url
|
||||
api_key = svcs[0].api_key
|
||||
svc = svcs[0]
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
if not api_url or not api_key:
|
||||
if not api_url or not api_key or not svc:
|
||||
raise HTTPException(status_code=400, detail="未找到可用的 Sub2API 服务,请先在设置中配置")
|
||||
|
||||
with get_db() as db:
|
||||
@@ -888,7 +894,9 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
|
||||
success, message = upload_to_sub2api(
|
||||
[account], api_url, api_key,
|
||||
concurrency=concurrency, priority=priority, proxy_id=proxy_id
|
||||
concurrency=concurrency,
|
||||
priority=priority,
|
||||
proxy_id=proxy_id if request and "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id,
|
||||
)
|
||||
if success:
|
||||
return {"success": True, "message": message}
|
||||
|
||||
@@ -462,7 +462,12 @@ def _run_sync_registration_task(task_uuid: str, email_service_type: str, proxy:
|
||||
if not _svc:
|
||||
continue
|
||||
log_callback(f"[Sub2API] 正在把账号发往服务站: {_svc.name}")
|
||||
_ok, _msg = upload_to_sub2api([saved_account], _svc.api_url, _svc.api_key)
|
||||
_ok, _msg = upload_to_sub2api(
|
||||
[saved_account],
|
||||
_svc.api_url,
|
||||
_svc.api_key,
|
||||
proxy_id=_svc.default_remote_proxy_id,
|
||||
)
|
||||
log_callback(f"[Sub2API] {'成功' if _ok else '失败'}({_svc.name}): {_msg}")
|
||||
except Exception as _e:
|
||||
log_callback(f"[Sub2API] 异常({_sid}): {_e}")
|
||||
|
||||
@@ -23,6 +23,7 @@ class Sub2ApiServiceCreate(BaseModel):
|
||||
name: str
|
||||
api_url: str
|
||||
api_key: str
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: bool = True
|
||||
priority: int = 0
|
||||
|
||||
@@ -31,6 +32,7 @@ class Sub2ApiServiceUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
api_url: Optional[str] = None
|
||||
api_key: Optional[str] = None
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: Optional[bool] = None
|
||||
priority: Optional[int] = None
|
||||
|
||||
@@ -40,6 +42,7 @@ class Sub2ApiServiceResponse(BaseModel):
|
||||
name: str
|
||||
api_url: str
|
||||
has_key: bool
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: bool
|
||||
priority: int
|
||||
created_at: Optional[str] = None
|
||||
@@ -50,8 +53,10 @@ class Sub2ApiServiceResponse(BaseModel):
|
||||
|
||||
|
||||
class Sub2ApiTestRequest(BaseModel):
|
||||
service_id: Optional[int] = None
|
||||
api_url: Optional[str] = None
|
||||
api_key: Optional[str] = None
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
|
||||
|
||||
class Sub2ApiUploadRequest(BaseModel):
|
||||
@@ -83,6 +88,7 @@ def _to_response(svc) -> Sub2ApiServiceResponse:
|
||||
name=svc.name,
|
||||
api_url=svc.api_url,
|
||||
has_key=bool(svc.api_key),
|
||||
default_remote_proxy_id=svc.default_remote_proxy_id,
|
||||
enabled=svc.enabled,
|
||||
priority=svc.priority,
|
||||
created_at=svc.created_at.isoformat() if svc.created_at else None,
|
||||
@@ -119,6 +125,23 @@ def _to_remote_proxy_response(proxy: dict) -> Sub2ApiRemoteProxyResponse:
|
||||
)
|
||||
|
||||
|
||||
def _resolve_temp_sub2api_request(request: Sub2ApiTestRequest):
|
||||
svc = None
|
||||
if request.service_id is not None:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, request.service_id)
|
||||
if not svc:
|
||||
raise HTTPException(status_code=404, detail="Sub2API 服务不存在")
|
||||
|
||||
api_url = (request.api_url or (svc.api_url if svc else "")).strip()
|
||||
api_key = (request.api_key or (svc.api_key if svc else "")).strip()
|
||||
|
||||
if not api_url or not api_key:
|
||||
raise HTTPException(status_code=400, detail="api_url 和 api_key 不能为空")
|
||||
|
||||
return svc, api_url, api_key
|
||||
|
||||
|
||||
# ============== API Endpoints ==============
|
||||
|
||||
@router.get("", response_model=List[Sub2ApiServiceResponse])
|
||||
@@ -140,6 +163,7 @@ async def create_sub2api_service(request: Sub2ApiServiceCreate):
|
||||
api_key=request.api_key,
|
||||
enabled=request.enabled,
|
||||
priority=request.priority,
|
||||
default_remote_proxy_id=request.default_remote_proxy_id,
|
||||
)
|
||||
return _to_response(svc)
|
||||
|
||||
@@ -161,6 +185,33 @@ async def list_remote_sub2api_proxies(service_id: Optional[int] = None):
|
||||
)
|
||||
|
||||
|
||||
@router.post("/remote-proxies", response_model=Sub2ApiRemoteProxyListResponse)
|
||||
async def list_remote_sub2api_proxies_direct(request: Sub2ApiTestRequest):
|
||||
"""按临时 Sub2API 配置拉取远端代理列表(用于新增前选择默认代理)"""
|
||||
svc, api_url, api_key = _resolve_temp_sub2api_request(request)
|
||||
|
||||
try:
|
||||
proxies = fetch_remote_sub2api_proxies(api_url, api_key)
|
||||
proxy_items = [_to_remote_proxy_response(proxy) for proxy in proxies]
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||
|
||||
return Sub2ApiRemoteProxyListResponse(
|
||||
service=_to_response(svc) if svc else Sub2ApiServiceResponse(
|
||||
id=0,
|
||||
name="未保存服务",
|
||||
api_url=api_url,
|
||||
has_key=bool(api_key),
|
||||
default_remote_proxy_id=request.default_remote_proxy_id,
|
||||
enabled=True,
|
||||
priority=0,
|
||||
created_at=None,
|
||||
updated_at=None,
|
||||
),
|
||||
proxies=proxy_items,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{service_id}", response_model=Sub2ApiServiceResponse)
|
||||
async def get_sub2api_service(service_id: int):
|
||||
"""获取单个 Sub2API 服务详情"""
|
||||
@@ -183,6 +234,7 @@ async def get_sub2api_service_full(service_id: int):
|
||||
"name": svc.name,
|
||||
"api_url": svc.api_url,
|
||||
"api_key": svc.api_key,
|
||||
"default_remote_proxy_id": svc.default_remote_proxy_id,
|
||||
"enabled": svc.enabled,
|
||||
"priority": svc.priority,
|
||||
}
|
||||
@@ -204,6 +256,8 @@ async def update_sub2api_service(service_id: int, request: Sub2ApiServiceUpdate)
|
||||
# api_key 留空则保持原值
|
||||
if request.api_key:
|
||||
update_data["api_key"] = request.api_key
|
||||
if "default_remote_proxy_id" in request.model_fields_set:
|
||||
update_data["default_remote_proxy_id"] = request.default_remote_proxy_id
|
||||
if request.enabled is not None:
|
||||
update_data["enabled"] = request.enabled
|
||||
if request.priority is not None:
|
||||
@@ -238,9 +292,8 @@ async def test_sub2api_service(service_id: int):
|
||||
@router.post("/test-connection")
|
||||
async def test_sub2api_connection_direct(request: Sub2ApiTestRequest):
|
||||
"""直接测试 Sub2API 连接(用于添加前验证)"""
|
||||
if not request.api_url or not request.api_key:
|
||||
raise HTTPException(status_code=400, detail="api_url 和 api_key 不能为空")
|
||||
success, message = test_sub2api_connection(request.api_url, request.api_key)
|
||||
_svc, api_url, api_key = _resolve_temp_sub2api_request(request)
|
||||
success, message = test_sub2api_connection(api_url, api_key)
|
||||
return {"success": success, "message": message}
|
||||
|
||||
|
||||
@@ -263,12 +316,14 @@ async def upload_accounts_to_sub2api(request: Sub2ApiUploadRequest):
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
selected_proxy_id = request.proxy_id if "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id
|
||||
|
||||
results = batch_upload_to_sub2api(
|
||||
request.account_ids,
|
||||
api_url,
|
||||
api_key,
|
||||
concurrency=request.concurrency,
|
||||
priority=request.priority,
|
||||
proxy_id=request.proxy_id,
|
||||
proxy_id=selected_proxy_id,
|
||||
)
|
||||
return results
|
||||
@@ -357,6 +357,27 @@ body {
|
||||
border-top: 1px solid var(--border-light);
|
||||
}
|
||||
|
||||
.sub2api-remote-proxy-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.sub2api-remote-proxy-select {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sub2api-remote-proxy-btn {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sub2api-remote-proxy-hint {
|
||||
margin-top: var(--spacing-xs);
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Checkbox 样式优化 */
|
||||
.form-group input[type="checkbox"] {
|
||||
width: auto;
|
||||
|
||||
@@ -1119,7 +1119,7 @@ async function handleBatchUploadSub2Api() {
|
||||
try {
|
||||
const payload = buildBatchPayload();
|
||||
if (choice.service_id != null) payload.service_id = choice.service_id;
|
||||
if (proxyInput.proxy_id != null) payload.proxy_id = proxyInput.proxy_id;
|
||||
payload.proxy_id = proxyInput.proxy_id;
|
||||
const result = await api.post('/accounts/batch-upload-sub2api', payload);
|
||||
|
||||
let message = `成功: ${result.success_count}`;
|
||||
@@ -1149,7 +1149,7 @@ async function uploadToSub2Api(id) {
|
||||
toast.info('正在上传到 Sub2API...');
|
||||
const payload = {};
|
||||
if (choice.service_id != null) payload.service_id = choice.service_id;
|
||||
if (proxyInput.proxy_id != null) payload.proxy_id = proxyInput.proxy_id;
|
||||
payload.proxy_id = proxyInput.proxy_id;
|
||||
const result = await api.post(`/accounts/${id}/upload-sub2api`, payload);
|
||||
if (result.success) {
|
||||
toast.success('上传成功');
|
||||
|
||||
+120
-7
@@ -57,6 +57,7 @@ const elements = {
|
||||
sub2ApiServiceForm: document.getElementById('sub2api-service-form'),
|
||||
sub2ApiServiceModalTitle: document.getElementById('sub2api-service-modal-title'),
|
||||
testSub2ApiServiceBtn: document.getElementById('test-sub2api-service-btn'),
|
||||
loadSub2ApiRemoteProxiesBtn: document.getElementById('load-sub2api-remote-proxies-btn'),
|
||||
// Team Manager 服务管理
|
||||
addTmServiceBtn: document.getElementById('add-tm-service-btn'),
|
||||
tmServicesTable: document.getElementById('tm-services-table'),
|
||||
@@ -312,6 +313,9 @@ function initEventListeners() {
|
||||
if (elements.testSub2ApiServiceBtn) {
|
||||
elements.testSub2ApiServiceBtn.addEventListener('click', handleTestSub2ApiService);
|
||||
}
|
||||
if (elements.loadSub2ApiRemoteProxiesBtn) {
|
||||
elements.loadSub2ApiRemoteProxiesBtn.addEventListener('click', () => loadSub2ApiRemoteProxiesForForm());
|
||||
}
|
||||
}
|
||||
|
||||
// 加载设置
|
||||
@@ -1379,6 +1383,101 @@ async function handleTestCpaService() {
|
||||
|
||||
let _sub2apiEditingId = null;
|
||||
|
||||
function getSub2ApiDefaultRemoteProxySelect() {
|
||||
return document.getElementById('sub2api-default-remote-proxy-id');
|
||||
}
|
||||
|
||||
function resetSub2ApiRemoteProxyOptions(selectedValue = '', firstOptionText = '不设置默认代理') {
|
||||
const select = getSub2ApiDefaultRemoteProxySelect();
|
||||
if (!select) return;
|
||||
|
||||
const normalizedValue = selectedValue == null ? '' : String(selectedValue);
|
||||
const options = [`<option value="">${escapeHtml(firstOptionText)}</option>`];
|
||||
if (normalizedValue) {
|
||||
options.push(`<option value="${escapeHtml(normalizedValue)}">当前默认代理 #${escapeHtml(normalizedValue)}(点击加载详情)</option>`);
|
||||
}
|
||||
|
||||
select.innerHTML = options.join('');
|
||||
select.value = normalizedValue;
|
||||
}
|
||||
|
||||
function renderSub2ApiRemoteProxyOptions(proxies, selectedValue = '') {
|
||||
const select = getSub2ApiDefaultRemoteProxySelect();
|
||||
if (!select) return;
|
||||
|
||||
const normalizedValue = selectedValue == null ? '' : String(selectedValue);
|
||||
const hasSelectedProxy = normalizedValue !== '' && proxies.some(proxy => String(proxy.id) === normalizedValue);
|
||||
const options = [
|
||||
`<option value="">${escapeHtml(proxies.length === 0 ? '不设置默认代理(当前暂无远端代理)' : '不设置默认代理')}</option>`
|
||||
];
|
||||
|
||||
if (normalizedValue && !hasSelectedProxy) {
|
||||
options.push(`<option value="${escapeHtml(normalizedValue)}">当前默认代理 #${escapeHtml(normalizedValue)}(远端已不存在)</option>`);
|
||||
}
|
||||
|
||||
options.push(...proxies.map(proxy => {
|
||||
const protocol = String(proxy.protocol || '').trim().toUpperCase();
|
||||
const host = String(proxy.host || '').trim();
|
||||
const port = proxy.port != null ? `:${proxy.port}` : '';
|
||||
const location = host ? ` - ${host}${port}` : '';
|
||||
const status = String(proxy.status || '').trim() || 'inactive';
|
||||
const label = `#${proxy.id} ${proxy.name || `Proxy ${proxy.id}`}${protocol ? ` (${protocol})` : ''}${location} [${status}]`;
|
||||
return `<option value="${proxy.id}">${escapeHtml(label)}</option>`;
|
||||
}));
|
||||
|
||||
select.innerHTML = options.join('');
|
||||
select.value = normalizedValue;
|
||||
}
|
||||
|
||||
function setSub2ApiRemoteProxyLoading(loading) {
|
||||
if (!elements.loadSub2ApiRemoteProxiesBtn) return;
|
||||
elements.loadSub2ApiRemoteProxiesBtn.disabled = loading;
|
||||
elements.loadSub2ApiRemoteProxiesBtn.textContent = loading ? '加载中...' : '加载代理';
|
||||
}
|
||||
|
||||
async function loadSub2ApiRemoteProxiesForForm({ silent = false } = {}) {
|
||||
const id = document.getElementById('sub2api-service-id').value.trim();
|
||||
const apiUrl = document.getElementById('sub2api-service-url').value.trim();
|
||||
const apiKey = document.getElementById('sub2api-service-key').value.trim();
|
||||
const select = getSub2ApiDefaultRemoteProxySelect();
|
||||
const selectedValue = select ? select.value : '';
|
||||
|
||||
if (!apiUrl) {
|
||||
if (!silent) toast.error('请先填写 API URL');
|
||||
return;
|
||||
}
|
||||
if (!id && !apiKey) {
|
||||
if (!silent) toast.error('请先填写 API Key');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = { api_url: apiUrl };
|
||||
if (id) payload.service_id = parseInt(id, 10);
|
||||
if (apiKey) payload.api_key = apiKey;
|
||||
|
||||
setSub2ApiRemoteProxyLoading(true);
|
||||
try {
|
||||
const result = await api.post('/sub2api-services/remote-proxies', payload);
|
||||
const proxies = result.proxies || [];
|
||||
renderSub2ApiRemoteProxyOptions(proxies, selectedValue);
|
||||
if (!silent) {
|
||||
if (proxies.length > 0) {
|
||||
toast.success(`已加载 ${proxies.length} 个远端代理`);
|
||||
} else {
|
||||
toast.info('当前服务下暂无可选远端代理');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (!silent) {
|
||||
toast.error('加载远端代理失败: ' + e.message);
|
||||
} else {
|
||||
console.error('加载远端代理失败:', e);
|
||||
}
|
||||
} finally {
|
||||
setSub2ApiRemoteProxyLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSub2ApiServices() {
|
||||
try {
|
||||
const services = await api.get('/sub2api-services');
|
||||
@@ -1416,19 +1515,31 @@ function openSub2ApiServiceModal(svc = null) {
|
||||
elements.sub2ApiServiceModalTitle.textContent = svc ? '编辑 Sub2API 服务' : '添加 Sub2API 服务';
|
||||
elements.sub2ApiServiceForm.reset();
|
||||
document.getElementById('sub2api-service-id').value = svc ? svc.id : '';
|
||||
|
||||
resetSub2ApiRemoteProxyOptions(svc ? svc.default_remote_proxy_id : '');
|
||||
|
||||
if (svc) {
|
||||
document.getElementById('sub2api-service-name').value = svc.name || '';
|
||||
document.getElementById('sub2api-service-url').value = svc.api_url || '';
|
||||
document.getElementById('sub2api-service-priority').value = svc.priority ?? 0;
|
||||
document.getElementById('sub2api-service-enabled').checked = svc.enabled !== false;
|
||||
document.getElementById('sub2api-service-key').placeholder = svc.has_key ? '已配置,留空保持不变' : '请输入 API Key';
|
||||
} else {
|
||||
document.getElementById('sub2api-service-key').placeholder = '请输入 API Key';
|
||||
}
|
||||
|
||||
elements.sub2ApiServiceEditModal.classList.add('active');
|
||||
|
||||
if (svc) {
|
||||
loadSub2ApiRemoteProxiesForForm({ silent: true });
|
||||
}
|
||||
}
|
||||
|
||||
function closeSub2ApiServiceModal() {
|
||||
elements.sub2ApiServiceEditModal.classList.remove('active');
|
||||
elements.sub2ApiServiceForm.reset();
|
||||
resetSub2ApiRemoteProxyOptions();
|
||||
setSub2ApiRemoteProxyLoading(false);
|
||||
_sub2apiEditingId = null;
|
||||
}
|
||||
|
||||
@@ -1455,10 +1566,13 @@ async function deleteSub2ApiService(id, name) {
|
||||
async function handleSaveSub2ApiService(e) {
|
||||
e.preventDefault();
|
||||
const id = document.getElementById('sub2api-service-id').value;
|
||||
const defaultRemoteProxyValue = getSub2ApiDefaultRemoteProxySelect()?.value || '';
|
||||
const parsedDefaultRemoteProxyId = defaultRemoteProxyValue === '' ? null : parseInt(defaultRemoteProxyValue, 10);
|
||||
const data = {
|
||||
name: document.getElementById('sub2api-service-name').value,
|
||||
api_url: document.getElementById('sub2api-service-url').value,
|
||||
api_key: document.getElementById('sub2api-service-key').value || undefined,
|
||||
default_remote_proxy_id: Number.isNaN(parsedDefaultRemoteProxyId) ? null : parsedDefaultRemoteProxyId,
|
||||
priority: parseInt(document.getElementById('sub2api-service-priority').value) || 0,
|
||||
enabled: document.getElementById('sub2api-service-enabled').checked,
|
||||
};
|
||||
@@ -1499,7 +1613,7 @@ async function testSub2ApiServiceById(id) {
|
||||
async function handleTestSub2ApiService() {
|
||||
const apiUrl = document.getElementById('sub2api-service-url').value.trim();
|
||||
const apiKey = document.getElementById('sub2api-service-key').value.trim();
|
||||
const id = document.getElementById('sub2api-service-id').value;
|
||||
const id = document.getElementById('sub2api-service-id').value.trim();
|
||||
|
||||
if (!apiUrl) {
|
||||
toast.error('请先填写 API URL');
|
||||
@@ -1514,12 +1628,11 @@ async function handleTestSub2ApiService() {
|
||||
elements.testSub2ApiServiceBtn.textContent = '测试中...';
|
||||
|
||||
try {
|
||||
let result;
|
||||
if (id && !apiKey) {
|
||||
result = await api.post(`/sub2api-services/${id}/test`);
|
||||
} else {
|
||||
result = await api.post('/sub2api-services/test-connection', { api_url: apiUrl, api_key: apiKey });
|
||||
}
|
||||
const payload = { api_url: apiUrl };
|
||||
if (id) payload.service_id = parseInt(id, 10);
|
||||
if (apiKey) payload.api_key = apiKey;
|
||||
|
||||
const result = await api.post('/sub2api-services/test-connection', payload);
|
||||
if (result.success) {
|
||||
toast.success(result.message);
|
||||
} else {
|
||||
|
||||
@@ -349,6 +349,16 @@
|
||||
<label for="sub2api-service-key">API Key</label>
|
||||
<input type="password" id="sub2api-service-key" placeholder="编辑时留空则保持原值" autocomplete="new-password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sub2api-default-remote-proxy-id">默认远端代理</label>
|
||||
<div class="sub2api-remote-proxy-row">
|
||||
<select id="sub2api-default-remote-proxy-id" class="sub2api-remote-proxy-select">
|
||||
<option value="">不设置默认代理</option>
|
||||
</select>
|
||||
<button type="button" class="btn btn-secondary sub2api-remote-proxy-btn" id="load-sub2api-remote-proxies-btn">加载代理</button>
|
||||
</div>
|
||||
<p class="sub2api-remote-proxy-hint">与账号页上传时选择的远端代理一致;仅在未显式选择代理时作为默认值。</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="sub2api-service-priority">优先级</label>
|
||||
|
||||
Reference in new issue
Block a user