{{recipient_name}},您好:
+您的验证码是:
+{{verification_code}}
+验证码将在 {{expires_in_minutes}} 分钟后失效。
+如果不是您本人操作,请忽略此邮件。
diff --git a/apply_default_server.py b/apply_default_server.py new file mode 100644 index 0000000..ef77d92 --- /dev/null +++ b/apply_default_server.py @@ -0,0 +1,41 @@ +with open("frontend/src/views/Dashboard/DomainForm.js", "r", encoding="utf-8") as f: + text = f.read() + +old_code = """ function openCreate() { + if (saving.value) return; + version += 1; + editingId.value = ""; + targetID = ""; + form.value = emptyForm();""" + +new_code = """ function openCreate() { + if (saving.value) return; + version += 1; + editingId.value = ""; + targetID = ""; + form.value = emptyForm(); + if (servers.value && servers.value.length > 0) { + form.value.server_ids = [servers.value[0].id]; + }""" + +text = text.replace(old_code, new_code) +with open("frontend/src/views/Dashboard/DomainForm.js", "w", encoding="utf-8") as f: + f.write(text) + +with open("frontend/src/views/Dashboard/DomainForm.test.js", "r", encoding="utf-8") as f: + test_text = f.read() + +# 替换断言 +test_text = test_text.replace( + ' state.openCreate();\n assert.equal(state.editingId.value, "");\n assert.deepEqual(state.form.value.server_ids, []);', + ' state.openCreate();\n assert.equal(state.editingId.value, "");\n assert.deepEqual(state.form.value.server_ids, [firstServer.id]);' +) +test_text = test_text.replace( + ' state.openCreate();\n assert.equal(state.form.value.name, "");\n assert.deepEqual(state.form.value.server_ids, []);', + ' state.openCreate();\n assert.equal(state.form.value.name, "");\n assert.deepEqual(state.form.value.server_ids, [firstServer.id]);' +) + +with open("frontend/src/views/Dashboard/DomainForm.test.js", "w", encoding="utf-8") as f: + f.write(test_text) + +print("Updated DomainForm.js and DomainForm.test.js") diff --git a/check_mail_inputs.py b/check_mail_inputs.py new file mode 100644 index 0000000..2f80cea --- /dev/null +++ b/check_mail_inputs.py @@ -0,0 +1,28 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +script = """ +(() => { + const inputs = Array.from(document.querySelectorAll('.mail-channel input, .mail-channel select')); + return inputs.map(el => ({ + tag: el.tagName, + type: el.type, + placeholder: el.placeholder, + value: el.type === 'checkbox' ? el.checked : el.value + })); +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) +ws.close() diff --git a/check_nav_items.py b/check_nav_items.py new file mode 100644 index 0000000..892b2bf --- /dev/null +++ b/check_nav_items.py @@ -0,0 +1,29 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 查找所有 nav item +script = """ +(() => { + const navItems = Array.from(document.querySelectorAll('.dashboard-navigation-link, .nav-item, nav a, nav button, aside button, aside a')); + return navItems.map(el => ({ + tag: el.tagName, + text: el.innerText.trim(), + href: el.getAttribute('href'), + classes: el.className + })); +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) +ws.close() diff --git a/check_page_state.py b/check_page_state.py new file mode 100644 index 0000000..58833a2 --- /dev/null +++ b/check_page_state.py @@ -0,0 +1,33 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +time.sleep(2) + +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": "document.body.innerText"} +})) +res = ws.recv() +print("Body text:", json.loads(res)["result"]["result"]["value"]) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_page_now.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_page_now.png") + +ws.close() diff --git a/check_projects_members.py b/check_projects_members.py new file mode 100644 index 0000000..8759e04 --- /dev/null +++ b/check_projects_members.py @@ -0,0 +1,44 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击侧边栏“项目与成员” +script = """ +(() => { + const items = Array.from(document.querySelectorAll('.navigation-item')); + const target = items.find(b => b.innerText.includes('项目与成员')); + if (target) { + target.click(); + return 'Navigated to 项目与成员'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_projects_members.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_projects_members.png") + +ws.close() diff --git a/check_second_server.py b/check_second_server.py new file mode 100644 index 0000000..28e0c3c --- /dev/null +++ b/check_second_server.py @@ -0,0 +1,14 @@ +import paramiko + +ssh = paramiko.SSHClient() +ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +try: + ssh.connect('47.108.78.12', port=22, username='root', password='10102442Lb!', timeout=10) + print('SSH to 47.108.78.12 succeeded!') + cmd = 'find / -maxdepth 3 -iname " *scert*\ 2>/dev/null; ls -la /opt' + stdin, stdout, stderr = ssh.exec_command(cmd) + print('--- Search result for scert on 47.108.78.12 ---') + print(stdout.read().decode('utf-8', errors='ignore')) + ssh.close() +except Exception as e: + print('Error:', e) diff --git a/click_add_domain.py b/click_add_domain.py new file mode 100644 index 0000000..f4c26f3 --- /dev/null +++ b/click_add_domain.py @@ -0,0 +1,43 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“添加域名”按钮 +script = """ +(() => { + const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('添加域名')); + if (btn) { + btn.click(); + return 'Clicked 添加域名'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_add_domain_modal.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_add_domain_modal.png") + +ws.close() diff --git a/click_domains.py b/click_domains.py new file mode 100644 index 0000000..909a628 --- /dev/null +++ b/click_domains.py @@ -0,0 +1,44 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“域名配置” +script = """ +(() => { + const buttons = Array.from(document.querySelectorAll('.navigation-item')); + const target = buttons.find(b => b.innerText.includes('域名配置')); + if (target) { + target.click(); + return 'Clicked 域名配置'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_domains_view.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_domains_view.png") + +ws.close() diff --git a/click_mail_tab.py b/click_mail_tab.py new file mode 100644 index 0000000..a14d0e1 --- /dev/null +++ b/click_mail_tab.py @@ -0,0 +1,44 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“邮件通知”选项卡 +script = """ +(() => { + const tabs = Array.from(document.querySelectorAll('button, div, span')); + const mailTab = tabs.find(el => el.innerText && el.innerText.trim() === '邮件通知'); + if (mailTab) { + mailTab.click(); + return 'Clicked 邮件通知'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_mail_tab.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_mail_tab.png") + +ws.close() diff --git a/click_server_btn.py b/click_server_btn.py new file mode 100644 index 0000000..6a24a6a --- /dev/null +++ b/click_server_btn.py @@ -0,0 +1,44 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“部署服务器”按钮 +script = """ +(() => { + const buttons = Array.from(document.querySelectorAll('.navigation-item')); + const target = buttons.find(b => b.innerText.includes('部署服务器')); + if (target) { + target.click(); + return 'Clicked 部署服务器'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_servers_clicked.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_servers_clicked.png") + +ws.close() diff --git a/click_servers.py b/click_servers.py new file mode 100644 index 0000000..83c3a0c --- /dev/null +++ b/click_servers.py @@ -0,0 +1,29 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“部署服务器” +script = """ +(() => { + const all = Array.from(document.querySelectorAll('span, button, a, div')); + const target = all.find(el => el.innerText && el.innerText.trim() === '部署服务器'); + if (target) { + target.click(); + return 'Clicked ' + target.tagName; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) +ws.close() diff --git a/click_settings.py b/click_settings.py new file mode 100644 index 0000000..203c02b --- /dev/null +++ b/click_settings.py @@ -0,0 +1,43 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +script = """ +(() => { + const all = Array.from(document.querySelectorAll('span, button, a, div')); + const target = all.find(el => el.innerText && el.innerText.trim() === '系统设置'); + if (target) { + target.click(); + return 'Clicked ' + target.tagName; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_settings_view.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_settings_view.png") + +ws.close() diff --git a/close_settings.py b/close_settings.py new file mode 100644 index 0000000..cb2119b --- /dev/null +++ b/close_settings.py @@ -0,0 +1,28 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“关闭”系统设置弹窗 +script = """ +(() => { + const closeBtn = document.querySelector('.close-button'); + if (closeBtn) { + closeBtn.click(); + return 'Closed settings modal'; + } + return 'Close button not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) +ws.close() diff --git a/current_view.png b/current_view.png new file mode 100644 index 0000000..40034c2 Binary files /dev/null and b/current_view.png differ diff --git a/dashboard_account_layout.png b/dashboard_account_layout.png new file mode 100644 index 0000000..38f9247 Binary files /dev/null and b/dashboard_account_layout.png differ diff --git a/dashboard_after_login.png b/dashboard_after_login.png new file mode 100644 index 0000000..5c78d39 Binary files /dev/null and b/dashboard_after_login.png differ diff --git a/dashboard_equal_columns.png b/dashboard_equal_columns.png new file mode 100644 index 0000000..6d3f93d Binary files /dev/null and b/dashboard_equal_columns.png differ diff --git a/deploy/scert_linux b/deploy/scert_linux new file mode 100644 index 0000000..8be5031 Binary files /dev/null and b/deploy/scert_linux differ diff --git a/deploy_frontend.py b/deploy_frontend.py new file mode 100644 index 0000000..6716f87 --- /dev/null +++ b/deploy_frontend.py @@ -0,0 +1,33 @@ +import paramiko, os + +ssh = paramiko.SSHClient() +ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +ssh.connect("8.137.23.95", port=22, username="root", password="10102442Lb!", timeout=10) + +sftp = ssh.open_sftp() + +local_dist = "frontend/dist" +remote_web = "/scert/web" + +# 上传所有文件 +for root, dirs, files in os.walk(local_dist): + rel_root = os.path.relpath(root, local_dist).replace("\\", "/") + remote_dir = remote_web if rel_root == "." else f"{remote_web}/{rel_root}" + try: + sftp.mkdir(remote_dir) + except: + pass + for file in files: + local_file = os.path.join(root, file) + remote_file = f"{remote_dir}/{file}" + print(f"Uploading {local_file} -> {remote_file}") + sftp.put(local_file, remote_file) + +sftp.close() + +# 检查远程 /scert/web 文件 +stdin, stdout, stderr = ssh.exec_command("ls -la /scert/web /scert/web/assets") +print(stdout.read().decode()) + +ssh.close() +print("Deploy frontend done!") diff --git a/do_update.py b/do_update.py new file mode 100644 index 0000000..e69de29 diff --git a/enable_smtp.py b/enable_smtp.py new file mode 100644 index 0000000..d65e10f --- /dev/null +++ b/enable_smtp.py @@ -0,0 +1,43 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“启用 SMTP 发送”checkbox +script = """ +(() => { + const checkbox = document.querySelector('.mail-switch input[type="checkbox"]'); + if (checkbox) { + checkbox.click(); + return 'Checkbox checked: ' + checkbox.checked; + } + return 'Checkbox not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_mail_tab_enabled.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_mail_tab_enabled.png") + +ws.close() diff --git a/find_settings.py b/find_settings.py new file mode 100644 index 0000000..22741a9 --- /dev/null +++ b/find_settings.py @@ -0,0 +1,27 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +script = """ +(() => { + const all = Array.from(document.querySelectorAll('*')); + return all.filter(el => el.children.length === 0 && el.innerText && el.innerText.includes('系统设置')).map(el => ({ + tag: el.tagName, + className: el.className, + text: el.innerText + })); +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) +ws.close() diff --git a/fix_test.py b/fix_test.py new file mode 100644 index 0000000..fdd2006 --- /dev/null +++ b/fix_test.py @@ -0,0 +1,12 @@ +with open("frontend/src/views/Dashboard/DomainForm.test.js", "r", encoding="utf-8") as f: + test_text = f.read() + +test_text = test_text.replace( + ' assert.equal(state.editingId.value, "");\n assert.deepEqual(state.form.value.server_ids, []);\n assert.equal(state.domainBindingsLoading.value, false);', + ' assert.equal(state.editingId.value, "");\n assert.deepEqual(state.form.value.server_ids, [firstServer.id]);\n assert.equal(state.domainBindingsLoading.value, false);' +) + +with open("frontend/src/views/Dashboard/DomainForm.test.js", "w", encoding="utf-8") as f: + f.write(test_text) + +print("Updated DomainForm.test.js line 241") diff --git a/live_screen.png b/live_screen.png new file mode 100644 index 0000000..0321e0b Binary files /dev/null and b/live_screen.png differ diff --git a/login_and_open_add_domain.py b/login_and_open_add_domain.py new file mode 100644 index 0000000..ea94805 --- /dev/null +++ b/login_and_open_add_domain.py @@ -0,0 +1,94 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 自动填写登录表单并登录 xuans / 10102442Lb! (备用 12345678a) +login_script = """ +(() => { + const inputs = Array.from(document.querySelectorAll('input')); + const userInput = inputs.find(i => i.placeholder && i.placeholder.includes('用户名') || i.type === 'text'); + const pwdInput = inputs.find(i => i.type === 'password'); + const submitBtn = document.querySelector('button[type="submit"]') || Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('登录')); + + if (userInput && pwdInput && submitBtn) { + userInput.value = 'xuans'; + userInput.dispatchEvent(new Event('input', { bubbles: true })); + pwdInput.value = '10102442Lb!'; + pwdInput.dispatchEvent(new Event('input', { bubbles: true })); + submitBtn.click(); + return 'Submitting login...'; + } + return 'Login elements not found'; +})() +""" + +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": login_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(2) + +# 查看是否进入控制台并点击“域名配置” +nav_script = """ +(() => { + const items = Array.from(document.querySelectorAll('.navigation-item, button')); + const target = items.find(b => b.innerText.includes('域名配置')); + if (target) { + target.click(); + return 'Navigated to 域名配置'; + } + return 'Not in dashboard yet: ' + document.body.innerText.slice(0, 100); +})() +""" +ws.send(json.dumps({ + "id": 2, + "method": "Runtime.evaluate", + "params": {"expression": nav_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 点击“添加域名” +add_script = """ +(() => { + const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('添加域名')); + if (btn) { + btn.click(); + return 'Clicked 添加域名'; + } + return '添加域名 not found'; +})() +""" +ws.send(json.dumps({ + "id": 3, + "method": "Runtime.evaluate", + "params": {"expression": add_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 截图保存 +ws.send(json.dumps({ + "id": 4, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_add_domain_default_checked.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_add_domain_default_checked.png") + +ws.close() diff --git a/login_page.png b/login_page.png new file mode 100644 index 0000000..6d3f93d Binary files /dev/null and b/login_page.png differ diff --git a/login_pwd2.py b/login_pwd2.py new file mode 100644 index 0000000..78f814f --- /dev/null +++ b/login_pwd2.py @@ -0,0 +1,48 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 使用 12345678a 尝试登录 +login_script = """ +(() => { + const inputs = Array.from(document.querySelectorAll('input')); + const userInput = inputs.find(i => i.placeholder && i.placeholder.includes('用户名') || i.type === 'text'); + const pwdInput = inputs.find(i => i.type === 'password'); + const submitBtn = document.querySelector('button[type="submit"]') || Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('登录')); + + if (userInput && pwdInput && submitBtn) { + userInput.value = 'xuans'; + userInput.dispatchEvent(new Event('input', { bubbles: true })); + pwdInput.value = '12345678a'; + pwdInput.dispatchEvent(new Event('input', { bubbles: true })); + submitBtn.click(); + return 'Submitting login with 12345678a...'; + } + return 'Login elements not found'; +})() +""" + +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": login_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(2) + +ws.send(json.dumps({ + "id": 2, + "method": "Runtime.evaluate", + "params": {"expression": "document.body.innerText.slice(0, 150)", "returnByValue": True} +})) +print(ws.recv()) + +ws.close() diff --git a/mail_settings_ready.png b/mail_settings_ready.png new file mode 100644 index 0000000..3e72750 Binary files /dev/null and b/mail_settings_ready.png differ diff --git a/mail_settings_tab.png b/mail_settings_tab.png new file mode 100644 index 0000000..3e72750 Binary files /dev/null and b/mail_settings_tab.png differ diff --git a/mail_settings_view.png b/mail_settings_view.png new file mode 100644 index 0000000..dcdc753 Binary files /dev/null and b/mail_settings_view.png differ diff --git a/mark_done.py b/mark_done.py new file mode 100644 index 0000000..887c2e8 --- /dev/null +++ b/mark_done.py @@ -0,0 +1,21 @@ +with open("doc/Scert整改任务执行清单.md", "r", encoding="utf-8") as f: + text = f.read() + +text = text.replace( + "- [ ] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。\n- [ ] 提交并双重推送 Git 远端仓库。", + "- [✓] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。\n- [✓] 提交并双重推送 Git 远端仓库。" +) +with open("doc/Scert整改任务执行清单.md", "w", encoding="utf-8") as f: + f.write(text) + +with open("doc/Scert整改合并优化清单.md", "r", encoding="utf-8") as f: + text_m = f.read() + +text_m = text_m.replace( + "- [ ] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。\n- [ ] 提交并双重推送 Git 远端仓库。", + "- [✓] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。\n- [✓] 提交并双重推送 Git 远端仓库。" +) +with open("doc/Scert整改合并优化清单.md", "w", encoding="utf-8") as f: + f.write(text_m) + +print("Marked status as completed in execution lists.") diff --git a/mcp_add_domain_default_checked.png b/mcp_add_domain_default_checked.png new file mode 100644 index 0000000..8a5c61c Binary files /dev/null and b/mcp_add_domain_default_checked.png differ diff --git a/mcp_add_domain_modal.png b/mcp_add_domain_modal.png new file mode 100644 index 0000000..5e7d2d7 Binary files /dev/null and b/mcp_add_domain_modal.png differ diff --git a/mcp_add_domain_verified.png b/mcp_add_domain_verified.png new file mode 100644 index 0000000..9469de0 Binary files /dev/null and b/mcp_add_domain_verified.png differ diff --git a/mcp_domains_view.png b/mcp_domains_view.png new file mode 100644 index 0000000..c0f0e4f Binary files /dev/null and b/mcp_domains_view.png differ diff --git a/mcp_mail_tab.png b/mcp_mail_tab.png new file mode 100644 index 0000000..3e72750 Binary files /dev/null and b/mcp_mail_tab.png differ diff --git a/mcp_mail_tab_enabled.png b/mcp_mail_tab_enabled.png new file mode 100644 index 0000000..01154c1 Binary files /dev/null and b/mcp_mail_tab_enabled.png differ diff --git a/mcp_page_now.png b/mcp_page_now.png new file mode 100644 index 0000000..d4d339a Binary files /dev/null and b/mcp_page_now.png differ diff --git a/mcp_projects_members.png b/mcp_projects_members.png new file mode 100644 index 0000000..40034c2 Binary files /dev/null and b/mcp_projects_members.png differ diff --git a/mcp_servers_clicked.png b/mcp_servers_clicked.png new file mode 100644 index 0000000..9d65428 Binary files /dev/null and b/mcp_servers_clicked.png differ diff --git a/mcp_servers_view.png b/mcp_servers_view.png new file mode 100644 index 0000000..d4d339a Binary files /dev/null and b/mcp_servers_view.png differ diff --git a/mcp_settings_view.png b/mcp_settings_view.png new file mode 100644 index 0000000..fe89fb7 Binary files /dev/null and b/mcp_settings_view.png differ diff --git a/mcp_verified.png b/mcp_verified.png new file mode 100644 index 0000000..3e72750 Binary files /dev/null and b/mcp_verified.png differ diff --git a/nav_to_settings.py b/nav_to_settings.py new file mode 100644 index 0000000..e0911a0 --- /dev/null +++ b/nav_to_settings.py @@ -0,0 +1,45 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击“系统设置” +script = """ +(() => { + const items = Array.from(document.querySelectorAll('.dashboard-navigation-item')); + const settingsItem = items.find(el => el.innerText.includes('系统设置')); + if (settingsItem) { + settingsItem.click(); + return 'Clicked 系统设置'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 截图保存 +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_settings_view.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_settings_view.png") + +ws.close() diff --git a/scert_preview_1.png b/scert_preview_1.png new file mode 100644 index 0000000..400e217 Binary files /dev/null and b/scert_preview_1.png differ diff --git a/scert_preview_active_dashboard.png b/scert_preview_active_dashboard.png new file mode 100644 index 0000000..0321e0b Binary files /dev/null and b/scert_preview_active_dashboard.png differ diff --git a/scert_preview_current.png b/scert_preview_current.png new file mode 100644 index 0000000..9469de0 Binary files /dev/null and b/scert_preview_current.png differ diff --git a/scert_preview_current_2.png b/scert_preview_current_2.png new file mode 100644 index 0000000..b0f5184 Binary files /dev/null and b/scert_preview_current_2.png differ diff --git a/scert_preview_dashboard_logged_in.png b/scert_preview_dashboard_logged_in.png new file mode 100644 index 0000000..03219f4 Binary files /dev/null and b/scert_preview_dashboard_logged_in.png differ diff --git a/scert_preview_login.png b/scert_preview_login.png new file mode 100644 index 0000000..9469de0 Binary files /dev/null and b/scert_preview_login.png differ diff --git a/scert_preview_odacm.png b/scert_preview_odacm.png new file mode 100644 index 0000000..9469de0 Binary files /dev/null and b/scert_preview_odacm.png differ diff --git a/scert_real_current.png b/scert_real_current.png new file mode 100644 index 0000000..0321e0b Binary files /dev/null and b/scert_real_current.png differ diff --git a/settings_view.png b/settings_view.png new file mode 100644 index 0000000..2e964eb Binary files /dev/null and b/settings_view.png differ diff --git a/sidebar_cropped.png b/sidebar_cropped.png new file mode 100644 index 0000000..6d0aef8 Binary files /dev/null and b/sidebar_cropped.png differ diff --git a/sidebar_dashboard_view.png b/sidebar_dashboard_view.png new file mode 100644 index 0000000..9b5eac2 Binary files /dev/null and b/sidebar_dashboard_view.png differ diff --git a/sidebar_detail.png b/sidebar_detail.png new file mode 100644 index 0000000..50212b2 Binary files /dev/null and b/sidebar_detail.png differ diff --git a/snap_servers.py b/snap_servers.py new file mode 100644 index 0000000..4384d43 --- /dev/null +++ b/snap_servers.py @@ -0,0 +1,25 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 1, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_servers_view.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_servers_view.png") + +ws.close() diff --git a/test_cdp.py b/test_cdp.py new file mode 100644 index 0000000..8c11a27 --- /dev/null +++ b/test_cdp.py @@ -0,0 +1,37 @@ +import json, base64, time +import websocket +import urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] +print("Connecting to ws_url:", ws_url) + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": "document.title + ' | ' + window.location.href"} +})) + +msg = ws.recv() +print("Eval result:", msg) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) + +msg2 = ws.recv() +data = json.loads(msg2) +if "result" in data and "data" in data["result"]: + with open("mcp_verified.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot captured successfully!") +else: + print("Response:", msg2[:200]) + +ws.close() diff --git a/test_default_server_mcp.py b/test_default_server_mcp.py new file mode 100644 index 0000000..4ed7ba3 --- /dev/null +++ b/test_default_server_mcp.py @@ -0,0 +1,59 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 清除缓存并刷新页面 +ws.send(json.dumps({ + "id": 1, + "method": "Network.clearBrowserCache" +})) +print(ws.recv()) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.reload", + "params": {"ignoreCache": True} +})) +print(ws.recv()) + +time.sleep(2) + +# 点击“添加域名” +script = """ +(() => { + const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('添加域名')); + if (btn) { + btn.click(); + return 'Clicked 添加域名'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 3, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +ws.send(json.dumps({ + "id": 4, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_add_domain_default_checked.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_add_domain_default_checked.png") + +ws.close() diff --git a/test_mcp_conn.py b/test_mcp_conn.py new file mode 100644 index 0000000..67df475 --- /dev/null +++ b/test_mcp_conn.py @@ -0,0 +1,36 @@ +import json, base64 +import websocket +import urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] +print("Connecting to ws_url:", ws_url) + +ws = websocket.create_connection(ws_url) + +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": "document.title + ' | ' + window.location.href"} +})) +res = ws.recv() +print("Page status:", res) + +ws.send(json.dumps({ + "id": 2, + "method": "Page.captureScreenshot" +})) + +while True: + msg = ws.recv() + data = json.loads(msg) + if data.get("id") == 2: + img_data = base64.b64decode(data["result"]["data"]) + with open("mcp_check_screenshot.png", "wb") as f: + f.write(img_data) + print("Screenshot saved to mcp_check_screenshot.png") + break + +ws.close() diff --git a/test_nav.py b/test_nav.py new file mode 100644 index 0000000..825ba27 --- /dev/null +++ b/test_nav.py @@ -0,0 +1,26 @@ +import json, websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击侧边栏的“系统设置”或切换视图查看 +script = """ +(() => { + const navItems = Array.from(document.querySelectorAll('.dashboard-navigation-item, .nav-item, button')); + return navItems.map(item => item.innerText.trim()).filter(Boolean); +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script, "returnByValue": True} +})) + +res = ws.recv() +print("Nav elements:", res) +ws.close() diff --git a/test_open_add_domain.py b/test_open_add_domain.py new file mode 100644 index 0000000..02edddb --- /dev/null +++ b/test_open_add_domain.py @@ -0,0 +1,65 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击侧边栏“域名配置” +nav_script = """ +(() => { + const items = Array.from(document.querySelectorAll('.navigation-item')); + const target = items.find(b => b.innerText.includes('域名配置')); + if (target) { + target.click(); + return 'Navigated to 域名配置'; + } + return '域名配置 not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": nav_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 点击“添加域名” +add_script = """ +(() => { + const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('添加域名')); + if (btn) { + btn.click(); + return 'Clicked 添加域名'; + } + return '添加域名 not found'; +})() +""" +ws.send(json.dumps({ + "id": 2, + "method": "Runtime.evaluate", + "params": {"expression": add_script, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 截图保存 +ws.send(json.dumps({ + "id": 3, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_add_domain_default_checked.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_add_domain_default_checked.png") + +ws.close() diff --git a/update_doc.py b/update_doc.py new file mode 100644 index 0000000..289b0ff --- /dev/null +++ b/update_doc.py @@ -0,0 +1,32 @@ +import sys + +with open("doc/Scert整改任务执行清单.md", "r", encoding="utf-8") as f: + text = f.read() + +target = """## 2026年10月18日 侧边栏底部SSL证书管理字样清理与侧边栏左右5px自适应布局 + +- [x] 清理 DashboardNavigation.vue 底部“SSL 证书管理”角标及冗余 CSS +- [x] 优化侧边栏及账号卡片等宽自适应布局,侧边栏以卡片宽度左右各留 5px 内边距(padding: 2px 5px) +- [x] 统一第一行版本号格式为 Vx.x.x(如 V1.52.1) +- [x] 运行前端单元测试 356 项全量验证通过 +- [x] 编译并成功部署前端产物至第一台服务器(8.137.23.95) +- [x] 双重推送远程仓库并持续汇报进度""" + +addition = """## 2026年10月18日 新建托管域名默认勾选第一台生产测试服务器 + +- [x] 修改 DomainForm.js 中 openCreate 逻辑,新建域名时如果已有配置服务器,默认将第一台服务器关联勾选(server_ids = [servers[0].id])。 +- [x] 同步更新 DomainForm.test.js 对应场景断言,确保单元测试与新建默认勾选逻辑严密契合。 +- [x] 前端自动化单元测试 356 项全量通过(356 pass)。 +- [x] 完成前端生产环境打包构建(vite build)生成新静态资源产物。 +- [ ] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。 +- [ ] 提交并双重推送 Git 远端仓库。 + +""" + target + +if target in text: + text = text.replace(target, addition, 1) + with open("doc/Scert整改任务执行清单.md", "w", encoding="utf-8") as f: + f.write(text) + print("Updated Scert整改任务执行清单.md") +else: + print("Target not found in Scert整改任务执行清单.md") diff --git a/update_doc_merge.py b/update_doc_merge.py new file mode 100644 index 0000000..cefe66f --- /dev/null +++ b/update_doc_merge.py @@ -0,0 +1,25 @@ +import sys + +with open("doc/Scert整改合并优化清单.md", "r", encoding="utf-8") as f: + text = f.read() + +target = """## 2026年10月17日 邮件模板美化与Linux生产主服务热部署""" + +addition = """## 2026年10月18日 新建托管域名默认勾选第一台生产测试服务器 + +- [x] 修改 DomainForm.js 中 openCreate 逻辑,新建域名时如果已有配置服务器,默认将第一台服务器关联勾选(server_ids = [servers[0].id])。 +- [x] 同步更新 DomainForm.test.js 对应场景断言,确保单元测试与新建默认勾选逻辑严密契合。 +- [x] 前端自动化单元测试 356 项全量通过(356 pass)。 +- [x] 完成前端生产环境打包构建(vite build)生成新静态资源产物。 +- [ ] 部署静态产物至第一台服务器(8.137.23.95)并在 Chrome MCP 验证实机新建域名弹窗默认勾选效果。 +- [ ] 提交并双重推送 Git 远端仓库。 + +""" + target + +if target in text: + text = text.replace(target, addition, 1) + with open("doc/Scert整改合并优化清单.md", "w", encoding="utf-8") as f: + f.write(text) + print("Updated Scert整改合并优化清单.md") +else: + print("Target not found in Scert整改合并优化清单.md") diff --git a/update_domain_form.py b/update_domain_form.py new file mode 100644 index 0000000..2b9472e --- /dev/null +++ b/update_domain_form.py @@ -0,0 +1,29 @@ +import sys + +with open("frontend/src/views/Dashboard/DomainForm.js", "r", encoding="utf-8") as f: + text = f.read() + +old_open_create = """ function openCreate() { + if (saving.value) return; + version += 1; + editingId.value = ""; + targetID = ""; + form.value = emptyForm();""" + +new_open_create = """ function openCreate() { + if (saving.value) return; + version += 1; + editingId.value = ""; + targetID = ""; + form.value = emptyForm(); + if (servers.value && servers.value.length > 0) { + form.value.server_ids = [servers.value[0].id]; + }""" + +if old_open_create in text: + text = text.replace(old_open_create, new_open_create, 1) + with open("frontend/src/views/Dashboard/DomainForm.js", "w", encoding="utf-8") as f: + f.write(text) + print("DomainForm.js updated successfully!") +else: + print("old_open_create not matched!") diff --git a/verify_domain_default.py b/verify_domain_default.py new file mode 100644 index 0000000..dba62af --- /dev/null +++ b/verify_domain_default.py @@ -0,0 +1,65 @@ +import json, base64, time +import websocket, urllib.request + +resp = urllib.request.urlopen("http://127.0.0.1:9222/json/list") +pages = json.loads(resp.read().decode("utf-8")) +page = next(p for p in pages if p.get("type") == "page" and "odacm.cn" in p.get("url")) +ws_url = page["webSocketDebuggerUrl"] + +ws = websocket.WebSocket() +ws.connect(ws_url, timeout=5) + +# 点击侧边栏“域名配置” +script_click_tab = """ +(() => { + const buttons = Array.from(document.querySelectorAll('.navigation-item')); + const target = buttons.find(b => b.innerText.includes('域名配置')); + if (target) { + target.click(); + return 'Clicked 域名配置'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 1, + "method": "Runtime.evaluate", + "params": {"expression": script_click_tab, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 点击“添加域名” +script_click_add = """ +(() => { + const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('添加域名')); + if (btn) { + btn.click(); + return 'Clicked 添加域名'; + } + return 'Not found'; +})() +""" +ws.send(json.dumps({ + "id": 2, + "method": "Runtime.evaluate", + "params": {"expression": script_click_add, "returnByValue": True} +})) +print(ws.recv()) + +time.sleep(1) + +# 截图保存 +ws.send(json.dumps({ + "id": 3, + "method": "Page.captureScreenshot" +})) +msg = ws.recv() +data = json.loads(msg) +if "result" in data and "data" in data["result"]: + with open("mcp_add_domain_verified.png", "wb") as f: + f.write(base64.b64decode(data["result"]["data"])) + print("Screenshot saved to mcp_add_domain_verified.png") + +ws.close() diff --git a/验证码.html b/验证码.html new file mode 100644 index 0000000..cdc73d6 --- /dev/null +++ b/验证码.html @@ -0,0 +1,322 @@ +1.[{{site_name}}] 邮箱验证码 + + +
+ + + + + +{{recipient_name}},您好:
+您的验证码是:
+{{verification_code}}
+验证码将在 {{expires_in_minutes}} 分钟后失效。
+如果不是您本人操作,请忽略此邮件。
{{recipient_name}},您好:
+我们收到了您的密码重置请求,请点击下方按钮设置新密码。
+ +此链接将在 {{expires_in_minutes}} 分钟后失效。
+如果按钮无法点击,请复制以下链接到浏览器中打开:
{{reset_url}}
如果不是您本人操作,请忽略此邮件。
{{recipient_name}},您好:
+您正在添加额外的通知邮箱,请输入以下验证码完成验证。
+{{verification_code}}
+验证码将在 {{expires_in_minutes}} 分钟后失效。
+如果不是您本人操作,请忽略此邮件。
{{recipient_name}},您好:
+您的账户在统计周期内多次触发平台内容审核/风控规则,系统已自动禁用该账户。
+| 禁用时间 | {{triggered_at}} |
| 所属分组 | {{group_name}} |
| 命中类别 / 分数 | {{moderation_category}} / {{moderation_score}} |
| 累计触发次数 | {{violation_count}} / {{ban_threshold}} |
如需申诉或恢复账号,请联系平台管理员处理。
规则:{{rule_name}}
+严重级别:{{severity}}
+状态:{{alert_status}}
+指标:{{metric_type}} {{operator}} {{metric_value}}(阈值 {{threshold_value}})
+触发时间:{{triggered_at}}
+说明:{{alert_description}}
{{recipient_name}},您好:
+您的 API 请求触发了平台内容审核/风控策略。
+| 触发时间 | {{triggered_at}} |
| 所属分组 | {{group_name}} |
| 命中类别 / 分数 | {{moderation_category}} / {{moderation_score}} |
| 累计触发次数 | {{violation_count}} / {{ban_threshold}} |
请检查请求内容,避免后续服务受到影响。
规则:{{rule_name}}
+严重级别:{{severity}}
+状态:{{alert_status}}
+指标:{{metric_type}} {{operator}} {{metric_value}}(阈值 {{threshold_value}})
+触发时间:{{triggered_at}}
+说明:{{alert_description}}
运维报表
+{{site_name}} 的运行概览
+| 报表 | {{report_name}} |
| 类型 | {{report_type}} |
| 统计周期 | {{report_start_time}} 至 {{report_end_time}} (UTC) |
| 总请求数{{report_total_requests}} | +成功请求{{report_success_count}} | +
| SLA 错误{{report_sla_error_count}} | +业务限流{{report_business_limited_count}} | +
| SLA | {{report_sla}} |
| 错误率 | {{report_error_rate}} |
| 上游错误率(不含 429 / 529) | {{report_upstream_error_rate}} |
| 上游错误(不含 429 / 529) | {{report_upstream_error_count_excl_429_529}} |
| 上游 429 / 529 | {{report_upstream_429_count}} / {{report_upstream_529_count}} |
| 请求延迟 p50 / p99 | {{report_latency_p50}} / {{report_latency_p99}} |
| 首 Token 时间 p50 / p99 | {{report_ttft_p50}} / {{report_ttft_p99}} |
| Token 消耗 | {{report_tokens}} |
| QPS(当前 / 峰值 / 平均) | {{report_qps_current}} / {{report_qps_peak}} / {{report_qps_avg}} |
| TPS(当前 / 峰值 / 平均) | {{report_tps_current}} / {{report_tps_peak}} / {{report_tps_avg}} |