当前位置: 首页 > news >正文

8. 【Vue实战--孢子记账--Web 版开发】-- 账户账本管理

本篇文章,咱们就来好好聊聊 AccountBook.vue 这个文件,它可是咱们孢子记账Web版里管理账本的核心。通过它,咱们能实现账本的增删改查,让你的财务管理井井有条。

一、功能概览

先来看看 AccountBook.vue 都能干些啥。简单来说,它就是账本的“大管家”,负责展示你的所有账本,并且提供新建、编辑、删除账本的功能。界面上,你会看到一个个账本卡片,每个卡片上都显示着账本的名称、描述和余额,旁边还有编辑和删除的按钮,操作起来非常直观。

在这里插入图片描述

二、实现细节

接下来,咱们深入代码,看看这些功能是怎么实现的。AccountBook.vue 是一个Vue单文件组件,采用了 <script setup> 语法糖,让代码更简洁、更易读。它主要依赖 vue 核心库、element-plus 组件库以及咱们自己定义的接口文件。

2.1 引入与依赖

<script setup> 块的开头,咱们可以看到一些必要的引入:

import {ref, onMounted, inject} from 'vue'
import type {AccountBook, CreateAccountBookRequest, UpdateAccountBookRequest} from '../Interface/accountBook.ts'
import type {Response} from '../Interface/response.ts'
import {ElMessage, ElMessageBox} from 'element-plus'
import {Plus, Edit, Delete, Setting} from '@element-plus/icons-vue'const axios: any = inject('axios')

这里 refonMounted 是Vue 3的API,用于创建响应式数据和处理组件挂载生命周期。inject('axios') 则是从全局注入 axios 实例,方便咱们进行HTTP请求。AccountBookCreateAccountBookRequestUpdateAccountBookRequestResponse 都是咱们自定义的TypeScript接口,它们定义了数据结构,让代码更健壮。element-plus 提供了丰富的UI组件,比如 ElMessage 用于消息提示,ElMessageBox 用于弹窗确认,还有各种图标,让界面更美观。

2.2 状态管理

为了管理账本数据和UI状态,咱们定义了一些响应式变量:

// 账本列表
const accountBooks = ref<AccountBook[]>([])
const loading = ref(false)// 创建账本相关
const createDialogVisible = ref(false)
const createForm = ref<CreateAccountBookRequest>({name: '',remarks: ''
})// 编辑账本相关
const editDialogVisible = ref(false)
const editForm = ref<UpdateAccountBookRequest>({accountBookId: '',name: '',remarks: ''
})

accountBooks 用来存储从后端获取到的账本列表,loading 则表示数据是否正在加载中。createDialogVisibleeditDialogVisible 控制新建和编辑账本的弹窗显示与隐藏。createFormeditForm 分别绑定了新建和编辑账本表单的数据,它们都是 ref 响应式对象,确保表单数据的实时更新。

2.3 表单验证

为了保证数据的合法性,咱们还定义了表单验证规则 formRules

// 表单验证规则
const formRules = {name: [{required: true, message: '请输入账本名称', trigger: 'blur'},{max: 20, message: '账本名称不能超过20个字符', trigger: 'blur'}],remarks: [{max: 100, message: '账本描述不能超过100个字符', trigger: 'blur'}]
}// 表单引用
const createFormRef = ref()
const editFormRef = ref()

formRules 定义了 nameremarks 字段的验证规则,比如 name 是必填项,且最大长度为20个字符。createFormRefeditFormRef 则是对表单组件的引用,方便咱们在提交表单时调用 validate() 方法进行手动验证。

2.4 获取账本列表

getAccountBooks 函数负责从后端获取账本列表数据:

