Files
photography/.cursor/rules/common/code-style.mdc
xujiang 604b9e59ba fix
2025-07-10 18:09:11 +08:00

263 lines
5.8 KiB
Plaintext
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.

---
description: Code style and naming conventions
---
# 代码风格和约定规则
## 📝 通用代码风格
### 文件命名
- **Go文件**: `camelCase.go` (例: `uploadPhotoHandler.go`)
- **TypeScript**: `kebab-case.tsx` 或 `PascalCase.tsx` (组件)
- **API文件**: `kebab-case.api` (例: `photo.api`)
- **配置文件**: `kebab-case.yaml/.json`
### 注释规范
```go
// ✅ Go - 函数注释
// UploadPhoto 上传照片到服务器
// 支持JPEG、PNG、GIF、WebP格式最大10MB
func (l *UploadPhotoLogic) UploadPhoto(req *types.UploadPhotoRequest) (*types.UploadPhotoResponse, error) {
// 实现逻辑
}
```
```typescript
// ✅ TypeScript - 接口注释
/**
* 照片数据接口
* @interface Photo
*/
interface Photo {
/** 照片唯一标识符 */
id: string
/** 照片标题 */
title: string
/** 文件名 */
filename: string
}
```
## 🎯 命名约定
### 变量命名
```go
// ✅ Go - 驼峰命名
var photoID string
var userList []User
var maxFileSize int64 = 10 * 1024 * 1024 // 10MB
// ❌ 避免
var photo_id string
var PhotoId string
```
```typescript
// ✅ TypeScript - 驼峰命名
const photoList: Photo[] = []
const isLoading = false
const handlePhotoUpload = () => {}
// ✅ 常量 - 大写下划线
const MAX_FILE_SIZE = 10 * 1024 * 1024
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL
```
### 函数命名
- **动词开头**: `getPhotoList`, `uploadPhoto`, `deleteCategory`
- **布尔值**: `isVisible`, `hasPermission`, `canEdit`
- **事件处理**: `handleClick`, `onPhotoSelect`, `onUploadSuccess`
## 🛡️ 错误处理
### Go 错误处理
```go
// ✅ 标准错误处理
func (l *UploadPhotoLogic) UploadPhoto(req *types.UploadPhotoRequest) (*types.UploadPhotoResponse, error) {
if !file.IsImageFile(req.File) {
return nil, errorx.NewDefaultError("不支持的文件类型")
}
photoID, err := l.savePhoto(req)
if err != nil {
logx.Errorf("保存照片失败: %v", err)
return nil, errorx.NewDefaultError("照片保存失败")
}
return &types.UploadPhotoResponse{
Id: photoID,
// ...
}, nil
}
```
### TypeScript 错误处理
```typescript
// ✅ 异步操作错误处理
try {
const response = await api.post<UploadResponse>('/photos', formData)
return response.data
} catch (error) {
if (axios.isAxiosError(error)) {
const message = error.response?.data?.msg || '上传失败'
throw new Error(message)
}
throw error
}
```
## 📦 导入组织
### Go 导入顺序
```go
import (
// 标准库
"context"
"fmt"
"net/http"
// 第三方库
"github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/core/logx"
// 本地包
"photography/internal/logic/photo"
"photography/internal/svc"
"photography/internal/types"
)
```
### TypeScript 导入顺序
```typescript
// React 相关
import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/router'
// 第三方库
import axios from 'axios'
import { useQuery } from '@tanstack/react-query'
// UI 组件
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
// 本地模块
import { api } from '@/lib/api'
import { Photo } from '@/types/api'
import { useAuthStore } from '@/stores/authStore'
```
## 🎨 CSS/样式约定
### Tailwind CSS 类名顺序
```tsx
// ✅ 推荐顺序:布局 → 尺寸 → 间距 → 颜色 → 其他
<div className="flex flex-col w-full h-full p-4 bg-white border rounded-lg shadow-md">
<img
className="w-full h-48 object-cover rounded-md"
src={photo.thumbnail}
alt={photo.title}
/>
</div>
```
### 响应式设计
```tsx
// ✅ 移动优先响应式
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{photos.map(photo => (
<PhotoCard key={photo.id} photo={photo} />
))}
</div>
```
## 🔧 类型定义
### TypeScript 接口规范
```typescript
// ✅ 明确的接口定义
interface PhotoCardProps {
photo: Photo
onEdit?: (id: string) => void
onDelete?: (id: string) => void
className?: string
}
// ✅ API 响应类型
interface ApiResponse<T> {
code: number
msg: string
data: T
}
type PhotoListResponse = ApiResponse<{
photos: Photo[]
total: number
page: number
limit: number
}>
```
### Go 结构体规范
```go
// ✅ 结构体标签完整
type Photo struct {
ID string `json:"id" db:"id"`
Title string `json:"title" db:"title"`
Description string `json:"description" db:"description"`
Filename string `json:"filename" db:"filename"`
Thumbnail string `json:"thumbnail" db:"thumbnail"`
CategoryID string `json:"category_id" db:"category_id"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
```
## 📊 性能约定
### 避免性能陷阱
```typescript
// ✅ 使用 useMemo 避免重复计算
const expensiveValue = useMemo(() => {
return photos.filter(photo => photo.category_id === selectedCategory)
}, [photos, selectedCategory])
// ✅ 使用 useCallback 避免重复渲染
const handlePhotoSelect = useCallback((id: string) => {
setSelectedPhoto(photos.find(p => p.id === id))
}, [photos])
```
## 🔒 安全约定
### 输入验证
```go
// ✅ 后端输入验证
if req.Title == "" {
return nil, errorx.NewDefaultError("照片标题不能为空")
}
if len(req.Title) > 100 {
return nil, errorx.NewDefaultError("照片标题不能超过100个字符")
}
```
```typescript
// ✅ 前端输入验证
const validatePhoto = (data: PhotoFormData): string[] => {
const errors: string[] = []
if (!data.title.trim()) {
errors.push('标题不能为空')
}
if (data.title.length > 100) {
errors.push('标题不能超过100个字符')
}
return errors
}
```
遵循这些约定可以保持代码的一致性和可维护性。