diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..a05e830 Binary files /dev/null and b/.DS_Store differ diff --git a/.claude/commands/project-scan.md b/.claude/commands/project-scan.md index 79d10d1..7dc3cac 100644 --- a/.claude/commands/project-scan.md +++ b/.claude/commands/project-scan.md @@ -11,10 +11,11 @@ description: 扫描项目生成配置(CLAUDE.md/restart.sh/ignore/Docker) | 1 | `.claude/CLAUDE.md` | 项目配置 | 直接生成 | | 2 | `restart.sh` | 前后端打包+启动脚本 | `templates/restart-*.sh.tmpl` | | 3 | `.claudeignore` | Claude Code 忽略 | `templates/claudeignore.tmpl` | -| 4 | `.gitignore` | Git 忽略 | `templates/gitignore-*.tmpl` | -| 5 | `.dockerignore` | Docker 忽略 | `templates/dockerignore.tmpl` | -| 6 | `Dockerfile` | 容器构建 | `templates/Dockerfile-*.tmpl` | -| 7 | `docker-compose.yml` | 容器编排 | `templates/docker-compose-*.yml.tmpl` | +| 4 | `.geminiignore` | Gemini CLI 忽略 | 与 `.claudeignore` 内容相同 | +| 5 | `.gitignore` | Git 忽略 | `templates/gitignore-*.tmpl` | +| 6 | `.dockerignore` | Docker 忽略 | `templates/dockerignore.tmpl` | +| 7 | `Dockerfile` | 容器构建 | `templates/Dockerfile-*.tmpl` | +| 8 | `docker-compose.yml` | 容器编排 | `templates/docker-compose-*.yml.tmpl` | --- @@ -50,7 +51,7 @@ description: 扫描项目生成配置(CLAUDE.md/restart.sh/ignore/Docker) **数据库**: [检测结果] **前后端分离**: [是/否] -即将生成 7 个文件,是否继续?[Y/n] +即将生成 8 个文件,是否继续?[Y/n] ``` ### 步骤 3:逐个生成文件 @@ -96,6 +97,7 @@ chmod +x restart.sh ✅ .claude/CLAUDE.md ✅ restart.sh ✅ .claudeignore +✅ .geminiignore ✅ .gitignore ✅ .dockerignore ✅ Dockerfile diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index cc0d32f..aa8d2ff 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -154,6 +154,229 @@ --- +## 布局一致性规则 + +创建或修改前端页面时,必须确保与项目中其他页面保持视觉和结构一致。 + +### 三大原则 + +| 原则 | 说明 | +|------|------| +| **先查后写** | 创建新页面前,先读取 2-3 个现有页面,提取布局模式 | +| **变量优先** | 间距/尺寸必须使用 CSS 变量或设计 Token,禁止硬编码 | +| **结构一致** | 同类型页面使用相同的 DOM 结构 | + +### 间距系统约束 + +所有间距值必须是 **4px 的倍数**: + +| 允许 | 禁止 | +|------|------| +| 4, 8, 12, 16, 20, 24, 32, 40, 48 | 5, 7, 13, 17, 23, 25, 30 | + +推荐使用变量而非硬编码: +- ✅ `padding: var(--page-padding)` +- ✅ `gap: var(--spacing-md)` +- ❌ `padding: 23px` +- ❌ `margin-top: 17px` + +### 页面结构规范 + +标准页面应遵循统一结构: + +``` +┌─────────────────────────────────────┐ +│ 页面标题区(固定高度) │ +│ [图标] 标题 | 描述 [操作按钮] │ +├─────────────────────────────────────┤ +│ 内容区(统一 padding) │ +│ │ +└─────────────────────────────────────┘ +``` + +### 新建页面检查清单 + +创建新页面前必须执行: + +- [ ] 读取了 2-3 个现有页面的布局结构 +- [ ] 页面标题区的 padding-top 与其他页面一致 +- [ ] 内容区的 padding 使用了变量或与其他页面相同 +- [ ] 不存在硬编码的非 4 倍数间距值 +- [ ] CSS 类名与现有命名风格一致 + +### 禁止行为 + +- ❌ 每个页面单独定义不同的 padding +- ❌ 使用硬编码的非 4 倍数间距 +- ❌ 新页面与现有页面结构差异过大 +- ❌ 不查看现有页面就创建新页面 + +--- + +## 覆盖层组件规范 + +系统中所有覆盖层(蒙版、遮罩、状态提示)必须统一管理,禁止各页面单独实现。 + +### 核心原则 + +| 原则 | 说明 | +|------|------| +| **容器统一** | 所有页面内容区容器结构一致(前提条件) | +| **单一来源** | 同类覆盖层只有一份组件实现 | +| **统一定位** | 所有覆盖层使用相同的定位策略 | +| **统一层级** | z-index 按类型分配,避免冲突 | +| **统一居中** | 内容居中方式一致,禁止硬编码偏移 | + +### 页面容器规范(前提条件) + +覆盖层位置一致的前提是**页面容器结构一致**。 + +**所有页面的内容区容器必须**: +- 设置统一的最小高度(撑满可视区域) +- 设置 `position: relative`(作为覆盖层定位基准) +- 使用一致的 DOM 结构层级 + +**容器结构示意**: + +``` +┌─────────────────────────────────────────┐ +│ App │ +│ ┌─────────┬───────────────────────────┐ │ +│ │ │ PageContent │ │ +│ │ Sidebar │ - position: relative │ │ +│ │ │ - min-height: 统一值 │ │ +│ │ │ ┌───────────────────────┐ │ │ +│ │ │ │ 页面具体内容 │ │ │ +│ │ │ └───────────────────────┘ │ │ +│ │ │ ┌───────────────────────┐ │ │ +│ │ │ │ 覆盖层(absolute) │ │ │ +│ │ │ └───────────────────────┘ │ │ +│ └─────────┴───────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +**禁止行为**: +- ❌ 不同页面内容区容器高度不一致 +- ❌ 容器未设置 position: relative +- ❌ 覆盖层定位基准不明确 + +### 覆盖层类型 + +系统中常见的覆盖层类型: + +| 类型 | 场景 | +|------|------| +| 权限蒙版 | 会员专属、功能受限、未登录 | +| 加载状态 | 数据加载中、提交中 | +| 空状态 | 无数据、无结果 | +| 错误状态 | 加载失败、网络异常 | +| 确认蒙版 | 危险操作确认 | + +### 一致性要求 + +**定位方式**: +- 所有覆盖层应使用相同的定位策略 +- 建议相对于内容区定位,避免遮挡导航/侧边栏 +- 禁止使用 `margin-top` 等硬编码偏移值 + +**居中方式**: +- 所有覆盖层内容居中方式应一致 +- 禁止不同页面使用不同的居中实现 + +**层级管理**: +- 项目应定义统一的 z-index 规范 +- 不同类型覆盖层应有明确的层级顺序 +- 禁止随意使用 `z-index: 999` 等魔法数字 + +### 蒙版定位规则(解决位置跳动) + +**问题**:蒙版在不同页面切换时位置上下跳动,原因是相对于「内容高度」居中而非「固定高度基准」居中。 + +**核心原则**: + +``` +❌ 错误:蒙版相对于「内容高度」居中 + → 内容多则蒙版偏下,内容少则蒙版偏上 + +✅ 正确:蒙版相对于「固定高度基准」居中 + → 无论内容多少,位置始终一致 +``` + +**两种正确方案**: + +| 方案 | 定位方式 | 适用场景 | +|------|---------|---------| +| 视口居中 | `position: fixed` + `inset: 0` | 全屏蒙版、模态框 | +| 容器居中 | 容器 `min-height` + 蒙版 `absolute` | 页面级蒙版(不遮挡导航) | + +**方案一:视口居中** + +```css +.overlay { + position: fixed; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 100; +} +``` + +**方案二:容器居中(推荐)** + +```css +/* 容器必须有固定的最小高度 */ +.page-content { + position: relative; + min-height: calc(100vh - var(--header-height, 0px)); +} + +/* 蒙版相对于容器居中 */ +.overlay { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; +} +``` + +**禁止做法**: +- ❌ 蒙版相对于内容高度居中(高度由内容撑开) +- ❌ 使用 `margin-top` 等硬编码偏移调整位置 +- ❌ 不同页面使用不同的居中实现 + +**验证方法**: +- 切换不同页面,蒙版位置是否一致? +- 页面内容增减时,蒙版位置是否变化? +- 不同屏幕高度下,蒙版是否始终可见? + +### 检查清单 + +创建或修改页面时: + +**容器检查**: +- [ ] 页面内容区容器是否设置了 position: relative +- [ ] 页面内容区容器是否设置了统一的 min-height +- [ ] 容器结构是否与其他页面一致 + +**覆盖层检查**: +- [ ] 是否复用了项目中已有的覆盖层组件 +- [ ] 是否存在重复实现的蒙版代码 +- [ ] 覆盖层定位方式是否与其他页面一致 +- [ ] 覆盖层居中位置是否与其他页面一致 +- [ ] z-index 是否符合项目规范 + +### 禁止行为 + +- ❌ 不同页面内容区容器结构不一致 +- ❌ 各页面单独实现相同功能的覆盖层 +- ❌ 不同页面的覆盖层位置不一致(上蹿下跳) +- ❌ 使用硬编码偏移值定位覆盖层内容 +- ❌ 随意使用 z-index 魔法数字 + +--- + ## 大文件处理策略 处理超过 500 行的文件时,必须遵循以下规则,防止 API 超时或响应截断。 diff --git a/.gemini/commands/layout-check.toml b/.gemini/commands/layout-check.toml new file mode 100644 index 0000000..ead1462 --- /dev/null +++ b/.gemini/commands/layout-check.toml @@ -0,0 +1,540 @@ +# 布局一致性检查命令 +# 用法: /layout-check [目录路径] + +description = "检查项目页面布局一致性,找出间距/结构不统一的问题" + +prompt = """ +你是一位前端架构师,专注于 UI 一致性审查。 + +## 任务 + +检查项目中所有页面的布局一致性,找出以下问题: +1. 页面标题区位置/间距不一致 +2. 内容区 padding 不统一 +3. 硬编码的非 4 倍数间距值 +4. 页面结构差异过大 + +## 输入 + +检查范围:{{args}} + +如果未指定,默认检查 `src/views/` 或 `src/pages/` 目录。 + +--- + +## 检查步骤 + +### 1. 扫描页面文件 + +找出所有 `.vue` 页面文件(排除 components 目录下的组件)。 + +### 2. 提取布局信息 + +对每个页面提取: +- 页面容器的 class 名 +- 标题区的结构和 padding-top +- 内容区的 padding 值 +- 使用的间距值(margin/padding/gap) + +### 3. 检查页面容器一致性 + +检查所有页面的内容区容器(覆盖层定位的前提条件): +- 容器是否设置了 position: relative(作为覆盖层定位基准) +- 容器是否设置了统一的 min-height(撑满可视区域) +- 容器的 DOM 结构层级是否一致 +- 容器的 class 命名是否统一 + +### 4. 检查覆盖层一致性 + +检查所有覆盖层组件(蒙版、遮罩、状态提示): +- 是否存在重复实现(同类覆盖层应只有一份组件) +- 定位方式是否一致(所有覆盖层应使用相同的 position 策略) +- 居中方式是否一致(禁止不同页面使用不同的居中实现) +- z-index 是否有统一规范(禁止魔法数字如 999) +- 覆盖层位置是否一致(禁止上蹿下跳) + +### 4.5. 检查蒙版定位基准(重点) + +**蒙版位置跳动的根本原因**:蒙版相对于「内容高度」居中,而非「固定高度基准」居中。 + +检查每个带蒙版的页面: +1. 蒙版的定位基准是什么? + - ✅ 正确:`position: fixed`(相对视口) + - ✅ 正确:`position: absolute` + 容器有 `min-height`(固定高度) + - ❌ 错误:`position: absolute` + 容器高度由内容撑开 +2. 容器是否设置了固定的 `min-height`? + - ✅ `min-height: calc(100vh - header高度)` + - ❌ `min-height: auto` 或未设置 +3. 居中方式是否一致? + - ✅ 所有页面使用相同的居中方式 + - ❌ 不同页面使用不同的实现 + +### 5. 对比分析 + +- 找出间距值的差异 +- 标记非 4 倍数的间距值(如 5, 7, 13, 17, 23, 25, 30 等) +- 识别结构差异较大的页面 +- 识别覆盖层实现不一致的页面 + +--- + +## 输出格式 + +### 页面布局摘要 + +| 页面 | 标题区 padding-top | 内容区 padding | 问题 | +|------|-------------------|----------------|------| +| Home.vue | 24px | 24px | - | +| Task.vue | 16px | 20px | ⚠️ 不一致 | +| Goal.vue | 24px | 24px | - | + +### 问题清单 + +#### ⚠️ 间距不一致 + +| 文件 | 行号 | 当前值 | 建议值 | +|------|------|--------|--------| +| Task.vue | 45 | padding-top: 16px | 24px(与其他页面一致) | +| Task.vue | 52 | padding: 20px | 24px(与其他页面一致) | + +#### ❌ 非 4 倍数间距 + +| 文件 | 行号 | 问题值 | 建议值 | +|------|------|--------|--------| +| Member.vue | 78 | margin: 17px | 16px 或 20px | +| Member.vue | 92 | gap: 13px | 12px 或 16px | + +#### ❌ 页面容器不一致 + +| 文件 | 问题 | 建议 | +|------|------|------| +| [文件名] | 容器未设置 position: relative | 添加 position: relative | +| [文件名] | 容器 min-height 与其他页面不同 | 统一为项目规范值 | +| [文件名] | 容器 DOM 结构与其他页面不同 | 统一容器结构 | + +#### ❌ 覆盖层不一致 + +| 文件 | 问题 | 建议 | +|------|------|------| +| [文件名] | 重复实现了蒙版组件 | 复用项目中已有的覆盖层组件 | +| [文件名] | 定位方式与其他页面不同 | 统一使用相同的定位策略 | +| [文件名] | 使用 margin-top 硬编码偏移 | 改用统一的居中方式 | +| [文件名] | z-index 使用魔法数字 | 遵循项目的层级规范 | + +#### ❌ 蒙版位置跳动(重点问题) + +| 文件 | 问题 | 根因 | 建议 | +|------|------|------|------| +| [文件名] | 蒙版相对内容高度居中 | 容器无 min-height | 容器添加 `min-height: calc(100vh - header)` | +| [文件名] | 不同页面蒙版位置不一致 | 定位基准不同 | 统一使用固定高度容器或 fixed 定位 | +| [文件名] | 页面切换时蒙版上下跳动 | 各页面内容高度不同 | 所有页面容器使用相同的 min-height | + +### 统一化建议 + +根据项目中使用频率最高的值,建议统一为: +- 页面 padding-top: **[推荐值]** +- 内容区 padding: **[推荐值]** +- 卡片间距: **[推荐值]** +- 元素间距: **[推荐值]** + +### CSS 变量建议 + +如果项目尚未定义间距变量,建议添加: + +```css +:root { + --page-padding: 24px; + --section-gap: 16px; + --card-gap: 12px; + --element-gap: 8px; +} +``` + +--- + +## 修复流程 + +检查完成后,询问用户是否修复。 + +### 问题分级 + +| 级别 | 类型 | 修复方式 | +|------|------|---------| +| L1 简单 | 非 4 倍数间距、z-index 魔法数字 | 批量修复,一次确认 | +| L2 中等 | padding/margin 不一致、容器 min-height 不一致 | 分组展示,批量确认 | +| L2.5 容器 | 容器缺少 position: relative | 分组展示,批量确认 | +| L3 复杂 | 覆盖层重复实现、定位策略不同、容器结构不同 | 逐个展示 diff,逐个确认 | + +### 步骤 1:询问是否修复 + +检查完成后输出: + +``` +--- + +## 是否修复? + +发现以下可修复的问题: +- L1 简单问题:X 个(间距值、z-index) +- L2 中等问题:X 个(padding/margin 不一致) +- L2.5 容器问题:X 个(position/min-height) +- L3 复杂问题:X 个(覆盖层重构、蒙版位置跳动) + +请选择: +1. 全部修复 +2. 选择性修复(输入级别,如 L1 或 L1,L2) +3. 跳过,仅查看 +``` + +### 步骤 2:修复前检查 + +用户选择修复后,检查 git 状态: + +``` +⚠️ 修复前检查 + +当前 git 状态: +- 分支:[branch name] +- 未提交更改:[有/无] + +即将修改 X 个文件。建议先提交当前更改。 + +是否继续?[Y/n] +``` + +### 步骤 3:L1 简单问题 - 批量修复 + +``` +## L1 简单问题(共 X 个) + +| 文件 | 行号 | 当前值 | 修复为 | +|------|------|--------|--------| +| Member.vue | 78 | margin: 17px | 16px | +| Member.vue | 92 | gap: 13px | 12px | +| Stats.vue | 45 | z-index: 999 | 按项目规范调整 | + +是否修复以上问题?[Y/n] +``` + +### 步骤 4:L2 中等问题 - 分组确认 + +``` +## L2 中等问题(共 X 个) + +### padding-top 不一致 + +项目主流值:24px(使用率 70%) + +| 文件 | 行号 | 当前值 | +|------|------|--------| +| Task.vue | 45 | 16px | +| Member.vue | 32 | 20px | + +统一为 24px?[Y/n/自定义值] +``` + +### 步骤 4.5:L2.5 容器问题 - 批量确认 + +``` +## L2.5 容器问题(共 X 个) + +以下页面容器缺少 position: relative(覆盖层定位基准): + +| 文件 | 行号 | 容器选择器 | +|------|------|-----------| +| Diary.vue | 12 | .page-content | +| Review.vue | 15 | .review-container | +| Stats.vue | 10 | .stats-wrapper | + +为以上容器添加 position: relative?[Y/n] +``` + +``` +## L2.5 容器问题(共 X 个) + +以下页面容器 min-height 不一致: + +| 文件 | 行号 | 当前值 | +|------|------|--------| +| Diary.vue | 18 | min-height: 500px | +| Review.vue | 22 | min-height: auto | +| Stats.vue | 16 | 未设置 | + +项目主流值:min-height: calc(100vh - 60px) + +统一为此值?[Y/n/自定义值] +``` + +### 步骤 5:L3 复杂问题 - 逐个确认 + +``` +## L3 复杂问题 1/X:覆盖层重复实现 + +发现 X 个页面各自实现了相似的蒙版: +- [文件1] (行 XX-XX) +- [文件2] (行 XX-XX) +- [文件3] (行 XX-XX) + +建议方案: +1. 提取为统一组件 +2. 各页面改为引用该组件 + +预览修改: + +【新建文件】[组件路径] +┌──────────────────────────────────── +│ [组件代码预览] +└──────────────────────────────────── + +【修改文件】[页面文件] +┌──────────────────────────────────── +│ - [删除的代码] +│ + [新增的代码] +└──────────────────────────────────── + +是否应用?[Y/n/跳过] +``` + +``` +## L3 复杂问题 2/X:覆盖层定位不一致 + +发现定位方式不同: +- [文件1]: [定位方式1] +- [文件2]: [定位方式2] +- [文件3]: [定位方式3] + +建议统一为:[推荐的定位方式] + +预览修改: + +【修改文件】[文件名] (行 XX) +┌──────────────────────────────────── +│ - [原代码] +│ + [新代码] +└──────────────────────────────────── + +是否应用?[Y/n/跳过] +``` + +``` +## L3 复杂问题 X/X:蒙版位置跳动 + +发现以下页面的蒙版位置不一致(页面切换时上下跳动): + +| 页面 | 蒙版定位 | 容器 min-height | 问题 | +|------|---------|----------------|------| +| Diary.vue | absolute | 未设置 | 蒙版偏下 | +| Review.vue | absolute | 500px | 蒙版偏上 | +| Stats.vue | absolute | auto | 蒙版居中 | + +**根本原因**:蒙版相对于「内容高度」居中,而非「固定高度基准」居中。 + +**建议方案**: +1. 所有页面容器统一设置 `min-height: calc(100vh - header高度)` +2. 或改用 `position: fixed` 实现全屏蒙版 + +预览修改: + +【修改文件】Diary.vue +┌──────────────────────────────────── +│ .page-content { +│ + min-height: calc(100vh - 60px); +│ position: relative; +│ } +└──────────────────────────────────── + +【修改文件】Review.vue +┌──────────────────────────────────── +│ .review-container { +│ - min-height: 500px; +│ + min-height: calc(100vh - 60px); +│ position: relative; +│ } +└──────────────────────────────────── + +是否应用?[Y/n/跳过] +``` + +``` +## L3 复杂问题 X/X:页面容器结构不同 + +发现页面容器 DOM 结构不一致: + +- Diary.vue: div.page > div.content > 蒙版 +- Review.vue: div.review-page > 蒙版 +- Stats.vue: section.stats > div.inner > 蒙版 + +建议统一为: +div.page-container (position: relative, min-height: 统一值) + └── 页面内容 + └── 覆盖层 (position: absolute) + +预览修改: + +【修改文件】Review.vue +┌──────────────────────────────────── +│ -