news 2026/8/15 22:39:41

【免费】基于Python的微信小程序共享单车系统(FastAPI+Vue3) 锋哥原创出品,必属精品

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【免费】基于Python的微信小程序共享单车系统(FastAPI+Vue3) 锋哥原创出品,必属精品

大家好,我是Java1234_小锋老师,分享一套锋哥原创的基于Python的微信小程序共享单车系统(FastAPI+Vue3) 。

项目介绍

共享单车作为城市绿色出行的重要组成部分,能够有效衔接公交、地铁等大运量公共交通,缓解短距离出行不便和道路拥堵问题。传统共享单车平台功能集中、接口封闭,难以直接作为高校实践教学和中小规模运营场景的完整解决方案。针对这一现状,本文设计并实现了一套面向实际业务闭环的微信小程序共享单车系统。

系统采用前后端分离的三层架构。用户端基于微信小程序开发,提供地图找车、扫码解锁、骑行计时、规范还车、余额充值、押金管理、骑行卡购买、订单查询、故障报修、骑行评价以及个人资料与密码维护等功能;管理端基于 Vue3、Vite 与 Element Plus 构建,实现用户与车辆管理、停车点维护、计费规则与骑行卡配置、订单与资金流水查询、故障处理、公告发布以及带统计图表的运营首页;服务端采用 Python 语言和 FastAPI 框架,结合 SQLAlchemy 2.x 与 MySQL 8 完成数据持久化,使用 JWT 实现管理员与普通用户的身份鉴别。

数据库设计遵循第三范式,建立 db_bike 库及 t_admin、t_user、t_bike、t_ride_order 等 12 张业务表。骑行计费采用“起步价 + 超时按分钟计费 + 单次上限”模型,并结合 Haversine 公式估算里程;支付环节支持余额支付、骑行卡抵扣和模拟微信支付。测试表明,系统主要业务流程运行稳定,接口响应及时,能够满足毕业设计对完整性、规范性与可演示性的要求,对同类校园或社区共享出行系统具有参考价值。

源码下载

链接: https://pan.baidu.com/s/1X2m0WnWBA8Vfoa4IzfehlQ?pwd=1234
提取码: 1234

系统展示

核心代码

""" 骑行卡服务 """ from sqlalchemy.orm import Session from app.exceptions import BusinessException from app.models import RideCard def page_list(db: Session, current: int, size: int, keyword: str = None): """分页查询骑行卡""" query = db.query(RideCard) if keyword: query = query.filter(RideCard.name.like(f"%{keyword}%")) total = query.count() records = ( query.order_by(RideCard.create_time.desc()) .offset((current - 1) * size) .limit(size) .all() ) return records, total def save_card(db: Session, data: dict) -> None: """保存骑行卡""" card_id = data.get("id") if card_id: card = db.query(RideCard).filter(RideCard.id == card_id).first() if not card: raise BusinessException("骑行卡不存在") for key, val in data.items(): if key != "id" and val is not None: setattr(card, key, val) else: card = RideCard( name=data["name"], card_type=data["card_type"], valid_days=data.get("valid_days", 30), total_times=data.get("total_times"), free_minutes=data.get("free_minutes", 30), price=data["price"], description=data.get("description"), status=data.get("status", 1), ) db.add(card) db.commit() def delete_card(db: Session, card_id: int) -> None: """删除骑行卡""" card = db.query(RideCard).filter(RideCard.id == card_id).first() if card: db.delete(card) db.commit() def list_active(db: Session): """查询上架骑行卡""" return ( db.query(RideCard) .filter(RideCard.status == 1) .order_by(RideCard.price.asc()) .all() )
<template> <div class="page-container"> <div class="search-bar"> <el-select v-model="query.status" placeholder="处理状态" clearable> <el-option v-for="(item, key) in faultStatusMap" :key="key" :label="item.label" :value="Number(key)" /> </el-select> <el-button type="primary" @click="loadData"><el-icon><Search /></el-icon> 搜索</el-button> </div> <div class="table-card"> <el-table :data="tableData" v-loading="loading" stripe border> <el-table-column prop="id" label="ID" min-width="70" /> <el-table-column prop="userId" label="用户ID" min-width="80" /> <el-table-column prop="bikeId" label="单车ID" min-width="80" /> <el-table-column prop="faultType" label="故障类型" min-width="120" /> <el-table-column prop="description" label="描述" min-width="180" show-overflow-tooltip /> <el-table-column label="状态" min-width="90"> <template #default="{ row }"> <el-tag :type="faultStatusMap[row.status]?.type" size="small"> {{ faultStatusMap[row.status]?.label }} </el-tag> </template> </el-table-column> <el-table-column label="报修时间" min-width="170"> <template #default="{ row }">{{ formatDateTime(row.createTime) }}</template> </el-table-column> <el-table-column label="操作" min-width="120" fixed="right"> <template #default="{ row }"> <el-button v-if="row.status !== 2" type="primary" link @click="openHandle(row)">处理</el-button> <el-button type="info" link @click="showDetail(row)">详情</el-button> </template> </el-table-column> </el-table> <div class="pagination-wrap"> <el-pagination v-model:current-page="query.current" v-model:page-size="query.size" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" background @size-change="loadData" @current-change="loadData" /> </div> </div> <!-- 处理弹窗 --> <el-dialog v-model="handleVisible" title="故障处理" width="520px" destroy-on-close> <el-form ref="formRef" :model="handleForm" label-width="100px"> <el-form-item label="处理状态"> <el-radio-group v-model="handleForm.status"> <el-radio :value="1">处理中</el-radio> <el-radio :value="2">已处理</el-radio> </el-radio-group> </el-form-item> <el-form-item label="回复内容"> <el-input v-model="handleForm.reply" type="textarea" :rows="4" placeholder="请输入处理回复" /> </el-form-item> </el-form> <template #footer> <el-button @click="handleVisible = false">取消</el-button> <el-button type="primary" :loading="submitLoading" @click="submitHandle">确定</el-button> </template> </el-dialog> <!-- 详情弹窗 --> <el-dialog v-model="detailVisible" title="故障详情" width="560px" destroy-on-close> <el-descriptions :column="1" border v-if="detailRow"> <el-descriptions-item label="故障类型">{{ detailRow.faultType }}</el-descriptions-item> <el-descriptions-item label="描述">{{ detailRow.description }}</el-descriptions-item> <el-descriptions-item label="图片"> <div v-if="detailRow.images" class="image-list"> <el-image v-for="(img, idx) in detailRow.images.split(',')" :key="idx" :src="img" :preview-src-list="detailRow.images.split(',')" fit="cover" style="width: 80px; height: 80px; margin-right: 8px; border-radius: 6px" /> </div> <span v-else>-</span> </el-descriptions-item> <el-descriptions-item label="回复">{{ detailRow.reply || '-' }}</el-descriptions-item> <el-descriptions-item label="处理时间">{{ formatDateTime(detailRow.handleTime) }}</el-descriptions-item> </el-descriptions> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted } from 'vue' import { ElMessage } from 'element-plus' import request from '@/utils/request' import { formatDateTime, faultStatusMap } from '@/utils/date' /** * 故障报修管理页面 */ const loading = ref(false) const submitLoading = ref(false) const handleVisible = ref(false) const detailVisible = ref(false) const detailRow = ref(null) const tableData = ref([]) const total = ref(0) const query = reactive({ current: 1, size: 10, status: null }) const handleForm = reactive({ id: null, status: 2, reply: '' }) async function loadData() { loading.value = true try { const res = await request.get('/admin/fault/page', { params: query }) tableData.value = res.data.records total.value = res.data.total } finally { loading.value = false } } /** 打开处理弹窗 */ function openHandle(row) { handleForm.id = row.id handleForm.status = row.status === 0 ? 1 : 2 handleForm.reply = row.reply || '' handleVisible.value = true } /** 提交处理 */ async function submitHandle() { submitLoading.value = true try { await request.put(`/admin/fault/handle/${handleForm.id}`, null, { params: { status: handleForm.status, reply: handleForm.reply } }) ElMessage.success('处理成功') handleVisible.value = false loadData() } finally { submitLoading.value = false } } /** 查看详情 */ function showDetail(row) { detailRow.value = row detailVisible.value = true } onMounted(() => loadData()) </script> <style scoped> .image-list { display: flex; flex-wrap: wrap; gap: 8px; } </style>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/15 22:30:08

