smart-admin-web 10.20.0 → 10.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/api/index.d.ts +19 -1
  2. package/dist/api/index.js +85 -66
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/schema.d.ts +448 -1
  5. package/dist/assets/icons/ph-subset.json.js +1 -1
  6. package/dist/components/FormContainer/index.vue.js +87 -75
  7. package/dist/components/FormContainer/index.vue.js.map +1 -1
  8. package/dist/components/UserPicker/UserAvatar.vue.d.ts +8 -0
  9. package/dist/components/UserPicker/UserAvatar.vue.js +8 -0
  10. package/dist/components/UserPicker/UserAvatar.vue.js.map +1 -0
  11. package/dist/components/UserPicker/UserAvatar2.vue.js +38 -0
  12. package/dist/components/UserPicker/UserAvatar2.vue.js.map +1 -0
  13. package/dist/components/UserPicker/index.vue.js +1 -1
  14. package/dist/components/UserPicker/index2.vue.js +328 -186
  15. package/dist/components/UserPicker/index2.vue.js.map +1 -1
  16. package/dist/index.js +248 -246
  17. package/dist/layouts/NoticeBell.vue.js +2 -2
  18. package/dist/layouts/NoticeBell2.vue.js +18 -17
  19. package/dist/layouts/NoticeBell2.vue.js.map +1 -1
  20. package/dist/lib/runtime.js +1 -1
  21. package/dist/lib/watermark.d.ts +1 -1
  22. package/dist/locales/en-US.d.ts +62 -3
  23. package/dist/locales/en-US.js +66 -7
  24. package/dist/locales/en-US.js.map +1 -1
  25. package/dist/locales/kernelMenuTitles.js +2 -1
  26. package/dist/locales/kernelMenuTitles.js.map +1 -1
  27. package/dist/locales/zh-CN.d.ts +62 -3
  28. package/dist/locales/zh-CN.js +66 -7
  29. package/dist/locales/zh-CN.js.map +1 -1
  30. package/dist/router/viewRegistry.js +6 -6
  31. package/dist/router/viewRegistry.js.map +1 -1
  32. package/dist/style.css +1 -1
  33. package/dist/theme/naive-theme.js +72 -67
  34. package/dist/theme/naive-theme.js.map +1 -1
  35. package/dist/types/api.d.ts +91 -0
  36. package/dist/types/api.js +17 -15
  37. package/dist/types/api.js.map +1 -1
  38. package/dist/utils/shake.d.ts +1 -0
  39. package/dist/utils/shake.js +30 -0
  40. package/dist/utils/shake.js.map +1 -0
  41. package/dist/views/login/LoginForm.vue.js +2 -2
  42. package/dist/views/login/LoginForm2.vue.js +135 -135
  43. package/dist/views/login/LoginForm2.vue.js.map +1 -1
  44. package/dist/views/login/components/LoginDesk.vue.js +1 -1
  45. package/dist/views/login/components/LoginDesk2.vue.js +59 -47
  46. package/dist/views/login/components/LoginDesk2.vue.js.map +1 -1
  47. package/dist/views/personal/notice2.vue.js +1 -1
  48. package/dist/views/personal/notice2.vue.js.map +1 -1
  49. package/dist/views/personal/sessions.vue.js +2 -2
  50. package/dist/views/personal/sessions2.vue.js +41 -40
  51. package/dist/views/personal/sessions2.vue.js.map +1 -1
  52. package/dist/views/system/ai-usage/index.vue.js +3 -3
  53. package/dist/views/system/ai-usage/index2.vue.js +13 -12
  54. package/dist/views/system/ai-usage/index2.vue.js.map +1 -1
  55. package/dist/views/system/config/components/AdvancedSection.vue.js +3 -3
  56. package/dist/views/system/config/components/AdvancedSection2.vue.js +2 -1
  57. package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -1
  58. package/dist/views/system/dict/index.vue.js +2 -2
  59. package/dist/views/system/dict/index2.vue.js +12 -1
  60. package/dist/views/system/dict/index2.vue.js.map +1 -1
  61. package/dist/views/system/file/index2.vue.js +1 -0
  62. package/dist/views/system/file/index2.vue.js.map +1 -1
  63. package/dist/views/system/job/index.vue.js +3 -3
  64. package/dist/views/system/job/index2.vue.js +182 -181
  65. package/dist/views/system/job/index2.vue.js.map +1 -1
  66. package/dist/views/system/job-log/components/AttemptTable2.vue.js +8 -3
  67. package/dist/views/system/job-log/components/AttemptTable2.vue.js.map +1 -1
  68. package/dist/views/system/job-log/index.vue.js +1 -1
  69. package/dist/views/system/job-log/index2.vue.js +5 -5
  70. package/dist/views/system/job-log/index2.vue.js.map +1 -1
  71. package/dist/views/system/log/exception/index.vue.js +2 -2
  72. package/dist/views/system/log/exception/index2.vue.js +8 -5
  73. package/dist/views/system/log/exception/index2.vue.js.map +1 -1
  74. package/dist/views/system/log/login/index2.vue.js +21 -12
  75. package/dist/views/system/log/login/index2.vue.js.map +1 -1
  76. package/dist/views/system/log/op/index.vue.js +2 -2
  77. package/dist/views/system/log/op/index2.vue.js +50 -40
  78. package/dist/views/system/log/op/index2.vue.js.map +1 -1
  79. package/dist/views/system/menu/components/ButtonManager.vue.js +2 -2
  80. package/dist/views/system/menu/components/ButtonManager2.vue.js +45 -36
  81. package/dist/views/system/menu/components/ButtonManager2.vue.js.map +1 -1
  82. package/dist/views/system/menu/index.vue.js +2 -2
  83. package/dist/views/system/menu/index2.vue.js +11 -11
  84. package/dist/views/system/menu/index2.vue.js.map +1 -1
  85. package/dist/views/system/module/index.vue.js +1 -1
  86. package/dist/views/system/module/index2.vue.js +171 -117
  87. package/dist/views/system/module/index2.vue.js.map +1 -1
  88. package/dist/views/system/notice/index.vue.js +3 -3
  89. package/dist/views/system/notice/index2.vue.js +1 -0
  90. package/dist/views/system/notice/index2.vue.js.map +1 -1
  91. package/dist/views/system/org/index.vue.js +2 -2
  92. package/dist/views/system/org/index2.vue.js +70 -67
  93. package/dist/views/system/org/index2.vue.js.map +1 -1
  94. package/dist/views/system/position/index.vue.js +2 -2
  95. package/dist/views/system/position/index2.vue.js +57 -48
  96. package/dist/views/system/position/index2.vue.js.map +1 -1
  97. package/dist/views/system/recycle/index.vue.js +1 -1
  98. package/dist/views/system/recycle/index2.vue.js +3 -1
  99. package/dist/views/system/recycle/index2.vue.js.map +1 -1
  100. package/dist/views/system/role/components/GrantMenuSheet.vue.d.ts +2 -0
  101. package/dist/views/system/role/components/GrantMenuSheet.vue.js +2 -2
  102. package/dist/views/system/role/components/GrantMenuSheet2.vue.js +54 -49
  103. package/dist/views/system/role/components/GrantMenuSheet2.vue.js.map +1 -1
  104. package/dist/views/system/role/components/GrantMenuTable.vue.js +1 -1
  105. package/dist/views/system/role/components/GrantMenuTable2.vue.js +159 -195
  106. package/dist/views/system/role/components/GrantMenuTable2.vue.js.map +1 -1
  107. package/dist/views/system/role/components/grantMenuGroups.d.ts +54 -0
  108. package/dist/views/system/role/components/grantMenuGroups.js +116 -76
  109. package/dist/views/system/role/components/grantMenuGroups.js.map +1 -1
  110. package/dist/views/system/role/index.vue.js +2 -2
  111. package/dist/views/system/role/index2.vue.js +152 -145
  112. package/dist/views/system/role/index2.vue.js.map +1 -1
  113. package/dist/views/system/session/index2.vue.js +39 -35
  114. package/dist/views/system/session/index2.vue.js.map +1 -1
  115. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.d.ts +10 -0
  116. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.js +5 -0
  117. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.js.map +1 -0
  118. package/dist/views/system/user/components/UserGrantEffectiveTable2.vue.js +96 -0
  119. package/dist/views/system/user/components/UserGrantEffectiveTable2.vue.js.map +1 -0
  120. package/dist/views/system/user/components/UserGrantMenuSheet.vue.d.ts +13 -0
  121. package/dist/views/system/user/components/UserGrantMenuSheet.vue.js +8 -0
  122. package/dist/views/system/user/components/UserGrantMenuSheet.vue.js.map +1 -0
  123. package/dist/views/system/user/components/UserGrantMenuSheet2.vue.js +216 -0
  124. package/dist/views/system/user/components/UserGrantMenuSheet2.vue.js.map +1 -0
  125. package/dist/views/system/user/components/UserGrantMenuTable.vue.d.ts +13 -0
  126. package/dist/views/system/user/components/UserGrantMenuTable.vue.js +8 -0
  127. package/dist/views/system/user/components/UserGrantMenuTable.vue.js.map +1 -0
  128. package/dist/views/system/user/components/UserGrantMenuTable2.vue.js +186 -0
  129. package/dist/views/system/user/components/UserGrantMenuTable2.vue.js.map +1 -0
  130. package/dist/views/system/user/components/UserGrantNodeRow.vue.d.ts +31 -0
  131. package/dist/views/system/user/components/UserGrantNodeRow.vue.js +8 -0
  132. package/dist/views/system/user/components/UserGrantNodeRow.vue.js.map +1 -0
  133. package/dist/views/system/user/components/UserGrantNodeRow2.vue.js +171 -0
  134. package/dist/views/system/user/components/UserGrantNodeRow2.vue.js.map +1 -0
  135. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.d.ts +21 -0
  136. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.js +5 -0
  137. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.js.map +1 -0
  138. package/dist/views/system/user/components/UserGrantOverviewDrawer2.vue.js +178 -0
  139. package/dist/views/system/user/components/UserGrantOverviewDrawer2.vue.js.map +1 -0
  140. package/dist/views/system/user/components/userGrantState.d.ts +64 -0
  141. package/dist/views/system/user/components/userGrantState.js +117 -0
  142. package/dist/views/system/user/components/userGrantState.js.map +1 -0
  143. package/dist/views/system/user/index.vue.js +2 -2
  144. package/dist/views/system/user/index2.vue.js +250 -207
  145. package/dist/views/system/user/index2.vue.js.map +1 -1
  146. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm2.vue.js","sources":["../../../src/views/login/LoginForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { reactive, ref, computed, nextTick, onMounted, onBeforeUnmount, h } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n NAlert,\n NButton,\n NForm,\n NFormItem,\n NInput,\n NCheckbox,\n NModal,\n NDropdown,\n useMessage,\n type DropdownOption,\n} from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { authApi, externalAuthApi, ApiError } from '#/api'\nimport type { LoginOutput } from '#/types/api'\nimport { useUserStore } from '#/stores/user'\nimport { useAuthStore } from '#/stores/auth'\nimport { useSite } from '#/composables/useSite'\nimport { resetRouter } from '#/router'\nimport { translateError } from '#/utils/error'\nimport {\n splitLoginProviders,\n PREVIEW_ALL_SSO_BRANDS,\n previewAllBrandProviders,\n claimWeComAutoLogin,\n} from '#/utils/oauthBrand'\nimport SmartLogo from '#/components/SmartLogo.vue'\nimport { runtime } from '#/lib/runtime'\nimport BrandIcon from '#/components/oauth/BrandIcon.vue'\n\n// 双栏布局下品牌区在左栏,卡内不重复 logo/标题,改用「欢迎回来」问候语(showGreeting);\n// 版权页脚由外壳画在卡外(showFooter=false)。单栏时全部默认:卡内顶部是 logo + 站点标题,再是「登录」标题。\nwithDefaults(\n defineProps<{\n showLogo?: boolean\n showTitle?: boolean\n showGreeting?: boolean\n showFooter?: boolean\n }>(),\n {\n showLogo: true,\n showTitle: true,\n showGreeting: false,\n showFooter: true,\n },\n)\n// 登录成功、即将跳转时通知外壳播退场动画(true);跳转没发生时撤销(false),免得页面停在淡出态\nconst emit = defineEmits<{ leave: [on: boolean] }>()\n\nconst router = useRouter()\nconst route = useRoute()\nconst message = useMessage()\nconst { t } = useI18n()\nconst user = useUserStore()\nconst auth = useAuthStore()\nconst { site, appVersion, loadSite } = useSite()\nconst year = new Date().getFullYear()\n\n/** 未绑定 SSO 后带回:登录成功后须确认再 claim(防静默抢绑) */\nconst pendingLink = computed(() =>\n typeof route.query.pendingLink === 'string' ? route.query.pendingLink : '',\n)\nconst pendingProvider = computed(() =>\n typeof route.query.provider === 'string' ? route.query.provider : '',\n)\nconst pendingDisplayName = computed(() =>\n typeof route.query.displayName === 'string' ? route.query.displayName : '',\n)\nconst pendingConfirmShow = ref(false)\nconst pendingClaimBusy = ref(false)\nconst pendingClaimToken = ref('')\n\n// 开发态(createSmartAdmin({ dev }))预填超管账号密码,免得每次手敲;生产留空。\n// SSO pending-link 场景故意不预填密码:解绑后 GitHub 会落到本页,预填+一点就 claim 看起来像「SSO 直接进了」。\nconst model = reactive(\n runtime.dev && !pendingLink.value\n ? { account: 'superAdmin', password: 'Aa123456', remember: true }\n : {\n account: runtime.dev ? 'superAdmin' : '',\n password: '',\n remember: true,\n },\n)\nconst loading = ref(false)\n\n// 登录形态:账号密码 / 短信免密 / 短信二次验证(40009) / TOTP 二次验证(40018)\n// 强制 MFA 未绑定(40020)用 Modal 引导,不切 mode,登录页默认也不常驻绑定链接\nconst mode = ref<'account' | 'sms' | 'mfa' | 'totp'>('account')\n\n// 短信免密登录\nconst smsModel = reactive({ phone: '', code: '' })\n// 二次验证挑战(40009 信令 args 下发)\nconst mfa = reactive({ challengeId: '', phoneMask: '', code: '' })\n// TOTP 挑战(40018)\nconst totp = reactive({ challengeId: '', code: '' })\n// 强制 MFA 但未绑定(40020):弹窗 + 带到 /mfa/bind 的账号\nconst bindRequiredShow = ref(false)\nconst bindAccount = ref('')\n\n// 发码/重发共用倒计时(同一时刻只有一个发码入口可见)\nconst countdown = ref(0)\nlet timer: number | undefined\nfunction startCountdown(s: number) {\n countdown.value = s\n window.clearInterval(timer)\n timer = window.setInterval(() => {\n countdown.value -= 1\n if (countdown.value <= 0) window.clearInterval(timer)\n }, 1000)\n}\nonBeforeUnmount(() => window.clearInterval(timer))\n\n// 验证码:是否启用由匿名站点信息(sys.security.captcha.enabled)运行时驱动;启用才拉取并展示。\n// 账号模式护登录,短信模式护发码(发码端点防脚本滥用)。\nconst captchaEnabled = ref(false)\nconst captchaId = ref('')\nconst captchaSvg = ref('')\nconst captchaCode = ref('')\nconst captchaType = ref('char')\n\n// math 类型需算出结果再输入,提示语不同;其余类型统一“请输入验证码”。\nconst captchaHint = computed(() =>\n captchaType.value === 'math' ? t('login.captchaMathPlaceholder') : t('login.captchaPlaceholder'),\n)\n\nasync function loadCaptcha() {\n try {\n const c = await authApi.captcha()\n captchaId.value = c.captchaId\n captchaSvg.value = c.svg\n captchaType.value = c.type || 'char'\n } catch {\n // 拉取失败不阻塞登录页渲染;点击图形可重试\n }\n}\n\n/** 验证码一次性消费:任何用掉票据的请求失败后必刷新,避免复用作废票据 */\nasync function refreshCaptchaAfterUse() {\n if (captchaEnabled.value) {\n captchaCode.value = ''\n await loadCaptcha()\n }\n}\n\nonMounted(async () => {\n // 站点信息全站共用(useSite 去重);验证码开关据此运行时驱动,启用才拉图。\n await loadSite()\n if (site.captchaEnabled) {\n captchaEnabled.value = true\n await loadCaptcha()\n }\n void loadSsoProviders()\n\n // SSO 回调带回的 TOTP 挑战:直接进入 totp 完成态\n const q = router.currentRoute.value.query\n const ch = typeof q.totpChallenge === 'string' ? q.totpChallenge : ''\n if (ch) {\n totp.challengeId = ch\n totp.code = ''\n mode.value = 'totp'\n }\n})\n\n// 第三方登录:默认后端 providers 驱动;PREVIEW_ALL_SSO_BRANDS 时铺全品牌图(图标验收)。\nconst ssoProviders = ref<{ code: string; displayName: string; icon?: string | null }[]>([])\nconst pendingProviderLabel = computed(() => {\n const code = pendingProvider.value\n if (!code) return t('oauth.thirdParty')\n const hit = ssoProviders.value.find(p => p.code === code)\n return hit?.displayName || code\n})\nconst ssoDisplayList = computed(() =>\n PREVIEW_ALL_SSO_BRANDS ? previewAllBrandProviders() : ssoProviders.value,\n)\n// 预览全图标时不截断;正常模式 N=4 溢出\nconst ssoSplit = computed(() =>\n PREVIEW_ALL_SSO_BRANDS\n ? { visible: ssoDisplayList.value, overflow: [] as typeof ssoDisplayList.value }\n : splitLoginProviders(ssoDisplayList.value),\n)\nconst ssoOverflowOptions = computed<DropdownOption[]>(() =>\n ssoSplit.value.overflow.map(p => ({\n key: p.code,\n label: () =>\n h(\n 'span',\n {\n class: 'lf-sso-menu-item',\n style: { display: 'inline-flex', alignItems: 'center', gap: '8px' },\n },\n [h(BrandIcon, { code: p.code, icon: p.icon, size: 20 }), h('span', null, p.displayName)],\n ),\n })),\n)\nasync function loadSsoProviders() {\n try {\n ssoProviders.value = await externalAuthApi.providers()\n } catch {\n // 未配置外部登录或拉取失败:整段 SSO 区不显(预览全图标模式仍会显示)\n return\n }\n // 企业微信客户端里直接走企业微信登录;SSO 带回来的认领 / 二次验证要留在本页完成\n const q = route.query\n if (\n !q.pendingLink &&\n !q.totpChallenge &&\n claimWeComAutoLogin({\n userAgent: navigator.userAgent,\n providers: ssoProviders.value,\n storage: sessionStorage,\n })\n ) {\n window.location.href = ssoHref('wecom')\n }\n}\n/** 顶层跳 IdP(与 Gitee 一样用 <a href>)。预览假项仍给 authorize 链,未配后端会失败。 */\nfunction ssoHref(code: string) {\n return externalAuthApi.authorizeUrl(code)\n}\nfunction onSsoOverflow(key: string | number) {\n window.location.href = ssoHref(String(key))\n}\n\nasync function enterHome() {\n await router.replace('/')\n}\n\n// 密码错 / 验证码错:表单左右抖一下(macOS 登录框的做法),比只弹 toast 更直接。\n// 先摘掉 class、等一帧再加,连续失败也能重播。\nconst shaking = ref(false)\nasync function shake() {\n shaking.value = false\n await nextTick()\n requestAnimationFrame(() => {\n shaking.value = true\n })\n}\n\n// 登录成功的收尾:先让页面淡出,再跳转。系统开了「减少动态效果」就不等。\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nasync function leaveThenEnter() {\n emit('leave', true)\n if (!window.matchMedia?.(REDUCED_MOTION).matches) {\n await new Promise<void>(resolve => setTimeout(resolve, 320))\n }\n await enterHome()\n emit('leave', false)\n}\n\nasync function finishLogin(res: LoginOutput) {\n // 每次登录都清动态路由/授权态,否则上次会话的 routesReady=true 会跳过 enterInitial,\n // 菜单壳在、业务路由未重建 → 进系统后处处 404(绑定 MFA 后回登录再登最易踩中)。\n resetRouter()\n auth.reset()\n user.setSession(res)\n\n // 现场绑定:不静默 claim——须用户确认,并依赖服务端 binder cookie 同浏览器校验\n const link = pendingLink.value\n if (link) {\n pendingClaimToken.value = link\n pendingConfirmShow.value = true\n return\n }\n message.success(t('login.success'))\n await leaveThenEnter()\n}\n\nconst pendingConfirmIdentity = computed(() =>\n pendingDisplayName.value\n ? t('oauth.pendingLinkIdentity', { display: pendingDisplayName.value })\n : '',\n)\n\nasync function confirmPendingBind() {\n if (pendingClaimBusy.value) return\n pendingClaimBusy.value = true\n try {\n await externalAuthApi.claimPendingLink(pendingClaimToken.value)\n message.success(t('oauth.pendingLinkSuccess', { name: pendingProviderLabel.value }))\n } catch (e) {\n message.warning(translateError(e))\n } finally {\n pendingClaimBusy.value = false\n pendingConfirmShow.value = false\n pendingClaimToken.value = ''\n }\n await enterHome()\n}\n\nasync function skipPendingBind() {\n pendingConfirmShow.value = false\n pendingClaimToken.value = ''\n message.success(t('login.success'))\n await enterHome()\n}\n\nasync function onSubmit() {\n if (mode.value === 'mfa') return onMfaSubmit()\n if (mode.value === 'totp') return onTotpSubmit()\n if (mode.value === 'sms') return onSmsSubmit()\n\n if (!model.account || !model.password) {\n message.warning(t('login.required'))\n return\n }\n if (captchaEnabled.value && !captchaCode.value) {\n message.warning(t('login.captchaRequired'))\n return\n }\n loading.value = true\n try {\n const res = await authApi.login({\n account: model.account,\n password: model.password,\n ...(captchaEnabled.value\n ? { captchaId: captchaId.value, captchaCode: captchaCode.value }\n : {}),\n })\n await finishLogin(res)\n } catch (e) {\n // 40018 = 密码已过、需 TOTP 二次验证\n if (e instanceof ApiError && e.code === 40018 && e.args) {\n totp.challengeId = String(e.args.challengeId ?? '')\n totp.code = ''\n mode.value = 'totp'\n } else if (e instanceof ApiError && e.code === 40020) {\n // 40020 = 强制 MFA 未绑定 → Modal 引导自助设置(登录页默认不常驻链接)\n bindAccount.value = model.account.trim()\n bindRequiredShow.value = true\n } else if (e instanceof ApiError && e.code === 40009 && e.args) {\n // 40009 = 密码已过、需短信二次验证\n mfa.challengeId = String(e.args.challengeId ?? '')\n mfa.phoneMask = String(e.args.phoneMask ?? '')\n mfa.code = ''\n mode.value = 'mfa'\n startCountdown(Number(e.args.resendSeconds ?? 60))\n } else {\n message.error(translateError(e))\n void shake()\n }\n await refreshCaptchaAfterUse()\n } finally {\n loading.value = false\n }\n}\n\nfunction closeBindRequired() {\n bindRequiredShow.value = false\n}\n\nfunction goBindAuthenticator() {\n const account = bindAccount.value || model.account.trim()\n bindRequiredShow.value = false\n void router.push({ path: '/mfa/bind', query: account ? { account } : {} })\n}\n\nfunction goRecovery() {\n const account = model.account.trim() || bindAccount.value\n void router.push({\n path: '/mfa/bind',\n query: { ...(account ? { account } : {}), mode: 'recovery' },\n })\n}\n\nasync function onMfaSubmit() {\n if (!mfa.code) {\n message.warning(t('login.smsCodePlaceholder'))\n return\n }\n loading.value = true\n try {\n await finishLogin(\n await authApi.smsChallengeLogin({ challengeId: mfa.challengeId, code: mfa.code }),\n )\n } catch (e) {\n message.error(translateError(e))\n void shake()\n } finally {\n loading.value = false\n }\n}\n\nasync function onTotpSubmit() {\n if (!totp.code) {\n message.warning(t('login.totpPlaceholder'))\n return\n }\n loading.value = true\n try {\n await finishLogin(\n await authApi.totpChallengeLogin({ challengeId: totp.challengeId, code: totp.code }),\n )\n } catch (e) {\n message.error(translateError(e))\n void shake()\n } finally {\n loading.value = false\n }\n}\n\nasync function onMfaResend() {\n if (countdown.value > 0) return\n try {\n const r = await authApi.smsChallengeResend({ challengeId: mfa.challengeId })\n message.success(t('login.smsSent'))\n startCountdown(r.resendSeconds)\n } catch (e) {\n message.error(translateError(e))\n }\n}\n\nfunction backToAccount() {\n mode.value = 'account'\n mfa.challengeId = ''\n mfa.code = ''\n totp.challengeId = ''\n totp.code = ''\n}\n\nasync function onSendSmsCode() {\n if (countdown.value > 0) return\n if (!smsModel.phone) {\n message.warning(t('login.phonePlaceholder'))\n return\n }\n if (captchaEnabled.value && !captchaCode.value) {\n message.warning(t('login.captchaRequired'))\n return\n }\n try {\n const r = await authApi.smsLoginSend({\n phone: smsModel.phone,\n ...(captchaEnabled.value\n ? { captchaId: captchaId.value, captchaCode: captchaCode.value }\n : {}),\n })\n message.success(t('login.smsSent'))\n startCountdown(r.resendSeconds)\n } catch (e) {\n message.error(translateError(e))\n }\n await refreshCaptchaAfterUse()\n}\n\nasync function onSmsSubmit() {\n if (!smsModel.phone || !smsModel.code) {\n message.warning(t('login.smsRequired'))\n return\n }\n loading.value = true\n try {\n await finishLogin(await authApi.smsLogin({ phone: smsModel.phone, code: smsModel.code }))\n } catch (e) {\n message.error(translateError(e))\n void shake()\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<template>\n <div class=\"login-form\" :class=\"{ shake: shaking }\" @animationend.self=\"shaking = false\">\n <div v-if=\"showLogo\" class=\"lf-brand\">\n <!-- 站点 logo 的取值顺序(配置 → brand 选项 → 内置矢量标)统一在 SmartLogo 里 -->\n <SmartLogo :size=\"34\" />\n <span class=\"lf-word\">{{ site.title }}</span>\n </div>\n\n <n-alert\n v-if=\"pendingLink\"\n type=\"info\"\n :bordered=\"false\"\n class=\"lf-pending-alert\"\n :title=\"t('oauth.pendingLinkTitle', { name: pendingProviderLabel })\"\n >\n {{ t('oauth.pendingLinkHint', { name: pendingProviderLabel }) }}\n </n-alert>\n\n <!-- 登录方式切换:旧内容先淡出上移,新内容的逐项浮现由外壳(LoginDesk)的入场动画负责 -->\n <Transition name=\"lf-swap\" mode=\"out-in\">\n <div :key=\"mode\" class=\"lf-body\">\n <!-- 短信二次验证:密码已过,凭挑战 + 短信码完成登录 -->\n <template v-if=\"mode === 'mfa'\">\n <h2 v-if=\"showTitle || showGreeting\" class=\"lf-title\">\n {{ t('login.mfaTitle', { phone: mfa.phoneMask }) }}\n </h2>\n <p class=\"lf-hint-line\">{{ t('login.mfaSub') }}</p>\n <n-form :show-feedback=\"false\" @keyup.enter=\"onSubmit\">\n <n-form-item :label=\"t('login.smsCode')\" path=\"code\">\n <n-input\n v-model:value=\"mfa.code\"\n :placeholder=\"t('login.smsCodePlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:chat-circle-text\" /></template>\n </n-input>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-button text type=\"primary\" @click=\"backToAccount\">\n {{ t('login.backToPassword') }}\n </n-button>\n <n-button\n text\n :type=\"countdown > 0 ? 'default' : 'primary'\"\n :disabled=\"countdown > 0\"\n @click=\"onMfaResend\"\n >\n {{ countdown > 0 ? t('login.resendAfter', { s: countdown }) : t('login.sendCode') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n </template>\n\n <!-- TOTP 二次验证:密码已过,凭 Authenticator 动态口令完成登录 -->\n <template v-else-if=\"mode === 'totp'\">\n <h2 v-if=\"showTitle || showGreeting\" class=\"lf-title\">{{ t('login.totpTitle') }}</h2>\n <p class=\"lf-hint-line\">{{ t('login.totpSub') }}</p>\n <n-form :show-feedback=\"false\" @keyup.enter=\"onSubmit\">\n <n-form-item :label=\"t('login.totpCode')\" path=\"code\">\n <n-input\n v-model:value=\"totp.code\"\n :placeholder=\"t('login.totpPlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:shield-check\" /></template>\n </n-input>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-button text type=\"primary\" @click=\"backToAccount\">\n {{ t('login.backToPassword') }}\n </n-button>\n <n-button text type=\"primary\" @click=\"goRecovery\">\n {{ t('login.useRecovery') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n </template>\n\n <template v-else>\n <!-- 单栏:卡内标题「登录」;双栏:品牌在左栏,这里是问候语 -->\n <h2 v-if=\"showTitle\" class=\"lf-title\">{{ t('login.title') }}</h2>\n <div v-else-if=\"showGreeting\" class=\"lf-greet\">\n <h1>{{ t('login.welcome') }}</h1>\n <p>{{ t('login.welcomeSub') }}</p>\n </div>\n <n-form\n :model=\"mode === 'account' ? model : smsModel\"\n :show-feedback=\"false\"\n @keyup.enter=\"onSubmit\"\n >\n <template v-if=\"mode === 'account'\">\n <n-form-item :label=\"t('login.account')\" path=\"account\">\n <n-input\n v-model:value=\"model.account\"\n :placeholder=\"t('login.accountPlaceholder')\"\n size=\"large\"\n >\n <template #prefix><Icon icon=\"ph:user\" /></template>\n </n-input>\n </n-form-item>\n <n-form-item :label=\"t('login.password')\" path=\"password\">\n <n-input\n v-model:value=\"model.password\"\n type=\"password\"\n show-password-on=\"click\"\n :placeholder=\"t('login.passwordPlaceholder')\"\n size=\"large\"\n >\n <template #prefix><Icon icon=\"ph:lock\" /></template>\n </n-input>\n </n-form-item>\n </template>\n <template v-else>\n <n-form-item :label=\"t('login.phone')\" path=\"phone\">\n <n-input\n v-model:value=\"smsModel.phone\"\n :placeholder=\"t('login.phonePlaceholder')\"\n size=\"large\"\n :maxlength=\"20\"\n >\n <template #prefix><Icon icon=\"ph:device-mobile\" /></template>\n </n-input>\n </n-form-item>\n </template>\n <n-form-item v-if=\"captchaEnabled\" :label=\"t('login.captcha')\" path=\"captcha\">\n <div class=\"lf-captcha\">\n <n-input\n v-model:value=\"captchaCode\"\n :placeholder=\"captchaHint\"\n size=\"large\"\n @keyup.enter=\"onSubmit\"\n >\n <template #prefix><Icon icon=\"ph:shield-check\" /></template>\n </n-input>\n <!-- SVG 来自本站后端;点击重取一张(一次性票据);取图失败时图形位为空,点击重试 -->\n <button\n type=\"button\"\n class=\"lf-captcha-img\"\n :class=\"{ empty: !captchaSvg }\"\n :title=\"t('login.captchaPlaceholder')\"\n :aria-label=\"t('login.captchaPlaceholder')\"\n @click=\"loadCaptcha\"\n v-html=\"captchaSvg\"\n />\n </div>\n </n-form-item>\n <n-form-item v-if=\"mode === 'sms'\" :label=\"t('login.smsCode')\" path=\"code\">\n <div class=\"lf-captcha\">\n <n-input\n v-model:value=\"smsModel.code\"\n :placeholder=\"t('login.smsCodePlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:chat-circle-text\" /></template>\n </n-input>\n <n-button\n class=\"lf-send-btn\"\n secondary\n size=\"large\"\n attr-type=\"button\"\n :disabled=\"countdown > 0\"\n @click=\"onSendSmsCode\"\n >\n {{\n countdown > 0 ? t('login.resendAfter', { s: countdown }) : t('login.sendCode')\n }}\n </n-button>\n </div>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-checkbox v-if=\"mode === 'account'\" v-model:checked=\"model.remember\">\n {{ t('login.remember') }}\n </n-checkbox>\n <span v-else />\n <n-button\n v-if=\"site.smsLoginEnabled\"\n text\n type=\"primary\"\n @click=\"mode = mode === 'account' ? 'sms' : 'account'\"\n >\n {{ mode === 'account' ? t('login.smsLogin') : t('login.accountLogin') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n\n <!-- 第三方登录:圆形品牌标;<a href>。PREVIEW_ALL_SSO_BRANDS 时展示全部品牌图。 -->\n <template v-if=\"ssoDisplayList.length\">\n <div class=\"lf-divider\">\n <span>{{ t('login.otherMethods') }}</span>\n </div>\n <div class=\"lf-sso\">\n <a\n v-for=\"p in ssoSplit.visible\"\n :key=\"p.code\"\n class=\"lf-sso-btn\"\n :href=\"ssoHref(p.code)\"\n :title=\"p.displayName\"\n :aria-label=\"p.displayName\"\n >\n <BrandIcon :code=\"p.code\" :icon=\"p.icon\" :size=\"28\" />\n </a>\n <n-dropdown\n v-if=\"ssoSplit.overflow.length\"\n trigger=\"click\"\n :options=\"ssoOverflowOptions\"\n @select=\"onSsoOverflow\"\n >\n <a\n class=\"lf-sso-btn lf-sso-more\"\n href=\"javascript:void(0)\"\n role=\"button\"\n :title=\"t('login.moreMethods')\"\n :aria-label=\"t('login.moreMethods')\"\n @click.prevent\n >\n <Icon icon=\"ph:dots-three\" :width=\"18\" />\n </a>\n </n-dropdown>\n </div>\n </template>\n </template>\n </div>\n </Transition>\n\n <!-- 页脚:版权(可选链接)+ 构建期版本号。双栏时外壳在卡外自绘页脚,传 :show-footer=\"false\" 关掉。 -->\n <footer v-if=\"showFooter\" class=\"lf-foot\">\n <span>\n © {{ year }}\n <a v-if=\"site.copyrightUrl\" :href=\"site.copyrightUrl\" target=\"_blank\" rel=\"noopener\">\n {{ site.copyright || site.title }}\n </a>\n <template v-else>{{ site.copyright || site.title }}</template>\n </span>\n <span v-if=\"appVersion\" class=\"lf-ver\">v{{ appVersion }}</span>\n </footer>\n\n <!-- 强制 MFA 未绑定(40020):遮罩 Modal,账密表单仍在底下;默认登录页不常驻绑定链接 -->\n <n-modal\n v-model:show=\"bindRequiredShow\"\n preset=\"dialog\"\n type=\"warning\"\n :title=\"t('login.totpBindTitle')\"\n :content=\"t('login.totpBindSub')\"\n :positive-text=\"t('login.setupAuthenticator')\"\n :negative-text=\"t('common.cancel')\"\n @positive-click=\"goBindAuthenticator\"\n @negative-click=\"closeBindRequired\"\n />\n <!-- pending-link:登录后显式确认绑定,防静默抢绑 -->\n <n-modal\n v-model:show=\"pendingConfirmShow\"\n preset=\"dialog\"\n type=\"info\"\n :title=\"t('oauth.pendingLinkConfirmTitle')\"\n :content=\"\n t('oauth.pendingLinkConfirmContent', {\n name: pendingProviderLabel,\n identity: pendingConfirmIdentity,\n account: user.userInfo?.account ?? '',\n })\n \"\n :positive-text=\"t('oauth.pendingLinkConfirmOk')\"\n :negative-text=\"t('oauth.pendingLinkConfirmSkip')\"\n :loading=\"pendingClaimBusy\"\n :closable=\"false\"\n :mask-closable=\"false\"\n @positive-click=\"confirmPendingBind\"\n @negative-click=\"skipPendingBind\"\n />\n </div>\n</template>\n\n<style scoped>\n.login-form {\n width: 100%;\n}\n/* 登录失败:左右抖一下并逐渐收住(macOS 登录框的做法),不回弹到别处 */\n.login-form.shake {\n animation: lf-shake 0.46s cubic-bezier(0.36, 0.07, 0.19, 0.97);\n}\n@keyframes lf-shake {\n 0%,\n 100% {\n transform: none;\n }\n 15% {\n transform: translate3d(-9px, 0, 0);\n }\n 30% {\n transform: translate3d(8px, 0, 0);\n }\n 45% {\n transform: translate3d(-6px, 0, 0);\n }\n 60% {\n transform: translate3d(4px, 0, 0);\n }\n 80% {\n transform: translate3d(-2px, 0, 0);\n }\n}\n/* 登录方式切换:旧内容淡出并轻微上移变虚 */\n.lf-swap-leave-active {\n transition:\n opacity 0.16s ease-in,\n transform 0.16s ease-in,\n filter 0.16s ease-in;\n}\n.lf-swap-leave-to {\n opacity: 0;\n transform: translate3d(0, -6px, 0);\n filter: blur(4px);\n}\n@media (prefers-reduced-motion: reduce) {\n .login-form.shake {\n animation: none;\n }\n}\n.lf-pending-alert {\n margin-bottom: 16px;\n border-radius: var(--radius-md);\n text-align: left;\n}\n/* 单栏卡内顶部:站点 logo + 标题。logo 取值顺序见 SmartLogo */\n.lf-brand {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 18px;\n}\n.lf-word {\n font-size: 22px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--text-1);\n}\n.lf-title {\n font-size: 20px;\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 1.3;\n margin: 0 0 16px;\n color: var(--text-1);\n}\n/* 双栏卡内问候语 */\n.lf-greet {\n text-align: center;\n margin: 2px 0 20px;\n}\n.lf-greet h1 {\n font-size: 26px;\n font-weight: 600;\n letter-spacing: -0.035em;\n margin: 0 0 4px;\n color: var(--text-1);\n}\n.lf-greet p {\n margin: 0;\n font-size: 13.5px;\n color: var(--text-3);\n}\n/* 二次验证副标题:标题下的弱化说明行 */\n.lf-hint-line {\n margin: -8px 0 18px;\n font-size: 13px;\n color: var(--text-3);\n}\n/* 表单项之间的间距(表单关了反馈行,没有校验规则要显示) */\n.login-form :deep(.n-form-item) {\n margin-bottom: 14px;\n}\n.row {\n margin: 2px 0 14px;\n min-height: 32px;\n}\n.lf-between {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n.lf-between > :deep(.n-button) {\n height: 32px;\n padding: 0 2px;\n}\n/* 验证码:输入框 + 可点击刷新的 SVG 图形(等高对齐) */\n.lf-captcha {\n display: flex;\n gap: 10px;\n width: 100%;\n align-items: stretch;\n}\n.lf-captcha > :deep(.n-input) {\n flex: 1;\n min-width: 0;\n}\n.lf-captcha-img {\n flex: none;\n height: 42px;\n min-width: 100px;\n padding: 0;\n border: 1px solid var(--hairline);\n border-radius: var(--radius-md);\n background: #fff;\n cursor: pointer;\n overflow: hidden;\n display: grid;\n place-items: center;\n line-height: 0;\n}\n/* 取图失败时图形位为空:换成输入框同款底色,否则空白框像 bug;点击重试 */\n.lf-captcha-img.empty {\n background: var(--fill);\n}\n.lf-captcha-img:focus-visible {\n outline: 2px solid var(--signal);\n outline-offset: 2px;\n}\n.lf-captcha-img :deep(svg) {\n display: block;\n height: 40px;\n width: auto;\n}\n/* 发码按钮:与验证码图形同尺寸位 */\n.lf-send-btn {\n flex: none;\n min-width: 104px;\n}\n/* 第三方登录:分隔线 + 圆形品牌标 */\n.lf-divider {\n display: flex;\n align-items: center;\n gap: 14px;\n margin: 22px 0 14px;\n}\n.lf-divider::before,\n.lf-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--hairline);\n}\n.lf-divider span {\n font-size: 13px;\n color: var(--text-3);\n}\n.lf-sso {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 12px;\n}\n/* 第三方登录:只露品牌标本身,不加灰底 / 描边 / 圆形裁切(会吃掉品牌标的轮廓);\n 40px 是点击热区,hover 才浮出一层极淡的圆角底,macOS 工具栏按钮的做法 */\n.lf-sso-btn {\n width: 40px;\n height: 40px;\n padding: 0;\n display: inline-grid;\n place-items: center;\n flex: none;\n border: none;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--text-1);\n text-decoration: none;\n cursor: pointer;\n transition: background var(--transition-base);\n}\n.lf-sso-btn :deep(.oauth-brand-badge) {\n width: 28px;\n height: 28px;\n}\n.lf-sso-btn:hover {\n background: var(--hover);\n color: var(--text-1);\n text-decoration: none;\n}\n.lf-sso-btn:active {\n background: var(--pressed);\n}\n.lf-sso-btn:focus-visible {\n outline: 2px solid var(--signal);\n outline-offset: 2px;\n}\n/* 页脚:版权 + 版本号,弱化色 */\n.lf-foot {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n margin-top: 20px;\n font-size: 13px;\n color: var(--text-3);\n}\n.lf-foot a {\n color: inherit;\n text-decoration: none;\n}\n.lf-foot a:hover {\n color: var(--signal);\n}\n.lf-ver {\n opacity: 0.75;\n}\n@media (max-width: 480px) {\n .lf-captcha-img {\n min-width: 92px;\n }\n}\n</style>\n"],"names":["REDUCED_MOTION","emit","__emit","router","useRouter","route","useRoute","message","useMessage","t","useI18n","user","useUserStore","auth","useAuthStore","site","appVersion","loadSite","useSite","year","pendingLink","computed","pendingProvider","pendingDisplayName","pendingConfirmShow","ref","pendingClaimBusy","pendingClaimToken","model","reactive","runtime","loading","mode","smsModel","mfa","totp","bindRequiredShow","bindAccount","countdown","timer","startCountdown","s","onBeforeUnmount","captchaEnabled","captchaId","captchaSvg","captchaCode","captchaType","captchaHint","loadCaptcha","c","authApi","refreshCaptchaAfterUse","onMounted","loadSsoProviders","q","ch","ssoProviders","pendingProviderLabel","code","hit","p","ssoDisplayList","ssoSplit","splitLoginProviders","ssoOverflowOptions","h","BrandIcon","externalAuthApi","claimWeComAutoLogin","ssoHref","onSsoOverflow","key","enterHome","shaking","shake","nextTick","leaveThenEnter","_a","resolve","finishLogin","res","resetRouter","link","pendingConfirmIdentity","confirmPendingBind","e","translateError","skipPendingBind","onSubmit","onMfaSubmit","onTotpSubmit","onSmsSubmit","ApiError","closeBindRequired","goBindAuthenticator","account","goRecovery","onMfaResend","r","backToAccount","onSendSmsCode","_createElementBlock","_normalizeClass","__props","_openBlock","_hoisted_1","_createVNode","SmartLogo","_createElementVNode","_hoisted_2","_toDisplayString","_unref","_createBlock","NAlert","_createTextVNode","_Transition","_Fragment","_hoisted_3","_hoisted_4","NForm","NFormItem","NInput","_cache","$event","Icon","_hoisted_5","NButton","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_13","_hoisted_14","NCheckbox","_hoisted_15","_hoisted_16","_hoisted_17","_renderList","NDropdown","_hoisted_20","_hoisted_21","_hoisted_22","NModal"],"mappings":"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"}
