快速开发实践

基于后端项目的前端开发实践记录

📋 项目概述

项目名称 : 比特奥定制报表系统
技术栈 : Vue 3 + Element Plus + Vite (前端) + Spring Boot (后端)
开发模式 : 前后端分离
项目结构: 单体仓库包含前后端代码

🏗️ 项目架构分析

目录结构设计

复制代码
bitao-defined_report_ui/
├── src/                    # 前端源码
│   ├── api/               # API接口层
│   ├── components/        # 组件库
│   │   ├── dict/         # 字典管理组件
│   │   ├── report/       # 报表管理组件
│   │   └── layout/       # 布局组件
│   ├── router/           # 路由配置
│   └── utils/            # 工具函数
├── backend/               # 后端源码
│   └── bitao-defined-report/
└── public/               # 静态资源

技术选型理由

  1. Vue 3: 组合式API,更好的TypeScript支持
  2. Element Plus: 成熟的UI组件库,快速开发
  3. Vite: 快速的构建工具,热更新体验好
  4. Axios: HTTP客户端,支持拦截器和请求/响应处理

🔄 前后端协作流程

1. API设计先行

后端API规范
java 复制代码
// 统一响应格式
public class ApiResponse<T> {
    private String traceId;     // 追踪ID
    private boolean result;     // 操作结果
    private int code;          // 状态码
    private String msg;        // 消息
    private T data;           // 数据
    private boolean success;   // 成功标识
}

// 分页参数基类
public class PageObject {
    private Integer pageNum = 1;
    private Integer pageSize = 10;
    private String isAsc = "desc";
}
前端API封装
javascript 复制代码
// api/reportApi.js
import request from '@/utils/request'

/**
 * 获取报表列表
 * @param {Object} params 查询参数
 * @returns {Promise} API响应
 */
export function getReportList(params) {
  return request({
    url: '/defined-report/report/selectByPage',
    method: 'post',
    data: params
  })
}

2. 数据类型对齐

关键经验:类型一致性
场景 后端类型 前端处理 注意事项
布尔状态 Boolean null/true/false 避免空字符串
分页参数 Integer Number 确保数值类型
时间字段 LocalDateTime String 统一格式化
枚举值 Enum String/Number 保持值一致
实际案例:状态字段处理
javascript 复制代码
// ❌ 错误做法
const queryParams = {
  usableStatus: ''  // 空字符串无法转换为Boolean
}

// ✅ 正确做法
const queryParams = {
  usableStatus: null  // null表示不筛选,true/false表示具体状态
}

🎨 组件开发模式

1. 页面组件结构

标准页面模板
vue 复制代码
<template>
  <div class="page-container">
    <!-- 查询表单 -->
    <div class="search-form">
      <el-form :model="queryParams" :inline="true">
        <!-- 查询条件 -->
      </el-form>
    </div>
    
    <!-- 操作工具栏 -->
    <div class="toolbar">
      <el-button type="primary" @click="handleAdd">新增</el-button>
    </div>
    
    <!-- 数据表格 -->
    <el-table :data="dataList" v-loading="loading">
      <!-- 表格列 -->
    </el-table>
    
    <!-- 分页组件 -->
    <pagination 
      v-model:page="queryParams.pageNum"
      v-model:limit="queryParams.pageSize"
      :total="total"
      @pagination="getList"
    />
  </div>
</template>

<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'

// 响应式数据
const loading = ref(false)
const dataList = ref([])
const total = ref(0)

// 查询参数
const queryParams = reactive({
  pageNum: 1,
  pageSize: 10,
  // 其他查询字段
})

// 获取列表数据
const getList = async () => {
  loading.value = true
  try {
    const response = await apiMethod(queryParams)
    if (response.code === 200) {
      dataList.value = response.data.data || []
      total.value = response.data.total || 0
    } else {
      ElMessage.error(response.message || '获取数据失败')
    }
  } catch (error) {
    console.error('获取数据失败:', error)
    ElMessage.error('网络错误,请稍后重试')
  } finally {
    loading.value = false
  }
}

// 页面初始化
onMounted(() => {
  getList()
})
</script>

2. 组件复用策略

通用组件抽取
javascript 复制代码
// components/pub/Pagination.vue - 分页组件
// components/layout/AppHeader.vue - 页面头部
// components/layout/Sidebar.vue - 侧边栏
业务组件分类
javascript 复制代码
// components/dict/ - 字典管理相关组件
// components/report/ - 报表管理相关组件
//   ├── management/ - 报表列表管理
//   ├── designer/ - 报表设计器
//   └── preview/ - 报表预览

🔧 开发工具配置

1. Vite配置优化

javascript 复制代码
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  server: {
    port: 3000,
    proxy: {
      '/defined-report': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
})

2. 请求拦截器配置

