修改配置的插件
This commit is contained in:
679
Unity/配置表联动查看器/ConfigLinkViewer/generate_config_link_data.py
Normal file
679
Unity/配置表联动查看器/ConfigLinkViewer/generate_config_link_data.py
Normal file
@@ -0,0 +1,679 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
DEFAULT_CONFIG_DIR = PROJECT_ROOT / "Assets" / "Resources" / "Resources_moved" / "config"
|
||||
DEFAULT_OUTPUT = Path(__file__).resolve().parent / "ConfigLinkData.json"
|
||||
DEFAULT_TABLE_INFO = Path(__file__).resolve().parent / "table_info.json"
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="ConfigLinkViewer 配置表联动关系自动生成")
|
||||
parser.add_argument("--config-dir", type=str, default=None,
|
||||
help="JSON 配置导出目录 (默认: Assets/Resources/Resources_moved/config)")
|
||||
parser.add_argument("--output", type=str, default=None,
|
||||
help="输出 ConfigLinkData.json 路径")
|
||||
parser.add_argument("--table-info", type=str, default=None,
|
||||
help="表信息配置 JSON 路径 (默认: table_info.json)")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def load_table_info(filepath):
|
||||
if filepath.exists():
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
entries = data.get("entries", [])
|
||||
return {
|
||||
entry["name"]: (entry.get("displayName", entry["name"]), entry.get("description", ""))
|
||||
for entry in entries
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
TABLE_NAME_TO_CN = {
|
||||
"hero": "英雄",
|
||||
"enemy": "敌人",
|
||||
"equip": "装备",
|
||||
"prop": "道具",
|
||||
"skill": "技能",
|
||||
"buff": "增益效果",
|
||||
"attribute": "属性",
|
||||
"quest": "任务",
|
||||
"player": "玩家",
|
||||
"rune": "符文",
|
||||
"recharge": "充值",
|
||||
"checkpointreward": "关卡奖励",
|
||||
"activity": "活动",
|
||||
"map_act": "地图波次1",
|
||||
"map_act2": "地图波次2",
|
||||
"map_act3": "地图波次3",
|
||||
"map_act4": "地图波次4",
|
||||
"fight_sample": "主线关卡",
|
||||
"fight_arena": "竞技场战斗",
|
||||
"fight_fb1": "副本1",
|
||||
"fight_fb2": "副本2",
|
||||
"fight_fb3": "副本3",
|
||||
"fight_fb4": "副本4",
|
||||
"map": "地图",
|
||||
}
|
||||
|
||||
|
||||
def load_json_file(filepath):
|
||||
try:
|
||||
with open(filepath, "r", encoding="utf-8-sig") as f:
|
||||
return json.load(f)
|
||||
except UnicodeDecodeError:
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
return []
|
||||
|
||||
|
||||
def extract_fields_from_json(filepath):
|
||||
data = load_json_file(filepath)
|
||||
|
||||
if isinstance(data, list) and len(data) > 0:
|
||||
return list(data[0].keys())
|
||||
elif isinstance(data, dict):
|
||||
return list(data.keys())
|
||||
return []
|
||||
|
||||
|
||||
def detect_reward_format(values):
|
||||
if not values:
|
||||
return ""
|
||||
sample = ""
|
||||
for v in values[:5]:
|
||||
if isinstance(v, str):
|
||||
sample = v
|
||||
break
|
||||
elif isinstance(v, list) and len(v) > 0:
|
||||
for item in v[:3]:
|
||||
if isinstance(item, str):
|
||||
sample = item
|
||||
break
|
||||
if sample:
|
||||
break
|
||||
|
||||
if not sample:
|
||||
return ""
|
||||
|
||||
if re.match(r"^item_\d+_\d+$", sample):
|
||||
return "item_id_num"
|
||||
if re.match(r"^hero_\d+$", sample):
|
||||
return "hero_id"
|
||||
if re.match(r"^rune_\d+_\d+$", sample):
|
||||
return "item_id_num"
|
||||
if re.match(r"^equip_\d+_\d+$", sample):
|
||||
return "item_id_num"
|
||||
if re.match(r"^Hero_\d+$", sample):
|
||||
return "item_id_num"
|
||||
if re.match(r"^\d+_\d+_\d+_\d+$", sample):
|
||||
return "id_lv_count_delay"
|
||||
if re.match(r"^\d+_\d+_\d+$", sample):
|
||||
return "id_lv_num"
|
||||
return ""
|
||||
|
||||
|
||||
def detect_consumes_format(values):
|
||||
if not values:
|
||||
return ""
|
||||
sample = ""
|
||||
for v in values[:5]:
|
||||
if isinstance(v, str):
|
||||
sample = v
|
||||
break
|
||||
elif isinstance(v, list) and len(v) > 0:
|
||||
for item in v[:3]:
|
||||
if isinstance(item, str):
|
||||
sample = item
|
||||
break
|
||||
if sample:
|
||||
break
|
||||
|
||||
if not sample:
|
||||
return ""
|
||||
|
||||
if re.match(r"^item_\d+_\d+$", sample):
|
||||
return "item_id_num"
|
||||
return ""
|
||||
|
||||
|
||||
def detect_monster_format(values):
|
||||
if not values:
|
||||
return ""
|
||||
sample = ""
|
||||
for v in values[:5]:
|
||||
if isinstance(v, str):
|
||||
sample = v
|
||||
break
|
||||
elif isinstance(v, list) and len(v) > 0:
|
||||
for item in v[:3]:
|
||||
if isinstance(item, str):
|
||||
sample = item
|
||||
break
|
||||
if sample:
|
||||
break
|
||||
|
||||
if not sample:
|
||||
return ""
|
||||
|
||||
if re.match(r"^\d+_\d+_\d+_\d+(\.\d+)?$", sample):
|
||||
return "id_lv_count_delay"
|
||||
if re.match(r"^\d+_\d+_\d+$", sample):
|
||||
return "id_lv_num"
|
||||
return ""
|
||||
|
||||
|
||||
def get_relation_for_target_id(table_name):
|
||||
mapping = {
|
||||
"herolevel": ("hero", "关联英雄ID"),
|
||||
"herostage": ("hero", "关联英雄ID"),
|
||||
"herolevelinternal": ("enemy", "关联敌人ID"),
|
||||
"enemylevel": ("enemy", "关联敌人ID"),
|
||||
"equiplevel": ("equip", "关联装备ID"),
|
||||
"equipstage": ("equip", "关联装备ID"),
|
||||
"playerlevel": ("player", "关联玩家ID"),
|
||||
"playerstage": ("player", "关联玩家ID"),
|
||||
"runelevel": ("rune", "关联符文ID"),
|
||||
"skilllevel": ("skill", "关联技能ID"),
|
||||
"buff": ("skill", "关联技能ID"),
|
||||
"map": ("map", "关联地图ID"),
|
||||
"map1": ("map", "关联地图ID"),
|
||||
"map2": ("map", "关联地图ID"),
|
||||
"map3": ("map", "关联地图ID"),
|
||||
"map_act": ("map", "关联地图ID"),
|
||||
"map_act2": ("map", "关联地图ID"),
|
||||
"map_act3": ("map", "关联地图ID"),
|
||||
"map_act4": ("map", "关联地图ID"),
|
||||
"test_map_act": ("map", "关联地图ID"),
|
||||
"trainbreak": ("prop", "关联训练突破ID"),
|
||||
"trainlevel": ("prop", "关联训练等级ID"),
|
||||
}
|
||||
if table_name in mapping:
|
||||
return mapping[table_name]
|
||||
return None
|
||||
|
||||
|
||||
def build_relations(table_name, fields, sample_values):
|
||||
relations = []
|
||||
|
||||
reward_fields = {
|
||||
"rewards", "rewards2", "pass_rewards", "activateRewards", "reward",
|
||||
"dailyQuestScoreRewards", "weeklyQuestScoreRewards", "achievementScoreRewards",
|
||||
"heroTujianRewards",
|
||||
}
|
||||
consume_fields = {"consumes", "lostConsumes"}
|
||||
monster_fields = {"monsters", "enemy_ids"}
|
||||
equip_fields = {"equips"}
|
||||
skill_fields = {"skill_ids", "skills"}
|
||||
hero_fields = {"hero_ids"}
|
||||
quest_fields = {"quest"}
|
||||
attr_fields = {"attr_id", "level_attr_id", "stage_attr_id"}
|
||||
shard_fields = {"shardItem"}
|
||||
compose_fields = {"compose"}
|
||||
next_fields = {"next"}
|
||||
recharge_fields = {"recharge_id"}
|
||||
product_fields = {"productId"}
|
||||
out_enemy_fields = {"out_enemy_config"}
|
||||
scene_fight_fields = {"fight_cf_name"}
|
||||
scene_map_fields = {"map_cf_name"}
|
||||
time_limit_fields = {"time_limit_boss"}
|
||||
|
||||
for field in fields:
|
||||
if field == "target_id":
|
||||
result = get_relation_for_target_id(table_name)
|
||||
if result:
|
||||
target, desc = result
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": target,
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": desc,
|
||||
})
|
||||
continue
|
||||
|
||||
if field == "activityId":
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "activity",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "所属活动ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field == "reward_id":
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "checkpointreward",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关卡奖励ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in reward_fields:
|
||||
fmt = detect_reward_format(sample_values.get(field, []))
|
||||
if not fmt:
|
||||
fmt = "item_id_num"
|
||||
|
||||
desc_map = {
|
||||
"rewards": "奖励道具",
|
||||
"rewards2": "付费奖励道具",
|
||||
"pass_rewards": "首通奖励道具",
|
||||
"activateRewards": "激活奖励道具",
|
||||
"reward": "宝箱奖励道具",
|
||||
}
|
||||
desc = desc_map.get(field, f"{field}奖励道具")
|
||||
|
||||
if table_name == "gacha" and field == "rewards":
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "hero",
|
||||
"targetField": "id",
|
||||
"format": "hero_id",
|
||||
"description": "召唤产出英雄(格式: hero_英雄ID)",
|
||||
})
|
||||
else:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "prop",
|
||||
"targetField": "id",
|
||||
"format": fmt,
|
||||
"description": f"{desc}(格式: {fmt})" if fmt else desc,
|
||||
})
|
||||
continue
|
||||
|
||||
if field in consume_fields:
|
||||
fmt = detect_consumes_format(sample_values.get(field, []))
|
||||
desc_map = {
|
||||
"consumes": "消耗道具",
|
||||
"lostConsumes": "失败损失道具",
|
||||
}
|
||||
desc = desc_map.get(field, field)
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "prop",
|
||||
"targetField": "id",
|
||||
"format": fmt if fmt else "item_id_num",
|
||||
"description": f"{desc}(格式: item_id_num)" if fmt else f"{desc}(格式: item_id_num)",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in monster_fields:
|
||||
fmt = detect_monster_format(sample_values.get(field, []))
|
||||
desc_map = {
|
||||
"monsters": "怪物列表",
|
||||
"enemy_ids": "敌人列表",
|
||||
}
|
||||
desc = desc_map.get(field, field)
|
||||
format_desc = f"(格式: {fmt})" if fmt else ""
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "enemy",
|
||||
"targetField": "id",
|
||||
"format": fmt,
|
||||
"description": f"{desc}{format_desc}",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in time_limit_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "enemy",
|
||||
"targetField": "id",
|
||||
"format": "id_lv_num_hp",
|
||||
"description": "限时Boss(格式: 敌人ID_等级_数量_血量百分比)",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in equip_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "equip",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "装备槽位装备ID列表",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in skill_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "skill",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "技能ID列表",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in hero_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "hero",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联英雄ID列表",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in quest_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "quest",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联任务ID列表",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in attr_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "attribute",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联属性ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in shard_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "prop",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "碎片道具ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in compose_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "prop",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "合成材料道具ID列表",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in next_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": table_name,
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "下一个ID(自引用)",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in recharge_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "recharge",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联充值档位ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in product_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "prop",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "商品道具ID",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in out_enemy_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "map_act",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "出怪波次配置表名",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in scene_fight_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "fight_sample",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联战斗配置表名",
|
||||
})
|
||||
continue
|
||||
|
||||
if field in scene_map_fields:
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": "map",
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": "关联地图配置表名",
|
||||
})
|
||||
continue
|
||||
|
||||
if re.match(r"^.+Id$", field) and field != "Id":
|
||||
prefix = field[:-2]
|
||||
for known_table in TABLE_NAME_TO_CN:
|
||||
if known_table.lower() == prefix.lower():
|
||||
relations.append({
|
||||
"field": field,
|
||||
"target": known_table,
|
||||
"targetField": "id",
|
||||
"format": "",
|
||||
"description": f"关联{TABLE_NAME_TO_CN[known_table]}ID",
|
||||
})
|
||||
break
|
||||
|
||||
return relations
|
||||
|
||||
|
||||
SUSPICIOUS_ID_PATTERNS = [
|
||||
(re.compile(r"^.+Id$"), "可能引用其他表的ID字段(驼峰)"),
|
||||
(re.compile(r"^.+_id$"), "可能引用其他表的ID字段(下划线)"),
|
||||
(re.compile(r"^.+_ids$"), "可能引用其他表的ID列表(下划线)"),
|
||||
(re.compile(r"^.+_Ids$"), "可能引用其他表的ID列表(驼峰)"),
|
||||
]
|
||||
|
||||
|
||||
def analyze_gaps(all_tables, table_fields_map):
|
||||
issues = []
|
||||
ai_prompt_parts = []
|
||||
|
||||
tables_not_in_info = [t["name"] for t in all_tables if t["displayName"] == t["name"]]
|
||||
if tables_not_in_info:
|
||||
issues.append({
|
||||
"type": "missing_display_name",
|
||||
"severity": "warning",
|
||||
"title": "以下表缺少中文名和描述",
|
||||
"items": tables_not_in_info,
|
||||
})
|
||||
ai_prompt_parts.append(
|
||||
f"以下表缺少中文名和描述,请补全 displayName 和 description:\n"
|
||||
+ "\n".join(f" - {t}" for t in tables_not_in_info)
|
||||
)
|
||||
|
||||
no_relation_tables = [t["name"] for t in all_tables if len(t["relations"]) == 0]
|
||||
if no_relation_tables:
|
||||
issues.append({
|
||||
"type": "no_relations",
|
||||
"severity": "info",
|
||||
"title": "以下表没有任何引用关系(可能是叶子表或需人工检查)",
|
||||
"items": no_relation_tables,
|
||||
})
|
||||
|
||||
unrecognized_fields = []
|
||||
for table_name, fields in table_fields_map.items():
|
||||
table_entry = next((t for t in all_tables if t["name"] == table_name), None)
|
||||
if not table_entry:
|
||||
continue
|
||||
related_fields = {r["field"] for r in table_entry["relations"]}
|
||||
for field in fields:
|
||||
if field in related_fields:
|
||||
continue
|
||||
for pattern, desc in SUSPICIOUS_ID_PATTERNS:
|
||||
if pattern.match(field):
|
||||
unrecognized_fields.append(f" {table_name}.{field} - {desc}")
|
||||
break
|
||||
|
||||
if unrecognized_fields:
|
||||
issues.append({
|
||||
"type": "unrecognized_fields",
|
||||
"severity": "warning",
|
||||
"title": "以下字段可能是引用关系但脚本未能识别",
|
||||
"items": unrecognized_fields,
|
||||
})
|
||||
ai_prompt_parts.append(
|
||||
"以下字段可能是引用关系但脚本未能识别,请分析并补全 relations:\n"
|
||||
+ "\n".join(unrecognized_fields)
|
||||
)
|
||||
|
||||
tables_with_missing_fields = []
|
||||
for table in all_tables:
|
||||
if table["displayName"] == table["name"] and len(table["relations"]) == 0:
|
||||
fields = table_fields_map.get(table["name"], [])
|
||||
if fields:
|
||||
tables_with_missing_fields.append(
|
||||
f" {table['name']} (字段: {', '.join(fields[:8])}{'...' if len(fields) > 8 else ''})"
|
||||
)
|
||||
|
||||
if tables_with_missing_fields:
|
||||
issues.append({
|
||||
"type": "fully_missing",
|
||||
"severity": "error",
|
||||
"title": "以下表完全未配置(无中文名、无描述、无引用关系)",
|
||||
"items": tables_with_missing_fields,
|
||||
})
|
||||
ai_prompt_parts.append(
|
||||
"以下表完全未配置,请补全 displayName、description 和 relations:\n"
|
||||
+ "\n".join(tables_with_missing_fields)
|
||||
)
|
||||
|
||||
return issues, ai_prompt_parts
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
config_dir = Path(args.config_dir) if args.config_dir else DEFAULT_CONFIG_DIR
|
||||
output_file = Path(args.output) if args.output else DEFAULT_OUTPUT
|
||||
table_info_file = Path(args.table_info) if args.table_info else DEFAULT_TABLE_INFO
|
||||
|
||||
table_info = load_table_info(table_info_file)
|
||||
|
||||
all_tables = []
|
||||
table_fields_map = {}
|
||||
|
||||
json_files = sorted(config_dir.glob("*.json"))
|
||||
|
||||
for filepath in json_files:
|
||||
table_name = filepath.stem
|
||||
fields = extract_fields_from_json(filepath)
|
||||
if not fields:
|
||||
continue
|
||||
|
||||
table_fields_map[table_name] = fields
|
||||
|
||||
sample_values = {}
|
||||
data = load_json_file(filepath)
|
||||
|
||||
if isinstance(data, list) and len(data) > 0:
|
||||
first_row = data[0]
|
||||
for field in fields:
|
||||
if field in first_row:
|
||||
val = first_row[field]
|
||||
if isinstance(val, list):
|
||||
sample_values[field] = val
|
||||
else:
|
||||
sample_values[field] = [val] if val is not None else []
|
||||
|
||||
display_name, description = table_info.get(table_name, (table_name, ""))
|
||||
relations = build_relations(table_name, fields, sample_values)
|
||||
|
||||
all_tables.append({
|
||||
"name": table_name,
|
||||
"displayName": display_name,
|
||||
"description": description,
|
||||
"fileExtension": ".xlsx",
|
||||
"relations": relations,
|
||||
})
|
||||
|
||||
txt_files = sorted(config_dir.glob("*.txt"))
|
||||
for filepath in txt_files:
|
||||
table_name = filepath.stem
|
||||
if table_name in table_info:
|
||||
display_name, description = table_info[table_name]
|
||||
else:
|
||||
display_name, description = table_name, ""
|
||||
all_tables.append({
|
||||
"name": table_name,
|
||||
"displayName": display_name,
|
||||
"description": description,
|
||||
"fileExtension": ".txt",
|
||||
"relations": [],
|
||||
})
|
||||
|
||||
output = {"tables": all_tables}
|
||||
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
json.dump(output, f, ensure_ascii=False, indent=4)
|
||||
|
||||
total_tables = len(all_tables)
|
||||
total_relations = sum(len(t['relations']) for t in all_tables)
|
||||
tables_with_rels = sum(1 for t in all_tables if t['relations'])
|
||||
|
||||
print("=" * 60)
|
||||
print(" ConfigLinkData.json 生成完成")
|
||||
print("=" * 60)
|
||||
print(f" 输出文件: {output_file}")
|
||||
print(f" 总表数: {total_tables}")
|
||||
print(f" 有引用关系的表: {tables_with_rels}")
|
||||
print(f" 总引用关系数: {total_relations}")
|
||||
print()
|
||||
|
||||
issues, ai_prompt_parts = analyze_gaps(all_tables, table_fields_map)
|
||||
|
||||
if not issues:
|
||||
print(" 所有表均已完整配置,无需要补全的内容。")
|
||||
else:
|
||||
print("-" * 60)
|
||||
print(" 查漏补缺报告")
|
||||
print("-" * 60)
|
||||
for issue in issues:
|
||||
severity_icon = {"error": "[!]", "warning": "[*]", "info": "[i]"}.get(issue["severity"], "")
|
||||
print(f"\n {severity_icon} {issue['title']} ({len(issue['items'])}项)")
|
||||
for item in issue["items"]:
|
||||
print(f" {item}")
|
||||
|
||||
if ai_prompt_parts:
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(" AI 补全提示词(可复制发送给 AI)")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("请帮我补全以下配置表联动关系配置:")
|
||||
print()
|
||||
for part in ai_prompt_parts:
|
||||
print(part)
|
||||
print()
|
||||
print("请直接返回修改后的 JSON 配置。")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user