阅读 3994

Golang+微信小程序 前后端分离 | 实战项目 车辆信息联络平台

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

Github 开源 欢迎来star 链接如下:

Golang代码部分

Python代码部分

小程序代码部分

使用Golang+微信小程序+Python 前后端分离打造的车辆信息联络平台实战项目。

在这里插入图片描述

1. 背景

1.1 实现目标:

  1. 用户可通过拍照识别车牌号进行绑定车牌号,也能通过车牌号找到对应的车主。
  2. 车牌冲突可进行申诉反馈。
  3. 可通过文本消息提醒、在线聊天、短信提醒等形式与对方车主产生联系。
  4. 强大的社区模块,支持闲置物品的交互买卖。
  5. 实时获取充电桩信息,方便用户选择。
  6. 除基本管理操作,后台还可对车流量进行实时监控。

1.2 开发环境:

开发语言: 后 端:Golang v1.15、Python v3.7

前 端:微信小程序基础库 v2.16.0、Vue v3.3.0

算 法 : Pytorch v1.7.1、Cuda v11.0

数 据 库 : MySQL v5.7.30、MongoDB v4.4.6、Redis v4.0.9

短信服务 :腾讯云短信

文件存储 :七牛云存储

服 务 器 : 阿里云服务器

1.3 go语言部分代码展示

model层

package model

import "github.com/jinzhu/gorm"

type Car struct {
   gorm.Model
   CarName    string  //车名字
   CarNum        string  //车牌号
   CarImages  string  //车照片
   CarBossId  uint        //车主ID
   CarBossName string
}

复制代码

service 层

package service

import (
   "CarDemo1/model"
   "CarDemo1/pkg/e"
   "CarDemo1/serializer"
   "fmt"
)

type ShowFriendService struct {

}

type ShowMyFriendInfoService struct {

}

type CreateFriendService struct {
   UserID uint  `form:"user_id" json:"user_id"`
}

type DeleteFriendService struct {
   UserID  string  `form:"user_id" json:"user_id"`
}


//展示好友
func (service *ShowFriendService) Show(id string) serializer.Response {
   var user model.User
   var friendsList []model.User
   code := e.Success
   model.DB.Table("user").Where("id = ?",id).First(&user)
   fmt.Println(user)
   err := model.DB.Model(&user).Association("Relations").Find(&friendsList).Error
   fmt.Println(friendsList)
   if err != nil {
      code = e.ErrorFriendFound
      return serializer.Response{
         Status:    code,
         Data:      err,
         Msg:       e.GetMsg(code),
      }
   }
   return serializer.Response{
      Status:    code,
      Data:      serializer.BuildFriends(friendsList),
      Msg:       e.GetMsg(code),
   }
}

//关注好友
func (service *CreateFriendService) Create(id uint) serializer.Response {
   var user model.User
   var friend model.User
   code := e.Success
   model.DB.Model(&friend).Where(`id = ? `,id).First(&friend)           //被关注者
   model.DB.Model(&user).Where(`id = ?`,service.UserID).First(&user)  //关注者
   err := model.DB.Model(&user).Association(`Relations`).Append([]model.User{friend}).Error
   if err != nil {
      code = e.ErrorFriendFound
      return serializer.Response{
         Status:    code,
         Msg:       e.GetMsg(code),
         Error:    err.Error(),
      }
   }
   return serializer.Response{
      Status:    code,
      Msg:       e.GetMsg(code),
   }
}

//解除好友关系
func (service *DeleteFriendService) Delete(id uint) serializer.Response {
   var user model.User
   var friend []model.User
   code := e.Success
   model.DB.Model(&friend).Where(`id = ?`,id).First(&friend)            //被关注者
   model.DB.Model(&user).Where(`id = ?`,service.UserID).First(&user)  //关注者
   err := model.DB.Model(&user).Association(`Relations`).Delete(friend).Error
   //model.DB.Model(&user).Association("Relations").Clear()
   // Remove the relationship between source & arguments if exists
   // only delete the reference, won’t delete those objects from DB.
   if err != nil {
      code = e.ErrorFriendFound
      return serializer.Response{
         Status:    code,
         Msg:       e.GetMsg(code),
         Error:err.Error(),
      }
   }
   return serializer.Response{
      Status:   code,
      Msg:      e.GetMsg(code),
   }
}

//展示好友的详细信息
func (service *ShowMyFriendInfoService) Show(id string) serializer.Response {
   var user model.User
   code := e.Success
   err := model.DB.Model(&model.User{}).Where(`id = ?`,id).First(&user).Error
   if err != nil {
      code = e.ErrorDatabase
      return serializer.Response{
         Status:    code,
         Data:      err,
         Msg:       e.GetMsg(code),
      }
   }
   return serializer.Response{
      Status:    code,
      Data:      serializer.BuildUser(user),
      Msg:       e.GetMsg(code),
   }
}
复制代码

