前端环境搭建
技术选型
本项目采用 Node.js 作为运行环境,核心框架选用 Vue,配合 ElementUI 组件库、Axios 请求拦截器、Vuex 状态管理、Vue-Router 路由以及 TypeScript 类型系统构建。
代码结构
项目核心目录与文件说明如下:
| 目录 / 文件 | 说明 |
|---|---|
| api | 封装 Ajax 请求的文件目录 |
| components | 公共组件存放目录 |
| views | 视图组件存放目录 |
| App.vue | 项目主组件、页面入口文件 |
| main.ts | 整个项目的入口文件 |
| router.ts | 路由配置文件 |
环境准备
安装依赖包(生成 node_modules 目录):
npm install
启动前端项目(需同时启动后端 Java 服务):
npm run serve
员工管理
分页查询
功能需求
实现员工列表的分页展示,支持按姓名筛选,并在表格中显示账号状态及操作按钮。
页面头部构建
使用 ElementUI 的 Input 和 Button 组件制作搜索栏。输入框与按钮均基于官方文档组件进行配置。
<div>
<label>员工姓名:</label>
<el-input placeholder="请输入员工姓名" />
<el-button type="primary">查询</el-button>
<el-button type="primary">+ 添加员工</el-button>
</div>
前后端数据交互
为查询按钮绑定 @click="pageQuery()" 事件。在 methods 中定义 pageQuery 方法,验证逻辑执行。
<script lang="ts">
export default {
methods: {
// 分页查询
pageQuery() {
// 验证当前方法能否成功执行
console.log('Query triggered')
}
}
}
</script>
封装 API 请求:在 src/api/employee.ts 中定义 getEmployeeList 方法,用于发送 Ajax 请求获取分页数据。
// 分页查询
export const getEmployeeList = (params: any) => {
return request({ url: '/employee/page', method: 'get', params })
}
导入 API 并定义模型数据:在员工管理组件中导入 getEmployeeList,并在 data() 中定义分页相关的模型数据。
import { getEmployeeList } from '@/api/employee'
export default {
data() {
return {
name: '', // 员工姓名
page: 1, // 页码
pageSize: 10, // 每页记录数
total: 0, // 总记录数
records: [] // 当前页要展示的数据集合
}
}
}
双向绑定输入框:将 name 属性与员工姓名输入框进行双向绑定。
<el-input v-model="name" placeholder="请输入员工姓名" clearable />
完善查询方法:在 pageQuery 方法中调用 getEmployeeList,处理返回数据。
pageQuery() {
const params = { page: this.page, pageSize: this.pageSize, name: this.name }
getEmployeeList(params)
.then((res) => {
if (res.data.code === 1) {
this.records = res.data.data.records
this.total = res.data.data.total
}
})
.catch((err) => {
this.$message.error('请求出错了:' + err.message)
})
}
自动加载数据
利用 Vue 的 created 生命周期钩子,在组件加载后自动发送 Ajax 请求,查询第一页数据。
created() {
this.pageQuery()
}
表格展示
使用 ElementUI 的 Table 组件展示后端返回的员工数据。注意状态列的样式处理。
<el-table :data="records" stripe>
<el-table-column prop="name" label="员工姓名" />
<el-table-column prop="username" label="账号" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="status" label="账号状态">
<template slot-scope="scope">
<span :class="scope.row.status === 0 ? 'stopUse' : 'activeUse'">
{{ scope.row.status === 0 ? '禁用' : '启用' }}
</span>
</template>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间" />
<el-table-column prop="操作" label="操作">
<template slot-scope="scope">
<el-button size="small" type="text">修改</el-button>
<el-button size="small" type="text">
{{ scope.row.status === 1 ? '禁用' : '启用' }}
</el-button>
<el-button size="small" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
分页条实现
使用 Pagination 组件实现翻页效果。监听 size-change 和 current-change 事件以刷新数据。
<el-pagination
:page-sizes="[10, 20, 30, 40, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
事件处理函数:
// pageSize 改变时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
// currentPage 改变时触发
handleCurrentChange(currentPage) {
this.page = currentPage
this.pageQuery()
}
启用禁用员工账号
功能需求
支持在列表中直接切换员工账号状态,管理员账号除外。
按钮交互
为表格中的'启用/禁用'按钮绑定 handleStartOrStop 事件,并根据当前状态动态显示文字。
<el-button type="text" size="small" @click="handleStartOrStop(scope.row)">
{{ scope.row.status == '1' ? '禁用' : '启用' }}
</el-button>
状态变更逻辑
在 methods 中定义 handleStartOrStop 方法,结合 ElementUI 的确认弹窗 confirm 确保操作安全。
handleStartOrStop(row) {
// 管理员保护逻辑
if (row.username === 'admin') {
this.$message.error('admin 为管理员账号,不能更改账号状态!')
return
}
this.$confirm('确认调整该账号的状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
enableOrDisableEmployee({ id: row.id, status: !row.status ? 1 : 0 })
.then((res) => {
if (res.status === 200) {
this.$message.success('账号状态更改成功!')
this.pageQuery() // 刷新数据
}
})
.catch((err) => {
this.$message.error('请求出错了:' + err.message)
})
})
}
封装 API 请求:在 src/api/employee.ts 中定义 enableOrDisableEmployee 方法。
export const enableOrDisableEmployee = (params: any) => {
return request({
url: `/employee/status/${params.status}`,
method: 'post',
params: { id: params.id }
})
}
新增员工
功能需求
通过表单录入员工信息,包含账号、姓名、手机、性别、身份证号等字段,并进行校验。
路由跳转
点击'添加员工'按钮,跳转到新增页面组件。
handleAddEmp() {
this.$router.push('/employee/add')
}
路由配置示例:
{ path: "/employee/add", component: () => import("@/views/employee/addEmployee.vue"), meta: { title: "添加/修改员工", hidden: true } }
表单元素开发
使用 Form 组件构建表单,设置 rules 进行校验。
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="180px">
<el-form-item label="账号" prop="username">
<el-input v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item label="员工姓名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="ruleForm.phone"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio v-model="ruleForm.sex" label="1">男</el-radio>
<el-radio v-model="ruleForm.sex" label="2">女</el-radio>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="ruleForm.idNumber"></el-input>
</el-form-item>
<div>
<el-button type="primary" @click="submitForm('ruleForm',false)">保存</el-button>
<el-button type="primary" @click="submitForm('ruleForm',true)">保存并继续添加员工</el-button>
<el-button @click="() => this.$router.push('/employee')">返回</el-button>
</div>
</el-form>
表单校验规则
定义正则表达式校验手机号和身份证号格式。
rules: {
phone: [
{
required: true,
trigger: 'blur',
validator: (rule, value, callback) => {
if (value === '' || !(/^1[3|4|5|6|7|8]\d{9}$/.test(value))) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
}
],
idNumber: [
{
required: true,
trigger: 'blur',
validator: (rule, value, callback) => {
if (value === '' || !(/(\d{15}$)|(\d{18}$)|(\d{17}(\d|X|x)$)/.test(value))) {
callback(new Error('请输入正确的身份证号'))
} else {
callback()
}
}
}
]
}
提交逻辑
封装 addEmployee 方法,根据 isContinue 参数决定是否保留表单或跳转。
submitForm(formName, isContinue) {
this.$refs[formName].validate((valid) => {
if (valid) {
addEmployee(this.ruleForm)
.then((res: any) => {
if (res.data.code === 1) {
this.$message.success('员工添加成功!')
if (isContinue) {
this.$router.push({ path: '/employee/add' })
} else {
this.ruleForm = { username: '', name: '', phone: '', sex: '1', idNumber: '' }
}
} else {
this.$message.error(res.data.msg)
}
})
}
})
}
修改员工
功能需求
复用新增页面组件,通过路由参数区分新增与修改模式,支持数据回显。
路由传参
点击'修改'按钮时,携带 ID 参数跳转。
handleUpdateEmp(row) {
if (row.username === 'admin') {
this.$message.error('admin 为管理员账号,不能修改!')
return
}
this.$router.push({ path: '/employee/add', query: { id: row.id } })
}
组件内判断
在 addEmployee.vue 中通过 optType 区分操作类型,并在 created 中根据路由参数初始化。
created() {
this.optType = this.$route.query.id ? 'update' : 'add'
if (this.optType === 'update') {
queryEmployeeById(this.$route.query.id).then((res) => {
if (res.data.code === 1) {
this.ruleForm = res.data.data
}
})
}
}
接口区分
封装 queryEmployeeById 和 updateEmployee 方法,分别对应 GET 和 PUT 请求。
export const queryEmployeeById = (id: number) => {
return request({ url: `/employee/${id}`, method: 'get' })
}
export const updateEmployee = (params: any) => {
return request({ url: '/employee', method: 'put', data: params })
}
按钮控制
仅在新增模式下显示'保存并继续添加员工'按钮。
<el-button v-if="this.optType === 'add'" type="primary" @click="submitForm('ruleForm',true)">
保存并继续添加员工
</el-button>
套餐管理
套餐分页查询
功能需求
支持按套餐名称、分类、售卖状态筛选,展示图片、价格及操作选项。
页面头部构建
增加下拉选择框以支持分类和状态筛选。
<div>
<label>套餐名称:</label>
<el-input v-model="name" clearable />
<label>套餐分类:</label>
<el-select v-model="categoryId" placeholder="请选择">
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<label>售卖状态:</label>
<el-select v-model="status" placeholder="请选择" clearable>
<el-option v-for="item in statusArr" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-button type="primary">查询</el-button>
<div>
<el-button type="danger">批量删除</el-button>
<el-button type="info">+ 新建套餐</el-button>
</div>
</div>
动态填充分类数据
在 created 生命周期中调用分类接口,填充下拉框选项。
import { getCategoryByType } from '@/api/category'
created() {
getCategoryByType({type: 2}).then((res) => {
if (res.data.code === 1) {
this.options = res.data.data
}
})
}
表格展示
使用 Image 组件展示套餐图片,状态列根据数值渲染文本。
<el-table :data="records" stripe>
<el-table-column prop="image" label="图片">
<template slot-scope="scope">
<el-image :src="scope.row.image"></el-image>
</template>
</el-table-column>
<el-table-column prop="name" label="套餐名称" />
<el-table-column prop="price" label="套餐价" />
<el-table-column prop="categoryName" label="套餐分类" />
<el-table-column label="售卖状态">
<template slot-scope="scope">
<div :class="scope.row.status === 0 ? 'stopUse' : 'activeUse'">
{{ scope.row.status === 0 ? '停售' : '启售' }}
</div>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" size="small">修改</el-button>
<el-button type="text" size="small">
{{ scope.row.status === 1 ? '停售' : '启售' }}
</el-button>
<el-button type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
启售停售套餐
功能需求
允许运营人员快速切换套餐的售卖状态。
状态切换逻辑
封装 enableOrDisableSetmeal 方法,结合确认弹窗防止误操作。
handleStartOrStop(row) {
this.$confirm('确认调整该套餐的售卖状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
enableOrDisableSetmeal({ id: row.id, status: !row.status ? 1 : 0 })
.then((res) => {
if (res.status === 200) {
this.$message.success('套餐售卖状态更改成功!')
this.pageQuery()
}
})
.catch((err) => {
this.$message.error('请求出错了:' + err.message)
})
})
}
删除套餐
功能需求
支持单个删除与批量删除,需先勾选再操作。
批量删除实现
监听表格 selection-change 事件获取选中行 ID,拼接后发送给后端。
handleDelete(type: string, id: string) {
let param
if (type === 'B' && this.multipleSelection.length === 0) {
this.$message('请选择需要删除的套餐!')
return
}
this.$confirm('确定删除该套餐?', '确定删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (type === 'S') {
param = id
} else {
const arr = new Array()
this.multipleSelection.forEach(element => {
arr.push(element.id)
})
param = arr.join(',')
}
deleteSetmeal(param).then(res => {
if (res.data.code === 1) {
this.$message.success('删除成功!')
this.pageQuery()
} else {
this.$message.error(res.data.msg)
}
})
})
}
新增套餐
功能需求
创建新套餐,关联菜品分类,设置售卖状态。
路由与组件
点击'新建套餐'跳转至 /setmeal/add,复用类似员工管理的表单逻辑,但数据结构不同。
核心逻辑
主要涉及套餐数据的提交与分类数据的联动。具体表单结构与员工新增类似,重点在于 setMeal 相关 API 的调用。
本文档涵盖了苍穹外卖系统前端的核心业务模块实现细节,从基础环境搭建到复杂 CRUD 操作,展示了 Vue 生态在企业级应用中的典型用法。

