# 开发指南 ## 开发环境搭建 ### 1. 环境准备 ```bash # 安装 Node.js (版本 16.0+) # 下载地址: https://nodejs.org/ # 安装 pnpm npm install -g pnpm # 验证安装 node --version pnpm --version ``` ### 2. 项目初始化 ```bash # 克隆项目 git clone cd shop-front-end # 安装依赖 pnpm install # 启动开发服务器 pnpm dev ``` ### 3. 开发工具配置 推荐使用 VSCode 并安装以下插件: - Vue Language Features (Volar) - TypeScript Vue Plugin (Volar) - ESLint - Prettier - Stylelint ## 代码规范 ### 1. 命名规范 #### 文件命名 - 组件文件: `PascalCase.vue` - 工具文件: `camelCase.ts` - 配置文件: `kebab-case.ts` - 样式文件: `kebab-case.scss` #### 变量命名 ```typescript // 正确 const userName = '张三' const MAX_COUNT = 100 const userList = [] // 避免 const username = '张三' // 驼峰 const max_count = 100 // 下划线 ``` #### 组件命名 ```vue ``` ### 2. 代码结构 #### Vue 组件结构 ```vue ``` ### 3. TypeScript 规范 #### 类型定义 ```typescript // 接口定义 interface Goods { id: number name: string price: number stock: number } // 类型别名 type GoodsStatus = 'available' | 'sold_out' | 'disabled' // 枚举 enum OrderStatus { PENDING = 1, PROCESSING = 2, COMPLETED = 3 } ``` #### 函数定义 ```typescript // 带类型的函数 const formatPrice = (price: number): string => { return `¥${price.toFixed(2)}` } // 异步函数 const fetchGoodsList = async (params: SearchParams): Promise => { const { data } = await getGoodsList(params) return data } ``` ## API 开发规范 ### 1. API 文件结构 ```typescript // src/api/shop/goods.ts import request from '@/utils/request' export interface Goods { id: number name: string price: number stock: number } export interface GoodsParams { page?: number size?: number keyword?: string } export interface GoodsListResponse { list: Goods[] total: number } // 获取商品列表 export const getGoodsList = (params: GoodsParams) => { return request.get('/api/goods/list', { params }) } // 创建商品 export const createGoods = (data: Partial) => { return request.post('/api/goods', data) } // 更新商品 export const updateGoods = (id: number, data: Partial) => { return request.put(`/api/goods/${id}`, data) } // 删除商品 export const deleteGoods = (id: number) => { return request.delete(`/api/goods/${id}`) } ``` ### 2. 请求封装 ```typescript // src/utils/request.ts import axios from 'axios' import { ElMessage } from 'element-plus' const request = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000 }) // 请求拦截器 request.interceptors.request.use( config => { // 添加 token const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, error => { return Promise.reject(error) } ) // 响应拦截器 request.interceptors.response.use( response => { return response.data }, error => { // 统一错误处理 ElMessage.error(error.response?.data?.message || '请求失败') return Promise.reject(error) } ) export default request ``` ## 组件开发规范 ### 1. 组件设计原则 #### 单一职责 每个组件只负责一个特定的功能。 #### 可复用性 组件应该设计为可复用的,通过 props 接收配置。 #### 组合优于继承 通过组合多个小组件来构建复杂功能。 ### 2. Props 定义 ```vue ``` ### 3. Emits 定义 ```vue ``` ## 状态管理规范 ### 1. Store 定义 ```typescript // src/store/modules/user.ts import { defineStore } from 'pinia' export interface UserState { userInfo: User | null token: string | null } export const useUserStore = defineStore('user', { state: (): UserState => ({ userInfo: null, token: null }), getters: { isLogin: state => !!state.token, userName: state => state.userInfo?.name || '' }, actions: { setUserInfo(userInfo: User) { this.userInfo = userInfo }, setToken(token: string) { this.token = token }, async login(credentials: LoginParams) { const { data } = await loginApi(credentials) this.setToken(data.token) this.setUserInfo(data.user) }, logout() { this.userInfo = null this.token = null } }, persist: { enabled: true, strategies: [ { key: 'user', storage: localStorage } ] } }) ``` ### 2. Store 使用 ```vue ``` ## 路由开发规范 ### 1. 路由定义 ```typescript // src/router/modules/shop.ts export default { path: '/shop', name: 'Shop', redirect: '/shop/goods', meta: { title: '店铺管理', icon: 'shop', rank: 10 }, children: [ { path: '/shop/goods', name: 'Goods', component: () => import('@/views/shop/goods/index.vue'), meta: { title: '商品管理', roles: ['admin', 'shop_manager'] } }, { path: '/shop/orders', name: 'Orders', component: () => import('@/views/shop/orders/index.vue'), meta: { title: '订单管理', roles: ['admin', 'shop_manager'] } } ] } as RouteConfigsTable ``` ### 2. 路由守卫 ```typescript // 在路由守卫中检查权限 router.beforeEach((to, from, next) => { const userStore = useUserStore() // 检查登录状态 if (!userStore.isLogin && to.path !== '/login') { next('/login') return } // 检查页面权限 if (to.meta.roles && !hasPermission(to.meta.roles)) { next('/error/403') return } next() }) ``` ## 样式开发规范 ### 1. SCSS 规范 ```scss // 变量定义 $primary-color: #409eff; $success-color: #67c23a; $warning-color: #e6a23c; $danger-color: #f56c6c; // 混入 @mixin flex-center { display: flex; align-items: center; justify-content: center; } // 组件样式 .goods-card { border: 1px solid #ebeef5; border-radius: 4px; padding: 20px; &__header { @include flex-center; margin-bottom: 16px; } &__title { font-size: 16px; font-weight: bold; color: $primary-color; } } ``` ### 2. CSS 类命名 使用 BEM 命名规范: ```scss .block {} .block__element {} .block--modifier {} ``` ## 测试规范 ### 1. 单元测试 ```typescript // tests/unit/utils/format.spec.ts import { formatPrice } from '@/utils/format' describe('formatPrice', () => { it('should format price correctly', () => { expect(formatPrice(100)).toBe('¥100.00') expect(formatPrice(99.9)).toBe('¥99.90') }) }) ``` ### 2. 组件测试 ```typescript // tests/unit/components/GoodsCard.spec.ts import { mount } from '@vue/test-utils' import GoodsCard from '@/components/GoodsCard.vue' describe('GoodsCard', () => { it('should render goods info', () => { const wrapper = mount(GoodsCard, { props: { goods: { id: 1, name: '测试商品', price: 100 } } }) expect(wrapper.text()).toContain('测试商品') expect(wrapper.text()).toContain('¥100.00') }) }) ``` ## 提交规范 ### 1. Commit Message 格式 ``` ():