serializer层

package serializer

import "CarDemo1/model"

type Friend struct {
   ID          uint       `json:"id"`
   UserName   string     `json:"user_name"`
   UserAvatar     string     `json:"user_avatar"`
}

//序列化好友
func BuildFriend(item model.User) Friend {
   return Friend{
      ID:          item.ID,
      UserName :   item.UserName,
      UserAvatar : item.Avatar,
   }
}

//序列化好友列表
func BuildFriends(items []model.User) (Friends []Friend) {
   for _, item := range items {
      Friend := BuildFriend(item)
      Friends = append(Friends, Friend)
   }
   return Friends
}
复制代码

1.4 小程序部分代码展示

publish.wxml 页面

<view class="container-publish">
	<view class="chose-image" bindtap="uploadImage">
		<image src="/images/publish.png"></image>
		<text>+图片</text>
	</view>
	<view class="image-list" wx:if="{{imageList.length > 0}}">
		<view class="item" wx:for="{{imageList}}" wx:key="key">
		<image src="{{item.path}}"></image>
			<icon wx:if="{{item.percent==100}}" class="rm" type="clear" color="red" data-index="{{index}}" data-item="{{item}}" bindtap="removeImage"></icon>
			<progress percent="{{item.percent}}" wx:if="{{item.error}}" color="#FF0000" />
			<progress percent="{{item.percent}}" wx:else />
		</view>
	</view>
	<view class="text">
		<textarea placeholder=" 来呀,写下你的心情" value="{{content}}" bindinput="bindContentInput" />
	</view>
 
  <view class="function-view">
   
    <view class="row" >
      <view class="left">{{ topicTitle }}</view>
      <view class="right">
        <image class="go-icon" src='/images/iconsmall.png'></image>
      </view>
    </view>
	<view class="topic-all">
	<view wx:for="{{ topicList }}" wx:key="topicList" class="topic-content">
	<view data-id="{{item.id}}" class="{{item.id == idx ?'choose':'notchoose'}}" bindtap="goIndex" data-id="{{item.id}}">#{{item.category_name}}  </view>
	</view>
	</view>
 </view>
</view>
<view class="publish-btn" bindtap="publishNews">发 布</view>
复制代码

publish.js页面

// pages/publish/publish.js

var api = require('../../config/api.js')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    userInfo: wx.getStorageSync('userInfo'),
    imageList: [],
    content: "",
    address: "",
    topicId: null,
    topicTitle: "选择合适的话题",
    idx: "",
  },
  resetData: function () {
    this.setData({
      imageList: [],
      content: "",
      address: "",
      topicId: null,
      topicTitle: "选择合适的话题",
    });
  },

  uploadImage: function () {
    // 选择图片并上传
    wx.chooseImage({
      count: 9,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: res => {
        var oldLength = parseInt(this.data.imageList.length);
        // 最多上传9张
        let totalCount = res.tempFiles.length + this.data.imageList.length;
        if (totalCount > 9) {
          wx.showToast({
            title: '图片最多选择9张',
            icon: 'none'
          });
          return
        };
        console.log(this.data.imageList.concat(res.tempFiles));
        // 本地图片在页面预览
        this.setData({
          imageList: this.data.imageList.concat(res.tempFiles)
        });
        // 上传新挑选的图片(原图片无需再上传)
        for (var index in res.tempFiles) {
          let imageFilePath = res.tempFiles[index].path;
          var filePathSplit = imageFilePath.split('.');
          var ext = filePathSplit[filePathSplit.length - 1];
          // 创建随机字符串
          let randowString = Math.random().toString(36).slice(-8) + String(new Date().getTime());
          var fileKey = randowString + "." + ext;
          var targetIndex = parseInt(oldLength) + parseInt(index);
          this.setData({
            ["imageList[" + targetIndex + "].key"]: fileKey
          });
        }
      }
    })
  },
  removeImage: function (event) {
    // 判断是否正在上传,如果正在上传就终止,否则就删除;
    // 删除图片,终止 & 删除
    var index = event.currentTarget.dataset['index'];
    var item = event.currentTarget.dataset['item'];
    if (item.percent == 100) {
      cos.deleteObject({
        Bucket: "mini-1251317460",
        Region: "ap-chengdu",
        Key: item.key
      }, (err, data) => {
        if (err) {
          wx.showToast({
            title: '删除失败',
            icon: 'none'
          });
        } else {
          var imageList = this.data.imageList;
          imageList.splice(index, 1);
          this.setData({
            imageList: imageList
          });
        }
      });
    }
  },
  getLocation: function () {
    wx.chooseLocation({
      success: res => {
        this.setData({
          address: res.address
        })
      }
    });
  },
  updateTopic: function (item) {
    this.setData({
      topicId: item.id,
      topicTitle: item.title
    })
  },
  bindContentInput: function (e) {
    this.setData({
      content: e.detail.value
    });
  },
  publishNews: function () {

    //发布至少需要一张图片
    if (this.data.imageList.length < 1) {
      wx.showToast({
        title: '至少选择一张图片',
        icon: 'none'
      });
      return
    }
    // 发布内容不能为空
    if (this.data.content.length < 1) {
      wx.showToast({
        title: '内容不能为空',
        icon: 'none'
      });
      return
    }

    wx.showLoading({
      title: '发布中...',
      duration: 2000,
    })
    var content = this.data.content
    wx.uploadFile({
      method:"POST",
      url: api.CreateSocial+content,
      filePath:this.data.imageList[0].path ,
      name: 'file',   // 和后端沟通好 接收文件的name
      header: {
        "Authorization": wx.getStorageSync('token'),
        user_id: this.data.userInfo.id,
        category_id: this.data.idx,
      },
      success: function (res) {
       var data = JSON.parse(res.data)
        console.log(data)
        if(data.status == 200){
          wx.showToast({
            title: '绑定成功',
            duration: 2000,
          })
          wx.navigateTo({
            url: '/pages/publishSuccess/publishSuccess',
          })
        }else{
          wx.showToast({
            title: '绑定失败',
            duration: 2000,
          })
        }
      },
      fail: function (err) {
        console.log(err)
      }
    });
  }
})
复制代码

