本文将完成一个物流原型系统核心代码的编写。

一、系统需求

系统需完成的功能包括:

  • 订单提交
  • 订单追踪(出发地、目的地、当前位置)
  • 地图集成(百度地图api)
  • 用户管理

二、技术基础

  • 后端:php,框架:thinkphp
  • 前端:bootstrap,jquery,百度api

关于thinkphp的核心学习可参考前一篇《利用thinkphp建立一个简单的站点》,其中介绍了该框架的基础入门教程。

三、系统设计

1、控制器及视图

由于是原型系统,所以在控制器上不分其他控制器,因此只需创建一个index的控制器,然后在该控制器的方法上做文章。视图文件也可就放在一个index文件夹中,方便调用。

2、数据库设计

user表:

  • id:int 8(用户编号)
  • name:varchar 20(用户名)
  • password:varchar 20(密码)
  • type:int 1(用户类型:用户、司机、管理员等)

order表:

  • id:int 8(订单编号)
  • start:varchar 50(订单起始地,位置信息用字符串描述)
  • end:varchar 50(订单目的地,位置信息用字符串描述)
  • time:varchar 50(订单上传时间)
  • lal:varchar 50(订单目前所处位置)

四、核心代码

1、index控制器

控制器index的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?php
namespace app\index\controller;

//引入多个包
use think\Controller;
use think\View;
use think\Db;
use think\Request;
use think\Session;

class Index extends Controller
{
public function index()//首页
{
$DB=new Db;
$order=$DB::table("order")->select();
$this->assign('order',$order);
$this->assign('name',Session::get('name'));
$this->assign('type',Session::get('type')==0?"用户":"司机");
return $this->fetch();
}
public function query()//查询页
{
if(request()->isPost()){
$DB=new Db;
$map['id']=input('id');
$order=$DB::table("order")->where($map)->find();
$this->assign('order',$order);
return $this->fetch();
}
$this->error("错误");

}
public function view($id)//订单页
{
$DB=new Db;
$map['id']=$id;
$order=$DB::table("order")->where($map)->find();
$this->assign('order',$order);
return $this->fetch('query');
}
public function add()//添加订单
{
if(request()->isPost()){
$data=[
'start'=>input('start'),
'end'=>input('end'),
'time'=>time(),
];
$DB=new Db;
$DB::name('order')->insert($data);
}
$this->success("添加成功!");
}
public function del($id)//删除订单
{
$DB=new Db;
$info=$DB::table("order")->where('id',$id)->delete();
if($info){
$this->success("删除成功!");
}else{
$this->error($file->getError());
}
}
public function douser()//验证用户
{
$request = Request::instance();
if(request()->isPost()){
$m['name']=input('name');
$m['password']=input('password');
$DB=new Db;
$userdata=$DB::table("user")->where($m)->find();
if($userdata==null){
return $this->error('用户名或密码错误!');
}else{
Session::set('name',$userdata['name']);
Session::set('type',$userdata['type']);
return $this->success('登录成功!',url('index/index'));
}
}
}
public function loginout()//注销
{
Session::delete('name');
Session::delete('type');
return $this->success('注销成功!',url('index/index'));
}
}

在index控制器中,我们写了几个函数用于构建对应链接所导致的行为,如显示主页、查询页等页面,用户登录注销等操作以及添加订单等行为。

2、index.html主页

主页index.html的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<html>
<head>
<title>物流信息原型系统</title>
<!-- 引入css文件 -->
<link rel="stylesheet" type="text/css" href="__HOME__/css/bootstrap.min.css" />
<!-- 引入js文件 -->
<script src="__HOME__/js/jquery-3.4.1.min.js"></script>
<script src="__HOME__/js/bootstrap.min.js"></script>
<script src="__HOME__/js/echarts.min.js"></script>
</head>
<body>
<nav class="navbar navbar-dark bg-dark navbar-expand-lg mb-3">
<a class="navbar-brand" href="{:url('index/index');}">物流信息原型系统</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
管理
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">上传单号</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">管理单号</a>
</div>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="单号" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">查询</button>
</form>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-4 col-sm-12">
{if condition="$Think.session.name == null"}
<div class="card" style="width: 100%;">
<div class="card-header">
登录
</div>
<div class="card-body">
<form method="post" action="{:url('index/douser');}">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">用户名</span>
</div>
<input name="name" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">密码</span>
</div>
<input name="password" type="password" class="form-control" placeholder="" aria-describedby="basic-addon1" value="">
</div>
<button id="count" type="submit" class="btn btn-primary btn-block mb-3" data-dismiss="modal">登录</button>
</form>
</div>
</div>
{else /}
<div class="card" style="width: 100%;">
<div class="card-header">
个人信息
</div>
<div class="card-body">
<div class="input-group mb-3">
姓名:{$name}</br>
类型:{$type}
</div>
<button type="submit" class="btn btn-primary btn-block mb-3" data-dismiss="modal">进入个人中心</button>
<a href="{:url('index/loginout');}" class="btn btn-primary btn-block mb-3" data-dismiss="modal">退出</a>
</div>
</div>
{/if}
<br/>
<div class="card" style="width: 100%;">
<div class="card-header">
查询订单
</div>
<div class="card-body">
<form method="post" action="{:url('index/query');}">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">单号</span>
</div>
<input name="id" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="">
</div>
<button id="count" type="submit" class="btn btn-primary btn-block mb-3" data-dismiss="modal">查询</button>
</form>
</div>
</div>
<br/>
</div>
<div class="col-md-8 col-sm-12">
<div class="card" style="width: 100%;">
<div class="card-header">
最新订单
</div>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th scope="col">单号</th>
<th scope="col">出发地</th>
<th scope="col">目的地</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody>
{foreach $order as $data}
<tr>
<th scope="row">{$data.id}</th>
<td>{$data.start}</td>
<td>{$data.end}</td>
<td><a href="{:url('index/view');}/id/{$data.id}">查看</a></td>
</tr>
{/foreach}
</tbody>
</table>

