mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 16:00:43 +00:00
琚帶绔?- 淇 MTU 闂锛氬す MSS + 璺緞 MTU 鎺㈡祴锛堝叕缃戝彲鐢ㄧ巼 48% -> 100%锛?- 澶嶇敤 HTTP 杩炴帴锛堝厤鎺夋瘡娆℃柊寤?TLS 鐨?30% 鎻℃墜澶辫触锛?- 姣忓垎閽熷洖澶存壘灞€鍩熺綉锛岃嚜鍔ㄥ垏鍥炲揩 400 鍊嶇殑璺緞 - 鐢婚潰蹇冭烦甯э細闈欐鏃剁渷娴侀噺锛屽鎴风浠嶇煡閬撴祦鏄椿鐨?- 閿佸睆鏃剁粰鍑哄彲鎿嶄綔鐨勬彁绀? 鎵嬭〃绔?- 鍐呯疆 GTS Root R4 / GlobalSign Root CA锛屼慨 SSLHandshakeException - 杩炴帴閿欒缈昏瘧鎴愪汉璇濓紙璇佷功/鏃堕棿/瑙f瀽/瓒呮椂鍒嗗埆鎻愮ず锛?- 缁忎腑杞繛涓婂悗鐢ㄦ湇鍔″櫒鎶ョ殑鍦板潃鍒锋柊宸查厤瀵硅褰?- 鏂板灞€鍩熺綉杩炴帴椤甸潰銆佹湇鍔″櫒寤惰繜妫€娴? 鏈嶅姟鍣ㄧ - 鏀寔 chunked 璇锋眰浣擄紙淇瘡 16 绉掍竴娆$殑杩炴帴閿欎贡涓庡ぇ闈㈢Н 502锛?- 缃戠粶璋冧紭鑴氭湰 net-tune.sh锛堝紑鏈鸿嚜鍔ㄥ簲鐢級 - 绠$悊椤碉細鎵归噺鍒犻櫎銆佺綉缁滀綋妫€銆佷笅杞藉尯 - 闅ч亾鏀?HTTP/2 + 鍙岃繛鎺? 鏂囨。 - 璁稿彲鍗忚 / 瀹夎鍓嶅繀璇?/ 瀹夎鍚庨』鐭ワ紙浣滆€咃細灏忛害瀛愶級
203 lines
7.1 KiB
Python
203 lines
7.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""中转管理端加"批量删除"(重写版)。
|
||
|
||
上一版的坑:
|
||
1. JS 里的换行我写成 \\n,但 relay.py 里是 f-string,
|
||
\\n 会被还原成真换行 -> JS 字符串跨行 -> 语法错误。
|
||
正确写法是补丁里用 \\\\n,这样 relay.py 源码里是 \\n,
|
||
f-string 渲染后 JS 拿到的是 反斜杠+n 两个字符。
|
||
2. rows.append 的锚点带太多上下文,容易被空格差异搞挂。
|
||
换成最小锚点。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import ast
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
RELAY = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\relay" r"\relay.py")
|
||
|
||
# ---------------------------------------------------------------- 后端
|
||
|
||
BACKEND_ANCHOR = ''' if path in ("/v1/admin/delete", "/v1/admin/delete_all"):'''
|
||
|
||
BACKEND_NEW = ''' if path == "/v1/admin/delete_many":
|
||
# 批量删除:勾几台删几台。
|
||
# 和"删除全部"的区别:不动没勾的,也不清孤儿绑定。
|
||
body = self._json_body()
|
||
wanted = body.get("deviceIds") or []
|
||
if not isinstance(wanted, list):
|
||
self._json(400, {"ok": False, "error": "deviceIds 要是数组"})
|
||
return
|
||
wanted = [str(item).strip() for item in wanted
|
||
if str(item).strip()]
|
||
if not wanted:
|
||
self._json(400, {"ok": False, "error": "没有勾选任何设备"})
|
||
return
|
||
results = [RELAY.delete_device(device_id=item)
|
||
for item in wanted]
|
||
done = [r for r in results if r.get("ok")]
|
||
failed = [r for r in results if not r.get("ok")]
|
||
log(f"管理操作:批量删除 {len(done)}/{len(wanted)} 台设备")
|
||
self._json(200, {
|
||
"ok": True,
|
||
"requested": len(wanted),
|
||
"deleted": len(done),
|
||
"failed": len(failed),
|
||
"devices": done,
|
||
"errors": failed[:10],
|
||
})
|
||
return
|
||
|
||
''' + BACKEND_ANCHOR
|
||
|
||
# ---------------------------------------------------------------- 行里加复选框(最小锚点)
|
||
|
||
ROW_ANCHOR = ''' rows.append(
|
||
"<tr>"
|
||
'''
|
||
|
||
ROW_NEW = ''' rows.append(
|
||
"<tr>"
|
||
# 批量删除用的复选框。value 放 deviceId。
|
||
"<td class=pickcell>"
|
||
f'<input type=checkbox class=pick value="{_esc(device["deviceId"])}">'
|
||
"</td>"
|
||
'''
|
||
|
||
# ---------------------------------------------------------------- 表头全选
|
||
|
||
HEADER_ANCHOR = "<table><tr><th>设备</th>"
|
||
HEADER_NEW = ("<table><tr><th class=pickcell>"
|
||
'<input type=checkbox id=pickAll title="全选"></th>'
|
||
"<th>设备</th>")
|
||
|
||
# ---------------------------------------------------------------- 顶部按钮
|
||
|
||
BAR_ANCHOR = " <button class=del id=delAll>删除全部设备</button>"
|
||
BAR_NEW = (" <button class=del id=delPicked>删除选中</button>\n"
|
||
" <button class=del id=delAll>删除全部设备</button>")
|
||
|
||
# ---------------------------------------------------------------- 样式
|
||
|
||
CSS_ANCHOR = (" button.del:hover{{background:#5a1c22;border-color:#a33;"
|
||
"color:#ffa198}}")
|
||
|
||
CSS_NEW = CSS_ANCHOR + """
|
||
button.del:disabled{{opacity:.45;cursor:not-allowed}}
|
||
.pickcell{{width:34px;text-align:center;padding-left:10px;padding-right:0}}
|
||
input[type=checkbox]{{width:15px;height:15px;cursor:pointer;accent-color:#2f81f7}}
|
||
tr.picked td{{background:#1f2733}}"""
|
||
|
||
# ---------------------------------------------------------------- 前端 JS
|
||
# 注意:这里写 \\\\n,落到 relay.py 里是 \\n,
|
||
# 再经 f-string 渲染,JS 拿到的才是 反斜杠+n。
|
||
|
||
JS_ANCHOR = '''document.querySelectorAll('button.del[data-device]').forEach(b => {{
|
||
b.onclick = () => del(b.dataset.device, b.dataset.name, b.dataset.code);
|
||
}});'''
|
||
|
||
JS_NEW = JS_ANCHOR + """
|
||
|
||
// ---------------- 批量删除 ----------------
|
||
const picks = () => Array.from(document.querySelectorAll('input.pick'));
|
||
const picked = () => picks().filter(c => c.checked).map(c => c.value);
|
||
|
||
function refreshPickState() {{
|
||
const chosen = picked().length;
|
||
const btn = document.getElementById('delPicked');
|
||
if (btn) {{
|
||
btn.disabled = chosen === 0;
|
||
btn.textContent = chosen ? ('删除选中 (' + chosen + ')') : '删除选中';
|
||
}}
|
||
picks().forEach(c => {{
|
||
const tr = c.closest('tr');
|
||
if (tr) tr.classList.toggle('picked', c.checked);
|
||
}});
|
||
const all = document.getElementById('pickAll');
|
||
if (all) {{
|
||
const total = picks().length;
|
||
all.checked = total > 0 && chosen === total;
|
||
all.indeterminate = chosen > 0 && chosen < total;
|
||
}}
|
||
}}
|
||
|
||
picks().forEach(c => c.addEventListener('change', refreshPickState));
|
||
const pickAll = document.getElementById('pickAll');
|
||
if (pickAll) pickAll.addEventListener('change', () => {{
|
||
picks().forEach(c => {{ c.checked = pickAll.checked; }});
|
||
refreshPickState();
|
||
}});
|
||
refreshPickState();
|
||
|
||
const delPicked = document.getElementById('delPicked');
|
||
if (delPicked) delPicked.onclick = async () => {{
|
||
const ids = picked();
|
||
if (!ids.length) return;
|
||
if (!confirm('删除选中的 ' + ids.length + ' 台设备?\\\\n\\\\n'
|
||
+ '会断开它们现在的手表连接,并清掉它们占的配对码。'))
|
||
return;
|
||
delPicked.disabled = true;
|
||
try {{
|
||
const r = await fetch('/v1/admin/delete_many', {{
|
||
method: 'POST',
|
||
headers: {{'Content-Type': 'application/json'}},
|
||
body: JSON.stringify({{deviceIds: ids}})
|
||
}});
|
||
const j = await r.json();
|
||
if (j.ok) {{
|
||
alert('已删除 ' + j.deleted + ' 台设备'
|
||
+ (j.failed ? (',' + j.failed + ' 台失败') : ''));
|
||
location.reload();
|
||
}} else {{
|
||
alert('删除失败:' + (j.error || '未知错误'));
|
||
delPicked.disabled = false;
|
||
}}
|
||
}} catch (e) {{
|
||
alert('请求出错:' + e);
|
||
delPicked.disabled = false;
|
||
}}
|
||
}};"""
|
||
|
||
PAIRS = [
|
||
(BACKEND_ANCHOR, BACKEND_NEW),
|
||
(ROW_ANCHOR, ROW_NEW),
|
||
(HEADER_ANCHOR, HEADER_NEW),
|
||
(BAR_ANCHOR, BAR_NEW),
|
||
(CSS_ANCHOR, CSS_NEW),
|
||
(JS_ANCHOR, JS_NEW),
|
||
]
|
||
|
||
|
||
def main() -> int:
|
||
text = RELAY.read_text(encoding="utf-8")
|
||
if "delete_many" in text:
|
||
print(" 已经加过了")
|
||
return 0
|
||
|
||
ok = True
|
||
for old, new in PAIRS:
|
||
if old not in text:
|
||
print(f" [失败] 锚点没找到 -> {old.strip()[:70]!r}")
|
||
ok = False
|
||
continue
|
||
if text.count(old) != 1:
|
||
print(f" [警告] 锚点出现 {text.count(old)} 次,只替换第一处")
|
||
text = text.replace(old, new, 1)
|
||
|
||
RELAY.write_text(text, encoding="utf-8", newline="\n")
|
||
if ok:
|
||
print(" 已加:/v1/admin/delete_many + 复选框 + 全选 + 删除选中")
|
||
|
||
try:
|
||
ast.parse(RELAY.read_text(encoding="utf-8"))
|
||
print(" relay.py 语法 OK")
|
||
except SyntaxError as exc:
|
||
print(f" relay.py 语法错误: 行 {exc.lineno}: {exc.msg}")
|
||
ok = False
|
||
return 0 if ok else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|