This commit is contained in:
sjk
2026-01-13 18:59:26 +08:00
commit 7feccf246d
56 changed files with 11596 additions and 0 deletions

515
static/js/browser.js Normal file
View File

@@ -0,0 +1,515 @@
// 全局变量存储当前选中的Profile和代理
let currentProfileId = null;
let currentProxyInfo = null;
// 格式化JSON显示
function formatResult(data, elementId) {
const el = document.getElementById(elementId);
el.innerHTML = `<pre style="background: #f5f5f5; padding: 12px; border-radius: 4px; overflow-x: auto; max-height: 400px;">${JSON.stringify(data, null, 2)}</pre>`;
}
// 查询Profile列表
async function listProfiles() {
try {
showToast('正在查询Profile列表...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/profiles`);
const data = await response.json();
if (data.success) {
const profiles = data.data?.data?.list || [];
if (profiles.length > 0) {
// 美化显示Profile信息
let html = '<div style="background: #f5f5f5; padding: 12px; border-radius: 4px; max-height: 500px; overflow-y: auto;">';
html += `<p style="margin-bottom: 12px; font-weight: 500; color: #333;">找到 ${profiles.length} 个Profile环境</p>`;
profiles.forEach((profile, idx) => {
const proxyConfig = profile.user_proxy_config || {};
const hasProxy = proxyConfig.proxy_host && proxyConfig.proxy_port;
html += `
<div style="background: white; padding: 14px; margin-bottom: 10px; border-radius: 4px; border-left: 4px solid ${hasProxy ? '#52c41a' : '#faad14'};">
<div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 10px;">
<div style="flex: 1;">
<div style="font-weight: 600; color: #333; font-size: 14px; margin-bottom: 4px;">
#${idx + 1} ${profile.name}
<span style="color: #999; font-size: 12px; font-weight: 400; margin-left: 8px;">No.${profile.profile_no}</span>
</div>
<div style="color: #666; font-size: 12px;">
Profile ID: <span style="font-family: monospace; background: #f0f0f0; padding: 2px 6px; border-radius: 2px;">${profile.profile_id}</span>
</div>
</div>
<button onclick="selectProfile('${profile.profile_id}', '${profile.name}')"
style="padding: 6px 12px; background: #1890ff; color: white; border: none; border-radius: 3px; cursor: pointer; font-size: 12px; white-space: nowrap;">
选择环境
</button>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 12px; padding: 8px; background: #fafafa; border-radius: 3px;">
<div>
<span style="color: #999;">当前IP:</span>
<span style="color: #333; font-weight: 500; margin-left: 4px;">${profile.ip || 'N/A'}</span>
${profile.ip_country ? `<span style="color: #999; margin-left: 4px;">(${profile.ip_country.toUpperCase()})</span>` : ''}
</div>
<div>
<span style="color: #999;">最后打开:</span>
<span style="color: #666; margin-left: 4px;">${profile.last_open_time ? new Date(parseInt(profile.last_open_time) * 1000).toLocaleString('zh-CN') : 'N/A'}</span>
</div>
</div>
${hasProxy ? `
<div style="margin-top: 10px; padding: 10px; background: #f6ffed; border: 1px solid #b7eb8f; border-radius: 3px;">
<div style="font-weight: 500; color: #52c41a; margin-bottom: 6px; font-size: 12px;">✓ 代理配置</div>
<div style="font-size: 12px; color: #666; line-height: 1.6;">
<div style="display: flex; gap: 16px; flex-wrap: wrap;">
<div>
<span style="color: #999;">类型:</span>
<span style="color: #333; margin-left: 4px;">${proxyConfig.proxy_type?.toUpperCase() || 'N/A'}</span>
</div>
<div>
<span style="color: #999;">地址:</span>
<span style="color: #333; margin-left: 4px; font-family: monospace;">${proxyConfig.proxy_host}:${proxyConfig.proxy_port}</span>
</div>
${proxyConfig.latest_ip ? `
<div>
<span style="color: #999;">最新IP:</span>
<span style="color: #333; margin-left: 4px; font-family: monospace;">${proxyConfig.latest_ip}</span>
</div>
` : ''}
</div>
${proxyConfig.proxy_user ? `
<div style="margin-top: 4px;">
<span style="color: #999;">认证:</span>
<span style="color: #333; margin-left: 4px; font-family: monospace;">${proxyConfig.proxy_user}</span>
</div>
` : ''}
</div>
</div>
` : `
<div style="margin-top: 10px; padding: 8px; background: #fffbe6; border: 1px solid #ffe58f; border-radius: 3px; font-size: 12px; color: #d48806;">
⚠ 未配置代理
</div>
`}
${profile.remark ? `
<div style="margin-top: 8px; padding: 6px 8px; background: #f0f0f0; border-radius: 3px; font-size: 11px; color: #666;">
备注: ${profile.remark}
</div>
` : ''}
</div>
`;
});
html += '</div>';
document.getElementById('profileResult').innerHTML = html;
// 自动选择第一个Profile
currentProfileId = profiles[0].profile_id;
document.getElementById('profileId').value = currentProfileId;
showToast(`找到 ${profiles.length} 个Profile环境`, 'success');
} else {
document.getElementById('profileResult').innerHTML = '<p style="color: #999; text-align: center; padding: 24px;">未找到Profile环境</p>';
showToast('未找到Profile', 'info');
}
} else {
showToast(data.message || '查询失败', 'error');
}
} catch (error) {
console.error('查询Profile列表错误:', error);
showToast('查询失败: ' + error.message, 'error');
}
}
// 选择Profile
function selectProfile(profileId, profileName) {
currentProfileId = profileId;
document.getElementById('profileId').value = profileId;
showToast(`已选择环境: ${profileName}`, 'success');
}
// 启动浏览器
async function startBrowser() {
const profileId = document.getElementById('profileId').value || currentProfileId;
if (!profileId) {
showToast('请先查询Profile列表或输入Profile ID', 'error');
return;
}
try {
showToast('正在启动浏览器...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/browser/start`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: profileId })
});
const data = await response.json();
if (data.success) {
formatResult(data.data, 'profileResult');
showToast('浏览器启动成功', 'success');
} else {
showToast(data.message || '启动失败', 'error');
}
} catch (error) {
showToast('启动失败: ' + error.message, 'error');
}
}
// 停止浏览器
async function stopBrowser() {
const profileId = document.getElementById('profileId').value || currentProfileId;
if (!profileId) {
showToast('请先输入Profile ID', 'error');
return;
}
try {
showToast('正在停止浏览器...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/browser/stop`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: profileId })
});
const data = await response.json();
if (data.success) {
formatResult(data.data, 'profileResult');
showToast('浏览器已停止', 'success');
} else {
showToast(data.message || '停止失败', 'error');
}
} catch (error) {
showToast('停止失败: ' + error.message, 'error');
}
}
// 获取大麦IP
async function getDamaiProxy() {
try {
showToast('正在获取大麦IP...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/proxy/damai`);
const data = await response.json();
if (data.success) {
currentProxyInfo = data.data;
formatResult(data.data, 'proxyResult');
showToast(`获取成功: ${data.data.host}:${data.data.port}`, 'success');
} else {
showToast(data.message || '获取失败', 'error');
}
} catch (error) {
showToast('获取失败: ' + error.message, 'error');
}
}
// 创建代理
async function createProxy() {
if (!currentProxyInfo) {
showToast('请先获取大麦IP', 'error');
return;
}
try {
showToast('正在创建代理...', 'info');
const proxyConfig = {
type: 'http',
host: currentProxyInfo.host,
port: currentProxyInfo.port,
user: '69538fdef04e1',
password: '63v0kQBr2yJXnjf',
ipchecker: 'ip2location',
remark: 'Damai Auto Proxy'
};
const response = await fetch(`${API_BASE}/api/adspower/proxy/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ proxy_config: proxyConfig })
});
const data = await response.json();
if (data.success) {
document.getElementById('proxyId').value = data.data.proxy_id;
formatResult(data.data, 'proxyResult');
showToast(`代理创建成功ID: ${data.data.proxy_id}`, 'success');
} else {
showToast(data.message || '创建失败', 'error');
}
} catch (error) {
showToast('创建失败: ' + error.message, 'error');
}
}
// 查询代理列表
async function listProxies() {
try {
showToast('正在查询代理列表...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/proxy/list?page=1&limit=50`);
// 检查响应类型
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
console.error('服务器返回非JSON响应:', contentType);
const text = await response.text();
console.error('响应内容:', text.substring(0, 200));
showToast('服务器响应错误,请检查后端服务', 'error');
return;
}
const data = await response.json();
if (data.success && data.data) {
const proxies = data.data?.data?.list || [];
if (proxies.length > 0) {
// 格式化显示代理信息
let html = '<div style="background: #f5f5f5; padding: 12px; border-radius: 4px; max-height: 400px; overflow-y: auto;">';
html += `<p style="margin-bottom: 12px; font-weight: 500;">找到 ${proxies.length} 个代理</p>`;
proxies.forEach((proxy, idx) => {
html += `
<div style="background: white; padding: 10px; margin-bottom: 8px; border-radius: 4px; border-left: 3px solid #1890ff;">
<div style="display: flex; justify-content: space-between; align-items: start;">
<div style="flex: 1;">
<div style="font-weight: 500; color: #333;">#${idx + 1} ID: ${proxy.proxy_id}</div>
<div style="color: #666; font-size: 13px; margin-top: 4px;">
${proxy.type} - ${proxy.host}:${proxy.port}
</div>
${proxy.remark ? `<div style="color: #999; font-size: 12px; margin-top: 2px;">备注: ${proxy.remark}</div>` : ''}
<div style="color: #999; font-size: 12px; margin-top: 2px;">
关联环境数: ${proxy.profile_count || 0}
</div>
</div>
<button onclick="document.getElementById('proxyId').value='${proxy.proxy_id}'"
style="padding: 4px 8px; background: #1890ff; color: white; border: none; border-radius: 2px; cursor: pointer; font-size: 12px;">
选择
</button>
</div>
</div>
`;
});
html += '</div>';
document.getElementById('proxyResult').innerHTML = html;
showToast(`找到 ${proxies.length} 个代理`, 'success');
} else {
document.getElementById('proxyResult').innerHTML = '<p style="color: #999; text-align: center; padding: 24px;">暂无代理,请先创建代理</p>';
showToast('暂无代理', 'info');
}
} else {
showToast(data.message || '查询失败', 'error');
document.getElementById('proxyResult').innerHTML = `<p style="color: #ff4d4f; padding: 12px;">${data.message || '查询失败'}</p>`;
}
} catch (error) {
console.error('查询代理列表错误:', error);
showToast('查询失败: ' + error.message, 'error');
document.getElementById('proxyResult').innerHTML = `<p style="color: #ff4d4f; padding: 12px;">错误: ${error.message}</p>`;
}
}
// 更新Profile代理API v2方式
async function updateProfileProxy() {
const profileId = document.getElementById('profileId').value;
const proxyId = document.getElementById('proxyId').value;
if (!profileId || !proxyId) {
showToast('请输入Profile ID和代理ID', 'error');
return;
}
try {
showToast('正在更新Profile代理 (API v2)...', 'info');
const response = await fetch(`${API_BASE}/api/adspower/profile/update`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ profile_id: profileId, proxy_id: proxyId })
});
const data = await response.json();
if (data.success) {
formatResult(data.data, 'updateResult');
showToast('更新成功 (API v2)', 'success');
} else {
showToast(data.message || '更新失败', 'error');
}
} catch (error) {
showToast('更新失败: ' + error.message, 'error');
}
}
// 更新Profile代理API v1方式
async function updateProfileProxyV1() {
const profileId = document.getElementById('profileId').value;
if (!profileId) {
showToast('请输入Profile ID', 'error');
return;
}
// 获取当前代理信息
if (!currentProxyInfo) {
showToast('请先获取大麦IP', 'error');
return;
}
try {
showToast('正在更新Profile代理 (API v1)...', 'info');
// 构建 proxy_config
const proxyConfig = {
proxy_type: 'http',
proxy_host: currentProxyInfo.host,
proxy_port: currentProxyInfo.port,
proxy_user: '69538fdef04e1',
proxy_password: '63v0kQBr2yJXnjf',
proxy_soft: 'other'
};
const response = await fetch(`${API_BASE}/api/adspower/profile/update-v1`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ profile_id: profileId, proxy_config: proxyConfig })
});
const data = await response.json();
if (data.success) {
let resultHtml = '<div style="background: #f6ffed; padding: 12px; border-radius: 4px; border: 1px solid #b7eb8f;">';
resultHtml += '<div style="color: #52c41a; font-weight: 500; margin-bottom: 8px;">✅ 代理更新成功 (API v1)</div>';
resultHtml += '<div style="font-size: 12px; color: #666;">';
resultHtml += `<div>Profile ID: ${profileId}</div>`;
resultHtml += `<div>代理地址: ${proxyConfig.proxy_host}:${proxyConfig.proxy_port}</div>`;
resultHtml += `<div>认证用户: ${proxyConfig.proxy_user}</div>`;
resultHtml += '</div></div>';
document.getElementById('updateResult').innerHTML = resultHtml;
showToast('更新成功 (API v1)', 'success');
} else {
showToast(data.message || '更新失败', 'error');
document.getElementById('updateResult').innerHTML = `<p style="color: #ff4d4f; padding: 12px;">${data.message || '更新失败'}</p>`;
}
} catch (error) {
console.error('更新Profile代理错误 (v1):', error);
showToast('更新失败: ' + error.message, 'error');
document.getElementById('updateResult').innerHTML = `<p style="color: #ff4d4f; padding: 12px;">错误: ${error.message}</p>`;
}
}
// 完整测试流程
async function fullTest(useProxy) {
const resultDiv = document.getElementById('fullTestResult');
let log = [];
function addLog(msg, type = 'info') {
const time = new Date().toLocaleTimeString();
const color = type === 'error' ? '#ff4d4f' : type === 'success' ? '#52c41a' : '#666';
log.push(`<div style="color: ${color}; margin: 4px 0;">[${time}] ${msg}</div>`);
resultDiv.innerHTML = log.join('');
}
try {
addLog('开始完整测试流程...');
// 1. 查询Profile
addLog('步骤1: 查询Profile列表');
const profileRes = await fetch(`${API_BASE}/api/adspower/profiles`);
const profileData = await profileRes.json();
if (!profileData.success) {
addLog('查询Profile失败: ' + profileData.message, 'error');
return;
}
const profiles = profileData.data?.data?.list || [];
if (profiles.length === 0) {
addLog('未找到Profile', 'error');
return;
}
currentProfileId = profiles[0].profile_id;
document.getElementById('profileId').value = currentProfileId;
addLog(`找到Profile: ${currentProfileId}`, 'success');
if (useProxy) {
// 2. 获取大麦IP
addLog('步骤2: 获取大麦IP代理');
const proxyRes = await fetch(`${API_BASE}/api/adspower/proxy/damai`);
const proxyData = await proxyRes.json();
if (!proxyData.success) {
addLog('获取代理失败: ' + proxyData.message, 'error');
return;
}
currentProxyInfo = proxyData.data;
addLog(`获取代理: ${currentProxyInfo.host}:${currentProxyInfo.port}`, 'success');
// 3. 创建代理
addLog('步骤3: 创建AdsPower代理');
const proxyConfig = {
type: 'http',
host: currentProxyInfo.host,
port: currentProxyInfo.port,
user: '69538fdef04e1',
password: '63v0kQBr2yJXnjf',
ipchecker: 'ip2location',
remark: 'Damai Auto Proxy'
};
const createProxyRes = await fetch(`${API_BASE}/api/adspower/proxy/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ proxy_config: proxyConfig })
});
const createProxyData = await createProxyRes.json();
if (!createProxyData.success) {
addLog('创建代理失败: ' + createProxyData.message, 'error');
return;
}
const proxyId = createProxyData.data.proxy_id;
document.getElementById('proxyId').value = proxyId;
addLog(`创建代理成功ID: ${proxyId}`, 'success');
// 4. 更新Profile
addLog('步骤4: 更新Profile代理配置');
const updateRes = await fetch(`${API_BASE}/api/adspower/profile/update`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ profile_id: currentProfileId, proxy_id: proxyId })
});
const updateData = await updateRes.json();
if (!updateData.success) {
addLog('更新Profile失败: ' + updateData.message, 'error');
return;
}
addLog('更新Profile成功', 'success');
}
// 5. 启动浏览器
addLog(`步骤${useProxy ? 5 : 2}: 启动浏览器`);
const startRes = await fetch(`${API_BASE}/api/adspower/browser/start`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: currentProfileId })
});
const startData = await startRes.json();
if (!startData.success) {
addLog('启动浏览器失败: ' + startData.message, 'error');
return;
}
addLog('浏览器启动成功', 'success');
addLog('测试流程完成!', 'success');
showToast('完整测试流程执行成功', 'success');
} catch (error) {
addLog('测试异常: ' + error.message, 'error');
showToast('测试失败: ' + error.message, 'error');
}
}