200 lines
5.8 KiB
Markdown
200 lines
5.8 KiB
Markdown
# 03 — 前端规则
|
||
|
||
> **适用**:所有前端 AI 开发任务(Web / H5 / 小程序)。
|
||
|
||
---
|
||
|
||
## 样式铁律
|
||
|
||
**禁止在组件文件中硬编码**:颜色值(`#xxx` / `rgb()`)、字号(`px` / `rpx` / `rem`)、间距(`margin` / `padding` 数值)、圆角(`border-radius` 数值)。
|
||
|
||
所有样式必须来自:
|
||
1. **Design Token 文件** → 变量(`$color-primary`)
|
||
2. **全局 CSS 类** → 语义类(`.text-h1` `.card` `.gap-2`)
|
||
3. **UI 框架内置类** → Tailwind / Ant Design 等
|
||
|
||
```vue
|
||
<!-- ❌ 禁止 -->
|
||
<style scoped>
|
||
.title { color: #333; font-size: 32rpx; margin: 20rpx; }
|
||
|
||
<!-- ✅ 正确 -->
|
||
<style scoped>
|
||
.title { color: $color-gray-800; @extend .text-h2; margin: $space-3; }
|
||
```
|
||
|
||
---
|
||
|
||
## 命名规则
|
||
|
||
| 元素 | 规则 | 示例(正确 → 错误) |
|
||
|------|------|---------------------|
|
||
| **组件文件** | 短横线分隔(kebab-case) | `task-card.vue` → ❌ `TaskCard.vue` |
|
||
| **页面文件** | 小写或短横线 | `task-detail.vue` `index.vue` |
|
||
| **组件 name** | 大驼峰(PascalCase) | `TaskCard` `UserAvatar` |
|
||
| **CSS 类名** | 短横线分隔 | `.task-card` `.btn-primary` → ❌ `.taskCard` |
|
||
| **JS 变量** | 小驼峰 | `taskList` `userName` → ❌ `task_list` |
|
||
| **JS 常量** | 全大写,下划线分隔 | `MAX_PAGE_SIZE` `API_BASE_URL` |
|
||
| **JS 函数** | 小驼峰,动词开头 | `fetchTasks()` `handleSubmit()` |
|
||
| **API 方法** | 小驼峰,动词+名词 | `taskApi.list()` `taskApi.create()` |
|
||
| **路由路径** | 小写,短横线 | `/task-detail` → ❌ `/taskDetail` |
|
||
| **文件目录** | 小写或短横线 | `task-hall/` `user-center/` |
|
||
| **静态资源** | 短横线分隔 | `icon-phone.svg` `bg-home.jpg` |
|
||
|
||
---
|
||
|
||
## 注释规则
|
||
|
||
| 位置 | 要求 | 示例 |
|
||
|------|------|------|
|
||
| **组件** | 顶部注释说明用途和 Props | `<!-- 任务卡片组件,用于列表展示 -->` |
|
||
| **复杂逻辑** | 行内注释说明"为什么" | `// 先查本地缓存,未命中再请求接口` |
|
||
| **计算属性** | 注释说明计算依据 | `// 根据任务状态和截止时间计算紧急程度` |
|
||
| **API 方法** | JSDoc 说明入参/返回 | `@param {Object} params @returns {Promise<{list,total}>}` |
|
||
| **TODO/FIXME** | 负责人+日期 | `// TODO(yaoshuli 2026-06) 待产品确认逻辑` |
|
||
| **禁止** | ❌ 注释写"做了什么" | `<!-- 循环渲染列表 -->` ← 删掉 |
|
||
| **禁止** | ❌ 注释掉的旧代码/旧模板 | 直接删,Git 有历史 |
|
||
| **禁止** | ❌ 无意义分隔注释 | `// ========== 数据获取 ==========` |
|
||
|
||
```vue
|
||
<!--
|
||
任务详情页面
|
||
- 展示任务基本信息、报名列表、结算记录
|
||
- 支持接单、提交、结算等操作
|
||
-->
|
||
<template>
|
||
<app-layout>
|
||
<!-- 任务信息卡片 -->
|
||
<m-card>
|
||
...
|
||
</m-card>
|
||
|
||
<!-- 仅管理员可见 -->
|
||
<m-card v-if="isAdmin">
|
||
...
|
||
</m-card>
|
||
</app-layout>
|
||
</template>
|
||
|
||
<script setup>
|
||
/**
|
||
* 提交任务成果。
|
||
* 提交成功后自动刷新列表并发送通知。
|
||
*
|
||
* @param {string} taskId - 任务ID
|
||
* @param {Object} payload - 提交内容 { files, remark }
|
||
* @returns {Promise<void>}
|
||
*/
|
||
const handleSubmit = async (taskId, payload) => {
|
||
// 先本地校验,避免无效请求
|
||
if (!payload.files.length) return;
|
||
|
||
await taskApi.submit(taskId, payload);
|
||
// TODO(yaoshuli 2026-06) 成功后应跳转到提交记录页
|
||
router.push('/task-list');
|
||
};
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## 组件使用铁律
|
||
|
||
| 场景 | ✅ 必须用 | ❌ 禁止 |
|
||
|------|----------|---------|
|
||
| 页面外壳 | 项目统一布局组件 | 自己写页头/侧栏/底栏/TabBar |
|
||
| 图标 | 项目统一图标组件 | 裸 `<img>` / emoji / Unicode |
|
||
| 按钮 | 项目统一按钮组件 | 自己写 button 样式 |
|
||
| 卡片 | 项目统一卡片组件 | 裸露 div+手写圆角阴影 |
|
||
|
||
---
|
||
|
||
## API 调用铁律
|
||
|
||
**所有 HTTP 请求走统一封装**,禁止组件内直调原生 API。
|
||
|
||
```javascript
|
||
// ✅ 正确:走项目统一封装
|
||
import { taskApi } from '@/services/task';
|
||
const res = await taskApi.list({ page: 1, size: 20 });
|
||
|
||
// ❌ 禁止
|
||
fetch('/api/task/list').then(...)
|
||
axios.get('/api/task/list')
|
||
uni.request({ url: '/api/task/list' })
|
||
```
|
||
|
||
---
|
||
|
||
## 新增页面模板(填空式)
|
||
|
||
```vue
|
||
<template>
|
||
<app-layout>
|
||
<!-- [填空] 页面内容 -->
|
||
<view v-if="loading">加载中...</view>
|
||
<view v-else-if="list.length === 0" class="empty-state">
|
||
<text>暂无数据</text>
|
||
</view>
|
||
<view v-else>
|
||
<!-- [填空] 数据展示 -->
|
||
</view>
|
||
</app-layout>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue';
|
||
// [填空] import API 方法
|
||
|
||
const list = ref([]);
|
||
const loading = ref(false);
|
||
|
||
const fetchData = async () => {
|
||
loading.value = true;
|
||
try {
|
||
const res = await [API方法]({ page: 1, size: 20 });
|
||
list.value = res.list;
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
|
||
onMounted(() => fetchData());
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// ⚠️ 不得超过 100 行,超过说明在造轮子
|
||
</style>
|
||
```
|
||
|
||
---
|
||
|
||
## 禁止清单
|
||
|
||
| 类别 | ❌ 禁止 |
|
||
|------|--------|
|
||
| **样式** | 硬编码颜色/字号/间距/圆角 |
|
||
| **样式** | 在 scoped 中定义全局重置 |
|
||
| **样式** | scoped 超过 100 行 |
|
||
| **组件** | 自己写布局外壳(页头/侧栏/TabBar) |
|
||
| **组件** | 裸用 `<img>` 代替图标组件 |
|
||
| **网络** | 直调 `fetch` / `axios` / `uni.request` |
|
||
| **网络** | 不处理错误态 |
|
||
| **状态** | 无加载态/空态 |
|
||
|
||
---
|
||
|
||
## 检查表
|
||
|
||
每完成一个前端任务,逐项自检:
|
||
|
||
- [ ] 使用项目统一布局组件
|
||
- [ ] 无硬编码颜色/字号/间距/圆角
|
||
- [ ] 图标全部走统一图标组件
|
||
- [ ] API 调用走统一封装,无裸调
|
||
- [ ] 页面/组件有加载态 + 空态 + 错误态
|
||
- [ ] 关键操作有 loading 态(防重复点击)
|
||
- [ ] `<style scoped>` 不超过 100 行
|
||
- [ ] PC/移动端均正常(如项目需响应式)
|
||
- [ ] 无禁止清单中的违规项
|