DEVELOPER_GUIDE.md 11 KB

开发者指南

📖 目录

🛠️ 开发环境搭建

1. 安装必要工具

# 安装 Node.js (推荐使用 nvm)
nvm install 16
nvm use 16

# 安装 pnpm (可选,替代 npm)
npm install -g pnpm

# 安装依赖
npm install
# 或
pnpm install

2. 配置开发环境

# 复制环境变量文件
cp .env.development.example .env.development

# 编辑 .env.development
# 配置后端 API 地址
VITE_API_URL=http://localhost:8000

3. 启动开发服务器

npm run dev

📁 项目结构说明

核心目录

/src/api/ - API 接口

// 示例:src/api/login/index.ts
import request from '/@/utils/service'

export function login(data: any) {
  return request({
    url: '/api/system/auth/login/',
    method: 'post',
    data
  })
}

/src/views/ - 页面视图

views/
├── position/        # 职位管理页面
│   ├── list/       # 职位列表
│   ├── detail/     # 职位详情
│   └── crud.tsx    # CRUD 配置
├── questionBank/   # 题库管理
├── talent/         # 人才管理
└── system/         # 系统管理

/src/components/ - 公共组件

  • auth/ - 权限控制组件
  • editor/ - 富文本编辑器
  • fileSelector/ - 文件选择器
  • table/ - 表格组件

/src/utils/ - 工具函数

  • request.ts - 请求封装
  • message.ts - 消息提示
  • storage.ts - 本地存储
  • formatTime.ts - 时间格式化

/src/stores/ - 状态管理

// 示例:src/stores/userInfo.ts
import { defineStore } from 'pinia'

export const useUserInfo = defineStore('userInfo', {
  state: () => ({
    userName: '',
    avatar: ''
  }),
  persist: {
    enabled: true
  }
})

📝 代码规范

1. TypeScript 规范

// ✅ 正确:明确的类型定义
interface UserInfo {
  id: number
  name: string
  email: string
}

function getUserInfo(id: number): Promise<UserInfo> {
  return request({
    url: `/api/user/${id}/`,
    method: 'get'
  })
}

// ❌ 错误:使用 any
function getUserInfo(id: any): any {
  // ...
}

2. Vue 3 规范

<template>
  <div class="container">
    <el-table :data="tableData">
      <el-table-column prop="name" label="名称" />
    </el-table>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

interface TableItem {
  name: string
}

const tableData = ref<TableItem[]>([])

const getData = async () => {
  // 获取数据逻辑
}
</script>

<style scoped lang="scss">
.container {
  padding: 20px;
}
</style>

3. 命名规范

  • 组件名:PascalCase - UserManagement.vue
  • 文件名:kebab-case - user-info.vue
  • 变量/函数:camelCase - getUserInfo
  • 常量:UPPER_SNAKE_CASE - API_BASE_URL
  • 类型/接口:PascalCase - UserInfo

4. 文件组织

component/
  ├── index.vue        # 主组件
  ├── components/      # 子组件
  │   ├── Form.vue
  │   └── List.vue
  ├── api.ts           # API 接口
  ├── types.ts         # 类型定义
  └── crud.tsx         # CRUD 配置(如需要)

🔄 开发流程

1. 创建新功能模块

步骤一:创建目录结构

src/views/newFeature/
  ├── index.vue    # 主页面
  ├── api.ts       # API 接口
  ├── types.ts     # 类型定义
  └── components/  # 子组件
      └── Dialog.vue

步骤二:定义类型

// src/views/newFeature/types.ts
export interface FeatureItem {
  id: number
  name: string
  description: string
  status: 'active' | 'inactive'
}

步骤三:定义 API

// src/views/newFeature/api.ts
import request from '/@/utils/service'

export function getFeatureList(params: any) {
  return request({
    url: '/api/feature/',
    method: 'get',
    params
  })
}

export function createFeature(data: any) {
  return request({
    url: '/api/feature/',
    method: 'post',
    data
  })
}

步骤四:创建页面

<!-- src/views/newFeature/index.vue -->
<template>
  <div class="feature-page">
    <el-table :data="tableData">
      <el-table-column prop="name" label="名称" />
    </el-table>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { getFeatureList } from './api'
import type { FeatureItem } from './types'

const tableData = ref<FeatureItem[]>([])

const loadData = async () => {
  const res = await getFeatureList({})
  tableData.value = res.data
}

onMounted(() => {
  loadData()
})
</script>

2. 使用 FastCRUD

// src/views/feature/crud.tsx
import { useCrud } from '@fast-crud/fast-crud'
import { createFeature, updateFeature, deleteFeature } from './api'

export default useCrud({
  async doAdd({ form }) {
    await createFeature(form)
  },
  async doEdit({ form }) {
    await updateFeature(form.id, form)
  },
  async doDel({ row }) {
    await deleteFeature(row.id)
  }
})

💡 常用功能示例

0. 项目中的实际示例