MySQL、Oracle、SQL Server查询当前时间函数全解析与跨数据库实践

1. 项目概述&#xff1a;为什么需要关注“查询当前时间”&#xff1f;在数据库开发和运维的日常工作中&#xff0c;“查询当前时间”这个操作看似简单&#xff0c;却是一个高频且基础到容易被忽视的环节。无论是记录操作日志、为数据行打上时间戳、进行基于时间的业务逻辑判断&…

作者头像 李华
网站建设 2026/8/15 22:27:38

智驾车载以太网(9)-davinci之phy

文档摘要:本文档将简单介绍一下什么是Phy,Phy的基本配置,autosar cp中当MCU连接PHY芯片或者switch交换机时如何配置,同时举例一下开发过程遇到的问题以及解决方案。 Phy介绍 以太网Phy是一个独立的芯片,它的主要作用是编解码和调制信号,一个Phy芯片主要包含以下三个子模…

作者头像 李华
网站建设 2026/8/15 22:27:03

某节二面:prompt到头怎么提升效果?别急着说微调

文章目录 前言 一、面试官真正想听的是什么 二、先确认:Prompt 真的到头了吗 1. Few-shot 例子分布检查 2. 思维链 CoT 有没有用上 3. 输出格式约束有没有搞清楚 4. 指令拆分 三、跳出单次调用,从架构层面破局 1. RAG:知识问题的正解 2. 工具调用:让模型别硬算 3. 多步 Age…

作者头像 李华
网站建设 2026/8/15 22:26:03

Swagger Codegen 实战指南:从 OpenAPI 规范到多语言代码生成

1. 引言在前后端分离的开发模式下&#xff0c;接口文档与代码实现的一致性一直是团队协作的痛点。Swagger Codegen 作为一款强大的代码生成工具&#xff0c;能够基于 OpenAPI&#xff08;原 Swagger&#xff09;规范文件自动生成客户端 SDK、服务端骨架代码以及 API 文档&#…

作者头像 李华
网站建设 2026/8/15 22:22:42

S1000D 5.0中文版:从数据模块到智能保障,重塑高端装备技术资料体系

1. 从“标准”到“工程”&#xff1a;S1000D 5.0中文版为何是装备技术资料领域的里程碑如果你在航空、航天、轨道交通、船舶或者大型复杂装备制造领域工作&#xff0c;那么“S1000D”这个代号你一定不陌生。它不是一个软件&#xff0c;也不是一个具体的产品&#xff0c;而是一套…

作者头像 李华
网站建设 2026/8/15 22:21:43

STM32驱动W25Q64JV SPI Flash:从基础SPI到Quad SPI的实战指南

1. 项目概述&#xff1a;为什么我们需要一份详尽的Flash操作指南&#xff1f;在嵌入式开发领域&#xff0c;尤其是基于STM32这类主流MCU的项目中&#xff0c;外部存储扩展几乎是刚需。无论是存放字库、图片、音频资源&#xff0c;还是记录设备运行日志、存储固件升级包&#xf…

作者头像 李华