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')
这里 ref
和 onMounted
是Vue 3的API,用于创建响应式数据和处理组件挂载生命周期。inject('axios')
则是从全局注入 axios
实例,方便咱们进行HTTP请求。AccountBook
、CreateAccountBookRequest
、UpdateAccountBookRequest
和 Response
都是咱们自定义的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
则表示数据是否正在加载中。createDialogVisible
和 editDialogVisible
控制新建和编辑账本的弹窗显示与隐藏。createForm
和 editForm
分别绑定了新建和编辑账本表单的数据,它们都是 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
定义了 name
和 remarks
字段的验证规则,比如 name
是必填项,且最大长度为20个字符。createFormRef
和 editFormRef
则是对表单组件的引用,方便咱们在提交表单时调用 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 编辑账本
openEditDialog
和 updateAccountBook
函数用于编辑账本:
// 关闭创建对话框
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
接口发送请求。成功后,显示“更新账本成功”的消息,关闭编辑弹窗,并重新获取账本列表。
closeCreateDialog
和 closeEditDialog
分别用于关闭新建和编辑弹窗,并重置表单的验证状态。
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-row
和el-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
的代码有更深入的理解!