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();
}
}