// 获取账本列表
const getAccountBooks = async () => {loading.value = truetry {const response = await axios.post(import.meta.env.VITE_API_BASE_URL + '/api/AccountBook/Query',{data: {pageIndex: 1,pageSize: 100}},{headers: {'Authorization': localStorage.getItem('token'),'Content-Type': 'application/json'}})const result: Response<AccountBook[]> = response.dataconsole.log('获取账本列表响应:', result)if (result.statusCode === 200) {accountBooks.value = result.data.data || []} else {ElMessage.error(result.errorMessage || '获取账本列表失败')}} catch (error) {console.error('获取账本列表失败:', error)ElMessage.error('获取账本列表失败')} finally {loading.value = false}
}

这个函数是一个异步函数,首先将 loading 设置为 true,表示正在加载。然后通过 axios.post 向后端 /api/AccountBook/Query 接口发送请求,请求体中包含了分页信息(这里是获取前100条数据),请求头中携带了 Authorization token 进行身份认证。请求成功后,会根据 statusCode 判断是否成功,如果成功则将返回的账本数据赋值给 accountBooks,否则显示错误消息。无论成功失败,最后都会将 loading 设置为 false

2.5 创建账本

createAccountBook 函数用于新建账本:

// 创建账本
const createAccountBook = async () => {try {// 表单验证await createFormRef.value.validate()const response = await axios.post(import.meta.env.VITE_API_BASE_URL + '/api/AccountBook/Add',createForm.value, {headers: {'Authorization': localStorage.getItem('token')}})const result: Response<boolean> = response.dataif (result.statusCode === 200) {ElMessage.success('创建账本成功')createDialogVisible.value = false// 重置表单createForm.value = {name: '',remarks: ''}// 重新获取列表await getAccountBooks()} else {ElMessage.error(result.errorMessage || '创建账本失败')}} catch (error) {if (error !== 'cancel') {console.error('创建账本失败:', error)ElMessage.error('创建账本失败')}}
}

在创建账本之前,会先调用 createFormRef.value.validate() 进行表单验证。验证通过后,通过 axios.post/api/AccountBook/Add 接口发送请求,请求体就是 createForm 的数据。成功后,会显示“创建账本成功”的消息,关闭新建弹窗,重置表单数据,并重新获取账本列表以更新界面。

2.6 删除账本

deleteAccountBook 函数用于删除账本:

// 删除账本
const deleteAccountBook = async (id: string, name: string) => {try {await ElMessageBox.confirm(`确定要删除账本"${name}"吗?`, '确认删除', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'})const response = await axios.delete(import.meta.env.VITE_API_BASE_URL + `/api/AccountBook/Delete/${id}`, {headers: {'Authorization': localStorage.getItem('token')}})const result: Response<boolean> = response.dataif (result.statusCode === 200) {ElMessage.success('删除账本成功')await getAccountBooks()} else {ElMessage.error(result.errorMessage || '删除账本失败')}} catch (error) {if (error !== 'cancel') {console.error('删除账本失败:', error)ElMessage.error('删除账本失败')}}
}

删除操作会先弹出一个确认框,询问用户是否确定删除。如果用户点击“确定”,则通过 axios.delete/api/AccountBook/Delete/{id} 接口发送删除请求。成功后,显示“删除账本成功”的消息,并重新获取账本列表。

2.7 编辑账本

openEditDialogupdateAccountBook 函数用于编辑账本:

// 关闭创建对话框
const closeCreateDialog = () => {createDialogVisible.value = false// 重置表单验证状态createFormRef.value?.resetFields()
}// 打开编辑对话框
const openEditDialog = (book: AccountBook) => {editForm.value = {accountBookId: book.accountBookId,name: book.name,remarks: book.remarks || ''}editDialogVisible.value = true
}// 更新账本
const updateAccountBook = async () => {try {// 表单验证await editFormRef.value.validate()const response = await axios.put(import.meta.env.VITE_API_BASE_URL + '/api/AccountBook/Update',editForm.value, {headers: {'Authorization': localStorage.getItem('token')}})const result: Response<boolean> = response.dataif (result.statusCode === 200) {ElMessage.success('更新账本成功')editDialogVisible.value = false// 重新获取列表await getAccountBooks()} else {ElMessage.error(result.errorMessage || '更新账本失败')}} catch (error) {if (error !== 'cancel') {console.error('更新账本失败:', error)ElMessage.error('更新账本失败')}}
}// 关闭编辑对话框
const closeEditDialog = () => {editDialogVisible.value = false// 重置表单验证状态editFormRef.value?.resetFields()
}

openEditDialog 函数在点击编辑按钮时调用,它会将当前账本的数据填充到 editForm 中,并打开编辑弹窗。updateAccountBook 函数则负责提交编辑后的数据,同样会先进行表单验证,然后通过 axios.put/api/AccountBook/Update 接口发送请求。成功后,显示“更新账本成功”的消息,关闭编辑弹窗,并重新获取账本列表。

closeCreateDialogcloseEditDialog 分别用于关闭新建和编辑弹窗,并重置表单的验证状态。

2.8 生命周期钩子

最后,在组件挂载时,咱们会调用 getAccountBooks 函数来获取账本列表,确保页面加载时就能看到数据:

onMounted(() => {getAccountBooks()
})

三、页面结构 (<template>)

页面的HTML结构主要由以下几个部分组成:

<template><!--面包屑导航--><el-breadcrumb separator="/"><el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item><el-breadcrumb-item ><span style="font-weight: bold">账本</span></el-breadcrumb-item></el-breadcrumb><div class="account-book-page"><!-- 页面标题和操作按钮 --><div class="page-header"><p></p><el-button type="primary" @click="createDialogVisible = true" :icon="Plus">新建账本</el-button></div><!-- 账本列表 --><div class="account-book-list" v-loading="loading"><el-row :gutter="20"><el-colv-for="(book) in accountBooks":key="book.accountBookId":xs="24":sm="12":md="8":lg="6":xl="4"class="book-item-col"><div class="book-item"><div class="book-header"><div class="book-icon"><el-icon size="24"><Setting/></el-icon></div></div><div class="book-info"><h3 class="book-name">{{ book.name }}</h3><p class="book-description" v-if="book.remarks">{{ book.remarks }}</p><div class="book-meta"><span class="book-balance">{{ book.balance }}</span></div></div><div class="book-actions"><el-buttontype="primary"size="small"circle:icon="Edit"title="编辑"@click="openEditDialog(book)"/><el-buttontype="danger"size="small"circle:icon="Delete"title="删除"@click="deleteAccountBook(book.accountBookId, book.name)"/></div></div></el-col></el-row><!-- 空状态 --><div v-if="!loading && accountBooks.length === 0" class="empty-state"><el-empty description="暂无账本,点击上方按钮创建第一个账本"><el-button type="primary" @click="createDialogVisible = true">创建账本</el-button></el-empty></div></div><!-- 创建账本对话框 --><el-dialogv-model="createDialogVisible"title="新建账本"width="500px"center><el-form :model="createForm" label-width="80px" ref="createFormRef" :rules="formRules"><el-form-item label="账本名称" prop="name" required><el-input v-model="createForm.name" placeholder="请输入账本名称"/></el-form-item><el-form-item label="账本描述" prop="remarks"><el-inputv-model="createForm.remarks"type="textarea"placeholder="请输入账本描述(可选)":rows="3"/></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="closeCreateDialog">取消</el-button><el-button type="primary" @click="createAccountBook">确定</el-button></div></template></el-dialog><!-- 编辑账本对话框 --><el-dialogv-model="editDialogVisible"title="编辑账本"width="500px"center><el-form :model="editForm" label-width="80px" ref="editFormRef" :rules="formRules"><el-form-item label="账本名称" prop="name" required><el-input v-model="editForm.name" placeholder="请输入账本名称"/></el-form-item><el-form-item label="账本描述" prop="remarks"><el-inputv-model="editForm.remarks"type="textarea"placeholder="请输入账本描述(可选)":rows="3"/></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="closeEditDialog">取消</el-button><el-button type="primary" @click="updateAccountBook">确定</el-button></div></template></el-dialog></div>
</template>
  • 面包屑导航: 位于页面顶部,显示当前页面的路径,方便用户了解自己在应用中的位置。
  • 页面标题和操作按钮: 包含一个“新建账本”按钮,点击后会打开新建账本的弹窗。
  • 账本列表: 使用 el-rowel-col 布局,以卡片的形式展示每个账本。每个卡片包含账本名称、描述、余额以及编辑和删除按钮。当没有账本时,会显示一个空状态提示。
  • 创建账本对话框: 使用 el-dialog 实现,包含一个表单,用于输入账本名称和描述。表单数据双向绑定到 createForm,并应用了 formRules 进行验证。
  • 编辑账本对话框: 结构与创建账本对话框类似,用于编辑现有账本的信息,表单数据绑定到 editForm

四、样式 (<style scoped>)

最后,咱们来看看 <style scoped> 部分,这里定义了组件的样式,scoped 属性确保样式只作用于当前组件,避免样式冲突。

<style scoped>
.account-book-page {padding: 20px;
}.page-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 30px;
}/* ... 其他样式 ... */@media (max-width: 768px) {.page-header {flex-direction: column;gap: 16px;align-items: stretch;}.page-header h2 {text-align: center;}
}
</style>

样式部分主要定义了页面的布局、账本卡片的样式、按钮的样式等。值得一提的是,它还包含了响应式设计,通过 @media 查询,在小屏幕设备上调整了页面头部布局,确保在不同设备上都有良好的用户体验。

五、小结

AccountBook.vue 通过Vue 3的组合式API、Element Plus组件库以及前后端交互,实现了一个功能完善、用户友好的账本管理界面。从数据定义到API调用,再到UI渲染和交互,整个流程清晰流畅,充分体现了现代前端开发的最佳实践。希望通过这篇讲解,你能对 AccountBook.vue 的代码有更深入的理解!

http://www.lryc.cn/news/576686.html

相关文章:

  • Uni-App 小程序面试题高频问答汇总
  • 【Docker基础】Docker容器管理:docker top及其参数详解
  • Ubuntu 主机通过 `enp4s0` 向开发板共享网络的完整步骤
  • Flutter基础(控制器)
  • 广外计算机网络期末复习
  • 大模型之提示词工程入门——解锁与AI高效沟通的“钥匙”
  • WOE值:风险建模中的“证据权重”量化术——从似然比理论到FICO评分卡实践
  • python学习打卡day57
  • Python基础(吃洋葱小游戏)
  • 如何让ChatGPT模仿人类写作,降低AIGC率?
  • SpringBoot3.x整合Knife4j接口文档
  • cocos creator 3.8 - 精品源码 - 六边形消消乐(六边形叠叠乐、六边形堆叠战士)
  • 阿里 Qwen3 模型更新,吉卜力风格get
  • (五)神经网络
  • 【数据标注师】线标注
  • Linux软连接和硬连接
  • 复杂驱动开发-TLE9471的休眠流程与定时唤醒
  • 断路器、空气开关、漏电保护器
  • 【扩欧应用】同余方程
  • 概述-4-通用语法及分类
  • 领域驱动设计(DDD)【21】之值对象的优势
  • WebRTC(十二):DTLS
  • PowerBI 柱状图显示MoM销量环比示例,以及解决相同列值时设置柱子颜色的问题
  • 【转】PostgreSql的镜像地址
  • 一个简单测试Deepseek吞吐量的脚本,国内环境可跑
  • QTreeWidget 简单使用
  • web自动化测试常见函数
  • 西门子S7-200 SMART PLC:小型自动化领域的高效之选
  • 华为云鸿蒙应用入门级开发者认证 实验部分题目及操作步骤
  • 基于Uniapp+SpringBoot+Vue 的在线商城小程序