630 lines
21 KiB
JavaScript
630 lines
21 KiB
JavaScript
// 云顶之弈阵容推荐器 - 前端脚本
|
|
|
|
// 页面加载完成后执行
|
|
$(document).ready(function() {
|
|
// 初始化抽屉
|
|
initDrawer();
|
|
|
|
// 加载本地存储的权重
|
|
loadWeightsFromLocalStorage();
|
|
|
|
// 初始化基础权重滑块
|
|
initBasicWeightSliders();
|
|
|
|
// 初始化羁绊权重滑块
|
|
initSynergyWeightSliders();
|
|
|
|
// 初始化棋子权重滑块
|
|
initChessWeightSliders();
|
|
|
|
// 监听人口数量变化
|
|
$('#population').on('input', function() {
|
|
$('#population-value').text($(this).val());
|
|
});
|
|
|
|
// 监听推荐结果数量变化
|
|
$('#num-results').on('input', function() {
|
|
$('#num-results-value').text($(this).val());
|
|
});
|
|
|
|
// 添加必要羁绊
|
|
$('#add-required-synergy').on('click', function() {
|
|
const synergySelect = $('#required-synergy-select');
|
|
const synergyId = synergySelect.val();
|
|
const synergyName = synergySelect.find('option:selected').text();
|
|
|
|
if (!synergyId) return;
|
|
|
|
// 检查是否已添加
|
|
if ($(`#required-synergy-${synergyId}`).length > 0) return;
|
|
|
|
// 添加到列表
|
|
const synergyItem = $(`
|
|
<div id="required-synergy-${synergyId}" class="flex items-center justify-between bg-indigo-50 p-2 rounded" data-synergy-id="${synergyId}">
|
|
<span class="text-gray-800">${synergyName}</span>
|
|
<button class="remove-synergy text-red-500 hover:text-red-700">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
`);
|
|
|
|
$('#required-synergies-list').append(synergyItem);
|
|
|
|
// 重置选择框
|
|
synergySelect.val('');
|
|
});
|
|
|
|
// 移除必要羁绊
|
|
$(document).on('click', '.remove-synergy', function() {
|
|
$(this).closest('div').remove();
|
|
});
|
|
|
|
// 添加必选棋子
|
|
$('#add-required-chess').on('click', function() {
|
|
const chessSelect = $('#required-chess-select');
|
|
const chessId = chessSelect.val();
|
|
const chessName = chessSelect.find('option:selected').text();
|
|
|
|
if (!chessId) return;
|
|
|
|
// 检查是否已添加
|
|
if ($(`#required-chess-${chessId}`).length > 0) return;
|
|
|
|
// 添加到列表
|
|
const chessItem = $(`
|
|
<div id="required-chess-${chessId}" class="flex items-center justify-between bg-indigo-50 p-2 rounded" data-chess-id="${chessId}">
|
|
<span class="text-gray-800">${chessName}</span>
|
|
<button class="remove-chess text-red-500 hover:text-red-700">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
`);
|
|
|
|
$('#required-chess-list').append(chessItem);
|
|
|
|
// 重置选择框
|
|
chessSelect.val('');
|
|
});
|
|
|
|
// 移除必选棋子
|
|
$(document).on('click', '.remove-chess', function() {
|
|
$(this).closest('div').remove();
|
|
});
|
|
|
|
// 生成阵容
|
|
$('#generate-btn').on('click', function() {
|
|
generateTeam();
|
|
});
|
|
|
|
// 仅显示已激活羁绊
|
|
$('#show-only-active').on('change', function() {
|
|
const isChecked = $(this).is(':checked');
|
|
toggleActiveSynergiesVisibility(isChecked);
|
|
});
|
|
|
|
// 仅显示已激活棋子
|
|
$('#show-only-active-chess').on('change', function() {
|
|
const isChecked = $(this).is(':checked');
|
|
toggleActiveChessVisibility(isChecked);
|
|
});
|
|
|
|
// 监听权重变化,保存到本地存储
|
|
$(document).on('change', '.noUi-target', function() {
|
|
saveWeightsToLocalStorage();
|
|
});
|
|
|
|
// 恢复默认配置按钮
|
|
$('#reset-to-default').on('click', function() {
|
|
resetToDefaultWeights();
|
|
});
|
|
});
|
|
|
|
/**
|
|
* 初始化抽屉控制
|
|
*/
|
|
function initDrawer() {
|
|
// 打开抽屉
|
|
$('#open-weights-drawer').on('click', function() {
|
|
$('#weights-drawer').addClass('open');
|
|
$('#drawer-backdrop').addClass('open');
|
|
});
|
|
|
|
// 关闭抽屉
|
|
$('#close-drawer, #drawer-backdrop').on('click', function() {
|
|
$('#weights-drawer').removeClass('open');
|
|
$('#drawer-backdrop').removeClass('open');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 从本地存储加载权重设置
|
|
*/
|
|
function loadWeightsFromLocalStorage() {
|
|
const storedWeights = localStorage.getItem('tft-weights');
|
|
if (!storedWeights) return;
|
|
|
|
try {
|
|
const weights = JSON.parse(storedWeights);
|
|
|
|
// 设置基础权重
|
|
if (weights.base_weights) {
|
|
if (weights.base_weights.synergy_level_weight) {
|
|
$('#synergy-level-weight-value').text(weights.base_weights.synergy_level_weight.toFixed(1));
|
|
}
|
|
if (weights.base_weights.synergy_count_weight) {
|
|
$('#synergy-count-weight-value').text(weights.base_weights.synergy_count_weight.toFixed(1));
|
|
}
|
|
if (weights.base_weights.chess_cost_weight) {
|
|
$('#chess-cost-weight-value').text(weights.base_weights.chess_cost_weight.toFixed(1));
|
|
}
|
|
}
|
|
|
|
// 设置羁绊权重
|
|
if (weights.synergy_weights) {
|
|
for (const [synergyId, weight] of Object.entries(weights.synergy_weights)) {
|
|
$(`.synergy-weight-item[data-synergy-id="${synergyId}"] .synergy-weight-value`).text(weight.toFixed(1));
|
|
}
|
|
}
|
|
|
|
// 设置棋子权重
|
|
if (weights.chess_weights) {
|
|
for (const [chessId, weight] of Object.entries(weights.chess_weights)) {
|
|
$(`.chess-weight-item[data-chess-id="${chessId}"] .chess-weight-value`).text(weight.toFixed(1));
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('加载权重设置失败:', e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存权重设置到本地存储
|
|
*/
|
|
function saveWeightsToLocalStorage() {
|
|
// 获取基础权重
|
|
const synergyLevelWeight = parseFloat($('#synergy-level-weight-value').text());
|
|
const synergyCountWeight = parseFloat($('#synergy-count-weight-value').text());
|
|
const chessCountWeight = parseFloat($('#chess-cost-weight-value').text());
|
|
|
|
// 获取羁绊权重
|
|
const synergyWeights = {};
|
|
$('.synergy-weight-item').each(function() {
|
|
const synergyId = $(this).data('synergy-id');
|
|
const weight = parseFloat($(this).find('.synergy-weight-value').text());
|
|
synergyWeights[synergyId] = weight;
|
|
});
|
|
|
|
// 获取棋子权重
|
|
const chessWeights = {};
|
|
$('.chess-weight-item').each(function() {
|
|
const chessId = $(this).data('chess-id');
|
|
const weight = parseFloat($(this).find('.chess-weight-value').text());
|
|
chessWeights[chessId] = weight;
|
|
});
|
|
|
|
// 构建权重对象
|
|
const weightsObj = {
|
|
base_weights: {
|
|
synergy_level_weight: synergyLevelWeight,
|
|
synergy_count_weight: synergyCountWeight,
|
|
chess_cost_weight: chessCountWeight
|
|
},
|
|
synergy_weights: synergyWeights,
|
|
chess_weights: chessWeights
|
|
};
|
|
|
|
// 保存到本地存储
|
|
localStorage.setItem('tft-weights', JSON.stringify(weightsObj));
|
|
}
|
|
|
|
/**
|
|
* 重置为默认权重
|
|
*/
|
|
function resetToDefaultWeights() {
|
|
// 发送请求获取默认权重
|
|
$.ajax({
|
|
url: '/api/weights',
|
|
type: 'GET',
|
|
success: function(response) {
|
|
// 更新基础权重
|
|
if (response.base_weights) {
|
|
if (response.base_weights.synergy_level_weight) {
|
|
const slider = document.getElementById('synergy-level-weight-slider').noUiSlider;
|
|
slider.set(response.base_weights.synergy_level_weight);
|
|
}
|
|
if (response.base_weights.synergy_count_weight) {
|
|
const slider = document.getElementById('synergy-count-weight-slider').noUiSlider;
|
|
slider.set(response.base_weights.synergy_count_weight);
|
|
}
|
|
if (response.base_weights.chess_cost_weight) {
|
|
const slider = document.getElementById('chess-cost-weight-slider').noUiSlider;
|
|
slider.set(response.base_weights.chess_cost_weight);
|
|
}
|
|
}
|
|
|
|
// 更新羁绊权重
|
|
if (response.synergy_weights) {
|
|
for (const [synergyId, weight] of Object.entries(response.synergy_weights)) {
|
|
const slider = $(`.synergy-weight-item[data-synergy-id="${synergyId}"] .synergy-weight-slider`)[0];
|
|
if (slider && slider.noUiSlider) {
|
|
slider.noUiSlider.set(weight);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 更新棋子权重
|
|
if (response.chess_weights) {
|
|
for (const [chessId, weight] of Object.entries(response.chess_weights)) {
|
|
const slider = $(`.chess-weight-item[data-chess-id="${chessId}"] .chess-weight-slider`)[0];
|
|
if (slider && slider.noUiSlider) {
|
|
slider.noUiSlider.set(weight);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 清除本地存储
|
|
localStorage.removeItem('tft-weights');
|
|
|
|
alert('已恢复默认权重设置');
|
|
},
|
|
error: function(xhr, status, error) {
|
|
alert(`恢复默认权重失败: ${error}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 初始化基础权重滑块
|
|
*/
|
|
function initBasicWeightSliders() {
|
|
// 羁绊等级权重
|
|
const synergyLevelSlider = document.getElementById('synergy-level-weight-slider');
|
|
const synergyLevelValue = parseFloat($('#synergy-level-weight-value').text());
|
|
|
|
noUiSlider.create(synergyLevelSlider, {
|
|
start: [synergyLevelValue],
|
|
connect: [true, false],
|
|
step: 0.1,
|
|
range: {
|
|
'min': [0.0],
|
|
'max': [3.0]
|
|
}
|
|
});
|
|
|
|
// 更新羁绊等级权重值
|
|
synergyLevelSlider.noUiSlider.on('update', function(values, handle) {
|
|
$('#synergy-level-weight-value').text(parseFloat(values[handle]).toFixed(1));
|
|
});
|
|
|
|
// 羁绊数量权重
|
|
const synergyCountSlider = document.getElementById('synergy-count-weight-slider');
|
|
const synergyCountValue = parseFloat($('#synergy-count-weight-value').text());
|
|
|
|
noUiSlider.create(synergyCountSlider, {
|
|
start: [synergyCountValue],
|
|
connect: [true, false],
|
|
step: 0.1,
|
|
range: {
|
|
'min': [0.0],
|
|
'max': [3.0]
|
|
}
|
|
});
|
|
|
|
// 更新羁绊数量权重值
|
|
synergyCountSlider.noUiSlider.on('update', function(values, handle) {
|
|
$('#synergy-count-weight-value').text(parseFloat(values[handle]).toFixed(1));
|
|
});
|
|
|
|
// 棋子费用权重
|
|
const chessCountSlider = document.getElementById('chess-cost-weight-slider');
|
|
const chessCountValue = parseFloat($('#chess-cost-weight-value').text());
|
|
|
|
noUiSlider.create(chessCountSlider, {
|
|
start: [chessCountValue],
|
|
connect: [true, false],
|
|
step: 0.1,
|
|
range: {
|
|
'min': [0.0],
|
|
'max': [1.0]
|
|
}
|
|
});
|
|
|
|
// 更新棋子费用权重值
|
|
chessCountSlider.noUiSlider.on('update', function(values, handle) {
|
|
$('#chess-cost-weight-value').text(parseFloat(values[handle]).toFixed(1));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 初始化羁绊权重滑块
|
|
*/
|
|
function initSynergyWeightSliders() {
|
|
$('.synergy-weight-item').each(function() {
|
|
const slider = $(this).find('.synergy-weight-slider')[0];
|
|
const valueElement = $(this).find('.synergy-weight-value');
|
|
const initialValue = parseFloat(valueElement.text());
|
|
|
|
noUiSlider.create(slider, {
|
|
start: [initialValue],
|
|
connect: [true, false],
|
|
step: 0.1,
|
|
range: {
|
|
'min': [0.0],
|
|
'max': [3.0]
|
|
}
|
|
});
|
|
|
|
// 更新权重值
|
|
slider.noUiSlider.on('update', function(values, handle) {
|
|
valueElement.text(parseFloat(values[handle]).toFixed(1));
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 初始化棋子权重滑块
|
|
*/
|
|
function initChessWeightSliders() {
|
|
$('.chess-weight-item').each(function() {
|
|
const slider = $(this).find('.chess-weight-slider')[0];
|
|
const valueElement = $(this).find('.chess-weight-value');
|
|
const initialValue = parseFloat(valueElement.text());
|
|
|
|
noUiSlider.create(slider, {
|
|
start: [initialValue],
|
|
connect: [true, false],
|
|
step: 0.1,
|
|
range: {
|
|
'min': [0.0],
|
|
'max': [3.0]
|
|
}
|
|
});
|
|
|
|
// 更新权重值
|
|
slider.noUiSlider.on('update', function(values, handle) {
|
|
valueElement.text(parseFloat(values[handle]).toFixed(1));
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 生成阵容
|
|
*/
|
|
function generateTeam() {
|
|
// 显示加载状态
|
|
$('#loading').removeClass('hidden');
|
|
$('#results-container').empty();
|
|
|
|
// 获取基础参数
|
|
const population = parseInt($('#population').val());
|
|
const numResults = parseInt($('#num-results').val());
|
|
|
|
// 获取基础权重
|
|
const synergyLevelWeight = parseFloat($('#synergy-level-weight-value').text());
|
|
const synergyCountWeight = parseFloat($('#synergy-count-weight-value').text());
|
|
const chessCountWeight = parseFloat($('#chess-cost-weight-value').text());
|
|
|
|
// 获取羁绊权重
|
|
const synergyWeights = {};
|
|
$('.synergy-weight-item').each(function() {
|
|
const synergyId = $(this).data('synergy-id');
|
|
const weight = parseFloat($(this).find('.synergy-weight-value').text());
|
|
synergyWeights[synergyId] = weight;
|
|
});
|
|
|
|
// 获取棋子权重
|
|
const chessWeights = {};
|
|
$('.chess-weight-item').each(function() {
|
|
const chessId = $(this).data('chess-id');
|
|
const weight = parseFloat($(this).find('.chess-weight-value').text());
|
|
chessWeights[chessId] = weight;
|
|
});
|
|
|
|
// 获取必选羁绊
|
|
const requiredSynergies = [];
|
|
$('#required-synergies-list > div').each(function() {
|
|
requiredSynergies.push($(this).data('synergy-id'));
|
|
});
|
|
|
|
// 获取必选棋子
|
|
const requiredChess = [];
|
|
$('#required-chess-list > div').each(function() {
|
|
requiredChess.push($(this).data('chess-id'));
|
|
});
|
|
|
|
// 构建请求体
|
|
const requestData = {
|
|
population: population,
|
|
num_results: numResults,
|
|
base_weights: {
|
|
synergy_level_weight: synergyLevelWeight,
|
|
synergy_count_weight: synergyCountWeight,
|
|
chess_cost_weight: chessCountWeight
|
|
},
|
|
synergy_weights: synergyWeights,
|
|
chess_weights: chessWeights,
|
|
required_synergies: requiredSynergies,
|
|
required_chess: requiredChess
|
|
};
|
|
|
|
// 保存当前设置到本地存储
|
|
saveWeightsToLocalStorage();
|
|
|
|
// 发送请求
|
|
$.ajax({
|
|
url: '/api/recommend',
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify(requestData),
|
|
success: function(response) {
|
|
// 隐藏加载状态
|
|
$('#loading').addClass('hidden');
|
|
|
|
if (response.status === 'success') {
|
|
// 渲染结果
|
|
renderResults(response.results);
|
|
|
|
// 更新羁绊和棋子激活状态
|
|
updateActiveStatus(response.results);
|
|
} else {
|
|
// 显示错误信息
|
|
$('#results-container').html(`<div class="text-red-600 p-4">生成阵容失败: ${response.message}</div>`);
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
// 隐藏加载状态
|
|
$('#loading').addClass('hidden');
|
|
|
|
// 显示错误信息
|
|
$('#results-container').html(`<div class="text-red-600 p-4">请求失败: ${error}</div>`);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 渲染阵容结果
|
|
* @param {Array} results 阵容结果列表
|
|
*/
|
|
function renderResults(results) {
|
|
const container = $('#results-container');
|
|
container.empty();
|
|
|
|
results.forEach((result, index) => {
|
|
// 克隆结果模板
|
|
const template = document.getElementById('team-result-template');
|
|
const teamElement = $(template.content.cloneNode(true));
|
|
|
|
// 设置阵容编号和评分
|
|
teamElement.find('.team-number').text(index + 1);
|
|
teamElement.find('.team-score').text(result.score.toFixed(1));
|
|
|
|
// 渲染棋子列表
|
|
const chessList = teamElement.find('.chess-list');
|
|
result.chess_list.forEach(chess => {
|
|
const chessCard = $(`
|
|
<div class="chess-card p-2 chess-cost-${chess.cost}">
|
|
<div class="font-medium text-sm">${chess.name}</div>
|
|
<div class="text-xs text-gray-500">${chess.cost}费</div>
|
|
</div>
|
|
`);
|
|
chessList.append(chessCard);
|
|
});
|
|
|
|
// 渲染羁绊列表
|
|
const synergyList = teamElement.find('.synergy-list');
|
|
result.active_synergies.forEach(synergy => {
|
|
const synergyTag = $(`
|
|
<div class="synergy-tag">
|
|
<span>${synergy.name}</span>
|
|
<span class="ml-1 text-indigo-700">(${synergy.level})</span>
|
|
</div>
|
|
`);
|
|
synergyList.append(synergyTag);
|
|
});
|
|
|
|
// 添加到结果容器
|
|
container.append(teamElement);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 更新羁绊和棋子的激活状态
|
|
* @param {Array} results 阵容结果列表
|
|
*/
|
|
function updateActiveStatus(results) {
|
|
// 重置激活状态
|
|
$('.synergy-weight-item').removeClass('active');
|
|
$('.chess-weight-item').removeClass('active');
|
|
|
|
// 收集所有被激活的羁绊和棋子
|
|
const activeSynergies = new Set();
|
|
const activeSynergyNames = new Set();
|
|
const activeChess = new Set();
|
|
const activeChessNames = new Set();
|
|
|
|
results.forEach(result => {
|
|
// 添加激活的羁绊
|
|
result.active_synergies.forEach(synergy => {
|
|
if (synergy.id) activeSynergies.add(String(synergy.id));
|
|
if (synergy.name) activeSynergyNames.add(synergy.name);
|
|
});
|
|
|
|
// 添加激活的棋子
|
|
result.chess_list.forEach(chess => {
|
|
if (chess.id) activeChess.add(String(chess.id));
|
|
if (chess.name) activeChessNames.add(chess.name);
|
|
});
|
|
});
|
|
|
|
// 处理羁绊激活状态
|
|
$('.synergy-weight-item').each(function() {
|
|
const $item = $(this);
|
|
const synergyId = String($item.data('synergy-id'));
|
|
const synergyName = $item.data('synergy-name') || $item.find('label').text().trim();
|
|
|
|
// 通过ID或名称匹配
|
|
if (activeSynergies.has(synergyId) ||
|
|
activeSynergyNames.has(synergyName) ||
|
|
activeSynergyNames.has(synergyName.toLowerCase())) {
|
|
$item.addClass('active');
|
|
}
|
|
});
|
|
|
|
// 处理棋子激活状态
|
|
$('.chess-weight-item').each(function() {
|
|
const $item = $(this);
|
|
const chessId = String($item.data('chess-id'));
|
|
const chessName = $item.data('chess-name') || $item.find('label').text().trim();
|
|
|
|
// 通过ID或名称匹配
|
|
if (activeChess.has(chessId) ||
|
|
activeChessNames.has(chessName) ||
|
|
activeChessNames.has(chessName.toLowerCase())) {
|
|
$item.addClass('active');
|
|
}
|
|
});
|
|
|
|
// 根据当前复选框状态更新显示
|
|
const showOnlyActiveSynergies = $('#show-only-active').is(':checked');
|
|
const showOnlyActiveChess = $('#show-only-active-chess').is(':checked');
|
|
|
|
// 更新显示状态
|
|
toggleActiveSynergiesVisibility(showOnlyActiveSynergies);
|
|
toggleActiveChessVisibility(showOnlyActiveChess);
|
|
}
|
|
|
|
/**
|
|
* 切换激活羁绊的可见性
|
|
* @param {boolean} showOnlyActive 是否只显示激活项
|
|
*/
|
|
function toggleActiveSynergiesVisibility(showOnlyActive) {
|
|
if (showOnlyActive) {
|
|
// 隐藏所有羁绊权重项
|
|
$('.synergy-weight-item').hide();
|
|
// 显示已激活羁绊项
|
|
$('.synergy-weight-item.active').show();
|
|
} else {
|
|
// 显示所有羁绊权重项
|
|
$('.synergy-weight-item').show();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 切换激活棋子的可见性
|
|
* @param {boolean} showOnlyActive 是否只显示激活项
|
|
*/
|
|
function toggleActiveChessVisibility(showOnlyActive) {
|
|
if (showOnlyActive) {
|
|
// 隐藏所有棋子权重项
|
|
$('.chess-weight-item').hide();
|
|
// 显示已激活棋子项
|
|
$('.chess-weight-item.active').show();
|
|
} else {
|
|
// 显示所有棋子权重项
|
|
$('.chess-weight-item').show();
|
|
}
|
|
}
|