diff --git a/backend/controllers/wechatcallback/page.css b/backend/controllers/wechatcallback/page.css index 08d00155..2ebf8701 100644 --- a/backend/controllers/wechatcallback/page.css +++ b/backend/controllers/wechatcallback/page.css @@ -2,7 +2,7 @@ color-scheme: light; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; color: #182638; - background: #f3f6fa; + background: #f4f7f8; -webkit-text-size-adjust: 100%; } @@ -11,35 +11,44 @@ } body { + display: flex; + flex-direction: column; margin: 0; min-height: 100vh; min-height: 100svh; - padding: 48px 20px 28px; - padding-top: max(48px, env(safe-area-inset-top)); - padding-bottom: max(28px, env(safe-area-inset-bottom)); + padding: 24px 20px; + padding-top: max(24px, env(safe-area-inset-top)); + padding-right: max(20px, env(safe-area-inset-right)); + padding-bottom: max(24px, env(safe-area-inset-bottom)); + padding-left: max(20px, env(safe-area-inset-left)); } .result-card { width: 100%; - max-width: 440px; - margin: 0 auto; - padding: 28px 24px 24px; - border: 1px solid #e5eaf1; - border-radius: 24px; + max-width: 420px; + margin: auto; + padding: 24px; + border: 1px solid #e6eceb; + border-radius: 20px; background: #fff; box-shadow: 0 12px 40px rgb(32 56 85 / 5%); text-align: center; } .brand { - color: #254c8a; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + color: #253d38; font-size: 18px; font-weight: 700; letter-spacing: 0.3px; } .brand span { - margin-left: 8px; + padding-left: 10px; + border-left: 1px solid #dce3e1; color: #697789; font-size: 14px; font-weight: 400; @@ -49,9 +58,9 @@ body { display: flex; align-items: center; justify-content: center; - width: 72px; - height: 72px; - margin: 32px auto 16px; + width: 64px; + height: 64px; + margin: 28px auto 18px; border-radius: 50%; font-size: 38px; font-weight: 600; @@ -68,33 +77,69 @@ body { background: #fff4e3; } +.checkmark { + width: 25px; + height: 14px; + margin-top: -6px; + border-bottom: 3px solid currentColor; + border-left: 3px solid currentColor; + transform: rotate(-45deg); +} + .status-label { - margin: 0 0 8px; - color: #637186; - font-size: 13px; + padding: 3px 8px; + border-radius: 6px; + color: #25634c; + background: #e6f1eb; + font-size: 12px; + font-weight: 400; + line-height: 1.5; +} + +.warning-label { + color: #8b531d; + background: #fff0db; } h1 { margin: 0; - font-size: 26px; + font-size: 24px; line-height: 1.4; font-weight: 650; } .description { - margin: 12px 0 24px; + margin: 10px 0 24px; color: #526174; font-size: 15px; line-height: 1.7; } +.next-step { + padding: 16px; + border: 1px solid #edf1f0; + border-radius: 12px; + background: #f7f9f8; + text-align: left; +} + +.next-step h2 { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 8px; + margin: 0 0 16px; + font-size: 14px; + line-height: 1.5; + font-weight: 600; +} + .steps { display: grid; - gap: 16px; + gap: 12px; margin: 0; - padding: 20px 16px; - border-radius: 16px; - background: #f6f8fb; + padding: 0; list-style: none; text-align: left; } @@ -102,31 +147,36 @@ h1 { .steps li { display: flex; align-items: flex-start; - gap: 12px; - font-size: 15px; + gap: 10px; + font-size: 14px; line-height: 24px; } +.steps strong { + color: #246248; + font-weight: 600; +} + .step-number { flex: 0 0 24px; height: 24px; border-radius: 50%; - background: #e8eef8; - color: #355987; + background: #e8eeeb; + color: #486456; font-size: 13px; font-weight: 600; text-align: center; } .notice { - margin: 20px 0; + margin: 16px 0 20px; color: #647286; font-size: 13px; line-height: 1.8; } footer { - padding-top: 18px; + padding-top: 16px; border-top: 1px solid #edf0f5; color: #68768a; font-size: 12px; @@ -135,14 +185,26 @@ footer { @media (max-width: 360px) { body { - padding: 24px 12px; + padding-right: max(12px, env(safe-area-inset-right)); + padding-left: max(12px, env(safe-area-inset-left)); } .result-card { padding: 24px 16px; } - .steps { - padding: 16px 12px; + .next-step { + padding: 14px 12px; + } +} + +@media (max-height: 600px) { + .status-icon { + margin-top: 20px; + margin-bottom: 14px; + } + + .description { + margin-bottom: 18px; } } diff --git a/backend/controllers/wechatcallback/page.html b/backend/controllers/wechatcallback/page.html index 4eccdfd5..3353f7aa 100644 --- a/backend/controllers/wechatcallback/page.html +++ b/backend/controllers/wechatcallback/page.html @@ -10,31 +10,53 @@
-
Smail 微信通知
+
Smail 微信通知
{{if .Authorized}} - -