1
+ {"version":3,"file":"LoginForm2.vue.js","sources":["../../../src/views/login/LoginForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { reactive, ref, computed, onMounted, onBeforeUnmount, h } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n NAlert,\n NButton,\n NForm,\n NFormItem,\n NInput,\n NCheckbox,\n NModal,\n NDropdown,\n useMessage,\n type DropdownOption,\n} from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { authApi, externalAuthApi, ApiError } from '#/api'\nimport type { LoginOutput } from '#/types/api'\nimport { useUserStore } from '#/stores/user'\nimport { useAuthStore } from '#/stores/auth'\nimport { useSite } from '#/composables/useSite'\nimport { resetRouter } from '#/router'\nimport { translateError } from '#/utils/error'\nimport { shake } from '#/utils/shake'\nimport {\n splitLoginProviders,\n PREVIEW_ALL_SSO_BRANDS,\n previewAllBrandProviders,\n claimWeComAutoLogin,\n} from '#/utils/oauthBrand'\nimport SmartLogo from '#/components/SmartLogo.vue'\nimport { runtime } from '#/lib/runtime'\nimport BrandIcon from '#/components/oauth/BrandIcon.vue'\n\n// 双栏布局下品牌区在左栏,卡内不重复 logo/标题,改用「欢迎回来」问候语(showGreeting);\n// 版权页脚由外壳画在卡外(showFooter=false)。单栏时全部默认:卡内顶部是 logo + 站点标题,再是「登录」标题。\nwithDefaults(\n defineProps<{\n showLogo?: boolean\n showTitle?: boolean\n showGreeting?: boolean\n showFooter?: boolean\n }>(),\n {\n showLogo: true,\n showTitle: true,\n showGreeting: false,\n showFooter: true,\n },\n)\n// 登录成功、即将跳转时通知外壳播退场动画(true);跳转没发生时撤销(false),免得页面停在淡出态\nconst emit = defineEmits<{ leave: [on: boolean] }>()\n\nconst router = useRouter()\nconst route = useRoute()\nconst message = useMessage()\nconst { t } = useI18n()\nconst user = useUserStore()\nconst auth = useAuthStore()\nconst { site, appVersion, loadSite } = useSite()\nconst year = new Date().getFullYear()\n\n/** 未绑定 SSO 后带回:登录成功后须确认再 claim(防静默抢绑) */\nconst pendingLink = computed(() =>\n typeof route.query.pendingLink === 'string' ? route.query.pendingLink : '',\n)\nconst pendingProvider = computed(() =>\n typeof route.query.provider === 'string' ? route.query.provider : '',\n)\nconst pendingDisplayName = computed(() =>\n typeof route.query.displayName === 'string' ? route.query.displayName : '',\n)\nconst pendingConfirmShow = ref(false)\nconst pendingClaimBusy = ref(false)\nconst pendingClaimToken = ref('')\n\n// 开发态(createSmartAdmin({ dev }))预填超管账号密码,免得每次手敲;生产留空。\n// SSO pending-link 场景故意不预填密码:解绑后 GitHub 会落到本页,预填+一点就 claim 看起来像「SSO 直接进了」。\nconst model = reactive(\n runtime.dev && !pendingLink.value\n ? { account: 'superAdmin', password: 'Aa123456', remember: true }\n : {\n account: runtime.dev ? 'superAdmin' : '',\n password: '',\n remember: true,\n },\n)\nconst loading = ref(false)\n\n// 登录形态:账号密码 / 短信免密 / 短信二次验证(40009) / TOTP 二次验证(40018)\n// 强制 MFA 未绑定(40020)用 Modal 引导,不切 mode,登录页默认也不常驻绑定链接\nconst mode = ref<'account' | 'sms' | 'mfa' | 'totp'>('account')\n\n// 短信免密登录\nconst smsModel = reactive({ phone: '', code: '' })\n// 二次验证挑战(40009 信令 args 下发)\nconst mfa = reactive({ challengeId: '', phoneMask: '', code: '' })\n// TOTP 挑战(40018)\nconst totp = reactive({ challengeId: '', code: '' })\n// 强制 MFA 但未绑定(40020):弹窗 + 带到 /mfa/bind 的账号\nconst bindRequiredShow = ref(false)\nconst bindAccount = ref('')\n\n// 发码/重发共用倒计时(同一时刻只有一个发码入口可见)\nconst countdown = ref(0)\nlet timer: number | undefined\nfunction startCountdown(s: number) {\n countdown.value = s\n window.clearInterval(timer)\n timer = window.setInterval(() => {\n countdown.value -= 1\n if (countdown.value <= 0) window.clearInterval(timer)\n }, 1000)\n}\nonBeforeUnmount(() => window.clearInterval(timer))\n\n// 验证码:是否启用由匿名站点信息(sys.security.captcha.enabled)运行时驱动;启用才拉取并展示。\n// 账号模式护登录,短信模式护发码(发码端点防脚本滥用)。\nconst captchaEnabled = ref(false)\nconst captchaId = ref('')\nconst captchaSvg = ref('')\nconst captchaCode = ref('')\nconst captchaType = ref('char')\n\n// math 类型需算出结果再输入,提示语不同;其余类型统一“请输入验证码”。\nconst captchaHint = computed(() =>\n captchaType.value === 'math' ? t('login.captchaMathPlaceholder') : t('login.captchaPlaceholder'),\n)\n\nasync function loadCaptcha() {\n try {\n const c = await authApi.captcha()\n captchaId.value = c.captchaId\n captchaSvg.value = c.svg\n captchaType.value = c.type || 'char'\n } catch {\n // 拉取失败不阻塞登录页渲染;点击图形可重试\n }\n}\n\n/** 验证码一次性消费:任何用掉票据的请求失败后必刷新,避免复用作废票据 */\nasync function refreshCaptchaAfterUse() {\n if (captchaEnabled.value) {\n captchaCode.value = ''\n await loadCaptcha()\n }\n}\n\nonMounted(async () => {\n // 站点信息全站共用(useSite 去重);验证码开关据此运行时驱动,启用才拉图。\n await loadSite()\n if (site.captchaEnabled) {\n captchaEnabled.value = true\n await loadCaptcha()\n }\n void loadSsoProviders()\n\n // SSO 回调带回的 TOTP 挑战:直接进入 totp 完成态\n const q = router.currentRoute.value.query\n const ch = typeof q.totpChallenge === 'string' ? q.totpChallenge : ''\n if (ch) {\n totp.challengeId = ch\n totp.code = ''\n mode.value = 'totp'\n }\n})\n\n// 第三方登录:默认后端 providers 驱动;PREVIEW_ALL_SSO_BRANDS 时铺全品牌图(图标验收)。\nconst ssoProviders = ref<{ code: string; displayName: string; icon?: string | null }[]>([])\nconst pendingProviderLabel = computed(() => {\n const code = pendingProvider.value\n if (!code) return t('oauth.thirdParty')\n const hit = ssoProviders.value.find(p => p.code === code)\n return hit?.displayName || code\n})\nconst ssoDisplayList = computed(() =>\n PREVIEW_ALL_SSO_BRANDS ? previewAllBrandProviders() : ssoProviders.value,\n)\n// 预览全图标时不截断;正常模式 N=4 溢出\nconst ssoSplit = computed(() =>\n PREVIEW_ALL_SSO_BRANDS\n ? { visible: ssoDisplayList.value, overflow: [] as typeof ssoDisplayList.value }\n : splitLoginProviders(ssoDisplayList.value),\n)\nconst ssoOverflowOptions = computed<DropdownOption[]>(() =>\n ssoSplit.value.overflow.map(p => ({\n key: p.code,\n label: () =>\n h(\n 'span',\n {\n class: 'lf-sso-menu-item',\n style: { display: 'inline-flex', alignItems: 'center', gap: '8px' },\n },\n [h(BrandIcon, { code: p.code, icon: p.icon, size: 20 }), h('span', null, p.displayName)],\n ),\n })),\n)\nasync function loadSsoProviders() {\n try {\n ssoProviders.value = await externalAuthApi.providers()\n } catch {\n // 未配置外部登录或拉取失败:整段 SSO 区不显(预览全图标模式仍会显示)\n return\n }\n // 企业微信客户端里直接走企业微信登录;SSO 带回来的认领 / 二次验证要留在本页完成\n const q = route.query\n if (\n !q.pendingLink &&\n !q.totpChallenge &&\n claimWeComAutoLogin({\n userAgent: navigator.userAgent,\n providers: ssoProviders.value,\n storage: sessionStorage,\n })\n ) {\n window.location.href = ssoHref('wecom')\n }\n}\n/** 顶层跳 IdP(与 Gitee 一样用 <a href>)。预览假项仍给 authorize 链,未配后端会失败。 */\nfunction ssoHref(code: string) {\n return externalAuthApi.authorizeUrl(code)\n}\nfunction onSsoOverflow(key: string | number) {\n window.location.href = ssoHref(String(key))\n}\n\nasync function enterHome() {\n await router.replace('/')\n}\n\n// 密码错 / 验证码错:表单左右抖一下(macOS 登录框的做法),比只弹 toast 更直接。\n// 动画细节与「为什么不用 CSS class」见 utils/shake。\nconst formEl = ref<HTMLElement>()\nfunction shakeForm() {\n shake(formEl.value)\n}\n\n// 登录成功的收尾:先让页面淡出,再跳转。系统开了「减少动态效果」就不等。\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nasync function leaveThenEnter() {\n emit('leave', true)\n if (!window.matchMedia?.(REDUCED_MOTION).matches) {\n await new Promise<void>(resolve => setTimeout(resolve, 320))\n }\n await enterHome()\n emit('leave', false)\n}\n\nasync function finishLogin(res: LoginOutput) {\n // 每次登录都清动态路由/授权态,否则上次会话的 routesReady=true 会跳过 enterInitial,\n // 菜单壳在、业务路由未重建 → 进系统后处处 404(绑定 MFA 后回登录再登最易踩中)。\n resetRouter()\n auth.reset()\n user.setSession(res)\n\n // 现场绑定:不静默 claim——须用户确认,并依赖服务端 binder cookie 同浏览器校验\n const link = pendingLink.value\n if (link) {\n pendingClaimToken.value = link\n pendingConfirmShow.value = true\n return\n }\n message.success(t('login.success'))\n await leaveThenEnter()\n}\n\nconst pendingConfirmIdentity = computed(() =>\n pendingDisplayName.value\n ? t('oauth.pendingLinkIdentity', { display: pendingDisplayName.value })\n : '',\n)\n\nasync function confirmPendingBind() {\n if (pendingClaimBusy.value) return\n pendingClaimBusy.value = true\n try {\n await externalAuthApi.claimPendingLink(pendingClaimToken.value)\n message.success(t('oauth.pendingLinkSuccess', { name: pendingProviderLabel.value }))\n } catch (e) {\n message.warning(translateError(e))\n } finally {\n pendingClaimBusy.value = false\n pendingConfirmShow.value = false\n pendingClaimToken.value = ''\n }\n await enterHome()\n}\n\nasync function skipPendingBind() {\n pendingConfirmShow.value = false\n pendingClaimToken.value = ''\n message.success(t('login.success'))\n await enterHome()\n}\n\nasync function onSubmit() {\n if (mode.value === 'mfa') return onMfaSubmit()\n if (mode.value === 'totp') return onTotpSubmit()\n if (mode.value === 'sms') return onSmsSubmit()\n\n if (!model.account || !model.password) {\n message.warning(t('login.required'))\n return\n }\n if (captchaEnabled.value && !captchaCode.value) {\n message.warning(t('login.captchaRequired'))\n return\n }\n loading.value = true\n try {\n const res = await authApi.login({\n account: model.account,\n password: model.password,\n ...(captchaEnabled.value\n ? { captchaId: captchaId.value, captchaCode: captchaCode.value }\n : {}),\n })\n await finishLogin(res)\n } catch (e) {\n // 40018 = 密码已过、需 TOTP 二次验证\n if (e instanceof ApiError && e.code === 40018 && e.args) {\n totp.challengeId = String(e.args.challengeId ?? '')\n totp.code = ''\n mode.value = 'totp'\n } else if (e instanceof ApiError && e.code === 40020) {\n // 40020 = 强制 MFA 未绑定 → Modal 引导自助设置(登录页默认不常驻链接)\n bindAccount.value = model.account.trim()\n bindRequiredShow.value = true\n } else if (e instanceof ApiError && e.code === 40009 && e.args) {\n // 40009 = 密码已过、需短信二次验证\n mfa.challengeId = String(e.args.challengeId ?? '')\n mfa.phoneMask = String(e.args.phoneMask ?? '')\n mfa.code = ''\n mode.value = 'mfa'\n startCountdown(Number(e.args.resendSeconds ?? 60))\n } else {\n message.error(translateError(e))\n shakeForm()\n }\n await refreshCaptchaAfterUse()\n } finally {\n loading.value = false\n }\n}\n\nfunction closeBindRequired() {\n bindRequiredShow.value = false\n}\n\nfunction goBindAuthenticator() {\n const account = bindAccount.value || model.account.trim()\n bindRequiredShow.value = false\n void router.push({ path: '/mfa/bind', query: account ? { account } : {} })\n}\n\nfunction goRecovery() {\n const account = model.account.trim() || bindAccount.value\n void router.push({\n path: '/mfa/bind',\n query: { ...(account ? { account } : {}), mode: 'recovery' },\n })\n}\n\nasync function onMfaSubmit() {\n if (!mfa.code) {\n message.warning(t('login.smsCodePlaceholder'))\n return\n }\n loading.value = true\n try {\n await finishLogin(\n await authApi.smsChallengeLogin({ challengeId: mfa.challengeId, code: mfa.code }),\n )\n } catch (e) {\n message.error(translateError(e))\n shakeForm()\n } finally {\n loading.value = false\n }\n}\n\nasync function onTotpSubmit() {\n if (!totp.code) {\n message.warning(t('login.totpPlaceholder'))\n return\n }\n loading.value = true\n try {\n await finishLogin(\n await authApi.totpChallengeLogin({ challengeId: totp.challengeId, code: totp.code }),\n )\n } catch (e) {\n message.error(translateError(e))\n shakeForm()\n } finally {\n loading.value = false\n }\n}\n\nasync function onMfaResend() {\n if (countdown.value > 0) return\n try {\n const r = await authApi.smsChallengeResend({ challengeId: mfa.challengeId })\n message.success(t('login.smsSent'))\n startCountdown(r.resendSeconds)\n } catch (e) {\n message.error(translateError(e))\n }\n}\n\nfunction backToAccount() {\n mode.value = 'account'\n mfa.challengeId = ''\n mfa.code = ''\n totp.challengeId = ''\n totp.code = ''\n}\n\nasync function onSendSmsCode() {\n if (countdown.value > 0) return\n if (!smsModel.phone) {\n message.warning(t('login.phonePlaceholder'))\n return\n }\n if (captchaEnabled.value && !captchaCode.value) {\n message.warning(t('login.captchaRequired'))\n return\n }\n try {\n const r = await authApi.smsLoginSend({\n phone: smsModel.phone,\n ...(captchaEnabled.value\n ? { captchaId: captchaId.value, captchaCode: captchaCode.value }\n : {}),\n })\n message.success(t('login.smsSent'))\n startCountdown(r.resendSeconds)\n } catch (e) {\n message.error(translateError(e))\n }\n await refreshCaptchaAfterUse()\n}\n\nasync function onSmsSubmit() {\n if (!smsModel.phone || !smsModel.code) {\n message.warning(t('login.smsRequired'))\n return\n }\n loading.value = true\n try {\n await finishLogin(await authApi.smsLogin({ phone: smsModel.phone, code: smsModel.code }))\n } catch (e) {\n message.error(translateError(e))\n shakeForm()\n } finally {\n loading.value = false\n }\n}\n</script>\n\n<template>\n <div ref=\"formEl\" class=\"login-form\">\n <div v-if=\"showLogo\" class=\"lf-brand\">\n <!-- 站点 logo 的取值顺序(配置 → brand 选项 → 内置矢量标)统一在 SmartLogo 里 -->\n <SmartLogo :size=\"34\" />\n <span class=\"lf-word\">{{ site.title }}</span>\n </div>\n\n <n-alert\n v-if=\"pendingLink\"\n type=\"info\"\n :bordered=\"false\"\n class=\"lf-pending-alert\"\n :title=\"t('oauth.pendingLinkTitle', { name: pendingProviderLabel })\"\n >\n {{ t('oauth.pendingLinkHint', { name: pendingProviderLabel }) }}\n </n-alert>\n\n <!-- 登录方式切换:旧内容先淡出上移,新内容的逐项浮现由外壳(LoginDesk)的入场动画负责 -->\n <Transition name=\"lf-swap\" mode=\"out-in\">\n <div :key=\"mode\" class=\"lf-body\">\n <!-- 短信二次验证:密码已过,凭挑战 + 短信码完成登录 -->\n <template v-if=\"mode === 'mfa'\">\n <h2 v-if=\"showTitle || showGreeting\" class=\"lf-title\">\n {{ t('login.mfaTitle', { phone: mfa.phoneMask }) }}\n </h2>\n <p class=\"lf-hint-line\">{{ t('login.mfaSub') }}</p>\n <n-form :show-feedback=\"false\" @keyup.enter=\"onSubmit\">\n <n-form-item :label=\"t('login.smsCode')\" path=\"code\">\n <n-input\n v-model:value=\"mfa.code\"\n :placeholder=\"t('login.smsCodePlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:chat-circle-text\" /></template>\n </n-input>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-button text type=\"primary\" @click=\"backToAccount\">\n {{ t('login.backToPassword') }}\n </n-button>\n <n-button\n text\n :type=\"countdown > 0 ? 'default' : 'primary'\"\n :disabled=\"countdown > 0\"\n @click=\"onMfaResend\"\n >\n {{ countdown > 0 ? t('login.resendAfter', { s: countdown }) : t('login.sendCode') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n </template>\n\n <!-- TOTP 二次验证:密码已过,凭 Authenticator 动态口令完成登录 -->\n <template v-else-if=\"mode === 'totp'\">\n <h2 v-if=\"showTitle || showGreeting\" class=\"lf-title\">{{ t('login.totpTitle') }}</h2>\n <p class=\"lf-hint-line\">{{ t('login.totpSub') }}</p>\n <n-form :show-feedback=\"false\" @keyup.enter=\"onSubmit\">\n <n-form-item :label=\"t('login.totpCode')\" path=\"code\">\n <n-input\n v-model:value=\"totp.code\"\n :placeholder=\"t('login.totpPlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:shield-check\" /></template>\n </n-input>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-button text type=\"primary\" @click=\"backToAccount\">\n {{ t('login.backToPassword') }}\n </n-button>\n <n-button text type=\"primary\" @click=\"goRecovery\">\n {{ t('login.useRecovery') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n </template>\n\n <template v-else>\n <!-- 单栏:卡内标题「登录」;双栏:品牌在左栏,这里是问候语 -->\n <h2 v-if=\"showTitle\" class=\"lf-title\">{{ t('login.title') }}</h2>\n <div v-else-if=\"showGreeting\" class=\"lf-greet\">\n <h1>{{ t('login.welcome') }}</h1>\n <p>{{ t('login.welcomeSub') }}</p>\n </div>\n <n-form\n :model=\"mode === 'account' ? model : smsModel\"\n :show-feedback=\"false\"\n @keyup.enter=\"onSubmit\"\n >\n <template v-if=\"mode === 'account'\">\n <n-form-item :label=\"t('login.account')\" path=\"account\">\n <n-input\n v-model:value=\"model.account\"\n :placeholder=\"t('login.accountPlaceholder')\"\n size=\"large\"\n >\n <template #prefix><Icon icon=\"ph:user\" /></template>\n </n-input>\n </n-form-item>\n <n-form-item :label=\"t('login.password')\" path=\"password\">\n <n-input\n v-model:value=\"model.password\"\n type=\"password\"\n show-password-on=\"click\"\n :placeholder=\"t('login.passwordPlaceholder')\"\n size=\"large\"\n >\n <template #prefix><Icon icon=\"ph:lock\" /></template>\n </n-input>\n </n-form-item>\n </template>\n <template v-else>\n <n-form-item :label=\"t('login.phone')\" path=\"phone\">\n <n-input\n v-model:value=\"smsModel.phone\"\n :placeholder=\"t('login.phonePlaceholder')\"\n size=\"large\"\n :maxlength=\"20\"\n >\n <template #prefix><Icon icon=\"ph:device-mobile\" /></template>\n </n-input>\n </n-form-item>\n </template>\n <n-form-item v-if=\"captchaEnabled\" :label=\"t('login.captcha')\" path=\"captcha\">\n <div class=\"lf-captcha\">\n <n-input\n v-model:value=\"captchaCode\"\n :placeholder=\"captchaHint\"\n size=\"large\"\n @keyup.enter=\"onSubmit\"\n >\n <template #prefix><Icon icon=\"ph:shield-check\" /></template>\n </n-input>\n <!-- SVG 来自本站后端;点击重取一张(一次性票据);取图失败时图形位为空,点击重试 -->\n <button\n type=\"button\"\n class=\"lf-captcha-img\"\n :class=\"{ empty: !captchaSvg }\"\n :title=\"t('login.captchaPlaceholder')\"\n :aria-label=\"t('login.captchaPlaceholder')\"\n @click=\"loadCaptcha\"\n v-html=\"captchaSvg\"\n />\n </div>\n </n-form-item>\n <n-form-item v-if=\"mode === 'sms'\" :label=\"t('login.smsCode')\" path=\"code\">\n <div class=\"lf-captcha\">\n <n-input\n v-model:value=\"smsModel.code\"\n :placeholder=\"t('login.smsCodePlaceholder')\"\n size=\"large\"\n :maxlength=\"6\"\n >\n <template #prefix><Icon icon=\"ph:chat-circle-text\" /></template>\n </n-input>\n <n-button\n class=\"lf-send-btn\"\n secondary\n size=\"large\"\n attr-type=\"button\"\n :disabled=\"countdown > 0\"\n @click=\"onSendSmsCode\"\n >\n {{\n countdown > 0 ? t('login.resendAfter', { s: countdown }) : t('login.sendCode')\n }}\n </n-button>\n </div>\n </n-form-item>\n <div class=\"row lf-between\">\n <n-checkbox v-if=\"mode === 'account'\" v-model:checked=\"model.remember\">\n {{ t('login.remember') }}\n </n-checkbox>\n <span v-else />\n <n-button\n v-if=\"site.smsLoginEnabled\"\n text\n type=\"primary\"\n @click=\"mode = mode === 'account' ? 'sms' : 'account'\"\n >\n {{ mode === 'account' ? t('login.smsLogin') : t('login.accountLogin') }}\n </n-button>\n </div>\n <n-button\n class=\"hero-btn cta\"\n type=\"primary\"\n size=\"large\"\n block\n attr-type=\"button\"\n :loading=\"loading\"\n @click=\"onSubmit\"\n >\n {{ loading ? t('common.loading') : t('login.submit') }}\n </n-button>\n </n-form>\n\n <!-- 第三方登录:圆形品牌标;<a href>。PREVIEW_ALL_SSO_BRANDS 时展示全部品牌图。 -->\n <template v-if=\"ssoDisplayList.length\">\n <div class=\"lf-divider\">\n <span>{{ t('login.otherMethods') }}</span>\n </div>\n <div class=\"lf-sso\">\n <a\n v-for=\"p in ssoSplit.visible\"\n :key=\"p.code\"\n class=\"lf-sso-btn\"\n :href=\"ssoHref(p.code)\"\n :title=\"p.displayName\"\n :aria-label=\"p.displayName\"\n >\n <BrandIcon :code=\"p.code\" :icon=\"p.icon\" :size=\"28\" />\n </a>\n <n-dropdown\n v-if=\"ssoSplit.overflow.length\"\n trigger=\"click\"\n :options=\"ssoOverflowOptions\"\n @select=\"onSsoOverflow\"\n >\n <a\n class=\"lf-sso-btn lf-sso-more\"\n href=\"javascript:void(0)\"\n role=\"button\"\n :title=\"t('login.moreMethods')\"\n :aria-label=\"t('login.moreMethods')\"\n @click.prevent\n >\n <Icon icon=\"ph:dots-three\" :width=\"18\" />\n </a>\n </n-dropdown>\n </div>\n </template>\n </template>\n </div>\n </Transition>\n\n <!-- 页脚:版权(可选链接)+ 构建期版本号。双栏时外壳在卡外自绘页脚,传 :show-footer=\"false\" 关掉。 -->\n <footer v-if=\"showFooter\" class=\"lf-foot\">\n <span>\n © {{ year }}\n <a v-if=\"site.copyrightUrl\" :href=\"site.copyrightUrl\" target=\"_blank\" rel=\"noopener\">\n {{ site.copyright || site.title }}\n </a>\n <template v-else>{{ site.copyright || site.title }}</template>\n </span>\n <span v-if=\"appVersion\" class=\"lf-ver\">v{{ appVersion }}</span>\n </footer>\n\n <!-- 强制 MFA 未绑定(40020):遮罩 Modal,账密表单仍在底下;默认登录页不常驻绑定链接 -->\n <n-modal\n v-model:show=\"bindRequiredShow\"\n preset=\"dialog\"\n type=\"warning\"\n :title=\"t('login.totpBindTitle')\"\n :content=\"t('login.totpBindSub')\"\n :positive-text=\"t('login.setupAuthenticator')\"\n :negative-text=\"t('common.cancel')\"\n @positive-click=\"goBindAuthenticator\"\n @negative-click=\"closeBindRequired\"\n />\n <!-- pending-link:登录后显式确认绑定,防静默抢绑 -->\n <n-modal\n v-model:show=\"pendingConfirmShow\"\n preset=\"dialog\"\n type=\"info\"\n :title=\"t('oauth.pendingLinkConfirmTitle')\"\n :content=\"\n t('oauth.pendingLinkConfirmContent', {\n name: pendingProviderLabel,\n identity: pendingConfirmIdentity,\n account: user.userInfo?.account ?? '',\n })\n \"\n :positive-text=\"t('oauth.pendingLinkConfirmOk')\"\n :negative-text=\"t('oauth.pendingLinkConfirmSkip')\"\n :loading=\"pendingClaimBusy\"\n :closable=\"false\"\n :mask-closable=\"false\"\n @positive-click=\"confirmPendingBind\"\n @negative-click=\"skipPendingBind\"\n />\n </div>\n</template>\n\n<style scoped>\n.login-form {\n width: 100%;\n}\n/* 登录方式切换:旧内容淡出并轻微上移变虚 */\n.lf-swap-leave-active {\n transition:\n opacity 0.16s ease-in,\n transform 0.16s ease-in,\n filter 0.16s ease-in;\n}\n.lf-swap-leave-to {\n opacity: 0;\n transform: translate3d(0, -6px, 0);\n filter: blur(4px);\n}\n.lf-pending-alert {\n margin-bottom: 16px;\n border-radius: var(--radius-md);\n text-align: left;\n}\n/* 单栏卡内顶部:站点 logo + 标题。logo 取值顺序见 SmartLogo */\n.lf-brand {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 18px;\n}\n.lf-word {\n font-size: 22px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--text-1);\n}\n.lf-title {\n font-size: 20px;\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 1.3;\n margin: 0 0 16px;\n color: var(--text-1);\n}\n/* 双栏卡内问候语 */\n.lf-greet {\n text-align: center;\n margin: 2px 0 20px;\n}\n.lf-greet h1 {\n font-size: 26px;\n font-weight: 600;\n letter-spacing: -0.035em;\n margin: 0 0 4px;\n color: var(--text-1);\n}\n.lf-greet p {\n margin: 0;\n font-size: 13.5px;\n color: var(--text-3);\n}\n/* 二次验证副标题:标题下的弱化说明行 */\n.lf-hint-line {\n margin: -8px 0 18px;\n font-size: 13px;\n color: var(--text-3);\n}\n/* 表单项之间的间距(表单关了反馈行,没有校验规则要显示) */\n.login-form :deep(.n-form-item) {\n margin-bottom: 14px;\n}\n.row {\n margin: 2px 0 14px;\n min-height: 32px;\n}\n.lf-between {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n.lf-between > :deep(.n-button) {\n height: 32px;\n padding: 0 2px;\n}\n/* 验证码:输入框 + 可点击刷新的 SVG 图形(等高对齐) */\n.lf-captcha {\n display: flex;\n gap: 10px;\n width: 100%;\n align-items: stretch;\n}\n.lf-captcha > :deep(.n-input) {\n flex: 1;\n min-width: 0;\n}\n.lf-captcha-img {\n flex: none;\n height: 42px;\n min-width: 100px;\n padding: 0;\n border: 1px solid var(--hairline);\n border-radius: var(--radius-md);\n background: #fff;\n cursor: pointer;\n overflow: hidden;\n display: grid;\n place-items: center;\n line-height: 0;\n}\n/* 取图失败时图形位为空:换成输入框同款底色,否则空白框像 bug;点击重试 */\n.lf-captcha-img.empty {\n background: var(--fill);\n}\n.lf-captcha-img:focus-visible {\n outline: 2px solid var(--signal);\n outline-offset: 2px;\n}\n.lf-captcha-img :deep(svg) {\n display: block;\n height: 40px;\n width: auto;\n}\n/* 发码按钮:与验证码图形同尺寸位 */\n.lf-send-btn {\n flex: none;\n min-width: 104px;\n}\n/* 第三方登录:分隔线 + 圆形品牌标 */\n.lf-divider {\n display: flex;\n align-items: center;\n gap: 14px;\n margin: 22px 0 14px;\n}\n.lf-divider::before,\n.lf-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--hairline);\n}\n.lf-divider span {\n font-size: 13px;\n color: var(--text-3);\n}\n.lf-sso {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 12px;\n}\n/* 第三方登录:只露品牌标本身,不加灰底 / 描边 / 圆形裁切(会吃掉品牌标的轮廓);\n 40px 是点击热区,hover 才浮出一层极淡的圆角底,macOS 工具栏按钮的做法 */\n.lf-sso-btn {\n width: 40px;\n height: 40px;\n padding: 0;\n display: inline-grid;\n place-items: center;\n flex: none;\n border: none;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--text-1);\n text-decoration: none;\n cursor: pointer;\n transition: background var(--transition-base);\n}\n.lf-sso-btn :deep(.oauth-brand-badge) {\n width: 28px;\n height: 28px;\n}\n.lf-sso-btn:hover {\n background: var(--hover);\n color: var(--text-1);\n text-decoration: none;\n}\n.lf-sso-btn:active {\n background: var(--pressed);\n}\n.lf-sso-btn:focus-visible {\n outline: 2px solid var(--signal);\n outline-offset: 2px;\n}\n/* 页脚:版权 + 版本号,弱化色 */\n.lf-foot {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n margin-top: 20px;\n font-size: 13px;\n color: var(--text-3);\n}\n.lf-foot a {\n color: inherit;\n text-decoration: none;\n}\n.lf-foot a:hover {\n color: var(--signal);\n}\n.lf-ver {\n opacity: 0.75;\n}\n@media (max-width: 480px) {\n .lf-captcha-img {\n min-width: 92px;\n }\n}\n</style>\n"],"names":["REDUCED_MOTION","emit","__emit","router","useRouter","route","useRoute","message","useMessage","t","useI18n","user","useUserStore","auth","useAuthStore","site","appVersion","loadSite","useSite","year","pendingLink","computed","pendingProvider","pendingDisplayName","pendingConfirmShow","ref","pendingClaimBusy","pendingClaimToken","model","reactive","runtime","loading","mode","smsModel","mfa","totp","bindRequiredShow","bindAccount","countdown","timer","startCountdown","s","onBeforeUnmount","captchaEnabled","captchaId","captchaSvg","captchaCode","captchaType","captchaHint","loadCaptcha","c","authApi","refreshCaptchaAfterUse","onMounted","loadSsoProviders","q","ch","ssoProviders","pendingProviderLabel","code","hit","p","ssoDisplayList","ssoSplit","splitLoginProviders","ssoOverflowOptions","h","BrandIcon","externalAuthApi","claimWeComAutoLogin","ssoHref","onSsoOverflow","key","enterHome","formEl","shakeForm","shake","leaveThenEnter","_a","resolve","finishLogin","res","resetRouter","link","pendingConfirmIdentity","confirmPendingBind","e","translateError","skipPendingBind","onSubmit","onMfaSubmit","onTotpSubmit","onSmsSubmit","ApiError","closeBindRequired","goBindAuthenticator","account","goRecovery","onMfaResend","r","backToAccount","onSendSmsCode","_createElementBlock","__props","_openBlock","_hoisted_1","_createVNode","SmartLogo","_createElementVNode","_hoisted_2","_toDisplayString","_unref","_createBlock","NAlert","_createTextVNode","_Transition","_Fragment","_hoisted_3","_hoisted_4","NForm","NFormItem","NInput","_cache","$event","Icon","_hoisted_5","NButton","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_normalizeClass","_hoisted_13","_hoisted_14","NCheckbox","_hoisted_15","_hoisted_16","_hoisted_17","_renderList","NDropdown","_hoisted_20","_hoisted_21","_hoisted_22","NModal"],"mappings":"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"}
@@ -2,7 +2,7 @@ import o from "./LoginDesk2.vue.js";
2
2
  /* empty css */
