From 79bd57b79d7151c2c7f12e0ae0034391b98c3402 Mon Sep 17 00:00:00 2001 From: hxuanyu <2252193204@qq.com> Date: Wed, 2 Apr 2025 15:48:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=9D=83=E9=87=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=9B=B4=E6=96=B0=E5=92=8C=E8=AF=A6=E7=BB=86=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=8E=B7=E5=8F=96API=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=A3=8B=E5=AD=90=E5=92=8C=E7=BE=81=E7=BB=8A=E7=9A=84=E8=AF=A6?= =?UTF-8?q?=E7=BB=86=E4=BF=A1=E6=81=AF=E5=B1=95=E7=A4=BA=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=E5=92=8C=E4=BB=A3=E7=A0=81=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/web/app.py | 129 ++++++- src/web/static/css/style.css | 121 +++++++ src/web/static/js/main.js | 631 ++++++++++++++++++++++++++++++++++- 3 files changed, 857 insertions(+), 24 deletions(-) diff --git a/src/web/app.py b/src/web/app.py index 97f7c9f..e6125f7 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -199,15 +199,120 @@ def create_app(config_path: Optional[str] = None): @app.route('/api/weights', methods=['POST']) def update_weights(): - """更新权重配置API - 已弃用,仅保留API兼容性""" + """更新权重配置API""" try: - return jsonify({ - 'status': 'success', - 'message': '权重配置已更新(本地存储模式)' - }) - + data = request.json + weights_config.update_config_data(data) + return jsonify({'status': 'success'}) except Exception as e: - logger.exception("更新权重配置时发生错误") + logger.exception("更新权重配置失败") + return jsonify({ + 'status': 'error', + 'message': str(e) + }), 500 + + @app.route('/api/details', methods=['GET']) + def get_details(): + """获取棋子或羁绊的详细信息API""" + try: + item_type = request.args.get('type') # 'chess' 或 'synergy' + item_id = request.args.get('id') + + if not item_type or not item_id: + return jsonify({ + 'status': 'error', + 'message': '缺少必要参数' + }), 400 + + # 获取详细信息 + if item_type == 'chess': + # 获取棋子详情 + chess = data_api.get_chess_by_id(item_id) + if not chess: + return jsonify({ + 'status': 'error', + 'message': f'未找到ID为{item_id}的棋子' + }), 404 + + # 获取棋子的所有羁绊 + synergies = data_api.get_synergies_of_chess(item_id) + + # 构建详细信息 + details = { + 'id': chess.get('chessId'), + 'name': chess.get('displayName', ''), + 'cost': chess.get('price', 0), + 'skill_name': chess.get('skillName', ''), + 'skill_description': chess.get('skillDescription', ''), + 'skill_introduce': chess.get('skillIntroduce', ''), + # 添加更多棋子属性 + 'health': chess.get('health', ''), + 'attack_damage': chess.get('attackDamage', ''), + 'attack_speed': chess.get('attackSpeed', ''), + 'attack_range': chess.get('range', ''), + 'armor': chess.get('armor', ''), + 'magic_resist': chess.get('magicResist', ''), + 'synergies': [{ + 'id': synergy.get('jobId') or synergy.get('raceId'), + 'name': synergy.get('name', ''), + 'type': 'job' if 'jobId' in synergy else 'race' + } for synergy in synergies] + } + + return jsonify({ + 'status': 'success', + 'type': 'chess', + 'details': details + }) + + elif item_type == 'synergy': + # 获取羁绊详情 + synergy = data_api.get_synergy_by_id(item_id) + if not synergy: + return jsonify({ + 'status': 'error', + 'message': f'未找到ID为{item_id}的羁绊' + }), 404 + + # 获取羁绊的所有等级信息 + synergy_levels = synergy.get('level', {}) + + # 获取该羁绊的所有棋子 + related_chess = data_api.get_chess_by_synergy(item_id) + + # 构建详细信息 + details = { + 'id': synergy.get('jobId') or synergy.get('raceId'), + 'name': synergy.get('name', ''), + 'description': synergy.get('description', ''), + 'introduce': synergy.get('introduce', ''), + 'type': 'job' if 'jobId' in synergy else 'race', + 'levels': [{ + 'level': level, + 'effect': effect + } for level, effect in synergy_levels.items()], + # 添加相关棋子 + 'related_chess': [{ + 'id': chess.get('chessId'), + 'name': chess.get('displayName', ''), + 'cost': chess.get('price', 0) + } for chess in related_chess] + } + + return jsonify({ + 'status': 'success', + 'type': 'synergy', + 'details': details + }) + + else: + return jsonify({ + 'status': 'error', + 'message': f'不支持的类型: {item_type}' + }), 400 + + except Exception as e: + logger.exception("获取详细信息失败") return jsonify({ 'status': 'error', 'message': str(e) @@ -220,16 +325,16 @@ def create_temp_config(base_config: Dict[str, Any], synergy_weights: Dict[str, float], chess_weights: Dict[str, float]) -> Dict[str, Any]: """ - 创建临时配置对象,不修改原始配置 + 创建临时权重配置 Args: base_config: 基础配置 - base_weights: 用户自定义的基础权重 - synergy_weights: 用户自定义的羁绊权重 - chess_weights: 用户自定义的棋子权重 + base_weights: 基础权重 + synergy_weights: 羁绊权重 + chess_weights: 棋子权重 Returns: - Dict[str, Any]: 临时配置对象 + Dict[str, Any]: 临时配置 """ # 深拷贝基础配置,避免修改原始配置 temp_config = copy.deepcopy(base_config) diff --git a/src/web/static/css/style.css b/src/web/static/css/style.css index 8d9b218..7deef8e 100644 --- a/src/web/static/css/style.css +++ b/src/web/static/css/style.css @@ -40,6 +40,127 @@ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); } +/* 悬停提示样式 */ +.chess-item, .synergy-item { + cursor: pointer; + position: relative; +} + +/* 活跃状态样式 */ +.chess-item.tooltip-active, .synergy-item.tooltip-active { + box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.4); + z-index: 5; +} + +/* 增强提示框样式 */ +#tft-tooltip { + transition: opacity 0.2s, transform 0.2s; + max-height: 80vh; + overflow-y: auto; + border: 1px solid rgba(99, 102, 241, 0.3); + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.2); + transform-origin: top left; + animation: tooltipFadeIn 0.2s ease-out; +} + +/* 提示框中的费用标识 */ +#tft-tooltip .cost-1 { border-left: 3px solid #94a3b8; } /* 1费 - 灰色 */ +#tft-tooltip .cost-2 { border-left: 3px solid #65a30d; } /* 2费 - 绿色 */ +#tft-tooltip .cost-3 { border-left: 3px solid #2563eb; } /* 3费 - 蓝色 */ +#tft-tooltip .cost-4 { border-left: 3px solid #7e22ce; } /* 4费 - 紫色 */ +#tft-tooltip .cost-5 { border-left: 3px solid #f59e0b; } /* 5费 - 金色 */ + +/* 提示框内交互元素样式 */ +.chess-item-mini, .synergy-item-mini { + cursor: pointer; + transition: all 0.2s; + position: relative; +} + +.chess-item-mini:hover, .synergy-item-mini:hover { + background-color: rgba(255, 255, 255, 0.1); + transform: translateY(-1px); +} + +.chess-item-mini:hover::after, .synergy-item-mini:hover::after { + content: '查看详情'; + position: absolute; + top: -18px; + right: 5px; + background: rgba(79, 70, 229, 0.9); + color: white; + font-size: 8px; + padding: 2px 4px; + border-radius: 2px; +} + +@keyframes tooltipFadeIn { + from { + opacity: 0; + transform: translateY(-5px) scale(0.98); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +/* 提示框中的各部分样式 */ +#tft-tooltip .tooltip-content { + word-break: break-word; +} + +/* 提示框返回按钮 */ +.tooltip-back-button { + opacity: 0.7; + transition: all 0.2s ease; + z-index: 15; +} + +.tooltip-back-button:hover { + opacity: 1; + transform: scale(1.1); + background-color: rgba(79, 70, 229, 0.9); +} + +/* 特殊介绍文本样式 */ +#tft-tooltip .skill-introduce, +#tft-tooltip .synergy-introduce { + border-left: 3px solid rgba(79, 70, 229, 0.7); + background-color: rgba(79, 70, 229, 0.1); + padding-left: 8px; +} + +#tft-tooltip .loading-spinner { + opacity: 0.8; +} + +/* 优化悬停标识 */ +.chess-item::after, .synergy-item::after { + content: '?'; + position: absolute; + top: -5px; + right: -5px; + width: 16px; + height: 16px; + background: rgba(79, 70, 229, 0.9); + color: white; + border-radius: 50%; + font-size: 10px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s, transform 0.2s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + z-index: 10; +} + +.chess-item:hover::after, .synergy-item:hover::after { + opacity: 1; + transform: scale(1.1); +} + /* 羁绊标签样式 */ .synergy-tag { background-color: #e0e7ff; diff --git a/src/web/static/js/main.js b/src/web/static/js/main.js index aed0d17..8434f62 100644 --- a/src/web/static/js/main.js +++ b/src/web/static/js/main.js @@ -40,7 +40,7 @@ $(document).ready(function() { // 添加到列表 const synergyItem = $(` -