等待确认绑定

+

微信授权成功

-

还差一步,请返回 Smail 确认绑定。

-
    -
  1. 回到发起扫码的 Smail 页面
  2. -
  3. 核对显示的微信昵称
  4. -
  5. 点击「确认绑定」
  6. -
-

本次授权不会自动绑定账号。
请在二维码有效期内完成确认。

+

还差一步,回到原设备确认即可。

+
+

+ 完成绑定 + 等待确认绑定 +

+
    +
  1. + + 回到发起扫码的 Smail 页面 +
  2. +
  3. + + 核对微信昵称,点击「确认绑定」 +
  4. +
+
+

本次授权不会自动绑定账号,请在二维码有效期内确认。

{{else}} -

请重新扫码

微信授权未完成

二维码可能已失效,或本次授权未完成。

-
    -
  1. 回到发起扫码的 Smail 页面
  2. -
  3. 关闭绑定弹窗,重新生成二维码
  4. -
  5. 使用本人微信重新扫码授权
  6. -
-

若已在 Smail 确认绑定,以原页面状态为准。
请勿刷新或重复打开旧授权链接。

+
+

+ 重新授权 + 请重新扫码 +

+
    +
  1. + + 回到发起扫码的 Smail 页面 +
  2. +
  3. + + 重新打开绑定弹窗,用本人微信扫码 +
  4. +
+
+

若已确认绑定,以原页面状态为准。请勿重复打开旧授权链接。

{{end}} - +
diff --git a/backend/controllers/wechatcallback/page_test.go b/backend/controllers/wechatcallback/page_test.go index 71007031..4d9f8d2f 100644 --- a/backend/controllers/wechatcallback/page_test.go +++ b/backend/controllers/wechatcallback/page_test.go @@ -39,6 +39,20 @@ func TestWriteAuthorizationResult(t *testing.T) { if test.authorized && !strings.Contains(body, "本次授权不会自动绑定账号") { t.Fatal("授权成功页面必须明确仍需原会话确认") } + if strings.Count(body, `
  • `) != 2 { + t.Fatal("结果页应仅展示两步操作指引") + } + for _, expected := range []string{`aria-labelledby="next-step-title"`, `id="next-step-title"`, "无需在微信中登录 Smail"} { + if !strings.Contains(body, expected) { + t.Fatalf("结果页缺少操作引导:%s", expected) + } + } + if test.authorized && (!strings.Contains(body, "核对微信昵称") || !strings.Contains(body, "「确认绑定」")) { + t.Fatal("授权成功页面必须引导核对昵称并手动确认") + } + if !test.authorized && !strings.Contains(body, "以原页面状态为准") { + t.Fatal("失效页面不能将重复回调误报为已经解除绑定") + } }) } }