3
3
  /* empty css */
4
4
  import t from "../../../_virtual/_plugin-vue_export-helper.js";
5
- const e = /* @__PURE__ */ t(o, [["__scopeId", "data-v-2da0e5ac"]]);
5
+ const e = /* @__PURE__ */ t(o, [["__scopeId", "data-v-59a1a1fe"]]);
6
6
  export {
7
7
  e as default
8
8
  };
@@ -1,12 +1,12 @@
1
- import { defineComponent as h, ref as w, onBeforeUnmount as b, openBlock as v, createElementBlock as g, normalizeClass as y, createElementVNode as o, renderSlot as l, createCommentVNode as $, createVNode as d, unref as e, withCtx as u, createTextVNode as x, toDisplayString as N, normalizeStyle as B } from "vue";
2
- import { NTooltip as C, NButton as D, NCard as P } from "naive-ui";
3
- import { Icon as S } from "@iconify/vue";
4
- import { useI18n as F } from "vue-i18n";
5
- import { useAppStore as A } from "../../../stores/app.js";
6
- const V = {
1
+ import { defineComponent as $, ref as w, onBeforeUnmount as b, openBlock as k, createElementBlock as h, normalizeClass as x, createElementVNode as o, renderSlot as l, createCommentVNode as B, createVNode as p, unref as t, withCtx as c, createTextVNode as C, toDisplayString as F, normalizeStyle as N } from "vue";
2
+ import { NTooltip as S, NButton as D, NCard as A } from "naive-ui";
3
+ import { Icon as V } from "@iconify/vue";
4
+ import { useI18n as q } from "vue-i18n";
5
+ import { useAppStore as T } from "../../../stores/app.js";
6
+ const z = {
7
7
  key: 0,
8
8
  class: "login-brand"
9
- }, T = { class: "login-brand-inner" }, q = { class: "login-stage" }, z = { class: "login-corner" }, U = /* @__PURE__ */ h({
9
+ }, E = { class: "login-brand-inner" }, I = { class: "login-stage" }, H = { class: "login-corner" }, X = /* @__PURE__ */ $({
10
10
  __name: "LoginDesk",
11
11
  props: {
12
12
  split: { type: Boolean, default: !1 },
@@ -14,24 +14,36 @@ const V = {
14
14
  contentStyle: { default: "padding: 26px 26px 22px" },
15
15
  leaving: { type: Boolean, default: !1 }
16
16
  },
17
- setup(i) {
18
- const r = A(), { t: a } = F(), p = w(null);
19
- let c = 0;
20
- function m(t, n) {
21
- cancelAnimationFrame(c), c = requestAnimationFrame(() => {
22
- var s, f;
23
- (s = p.value) == null || s.style.setProperty("--px", t.toFixed(3)), (f = p.value) == null || f.style.setProperty("--py", n.toFixed(3));
17
+ setup(r) {
18
+ const s = T(), { t: a } = q(), m = w(null);
19
+ let u = 0;
20
+ function y(e, n, d, v) {
21
+ cancelAnimationFrame(u), u = requestAnimationFrame(() => {
22
+ var g;
23
+ const i = m.value;
24
+ if (!i) return;
25
+ if (i.style.setProperty("--px", e.toFixed(3)), i.style.setProperty("--py", n.toFixed(3)), d === void 0 || v === void 0) {
26
+ i.style.setProperty("--lit", "0");
27
+ return;
28
+ }
29
+ const f = (g = i.querySelector(".desk-card")) == null ? void 0 : g.getBoundingClientRect();
30
+ f && (i.style.setProperty("--mx", `${(d - f.left).toFixed(1)}px`), i.style.setProperty("--my", `${(v - f.top).toFixed(1)}px`)), i.style.setProperty("--lit", "1");
24
31
  });
25
32
  }
26
- function k(t) {
27
- t.pointerType === "mouse" && m(t.clientX / window.innerWidth * 2 - 1, t.clientY / window.innerHeight * 2 - 1);
33
+ function P(e) {
34
+ e.pointerType === "mouse" && y(
35
+ e.clientX / window.innerWidth * 2 - 1,
36
+ e.clientY / window.innerHeight * 2 - 1,
37
+ e.clientX,
38
+ e.clientY
39
+ );
28
40
  }
29
- return b(() => cancelAnimationFrame(c)), (t, n) => (v(), g("div", {
41
+ return b(() => cancelAnimationFrame(u)), (e, n) => (k(), h("div", {
30
42
  ref_key: "root",
31
- ref: p,
32
- class: y(["login desk-bg", { split: i.split, leaving: i.leaving }]),
33
- onPointermove: k,
34
- onPointerleave: n[1] || (n[1] = (s) => m(0, 0))
43
+ ref: m,
44
+ class: x(["login desk-bg", { split: r.split, leaving: r.leaving }]),
45
+ onPointermove: P,
46
+ onPointerleave: n[1] || (n[1] = (d) => y(0, 0))
35
47
  }, [
36
48
  n[2] || (n[2] = o("div", {
37
49
  class: "desk",
@@ -42,59 +54,59 @@ const V = {
42
54
  o("i"),
43
55
  o("i")
44
56
  ], -1)),
45
- i.split ? (v(), g("div", V, [
46
- o("div", T, [
47
- l(t.$slots, "brand", {}, void 0, !0)
57
+ r.split ? (k(), h("div", z, [
58
+ o("div", E, [
59
+ l(e.$slots, "brand", {}, void 0, !0)
48
60
  ])
49
- ])) : $("", !0),
50
- o("div", q, [
51
- o("div", z, [
52
- l(t.$slots, "corner", {}, void 0, !0),
53
- d(e(C), null, {
54
- trigger: u(() => [
55
- d(e(D), {
61
+ ])) : B("", !0),
62
+ o("div", I, [
63
+ o("div", H, [
64
+ l(e.$slots, "corner", {}, void 0, !0),
65
+ p(t(S), null, {
66
+ trigger: c(() => [
67
+ p(t(D), {
56
68
  quaternary: "",
57
69
  circle: "",
58
- "aria-label": e(r).isDark ? e(a)("app.light") : e(a)("app.dark"),
59
- onClick: n[0] || (n[0] = (s) => e(r).toggleDark())
70
+ "aria-label": t(s).isDark ? t(a)("app.light") : t(a)("app.dark"),
71
+ onClick: n[0] || (n[0] = (d) => t(s).toggleDark())
60
72
  }, {
61
- icon: u(() => [
62
- d(e(S), {
63
- icon: e(r).isDark ? "ph:moon" : "ph:sun",
73
+ icon: c(() => [
74
+ p(t(V), {
75
+ icon: t(s).isDark ? "ph:moon" : "ph:sun",
64
76
  width: 18
65
77
  }, null, 8, ["icon"])
66
78
  ]),
67
79
  _: 1
68
80
  }, 8, ["aria-label"])
69
81
  ]),
70
- default: u(() => [
71
- x(" " + N(e(r).isDark ? e(a)("app.light") : e(a)("app.dark")), 1)
82
+ default: c(() => [
83
+ C(" " + F(t(s).isDark ? t(a)("app.light") : t(a)("app.dark")), 1)
72
84
  ]),
73
85
  _: 1
74
86
  })
75
87
  ]),
76
88
  o("div", {
77
- class: y(["login-card", { "on-desk": i.split }]),
78
- style: B(i.split ? void 0 : { width: `${i.width}px` })
89
+ class: x(["login-card", { "on-desk": r.split }]),
90
+ style: N(r.split ? void 0 : { width: `${r.width}px` })
79
91
  }, [
80
- l(t.$slots, "above", {}, void 0, !0),
81
- d(e(P), {
92
+ l(e.$slots, "above", {}, void 0, !0),
93
+ p(t(A), {
82
94
  bordered: !0,
83
95
  class: "desk-card",
84
- "content-style": i.contentStyle
96
+ "content-style": r.contentStyle
85
97
  }, {
86
- default: u(() => [
87
- l(t.$slots, "default", {}, void 0, !0)
98
+ default: c(() => [
99
+ l(e.$slots, "default", {}, void 0, !0)
88
100
  ]),
89
101
  _: 3
90
102
  }, 8, ["content-style"]),
91
- l(t.$slots, "after", {}, void 0, !0)
103
+ l(e.$slots, "after", {}, void 0, !0)
92
104
  ], 6)
93
105
  ])
94
106
  ], 34));
95
107
  }
96
108
  });
97
109
  export {
98
- U as default
110
+ X as default
99
111
  };
100
112
  //# sourceMappingURL=LoginDesk2.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginDesk2.vue.js","sources":["../../../../src/views/login/components/LoginDesk.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 入口类全屏页(登录 / 二次验证 / 第三方回调 / 门户加载失败)共用的外壳:macOS 锁屏语言。\n// 整页一张慢慢飘的柔光色场(.desk,颜色全由强调色推导,无网格)+ 浮在上面的毛玻璃卡,右上角是工具栏。\n// 单栏 = 居中一张卡;双栏(split)= 左栏品牌区(brand 插槽)压在色场上,右栏是这张卡。\n// 只管视觉外壳:卡里放什么、表单怎么提交都在各页自己手里。\n//\n// 动效(全部不回弹):入场按「卡 → 标题 → 字段 → 按钮」依次浮现(先模糊后清晰);\n// 色场与卡跟着指针做反向视差;leaving 为真时整页淡出放大一点(像 macOS 解锁),给登录成功收尾。\nimport { onBeforeUnmount, ref } from 'vue'\nimport { NButton, NCard, NTooltip } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useAppStore } from '#/stores/app'\n\nwithDefaults(\n defineProps<{\n /** 双栏:左栏渲染 brand 插槽,卡片宽度收到 384 */\n split?: boolean\n /** 卡片宽度(px),窄屏被 max-width:100% 收住 */\n width?: number\n /** NCard 内容区内边距 */\n contentStyle?: string\n /** 退场:登录成功后由页面置真,整页淡出,等动画播完再跳转 */\n leaving?: boolean\n }>(),\n { split: false, width: 400, contentStyle: 'padding: 26px 26px 22px', leaving: false },\n)\n\nconst app = useAppStore()\nconst { t } = useI18n()\n\n// 指针视差:只认鼠标(触屏没有悬停位置),坐标归一到 -1..1 写成 CSS 变量,位移与过渡都在 CSS 里\nconst root = ref<HTMLElement | null>(null)\nlet raf = 0\nfunction setParallax(x: number, y: number) {\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n root.value?.style.setProperty('--px', x.toFixed(3))\n root.value?.style.setProperty('--py', y.toFixed(3))\n })\n}\nfunction onPointerMove(e: PointerEvent) {\n if (e.pointerType !== 'mouse') return\n setParallax((e.clientX / window.innerWidth) * 2 - 1, (e.clientY / window.innerHeight) * 2 - 1)\n}\nonBeforeUnmount(() => cancelAnimationFrame(raf))\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"login desk-bg\"\n :class=\"{ split, leaving }\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"setParallax(0, 0)\"\n >\n <div class=\"desk\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n <i />\n </div>\n\n <div v-if=\"split\" class=\"login-brand\">\n <div class=\"login-brand-inner\"><slot name=\"brand\" /></div>\n </div>\n\n <div class=\"login-stage\">\n <!-- 右上角工具栏:页面自己的按钮(布局切换、语言)在前,主题切换永远贴最右角 -->\n <div class=\"login-corner\">\n <slot name=\"corner\" />\n <n-tooltip>\n <template #trigger>\n <n-button\n quaternary\n circle\n :aria-label=\"app.isDark ? t('app.light') : t('app.dark')\"\n @click=\"app.toggleDark()\"\n >\n <template #icon>\n <Icon :icon=\"app.isDark ? 'ph:moon' : 'ph:sun'\" :width=\"18\" />\n </template>\n </n-button>\n </template>\n {{ app.isDark ? t('app.light') : t('app.dark') }}\n </n-tooltip>\n </div>\n\n <!-- margin-top 给右上角工具栏留位:窄屏内容比视口高时,顶部不会被工具栏盖住 -->\n <div\n class=\"login-card\"\n :class=\"{ 'on-desk': split }\"\n :style=\"split ? undefined : { width: `${width}px` }\"\n >\n <slot name=\"above\" />\n <n-card :bordered=\"true\" class=\"desk-card\" :content-style=\"contentStyle\">\n <slot />\n </n-card>\n <slot name=\"after\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* 登录页(单栏 / 双栏都算)是 macOS 桌面那种纯色场:不要网格线,不要透视地面 */\n.login {\n /* 减速到底、不过冲:入场与视差共用这条曲线 */\n --rise: cubic-bezier(0.22, 1, 0.36, 1);\n min-height: 100dvh;\n background: var(--desk-base);\n position: relative;\n overflow: hidden;\n}\n.login.split {\n display: grid;\n grid-template-columns: minmax(340px, 46%) 1fr;\n}\n.login-stage {\n min-height: 100dvh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n position: relative;\n overflow: hidden;\n}\n\n/* 色场:四团 blur(70px) 的柔光球慢速漂移,颜色由强调色推导(--desk-1..4);\n 整体再按指针反向平移一点(用独立的 translate 属性,不和漂移动画的 transform 打架) */\n.desk {\n position: absolute;\n inset: -20%;\n pointer-events: none;\n z-index: 0;\n translate: calc(var(--px, 0) * -22px) calc(var(--py, 0) * -16px);\n transition: translate 1.4s var(--rise);\n}\n.desk i {\n position: absolute;\n display: block;\n border-radius: 50%;\n filter: blur(70px);\n opacity: var(--desk-op);\n}\n.desk i:nth-child(1) {\n left: 2%;\n top: 4%;\n width: 46%;\n height: 62%;\n background: var(--desk-1);\n animation: drift1 26s ease-in-out infinite alternate;\n}\n.desk i:nth-child(2) {\n left: 26%;\n top: 34%;\n width: 44%;\n height: 56%;\n background: var(--desk-2);\n animation: drift2 32s ease-in-out infinite alternate;\n}\n.desk i:nth-child(3) {\n left: 54%;\n top: -6%;\n width: 40%;\n height: 58%;\n background: var(--desk-3);\n animation: drift3 29s ease-in-out infinite alternate;\n}\n.desk i:nth-child(4) {\n left: 62%;\n top: 46%;\n width: 46%;\n height: 62%;\n background: var(--desk-4);\n animation: drift1 35s ease-in-out infinite alternate-reverse;\n}\n@keyframes drift1 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(6%, -5%, 0) scale(1.12);\n }\n}\n@keyframes drift2 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(-7%, 4%, 0) scale(1.08);\n }\n}\n@keyframes drift3 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(4%, 7%, 0) scale(1.15);\n }\n}\n\n.login-corner {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 3;\n display: flex;\n gap: 8px;\n animation: fadeIn 0.9s var(--rise) 0.7s both;\n}\n\n/* 双栏左栏:文字直接压在色场上(像 macOS 桌面上的字),不单独做一块彩色面板 */\n.login-brand {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 48px clamp(32px, 5vw, 76px);\n}\n.login-brand-inner {\n max-width: 440px;\n}\n\n.login-card {\n width: 400px;\n max-width: 100%;\n position: relative;\n z-index: 2;\n margin-top: 44px;\n}\n.login-card.on-desk {\n width: 384px;\n}\n\n/* 表单是一块浮在色场上的毛玻璃卡(macOS 的 vibrancy 材质),单栏双栏同一套 */\n.desk-card {\n border: 1px solid var(--glass-border) !important;\n border-radius: 22px !important;\n background: var(--glass-panel) !important;\n box-shadow: var(--glass-shadow) !important;\n backdrop-filter: blur(40px) saturate(180%);\n -webkit-backdrop-filter: blur(40px) saturate(180%);\n /* 反向视差:卡朝指针方向挪一点,色场反方向挪,拉出前后景深 */\n translate: calc(var(--px, 0) * 6px) calc(var(--py, 0) * 4px);\n transition:\n translate 1s var(--rise),\n background-color 0.3s,\n border-color 0.3s,\n box-shadow 0.3s;\n}\n.login-card :deep(.n-input) {\n border-radius: var(--radius-md);\n}\n/* 主按钮:强调色 → 第二色渐变,带一层强调色辉光;hover 只加深辉光并微提亮、不位移,按下轻轻收一下 */\n.login-card :deep(.n-button.cta) {\n background-image: linear-gradient(120deg, var(--signal), var(--login-accent-2));\n border-color: transparent;\n box-shadow: 0 10px 26px -10px var(--signal-glow);\n transition:\n box-shadow 0.22s var(--ease),\n transform 0.2s var(--ease),\n filter 0.2s var(--ease);\n}\n.login-card :deep(.n-button.cta:hover) {\n box-shadow: 0 16px 34px -10px var(--signal-glow);\n filter: brightness(1.04);\n}\n.login-card :deep(.n-button.cta:active:not(:disabled)) {\n transform: scale(0.985);\n filter: brightness(0.97);\n box-shadow: 0 6px 18px -10px var(--signal-glow);\n}\n\n/* ── 入场编排 ─────────────────────────────────────────────\n 动画必须挂在 .desk-card 自己身上,不能挂它的父级 .login-card:父级 opacity < 1 会让子元素的\n backdrop-filter 失去背景,动画期间卡是不模糊的,结束那一帧模糊才「啪」地打上去,看着就是生硬。\n 内容项(标题 / 字段 / 按钮 / 左栏文字)各自带延迟依次浮现,先模糊后清晰,不回弹。 */\n.desk-card {\n animation: cardIn 0.95s var(--rise) 0.08s both;\n}\n.login-card > :deep(:not(.desk-card)) {\n animation: fadeIn 0.9s var(--rise) 0.55s both;\n}\n\n/* 左栏:Logo → 标语 → 说明 → 亮点逐行 */\n.login-brand-inner :deep(.login-hero-panel > :not(.points)),\n.login-brand-inner :deep(.points li) {\n animation: riseIn 0.9s var(--rise) both;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(1)) {\n animation-delay: 0.1s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(2)) {\n animation-delay: 0.18s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(3)) {\n animation-delay: 0.26s;\n}\n.login-brand-inner :deep(.points li:nth-child(1)) {\n animation-delay: 0.36s;\n}\n.login-brand-inner :deep(.points li:nth-child(2)) {\n animation-delay: 0.43s;\n}\n.login-brand-inner :deep(.points li:nth-child(n + 3)) {\n animation-delay: 0.5s;\n}\n\n/* 卡内:LoginForm 的 .login-form > .lf-brand / .lf-body(标题、表单、第三方登录)和表单里的各行 */\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert),\n.login-card :deep(.lf-body > :not(form)),\n.login-card :deep(.lf-body form > *) {\n animation: riseIn 0.8s var(--rise) both;\n}\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert) {\n animation-delay: 0.18s;\n}\n.login-card :deep(.lf-body > :not(form)) {\n animation-delay: 0.22s;\n}\n.login-card :deep(.lf-body form > :nth-child(1)) {\n animation-delay: 0.28s;\n}\n.login-card :deep(.lf-body form > :nth-child(2)) {\n animation-delay: 0.34s;\n}\n.login-card :deep(.lf-body form > :nth-child(3)) {\n animation-delay: 0.4s;\n}\n.login-card :deep(.lf-body form > :nth-child(4)) {\n animation-delay: 0.46s;\n}\n.login-card :deep(.lf-body form > :nth-child(n + 5)) {\n animation-delay: 0.52s;\n}\n.login-card :deep(.lf-body > .lf-divider) {\n animation-delay: 0.56s;\n}\n.login-card :deep(.lf-body > .lf-sso) {\n animation-delay: 0.62s;\n}\n\n@keyframes cardIn {\n from {\n opacity: 0;\n transform: translate3d(0, 28px, 0) scale(0.965);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n@keyframes riseIn {\n from {\n opacity: 0;\n transform: translate3d(0, 12px, 0);\n filter: blur(6px);\n }\n to {\n opacity: 1;\n transform: none;\n filter: none;\n }\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ── 退场:登录成功后整页淡出并微微放大(macOS 解锁的感觉),色场留着不动 ── */\n.login.leaving .desk-card {\n animation: cardOut 0.34s cubic-bezier(0.4, 0, 1, 1) both;\n}\n.login.leaving .login-brand-inner,\n.login.leaving .login-corner,\n.login.leaving .login-card > :deep(:not(.desk-card)) {\n animation: fadeOut 0.28s ease-in both;\n}\n@keyframes cardOut {\n to {\n opacity: 0;\n transform: translate3d(0, -8px, 0) scale(1.02);\n }\n}\n@keyframes fadeOut {\n to {\n opacity: 0;\n }\n}\n\n/* 减少动效:全局规则已把时长压到近零,这里再清掉延迟(否则 both 的起始态会把内容藏到延迟结束)并取消视差与漂移 */\n@media (prefers-reduced-motion: reduce) {\n .desk i {\n animation: none !important;\n }\n .desk,\n .desk-card {\n translate: none;\n }\n .login :deep(*),\n .login .desk-card,\n .login .login-corner {\n animation-delay: 0s !important;\n }\n}\n/* 窄屏收紧:卡片侧边留 16px,卡内边距随之压小(内联的 content-style 要靠 !important 盖住) */\n@media (max-width: 480px) {\n .login-stage {\n padding: 16px;\n }\n .desk-card :deep(.n-card__content) {\n padding: 22px 20px 18px !important;\n }\n}\n</style>\n\n<!-- View Transitions 的伪元素在文档根上,scoped 样式够不到,所以单独一块全局样式。\n 只在布局切换那一刻(.switching)给卡片命名:常驻的 view-transition-name 会让它多出独立图层。 -->\n<style>\n.login.switching .desk-card {\n view-transition-name: login-card;\n}\n::view-transition-group(login-card) {\n animation-duration: 0.62s;\n animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);\n}\n</style>\n"],"names":["app","useAppStore","t","useI18n","root","ref","raf","setParallax","x","y","_a","_b","onPointerMove","e","onBeforeUnmount","_createElementBlock","_normalizeClass","__props","_createElementVNode","_openBlock","_hoisted_1","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_hoisted_4","_createVNode","_unref","NTooltip","NButton","_cache","$event","Icon","_createTextVNode","_normalizeStyle","NCard"],"mappings":"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"}
1
+ {"version":3,"file":"LoginDesk2.vue.js","sources":["../../../../src/views/login/components/LoginDesk.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 入口类全屏页(登录 / 二次验证 / 第三方回调 / 门户加载失败)共用的外壳:macOS 锁屏语言。\n// 整页一张慢慢飘的柔光色场(.desk,颜色全由强调色推导,无网格)+ 浮在上面的毛玻璃卡,右上角是工具栏。\n// 单栏 = 居中一张卡;双栏(split)= 左栏品牌区(brand 插槽)压在色场上,右栏是这张卡。\n// 只管视觉外壳:卡里放什么、表单怎么提交都在各页自己手里。\n//\n// 动效(全部不回弹):入场按「卡 → 标题 → 字段 → 按钮」依次浮现(先模糊后清晰);\n// 色场与卡跟着指针做反向视差;leaving 为真时整页淡出放大一点(像 macOS 解锁),给登录成功收尾。\nimport { onBeforeUnmount, ref } from 'vue'\nimport { NButton, NCard, NTooltip } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useAppStore } from '#/stores/app'\n\nwithDefaults(\n defineProps<{\n /** 双栏:左栏渲染 brand 插槽,卡片宽度收到 384 */\n split?: boolean\n /** 卡片宽度(px),窄屏被 max-width:100% 收住 */\n width?: number\n /** NCard 内容区内边距 */\n contentStyle?: string\n /** 退场:登录成功后由页面置真,整页淡出,等动画播完再跳转 */\n leaving?: boolean\n }>(),\n { split: false, width: 400, contentStyle: 'padding: 26px 26px 22px', leaving: false },\n)\n\nconst app = useAppStore()\nconst { t } = useI18n()\n\n// 指针视差:只认鼠标(触屏没有悬停位置),坐标归一到 -1..1 写成 CSS 变量,位移与过渡都在 CSS 里。\n// 另外把指针相对卡片左上角的位置(--mx / --my,px)和「指针在窗口内」(--lit)写出来,\n// 给卡片面上那束跟着指针走的柔光用:指针停在卡片上时视差位移趋近于零,光斑是这时唯一的反馈。\nconst root = ref<HTMLElement | null>(null)\nlet raf = 0\nfunction setPointer(x: number, y: number, clientX?: number, clientY?: number) {\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n const el = root.value\n if (!el) return\n el.style.setProperty('--px', x.toFixed(3))\n el.style.setProperty('--py', y.toFixed(3))\n if (clientX === undefined || clientY === undefined) {\n // 指针离开:只熄灭柔光,保留最后位置,淡出时光斑不跳\n el.style.setProperty('--lit', '0')\n return\n }\n const card = el.querySelector('.desk-card')?.getBoundingClientRect()\n if (card) {\n el.style.setProperty('--mx', `${(clientX - card.left).toFixed(1)}px`)\n el.style.setProperty('--my', `${(clientY - card.top).toFixed(1)}px`)\n }\n el.style.setProperty('--lit', '1')\n })\n}\nfunction onPointerMove(e: PointerEvent) {\n if (e.pointerType !== 'mouse') return\n setPointer(\n (e.clientX / window.innerWidth) * 2 - 1,\n (e.clientY / window.innerHeight) * 2 - 1,\n e.clientX,\n e.clientY,\n )\n}\nonBeforeUnmount(() => cancelAnimationFrame(raf))\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"login desk-bg\"\n :class=\"{ split, leaving }\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"setPointer(0, 0)\"\n >\n <div class=\"desk\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n <i />\n </div>\n\n <div v-if=\"split\" class=\"login-brand\">\n <div class=\"login-brand-inner\"><slot name=\"brand\" /></div>\n </div>\n\n <div class=\"login-stage\">\n <!-- 右上角工具栏:页面自己的按钮(布局切换、语言)在前,主题切换永远贴最右角 -->\n <div class=\"login-corner\">\n <slot name=\"corner\" />\n <n-tooltip>\n <template #trigger>\n <n-button\n quaternary\n circle\n :aria-label=\"app.isDark ? t('app.light') : t('app.dark')\"\n @click=\"app.toggleDark()\"\n >\n <template #icon>\n <Icon :icon=\"app.isDark ? 'ph:moon' : 'ph:sun'\" :width=\"18\" />\n </template>\n </n-button>\n </template>\n {{ app.isDark ? t('app.light') : t('app.dark') }}\n </n-tooltip>\n </div>\n\n <!-- margin-top 给右上角工具栏留位:窄屏内容比视口高时,顶部不会被工具栏盖住 -->\n <div\n class=\"login-card\"\n :class=\"{ 'on-desk': split }\"\n :style=\"split ? undefined : { width: `${width}px` }\"\n >\n <slot name=\"above\" />\n <n-card :bordered=\"true\" class=\"desk-card\" :content-style=\"contentStyle\">\n <slot />\n </n-card>\n <slot name=\"after\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* 登录页(单栏 / 双栏都算)是 macOS 桌面那种纯色场:不要网格线,不要透视地面 */\n.login {\n /* 减速到底、不过冲:入场与视差共用这条曲线 */\n --rise: cubic-bezier(0.22, 1, 0.36, 1);\n min-height: 100dvh;\n background: var(--desk-base);\n position: relative;\n overflow: hidden;\n}\n.login.split {\n display: grid;\n grid-template-columns: minmax(340px, 46%) 1fr;\n}\n.login-stage {\n min-height: 100dvh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n position: relative;\n overflow: hidden;\n}\n\n/* 色场:四团 blur(70px) 的柔光球慢速漂移,颜色由强调色推导(--desk-1..4);\n 整体再按指针反向平移一点(用独立的 translate 属性,不和漂移动画的 transform 打架) */\n.desk {\n position: absolute;\n inset: -20%;\n pointer-events: none;\n z-index: 0;\n translate: calc(var(--px, 0) * -44px) calc(var(--py, 0) * -30px);\n transition: translate 1.2s var(--rise);\n}\n.desk i {\n position: absolute;\n display: block;\n border-radius: 50%;\n filter: blur(70px);\n opacity: var(--desk-op);\n}\n.desk i:nth-child(1) {\n left: 2%;\n top: 4%;\n width: 46%;\n height: 62%;\n background: var(--desk-1);\n animation: drift1 26s ease-in-out infinite alternate;\n}\n.desk i:nth-child(2) {\n left: 26%;\n top: 34%;\n width: 44%;\n height: 56%;\n background: var(--desk-2);\n animation: drift2 32s ease-in-out infinite alternate;\n}\n.desk i:nth-child(3) {\n left: 54%;\n top: -6%;\n width: 40%;\n height: 58%;\n background: var(--desk-3);\n animation: drift3 29s ease-in-out infinite alternate;\n}\n.desk i:nth-child(4) {\n left: 62%;\n top: 46%;\n width: 46%;\n height: 62%;\n background: var(--desk-4);\n animation: drift1 35s ease-in-out infinite alternate-reverse;\n}\n@keyframes drift1 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(6%, -5%, 0) scale(1.12);\n }\n}\n@keyframes drift2 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(-7%, 4%, 0) scale(1.08);\n }\n}\n@keyframes drift3 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(4%, 7%, 0) scale(1.15);\n }\n}\n\n.login-corner {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 3;\n display: flex;\n gap: 8px;\n animation: fadeIn 0.9s var(--rise) 0.7s both;\n}\n\n/* 双栏左栏:文字直接压在色场上(像 macOS 桌面上的字),不单独做一块彩色面板 */\n.login-brand {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 48px clamp(32px, 5vw, 76px);\n}\n.login-brand-inner {\n max-width: 440px;\n}\n\n.login-card {\n width: 400px;\n max-width: 100%;\n position: relative;\n z-index: 2;\n margin-top: 44px;\n}\n.login-card.on-desk {\n width: 384px;\n}\n\n/* 表单是一块浮在色场上的毛玻璃卡(macOS 的 vibrancy 材质),单栏双栏同一套 */\n.desk-card {\n border: 1px solid var(--glass-border) !important;\n border-radius: 22px !important;\n background: var(--glass-panel) !important;\n box-shadow: var(--glass-shadow) !important;\n backdrop-filter: blur(40px) saturate(180%);\n -webkit-backdrop-filter: blur(40px) saturate(180%);\n /* 反向视差:卡朝指针方向挪,色场反方向挪,拉出前后景深。\n 卡的跟随比色场快(0.45s 对 1.2s),指针一动卡就有回应;位移在窗口边缘最大,\n 指针停在卡片上时趋近于零,不会让要点的按钮在手下漂走 */\n translate: calc(var(--px, 0) * 16px) calc(var(--py, 0) * 11px);\n transition:\n translate 0.45s var(--rise),\n background-color 0.3s,\n border-color 0.3s,\n box-shadow 0.3s;\n isolation: isolate;\n}\n/* 跟着指针走的柔光:画在毛玻璃面上、内容的下面(isolation + z-index:-1),强调色推导,亮暗主题通用。\n 指针不在窗口内时淡出;--mx / --my 是指针相对卡片左上角的位置(见脚本) */\n.desk-card::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n border-radius: inherit;\n pointer-events: none;\n background: radial-gradient(\n 340px circle at var(--mx, 50%) var(--my, 0%),\n color-mix(in srgb, var(--signal) var(--spot, 28%), transparent),\n transparent 72%\n );\n opacity: var(--lit, 0);\n transition: opacity 0.5s var(--rise);\n}\n/* 亮色的玻璃底本来就亮,同样的强调色占比要给高一点才看得出;暗色里 20% 已经够醒目 */\n:root[data-theme='dark'] .desk-card {\n --spot: 20%;\n}\n.login-card :deep(.n-input) {\n border-radius: var(--radius-md);\n}\n/* 主按钮:强调色 → 第二色渐变,带一层强调色辉光;hover 只加深辉光并微提亮、不位移,按下轻轻收一下 */\n.login-card :deep(.n-button.cta) {\n background-image: linear-gradient(120deg, var(--signal), var(--login-accent-2));\n border-color: transparent;\n box-shadow: 0 10px 26px -10px var(--signal-glow);\n transition:\n box-shadow 0.22s var(--ease),\n transform 0.2s var(--ease),\n filter 0.2s var(--ease);\n}\n.login-card :deep(.n-button.cta:hover) {\n box-shadow: 0 16px 34px -10px var(--signal-glow);\n filter: brightness(1.04);\n}\n.login-card :deep(.n-button.cta:active:not(:disabled)) {\n transform: scale(0.985);\n filter: brightness(0.97);\n box-shadow: 0 6px 18px -10px var(--signal-glow);\n}\n\n/* ── 入场编排 ─────────────────────────────────────────────\n 动画必须挂在 .desk-card 自己身上,不能挂它的父级 .login-card:父级 opacity < 1 会让子元素的\n backdrop-filter 失去背景,动画期间卡是不模糊的,结束那一帧模糊才「啪」地打上去,看着就是生硬。\n 内容项(标题 / 字段 / 按钮 / 左栏文字)各自带延迟依次浮现,先模糊后清晰,不回弹。 */\n.desk-card {\n animation: cardIn 0.95s var(--rise) 0.08s both;\n}\n.login-card > :deep(:not(.desk-card)) {\n animation: fadeIn 0.9s var(--rise) 0.55s both;\n}\n\n/* 左栏:Logo → 标语 → 说明 → 亮点逐行 */\n.login-brand-inner :deep(.login-hero-panel > :not(.points)),\n.login-brand-inner :deep(.points li) {\n animation: riseIn 0.9s var(--rise) both;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(1)) {\n animation-delay: 0.1s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(2)) {\n animation-delay: 0.18s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(3)) {\n animation-delay: 0.26s;\n}\n.login-brand-inner :deep(.points li:nth-child(1)) {\n animation-delay: 0.36s;\n}\n.login-brand-inner :deep(.points li:nth-child(2)) {\n animation-delay: 0.43s;\n}\n.login-brand-inner :deep(.points li:nth-child(n + 3)) {\n animation-delay: 0.5s;\n}\n\n/* 卡内:LoginForm 的 .login-form > .lf-brand / .lf-body(标题、表单、第三方登录)和表单里的各行 */\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert),\n.login-card :deep(.lf-body > :not(form)),\n.login-card :deep(.lf-body form > *) {\n animation: riseIn 0.8s var(--rise) both;\n}\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert) {\n animation-delay: 0.18s;\n}\n.login-card :deep(.lf-body > :not(form)) {\n animation-delay: 0.22s;\n}\n.login-card :deep(.lf-body form > :nth-child(1)) {\n animation-delay: 0.28s;\n}\n.login-card :deep(.lf-body form > :nth-child(2)) {\n animation-delay: 0.34s;\n}\n.login-card :deep(.lf-body form > :nth-child(3)) {\n animation-delay: 0.4s;\n}\n.login-card :deep(.lf-body form > :nth-child(4)) {\n animation-delay: 0.46s;\n}\n.login-card :deep(.lf-body form > :nth-child(n + 5)) {\n animation-delay: 0.52s;\n}\n.login-card :deep(.lf-body > .lf-divider) {\n animation-delay: 0.56s;\n}\n.login-card :deep(.lf-body > .lf-sso) {\n animation-delay: 0.62s;\n}\n\n@keyframes cardIn {\n from {\n opacity: 0;\n transform: translate3d(0, 28px, 0) scale(0.965);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n@keyframes riseIn {\n from {\n opacity: 0;\n transform: translate3d(0, 12px, 0);\n filter: blur(6px);\n }\n to {\n opacity: 1;\n transform: none;\n filter: none;\n }\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ── 退场:登录成功后整页淡出并微微放大(macOS 解锁的感觉),色场留着不动 ── */\n.login.leaving .desk-card {\n animation: cardOut 0.34s cubic-bezier(0.4, 0, 1, 1) both;\n}\n.login.leaving .login-brand-inner,\n.login.leaving .login-corner,\n.login.leaving .login-card > :deep(:not(.desk-card)) {\n animation: fadeOut 0.28s ease-in both;\n}\n@keyframes cardOut {\n to {\n opacity: 0;\n transform: translate3d(0, -8px, 0) scale(1.02);\n }\n}\n@keyframes fadeOut {\n to {\n opacity: 0;\n }\n}\n\n/* 减少动效:全局规则已把时长压到近零,这里再清掉延迟(否则 both 的起始态会把内容藏到延迟结束)并取消视差与漂移 */\n@media (prefers-reduced-motion: reduce) {\n .desk i {\n animation: none !important;\n }\n .desk,\n .desk-card {\n translate: none;\n }\n .desk-card::after {\n display: none;\n }\n .login :deep(*),\n .login .desk-card,\n .login .login-corner {\n animation-delay: 0s !important;\n }\n}\n/* 窄屏收紧:卡片侧边留 16px,卡内边距随之压小(内联的 content-style 要靠 !important 盖住) */\n@media (max-width: 480px) {\n .login-stage {\n padding: 16px;\n }\n .desk-card :deep(.n-card__content) {\n padding: 22px 20px 18px !important;\n }\n}\n</style>\n\n<!-- View Transitions 的伪元素在文档根上,scoped 样式够不到,所以单独一块全局样式。\n 只在布局切换那一刻(.switching)给卡片命名:常驻的 view-transition-name 会让它多出独立图层。 -->\n<style>\n.login.switching .desk-card {\n view-transition-name: login-card;\n}\n::view-transition-group(login-card) {\n animation-duration: 0.62s;\n animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);\n}\n</style>\n"],"names":["app","useAppStore","t","useI18n","root","ref","raf","setPointer","x","y","clientX","clientY","el","card","_a","onPointerMove","onBeforeUnmount","_createElementBlock","_normalizeClass","__props","_createElementVNode","_openBlock","_hoisted_1","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_hoisted_4","_createVNode","_unref","NTooltip","NButton","_cache","$event","Icon","_createTextVNode","_normalizeStyle","NCard"],"mappings":"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"}
@@ -34,7 +34,7 @@ const te = { class: "fill-page" }, ge = /* @__PURE__ */ F({
34
34
  () => e.isRead ? t("notice.read") : t("notice.unread")
35
35
  )
36
36
  },
37
- { key: "title", title: () => t("notice.noticeTitle"), search: {} },
37
+ { key: "title", ellipsis: { tooltip: !0 }, title: () => t("notice.noticeTitle"), search: {} },
38
38
  {
39
39
  key: "type",
40
40
  title: () => t("notice.type"),