Files
Road_roller/.claude/skills/project-structure/SKILL.md
2026-09-17 08:52:53 +08:00

437 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Project Structure Skill
本 skill 定义项目的分层架构和文件组织规范,用于指导 Agent 在创建新页面、组件时遵循统一的目录结构。
## 核心原则
1. **页面放在 `pages/`** - 每个页面一个目录,包含 `index.vue`
2. **组件放在 `components/`** - 公共组件直接放目录下,页面专属组件按页面名分子目录
3. **页面专属组件与页面同名** - 如 `home` 页面的组件放在 `components/home/`
4. **使用 easycom 自动加载** - 无需手动 import,组件通过文件路径自动生成标签名
## 组件放置规则(重要)
### 公共组件(跨页面复用)
当用户要求创建**公共组件**时,直接放在 `components/` 根目录下:
```
components/
├── backNav.vue # 通用返回导航栏
├── tabBar.vue # 通用底部栏
├── modal.vue # 通用弹窗
└── ...
```
标签名:`<back-nav />`、`<tab-bar />`、`<modal />`
### 页面专属组件(仅特定页面使用)
当组件只在某个页面内使用时,放在 `components/{pageName}/` 子目录下:
```
components/
├── home/ # 首页专属组件
│ ├── status.vue
│ └── overview.vue
├── message/ # 消息页专属组件
│ └── list.vue
└── bluetooth/ # 蓝牙页专属组件
└── device.vue
```
标签名:`<home-status />`、`<message-list />`、`<bluetooth-device />`
### 判断依据
| 需求描述 | 放置位置 | 示例 |
|----------|----------|------|
| "做一个通用的返回导航" | `components/backNav.vue` | `<back-nav />` |
| "做一个通用的弹窗组件" | `components/modal.vue` | `<modal />` |
| "首页的项目列表组件" | `components/home/projectList.vue` | `<home-projectList />` |
| "消息页的消息列表" | `components/message/list.vue` | `<message-list />` |
| "蓝牙页的设备卡片" | `components/bluetooth/device.vue` | `<bluetooth-device />` |
## 目录结构
```
src/
├── pages/ # 页面目录
│ ├── home/ # 首页
│ │ └── index.vue
│ ├── report/ # 报告页
│ │ └── index.vue
│ ├── message/ # 消息页
│ │ └── index.vue
│ ├── bluetooth/ # 蓝牙页
│ │ └── index.vue
│ └── work/ # 工作页
│ └── index.vue
│
├── components/ # 组件目录
│ ├── backNav.vue # 公共组件:通用返回导航栏
│ │
│ ├── home/ # 首页专属组件
│ │ ├── homeNav.vue # 首页导航栏
│ │ ├── overview.vue # 今日作业概览
│ │ ├── status.vue # 实时作业状态
│ │ ├── projectList.vue # 项目列表容器
│ │ ├── list.vue # 项目列表项
│ │ ├── progress.vue # 项目作业进度
│ │ ├── construction.vue # 当前施工段
│ │ ├── warning.vue # 异常警告容器
│ │ └── warning_list.vue # 异常警告项
│ │
│ ├── message/ # 消息页专属组件
│ │ └── list.vue # 消息列表项
│ │
│ └── bluetooth/ # 蓝牙页专属组件
│ └── device.vue # 蓝牙设备卡片
│
├── composables/ # 组合式函数
├── store/ # Pinia 状态管理
├── api/ # 接口请求
├── utils/ # 工具函数
├── static/ # 静态资源
└── layouts/ # 布局组件
```
## 命名规范
### 文件命名
- **页面**: `index.vue`(固定)
- **组件**: `camelCase.vue`(如 `projectList.vue`)
- **组合式函数**: `useXxx.ts`(如 `useCount.ts`)
### 组件标签名(easycom 规则)
- **公共组件**: `backNav.vue` → `<back-nav />`
- **页面专属组件**: `home/status.vue` → `<home-status />`
- **嵌套组件**: `home/list.vue` → `<home-list />`
### easycom 自动扫描规则
```json
{
"easycom": {
"autoscan": true,
"custom": {
"^wd-(.*)": "@wot-ui/ui/components/wd-$1/wd-$1.vue",
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
}
}
```
### easycom 自动生成标签名规则
| 文件路径 | 自动生成标签名 |
|----------|----------------|
| `components/backNav.vue` | `<back-nav />` |
| `components/modal.vue` | `<modal />` |
| `components/home/status.vue` | `<home-status />` |
| `components/message/list.vue` | `<message-list />` |
| `components/bluetooth/device.vue` | `<bluetooth-device />` |
## 组件拆分原则
### 何时拆分组件
1. **模板超过 100 行** - 拆分为子组件
2. **重复使用的 UI 块** - 提取为独立组件
3. **逻辑独立的功能块** - 拆分便于维护
### 拆分模式
```
页面容器组件(如 projectList.vue)
└── 列表项组件(如 projectList_list.vue)
页面容器组件(如 warning.vue)
└── 列表项组件(如 warning_list.vue)
```
### 示例:项目列表
```
components/home/
├── projectList.vue # 容器:卡片标题 + card-body
└── projectList_list.vue # 内容:项目信息 + 参数 + 操作按钮
```
使用方式:
```vue
<home-projectList>
<home-projectList_list />
</home-projectList>
```
## 创建新页面步骤
1. **创建页面目录**
```
src/pages/{pageName}/index.vue
```
2. **创建页面专属组件目录**(如需要)
```
src/components/{pageName}/
```
3. **配置路由**(如需要)
```json
// src/pages.json
{
"path": "pages/{pageName}/index",
"type": "page",
"style": {
"navigationBarTitleText": "页面标题"
}
}
```
4. **使用组件**
```vue
<template>
<view class="page">
<!-- 示例:替换为具体组件名,如 <home-component /> -->
<home-component />
</view>
</template>
```
## 页面专属组件 vs 公共组件
| 类型 | 位置 | 标签名 | 示例 |
|------|------|--------|------|
| 公共组件 | `components/` 根目录 | `{name}` | `<back-nav />` |
| 页面专属组件 | `components/{pageName}/` | `{pageName}-{name}` | `<home-status />` |
## 页面样式规范
### 内容区域样式
所有使用自定义导航栏(`<back-nav />`)的页面,`.content` 容器必须使用以下样式:
```css
.content {
padding: 16px;
padding-top: 72px;
}
```
- `padding-top: 72px` 为导航栏预留空间,避免内容被遮挡
- `padding: 16px` 保持左右边距一致
### 卡片样式规范(重要)
每个组件自身就是一个卡片,**页面不要用额外的 `.card` 容器包裹组件**,否则多个组件会合并成一个卡片。
**卡片间距规则**:
- 卡片之间间距统一为 **12px**
- 页面通过 `gap: 12px` 设置间距,**组件内部不要添加 margin**
- 组件只负责自身样式(背景、圆角、内边距),不负责与其他组件的间距
**正确做法** - 页面用 gap 设置间距:
```vue
<!-- 页面 -->
<template>
<view class="page">
<back-nav title="页面标题" />
<view class="content">
<component-a />
<component-b />
</view>
</view>
</template>
<template>
<view class="card">
<!-- 内容 -->
</view>
</template>
<!-- 组件 a.vue -->
<style scoped>
.content {
display: flex;
flex-direction: column;
gap: 12px; /* 卡片间距 */
}
</style>
<style scoped>
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
/* 不要添加 margin */
}
</style>
```
**错误做法** - 组件添加 margin 影响间距:
```css
/* 错误:组件添加 margin */
.card {
margin-bottom: 16px; /* 不要用 margin */
}
```
**组件卡片统一样式:**
```css
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
}
```
**例外情况** - 多个子组件需要合并展示时:
当明确要求将多个组件放在同一个卡片内时,由最外层容器组件统一设置卡片样式,子组件背景透明:
```css
/* 容器组件 */
.container {
background: #fff;
border-radius: 12px;
padding: 16px;
}
/* 子组件 */
.child {
background: transparent;
padding: 0;
}
```
### 页面模板示例
```vue
<template>
<view class="page">
<back-nav title="页面标题" />
<view class="content">
<view class="card">
<!-- 卡片内容 -->
</view>
</view>
</view>
</template>
<style scoped>
.page {
min-height: 100vh;
background-color: #EAEFF9;
}
.content {
padding: 16px;
padding-top: 72px;
}
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
}
</style>
```
### 字体规范
项目使用三级字体体系:
| 级别 | 字号 | 用途 | 示例 |
|------|------|------|------|
| 一级 | 22px | 最大标题 | 页面标题、卡片大标题 |
| 二级 | 18px | 次级正常字体 | 正文、列表项、表单标签 |
| 三级 | 14px | 最小描述字体 | 辅助说明、placeholder、元信息 |
**CSS 变量:**
```css
/* 一级标题 */
--font-size-title: 22px;
/* 二级正文 */
--font-size-body: 18px;
/* 三级描述 */
--font-size-caption: 14px;
```
**使用示例:**
```vue
<template>
<view class="card">
<text class="title">
项目名称
</text>
<text class="body">
项目描述内容
</text>
<text class="caption">
辅助说明文字
</text>
</view>
</template>
<style scoped>
.title {
font-size: 22px;
font-weight: bold;
color: #333;
}
.body {
font-size: 18px;
color: #333;
}
.caption {
font-size: 14px;
color: #999;
}
</style>
```
## 注意事项
1. **不要在页面中直接写大段模板** - 超过 100 行考虑拆分
2. **组件样式使用 scoped** - 避免样式污染
3. **组件 props 要有默认值** - 提高组件易用性
4. **事件命名使用 kebab-case** - 如 `@handle-click`
5. **插槽优先于 props 传内容** - 灵活性更高
6. **禁止使用 git 提交** - 代码的改动必须经过手动提交
## UI 组件库使用规范(重要)
项目使用两套 UI 组件库,按场景分工:
### uni-ui(表单/表格场景)
**仅用于**表单、表格相关的组件:
- 下拉选择:`<uni-data-select>`
- 单选框:`<uni-radio>` / `<uni-radio-group>`
- 多选框:`<uni-checkbox>` / `<uni-checkbox-group>`
- 日期选择:`<uni-datetime-picker>`
- 输入框:`<uni-easyinput>`
- 数据选择器:`<uni-data-picker>`
- 图标:`<uni-icons>`
官网:https://uniapp.dcloud.net.cn/component/uniui/uni-data-select.html
### wot-ui(其他所有场景)
**除表单表格外**,其他所有 UI 组件统一使用 wot-ui:
- 按钮:`<wd-button>`
- 图标:`<wd-icon>`
- 弹窗:`<wd-dialog>`
- 导航栏:`<wd-nav-bar>`
- 标签:`<wd-tag>`
- 步骤条:`<wd-steps>`
- 加载:`<wd-loading>`
- 等等
### 快速判断
| 场景 | 使用库 | 组件示例 |
|------|--------|----------|
| 输入框 | uni-ui | `<uni-easyinput>` |
| 下拉选择 | uni-ui | `<uni-data-select>` |
| 单选/多选 | uni-ui | `<uni-radio>` / `<uni-checkbox>` |
| 日期时间选择 | uni-ui | `<uni-datetime-picker>` |
| 按钮 | wot-ui | `<wd-button>` |
| 图标 | wot-ui | `<wd-icon>` |
| 弹窗/通知 | wot-ui | `<wd-dialog>` / `<wd-toast>` |
| 导航栏 | wot-ui | `<wd-nav-bar>` |
| 标签/徽标 | wot-ui | `<wd-tag>` / `<wd-badge>` |
| 表格展示 | uni-ui | `<uni-table>` |