From 265dd6bfa37b3a8a18bdbc9139c4c97e60e777f1 Mon Sep 17 00:00:00 2001 From: hxuanyu <2252193204@qq.com> Date: Wed, 2 Apr 2025 14:44:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 99 +++++++++++++++++++++++++++++- analysis_summary.txt | Bin 0 -> 20 bytes src/web/app.py | 18 +++++- src/web/static/js/main.js | 113 +++++++++++++++++++++++++++++++++-- src/web/templates/index.html | 13 +++- 5 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 analysis_summary.txt diff --git a/README.md b/README.md index 4cbd3a5..b77bbd2 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ - 交互式命令行界面,便于直接使用 - 支持自定义评分参数 +5. **Web界面模块** + - 基于Flask的Web界面,提供图形化操作体验 + - 可视化显示阵容推荐结果 + - 支持在线调整权重参数与配置 + ## 环境与依赖 - **Python版本:** Python 3.8+ @@ -34,7 +39,12 @@ - requests: 用于获取在线数据 - pandas: 用于数据处理 - pyyaml: 用于配置文件解析 + - numpy: 用于数值计算 + - flask: 用于Web界面 + - flask-cors: 处理跨域请求 + - waitress: 生产环境Web服务器 - pytest: 用于单元测试 + - tqdm: 用于进度显示 ## 项目安装 @@ -61,7 +71,7 @@ python main.py --help 输出结果会显示所有可用的子命令和选项。 -### Web界面(新增) +### Web界面 运行以下命令启动Web界面: @@ -74,6 +84,7 @@ python main.py web - `--host`: 指定服务器主机地址,默认为"0.0.0.0"(允许所有网络接口访问) - `--port`: 指定服务器端口,默认为5000 - `--dev`: 启用开发模式(开启调试功能,自动重载代码) +- `--config`: 指定自定义配置文件路径 例如: ```bash @@ -135,6 +146,32 @@ python main.py scoring python main.py scoring --config path/to/custom_config.yaml ``` +### 配置管理 + +运行以下命令管理权重配置: + +```bash +python main.py config --show +``` + +配置管理提供以下功能: +- 显示当前所有权重配置 +- 设置特定羁绊的权重 +- 设置特定棋子的权重 +- 设置基础权重参数 + +例如: +```bash +# 设置羁绊权重 +python main.py config --set-synergy "超频战士" 1.5 + +# 设置棋子权重 +python main.py config --set-chess "厄加特" 1.8 + +# 设置基础权重参数 +python main.py config --set-base "synergy_level_weight" 1.2 +``` + ### 命令行界面 运行以下命令启动交互式命令行界面: @@ -160,6 +197,7 @@ python main.py cli --population 8 --results 5 --level-weight 1.2 --count-weight - `--level-weight`:羁绊等级权重,默认为1.0 - `--count-weight`:羁绊数量权重,默认为0.5 - `--cost-weight`:棋子费用权重,默认为0.1 +- `--config`:指定自定义配置文件路径 ## 项目结构 @@ -186,7 +224,10 @@ TFT-Strategist/ │ │ ├── __init__.py │ │ ├── api.py # 编程接口 │ │ └── cli.py # 命令行界面 -│ ├── web/ # Web界面模块 (新增) +│ ├── config/ # 配置管理模块 +│ │ ├── __init__.py +│ │ └── weights_config.py # 权重配置管理 +│ ├── web/ # Web界面模块 │ │ ├── __init__.py │ │ ├── app.py # Flask应用 │ │ ├── static/ # 静态资源 @@ -207,6 +248,10 @@ TFT-Strategist/ │ └── test_interface.py # 接口模块测试 ├── main.py # 主程序入口 ├── requirements.txt # 项目依赖 +├── test_direct.py # 直接测试脚本 +├── test_recommendation.py # 阵容推荐测试脚本 +├── generate_weights_config.py # 权重配置生成工具 +├── get_data.py # 数据获取工具 └── README.md # 项目文档 ``` @@ -478,20 +523,68 @@ python main.py cli [参数] 2. 添加必选棋子 3. 获取详细的阵容推荐结果 +## Web界面模块详解 + +Web界面模块提供了图形化的用户交互方式,基于Flask框架实现。 + +### 主要功能 + +1. **阵容推荐设置** + - 可视化选择阵容人口 + - 添加/删除必选羁绊和棋子 + - 自定义权重调整 + +2. **阵容展示** + - 直观显示推荐阵容棋子和羁绊 + - 支持多种排序和筛选方式 + - 详细的阵容分析数据 + +3. **配置管理** + - 在线编辑权重配置 + - 保存和加载配置文件 + - 配置模板管理 + +### 启动方式 + +```bash +python main.py web [--host HOST] [--port PORT] [--dev] [--config CONFIG_PATH] +``` + +## 工具脚本 + +### generate_weights_config.py + +用于生成初始权重配置文件,可根据游戏最新数据自动更新配置。 + +```bash +python generate_weights_config.py [--output OUTPUT_PATH] +``` + +### get_data.py + +用于从官方接口获取最新游戏数据,支持手动更新。 + +```bash +python get_data.py [--force] +``` + ## 开发计划 - [x] 数据提供模块 - [x] 阵容推荐模块 - [x] 阵容评分模块 - [x] 接口模块 +- [x] Web界面模块 +- [x] 配置管理功能 ## 未来展望 -- [ ] 图形用户界面(GUI)开发 +- [ ] 优化算法效率,支持更复杂的推荐策略 - [ ] 基于历史数据的胜率分析 - [ ] 支持装备推荐 - [ ] 多语言支持 - [ ] 基于机器学习的个性化推荐 +- [ ] 移动端应用开发 ## 贡献指南 diff --git a/analysis_summary.txt b/analysis_summary.txt new file mode 100644 index 0000000000000000000000000000000000000000..cde863185bc2c93067a60003ba21b82b3bb4163e GIT binary patch literal 20 bcmezWuX4t_GPa-z={?Z`NsRw_8Mqh#a0>`B literal 0 HcmV?d00001 diff --git a/src/web/app.py b/src/web/app.py index 0238e35..97f7c9f 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -56,11 +56,26 @@ def create_app(config_path: Optional[str] = None): all_synergies = all_jobs + all_races all_chess = data_api.get_all_chess() + # 打印羁绊和棋子数据结构,用于调试 + logger.info(f"羁绊数量: {len(all_synergies)}") + if all_synergies: + sample_synergy = all_synergies[0] + logger.info(f"羁绊示例: {sample_synergy}") + + logger.info(f"棋子数量: {len(all_chess)}") + if all_chess: + sample_chess = all_chess[0] + logger.info(f"棋子示例: {sample_chess}") + # 获取全局配置中的权重信息 base_weights = weights_config.get_base_weights() synergy_weights = weights_config.get_synergy_weights() chess_weights = weights_config.get_chess_weights() + # 打印权重配置,用于调试 + logger.info(f"羁绊权重示例: {list(synergy_weights.items())[:3]}") + logger.info(f"棋子权重示例: {list(chess_weights.items())[:3]}") + return render_template('index.html', synergies=all_synergies, chess=all_chess, @@ -144,9 +159,10 @@ def create_app(config_path: Optional[str] = None): for synergy_id, level in active_synergies.items(): synergy_info = data_api.get_synergy_by_id(synergy_id) if synergy_info: + name = synergy_info.get('name', '') active_synergies_list.append({ 'id': synergy_id, - 'name': synergy_info.get('name', ''), + 'name': name, 'level': level, 'description': synergy_info.get('description', ''), 'image': f"synergy_{synergy_id}.png" # 假设有对应图片 diff --git a/src/web/static/js/main.js b/src/web/static/js/main.js index aa056bb..b7fff7e 100644 --- a/src/web/static/js/main.js +++ b/src/web/static/js/main.js @@ -556,30 +556,123 @@ function updateActiveStatus(results) { // 收集所有被激活的羁绊和棋子 const activeSynergies = new Set(); + const activeSynergyNames = new Set(); // 添加名称集合 const activeChess = new Set(); + const activeChessNames = new Set(); // 添加名称集合 + + console.log('更新激活状态:', results); results.forEach(result => { // 添加激活的羁绊 result.active_synergies.forEach(synergy => { - activeSynergies.add(synergy.id); + console.log('激活羁绊:', synergy); + if (synergy.id) activeSynergies.add(synergy.id); + if (synergy.name) activeSynergyNames.add(synergy.name); // 添加名称 }); // 添加激活的棋子 result.chess_list.forEach(chess => { - activeChess.add(chess.id); + console.log('激活棋子:', chess); + if (chess.id) activeChess.add(chess.id); + if (chess.name) activeChessNames.add(chess.name); // 添加名称 }); }); - // 设置羁绊激活状态 + console.log('所有激活的羁绊ID:', Array.from(activeSynergies)); + console.log('所有激活的羁绊名称:', Array.from(activeSynergyNames)); + console.log('所有激活的棋子ID:', Array.from(activeChess)); + console.log('所有激活的棋子名称:', Array.from(activeChessNames)); + + // 记录是否有成功匹配 + let synergyMatched = false; + let chessMatched = false; + + // 使用多种方式尝试匹配 + + // 1. 通过ID直接匹配 activeSynergies.forEach(synergyId => { - $(`.synergy-weight-item[data-synergy-id="${synergyId}"]`).addClass('active'); + const selector = `.synergy-weight-item[data-synergy-id="${synergyId}"]`; + const $elements = $(selector); + console.log('查找羁绊元素(通过ID):', selector, $elements.length); + if ($elements.length > 0) { + $elements.addClass('active'); + synergyMatched = true; + } }); - // 设置棋子激活状态 activeChess.forEach(chessId => { - $(`.chess-weight-item[data-chess-id="${chessId}"]`).addClass('active'); + const selector = `.chess-weight-item[data-chess-id="${chessId}"]`; + const $elements = $(selector); + console.log('查找棋子元素(通过ID):', selector, $elements.length); + if ($elements.length > 0) { + $elements.addClass('active'); + chessMatched = true; + } }); + // 2. 通过名称匹配 + if (!synergyMatched) { + console.log('ID匹配失败,尝试使用名称匹配羁绊'); + $('.synergy-weight-item').each(function() { + const $item = $(this); + const synergyName = $item.find('label').text().trim(); + const dataName = $item.data('synergy-name'); + + if (activeSynergyNames.has(synergyName) || + (dataName && activeSynergyNames.has(dataName))) { + $item.addClass('active'); + console.log('通过名称匹配到羁绊:', synergyName); + synergyMatched = true; + } + }); + } + + if (!chessMatched) { + console.log('ID匹配失败,尝试使用名称匹配棋子'); + $('.chess-weight-item').each(function() { + const $item = $(this); + const chessName = $item.find('label').text().trim(); + const dataName = $item.data('chess-name'); + + if (activeChessNames.has(chessName) || + (dataName && activeChessNames.has(dataName))) { + $item.addClass('active'); + console.log('通过名称匹配到棋子:', chessName); + chessMatched = true; + } + }); + } + + // 3. 最后的尝试:直接遍历匹配名称(不区分大小写) + if (!synergyMatched) { + console.log('所有正常匹配方式失败,尝试不区分大小写的名称匹配'); + const lowerSynergyNames = Array.from(activeSynergyNames).map(name => name.toLowerCase()); + + $('.synergy-weight-item').each(function() { + const $item = $(this); + const synergyName = $item.find('label').text().trim().toLowerCase(); + + if (lowerSynergyNames.includes(synergyName)) { + $item.addClass('active'); + console.log('通过不区分大小写名称匹配到羁绊:', synergyName); + } + }); + } + + if (!chessMatched) { + const lowerChessNames = Array.from(activeChessNames).map(name => name.toLowerCase()); + + $('.chess-weight-item').each(function() { + const $item = $(this); + const chessName = $item.find('label').text().trim().toLowerCase(); + + if (lowerChessNames.includes(chessName)) { + $item.addClass('active'); + console.log('通过不区分大小写名称匹配到棋子:', chessName); + } + }); + } + // 如果勾选了"仅显示已激活",则更新显示状态 if ($('#show-only-active').is(':checked')) { $('.synergy-weight-item').hide(); @@ -590,4 +683,12 @@ function updateActiveStatus(results) { $('.chess-weight-item').hide(); $('.chess-weight-item.active').show(); } + + // 添加高亮样式,以便更好地区分激活项 + $('.synergy-weight-item.active').css('background-color', '#e0e7ff'); + $('.chess-weight-item.active').css('background-color', '#e0e7ff'); + + // 输出激活项目数量统计 + console.log('成功激活的羁绊数量:', $('.synergy-weight-item.active').length); + console.log('成功激活的棋子数量:', $('.chess-weight-item.active').length); } \ No newline at end of file diff --git a/src/web/templates/index.html b/src/web/templates/index.html index 335a9d3..99a39fc 100644 --- a/src/web/templates/index.html +++ b/src/web/templates/index.html @@ -44,6 +44,15 @@ .drawer-backdrop.open { display: block; } + + /* 添加激活状态样式 */ + .synergy-weight-item.active, + .chess-weight-item.active { + background-color: #e0e7ff; + border-left: 3px solid #4f46e5; + padding-left: 5px; + border-radius: 4px; + }
@@ -109,7 +118,7 @@