2. 功能介绍


2.1 主体部分

声明:这里的首页以及个人信息页面是参考隔壁有坑的小程序前端。 原作者github:GitHub

  • 主页面中,UI界面简介大方得体。方便用户快速了解小程序的大体功能,也非常感谢原作者的开源!
  • 主页面呈现四个模块
    1. 社区模块
    2. 亲友模块
    3. 聊天模块
    4. 个人中心

2.2 用户模块

个人中心是可以对用户个人的信息进行修改、由于是用微信登陆,所以姓名和头像是读取微信的头像和名字。所以名字和头像是不支持修改的。

但是手机号、邮箱号、车辆是可以进行解绑定的。 用户可以通过绑定自己的车牌号来管理自己的车辆。

车牌,我们提供了一个ocr的算法接口,可以对车牌进行识别,然后返回车牌信息进行绑定车辆。

  • 个人信息
  • 绑定邮箱
  • 绑定手机
  • 绑定车牌

2.3 社区模块

推荐模块、亲友圈、闲来康康、我的世界等。

  • 我的世界模块可以查看到用户个人发布的帖子。
  • 帖子详情、可以对帖子进行评论、点赞等操作。
  • 帖子发送,用户可以通过话题进行发布帖子。

2.4 聊天模块以及充电功能

  • 聊天功能,实现实时聊天。
  • 系统消息,系统可有针对性的对其进行发送信息。
  • 用户反馈,可以进行评论举报、聊天举报、车牌申诉等功能。
  • 充电桩查询,我们用爬虫将学校充电桩的情况进行爬取,使得用户能够查看充电桩的情况。

2.5 算法方面

算法部分的结果都是通过flask框架进行api接口的返回。


2.5.1 FasterRCNN网络车牌识别

在这里插入图片描述

2.5.2 YOLOV5 车辆识别

在这里插入图片描述 在这里插入图片描述

2.6 后台管理模块

后台模块相对简单,并没有设计到比较多的功能,后需再进行完善。

  • 用户模块管理
- 车辆模块管理
- 反馈信息管理
- 车流监控管理
 
复制代码

在这里插入图片描述 可对用户进行拉黑、封号处理

在这里插入图片描述 可下架、修改用户的帖子信息。

在这里插入图片描述 可对用户的车辆进行处理、更换车牌号等

3. 总结

本人目前大二,很多东西都不怎么懂。所以写的代码结构不是很好。

  • go的ws也有涉及。
  • gorm的多对多也有了深入的了解。还有后端的一些逻辑结构。
  • 熟悉了腾讯云短信,七牛云存储,阿里云服务器的一些操作。

算法方面

  • FasterRCNN的车牌识别
  • YOLO网络的车辆检测

不过顺便可以把这个当作下学期的软工实践了哈哈!

喜欢的小伙伴可以关注我噢~

文章分类
后端
文章标签