diff --git a/frontend/m/js/pages.js b/frontend/m/js/pages.js
index 08a53c9..8e78515 100644
--- a/frontend/m/js/pages.js
+++ b/frontend/m/js/pages.js
@@ -3466,7 +3466,7 @@
}
function showToast(message) {
- const root = document.getElementById("m-sheet-root");
+ const root = ensureSheetRoot();
if (!root) return;
let toast = document.getElementById("m-toast");
if (!toast) {
@@ -4966,7 +4966,7 @@
const page = document.querySelector(".m-page");
if (page) {
page.innerHTML = '
' + html + "
" +
- '';
+ '';
}
}
@@ -4981,7 +4981,7 @@
const page = document.querySelector(".m-page");
if (page) {
page.innerHTML = '' + html + "
" +
- '';
+ '';
}
}
@@ -5058,13 +5058,13 @@
formFieldHtml("主模型", '', false) +
formFieldHtml("辅助模型", '', false) +
'' + renderModelPoolHtml(llm.models || []) + "
" +
- '' +
+ '' +
"";
const page = document.querySelector(".m-page");
if (!page) return;
const bar = tab === "models"
- ? ''
- : '';
+ ? ''
+ : '';
page.innerHTML = adminTabHtml() + '' + (tab === "models" ? modelsHtml : marketHtml) + "
" + bar;
if (tab === "models") updateSystemModelRoleOptions(llm.primary_model_id || "", llm.fallback_model_id || "");
}
diff --git a/tests/e2e/mobile-app.spec.js b/tests/e2e/mobile-app.spec.js
index 991431f..e532b7e 100644
--- a/tests/e2e/mobile-app.spec.js
+++ b/tests/e2e/mobile-app.spec.js
@@ -355,6 +355,18 @@ test("system management pages render real content instead of placeholders", asyn
await expect(page.locator("#m-sys-member-limit")).toBeVisible();
});
+test("empty profile save click shows a toast instead of a dead button", async ({ page }) => {
+ await mockMobileApi(page);
+ await openMobile(page);
+ await navigateToFeature(page, "system/profile");
+ await expect(page.locator("[data-system-save-birth]")).toBeVisible();
+ await page.locator("#m-sys-birth-date").fill("");
+ await page.locator("#m-sys-birth-time").fill("");
+ await page.locator("[data-system-save-birth]").click();
+ await expect(page.locator("#m-toast.is-visible")).toBeVisible();
+ await expect(page.locator("#m-toast")).toContainText("请填写完整出生日期和时间");
+});
+
test("non-admin cannot open system admin pages as placeholders", async ({ page }) => {
await mockMobileApi(page, { auth: authSession("user", true) });
await openMobile(page);
diff --git a/tests/test_mobile_system_pages.py b/tests/test_mobile_system_pages.py
index 6eb033c..4634819 100644
--- a/tests/test_mobile_system_pages.py
+++ b/tests/test_mobile_system_pages.py
@@ -57,3 +57,22 @@ class MobileSystemPagesRegressionTests(unittest.TestCase):
'location.assign("/login/")',
):
self.assertIn(marker, pages)
+
+ def test_system_boolean_attrs_do_not_have_stray_quotes(self) -> None:
+ pages = PAGES.read_text(encoding="utf-8")
+ stray = re.findall(r'data-system-[a-z-]*"(?=[>\s])', pages)
+ self.assertEqual(
+ stray,
+ [],
+ "boolean data-system attributes must not have a trailing quote before > or space",
+ )
+ for name in (
+ "data-system-save-birth",
+ "data-system-save-password",
+ "data-system-add-model",
+ "data-system-save-models",
+ "data-system-save-market",
+ "data-system-refresh",
+ ):
+ self.assertIn(name, pages)
+ self.assertNotIn(name + '">', pages)