查看现有业务模块代码以了解项目风格:

  • 职位管理src/views/position/ - 复杂的职位详情编辑
  • 题库管理src/views/questionBank/ - 题目CRUD和管理
  • 系统管理src/views/system/account/ - 用户管理示例
  • 求职申请src/views/JobApplication/ - 申请状态管理

1. 权限控制

<template>
  <!-- 按钮权限 -->
  <auths value="system:user:add">
    <el-button @click="handleAdd">新增</el-button>
  </auths>
  
  <!-- 字段权限 -->
  <auth value="system:user:name:view">
    <span>{{ userInfo.name }}</span>
  </auth>
</template>

2. 消息提示

import { successMessage, warningMessage, errorMessage } from '/@/utils/message'

// 成功提示
successMessage('操作成功')

// 警告提示
warningMessage('请填写完整信息')

// 错误提示
errorMessage('操作失败')

3. 表格操作

<template>
  <fs-table>
    <fs-table-column prop="name" label="名称" />
    <template #action="{ row }">
      <el-button @click="handleEdit(row)">编辑</el-button>
      <el-button @click="handleDelete(row)">删除</el-button>
    </template>
  </fs-table>
</template>

4. 表单验证

<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'

const form = ref({
  name: '',
  email: ''
})

const rules = {
  name: [
    { required: true, message: '请输入名称', trigger: 'blur' }
  ],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱', trigger: 'blur' }
  ]
}
</script>

<template>
  <el-form :model="form" :rules="rules" ref="formRef">
    <el-form-item label="名称" prop="name">
      <el-input v-model="form.name" />
    </el-form-item>
    <el-form-item label="邮箱" prop="email">
      <el-input v-model="form.email" />
    </el-form-item>
  </el-form>
</template>

5. 文件上传

<template>
  <fs-uploader v-model="fileList" />
</template>

<script setup lang="ts">
import { ref } from 'vue'

const fileList = ref([])
</script>

6. 富文本编辑器

<template>
  <fs-editor v-model="content" />
</template>

<script setup lang="ts">
import { ref } from 'vue'

const content = ref('')
</script>

7. 字典数据获取

<template>
  <el-select v-model="value" dict="status">
    <el-option label="启用" value="1" />
    <el-option label="禁用" value="0" />
  </el-select>
</template>

8. 本地存储

import { Local } from '/@/utils/storage'

// 保存数据
Local.set('key', { data: 'value' })

// 获取数据
const data = Local.get('key')

// 删除数据
Local.remove('key')

9. 路由跳转

import { useRouter } from 'vue-router'

const router = useRouter()

// 普通跳转
router.push('/position/list')

// 带参数跳转
router.push({
  path: '/position/detail',
  query: { id: 123 }
})

// 在新标签页打开
window.open(`/position/detail?id=123`)

10. 表格数据操作

<script setup lang="ts">
const tableData = ref([])
const loading = ref(false)

const loadData = async () => {
  loading.value = true
  try {
    const res = await request({
      url: '/api/position/list/',
      method: 'get',
      params: { page: 1, limit: 20 }
    })
    tableData.value = res.data
  } finally {
    loading.value = false
  }
}

// 刷新数据
const refresh = () => {
  loadData()
}
</script>

<template>
  <el-table :data="tableData" v-loading="loading">
    <el-table-column prop="name" label="职位名称" />
    <el-table-column prop="status" label="状态" />
  </el-table>
</template>

🐛 调试技巧

1. Vue DevTools

安装 Vue DevTools 浏览器插件,用于:

  • 查看组件树
  • 检查组件状态
  • 追踪组件更新
  • 性能分析

2. 控制台调试

// 打印日志
console.log('Data:', data)

// 打印表格
console.table(dataList)

// 断点调试
debugger

// 打印组件实例
console.log(this.$refs.myComponent)

3. Vite HMR

修改代码后,Vite 会自动热更新,无需手动刷新页面。

4. 网络请求调试

使用浏览器开发者工具的 Network 面板:

  • 查看请求/响应
  • 检查请求头
  • 查看响应数据

❓ 常见问题

1. 依赖安装失败

# 清除缓存
npm cache clean --force

# 删除 node_modules
rm -rf node_modules

# 重新安装
npm install

2. 端口被占用

# 修改 vite.config.ts 中的端口
server: {
  port: 3000  // 改为其他端口
}

3. TypeScript 类型错误

# 重新生成类型声明
npm run type-check

4. 样式不生效

  • 检查样式文件导入
  • 检查 scoped 属性
  • 检查 Tailwind CSS 配置

5. 路由跳转失败

// 使用 router.push
import { useRouter } from 'vue-router'
const router = useRouter()
router.push('/path')

📚 参考资料

🎯 最佳实践

1. 组件拆分

保持组件精简,单一职责。

2. 代码复用

提取公共逻辑到 hooks 或 utils。

3. 性能优化

  • 使用 v-if 替代 v-show
  • 使用 computed 缓存计算
  • 大列表使用虚拟滚动

4. 错误处理

try {
  await saveData()
  successMessage('保存成功')
} catch (error) {
  errorMessage('保存失败')
  console.error(error)
}

提示:遇到问题时,先查阅文档,然后查看已有代码实现,最后在团队中讨论。