微信小程序ofo小黄车+thinkphp5.0打造全栈应用

2023-10-08 00:10

本文主要是介绍微信小程序ofo小黄车+thinkphp5.0打造全栈应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:https://www.imooc.com/article/20310

ofo至今还没有微信小程序(很费解),每次用ofo都得去支付宝,很不方便,我用微信用的比较多,无意间在简书上面看到某人写了一个关于ofo的小程序,链接如下:给ofo小黄车撸一个微信小程序,不过数据都是模拟的,没有数据库,没有后台,这对于一个PHP攻城狮来说,是可忍孰不可忍呀,刚刚学完七月老师的课程,受益匪浅,刚好自己动手做一个,说动手就动手,let's do it;

先献上一波效果图吧:

体验版页面

支付页面

计费页面

开锁页面

用车页面

开锁页面

充值页面

个人中心页面

我的钱包页面

首页页面

ofo小程序的架构体系:

小程序数据从服务器到前端交互总结:

数据库设计:

用户表:

**user  | CREATE TABLE `user` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `openid` varchar(50) NOT NULL COMMENT '用户的唯一标识', `create_time` int(11) DEFAULT NULL, `delete_time` int(11) DEFAULT NULL, `balance` decimal(60,2) NOT NULL COMMENT '余额', `guarantee` decimal(60,2) NOT NULL COMMENT '保证金', `update_time` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |

小黄车表:

**| bike  | CREATE TABLE `bike` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `latitude` float(11,6) NOT NULL COMMENT '经度', `is_show` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0未使用 1使用', `longitude` float(11,6) NOT NULL COMMENT '纬度', `password` int(11) NOT NULL COMMENT '单车密码', `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0正常,1故障', `create_time` int(11) NOT NULL, `update_time` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 |

故障分类表:

**| trouble_cate | CREATE TABLE `trouble_cate` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL COMMENT '故障名称', `create_time` int(11) DEFAULT NULL, `update_time` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |

故障记录表:

**| trouble_record | CREATE TABLE `trouble_record` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '用户ID', `bike_id` int(11) DEFAULT NULL COMMENT '单车ID', `longitude` varchar(50) NOT NULL COMMENT '经度', `latitude` varchar(50) NOT NULL COMMENT '纬度', `img` varchar(50) DEFAULT NULL COMMENT '上传的图片', `remark` varchar(50) DEFAULT NULL COMMENT '备注', `create_time` int(11) NOT NULL, `update_time` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 |

充值表:

**| charge | CREATE TABLE `charge` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '用户ID', `price` decimal(60,2) NOT NULL COMMENT '费用', `type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0为保证金 1为余额', `create_time` int(11) NOT NULL, `update_time` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8 |

骑行记录表:

**| record | CREATE TABLE `record` (** `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `bike_id` int(11) NOT NULL COMMENT '单车ID', `user_id` int(11) NOT NULL COMMENT '用户ID', `end_time` int(11) NOT NULL COMMENT '结束时间', `start_time` int(11) NOT NULL COMMENT '开始时间', `total_price` decimal(10,0) NOT NULL COMMENT '总价格', `start_long` varchar(50) NOT NULL COMMENT '开始经度', `start_lati` varchar(50) NOT NULL COMMENT '开始纬度', `end_long` varchar(50) NOT NULL COMMENT '结束经度', `end_lati` varchar(50) NOT NULL COMMENT '结束纬度', `create_time` int(11) NOT NULL, `update_time` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8 |

核心知识体系:

1.thinkphp5.0相关的知识

  • TP5三大核心:路由、控制器、模型
  • 以ORM的方式查询数据库
  • 使用TP5验证器Validate构建整个验证层
  • 开发环境和生产环境下不同的全局异常处理机制
  • TP5缓存的使用
  • 在TP5中使用数据库事务
    2.微信小程序+微信支付
  • 微信小程序登录状态维护
  • 微信支付接入
  • Class和Module面向对象的思维构建前端代码
  • 体验优化
    3.API接口的设计
  • 采用RESTFul API风格
  • (RESTFul API风格可参考GitHub 开发者文档)
  • 返回码、URL语义、HTTP动词、错误码、异常返回
  • 使用Token令牌来构建用户授权体系
  • API版本控制(v1、v2)

