后台管理系统-月卡管理

news/2025/2/21 10:36:44/

功能说明并准备静态结构

javascript"><template><div class="card-container"><!-- 搜索区域 --><div class="search-container"><span class="search-label">车牌号码:</span><el-input clearable placeholder="请输入内容" class="search-main" /><span class="search-label">车主姓名:</span><el-input clearable placeholder="请输入内容" class="search-main" /><span class="search-label">状态:</span><el-select><el-option v-for="item in []" :key="item.id" /></el-select><el-button type="primary" class="search-btn">查询</el-button></div><!-- 新增删除操作区域 --><div class="create-container"><div><el-button type="primary">添加月卡</el-button><el-button>批量删除</el-button></div><div class="tip"><i class="el-icon-info"></i><span>本园区共计 1486 个车位,月卡用户 0 人,车位占有率 0.00%</span></div></div><!-- 表格区域 --><div class="table"><el-table style="width: 100%" :data="[]"><el-table-column type="index" label="序号" /><el-table-column label="车主名称" /><el-table-column label="联系方式" /><el-table-column label="车牌号码" /><el-table-column label="车辆品牌" /><el-table-column label="剩余有效天数" /><el-table-column label="操作" fixed="right" width="180"><template #default="scope"><el-button size="mini" type="text">续费</el-button><el-button size="mini" type="text">查看</el-button><el-button size="mini" type="text">编辑</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></div><div class="page-container"><el-pagination layout="total, prev, pager, next" :total="0" /></div><!-- 添加楼宇 --><el-dialog title="添加楼宇" width="580px"><!-- 表单接口 --><div class="form-container"><!-- <el-form ref="addForm" :model="addForm" :rules="addFormRules"><el-form-item label="楼宇名称" prop="name"><el-input v-model="addForm.name" /></el-form-item><el-form-item label="楼宇层数" prop="floors"><el-input v-model="addForm.floors" /></el-form-item><el-form-item label="在管面积" prop="area"><el-input v-model="addForm.area" /></el-form-item><el-form-item label="物业费" prop="propertyFeePrice"><el-input v-model="addForm.propertyFeePrice" /></el-form-item></el-form> --></div><template #footer><el-button size="mini">取 消</el-button><el-button size="mini" type="primary">确 定</el-button></template></el-dialog></div>
</template><script>
export default {};
</script><style lang="scss" scoped>
.card-container {padding: 20px;background-color: #fff;
}.search-container {display: flex;align-items: center;border-bottom: 1px solid rgb(237, 237, 237, 0.9);padding-bottom: 20px;.search-main {width: 220px;margin-right: 10px;}.search-btn {margin-left: 20px;}
}
.create-container {display: flex;justify-content: space-between;margin: 10px 0px;.tip {background: #e6f7ff;height: 39px;width: 427px;border: 1px solid #0094ff;border-radius: 3px;line-height: 39px;padding-left: 15px;i {color: #0094ff;margin-right: 10px;}span {font-size: 13px;}}
}
.page-container {padding: 4px 0px;text-align: right;
}
.form-container {padding: 0px 80px;
}
</style>

渲染基础Table列表

实现思路分析

代码实现

1- 接口封装

import request from '@/utils/request'/*** 获取楼宇列表* @param { page, pageSize} params* @returns*/
export function getCardListAPI(params) {return request({url: '/parking/card/list',params})
}

2- 代码实现

<script>import { getCardListAPI } from '@/apis/card'export default {data() {return {// 请求参数params: {page: 1,pageSize: 10},// 月卡列表cardList: []}},mounted() {this.getCardList()},methods: {async getCardList() {const res = await getCardListAPI(this.params)this.cardList = res.data.rows}}}
</script<template><el-table style="width: 100%" :data="cardList"><el-table-column type="index" label="序号" /><el-table-column label="车主名称" prop="personName" /><el-table-column label="联系方式" prop="phoneNumber" /><el-table-column label="车牌号码" prop="carNumber" /><el-table-column label="车辆品牌" prop="carBrand" /><el-table-column label="剩余有效天数" prop="totalEffectiveDate" /><el-table-column label="操作" fixed="right" width="180"><template #default="scope"><el-button size="mini" type="text">续费</el-button><el-button size="mini" type="text">查看</el-button><el-button size="mini" type="text">编辑</el-button><el-button size="mini" type="text">删除</el-button></template></el-table-column></el-table></template>

适配状态显示

<el-table-column label="状态" prop="cardStatus" :formatter="formatStatus" />formatStatus(row) {const MAP = {0: '可用',1: '已过期'}return MAP[row.cardStatus]
}

分页功能实现

分出页数

分页公式:页数 = 总条数 / 每页条数

<el-paginationlayout="total, prev, pager, next":page-size="params.pageSize":total="total"
/><script>
import { getCardListAPI } from '@/apis/card'
export default {data() {return {// 请求参数params: {page: 1,pageSize: 2},total: 0,// 月卡列表cardList: []}},mounted() {this.getCardList()},methods: {async getCardList() {const res = await getCardListAPI(this.params)this.cardList = res.data.rowsthis.total = res.data.total}}
}
</script>

实现点击切换

实现步骤:

  1. 拿到当前点击了第几页
  1. 使用当前点击的页数去和后端要数据
<el-paginationlayout="total, prev, pager, next":page-size="params.pageSize":total="total"@current-change="pageChange"
/>methods: {async getCardList() {const res = await getCardListAPI(this.params)this.cardList = res.data.rowsthis.total = res.data.total},pageChange(page) {// 把点击的页数赋值给请求参数页数this.params.page = page// 使用最新的请求参数获取列表数据this.getCardList()}
}

搜索功能实现

收集查询字段数据

<!-- 搜索区域 -->
<div class="search-container"><span class="search-label">车牌号码:</span><el-input v-model="params.carNumber" clearable placeholder="请输入内容" class="search-main" /><span class="search-label">车主姓名:</span><el-input v-model="params.personName" clearable placeholder="请输入内容" class="search-main" /><span class="search-label">状态:</span><el-select v-model="params.cardStatus"><el-optionv-for="item in cardStatusList":key="item.id":value="item.id":label="item.name"/></el-select><el-button type="primary" class="search-btn" @click="doSearch">查询</el-button></divdata() {return {// 请求参数params: {page: 1,pageSize: 5,carNumber: null,personName: null,cardStatus: null},// 月卡状态cardStatusList: [{id: null,name: '全部'},{id: 0,name: '可用'},{id: 1,name: '已过期'}]}}

调用接口获取数据

doSearch() {// 调用接口之前把页数参数重置为1this.params.page = 1this.getCardList()
}<el-button type="primary" class="search-btn" @click="doSearch">查询</el-button>

新增月卡实现

配置路由完成跳转

<template><div class="add-card"><header class="add-header"><el-page-header content="增加月卡" @back="$router.back()" /></header><main class="add-main"><div class="form-container"><div class="title">车辆信息</div><div class="form"><el-form label-width="100px"><el-form-item label="车主姓名"><el-input /></el-form-item><el-form-item label="联系方式"><el-input /></el-form-item><el-form-item label="车辆号码"><el-input /></el-form-item><el-form-item label="企业联系人"><el-input /></el-form-item></el-form></div></div><div class="form-container"><div class="title">最新一次月卡缴费信息</div><div class="form"><el-form label-width="100px"><el-form-item label="有效日期"><el-input /></el-form-item><el-form-item label="支付金额"><el-input /></el-form-item><el-form-item label="支付方式"><el-select><el-optionv-for="item in [{}]":key="item.industryCode":value="item.industryCode":label="item.industryName"/></el-select></el-form-item></el-form></div></div></main><footer class="add-footer"><div class="btn-container"><el-button>重置</el-button><el-button type="primary">确定</el-button></div></footer></div></template><script>
export default {}
</script><style scoped lang="scss">
.add-card {background-color: #f4f6f8;height: 100vh;.add-header {display: flex;align-items: center;padding: 0 20px;height: 64px;background-color: #fff;.left {span {margin-right: 4px;}.arrow{cursor: pointer;}}.right {text-align: right;}}.add-main {background: #f4f6f8;padding: 20px 130px;.form-container {background-color: #fff;.title {height: 60px;line-height: 60px;padding-left: 20px;}.form {margin-bottom: 20px;padding: 20px 65px 24px;.el-form {display: flex;flex-wrap: wrap;.el-form-item {width: 50%;}}}}.preview{img{width: 100px;}}}.add-footer {position: fixed;bottom: 0;width: 100%;padding: 24px 50px;color: #000000d9;font-size: 14px;background: #fff;text-align: center;}
}
</style>
// 添加一级路由
{path: '/cardAdd',component: () => import('@/views/car/car-card/cardAdd'),hidden:true
}
<el-button type="primary" @click="$router.push('/cardAdd')">添加月卡</el-button>

车辆信息表单验证

其它项做非空校验,车辆号码既做非空校验,也做正则校验

<el-form :model="carInfoForm" :rules="carInfoRules" label-width="100px"><el-form-item label="车主姓名" prop="personName"><el-input v-model="carInfoForm.personName" /></el-form-item><el-form-item label="联系方式" prop="phoneNumber"><el-input v-model="carInfoForm.phoneNumber" /></el-form-item><el-form-item label="车辆号码" prop="carNumber"><el-input v-model="carInfoForm.carNumber" /></el-form-item><el-form-item label="车辆品牌" prop="carBrand"><el-input v-model="carInfoForm.carBrand" /></el-form-item></el-form>data() {return {// 车辆信息表单carInfoForm: {personName: '', // 车主姓名phoneNumber: '', // 联系方式carNumber: '', // 车牌号码carBrand: '' // 车辆品牌},carInfoRules: {personName: [{required: true, message: '请输入车主姓名', trigger: 'blur'}],phoneNumber: [{required: true, message: '请输入联系方式', trigger: 'blur'}],carNumber: [{required: true, message: '请输入车辆号码', trigger: 'blur'}],carBrand: [{required: true, message: '请输入车辆品牌', trigger: 'blur'}]}}}

车牌号单独校验

较复杂的校验可以通过设置一个校验函数来做,给校验选项添加一个validator选项,值为校验函数,在校验函数中编写校验规则

 data() {const validaeCarNumber = (rule, value, callback) => {const plateNumberRegex = /^[\u4E00-\u9FA5][\da-zA-Z]{6}$/if (plateNumberRegex.test(value)) {callback()} else {callback(new Error('请输入正确的车牌号'))}}return {carInfoRules: {carNumber: [{required: true, message: '请输入车辆号码', trigger: 'blur'},{validator: validaeCarNumber, trigger: 'blur'}]}}}

缴费信息表单校验

<el-form :model="feeForm" :rules="feeFormRules" label-width="100px"><el-form-item label="有效日期" prop="payTime"><el-date-pickerv-model="feeForm.payTime"type="daterange"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"/></el-form-item><el-form-item label="支付金额" prop="paymentAmount"><el-input v-model="feeForm.paymentAmount" /></el-form-item><el-form-item label="支付方式" prop="paymentMethod"><el-select v-model="feeForm.paymentMethod"><el-optionv-for="item in payMethodList":key="item.id":value="item.id":label="item.name"/></el-select></el-form-item></el-form>data() {return {// 缴费信息表单feeForm: {payTime: '', // 支付时间paymentAmount: null, // 支付金额paymentMethod: '' // 支付方式},// 缴费规则feeFormRules: {payTime: [{required: true,message: '请选择支付时间'}],paymentAmount: [{required: true,message: '请输入支付金额',trigger: 'blur'}],paymentMethod: [{required: true,message: '请选择支付方式',trigger: 'change'}]},// 支付方式列表payMethodList: [{id: 'Alipay',name: '支付宝'},{id: 'WeChat',name: '微信'},{id: 'Cash',name: '线下'}]}}

统一校验俩个表单

校验方式:表单校验采用串行校验,也就是第一个表单校验通过之后再进行第二个校验

<el-form ref="carInfoForm"></el-form><el-form ref="feeForm"></el-form>methods: {confirmAdd() {this.$refs.carInfoForm.validate(valid => {if (valid) {this.$refs.feeForm.validate(valid => {if (valid) {// 全部校验通过// TODO 确定}})}})}
}

收集表单确认提交


1-封装接口

/*** 新增月卡* @data* @returns*/
export function createCardAPI(data) {return request({url: '/parking/card',method: 'POST',data})
}

2-处理表单数据提交

methods: {confirmAdd() {this.$refs.carInfoForm.validate(valid => {if (valid) {this.$refs.feeForm.validate(valid => {if (valid) {// 全部校验通过// TODO 确定// 参数处理const payload = {...this.feeForm,...this.carInfoForm,// 单独处理时间cardStartDate: this.feeForm.payTime[0],cardEndDate: this.feeForm.payTime[1]}// 删掉多余字段delete payload.payTimeawait createCardAPI(payload)this.$router.back()}})}})}
}

重置表单

重置表单主要做两件事

  1. 清空输入数据
  1. 清空校验错误
// 重置表单
resetForm() {this.$refs.feeForm.resetFields()this.$refs.carInfoForm.resetFields()
}

编辑月卡

编辑功能的通用实现流程

携带id跳转并缓存id

<el-button size="mini" type="text" @click="editCard(scope.row.id)">编辑</el-button>editCard(id) {this.$router.push({path: '/cardAdd',query: {id}})
}

回填数据

1- 封装接口

/*** 获取月卡详情* @data* @returns*/
export function getCardDetailAPI(id) {return request({url: `/parking/card/detail/${id}`})
}

2-根据id获取详情

// 获取详情
async getDetail() {const res = await getCardDetailAPI(this.id)// 回填车辆信息表单const { carInfoId, personName, phoneNumber, carNumber, carBrand } = res.datathis.carInfoForm = {personName, phoneNumber, carNumber, carBrand, carInfoId}// 回填缴费信息表单const { rechargeId, cardStartDate, cardEndDate, paymentAmount, paymentMethod } = res.datathis.feeForm = {rechargeId,paymentAmount,paymentMethod,payTime: [cardStartDate, cardEndDate]}
}mounted() {if (this.id) {this.getDetail()}
}

根据id做接口适配

封装编辑接口


/*** 新增月卡* @data* @returns*/
export function updateCardAPI(data) {return request({url: 'parking/card/edit',method: 'PUT',data})
}
methods: {confirmAdd() {this.$refs.carInfoForm.validate(valid => {if (valid) {this.$refs.feeForm.validate(async valid => {if (valid) {// 全部校验通过// TODO 确定// 参数处理const payload = {...this.feeForm,...this.carInfoForm,cardStartDate: this.feeForm.payTime[0],cardEndDate: this.feeForm.payTime[1]}delete payload.payTimeif (this.id) {// 编辑await updateCardAPI(payload)} else {// 新增await createCardAPI(payload)}this.$router.back()}})}})}
}

删除功能实现

/*** 删除月卡* @param {*} id* @returns*/
export function delCardAPI(id) {return request({url: `/parking/card/${id}`,method: 'DELETE'})
}

// 绑定事件
<el-button size="mini" type="text" @click="delCard(scope.row.id)">删除</el-button>// 导入接口
import { delCardAPI } from '@/apis/card'// 删除逻辑
delCard(id) {this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {await delCardAPI(id)this.getCardList()this.$message({type: 'success',message: '删除成功!'})}).catch((error) => {console.log(error)})
}

批量删除

收集用户选择行

<el-table style="width: 100%" :data="cardList" @selection-change="handleSelectionChange"><el-table-columntype="selection"width="55"/><!-- 省略 -->
</el-table>data() {return {// 已选择列表selectedCarList: []}
}methods:{handleSelectionChange(rowList) {console.log(rowList)this.selectedCarList = rowList}
}

处理数据调用接口

/*** 删除月卡* @param {*} id* @returns*/
export function delCardListAPI(idList) {return request({url: `/parking/card/${idList.join(',')}`,method: 'DELETE'})
}delCartList() {this.$confirm('此操作将永久删除选择的月卡, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {// 处理idawait delCardListAPI(this.selectedCarList.map(item => item.id))this.getCardList()this.$message({type: 'success',message: '删除成功!'})}).catch((error) => {console.log(error)})
}

http://www.ppmy.cn/news/1573858.html

相关文章

GCC头文件搜索顺序详解

在C/C编程中&#xff0c;合理管理头文件的引入路径对于项目的组织至关重要。GCC编译器提供了灵活的机制来指定头文件的搜索路径&#xff0c;这主要通过#include "…"和#include <…>两种形式实现。本文将详细介绍这两种形式的区别以及如何使用-I参数优化头文件…

代理和NAT多路转接

1.NAT技术背景 在IPv4协议中存在IP地址数量不充足的问题&#xff0c; NAT技术当前解决IP地址不够用的主要手段, 是路由器的一个重要功能。 NAT能够将私有IP对外通信时转为全局IP. 也就是就是一种将私有IP和全局IP相互转化的技术方法: 很多学校, 家庭, 公司内部采用每个终端设…

嵌入式0xDEADBEEF

在嵌入式系统中&#xff0c;0xDEADBEEF 是一个常见的“魔数”&#xff08;magic number&#xff09;&#xff0c;通常用于调试和内存管理。它的含义和用途如下&#xff1a; 1. 调试用途 未初始化内存的标记&#xff1a;在调试时&#xff0c;0xDEADBEEF 常用于标记未初始化或已…

解决 WSL Ubuntu 中 /etc/resolv.conf 自动重置问题

解决 WSL Ubuntu 中 /etc/resolv.conf 自动重置问题 前言问题描述问题原因尝试过的命令及分析解决方案&#xff1a;修改 wsl.conf 禁用自动生成总结 前言 在使用 Windows Subsystem for Linux (WSL) 的 Ubuntu 子系统时&#xff0c;你可能会遇到 /etc/resolv.conf 文件被自动重…

Postman配置环境变量(超详细的)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Postman是一套比较方便的接口测试工具&#xff0c;但我们在使用过程中&#xff0c;可能会出现创建了API请求&#xff0c;但API的URL会随着服务器IP地址的变化而改…

Python 实现反转、合并链表有啥用?

大家好&#xff0c;我是 V 哥。使用 Python 实现反转链表、合并链表在开发中比较常见&#xff0c;我们先来看看各自的应用场景。先赞再看后评论&#xff0c;腰缠万贯财进门。 2024博客之星年度总评选&#xff0c;感谢给 V 哥投上宝贵的一票 反转链表 比如&#xff0c;在处理…

跳表(Skip List)详解

一、什么是跳表&#xff1f; 跳表是一种基于有序链表的高效数据结构&#xff0c;通过建立多级索引实现快速查询。它在平均情况下支持O(log n)时间复杂度的搜索、插入和删除操作&#xff0c;性能接近平衡树&#xff0c;但实现更为简单。 二、核心原理 1. 层级结构 底层为完整…

JavaScript设计模式 -- 状态模式

在软件开发中&#xff0c;很多对象的行为会随着其内部状态的变化而改变。如果将所有状态逻辑写在一个类中&#xff0c;代码不仅臃肿而且难以维护。**状态模式&#xff08;State Pattern&#xff09;**正是为了解决这个问题而设计的。通过将对象的状态封装成独立的状态类&#x…