Post

07_前端开发基础_Vue3实战(前端工程化讲解)

本 绹 本篇章内容强调两大前端模块的构建:登录和商品管理。核心在于与后端接口的有效对接,确保交互流畅且准确。关键观点体现在使用 **Vue 3 来实现表单验证与数据交互、Element Plus 提供的组件以简化UI设格,以及通过`Axios" 增强的数据请求功能。。 登录功能涉及验证表单输入、发送 POST 请求至 `/api/login`,并实现成功后的页面路由跳转。商品管理模块则扩展了商品增删改查(CRUD) 的操作,从基本数据获取到包含分页、搜索、新增、编辑、和删除功能的完整实现。 具体而言,通过 Vue 3 的组合式 API 创建响应式数据及事件处理,通过 Element Plus 的表表组件渲染即时数据集,并利用 Element Plus 的对话框实现用户输入验证和数据提交。后代表现和交互处理的整体现示了前端应用的多余层次与动态响应能力。

进销存项目 阅读 0 点赞 0 评论 0

07_前端开发基础_Vue3实战

[TOC]

前言

本章节我们将切换到 前端开发 的视角。
我们将使用 frontend-student 项目作为练习环境,该项目已经搭建好了基础框架(Vue 3 + Vite + Element Plus),但 登录商品管理 模块的代码已被清空。
你的任务是:手动实现这两个模块的前端逻辑,并与后端接口进行对接!

后端接口文档地址http://localhost:8080/doc.html (请确保后端项目已启动)


一、前端环境准备

1.1 安装 Node.js

前端开发离不开 Node.js 环境。请确保你已安装 Node.js (建议 v16+)。
验证命令:

node -v
npm -v

1.2 启动项目

进入 frontend-student 目录,安装依赖并启动:

# 进入目录
cd frontend-student

# 安装依赖
npm install

# 启动项目
npm run dev

启动成功后,浏览器打开 http://localhost:5173。你会看到一个空白的登录页。


二、实战:登录模块 (Login.vue)

目标:实现用户登录界面,调用后端 /api/login 接口,登录成功后跳转到首页。
文件位置src/views/Login.vue

2.1 编写 HTML 结构 (Template)

使用 Element Plus 的表单组件。

<template>
  <div class="login-container">
    <el-card class="login-card">
      <template #header>
        <h2 style="text-align: center">进销存系统登录</h2>
      </template>
      
      <el-form :model="form" ref="formRef" :rules="rules">
        <el-form-item prop="username">
          <el-input v-model="form.username" placeholder="用户名" prefix-icon="User" />
        </el-form-item>
        
        <el-form-item prop="password">
          <el-input 
            v-model="form.password" 
            placeholder="密码" 
            prefix-icon="Lock" 
            type="password" 
            show-password 
            @keyup.enter="handleLogin"
          />
        </el-form-item>
        
        <el-button type="primary" style="width: 100%" @click="handleLogin" :loading="loading">
          立即登录
        </el-button>
      </el-form>
    </el-card>
  </div>
</template>

2.2 编写 JS 逻辑 (Script)

使用 Vue 3 的 setup 语法糖和 axios 请求。

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import request from '@/utils/request' // 已封装好的 axios 实例
import { ElMessage } from 'element-plus'

const router = useRouter()
const loading = ref(false)
const formRef = ref(null)

// 响应式表单数据
const form = reactive({
  username: '',
  password: ''
})

// 表单校验规则
const rules = {
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}

const handleLogin = () => {
  // 1. 校验表单
  formRef.value.validate(async (valid) => {
    if (!valid) return
    
    loading.value = true
    try {
      // 2. 调用后端接口
      // 后端接口: POST /api/login, 参数: { username, password }
      const res = await request.post('/login', form)
      
      // 3. 处理响应
      ElMessage.success('登录成功')
      // 登录成功后跳转到首页
      router.push('/')
      
    } catch (error) {
      // 错误处理已在 request.js 拦截器中统一处理,这里可省略或做额外操作
      console.error(error)
    } finally {
      loading.value = false
    }
  })
}
</script>

2.3 添加样式 (Style)

<style scoped>
.login-container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f0f2f5;
}
.login-card {
  width: 400px;
}
</style>

三、实战:商品管理 (Product.vue)

目标:实现商品的增删改查 (CRUD)。为了让大家更好地理解,我们将这个大功能拆解为 5 个小步骤,逐一实现。
文件位置src/views/Product.vue

3.1 第一步:基础列表展示 (Read)

先实现最简单的功能:从后端获取数据,展示在表格中。不考虑搜索和分页。

3.1.1 编写 HTML (Template)

只保留表格部分,使用 el-table 组件。

<template>
  <div class="page-container">
    <!-- 表格 -->
    <el-table :data="tableData" border stripe v-loading="loading">
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="name" label="商品名称" />
      <el-table-column prop="categoryName" label="分类" />
      <el-table-column prop="price" label="价格">
        <template #default="{ row }">¥{{ row.price }}</template>
      </el-table-column>
      <el-table-column prop="stock" label="库存" />
    </el-table>
  </div>
</template>

3.1.2 编写 JS (Script)

定义数据并调用 /api/products 接口。

<script setup>
import { ref, onMounted } from 'vue'
import request from '@/utils/request'

// 响应式数据
const tableData = ref([])
const loading = ref(false)

// 获取商品列表的方法
const fetchData = async () => {
  loading.value = true
  try {
    // 暂时不传分页参数,后端默认会返回第一页
    const res = await request.get('/products')
    // 注意:后端返回结构是 res.data.data.records (MyBatis-Plus 分页结构)
    tableData.value = res.data.data.records
  } finally {
    loading.value = false
  }
}

// 页面加载完成后自动调用
onMounted(() => {
  fetchData()
})
</script>

<style scoped>
.page-container {
  padding: 20px;
}
</style>

3.2 第二步:添加搜索和分页

数据量大了需要分页,且需要根据名称搜索。

3.2.1 修改 HTML

在表格上方添加 搜索框,在表格下方添加 分页组件

<template>
  <div class="page-container">
    <!-- 1. 工具栏 (新增) -->
    <div class="toolbar">
      <el-input 
        v-model="searchName" 
        placeholder="搜索商品名称" 
        style="width: 200px" 
        clearable
        @clear="fetchData"
        @keyup.enter="fetchData"
      >
        <template #append>
          <el-button icon="Search" @click="fetchData" />
        </template>
      </el-input>
    </div>

    <!-- 2. 表格 (保持不变) -->
    <el-table :data="tableData" border stripe v-loading="loading">
       <!-- ...列定义... -->
    </el-table>

    <!-- 3. 分页 (新增) -->
    <div class="pagination">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="[10, 20, 50]"
        layout="total, sizes, prev, pager, next"
        :total="total"
        @size-change="fetchData"
        @current-change="fetchData"
      />
    </div>
  </div>
</template>

3.2.2 修改 JS

添加分页参数和搜索参数,并更新 fetchData 方法。

// ... 之前的 import ...

// 新增响应式数据
const searchName = ref('')
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0) // 总条数

const fetchData = async () => {
  loading.value = true
  try {
    // 传入参数
    const res = await request.get('/products', {
      params: {
        page: currentPage.value,
        size: pageSize.value,
        name: searchName.value
      }
    })
    tableData.value = res.data.data.records
    total.value = res.data.data.total // 更新总条数
  } finally {
    loading.value = false
  }
}

// ... onMounted ...

记得添加样式:

.toolbar {
  margin-bottom: 20px;
  display: flex;
}
.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}

3.3 第三步:添加“新建商品”功能 (Create)

通过弹窗 (el-dialog) 来实现商品的添加。

3.3.1 修改 HTML

  1. 在工具栏添加“新建”按钮。
  2. 添加弹窗组件。
    <!-- 工具栏 -->
    <div class="toolbar">
      <!-- 新增按钮 -->
      <el-button type="primary" icon="Plus" @click="openCreateDialog">新建商品</el-button>
      
      <!-- ...搜索框... -->
    </div>

    <!-- ...表格... -->

    <!-- 弹窗 (新增) -->
    <el-dialog v-model="dialogVisible" title="新建商品" width="500px">
      <el-form :model="form" label-width="80px">
        <el-form-item label="名称">
          <el-input v-model="form.name" />
        </el-form-item>
        <el-form-item label="分类">
          <!-- 下拉框数据来源于 categories -->
          <el-select v-model="form.categoryId" placeholder="请选择分类" style="width: 100%">
            <el-option v-for="c in categories" :key="c.id" :label="c.name" :value="c.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="价格">
          <el-input-number v-model="form.price" :min="0" :precision="2" />
        </el-form-item>
        <el-form-item label="库存">
          <el-input-number v-model="form.stock" :min="0" :precision="0" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitCreateForm">确定</el-button>
      </template>
    </el-dialog>

3.3.2 修改 JS

添加弹窗控制、表单数据、分类列表获取、提交逻辑。

import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'

// ... 之前的代码 ...

const dialogVisible = ref(false)
const categories = ref([]) // 分类下拉数据
const form = reactive({
  name: '',
  categoryId: null,
  price: 0,
  stock: 0
})

// 获取分类列表 (用于下拉框)
const fetchCategories = async () => {
  const res = await request.get('/categories')
  categories.value = res.data.data
}

// 打开新建弹窗
const openCreateDialog = () => {
  // 重置表单
  form.name = ''
  form.categoryId = null
  form.price = 0
  form.stock = 0
  
  dialogVisible.value = true
  // 如果分类数据为空,则请求一次
  if (categories.value.length === 0) {
    fetchCategories()
  }
}

// 提交新建表单
const submitCreateForm = async () => {
  try {
    // 调用后端 POST 接口
    await request.post('/products', form)
    ElMessage.success('添加成功')
    dialogVisible.value = false
    fetchData() // 刷新列表
  } catch (error) {
    console.error(error)
  }
}

3.4 第四步:添加“编辑商品”功能 (Update)

复用同一个弹窗,但需要区分是“新建”还是“编辑”。

3.4.1 修改 HTML

  1. 在表格中添加“操作”列(包含编辑按钮)。
  2. 修改弹窗标题,动态显示“新建”或“编辑”。
  3. 注意:我们将之前的“新建商品”按钮的点击事件也修改为 openDialog
    <!-- 工具栏 (修改按钮点击事件) -->
    <div class="toolbar">
      <el-button type="primary" icon="Plus" @click="openDialog()">新建商品</el-button>
      <!-- ...搜索框... -->
    </div>

    <!-- 表格 (添加操作列) -->
    <el-table ...>
      <!-- ...其他列... -->
      <el-table-column label="操作" width="180">
        <template #default="{ row }">
          <el-button type="primary" link @click="openDialog(row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 弹窗 (标题动态化, 按钮事件修改) -->
    <el-dialog v-model="dialogVisible" :title="form.id ? '编辑商品' : '新建商品'" width="500px">
       <!-- ...表单内容不变... -->
       <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <!-- 按钮点击事件改为统一的 submitForm -->
        <el-button type="primary" @click="submitForm">确定</el-button>
      </template>
    </el-dialog>

3.4.2 修改 JS

增加 id 字段,并合并新建和编辑的逻辑。我们将之前的 openCreateDialogsubmitCreateForm 改造为通用的 openDialogsubmitForm

// 1. 修改 form 定义,增加 id 字段
const form = reactive({
  id: null, // 新增
  name: '',
  categoryId: null,
  price: 0,
  stock: 0
})

// 2. 定义通用的打开弹窗方法 (替换原有的 openCreateDialog)
const openDialog = (row = null) => {
  if (row) {
    // 编辑模式:回显数据
    Object.assign(form, row)
  } else {
    // 新建模式:重置表单
    form.id = null
    form.name = ''
    form.categoryId = null
    form.price = 0
    form.stock = 0
  }
  dialogVisible.value = true
  if (categories.value.length === 0) {
    fetchCategories()
  }
}

// 3. 定义通用的提交方法 (替换原有的 submitCreateForm)
const submitForm = async () => {
  try {
    if (form.id) {
      // 有ID,说明是编辑 -> PUT
      await request.put('/products', form)
    } else {
      // 无ID,说明是新建 -> POST
      await request.post('/products', form)
    }
    ElMessage.success('操作成功')
    dialogVisible.value = false
    fetchData() // 刷新列表
  } catch (error) {
    console.error(error)
  }
}

3.5 第五步:添加“删除”功能 (Delete)

最后完善删除逻辑。

3.5.1 修改 HTML

在操作列添加“删除”按钮,使用 el-popconfirm 二次确认。

      <el-table-column label="操作" width="180">
        <template #default="{ row }">
          <!-- 编辑按钮 -->
          <el-button type="primary" link @click="openDialog(row)">编辑</el-button>
          
          <!-- 删除按钮 (新增) -->
          <el-popconfirm title="确定删除吗?" @confirm="handleDelete(row.id)">
            <template #reference>
              <el-button type="danger" link>删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>

3.5.2 修改 JS

添加删除方法。

const handleDelete = async (id) => {
  try {
    await request.delete(`/products/${id}`)
    ElMessage.success('删除成功')
    fetchData() // 刷新列表
  } catch (error) {
    console.error(error)
  }
}

四、总结

通过本章节的练习,你应该掌握了:

  1. Vue 3 组合式 API (ref, reactive, onMounted) 的基本使用。
  2. Element Plus 常用组件 (el-table, el-form, el-dialog) 的使用。
  3. Axios 前后端数据交互(GET, POST, PUT, DELETE)。

前端开发的本质就是:获取数据 -> 渲染页面 -> 响应交互 -> 提交数据。希望你能通过这个案例举一反三!

继续阅读

全部归档
06_进销存系统_进阶功能
06_进销存系统_进阶功能

该该简要摘要涵盖了 Excel 导出和定时任务的核心内容, .以及相关的关键结论和细节和技术收益: --- 在使用进销存系统中的改进功能。 弳主要有两项: . 一是 1 . . 1 . . . . . . . . . 开` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 摘要: : 该系统进销存 . 中加入的两项改进功能: 包括使用 .Excel �导出功能和定时任务. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

04_进销存系统_项目搭建
04_进销存系统_项目搭建

从零开始搭建进销存系统的开发环境,涉及前端和后端两部分。前端仅需导入代码并启动,具体步骤包括导入前端项目 (位于 `frontend` 文件夹)、初始化依赖 (`npm install`) 与启动开发服务器 (`npm run dev`)。后端部分则更丰富,涵盖创建Spring Boot项目、引入特定依赖 (如Web、MySQL和MyBatis+Plus等)””以及配置文件 (`application.yml`)”。后端骨架生成后,需手动编写Controller层代码以实现具体的业务功能。总体而言,“本章节帮助开发者完成基础环境设置,为后续功能开发奠定基础。

评论