【免费】微信小程序网约车(打车,在线叫车,移动出行)系统(SpringBoot4+Vue3) 锋哥原创出品,必属精品

大家好,我是Java1234_小锋老师,分享一套锋哥原创的微信小程序网约车(打车,在线叫车,移动出行)系统(SpringBoot4+Vue3)。

项目介绍

随着移动互联网与共享出行模式的快速发展,网约车已成为城市居民日常出行的重要方式。传统电话召车或路边扬招方式存在信息不对称、匹配效率低、服务过程难追溯等问题。微信小程序具有即用即走、无需安装、传播成本低等优势,适合作为网约车业务的移动入口。本文围绕"微信小程序网约车系统"开展需求分析、总体设计、数据库设计与系统实现,构建覆盖乘客端、司机端与管理后台的一体化出行服务平台。

系统采用前后端分离架构。后端基于Spring Boot构建RESTful接口,结合MyBatis-Plus完成数据持久化,使用JWT实现多端统一身份认证,并通过WebSocket完成订单实时推送与状态同步;管理后台采用Vue3、Vite、Element Plus与ECharts实现可视化运营管理;乘客端与司机端分别使用微信小程序原生技术开发,完成地图叫车、抢单接驾、行程推进、余额支付、评价投诉与个人中心等核心业务。数据库选用MySQL,库名为db_taxi,相关业务表均以t_为前缀进行规范化设计。

论文详细给出了系统功能结构图、实体属性图、实体关系图与关键业务时序图,并对每个数据表字段(字段名、类型、长度、是否为空、备注)进行了完整说明。系统实现章节结合核心代码阐述了登录注册、价格预估、下单派单、并发抢单、余额支付、司机审核与后台统计等关键模块。测试结果表明,系统功能完整、流程闭环,能够满足本科毕业设计对工程实践与文档规范的要求,对同类校园或区域出行平台建设具有一定参考价值。

源码下载

链接: https://pan.baidu.com/s/1aL90CVm2HeRnpSSug4Rt1Q?pwd=1234

提取码: 1234

系统展示

核心代码

java 复制代码
package com.taxi.controller.app;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.taxi.common.Constants;
import com.taxi.common.Result;
import com.taxi.dto.*;
import com.taxi.entity.*;
import com.taxi.interceptor.JwtTokenInterceptor;
import com.taxi.mapper.*;
import com.taxi.service.DriverService;
import com.taxi.service.OrderService;
import com.taxi.utils.FileUploadUtil;
import com.taxi.vo.LoginVO;
import com.taxi.vo.OrderDetailVO;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 司机端小程序控制器
 *
 * @author taxi
 */
@RestController
@RequestMapping("/app/driver")
public class AppDriverController {

    @Autowired
    private DriverService driverService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private VehicleMapper vehicleMapper;
    @Autowired
    private CarTypeMapper carTypeMapper;
    @Autowired
    private BalanceRecordMapper balanceRecordMapper;
    @Autowired
    private FileUploadUtil fileUploadUtil;

    /** 司机登录 */
    @PostMapping("/login")
    public Result<LoginVO> login(@RequestBody LoginDTO dto) {
        return Result.success(driverService.login(dto));
    }

    /** 司机注册(入驻申请) */
    @PostMapping("/register")
    public Result<Void> register(@RequestBody DriverRegisterDTO dto) {
        driverService.register(dto);
        return Result.success();
    }

