【免费】微信小程序网约车(打车,在线叫车,移动出行)系统(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>
相关推荐
AI砖家1 天前
AI编程—微信小程序开发规范
微信小程序·小程序·notepad++·ai编程
sam-zy2 天前
微信小程序+ESP8266+Arduino 开发智能插座,有本地OTA功能
微信小程序·小程序
A24207349302 天前
微信小程序开发:常用基础语法与指令详解
微信小程序·小程序·notepad++
laboratory agent开发3 天前
2026小程序系统多维度技术与落地能力深度解析
微信小程序
laboratory agent开发5 天前
多维度拆解小程序平台:数字化经营工具的理性选择指南
微信小程序
T01156185 天前
独立开发者商单实战|商超门店小程序(自提 + 同城配送):小程序全端页面 & 业务流程总图汇总
微信小程序·小程序·个人开发·前端实战
驳是6 天前
入坑 UniApp 写小程序,一些感受
微信小程序
不如摸鱼去7 天前
Wot UI 2.3.0 发布:二维码组件来了,Open Wot 与 wot-starter 同步更新
前端·ui·微信小程序·前端框架·uni-app
万亿少女的梦1687 天前
基于微信小程序、Express与MongoDB的校园失物招领系统设计
mongodb·微信小程序·node.js·express·系统设计