2026-09-23
登录页「记住密码」多账号下拉选择(已完成)
- 需求:登录页勾选记住密码后,把企业名+账号+密码存本地;之后企业名/账号均可下拉选择(同时支持手输新值)
- 实现:
src/hooks/web/useCache.ts:新增 CACHE_KEY.SavedAccounts = 'savedAccounts'
src/utils/auth.ts:新增 SavedAccountType + getSavedAccounts / addSavedAccount / removeSavedAccount,密码复用 encrypt/decrypt(RSA)加密存 localStorage(web-storage-cache,有效期 365 天,上限 20 条,同 tenantName+username 去重覆盖并置顶)
src/views/Login/components/LoginForm.vue:
- 企业名、账号两个
el-input 改为 el-select(filterable + allow-create + default-first-option,仍可手输新值)
- 账号下拉项显示
账号(企业名),右侧删除图标可单条移除
- 选企业名 → 自动带出该企业下最近记住的账号+密码;选账号 → 自动带出企业名+密码(优先匹配当前企业名)
- 登录成功:勾选记住 →
addSavedAccount;未勾选 → 从列表移除该账号
src/locales/zh-CN.ts / en.ts:新增 login.rememberPassword(记住密码)
- 已跑
vue-tsc --noEmit,改动文件无类型报错
⚠️ 补做:真正生效的登录页是 src/views/Login/Login.vue(不是 components/LoginForm.vue)
- 事由:在
components/LoginForm.vue 改完后用户截图反馈「没看到新功能」
- 根因:本项目真实登录路由渲染的是
views/Login/Login.vue 的自定义手写表单(原生 <input> + .inputM/.inputS 样式 + 「使用谷歌浏览器」页脚);
components/LoginForm.vue / MobileForm / QrCodeForm / RegisterForm 在 Login.vue 里全是注释掉的(<LoginForm ... /> 注释),改了不生效
- 排查手法:用户截图里的特征文案(
账号登录 / 使用谷歌浏览器 / 欢迎来到颐年)→ 在项目里 Grep,直接定位真正的组件
- 教训:改登录页前先确认实际挂载的组件;本项目多个 Login 入口并存,别默认
LoginForm.vue
- Login.vue 侧实现:企业名/账号输入框
@focus/@input 弹自绘 .account-dropdown 面板(失焦 150ms 延时关闭,选项用 @mousedown.prevent 以免 blur 早于 click);
密码框下新增「记住密码」el-checkbox(登录按钮 marginTop 由 40px 收为 12px,卡片 500px 高度不变);登录成功分支同样 addSavedAccount / removeSavedAccount
- 共用同一套
src/utils/auth.ts 的 SavedAccounts 存储(跨两个登录页互通)
🐛 上述功能上线后两个 BUG 的修复(务必记住这两个坑)
- 密码被清空 / 回填后是乱码
- 根因:
src/utils/auth.ts 的 setLoginForm() 原地改写传入对象(loginForm.password = encrypt(...))。
handleLogin 里先 setLoginForm(loginData.loginForm) 再 addSavedAccount(...) → 存进去的是「密文再加密」→ 读时解不开 → 密码空
- 修法:①
setLoginForm 改为 { ...loginForm, password: encrypt(...) } 不再改原对象;
② SavedAccounts 的增删改统一基于原始密文列表 getSavedAccountsRaw(),禁止「先全解密再全加密」(会把解密失败的条目永久写成空);
③ 解密结果仍像密文(≥40 位 base64)时再解一层,自动修复历史二次加密数据
- 自绘下拉面板自动关闭
- 根因:面板
position:absolute 在 overflow:auto 滚动容器内会撑出滚动条→重排→input 失焦→blur 关闭;且原本用 blur+150ms 延时关闭太脆
- 修法:面板
Teleport to="body" + position:fixed + 输入框 getBoundingClientRect() 定位;
关闭只判 document.mousedown 是否落在面板/输入框外,完全不依赖 focus/blur;scroll/resize 只重新定位
- 选中空的记住密码不再覆盖用户已输入的内容(
if (matched.password) 守卫)
vue-tsc --noEmit 已过
交互约定
- 回填策略:选企业名 → 带出该企业最近记住的账号+密码;选账号 → 带出企业名+密码;两者都加非空守卫
后续微调(同日)
- 登录下拉改为打开即展示全部记住的企业名/账号,不再按输入内容过滤(用户明确要求)
- 临时医嘱单打印页
short-doctor-order/Print.vue:字体全部改黑色(标题/字段标签/表头),红色仅保留线条(标题双红线、表格边框);
长期医嘱单 Print.vue 本就是黑色;execute-doctor-order 无红色字体