分享一套锋哥原创的基于Python的会员管理系统(带微信小程序会员端)(FastAPI+Vue3)优质版

📅 2026/7/12 23:10:52
分享一套锋哥原创的基于Python的会员管理系统(带微信小程序会员端)(FastAPI+Vue3)优质版
大家好我是Java1234_小锋老师分享一套锋哥原创的基于Python的会员管理系统(带微信小程序会员端)(FastAPIVue3)优质版项目介绍随着移动互联网与数字化运营的快速发展会员制已成为零售、餐饮、生活服务等行业提升客户黏性与复购率的重要手段。传统依赖纸质会员卡或分散表格登记的管理模式存在信息滞后、统计困难、等级折扣难以自动执行、会员端触达不便等问题。因此设计并实现一套前后端分离、移动端可访问的会员管理系统对中小型商户实现精细化运营具有现实意义。本文设计并实现了“基于Python的会员管理系统带微信小程序端”。系统采用B/S架构与前后端分离思想后端基于Python语言与FastAPI框架构建RESTful接口使用SQLAlchemy操作MySQL数据库库名db_member并结合JWT完成管理员与会员双端身份认证管理后台基于Vue3、Vue Router、Pinia与Element Plus实现首页集成ECharts数据统计图表微信小程序端面向会员用户提供用户名密码登录、注册、公告浏览、资产查看、头像与个人资料修改、密码修改等功能。业务上覆盖会员档案、会员等级与折扣、商品管理、充值、消费、积分获取与兑换、公告发布以及管理员与角色管理等核心场景并实现消费折扣计算、余额扣减、积分累计与自动升级等关键业务闭环。系统经过功能测试验证各模块运行稳定接口响应正常能够满足本科毕业设计对完整性、规范性与实用性的要求。实践表明Python与FastAPI适合快速构建高可读性的后端服务Vue3适合构建交互友好的管理端微信小程序则能有效降低会员使用门槛。论文同时给出了E-R图、功能结构图、时序图与数据表字段设计并对关键功能附核心代码说明便于复现与二次开发。源码下载链接: https://pan.baidu.com/s/1hbcKeOPblLjWPn4royqf3A?pwd1234提取码: 1234系统展示核心代码 消费业务服务 对齐 Java ConsumeServiceImpl.doConsume from decimal import Decimal, ROUND_DOWN, ROUND_HALF_UP from sqlalchemy.orm import Session from app.common.exception import BusinessException from app.models.consume import Consume from app.models.member import Member from app.models.member_level import MemberLevel from app.models.points_record import PointsRecord from app.models.product import Product class ConsumeService: 消费服务类 staticmethod def do_consume(db: Session, consume: Consume) - None: 执行会员消费按等级折扣扣费、扣库存、增加积分并记录 :param db: 数据库会话 :param consume: 消费信息 member ( db.query(Member) .filter(Member.id consume.member_id, Member.deleted 0) .first() ) if member is None: raise BusinessException(会员不存在) if member.status is not None and member.status 0: raise BusinessException(会员已冻结无法消费) amount consume.amount # 若选择了商品以商品价格为准并扣库存 if consume.product_id is not None: product ( db.query(Product) .filter(Product.id consume.product_id, Product.deleted 0) .first() ) if product is None: raise BusinessException(商品不存在) if product.status is not None and product.status 0: raise BusinessException(商品已下架) if product.stock is not None and product.stock 0: raise BusinessException(商品库存不足) amount product.price product.stock product.stock - 1 db.add(product) if amount is None or amount 0: raise BusinessException(消费金额必须大于0) # 按会员等级计算折扣 discount Decimal(1) if member.level_id is not None: level ( db.query(MemberLevel) .filter(MemberLevel.id member.level_id, MemberLevel.deleted 0) .first() ) if level is not None and level.discount is not None: discount Decimal(str(level.discount)) real_amount (amount * discount).quantize(Decimal(0.01), roundingROUND_HALF_UP) balance member.balance if member.balance is not None else Decimal(0) if balance real_amount: raise BusinessException(会员余额不足) new_balance balance - real_amount points_gained int(real_amount.to_integral_value(roundingROUND_DOWN)) current_points member.points if member.points is not None else 0 new_points current_points points_gained member.balance new_balance member.points new_points ConsumeService._upgrade_level(db, member, new_points) db.add(member) consume.amount amount consume.real_amount real_amount consume.points_gained points_gained consume.balance_after new_balance consume.deleted 0 db.add(consume) # 记录积分获取 if points_gained 0: record PointsRecord( member_idmember.id, change_pointspoints_gained, type获取, remark消费获得积分, deleted0, ) db.add(record) db.commit() staticmethod def _upgrade_level(db: Session, member: Member, new_points: int) - None: 根据积分自动升级会员等级 :param db: 数据库会话 :param member: 会员 :param new_points: 最新积分 levels ( db.query(MemberLevel) .filter(MemberLevel.deleted 0) .order_by(MemberLevel.upgrade_points.desc()) .all() ) for level in levels: if level.upgrade_points is not None and new_points level.upgrade_points: member.level_id level.id breaktemplate div classpage-card div classsearch-bar el-select v-modelquery.memberId placeholder选择会员 clearable filterable stylewidth: 200px el-option v-form in members :keym.id :label${m.name}(${m.cardNo}) :valuem.id / /el-select el-button typeprimary clickloadDatael-iconSearch //el-icon查询/el-button el-button clickquery.memberIdnull; query.pageNum1; loadData()el-iconRefresh //el-icon重置/el-button /div div classtoolbar el-button typeprimary clickopenDialog()el-iconPlus //el-icon会员消费/el-button /div el-table :datatableData stripe border stylewidth: 100% el-table-column propcardNo label会员卡号 min-width120 / el-table-column propmemberName label会员姓名 min-width100 / el-table-column propproductName label商品 min-width120 / el-table-column propamount label原价 min-width90 / el-table-column proprealAmount label实付 min-width90 / el-table-column proppointsGained label获得积分 min-width90 / el-table-column propbalanceAfter label消费后余额 min-width110 / el-table-column propoperator label操作人 min-width90 / el-table-column propcreateTime label消费时间 min-width160 / el-table-column label操作 min-width90 fixedright template #default{ row } el-button typedanger link clickhandleDelete(row)删除/el-button /template /el-table-column /el-table div classpagination-wrap el-pagination v-model:current-pagequery.pageNum v-model:page-sizequery.pageSize :totaltotal :page-sizes[10,20,50] layouttotal, sizes, prev, pager, next size-changeloadData current-changeloadData / /div el-dialog v-modeldialogVisible title会员消费 width480px destroy-on-close el-form refformRef :modelform :rulesrules label-width90px el-form-item label会员 propmemberId el-select v-modelform.memberId filterable placeholder请选择会员 stylewidth: 100% el-option v-form in members :keym.id :label${m.name}(${m.cardNo}) 余额:${m.balance} :valuem.id / /el-select /el-form-item el-form-item label商品 propproductId el-select v-modelform.productId filterable placeholder请选择商品 stylewidth: 100% el-option v-forp in products :keyp.id :label${p.productName} ¥${p.price} :valuep.id / /el-select /el-form-item el-form-item label备注 el-input v-modelform.remark / /el-form-item /el-form template #footer el-button clickdialogVisible false取消/el-button el-button typeprimary :loadingsaving clickhandleSave确认消费/el-button /template /el-dialog /div /template script setup /** * 消费管理页面 */ import { ref, reactive, onMounted } from vue import { ElMessage, ElMessageBox } from element-plus import request from /utils/request const tableData ref([]) const members ref([]) const products ref([]) const total ref(0) const dialogVisible ref(false) const saving ref(false) const formRef ref() const query reactive({ pageNum: 1, pageSize: 10, memberId: null }) const form reactive({ memberId: null, productId: null, remark: }) const rules { memberId: [{ required: true, message: 请选择会员, trigger: change }], productId: [{ required: true, message: 请选择商品, trigger: change }] } async function loadData() { const res await request.get(/api/consume/list, { params: query }) tableData.value res.data.records total.value res.data.total } async function loadOptions() { const [m, p] await Promise.all([ request.get(/api/member/all), request.get(/api/product/all) ]) members.value m.data products.value p.data } function openDialog() { Object.assign(form, { memberId: null, productId: null, remark: }) dialogVisible.value true } async function handleSave() { await formRef.value.validate() saving.value true try { await request.post(/api/consume, form) ElMessage.success(消费成功) dialogVisible.value false loadData() loadOptions() } finally { saving.value false } } function handleDelete(row) { ElMessageBox.confirm(确定删除该消费记录吗, 提示, { type: warning }).then(async () { await request.delete(/api/consume/${row.id}) ElMessage.success(删除成功) loadData() }).catch(() {}) } onMounted(() { loadOptions(); loadData() }) /script