# 登录页客迹视觉 V1 对齐 — 实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 将 admin 登录页从 Art Design Pro 模板原版重做为客迹视觉 V1(深蓝品牌区 + 浅色表单区双栏),对齐设计稿 assets/design/keji-admin-v1/03-login.png。 **Architecture:** 重写三页共用组件 LoginLeftView.vue(背景图 + logo + 标语叠加层),简化 login/index.vue(移除 AuthTopBar/账号下拉/注册与忘记密码链接)并重写 style.css(固定浅色 + Element Plus 变量覆盖防暗色污染),同步更新 zh/en i18n 文案。 **Tech Stack:** Vue3 + TS + Element Plus + Tailwind(Art Design Pro 模板),Playwright 视觉验证。 **Spec:** docs/superpowers/specs/2026-09-17-login-keji-visual-v1-design.md(含全部决策记录与色值) **TDD 说明:** 纯视觉重构、登录逻辑零改动(spec 明确),无新增单元测试。验证 = Playwright 截图对照设计稿 + `pnpm build` + 现有测试不受影响。 **工作目录:** 全程在 `admin/` 下操作(git 仓库根为 D:\project\cms-cj,分支 m1)。 --- ### Task 1: i18n 文案更新 **Files:** - Modify: `admin/src/locales/langs/zh.json:151-179`(login 对象) - Modify: `admin/src/locales/langs/en.json:151-179`(login 对象) - [ ] **Step 1: 更新 zh.json 的 login 对象** 将 `zh.json` 中 `"login"` 对象内以下 key 的值替换(其余 key 原样保留): ```json "leftView": { "title": "看见来访,读懂客迹", "subTitle": "网站访问与客户旅程分析", "slogan": "数据驱动增长 · 洞察创造价值", "footer": "让每一次来访都有价值" }, "title": "欢迎登录客迹", "subTitle": "登录您的独立数据工作台", ``` 并在 `"placeholder"` 对象同级新增三个 key(放在 `"btnText"` 之后): ```json "accountLabel": "账号", "passwordLabel": "密码", "adminAssigned": "账号由管理员分配", ``` 同时把 `"rememberPwd": "记住密码"` 改为 `"rememberPwd": "保持登录"`。 删除 `"noAccount"` 和 `"register"` 两个 key(入口已移除)。 - [ ] **Step 2: 更新 en.json 的 login 对象** `en.json` 同结构对应更新: ```json "leftView": { "title": "See every visit, understand every journey", "subTitle": "Website visit & customer journey analytics", "slogan": "Data-driven growth · Insight-driven value", "footer": "Make every visit count" }, "title": "Welcome to KEJI", "subTitle": "Sign in to your data workspace", ``` 新增: ```json "accountLabel": "Account", "passwordLabel": "Password", "adminAssigned": "Accounts are assigned by the administrator", ``` `"rememberPwd": "Stay signed in"`;删除 `"noAccount"`、`"register"`。 **注意:** en.json 删除 noAccount/register 后,`register/index.vue` 等其他文件若引用 `$t('login.register')` 会显示 key 本身。先全局搜索确认只有 login/index.vue 引用(本任务后 Task 3 会移除该引用;若搜索发现其他引用处则保留 key 不删)。 - [ ] **Step 3: 验证 JSON 合法** Run: `python -c "import json; json.load(open('src/locales/langs/zh.json', encoding='utf-8')); json.load(open('src/locales/langs/en.json', encoding='utf-8')); print('OK')"` Expected: `OK` - [ ] **Step 4: Commit** ```bash git add src/locales/langs/zh.json src/locales/langs/en.json git commit -m "feat(admin): 登录页i18n文案对齐客迹V1" ``` --- ### Task 2: 重写 LoginLeftView.vue(左侧品牌区) **Files:** - Modify: `admin/src/components/core/views/login/LoginLeftView.vue`(整文件重写) 资源(已存在,无需新增):`src/assets/images/logo-w.png`(1944×809 透明底白字)、`src/assets/images/login/login-left-background.png`(1196×1315)。 - [ ] **Step 1: 整文件替换为以下内容** ```vue {{ $t('login.leftView.title') }} {{ $t('login.leftView.subTitle') }} {{ $t('login.leftView.slogan') }} {{ $t('login.leftView.footer') }} ``` 要点:背景图走 JS import + inline style(Vite 哈希 + 懒加载友好);`hideContent` prop 删除(已确认无调用方);`<=1600px` 中间宽度规则不再保留,仅 58vw 一档;`<=1180px` 直接 display:none。 - [ ] **Step 2: 类型检查编译通过** Run: `pnpm typecheck || pnpm run build`(若项目无 typecheck 脚本则跳过,Task 5 统一 build 验证) Expected: 无错误(LoginLeftView 无外部引用变化,register/forget-password 自动获得新品牌区) - [ ] **Step 3: Commit** ```bash git add src/components/core/views/login/LoginLeftView.vue git commit -m "feat(admin): 登录左侧品牌区重做为客迹V1深蓝视觉" ``` --- ### Task 3: 简化 login/index.vue + 重写 style.css(右侧表单) **Files:** - Modify: `admin/src/views/auth/login/index.vue`(模板 + script + style) - Modify: `admin/src/views/auth/login/style.css`(整文件重写) - [ ] **Step 1: 替换 index.vue 的 template 部分** ```vue {{ $t('login.title') }} {{ $t('login.subTitle') }} {{ $t('login.placeholder.slider') }} {{ $t('login.rememberPwd') }} {{ $t('login.btnText') }} {{ $t('login.adminAssigned') }} ``` - [ ] **Step 2: 修改 index.vue 的 script 部分** 1. 新增 import:`import { User, Lock } from '@element-plus/icons-vue'` 2. 删除:`import { useSettingStore } from '@/store/modules/setting'`、`const settingStore = useSettingStore()`、`const { isDark } = storeToRefs(settingStore)`(滑块已固定浅色,isDark 不再使用) 3. 删除:`type AccountKey`、`export interface Account`、`const accounts = computed...` 整块、`setupAccount` 函数、`onMounted(() => { setupAccount('admin') })` 4. `formData` 初始化改为 `username: 'admin'`(保持 M1 单管理员预填行为): ```ts const formData = reactive({ account: '', username: 'admin', password: '', rememberPassword: true }) ``` 5. 其余逻辑(handleSubmit、resetDragVerify、showLoginSuccessNotice、formKey/locale watch)**零改动**。 - [ ] **Step 3: index.vue 底部 scoped style 简化** 删除 `:deep(.el-select__wrapper)` 覆盖块(ElSelect 已移除),`@import './style.css'` 保留。 - [ ] **Step 4: style.css 整文件替换** ```css @reference '@styles/core/tailwind.css'; /* 授权页右侧区域(客迹V1:固定浅色,不随暗色主题变化) */ .auth-right-bg { /* 覆盖 Element Plus 暗色变量,防止 html.dark 时表单控件变暗 */ --el-bg-color: #ffffff; --el-bg-color-overlay: #ffffff; --el-fill-color-blank: #ffffff; --el-fill-color-light: #f5f7fa; --el-text-color-primary: #1a1a1a; --el-text-color-regular: #303133; --el-border-color: #dcdfe6; --el-border-color-light: #e4e7ed; --el-border-color-lighter: #ebeef5; background-color: #f7f8fa; } .auth-right-wrap { @apply absolute inset-0 w-[440px] h-[680px] py-[5px] m-auto overflow-hidden max-sm:px-7 max-sm:w-full animate-[slideInRight_0.6s_cubic-bezier(0.25,0.46,0.45,0.94)_forwards] max-md:animate-none; .form { @apply h-full py-[40px]; } .title { @apply text-[#1A1A1A] text-[32px] font-semibold text-center; } .sub-title { @apply mt-[10px] text-[#8A94A6] text-[15px] text-center; } .custom-height { @apply !h-[56px]; } /* 表单标签样式 */ :deep(.el-form-item__label) { color: #1a1a1a; font-weight: 600; } /* 账号由管理员分配 */ .admin-assigned { @apply flex-cc gap-3 mt-8; .line { @apply inline-block w-6 h-px bg-[#D3D9E3]; } .text { @apply text-[13px] text-[#9AA3B2]; } } } /* 滑入动画 */ @keyframes slideInRight { from { opacity: 0; transform: translateX(30px); } to { opacity: 1; transform: translateX(0); } } ``` - [ ] **Step 5: 验证无残留引用** Run: `grep -rn "setupAccount\|AuthTopBar\|noAccount\|ElSelect" src/views/auth/login/` Expected: 无输出(login 页内已无这些引用;register/forget-password 中的 AuthTopBar 不受影响) - [ ] **Step 6: Commit** ```bash git add src/views/auth/login/index.vue src/views/auth/login/style.css git commit -m "feat(admin): 登录表单区对齐客迹V1——移除账号下拉/注册/忘记密码入口,固定浅色" ``` --- ### Task 4: 视觉验证(Playwright 截图对照设计稿) **Files:** - 无代码改动;产出截图到 `admin/exports/`(或临时目录,不入库) - [ ] **Step 1: 启动 dev server** Run: `cd admin && pnpm dev`(后台运行) Expected: Vite 启动在 http://localhost:3006 - [ ] **Step 2: Playwright 三档截图** 用 playwright MCP 打开 `http://localhost:3006/#/login`(或路由实际形态,先 navigate 探测),分别设置视口并截图: 1. 1920×1080(桌面标准) 2. 1440×900(小桌面) 3. 375×812(移动,验证左侧隐藏 + 表单单栏) - [ ] **Step 3: 对照检查清单** - [ ] 左侧 58vw 深蓝背景图完整覆盖、无拉伸变形 - [ ] logo-w.png 白字清晰可见(左上角) - [ ] 主标语/副标题/短横线/口号/底部文案齐全、层级与留白接近设计稿 - [ ] 右侧 #F7F8FA 底、标题居中、输入框 56px 高带图标 - [ ] 滑块浅蓝灰底、文字 #4D5875 可读、验证通过后主色进度条 - [ ] 登录按钮全宽主色 - [ ] 底部"— 账号由管理员分配 —" - [ ] 375px:左侧隐藏、表单居中占满 - [ ] 浏览器切 html.dark 类(Playwright evaluate `document.documentElement.classList.add('dark')`)后右侧仍浅色 发现问题 → 回到对应 Task 修正(样式微调不新增任务)。 - [ ] **Step 4: 实际登录冒烟** 本地 dev 直连生产 API 不可用时仅验证 UI 交互:滑块可拖动、按钮可点、空值提交报错提示正常。(真实登录冒烟放到 Task 5 线上验证时用管理员账号完成,密码不入库——问用户索取或由用户自测) --- ### Task 5: 构建验证 + 部署上线 - [ ] **Step 1: pnpm build** Run: `cd admin && pnpm build` Expected: 构建成功,dist/ 生成新哈希文件 - [ ] **Step 2: 标准部署流程(项目约定:测试通过后直接上线,无需等确认)** ```bash cd admin && pnpm build tar -czf /tmp/admin-dist.tar.gz dist/ scp -i ~/.ssh/id_ed25519 -J root@8.152.213.143 /tmp/admin-dist.tar.gz root@47.254.176.10:/tmp/ ssh -i ~/.ssh/id_ed25519 -J root@8.152.213.143 root@47.254.176.10 "cd /opt/cms-cj && tar -xzf /tmp/admin-dist.tar.gz && rm /tmp/admin-dist.tar.gz" ``` (原地覆盖 dist 内容,bind mount 不受影响,无需重启容器) - [ ] **Step 3: 线上验证** Playwright 打开 https://tracker.12418113.xyz 登录页,截图确认新视觉生效;记录 `index-xxx.js` 哈希作为版本号。 - [ ] **Step 4: 汇报** 汇报内容:完成项清单、三档截图、线上版本哈希、验证结果。 --- ## 风险提示(执行者注意) 1. **严格不动服务器其他项目**(1Panel、其他网站容器)——只解压覆盖 /opt/cms-cj 下的前端文件。 2. `05-login-left-background.png` 为 AI 去字重建背景,与设计稿非逐像素一致是**预期内的**,不要试图"修正"背景图。 3. register/forget-password 页共用 LoginLeftView,视觉同步变化是**预期行为**(spec 决策 4)。 4. 若 grep 发现 `login.noAccount`/`login.register` 有 login 页之外的引用,保留对应 i18n key 不删,并在 commit message 中说明。
{{ $t('login.leftView.subTitle') }}
{{ $t('login.leftView.slogan') }}
{{ $t('login.leftView.footer') }}
{{ $t('login.subTitle') }}
{{ $t('login.placeholder.slider') }}