</div>
</div>
</div>
</div>
</div>
</body>
</html>

主页中用到了thinkph视图的输出函数,在无用户登录时显示登录框,在登录后显示用户个人信息框。同时在该页面集成查询、最新订单的显示等页面。

3、query.html查询页

查询也query.html的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<html>
<head>
<title>物流信息原型系统</title>
<!-- 引入css文件 -->
<link rel="stylesheet" type="text/css" href="__HOME__/css/bootstrap.min.css" />
<!-- 引入js文件 -->
<script src="__HOME__/js/jquery-3.4.1.min.js"></script>
<script src="__HOME__/js/bootstrap.min.js"></script>
<script src="__HOME__/js/echarts.min.js"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=RODusGpnlcywQkMpTigghmhb5mfPu2Gf"></script>
</head>
<body>
<nav class="navbar navbar-dark bg-dark navbar-expand-lg mb-3">
<a class="navbar-brand" href="{:url('index/index');}">物流信息原型系统</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
管理
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">上传单号</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">管理单号</a>
</div>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="单号" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">查询</button>
</form>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-4 col-sm-12">
<div class="card" style="width: 100%;">
<div class="card-header">
查询订单
</div>
<div class="card-body">
<form method="post" action="{:url('index/query');}">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">单号</span>
</div>
<input name="id" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="{$order.id}">
</div>
<button id="count" type="submit" class="btn btn-primary btn-block mb-3" data-dismiss="modal">查询</button>
</form>
</div>
</div>
<br/>
<div class="card" style="width: 100%;">
<div class="card-header">
管理订单
</div>
<div class="card-body">
<form method="post" action="{:url('index/query');}">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">当前位置</span>
</div>
<input id="lal" name="lal" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">信息</span>
</div>
<input name="inf" type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="">
</div>
<button id="count" type="submit" class="btn btn-primary btn-block mb-3" data-dismiss="modal">更新</button>
</form>
</div>
</div>
<br/>
</div>
<div class="col-md-8 col-sm-12">
<div class="card mb-3" style="width: 100%;">
<div class="card-header">
订单信息
</div>
<div class="card-body">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">单号</span>
</div>
<input type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="{$order.id}">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">出发地</span>
</div>
<input type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="{$order.start}">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">目的地</span>
</div>
<input type="text" class="form-control" placeholder="" aria-describedby="basic-addon1" value="{$order.end}">
</div>
<div class="input-group mb-3">

</div>
<div id="container" style="width:100%;height:500px"></div>
</div>
<script type="text/javascript">
var map = new BMap.Map("container"); // 创建地图实例
var curpoint = new BMap.Point({$order.lal}); // 创建点坐标
map.centerAndZoom(curpoint, 8); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放

var myIcon = new BMap.Icon("__HOME__/img/1.png", new BMap.Size(50,32));
var marker = new BMap.Marker(curpoint,{icon:myIcon}); // 创建标注
map.addOverlay(marker); // 将标注添加到地图中

// 创建地址解析器实例
var myGeo = new BMap.Geocoder();

// 将地址解析结果显示在地图上,并调整地图视野
myGeo.getPoint("{$order.start}", function(spoint){
if (spoint) {
map.addOverlay(new BMap.Marker(spoint));
myGeo.getPoint("{$order.end}", function(epoint){
if (epoint) {
map.addOverlay(new BMap.Marker(epoint));
var driving = new BMap.DrivingRoute(map, {
renderOptions: {
map: map,
autoViewport: true
}
});

driving.search(curpoint, epoint);
//调整视野
map.setViewport([spoint, curpoint, epoint]);
}else{
alert("您选择地址没有解析到结果!");
}
});
}else{
alert("您选择地址没有解析到结果!");
}
});

//获取位置
function getPosition() {
if(navigator.geolocation){
//navigator.geolocation.getCurrentPosition这个方法里面有三个参数
//这个会在界面拉出一个消息框,让用户确认是否允许获取位置,不过pc端我试了都是err,
//参1,成功后执行的函数
//参2,失败时执行的函数
//参3,选项配置,下面是在6000毫秒内结束请求
navigator.geolocation.getCurrentPosition(
function (position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
$('#lal').val(latitude+latitude);
},
/*function (error) {
//处理错误
switch (error.code) {
case 1:
alert("位置服务被拒绝。");
break;
case 2:
alert("暂时获取不到位置信息。");
break;
case 3:
alert("获取信息超时。");
break;
default:
alert("未知错误。");
break;
}
}*/
)
}
}
getPosition();
</script>
</div>
</div>
</div>
</div>
</body>
</html>

在该页面中最核心的代码是调用百度地图的api,该调用需要先申请ak密匙然后填入其中才可正确调用。

通过这样几步就能完成一个物流系统核心代码的编写。