// ==UserScript==
// @name 艾德尔阵图AI规划器(智能布局版)
// @namespace https://idlexiuxianzhuan.cn/
// @version 7.0
// @description AI根据阵盘形状和阵纹效果,智能规划并放置阵盘阵纹,主动寻找激活布局
// @author 最中幻想
// @match https://idlexiuxianzhuan.cn/*
// @grant GM_xmlhttpRequest
// @grant GM_download
// @grant GM_notification
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// ========================== 配置 ==========================
let DEEPSEEK_API_KEY = GM_getValue('deepseek_key', '');
const DEEPSEEK_API_URL = 'https://api.deepseek.com/v1/chat/completions';
let allRunes = [];
let recordedLayouts = [];
let currentShapeFilter = '全部';
let runningAutoTest = false;
let stopAutoTestFlag = false;
// ========================== 日志 ==========================
let logPanel;
function addLog(msg, type = 'info') {
const logDiv = document.createElement('div');
logDiv.style.cssText = `padding: 4px 8px; border-bottom: 1px solid #3a3a5a; font-size: 12px; color: ${type === 'error' ? '#ff8888' : (type === 'success' ? '#88ff88' : '#ddd')};`;
logDiv.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
if (logPanel) logPanel.appendChild(logDiv);
logPanel.scrollTop = logPanel.scrollHeight;
console.log(msg);
}
function createLogPanel() {
const panel = document.createElement('div');
panel.id = 'array-tester-log';
panel.style.cssText = `position: fixed; top: 10px; left: 10px; right: 10px; max-height: 180px; background: rgba(0,0,0,0.85); backdrop-filter: blur(10px); border-radius: 12px; padding: 8px; overflow-y: auto; z-index: 1000000; font-family: monospace; font-size: 12px; color: #ddd; border: 1px solid #5a5a7a; pointer-events: none;`;
document.body.appendChild(panel);
logPanel = panel;
addLog('日志面板已启动', 'success');
}
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
async function waitForElement(selector, timeout = 10000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const el = document.querySelector(selector);
if (el) return el;
await sleep(300);
}
return null;
}
async function safeClick(element, description) {
if (!element) { addLog(`❌ 点击失败: ${description} - 元素不存在`, 'error'); return false; }
try {
element.scrollIntoView({ block: 'center' });
await sleep(100);
element.click();
addLog(`✅ 点击: ${description}`, 'success');
await sleep(600);
return true;
} catch (e) { addLog(`❌ 点击异常: ${description} - ${e.message}`, 'error'); return false; }
}
function getButtonByText(parent, text) {
const btns = parent.querySelectorAll('button');
return Array.from(btns).find(btn => btn.innerText.includes(text));
}
// ========================== 数据抓取(增强版,提供更多信息给AI) ==========================
async function getAllRunes() {
let all = [];
let page = 1;
while (true) {
await waitForElement('.cave-pool-card:last-child .cave-pool-item.rune', 5000);
const items = document.querySelectorAll('.cave-pool-card:last-child .cave-pool-item.rune');
for (let item of items) {
const nameEl = item.querySelector('.cave-pool-item-name');
if (!nameEl) continue;
const name = nameEl.innerText.trim();
const metaEl = item.querySelector('.cave-pool-item-meta');
const meta = metaEl ? metaEl.innerText : '';
// 从meta中提取核心效果、指向、品质浮动
let core = '聚灵', direction = '↓', qualityBonus = 0;
const coreMatch = meta.match(/核心效果:([^。]+)/);
if (coreMatch) core = coreMatch[1];
const dirMatch = meta.match(/指向:([←↑→↓]+)/);
if (dirMatch) direction = dirMatch[1];
const qualMatch = meta.match(/品质浮动加成 \+(\d+)%/);
if (qualMatch) qualityBonus = parseInt(qualMatch[1]);
const placeBtn = getButtonByText(item, '选中放置');
all.push({ name, core, direction, qualityBonus, meta, element: item, placeBtn });
}
addLog(`阵纹第 ${page} 页获取 ${items.length} 个,累计 ${all.length}`, 'info');
const pageNav = document.querySelector('.cave-pool-card:last-child .page-nav');
if (!pageNav) break;
const nextBtn = pageNav.querySelector('button:last-child');
if (!nextBtn || nextBtn.disabled || nextBtn.innerText !== '下一页') break;
if (!await safeClick(nextBtn, `翻页 ${page}`)) break;
page++;
await sleep(1000);
}
addLog(`总共获取 ${all.length} 个阵纹`, 'success');
return all;
}
async function applyShapeFilter(shape) {
if (shape === '全部') return;
const filterRow = document.querySelector('.cave-pool-card:first-child .cave-rune-filter-row, .cave-pool-card:first-child label');
if (!filterRow) { addLog('未找到阵盘形状筛选下拉框', 'error'); return; }
const select = filterRow.querySelector('select');
if (!select) { addLog('未找到形状选择器', 'error'); return; }
select.value = shape;
select.dispatchEvent(new Event('change', { bubbles: true }));
await sleep(800);
addLog(`已应用阵盘筛选: ${shape}`, 'success');
}
async function getPlatesWithFilter(shape) {
await applyShapeFilter(shape);
await waitForElement('.cave-pool-card:first-child .cave-pool-item.plate', 5000);
const items = document.querySelectorAll('.cave-pool-card:first-child .cave-pool-item.plate');
const plates = [];
for (let item of items) {
const nameEl = item.querySelector('.cave-pool-item-name');
if (!nameEl) continue;
const name = nameEl.innerText.trim();
const metaEl = item.querySelector('.cave-pool-item-meta');
const meta = metaEl ? metaEl.innerText : '';
let shape = '未知', power = 0, bonuses = {};
if (meta) {
const shapeMatch = meta.match(/形状:([^,]+)/);
if (shapeMatch) shape = shapeMatch[1];
const powerMatch = meta.match(/每回合提供流量 (\d+)/);
if (powerMatch) power = parseInt(powerMatch[1]);
// 提取词条例如 "铸骨效果 +11%" "所有被指向的阵纹效果 +5%"
const specificBonus = meta.match(/(聚灵|铸骨|灵锐|引流|攻伐|守御|迅行|平衡|聚气|锋芒)效果 \+(\d+)%/);
if (specificBonus) bonuses[specificBonus[1]] = parseInt(specificBonus[2]);
const generalMatch = meta.match(/所有被指向的阵纹效果 \+(\d+)%/);
if (generalMatch) bonuses['所有'] = parseInt(generalMatch[1]);
}
const placeBtn = getButtonByText(item, '选中放置');
const rotateBtn = getButtonByText(item, '旋转');
plates.push({ name, shape, power, bonuses, meta, element: item, placeBtn, rotateBtn });
}
addLog(`筛选后得到 ${plates.length} 个阵盘`, 'info');
return plates;
}
// 获取当前阵图详细状态(包括连通纹数量、触发值、属性加成等)
async function getLayoutState() {
const cells = document.querySelectorAll('.cave-formation-grid .cave-formation-cell');
const grid = [];
for (let i = 0; i < cells.length; i++) {
const cell = cells[i];
const piece = cell.querySelector('.cave-piece');
if (piece) {
const type = piece.querySelector('.cave-piece-type')?.innerText;
const name = piece.querySelector('.cave-piece-name')?.innerText;
const meta = piece.querySelector('.cave-piece-meta')?.innerText;
grid.push({ index: i, type, name, meta });
} else {
grid.push(null);
}
}
// 解析各种文本信息
let connectedCount = 0, triggerValue = 0, flowSupply = 0, flowConsume = 0, attrBonus = '';
const hints = document.querySelectorAll('.form-hint');
for (let hint of hints) {
const text = hint.innerText;
if (text.includes('连通阵纹')) {
const match = text.match(/连通阵纹 (\d+)\/(\d+)/);
if (match) connectedCount = parseInt(match[1]);
const triggerMatch = text.match(/主阵触发值总计 (\d+)/);
if (triggerMatch) triggerValue = parseInt(triggerMatch[1]);
}
if (text.includes('阵法流量')) {
const supplyMatch = text.match(/供给 (\d+)/);
if (supplyMatch) flowSupply = parseInt(supplyMatch[1]);
const consumeMatch = text.match(/连通消耗 (\d+)/);
if (consumeMatch) flowConsume = parseInt(consumeMatch[1]);
}
if (text.includes('总体属性加成')) attrBonus = text;
}
const isActivated = Array.from(document.querySelectorAll('.form-hint, .cave-formation-head, .pending-job'))
.some(el => el.innerText.includes('已激活'));
return { grid, connectedCount, triggerValue, flowSupply, flowConsume, attrBonus, isActivated };
}
async function clearGrid() {
const clearBtn = document.querySelector('.cave-formation-main .btn-xs');
if (clearBtn) return await safeClick(clearBtn, '一键清空阵图');
return false;
}
function getEmptyCells() {
const cells = document.querySelectorAll('.cave-formation-grid .cave-formation-cell');
const empty = [];
cells.forEach((cell, idx) => { if (!cell.querySelector('.cave-piece')) empty.push(idx); });
return empty;
}
async function placePlate(plate, cellIndex, rotations = 0) {
if (!plate.placeBtn) { addLog(`❌ 阵盘 ${plate.name} 缺少放置按钮`, 'error'); return false; }
if (!await safeClick(plate.placeBtn, `选中阵盘 ${plate.name}`)) return false;
// 执行旋转
for (let i = 0; i < rotations; i++) {
if (plate.rotateBtn) await safeClick(plate.rotateBtn, `旋转阵盘 ${plate.name}`);
else break;
}
const cells = document.querySelectorAll('.cave-formation-grid .cave-formation-cell');
if (!cells[cellIndex]) return false;
return await safeClick(cells[cellIndex], `放置到格子 ${cellIndex}`);
}
async function placeRune(rune, cellIndex) {
if (!rune.placeBtn) { addLog(`❌ 阵纹 ${rune.name} 缺少放置按钮`, 'error'); return false; }
if (!await safeClick(rune.placeBtn, `选中阵纹 ${rune.name}`)) return false;
const cells = document.querySelectorAll('.cave-formation-grid .cave-formation-cell');
if (!cells[cellIndex]) return false;
return await safeClick(cells[cellIndex], `放置到格子 ${cellIndex}`);
}
async function waitForActivation(timeout = 8000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const toast = document.querySelector('.toast');
if (toast && toast.innerText.includes('主阵已激活')) return true;
const activeHint = Array.from(document.querySelectorAll('.form-hint, .cave-formation-head, .pending-job'))
.some(el => el.innerText.includes('已激活'));
if (activeHint) return true;
await sleep(300);
}
return false;
}
function recordSuccess() {
const layout = captureCurrentLayout();
recordedLayouts.push(layout);
addLog(`🎉 记录激活布局 #${recordedLayouts.length}`, 'success');
}
function captureCurrentLayout() {
const cells = document.querySelectorAll('.cave-formation-grid .cave-formation-cell');
const grid = [];
cells.forEach(cell => {
const piece = cell.querySelector('.cave-piece');
if (piece) {
const type = piece.querySelector('.cave-piece-type')?.innerText;
const name = piece.querySelector('.cave-piece-name')?.innerText;
const meta = piece.querySelector('.cave-piece-meta')?.innerText;
grid.push({ type, name, meta });
} else { grid.push(null); }
});
let attrText = '', statusText = '';
document.querySelectorAll('.form-hint').forEach(hint => {
if (hint.innerText.includes('总体属性加成')) attrText = hint.innerText;
if (hint.innerText.includes('连通阵纹')) statusText = hint.innerText;
});
return { grid, attrText, statusText, timestamp: new Date().toISOString() };
}
// ========================== AI 智能规划核心 ==========================
const toolDefinitions = [
{ name: 'clear_grid', description: '清空阵图', parameters: {} },
{ name: 'filter_plates', description: '筛选阵盘形状', parameters: { shape: { type: 'string', enum: ['全部','长二','T五','X五'] } } },
{ name: 'get_plates', description: '获取当前可用阵盘列表(含形状、提供流量、词条)', parameters: {} },
{ name: 'get_runes', description: '获取全部阵纹列表(含核心效果、指向、品质浮动)', parameters: {} },
{ name: 'place_plate', description: '放置阵盘到指定格子(0-24),可指定旋转次数(0-3)', parameters: { plateIndex: { type: 'integer' }, cellIndex: { type: 'integer' }, rotations: { type: 'integer', default: 0 } } },
{ name: 'place_rune', description: '放置阵纹到指定格子', parameters: { runeIndex: { type: 'integer' }, cellIndex: { type: 'integer' } } },
{ name: 'get_layout_state', description: '获取当前阵图详细状态(连通数、触发值、是否激活等)', parameters: {} },
{ name: 'record_current_layout', description: '将当前布局记录为成功激活布局', parameters: {} },
{ name: 'export_records', description: '导出所有记录', parameters: {} },
{ name: 'start_auto_test', description: '运行随机自动测试(备用方式)', parameters: {} },
{ name: 'stop_auto_test', description: '停止随机测试', parameters: {} },
{ name: 'wait_for_activation', description: '等待主阵激活(最多8秒)', parameters: {} }
];
const toolsForAPI = toolDefinitions.map(tool => ({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: {
type: 'object',
properties: Object.fromEntries(Object.entries(tool.parameters || {}).map(([k, v]) => [k, { type: v.type, enum: v.enum }])),
required: []
}
}
}));
async function callTool(toolName, args) {
addLog(`🔧 执行工具: ${toolName} ${JSON.stringify(args)}`, 'info');
try {
switch (toolName) {
case 'clear_grid': await clearGrid(); return { ok: true };
case 'filter_plates': currentShapeFilter = args.shape; await applyShapeFilter(currentShapeFilter); return { ok: true, shape: currentShapeFilter };
case 'get_plates': {
const plates = await getPlatesWithFilter(currentShapeFilter);
return { ok: true, plates: plates.map((p,i) => ({ index: i, name: p.name, shape: p.shape, power: p.power, bonuses: p.bonuses })) };
}
case 'get_runes': {
if (allRunes.length === 0) allRunes = await getAllRunes();
return { ok: true, runes: allRunes.map((r,i) => ({ index: i, name: r.name, core: r.core, direction: r.direction, qualityBonus: r.qualityBonus })) };
}
case 'place_plate': {
const plates = await getPlatesWithFilter(currentShapeFilter);
const plate = plates[args.plateIndex];
if (!plate) return { ok: false, error: '无效的阵盘索引' };
const success = await placePlate(plate, args.cellIndex, args.rotations || 0);
return { ok: success };
}
case 'place_rune': {
if (allRunes.length === 0) allRunes = await getAllRunes();
const rune = allRunes[args.runeIndex];
if (!rune) return { ok: false, error: '无效的阵纹索引' };
const success = await placeRune(rune, args.cellIndex);
return { ok: success };
}
case 'get_layout_state': {
const state = await getLayoutState();
return { ok: true, state };
}
case 'record_current_layout': recordSuccess(); return { ok: true };
case 'export_records': exportRecords(); return { ok: true };
case 'start_auto_test': startAutoTest(); return { ok: true };
case 'stop_auto_test': stopAutoTest(); return { ok: true };
case 'wait_for_activation': {
const activated = await waitForActivation(8000);
return { ok: true, activated };
}
default: return { ok: false, error: '未知工具' };
}
} catch (e) {
addLog(`工具异常: ${e.message}`, 'error');
return { ok: false, error: e.message };
}
}
async function askAIWithLoop(userMessage) {
if (!DEEPSEEK_API_KEY) {
addLog('请先设置DeepSeek API密钥', 'error');
return 'API密钥未配置';
}
let conversation = [
{ role: 'system', content: `你是艾德尔修仙传的阵图布局专家。你的目标是:通过智能分析阵盘形状、阵纹效果、连通规则,主动规划并放置阵盘和阵纹,以达到“主阵已激活”状态,并记录成功的布局。你拥有以下工具可以使用。每次任务执行中,你可以连续调用多个工具,并根据结果调整策略。当任务完成时,你必须返回一个JSON对象,格式为 { "done": true, "message": "总结信息" }。不要在未完成时返回done。
具体规划思路:
1. 首先调用 get_plates 和 get_runes 获取所有可用部件。
2. 分析阵盘的形状(长二、T五、X五等)和提供的流量,以及词条加成。
3. 分析阵纹的核心效果(聚灵、铸骨等)、指向和品质浮动。
4. 规划一个5x5网格的布局:首先放置一个阵盘(选择合适的位置和旋转),然后在周围空格子放置阵纹,使得阵纹的指向能够连接到阵盘,并且尽可能提高触发值。
5. 放置过程中可以多次调用 get_layout_state 检查连通数和触发值。
6. 如果触发了激活,立即调用 record_current_layout 记录,然后可以 clear_grid 开始下一轮尝试,或结束任务。
7. 尽量使用较少的尝试次数找到激活方案,避免随机穷举。
8. 你可以自主决定尝试不同的阵盘和阵纹组合。` }
];
conversation.push({ role: 'user', content: userMessage });
let finalAnswer = '';
let loopCount = 0;
const MAX_LOOPS = 30;
while (loopCount++ < MAX_LOOPS) {
const resp = await new Promise((resolve) => {
GM_xmlhttpRequest({
method: 'POST',
url: DEEPSEEK_API_URL,
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${DEEPSEEK_API_KEY}` },
data: JSON.stringify({
model: 'deepseek-chat',
messages: conversation,
tools: toolsForAPI,
tool_choice: 'auto',
temperature: 0.3
}),
onload: (r) => resolve(JSON.parse(r.responseText)),
onerror: (err) => resolve({ error: true, message: err })
});
});
if (resp.error) { addLog('API请求失败', 'error'); break; }
const choice = resp.choices[0];
const message = choice.message;
conversation.push(message);
if (message.tool_calls && message.tool_calls.length) {
const toolResults = [];
for (let tc of message.tool_calls) {
const toolName = tc.function.name;
const args = JSON.parse(tc.function.arguments);
const result = await callTool(toolName, args);
toolResults.push({ tool_call_id: tc.id, role: 'tool', content: JSON.stringify(result) });
}
conversation.push(...toolResults);
continue;
} else {
const content = message.content;
try {
const jsonMatch = content.match(/\{[\s\S]*"done"\s*:\s*true[\s\S]*\}/);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[0]);
if (parsed.done === true) {
finalAnswer = parsed.message || '任务完成';
addLog(`AI 完成任务: ${finalAnswer}`, 'success');
break;
}
}
} catch(e) {}
finalAnswer = content || '无明确完成标志';
break;
}
}
if (loopCount >= MAX_LOOPS) finalAnswer = '达到最大循环次数,任务可能未完成。';
return finalAnswer;
}
// ========================== UI 组件(与之前类似) ==========================
let chatPanel, chatLogDiv, chatInput;
function appendChatMessage(role, text) {
const div = document.createElement('div');
div.style.cssText = `padding: 6px 10px; border-radius: 12px; max-width: 85%; margin: 4px 0; ${role === 'user' ? 'align-self: flex-end; background: #2c6e2c;' : 'align-self: flex-start; background: #2a2a3a;'}`;
div.textContent = text;
chatLogDiv.appendChild(div);
chatLogDiv.scrollTop = chatLogDiv.scrollHeight;
}
async function onSendMessage() {
const msg = chatInput.value.trim();
if (!msg) return;
appendChatMessage('user', msg);
chatInput.value = '';
const reply = await askAIWithLoop(msg);
appendChatMessage('ai', reply);
}
function createChatPanel() {
const panel = document.createElement('div');
panel.id = 'ai-chat-panel';
panel.style.cssText = `
position: fixed; bottom: 20px; right: 20px; width: 360px; max-width: 90vw;
background: #1e1e2fe6; backdrop-filter: blur(12px); border-radius: 20px;
border: 1px solid #6a6a8a; display: flex; flex-direction: column;
z-index: 1000001; font-family: system-ui; box-shadow: 0 4px 20px black;
`;
const header = document.createElement('div');
header.style.cssText = 'padding: 8px 12px; background: #2a2a3a; border-radius: 20px 20px 0 0; cursor: move; display: flex; justify-content: space-between;';
header.innerHTML = '🧠 AI规划器 (DeepSeek)';
const logDiv = document.createElement('div');
logDiv.style.cssText = 'height: 300px; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 6px; font-size: 13px;';
const inputDiv = document.createElement('div');
inputDiv.style.cssText = 'display: flex; padding: 8px; gap: 8px; border-top: 1px solid #4a4a6a;';
chatInput = document.createElement('input');
chatInput.style.cssText = 'flex:1; background:#2a2a3a; border:none; border-radius:20px; padding:8px 12px; color:white;';
chatInput.placeholder = '例如:请规划一个能激活主阵的布局,找到后记录并导出。';
const sendBtn = document.createElement('button');
sendBtn.textContent = '发送';
sendBtn.style.cssText = 'background:#2c6e2c; border:none; border-radius:20px; padding:8px 16px; color:white; cursor:pointer;';
sendBtn.onclick = onSendMessage;
inputDiv.appendChild(chatInput);
inputDiv.appendChild(sendBtn);
panel.appendChild(header);
panel.appendChild(logDiv);
panel.appendChild(inputDiv);
document.body.appendChild(panel);
chatLogDiv = logDiv;
header.querySelector('#close-chat').onclick = () => panel.style.display = 'none';
// 拖拽
let offsetX, offsetY, isDragging = false;
header.addEventListener('mousedown', (e) => {
if (e.target === header.querySelector('#close-chat')) return;
isDragging = true;
offsetX = e.clientX - panel.offsetLeft;
offsetY = e.clientY - panel.offsetTop;
panel.style.position = 'fixed';
panel.style.bottom = 'auto';
panel.style.top = panel.offsetTop + 'px';
panel.style.right = 'auto';
panel.style.left = panel.offsetLeft + 'px';
e.preventDefault();
});
window.addEventListener('mousemove', (e) => {
if (!isDragging) return;
panel.style.left = (e.clientX - offsetX) + 'px';
panel.style.top = (e.clientY - offsetY) + 'px';
});
window.addEventListener('mouseup', () => { isDragging = false; });
appendChatMessage('ai', '你好!我是AI阵图规划助手。我会智能分析阵盘和阵纹,主动尝试布局以激活主阵。你可以给我一个目标,例如:“找到一种激活布局并记录”。');
}
// 辅助手动测试功能(保留但不必须)
async function startAutoTest() {
if (runningAutoTest) return;
runningAutoTest = true;
stopAutoTestFlag = false;
if (allRunes.length === 0) allRunes = await getAllRunes();
let attempt = 0;
while (!stopAutoTestFlag && attempt < 100) {
attempt++;
const plates = await getPlatesWithFilter(currentShapeFilter);
if (plates.length === 0) break;
await clearGrid();
// 随机尝试(纯机械,备用)
const plate = plates[Math.floor(Math.random() * plates.length)];
const empty = getEmptyCells();
if (empty.length) await placePlate(plate, empty[Math.floor(Math.random() * empty.length)]);
for (let i = 0; i < 12; i++) {
if (await waitForActivation(1500)) { recordSuccess(); break; }
const emptyCells = getEmptyCells();
if (emptyCells.length === 0) break;
const rune = allRunes[Math.floor(Math.random() * allRunes.length)];
await placeRune(rune, emptyCells[Math.floor(Math.random() * emptyCells.length)]);
}
await sleep(800);
}
runningAutoTest = false;
}
function stopAutoTest() { stopAutoTestFlag = true; }
function exportRecords() {
if (!recordedLayouts.length) { alert('暂无记录'); return; }
const data = JSON.stringify(recordedLayouts, null, 2);
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.download = `array_ai_layouts_${Date.now()}.json`;
a.href = url;
a.click();
URL.revokeObjectURL(url);
addLog('已导出记录', 'success');
}
function clearRecords() { recordedLayouts = []; addLog('记录已清空', 'info'); }
function showApiKeyDialog() {
const key = prompt('DeepSeek API Key:', DEEPSEEK_API_KEY);
if (key !== null) {
DEEPSEEK_API_KEY = key;
GM_setValue('deepseek_key', key);
addLog('API密钥已保存', 'success');
}
}
function createMainPanel() {
const panel = document.createElement('div');
panel.id = 'auto-tester-controls';
panel.style.cssText = `
position: fixed; top: 220px; left: 10px; background: #1e1e2fe6;
backdrop-filter: blur(8px); border-radius: 16px; padding: 12px;
display: flex; flex-direction: column; gap: 8px; z-index: 1000000;
border: 1px solid #6a6a8a; font-family: system-ui; min-width: 170px;
`;
const shapeRow = document.createElement('div');
shapeRow.style.cssText = 'display:flex; gap:6px; align-items:center; color:white; font-size:13px;';
shapeRow.innerText = '阵盘形状: ';
const shapeSelect = document.createElement('select');
shapeSelect.style.cssText = 'background:#2a2a3a; color:white; border-radius:16px; padding:4px 8px;';
['全部','长二','T五','X五'].forEach(s => { const opt = document.createElement('option'); opt.value = s; opt.text = s; shapeSelect.appendChild(opt); });
shapeSelect.value = currentShapeFilter;
shapeSelect.onchange = (e) => { currentShapeFilter = e.target.value; addLog(`形状改为 ${currentShapeFilter}`, 'info'); };
shapeRow.appendChild(shapeSelect);
panel.appendChild(shapeRow);
const btnStyle = 'background:#2c6e2c; border:none; color:white; padding:8px; border-radius:30px; cursor:pointer; margin:2px 0;';
const startBtn = document.createElement('button'); startBtn.textContent = '⏵ 随机测试(备用)'; startBtn.style.cssText = btnStyle; startBtn.onclick = startAutoTest;
const stopBtn = document.createElement('button'); stopBtn.textContent = '⏹ 停止随机'; stopBtn.style.cssText = btnStyle.replace('#2c6e2c','#8b3c3c'); stopBtn.onclick = stopAutoTest;
const exportBtn = document.createElement('button'); exportBtn.textContent = '💾 导出记录'; exportBtn.style.cssText = btnStyle.replace('#2c6e2c','#2980b9'); exportBtn.onclick = exportRecords;
const clearBtn = document.createElement('button'); clearBtn.textContent = '🗑️ 清空记录'; clearBtn.style.cssText = btnStyle.replace('#2c6e2c','#7f8c8d'); clearBtn.onclick = clearRecords;
const apiBtn = document.createElement('button'); apiBtn.textContent = '🔑 设置API密钥'; apiBtn.style.cssText = btnStyle.replace('#2c6e2c','#9b59b6'); apiBtn.onclick = showApiKeyDialog;
const chatToggle = document.createElement('button'); chatToggle.textContent = '💬 显示/隐藏AI'; chatToggle.style.cssText = btnStyle.replace('#2c6e2c','#34495e'); chatToggle.onclick = () => { if(chatPanel) chatPanel.style.display = chatPanel.style.display === 'none' ? 'flex' : 'none'; };
panel.append(startBtn, stopBtn, exportBtn, clearBtn, apiBtn, chatToggle);
document.body.appendChild(panel);
}
function init() {
createLogPanel();
createMainPanel();
createChatPanel();
addLog('AI智能阵图规划器已加载,设置DeepSeek API密钥后即可使用。', 'success');
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();