ofo页面逻辑和所需接口分析

1.首页页面逻辑与接口分析

根据效果图,很明显我们知道肯定需要一个获取单车信息的接口,接口代码如下:

/*** @return false|\PDOStatement|string|\think\Collection* @throws BikeException* 获取单车的位置信息*/public function getBicyclePosition() { $bikes = BikeModel::getBicyclePosition(); if(!$bikes) { throw new BikeException(); } return $bikes; }

立即用车按钮分析,首先我们需要先判断有没有登录,登录我们使用的是token令牌(后面会在个人中心登录按钮讲下如何生成token令牌,如何利用tp5的缓存,使token令牌有有效期),如果令牌存在,我们还得判断令牌是否有效,否则重新登录,如果验证通过,我们还得判断这个用户是否已经有押金,如果没有押金,跳到充值页面去充值,否则跳转到用车页面,根据分析,我们需要一个验证token是否有效的接口,接口代码如下,

/*** @return bool* @throws TokenException* 验证token*/public function verifyToken() { $token = Request::instance()->header('token'); $var = Cache::get($token); if(!$var) { throw new TokenException([ 'msg'=>'token已经过期', 'errorCode'=>10002 ]); } return true; }

我们还需要一个获取用户信息的接口,判断是否有押金,接口代码如下:

/*** @return null|static* @throws UserException* 获取用户的信息*/public function getUserInfo(){ $uid = Token::getCurrentUid(); $user = UserModel::get($uid); if(!$user) { throw new UserException(); } return $user; }

故障按钮分析:同样的我们需要验证是否登录,登录是否过期,否则我们跳转到登录页面。(注意:我们需要把用户的初始位置,记录到小程序的缓存中,因为骑行记录表需要记录用户的初始位置)

2.登录页面逻辑和所需接口分析

关于使用token令牌的好处,请自行百度,首先我先用一张图来说明微信小程序如何获取token:

根据效果图,我们需要获取token令牌接口,接口代码如下:

 /*** @param $code* @return array* 获取token*/public function getToken($code) { (new TokenGet())->goCheck(); $user = new UserToken($code); $token = $user->get(); return [ 'token'=>$token ]; }

设置token的有效期,把token存储在服务器端的缓存中,返回token,客户端获取到token,存储到缓存中,双向存储token,以后每次访问接口都携带token,更加安全,有效的防止有人伪造token获取接口的信息

3.个人中心页面逻辑和所需接口分析

根据效果图,点击我的钱包按钮需要跳转到我的钱包页面,我们需要一个获取用户信息的接口,接口代码如下:

/*** @return null|static* @throws UserException* 获取用户的信息*/public function getUserInfo(){ $uid = Token::getCurrentUid(); $user = UserModel::get($uid); if(!$user) { throw new UserException(); } return $user; }

退出登录按钮:我们需要删除本地token,跳转到登录页面

4.充值页面逻辑和接口分析

根据效果图:我们需要一个充值的接口,因为是个人开发,没有商户号,所以微信支付就没有做,不过其实微信支付也并不难,附上微信支付的流程:

商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。 步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【[统一下单API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)】。 步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appidpartneridprepayidnoncestrtimestamppackage。注意:package的值格式为Sign=WXPay 步骤4:商户APP调起微信支付。api参见本章节【[app端开发步骤说明](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5)】 步骤5:商户后台接收支付通知。api参见【[支付结果通知API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7)】 步骤6:商户后台查询支付结果。,api参见【[查询订单API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_2)】