    /** 获取个人信息 */
    @GetMapping("/info")
    public Result<Driver> info(HttpServletRequest request) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        return Result.success(driverService.getInfo(id));
    }

    /** 修改资料 */
    @PutMapping("/profile")
    public Result<Void> updateProfile(HttpServletRequest request, @RequestBody Driver driver) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        driverService.updateProfile(id, driver);
        return Result.success();
    }

    /** 修改密码 */
    @PutMapping("/password")
    public Result<Void> updatePassword(HttpServletRequest request, @RequestBody PasswordDTO dto) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        driverService.updatePassword(id, dto);
        return Result.success();
    }

    /** 上传头像 */
    @PostMapping("/upload")
    public Result<String> upload(@RequestParam("file") MultipartFile file) {
        return Result.success(fileUploadUtil.upload(file));
    }

    /** 切换工作状态(上线/下线) */
    @PutMapping("/workStatus")
    public Result<Void> toggleWorkStatus(HttpServletRequest request, @RequestParam Integer workStatus) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        driverService.toggleWorkStatus(id, workStatus);
        return Result.success();
    }

    /** 获取车辆信息 */
    @GetMapping("/vehicle")
    public Result<Vehicle> vehicle(HttpServletRequest request) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        Vehicle vehicle = vehicleMapper.selectOne(new LambdaQueryWrapper<Vehicle>()
                .eq(Vehicle::getDriverId, id));
        return Result.success(vehicle);
    }

    /** 待接订单列表 */
    @GetMapping("/orders/pending")
    public Result<List<OrderDetailVO>> pendingOrders() {
        return Result.success(orderService.pendingOrders());
    }

    /** 抢单 */
    @PostMapping("/order/accept/{id}")
    public Result<Void> acceptOrder(HttpServletRequest request, @PathVariable Long id) {
        Long driverId = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        orderService.acceptOrder(driverId, id);
        return Result.success();
    }

    /** 到达乘客位置 */
    @PostMapping("/order/arrive/{id}")
    public Result<Void> arriveOrder(HttpServletRequest request, @PathVariable Long id) {
        Long driverId = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        orderService.arriveOrder(driverId, id);
        return Result.success();
    }

    /** 开始行程 */
    @PostMapping("/order/start/{id}")
    public Result<Void> startTrip(HttpServletRequest request, @PathVariable Long id) {
        Long driverId = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        orderService.startTrip(driverId, id);
        return Result.success();
    }

    /** 结束行程 */
    @PostMapping("/order/end/{id}")
    public Result<Void> endTrip(HttpServletRequest request, @PathVariable Long id) {
        Long driverId = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        orderService.endTrip(driverId, id);
        return Result.success();
    }

    /** 我的订单列表 */
    @GetMapping("/orders")
    public Result<List<OrderDetailVO>> orders(HttpServletRequest request,
                                              @RequestParam(required = false) Integer status) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        return Result.success(orderService.driverOrders(id, status));
    }

    /** 订单详情 */
    @GetMapping("/order/{id}")
    public Result<OrderDetailVO> orderDetail(@PathVariable Long id) {
        return Result.success(orderService.getOrderDetail(id));
    }

    /** 收入流水 */
    @GetMapping("/incomeRecords")
    public Result<List<BalanceRecord>> incomeRecords(HttpServletRequest request) {
        Long id = (Long) request.getAttribute(JwtTokenInterceptor.ATTR_USER_ID);
        List<BalanceRecord> records = balanceRecordMapper.selectList(
                new LambdaQueryWrapper<BalanceRecord>()
                        .eq(BalanceRecord::getUserId, id)
                        .eq(BalanceRecord::getUserType, Constants.USER_TYPE_DRIVER)
                        .orderByDesc(BalanceRecord::getCreateTime));
        return Result.success(records);
    }
}
html 复制代码
<template>
  <div class="page-container">
    <!-- 统计卡片 -->
    <el-row :gutter="20" style="margin-bottom: 20px">
      <el-col :span="6">
        <div class="stat-card">
          <div class="stat-label">订单总数</div>
          <div class="stat-value">{{ data.totalOrders || 0 }}</div>
        </div>
      </el-col>
      <el-col :span="6">
        <div class="stat-card green">
          <div class="stat-label">乘客总数</div>
          <div class="stat-value">{{ data.totalPassengers || 0 }}</div>
        </div>
      </el-col>
      <el-col :span="6">
        <div class="stat-card orange">
          <div class="stat-label">司机总数</div>
          <div class="stat-value">{{ data.totalDrivers || 0 }}</div>
        </div>
      </el-col>
      <el-col :span="6">
        <div class="stat-card blue">
          <div class="stat-label">总营收(元)</div>
          <div class="stat-value">{{ data.totalRevenue || 0 }}</div>
        </div>
      </el-col>
    </el-row>

    <!-- 图表区域 -->
    <el-row :gutter="20">
      <el-col :span="12">
        <div class="chart-card">
          <h3>近7日订单量</h3>
          <div ref="orderChartRef" style="height: 300px"></div>
        </div>
      </el-col>
      <el-col :span="12">
        <div class="chart-card">
          <h3>近7日营收</h3>
          <div ref="revenueChartRef" style="height: 300px"></div>
        </div>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :span="12">
        <div class="chart-card">
          <h3>订单状态分布</h3>
          <div ref="statusChartRef" style="height: 300px"></div>
        </div>
      </el-col>
      <el-col :span="12">
        <div class="chart-card">
          <h3>司机接单排行</h3>
          <div ref="rankChartRef" style="height: 300px"></div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import request from '@/utils/request'
