mirror of
https://github.com/wess09/AzurLaneAutoScript.git
synced 2026-05-14 06:58:22 +08:00
Compare commits
2 Commits
c3d8829548
...
147ba2da91
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
147ba2da91 | ||
|
|
4e8741d1a2 |
@ -321,11 +321,96 @@ async def api_notify_stream(request):
|
||||
)
|
||||
|
||||
|
||||
async def api_import_legacy_upload(request):
|
||||
"""
|
||||
接收浏览器上传的旧 ALAS 文件夹内容,写入本项目对应位置。
|
||||
前端使用 webkitdirectory 选择文件夹后上传。
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
form = await request.form()
|
||||
current_root = Path(os.getcwd()).resolve()
|
||||
|
||||
result = {
|
||||
"config": 0,
|
||||
"db": 0,
|
||||
"cl1": 0,
|
||||
"azurstat": 0,
|
||||
"skipped": 0,
|
||||
"errors": 0,
|
||||
}
|
||||
|
||||
for file in form.getlist('file'):
|
||||
if not hasattr(file, 'filename') or not file.filename:
|
||||
continue
|
||||
|
||||
relative_path = file.filename.replace("\\", "/")
|
||||
filename = Path(relative_path).name
|
||||
|
||||
# 提取根级相对路径:跳过前导 / 和可能的文件夹名前缀
|
||||
parts = relative_path.split("/")
|
||||
# parts[0]='' (前导 /), parts[1]可能是文件夹名或 config/log
|
||||
start_idx = 1
|
||||
if len(parts) >= 3 and parts[1] not in ("config", "log"):
|
||||
start_idx = 2 # parts[1] 是文件夹名,跳过
|
||||
sub_path = "/".join(parts[start_idx:])
|
||||
|
||||
# 判断是否需要处理该文件
|
||||
rel_target = None
|
||||
|
||||
# 只匹配 根目录/config/ 下的 .json/.db(排除 template*)
|
||||
if sub_path.startswith("config/"):
|
||||
ext = Path(filename).suffix.lower()
|
||||
if ext in (".json", ".db") and not filename.lower().startswith("template"):
|
||||
rel_target = sub_path
|
||||
|
||||
# 只匹配 根目录/log/cl1/ 下的所有文件
|
||||
if sub_path.startswith("log/cl1/"):
|
||||
rel_target = sub_path
|
||||
|
||||
# 只匹配 根目录/log/azurstat_meowofficer_farming.csv
|
||||
if sub_path == "log/azurstat_meowofficer_farming.csv":
|
||||
rel_target = sub_path
|
||||
|
||||
if rel_target is None:
|
||||
result["skipped"] += 1
|
||||
continue
|
||||
|
||||
target = current_root / rel_target
|
||||
|
||||
try:
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
content = await file.read()
|
||||
target.write_bytes(content)
|
||||
|
||||
if rel_target.startswith("config/"):
|
||||
ext = Path(filename).suffix.lower()
|
||||
if ext == ".json":
|
||||
result["config"] += 1
|
||||
else:
|
||||
result["db"] += 1
|
||||
elif rel_target.startswith("log/cl1/"):
|
||||
result["cl1"] += 1
|
||||
elif "azurstat" in rel_target:
|
||||
result["azurstat"] += 1
|
||||
except Exception as e:
|
||||
logger.error(f"写入失败 {target}: {e}")
|
||||
result["errors"] += 1
|
||||
|
||||
logger.info(f"导入完成: {result}")
|
||||
return JSONResponse({"success": True, "data": result})
|
||||
except Exception as e:
|
||||
logger.error(f"导入API错误: {e}")
|
||||
return JSONResponse({"success": False, "error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
api_routes = [
|
||||
Route("/api/cl1_stats", api_cl1_stats),
|
||||
Route("/api/ap_timeline", api_ap_timeline),
|
||||
Route("/api/notify", api_notify, methods=["POST"]),
|
||||
Route("/api/notify_stream", api_notify_stream),
|
||||
Route("/api/import_legacy_upload", api_import_legacy_upload, methods=["POST"]),
|
||||
Route("/obs", serve_obs_overlay),
|
||||
WebSocketRoute("/ws/live_screenshot", ws_live_screenshot),
|
||||
]
|
||||
|
||||
@ -2563,6 +2563,12 @@ class AlasGUI(Frame):
|
||||
color="menu",
|
||||
).style(f"--menu-HomePage--")
|
||||
|
||||
put_button(
|
||||
label="导入旧数据",
|
||||
onclick=self.ui_import_legacy,
|
||||
color="menu",
|
||||
).style(f"--menu-Import--")
|
||||
|
||||
# put_button(
|
||||
# label=t("Gui.MenuDevelop.Translate"),
|
||||
# onclick=self.dev_translate,
|
||||
@ -3050,6 +3056,112 @@ class AlasGUI(Frame):
|
||||
|
||||
put()
|
||||
|
||||
@use_scope("content", clear=True)
|
||||
def ui_import_legacy(self) -> None:
|
||||
"""Develop 菜单:导入旧 AzurPilot 数据"""
|
||||
self.init_menu(name="Import")
|
||||
self.set_title("导入旧数据")
|
||||
from pywebio.output import put_markdown, put_html, put_buttons, put_scope
|
||||
import json
|
||||
|
||||
# 检查上一轮导入的结果(通过 sessionStorage 跨刷新传递)
|
||||
try:
|
||||
raw = eval_js("(function(){var r=sessionStorage.getItem('import_msg');if(r){sessionStorage.removeItem('import_msg');return r;}return null;})()")
|
||||
if raw:
|
||||
info = json.loads(raw)
|
||||
if info.get("ok"):
|
||||
d = info["data"]
|
||||
parts = []
|
||||
toast("导入成功", color="success", duration=10)
|
||||
else:
|
||||
toast("导入失败:" + info.get("error", "未知错误"), color="error", duration=10)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def import_legacy_upload():
|
||||
toast("请在弹出的窗口中选择旧 AzurPilot/ALAS 根目录", color="info", duration=0)
|
||||
run_js("""
|
||||
(function(){
|
||||
var input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.setAttribute('webkitdirectory', '');
|
||||
input.setAttribute('multiple', '');
|
||||
input.style.display = 'none';
|
||||
|
||||
input.addEventListener('change', async function(e) {
|
||||
var files = e.target.files;
|
||||
document.body.removeChild(input);
|
||||
if (!files || files.length === 0) return;
|
||||
|
||||
var formData = new FormData();
|
||||
var matched = 0, skipped = 0, total = files.length;
|
||||
|
||||
for (var i = 0; i < total; i++) {
|
||||
var file = files[i];
|
||||
var relPath = '/' + file.webkitRelativePath.replace(/\\\\/g, '/');
|
||||
var name = relPath.split('/').pop().toLowerCase();
|
||||
|
||||
var pp = relPath.split('/');
|
||||
var si = 1;
|
||||
if (pp.length >= 3 && pp[1] !== 'config' && pp[1] !== 'log') si = 2;
|
||||
var subPath = pp.slice(si).join('/');
|
||||
|
||||
var ok = false;
|
||||
if (subPath.startsWith('config/')) {
|
||||
if ((name.endsWith('.json') || name.endsWith('.db')) && !name.startsWith('template')) ok = true;
|
||||
} else if (subPath.startsWith('log/cl1/')) {
|
||||
ok = true;
|
||||
} else if (subPath === 'log/azurstat_meowofficer_farming.csv') {
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok) { skipped++; continue; }
|
||||
matched++;
|
||||
formData.append('file', file, relPath);
|
||||
}
|
||||
|
||||
if (matched === 0) {
|
||||
sessionStorage.setItem('import_msg', JSON.stringify({ok:false, error:'所选文件夹中没有找到 config/ 或 log/cl1/ 下的匹配文件'}));
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var resp = await fetch('/api/import_legacy_upload', { method: 'POST', body: formData });
|
||||
var result = await resp.json();
|
||||
if (result.success) {
|
||||
result.data.total = total;
|
||||
sessionStorage.setItem('import_msg', JSON.stringify({ok:true, data:result.data, total:total}));
|
||||
} else {
|
||||
sessionStorage.setItem('import_msg', JSON.stringify({ok:false, error:result.error || '未知错误'}));
|
||||
}
|
||||
} catch (err) {
|
||||
sessionStorage.setItem('import_msg', JSON.stringify({ok:false, error:'上传请求失败: ' + err.message}));
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
})();
|
||||
""")
|
||||
|
||||
put_html(build_title_block("导入旧 AzurPilot/ALAS 数据", margin_top=12, margin_bottom=8))
|
||||
put_markdown(
|
||||
"选择旧 AzurPilot/ALAS 根目录后,自动将以下数据导入到当前项目:\n\n"
|
||||
"**配置 数据文件等**\n\n"
|
||||
"> 同名文件将被覆盖,建议先备份当前项目。"
|
||||
)
|
||||
|
||||
put_scope("import_btn")
|
||||
with use_scope("import_btn"):
|
||||
put_buttons(
|
||||
[
|
||||
{"label": "选择旧 AzurPilot/ALAS 文件夹", "value": "upload", "color": "primary"},
|
||||
],
|
||||
onclick=[import_legacy_upload],
|
||||
)
|
||||
|
||||
def show(self) -> None:
|
||||
self._show()
|
||||
self.load_home = True
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user