这个接口需要注意的是,从哪个页面过来的,从首页过来的,应该就是押金充值,从我的钱包页面和支付页面过来的,就应该是余额充值,根据form不同,我们数据库充值记录表里面的type就不同,type为1代表余额充值,type为1为押金充值,接口代码如下:

/*** @param $guarantee* 充值*/public function pay($from,$price) { $type = 1; if($from == 'index') { $type = 0; }else if($from == 'wallet' || $from == 'pay') { $type = 1; } $uid = Token::getCurrentUid(); Db::startTrans(); try{ if($type == 1) { $user = UserModel::get($uid); $price = $price + $user->balance; $result = new UserModel(); $res = $result->save(['balance'=>$price],['id'=>$uid]); }else { $res = UserModel::update(['guarantee'=>$price],['id'=>$uid]); } $rel = Charge::create([ 'price'=>$price, 'type'=>$type, 'user_id'=>$uid ]); if($rel && $res) { Db::commit(); } }catch (Exception $e) { Db::rollback(); throw new UserException([ 'msg'=>'充值失败' ]); } }

5.立即用车页面逻辑与接口分析

根据效果图,我们需要一个获取单车密码的接口,根据用户输入的ID,获取单车的信息,如果is_show为1,服务器抛出自定义的异常,单车正在被使用,type为1,单车被报修,出现故障,不能使用,单车如果不存在,抛出异常,单车不存在。获取到单车的密码后,携带密码和单车号到结果页面,接口代码如下:

/*** @param $id* @return array|false|\PDOStatement|string|\think\Model* @throws BikeException* 根据单车的ID获取单车的信息*/public function getBikeByID($id) { // (new IsMustBePostiveInt())->goCheck(); $bike = BikeModel::getBikeByID($id); if(!$bike) { throw new BikeException([ 'msg'=>'该车牌号不存在' ]); } if($bike['is_show'] == 1){ throw new BikeException([ 'msg'=>'此单车正在被使用', 'errorCode'=>10001 ]); } if($bike['type'] == 1) { throw new BikeException([ 'msg'=>'此单车多次被报修,暂不可使用', 'errorCode'=>10002 ]); } return $bike; } }

6.计时页面逻辑和接口分析

根据效果图:计时开始时,我们需要把单车的使用状态改变,改变为正在使用状态,接口代码如下:

/*** @param $id* 修改单车的使用状态*/public function updateBikeStatus($type = 0,$id) { // (new IsMustBePostiveInt())->goCheck(); if($type == 0) { //锁定单车,单车在被使用中 $data = [ 'is_show'=>1 ]; }elseif ($type == 1) { //释放单车,单车恢复使用 $data = [ 'is_show'=>0 ]; }elseif ($type == 2) { //单车出现故障 $data = [ 'type'=>1 ]; }elseif ($type == 3) { //单车恢复正常 $data = [ 'type'=>0 ]; } $res = \app\api\model\Bike::update($data,['id'=>$id]); if($res) { return true; }else { echo false; } }

7.故障页面逻辑和接口分析

根据效果图,我们首先需要一个获取故障分类名称的接口,接口代码如下:

 /*** @return false|\PDOStatement|string|\think\Collection* 获取问题的分类信息*/public function getTroubleCate() { $res = new \app\api\model\TroubleCate(); $troubleCate = $res->select(); return $troubleCate; }

然后提交的时候,我们需要一个记录故障的接口,这个接口中,我们首先需要判断,如果没有选择车牌损坏,则必须填写车牌号,否则服务器返回自定义的异常,请输入单车号,单车和故障很明显是多对多的关系,我们在记录的时候,还要写到另外一张表中去,有记录ID和分类ID组成的主键的表,同时我们根据单车的ID还得修改单车的状态,接口代码如下:

public function recordTrouble($record) { //分为两种情况,车牌损坏,车牌未损坏 //如果有车牌号码,先判断单车是否存在,不存在,抛出异常, //如果存在,写到trouble_record表,根据trouble_record //的id,还有trouble_id写到bike_trouble表,多对多表,全部写入成功之后, //修改bike表的type值,用到事务,要么失败,要么成功 $bikeID = $record['inputValue']['num']; //2代表车牌被损坏,看不到车牌号码 if(!in_array(2,$record['checkboxValue'])) { if($bikeID) { $bike = new Bike(); $bike->getBikeByID($bikeID); }else { throw new BikeException([ 'msg'=>'请输入单车编号', 'errorCode'=>10003 ]); } } try { Db::startTrans(); $address = $record['address']; $uid = \app\api\service\Token::getCurrentUid(); $troubleRecord = new \app\api\model\TroubleRecord(); $troubleRecord->user_id=$uid; $troubleRecord->bike_id=$bikeID; $troubleRecord->longitude=$address['start_long']; $troubleRecord->latitude=$address['start_lati']; $troubleRecord->img=json_encode($record['picUrls']); $troubleRecord->remark=$record['inputValue']['desc']; //更新故障记录表troubleRecord $troubleRecord->save(); $resID = $troubleRecord->id; $troublesID = $record['checkboxValue']; $newArr = array(); foreach ($troublesID as $k=>$v) { $newArr[$k]['trouble_id'] = $v; $newArr[$k]['record_id'] = $resID; } $bikeTrouble = new BikeTrouble(); //更新故障表bikeTrouble表 $rel = $bikeTrouble->saveAll($newArr); if($bikeID) 

转载于:https://www.cnblogs.com/itfantasy/p/8385678.html

这篇关于微信小程序ofo小黄车+thinkphp5.0打造全栈应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/161372

相关文章

CSS3 布局样式及其应用举例

《CSS3布局样式及其应用举例》CSS3的布局特性为前端开发者提供了无限可能,无论是Flexbox的一维布局还是Grid的二维布局,它们都能够帮助开发者以更清晰、简洁的方式实现复杂的网页布局,本文给... 目录深入探讨 css3 布局样式及其应用引言一、CSS布局的历史与发展1.1 早期布局的局限性1.2

Java使用WebView实现桌面程序的技术指南

《Java使用WebView实现桌面程序的技术指南》在现代软件开发中,许多应用需要在桌面程序中嵌入Web页面,例如,你可能需要在Java桌面应用中嵌入一部分Web前端,或者加载一个HTML5界面以增强... 目录1、简述2、WebView 特点3、搭建 WebView 示例3.1 添加 JavaFX 依赖3

防止SpringBoot程序崩溃的几种方式汇总

《防止SpringBoot程序崩溃的几种方式汇总》本文总结了8种防止SpringBoot程序崩溃的方法,包括全局异常处理、try-catch、断路器、资源限制、监控、优雅停机、健康检查和数据库连接池配... 目录1. 全局异常处理2. 使用 try-catch 捕获异常3. 使用断路器4. 设置最大内存和线

在React聊天应用中实现图片上传功能

《在React聊天应用中实现图片上传功能》在现代聊天应用中,除了文字和表情,图片分享也是一个重要的功能,本文将详细介绍如何在基于React的聊天应用中实现图片上传和预览功能,感兴趣的小伙伴跟着小编一起... 目录技术栈实现步骤1. 消息组件改造2. 图片预览组件3. 聊天输入组件改造功能特点使用说明注意事项

Redis中RedisSearch使用及应用场景

《Redis中RedisSearch使用及应用场景》RedisSearch是一个强大的全文搜索和索引模块,可以为Redis添加高效的搜索功能,下面就来介绍一下RedisSearch使用及应用场景,感兴... 目录1. RedisSearch的基本概念2. RedisSearch的核心功能(1) 创建索引(2

Python datetime 模块概述及应用场景

《Pythondatetime模块概述及应用场景》Python的datetime模块是标准库中用于处理日期和时间的核心模块,本文给大家介绍Pythondatetime模块概述及应用场景,感兴趣的朋... 目录一、python datetime 模块概述二、datetime 模块核心类解析三、日期时间格式化与

使用Python创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获