import { orderStatusMap } from '@/utils/date'

const data = ref({})
const orderChartRef = ref(null)
const revenueChartRef = ref(null)
const statusChartRef = ref(null)
const rankChartRef = ref(null)
let charts = []

/** 加载统计数据并渲染图表 */
async function loadData() {
  const res = await request.get('/admin/stat/dashboard')
  data.value = res.data

  // 近7日订单折线图
  const orderChart = echarts.init(orderChartRef.value)
  const dailyOrders = res.data.dailyOrders || []
  orderChart.setOption({
    tooltip: { trigger: 'axis' },
    xAxis: { type: 'category', data: dailyOrders.map(i => i.date) },
    yAxis: { type: 'value', minInterval: 1 },
    series: [{ type: 'line', data: dailyOrders.map(i => i.count), smooth: true, areaStyle: { opacity: 0.3 }, itemStyle: { color: '#667eea' } }]
  })
  charts.push(orderChart)

  // 近7日营收柱状图
  const revenueChart = echarts.init(revenueChartRef.value)
  const dailyRevenue = res.data.dailyRevenue || []
  revenueChart.setOption({
    tooltip: { trigger: 'axis' },
    xAxis: { type: 'category', data: dailyRevenue.map(i => i.date) },
    yAxis: { type: 'value' },
    series: [{ type: 'bar', data: dailyRevenue.map(i => i.amount), itemStyle: { color: '#11998e', borderRadius: [4, 4, 0, 0] } }]
  })
  charts.push(revenueChart)

  // 订单状态饼图
  const statusChart = echarts.init(statusChartRef.value)
  const statusData = (res.data.orderStatusDistribution || []).map(i => ({
    name: orderStatusMap[i.status] || '未知', value: i.count
  }))
  statusChart.setOption({
    tooltip: { trigger: 'item' },
    legend: { bottom: 0 },
    series: [{ type: 'pie', radius: ['40%', '70%'], data: statusData, emphasis: { itemStyle: { shadowBlur: 10 } } }]
  })
  charts.push(statusChart)

  // 司机排行横向柱状图
  const rankChart = echarts.init(rankChartRef.value)
  const ranking = res.data.driverRanking || []
  rankChart.setOption({
    tooltip: { trigger: 'axis' },
    yAxis: { type: 'category', data: ranking.map(i => i.driverName).reverse() },
    xAxis: { type: 'value', minInterval: 1 },
    series: [{ type: 'bar', data: ranking.map(i => i.orderCount).reverse(), itemStyle: { color: '#f5576c', borderRadius: [0, 4, 4, 0] } }]
  })
  charts.push(rankChart)
}

onMounted(() => loadData())
onUnmounted(() => charts.forEach(c => c.dispose()))
</script>
相关推荐
andrsted4 小时前
作业发布、课堂检测和错题讲评,用一个小程序完成
学习·微信小程序·小程序·学习方法
汤姆yu5 小时前
基于微信小程序的家电维修预约系统
微信小程序·小程序·家电维修
软件聚导航18 小时前
「聚小软 AI 助手」技术升级:从数据库检索到 RAG 知识库问答
前端·数据库·mysql·微信小程序·小程序·ai编程·rag
一叶星殇1 天前
微信小程序 Vant Popup 滚动穿透:页面级与组件级解决方案详解
微信小程序·小程序
2601_963869951 天前
【计算机毕业设计】基于微信小程序的点餐传菜系统设计与实现
微信小程序·小程序·课程设计
北漂燕郊杨哥1 天前
VS Code 安装微信小程序 MCP 介绍
vscode·微信小程序·小程序·mcp
维双云2 天前
2026微信小程序开店用哪个平台?长期稳定运营的系统选择方法
微信小程序·小程序
辛迪聊物业数字化2 天前
【智能楼宇系统有什么用?赋能园区高效 节能 安全】
经验分享·安全·微信小程序·php
Coodor2 天前
使用web也可以写NFC微信小程序拉取
前端·微信小程序·小程序·nfc拉起小程序
太阳之神aboluo3 天前
微信小程序 (1) 基础用法
微信小程序·小程序