19 KiB
19 KiB
健身房管理系统前端开发规范文档
文档编号: GYM-FE-DEV-001
版本: v1.0
日期: 2026-03-04
作者: 张翔
状态: 初稿
文档修订历史
| 版本 | 日期 | 作者 | 修订内容 |
|---|---|---|---|
| v1.0 | 2026-03-04 | 张翔 | 创建前端开发规范 |
参考文档
- 《健身房管理系统前端技术架构详细设计》 GYM-FE-ARCH-001
- Vue 3 风格指南
- TypeScript 编码规范
- Airbnb JavaScript Style Guide
一、编码规范
1.1 代码风格
1.1.1 使用ESLint
// .eslintrc.json
{
"extends": [
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
1.1.2 使用Prettier
// .prettierrc
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "es5",
"arrowParens": "avoid",
"endOfLine": "lf"
}
1.2 命名规范
1.2.1 文件命名
| 类型 | 命名规范 | 示例 |
|---|---|---|
| 组件文件 | PascalCase | MemberList.vue, CourseCard.vue |
| 工具文件 | camelCase | formatDate.ts, validator.ts |
| 类型文件 | camelCase | api.ts, models.ts |
| 常量文件 | UPPER_SNAKE_CASE | API_BASE_URL.ts |
| 样式文件 | kebab-case | member-list.scss, button.css |
1.2.2 变量命名
// 布尔值:使用is/has/can前缀
const isActive = true
const hasPermission = false
const canEdit = true
// 常量:使用UPPER_SNAKE_CASE
const API_BASE_URL = 'https://api.example.com'
const MAX_RETRY_COUNT = 3
// 函数:使用camelCase,动词开头
function getMemberList() {}
function validatePhoneNumber() {}
function handleSearch() {}
// 类:使用PascalCase
class UserService {}
class MemberValidator {}
// 接口:使用PascalCase,I前缀可选
interface Member {}
interface IMember {}
// 类型别名:使用PascalCase
type MemberStatus = 'active' | 'inactive'
// 枚举:使用PascalCase
enum MemberLevel {
BRONZE = 1,
SILVER = 2,
GOLD = 3
}
1.2.3 组件命名
<!-- 组件名称使用PascalCase -->
<template>
<MemberList />
<CourseCard />
</template>
<script setup lang="ts">
// 组件文件名与组件名一致
const componentName = 'MemberList'
</script>
1.3 代码格式
1.3.1 缩进与空格
// 使用2个空格缩进
function example() {
if (condition) {
doSomething()
}
}
// 对象和数组使用空格
const obj = { a: 1, b: 2 }
const arr = [1, 2, 3]
// 运算符前后使用空格
const sum = a + b
const result = a > b ? a : b
1.3.2 引号使用
// 优先使用单引号
const name = 'John'
const message = 'Hello, world!'
// 字符串中包含单引号时使用双引号
const quote = "It's a beautiful day"
// 模板字符串使用反引号
const greeting = `Hello, ${name}!`
1.3.3 分号使用
// 不使用分号
const a = 1
const b = 2
function example() {
return a + b
}
二、Vue组件规范
2.1 组件结构
<template>
<!-- 模板内容 -->
</template>
<script setup lang="ts">
// 导入
import { ref, computed, onMounted } from 'vue'
import { useAuthStore } from '@/stores/auth'
// Props定义
interface Props {
title: string
count?: number
}
const props = withDefaults(defineProps<Props>(), {
count: 0
})
// Emits定义
const emit = defineEmits<{
click: [event: MouseEvent]
change: [value: string]
}>()
// 响应式数据
const count = ref(0)
const message = ref('Hello')
// 计算属性
const doubled = computed(() => count.value * 2)
// 方法
const handleClick = (event: MouseEvent) => {
emit('click', event)
}
// 生命周期
onMounted(() => {
console.log('Component mounted')
})
</script>
<style scoped lang="scss">
/* 样式内容 */
</style>
2.2 Props定义
// 使用TypeScript接口定义Props
interface Props {
title: string
count?: number
items: string[]
config: {
enabled: boolean
timeout: number
}
}
// 使用withDefaults设置默认值
const props = withDefaults(defineProps<Props>(), {
count: 0,
items: () => [],
config: () => ({ enabled: true, timeout: 5000 })
})
2.3 Emits定义
// 使用TypeScript定义Emits
const emit = defineEmits<{
click: [event: MouseEvent]
change: [value: string]
submit: [data: FormData]
cancel: []
}>()
// 触发事件
emit('click', event)
emit('change', newValue)
emit('submit', formData)
emit('cancel')
2.4 响应式数据
// 使用ref定义基本类型
const count = ref(0)
const message = ref('Hello')
// 使用reactive定义对象
const user = reactive({
name: 'John',
age: 30
})
// 使用computed定义计算属性
const fullName = computed(() => `${user.name} is ${user.age} years old`)
// 使用readonly定义只读数据
const readonlyData = readonly({ id: 1, name: 'John' })
// 使用shallowRef和shallowReactive优化性能
const largeList = shallowRef<any[]>([])
const largeObject = shallowReactive({})
2.5 组件通信
2.5.1 Props传递
<!-- 父组件 -->
<template>
<child-component
:title="pageTitle"
:count="itemCount"
@update="handleUpdate"
/>
</template>
<script setup lang="ts">
import ChildComponent from './ChildComponent.vue'
const pageTitle = ref('Dashboard')
const itemCount = ref(10)
const handleUpdate = (value: any) => {
console.log('Update:', value)
}
</script>
2.5.2 事件传递
<!-- 子组件 -->
<template>
<button @click="handleClick">Click me</button>
</template>
<script setup lang="ts">
const emit = defineEmits<{
click: [event: MouseEvent]
}>()
const handleClick = (event: MouseEvent) => {
emit('click', event)
}
</script>
2.5.3 Provide/Inject
// 父组件
import { provide } from 'vue'
const theme = ref('light')
provide('theme', theme)
// 子组件
import { inject } from 'vue'
const theme = inject<Ref<string>>('theme')
三、TypeScript规范
3.1 类型定义
3.1.1 基础类型
// 使用明确的类型
const count: number = 10
const name: string = 'John'
const isActive: boolean = true
const items: string[] = ['a', 'b', 'c']
const user: { name: string; age: number } = { name: 'John', age: 30 }
3.1.2 接口定义
// 定义接口
interface Member {
id: number
name: string
phone: string
level: MemberLevel
status: MemberStatus
}
// 可选属性
interface User {
id: number
name: string
email?: string
}
// 只读属性
interface Config {
readonly id: number
name: string
}
// 索引签名
interface StringDictionary {
[key: string]: string
}
3.1.3 类型别名
// 定义类型别名
type MemberStatus = 'active' | 'inactive' | 'frozen'
type MemberLevel = 1 | 2 | 3 | 4 | 5
// 联合类型
type ID = number | string
// 交叉类型
type Name = { firstName: string; lastName: string }
type Age = { age: number }
type Person = Name & Age
3.1.4 泛型
// 泛型函数
function identity<T>(arg: T): T {
return arg
}
// 泛型接口
interface Response<T> {
code: number
data: T
message: string
}
// 泛型类
class Storage<T> {
private items: T[] = []
add(item: T): void {
this.items.push(item)
}
get(index: number): T | undefined {
return this.items[index]
}
}
3.2 类型断言
// 使用as关键字进行类型断言
const element = document.getElementById('app') as HTMLElement
// 使用尖括号语法(JSX中不可用)
const element2 = <HTMLElement>document.getElementById('app')
// 非空断言
const value = input.value!
3.3 类型守卫
// typeof类型守卫
function processValue(value: string | number) {
if (typeof value === 'string') {
console.log(value.toUpperCase())
} else {
console.log(value.toFixed(2))
}
}
// instanceof类型守卫
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark()
} else {
animal.meow()
}
}
// 自定义类型守卫
interface Member {
id: number
name: string
type: 'individual' | 'corporate'
}
function isCorporateMember(member: Member): member is Member & { type: 'corporate' } {
return member.type === 'corporate'
}
四、注释规范
4.1 文件注释
/**
* 会员服务
*
* 提供会员相关的业务逻辑处理
*
* @example
* const memberService = new MemberService()
* const members = await memberService.getList()
*/
export class MemberService {
// ...
}
4.2 函数注释
/**
* 获取会员列表
*
* @param params - 查询参数
* @param params.page - 页码
* @param params.pageSize - 每页数量
* @param params.keyword - 搜索关键词
* @returns 会员列表数据
* @throws {Error} 当API请求失败时抛出错误
*
* @example
* const result = await getMemberList({ page: 1, pageSize: 10 })
*/
export async function getMemberList(params: {
page: number
pageSize: number
keyword?: string
}): Promise<MemberListResponse> {
// ...
}
4.3 类注释
/**
* 会员验证器
*
* 提供会员数据验证功能
*/
export class MemberValidator {
/**
* 验证手机号
*
* @param phone - 手机号
* @returns 验证结果
*/
validatePhone(phone: string): ValidationResult {
// ...
}
}
4.4 行内注释
// 计算会员等级
const level = calculateLevel(exp)
// TODO: 需要优化这个算法的性能
const result = complexCalculation(data)
// FIXME: 这里有个bug,需要修复
const value = buggyFunction()
// HACK: 临时解决方案,后续需要重构
const temp = workaround(data)
五、文件组织规范
5.1 目录结构
src/
├── api/ # API接口
│ ├── modules/ # API模块
│ │ ├── auth.ts
│ │ ├── member.ts
│ │ └── booking.ts
│ └── request.ts # Axios封装
├── assets/ # 静态资源
│ ├── images/ # 图片
│ ├── icons/ # 图标
│ └── styles/ # 样式
├── components/ # 组件
│ ├── base/ # 基础组件
│ ├── business/ # 业务组件
│ └── layout/ # 布局组件
├── composables/ # Composables
├── config/ # 配置
├── directives/ # 自定义指令
├── hooks/ # Hooks
├── layouts/ # 布局
├── router/ # 路由
├── stores/ # 状态管理
├── types/ # 类型定义
├── utils/ # 工具函数
├── views/ # 页面
├── App.vue
└── main.ts
5.2 文件导入顺序
// 1. Vue相关导入
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
// 2. 第三方库导入
import axios from 'axios'
import dayjs from 'dayjs'
// 3. 内部模块导入
import { useAuthStore } from '@/stores/auth'
import { formatDate } from '@/utils/formatter'
// 4. 类型导入
import type { Member, MemberListParams } from '@/types/models'
// 5. 样式导入
import './styles/index.scss'
5.3 导出规范
// 命名导出
export function formatDate(date: Date): string {}
export function formatTime(time: Date): string {}
// 默认导出(仅用于组件)
export default defineComponent({
// ...
})
// 类型导出
export type { Member, MemberStatus }
export interface { MemberListParams }
六、Git提交规范
6.1 提交信息格式
<type>(<scope>): <subject>
<body>
<footer>
6.2 Type类型
| Type | 描述 | 示例 |
|---|---|---|
| feat | 新功能 | feat(member): add member list page |
| fix | 修复bug | fix(booking): resolve booking conflict |
| docs | 文档更新 | docs(readme): update installation guide |
| style | 代码格式调整 | style(member): format member component |
| refactor | 重构 | refactor(auth): simplify login logic |
| perf | 性能优化 | perf(list): optimize virtual scroll |
| test | 测试相关 | test(member): add member validator tests |
| chore | 构建过程或辅助工具变动 | chore(deps): update dependencies |
| ci | CI配置文件更新 | ci(github): add workflow config |
6.3 Scope范围
| Scope | 描述 |
|---|---|
| auth | 认证相关 |
| member | 会员相关 |
| booking | 预约相关 |
| checkin | 签到相关 |
| course | 课程相关 |
| finance | 财务相关 |
| data | 数据相关 |
| system | 系统相关 |
| ui | UI组件 |
| utils | 工具函数 |
6.4 提交示例
# 新功能
git commit -m "feat(member): add member search functionality"
# 修复bug
git commit -m "fix(booking): resolve booking time conflict issue"
# 文档更新
git commit -m "docs(readme): update project setup instructions"
# 性能优化
git commit -m "perf(list): optimize virtual scroll performance"
# 重构
git commit -m "refactor(auth): simplify authentication flow"
七、代码审查规范
7.1 审查清单
7.1.1 功能性
- 代码实现了需求文档中的功能
- 代码逻辑正确,没有明显的bug
- 边界情况得到处理
- 错误处理完善
7.1.2 代码质量
- 代码符合项目编码规范
- 代码结构清晰,易于理解
- 代码有适当的注释
- 变量和函数命名准确
7.1.3 性能
- 没有明显的性能问题
- 使用了适当的优化技术
- 没有不必要的重复计算
- 大数据量处理使用了虚拟滚动
7.1.4 安全性
- 输入验证完善
- 敏感数据加密存储
- 没有XSS、CSRF等安全漏洞
- 权限控制正确
7.1.5 测试
- 单元测试覆盖率达标
- 测试用例充分
- 测试通过
- 没有测试警告
7.2 审查流程
-
提交Pull Request
- 确保代码通过所有检查
- 编写清晰的PR描述
- 关联相关的Issue
-
代码审查
- 至少一名审查者批准
- 解决所有审查意见
- 确保没有冲突
-
合并代码
- 确保CI/CD通过
- 删除功能分支
- 更新相关文档
八、最佳实践
8.1 组件设计
8.1.1 单一职责
<!-- Bad: 组件职责过多 -->
<template>
<div>
<input v-model="form.name" />
<input v-model="form.phone" />
<button @click="submit">提交</button>
<div v-if="showChart">
<chart :data="chartData" />
</div>
</div>
</template>
<!-- Good: 组件职责单一 -->
<template>
<member-form :model="form" @submit="handleSubmit" />
<data-chart v-if="showChart" :data="chartData" />
</template>
8.1.2 Props验证
// 使用TypeScript接口定义Props
interface Props {
title: string
count?: number
items: string[]
}
const props = withDefaults(defineProps<Props>(), {
count: 0,
items: () => []
})
8.2 状态管理
8.2.1 合理使用状态
// 全局状态:用户信息、权限等
const authStore = useAuthStore()
// 模块状态:当前页面数据
const pageData = ref({})
// 组件状态:弹窗显示、加载状态
const showModal = ref(false)
const loading = ref(false)
8.2.2 避免状态冗余
// Bad: 冗余状态
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
// Good: 单一数据源
const user = reactive({
firstName: 'John',
lastName: 'Doe'
})
const fullName = computed(() => `${user.firstName} ${user.lastName}`)
8.3 错误处理
8.3.1 统一错误处理
// utils/errorHandler.ts
export function handleError(error: unknown): void {
if (error instanceof Error) {
console.error('Error:', error.message)
// 显示错误提示
showErrorToast(error.message)
} else {
console.error('Unknown error:', error)
showErrorToast('发生未知错误')
}
}
// 使用
try {
await api.getMemberList()
} catch (error) {
handleError(error)
}
8.3.2 错误边界
<template>
<error-boundary @error="handleError">
<router-view />
</error-boundary>
</template>
<script setup lang="ts">
const handleError = (error: Error) => {
console.error('Error caught by boundary:', error)
}
</script>
8.4 性能优化
8.4.1 避免不必要的响应式
// Bad: 所有数据都是响应式
const config = reactive({
apiBaseUrl: 'https://api.example.com',
timeout: 5000,
maxRetries: 3
})
// Good: 常量不需要响应式
const API_BASE_URL = 'https://api.example.com'
const TIMEOUT = 5000
const MAX_RETRIES = 3
8.4.2 使用计算属性缓存
// Good: 使用computed缓存结果
const filteredMembers = computed(() => {
return memberList.value.filter(member =>
member.name.includes(searchKeyword.value)
)
})
九、开发流程
9.1 分支管理
main (主分支)
├── develop (开发分支)
│ ├── feature/member-list (功能分支)
│ ├── feature/booking-system (功能分支)
│ └── fix/booking-bug (修复分支)
└── release/v1.0.0 (发布分支)
9.2 开发流程
-
创建功能分支
git checkout develop git pull origin develop git checkout -b feature/member-list -
开发功能
- 按照编码规范编写代码
- 编写单元测试
- 本地测试通过
-
提交代码
git add . git commit -m "feat(member): add member list page" git push origin feature/member-list -
创建Pull Request
- 编写清晰的PR描述
- 关联相关的Issue
- 请求代码审查
-
代码审查
- 至少一名审查者批准
- 解决所有审查意见
-
合并代码
- 合并到develop分支
- 删除功能分支
9.3 发布流程
-
创建发布分支
git checkout develop git pull origin develop git checkout -b release/v1.0.0 -
发布准备
- 更新版本号
- 更新CHANGELOG
- 运行完整测试
-
合并到main
git checkout main git merge release/v1.0.0 git tag v1.0.0 git push origin main --tags -
合并回develop
git checkout develop git merge release/v1.0.0 git push origin develop
十、总结
本文档详细描述了健身房管理系统前端的开发规范,包括:
- 编码规范:代码风格、命名规范、代码格式
- Vue组件规范:组件结构、Props定义、Emits定义、响应式数据、组件通信
- TypeScript规范:类型定义、类型断言、类型守卫
- 注释规范:文件注释、函数注释、类注释、行内注释
- 文件组织规范:目录结构、文件导入顺序、导出规范
- Git提交规范:提交信息格式、Type类型、Scope范围、提交示例
- 代码审查规范:审查清单、审查流程
- 最佳实践:组件设计、状态管理、错误处理、性能优化
- 开发流程:分支管理、开发流程、发布流程
通过遵循本文档的开发规范,可以确保代码质量、提高开发效率、降低维护成本。