javascript 复制代码
// utils/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 添加token等通用处理
    return config
  },
  error => {
    console.log(error)
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    const res = response.data
    
    // 统一错误处理
    if (res.code !== 200) {
      ElMessage.error(res.message || '系统错误')
      return Promise.reject(new Error(res.message || 'Error'))
    }
    
    return res
  },
  error => {
    console.log('err' + error)
    ElMessage.error(error.message)
    return Promise.reject(error)
  }
)

export default service

🐛 常见问题与解决方案

1. 分页查询问题

问题描述

前端发送分页请求时,后端返回"系统繁忙"错误

根本原因
  1. 参数类型不匹配(字符串 vs 布尔值)
  2. 缺少默认分页参数
解决方案
javascript 复制代码
// 前端:确保参数类型正确
const queryParams = reactive({
  pageNum: 1,           // Number类型
  pageSize: 10,         // Number类型
  usableStatus: null    // null/Boolean类型
})
java 复制代码
// 后端:添加默认构造函数
public ReportFormsPageParam() {
    super();
    this.setPageNum(1);
    this.setPageSize(10);
    this.setIsAsc("desc");
}

2. 状态管理最佳实践

组件内状态
javascript 复制代码
// 使用 reactive 管理表单数据
const formData = reactive({
  name: '',
  status: null
})

// 使用 ref 管理简单状态
const loading = ref(false)
const visible = ref(false)
跨组件状态
javascript 复制代码
// 使用 provide/inject
// 父组件
provide('userInfo', userInfo)

// 子组件
const userInfo = inject('userInfo')

📊 性能优化实践

1. 组件懒加载

javascript 复制代码
// router/index.js
const routes = [
  {
    path: '/report/list',
    component: () => import('@/components/report/management/ReportList.vue')
  }
]

2. 表格虚拟滚动

vue 复制代码
<!-- 大数据量表格优化 -->
<el-table-v2
  :columns="columns"
  :data="data"
  :width="700"
  :height="400"
  fixed
/>

3. 请求防抖

javascript 复制代码
import { debounce } from 'lodash-es'

// 搜索防抖
const handleSearch = debounce(() => {
  getList()
}, 300)

🔍 调试与测试

1. 开发调试

javascript 复制代码
// 开发环境日志
if (process.env.NODE_ENV === 'development') {
  console.log('API请求参数:', params)
  console.log('API响应数据:', response)
}

2. API测试

bash 复制代码
# 使用PowerShell测试API
Invoke-WebRequest -Uri 'http://localhost:3000/defined-report/report/selectByPage' `
  -Method POST `
  -ContentType 'application/json' `
  -Body '{"pageNum": 1, "pageSize": 10}'

📝 开发规范

1. 命名规范

  • 文件命名: PascalCase (ReportList.vue)
  • 组件名: PascalCase (ReportList)
  • 方法名: camelCase (handleQuery)
  • 常量名: UPPER_SNAKE_CASE (API_BASE_URL)

2. 代码注释

javascript 复制代码
/**
 * 获取报表列表数据
 * @param {Object} params 查询参数
 * @param {Number} params.pageNum 页码
 * @param {Number} params.pageSize 每页大小
 * @returns {Promise<Object>} 返回报表列表数据
 */
const getReportList = async (params) => {
  // 实现逻辑
}

3. 错误处理

javascript 复制代码
try {
  const response = await apiCall()
  // 成功处理
} catch (error) {
  console.error('操作失败:', error)
  ElMessage.error('操作失败,请稍后重试')
  // 错误恢复逻辑
}

🚀 部署与发布

1. 构建配置

json 复制代码
// package.json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

2. 环境配置

javascript 复制代码
// .env.development
VUE_APP_BASE_API = '/api'
VUE_APP_ENV = 'development'

// .env.production
VUE_APP_BASE_API = 'https://api.example.com'
VUE_APP_ENV = 'production'

📈 项目总结

成功经验

  1. 前后端类型对齐: 避免了大量的类型转换问题
  2. 组件化开发: 提高了代码复用性和维护性
  3. 统一错误处理: 提升了用户体验
  4. API层抽象: 便于接口管理和维护

改进建议

  1. 引入TypeScript: 提供更好的类型安全
  2. 添加单元测试: 保证代码质量
  3. 性能监控: 添加性能指标收集
  4. 文档完善: 建立完整的组件文档

技术债务

  1. 部分组件耦合度较高,需要进一步解耦
  2. 缺少统一的状态管理方案
  3. 错误边界处理不够完善
  4. 缺少自动化测试覆盖

🎯 最佳实践总结

  1. API优先设计: 前后端并行开发的基础
  2. 类型一致性: 减少运行时错误的关键
  3. 组件化思维: 提高开发效率的核心
  4. 错误处理: 用户体验的重要保障
  5. 性能意识: 从开发阶段就要考虑性能优化
  6. 文档驱动: 良好的文档是团队协作的基础

通过这个项目的实践,我们建立了一套完整的前端开发流程和规范,为后续项目提供了宝贵的经验和参考。