# 智慧城市
**Repository Path**: flashing/smart-city
## Basic Information
- **Project Name**: 智慧城市
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2022-02-10
- **Last Updated**: 2022-02-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
通盘全局考虑; 能否完成; 时间
业务流程图: 还原真实场景
# 1 需求分析
系统主要分为三个角色, 分别是普通用户, 交管部门以及管理员, 不同的角色有不同的权限, 即角色专有功能; 除此之外系统还包括一些不同角色的公共功能.

初始思路为单页面应用,根据用户登录成功返回的用户类型, 设置url的查询参数, 再进行页面的渲染, 对应显示不同角色的特定功能

# 2 分工及业务流程
## 2.1 功能划分
根据**需求**以及**任务计划书**, 将系统功能进行**难易等级**划分, 并分配给不同的小组成员, 尽量使得分工合理.
[基于WebGIS的智慧交通系统》任务计划 (qq.com)](https://docs.qq.com/sheet/DSHJrSEx3bHpqek9D?tab=BB08J2)
## 2.2 甘特
[甘特计划表 (qq.com)](https://docs.qq.com/sheet/DSE5VbWVzdFl1aXlQ?tab=BB08J2)
## 2.3 业务流程
### 2.3.1 事件查询


### 2.3.2 实时路况

### 2.3.3 公告
#### 1) 发布公告

#### 2) 查看公告

### 2.3.4 登录注册

# 3 数据库设计
## 3.1 E-R图

## 3.2 数据表
### 3.2.1 用户信息表
记录用户的账号与密码等信息
| gg_user表:用户存储系统注册用户信息 | | | |
| ----------------------------------- | ----------- | -------------------------------------------------- | ---------- |
| 字段 | 类型 | 字段说明 | 键 |
| user_id | int | 用户唯一标识 | 主键,自增 |
| user_name | varchar(50) | 用户账号 | |
| user_password | varchar(50) | 用户面膜 | |
| user_type | varchar(20) | 管理员(admin)、交通部门(traffic)、普通用户(common) | |
| user_onlinestatus | int | 0表示未登录、1表示已登录 | |
| user_other | int | 0标表示用户已被删除、1表示用户未被删除 | |
### 3.2.2 实时路况表
记录实时路况的数据信息
实时路况表中车流量数据每十分钟自动更新一次, 车流量值暂时使用随机数
```sql
update gg_traffic set traffic_vehicleflow = floor(100 + rand()*600);
```
| gg_traffic表:存储实时路况信息 | | | |
| ------------------------------ | ------------ | ----------------------------- | ---------- |
| 字段 | 类型 | 字段说明 | 键 |
| traffic_id | int | 实时路况表唯一标识 | 主键,自增 |
| traffic_path | varchar(MAX) | 存储2个坐标,表示道路的一部分 | |
| traffic_road | varchar(50) | 存储该段路所属的道路名称 | |
| traffic_vehicleflow | int | 存储该段路中的车辆数据 | |
| traffic_time | datatime | 存储时间信息 | |
### 3.2.3 事件报告表
记录普通用户报告的事件信息
| gg_event表:存储用户报告的事件信息 | | | |
| ---------------------------------- | -------------- | ------------------------------------------------------------ | ---------- |
| 字段 | 类型 | 字段说明 | 键 |
| event_id | int | 事件表唯一标识 | 主键,自增 |
| user_id | int | 存储用户id,作为用户表的外键 | 外键 |
| event_type | nvarchar(50) | 存储事件类型 | |
| event_addr | nvarchar(50) | 存储事件发生的具体地址 | |
| event_mark | nvarchar(50) | 存储事件发生地址旁边的建筑标识,方便快速确认事件位置 | |
| event_time | datetime | 事件发生的时间信息 | |
| event_describe | nvarchar(1000) | 事件的描述 | |
| event_status | int | 事件的处理状态,0表示未处理,1、2表示已处理,1代表忽略,2代表通过 | |
### 3.2.4 施工公告表
记录交通部门发布的公告信息
| gg_notice表:存储发布公告的信息 | | | |
| ------------------------------- | -------------- | ------------------------------------------------ | --------------------- |
| 字段 | 类型 | 字段说明 | 键 |
| notice_id | int | 公告表唯一标识 | 主键,自增 |
| user_id | int | 存储用户id,用于确认那个交通部门人员发布公告信息 | 外键 |
| notice_content | nvarchar(1000) | 存储公告的信息 | |
| notice_time | timestamp | 存储公告的发布时间 | 默认CURRENT_TIMESTAMP |
| affected_area | nvarchar(1000) | 存储受影响的区域及小区电话 | |
### 3.2.5 事件管理表
| gg_checked_event表:存储核实后的交通事件 | | | |
| ---------------------------------------- | ------------ | ------------------------------------------------------- | ---------- |
| 字段 | 类型 | 字段说明 | 键 |
| checked_event_id | int | 事件表唯一标识 | 主键,自增 |
| TC_user_id | int | 存储交管部门用户id,作为用户表的外键 | 外键 |
| checked_event_type | varchar(50) | 存储事件类型 | notnull |
| checked_event_addr | varchar(50) | 存储事件发生的具体地址 | notnull |
| checked_event_time | datetime | 事件发生的时间信息 | notnull |
| checked_car_number | varchar(50) | 车牌号 | notnull |
| checked_car_driver | varchar(50) | 司机姓名 | notnull |
| checked_car_status | int | 事件的处理状态,0表示未处理,1表示正在处理,2表示已处理 | 默认为0 |
| checked_add_path | varchar(MAX) | 存储2个坐标,表示道路的一部分 | |
# 4 接口设计
## 4.1 公共功能接口
### 4.1.1 实时路况
```http
GET http://{{host}}/API/V1/all/gg_traffic
```
**接口描述**: 返回当前时刻的路况信息(道路名称, 车流量, 道路起始坐标)
**响应参数**:
| 参数名 | 类型 | 示例 | 可选 |
| --------------------------------------- | ------ | ------------------- | ---- |
| code | int | 1 | 必填 |
| message | string | 成功 | 必填 |
| result | object | | 必填 |
| result.roads | array | | 必填 |
| result.roads[index].traffic_path | string | 114,36;116,38 | 必填 |
| result.roads[index].traffic_road | string | 文华路 | 必填 |
| result.roads[index].traffic_vehicleflow | int | 200 | 必填 |
| result.roads[index].traffic_time | string | 2022-01-04 22:46:20 | 必填 |
**成功的响应示例**:
```js
{
code: 1
message: '成功',
result: {
roads: [
{
traffic_path: '114,36;116,38',
traffic_road: '文华路',
traffic_vehicleflow: 200,
traffic_time:'2022-01-04 22:46:20',
},
{
traffic_path: '114,36;116,38',
traffic_road: '文华路',
traffic_vehicleflow: 200,
traffic_time:'2022-01-04 22:46:20',
},
]
}
}
```
### 4.1.2 搜索框事件查询
从IG Server发布的数据服务中进行关键字查询
```js
const query_sql = new Query({
service: 'city',
layerID: '2',
})
const sql = document.querySelector('#sql').value
query_sql.queryBySql(sql, querySuccess)
```
不同角色查询到的内容稍微不同
*普通用户不能查询到某一个事件的车牌号、车主等隐私信息*
### 4.1.3 登录注册
#### 1) 登录
```http
POST http://{{host}}/API/V1/all/gg_user/login
```
> 请求示例
```js
$.ajax({
type: 'POST',
url: baseURL + '/all/gg_user/login',
data: JSON.stringify({
password: newPas,
username: username,
timestamp: timestamp,
}),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
})
```
> 响应示例
```js
{
code:0,
message:'登录成功',
result:{
data,
token,
}
}
```
#### 2) 注册
```http
POST http://{{host}}/API/V1/all/gg_user/register
```
> 请求示例
```js
$.ajax({
type: 'POST',
url: baseURL + '/all/gg_user/register',
data: JSON.stringify({
password: newPas,
username: username,
}),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
})
```
> 响应示例
```js
{
code:0,
message:'注册成功',
result:{
data,
token,
}
}
```
#### 3) 忘记密码
跳转至修改密码界面
验证方式:暂时还没想好
## 4.2 普通用户
### 4.2.1 查看公告
```http
GET http://{{host}}/API/V1/user/gg_notice
```
**接口描述**: 获取最新的公告记录
**响应参数**:
| 参数名 | 类型 | 示例 | 可选 |
| --------------------- | ------------------------------------ | ---- | ---- |
| code | int | 1 | 必填 |
| message | string | 成功 | 必填 |
| result | object | | 必填 |
| result.notice_content | string | | 必填 |
| result.notice_time | string | | 必填 |
| result.affected_area | string "金地中心城东区,长江职业学院" | | 必填 |
**成功的响应示例**:
```js
{
code: 1
message: '成功',
result: {
notice_content: '您好, 洪山区关山大道近期维修, 时间为2019年10月-2020年8月,请及时规划出行路线,避免对您的出行造成影响',
notice_time:'2019-10-26 10:33:20',
affected_area:"金地中心城东区,长江职业学院",
}
}
```
### 4.2.2 报告路况
```http
POST http://{{host}}/API/V1/user/gg_event
```
**接口描述**: 普通用户提交路况事件
**响应参数**:
| 参数名 | 类型 | 示例 | 可选 |
| ------------------------ | ------------ | ----------------------- | ------- |
| code | int | 1 | 必填 |
| message | string | 成功 | 必填 |
| result | object | | 必填 |
| result.event_type | varchar(50) | ['碰撞'] | 必填 |
| result.event_addr | varchar(50) | ['中山路'] | 必填 |
| result.event_mark | varchar(50) | ['新华书店'] | |
| result.event_time | datetime | ['2021/12/30 12:01:30'] | 必填 |
| result.event_description | varchar(255) | ['翻车了'] | |
| result.event_status | int | 不可修改 | 默认为0 |
**成功的响应示例**:
```js
{
code: 1
message: '成功',
result: {
event_type: '碰撞',
event_time:'2021/12/30 12:01:30',
event_addr:'中山路',
}
}
```
## 4.3 交管部门
### 4.3.1 交互式事件查询
从IG Server发布的数据服务中进行几何查询
```js
const query = new Query({
service: 'city', // 要查询的地图文档
layerID: 2, // 要查询的图层
})
query.queryByGeom(e.feature.getGeometry(), querySuccess)
```
将查询到的结果进行统计分析: 热力图, echarts图
### 4.3.2 发布公告
点击发布公告->交互式绘制维修道路线要素->缓冲区分析->与居民区进行叠加分析->弹框表单编辑公告信息框->发送
```http
POST http://{{host}}/API/V1/traffic/gg_notice
```
**接口描述**: 交管部门添加一条公告信息
**请求参数**:
| 参数名 | 类型 | 示例 | 可选 |
| -------------- | ------------------------------------- | -------- | ---- |
| user_id | int | 2 | 必填 |
| notice_content | string | 公告信息 | 必填 |
| affected_area | string "金地中心城东区,长江职业学院" | | 必填 |
**响应参数**:
| 参数名 | 类型 | 示例 | 可选 |
| ------- | ------ | ---- | ---- |
| code | int | 1 | 必填 |
| message | string | 成功 | 必填 |
**成功的响应示例**:
```js
{
code: 1
message: '成功',
}
```
### 4.3.3 事件处理
添加、查看、修改事件
```html
POST http://{{host}}/API/V1/traffic/gg_checked_event
GET http://{{host}}/API/V1/traffic/gg_checked_event
PUT http://{{host}}/API/V1/traffic/gg_checked_event
```
**接口描述**: 交管部门核实普通用户提交的路况信息后执行添加待办事件
**响应参数**:
| gg_checked_event | | | |
| ------------------------- | ----------- | ------------------------------ | ------------ |
| 字段 | 类型 | 示例 | 可选 |
| code | int | 1 | 必填 |
| message | string | 成功 | 必填 |
| result | object | | 必填 |
| result.checked_event_id | int | datatime+id | 必填 |
| result.checked_event_type | varchar(50) | 碰撞 | notnull |
| result.checked_event_addr | varchar(50) | 中山路 | notnull |
| result.checked_event_time | datetime | ['2021/12/30 12:01:30'] | notnull |
| result.checked_car_number | varchar(50) | 赣88888 | notnull |
| result.checked_car_driver | varchar(50) | 张三 | notnull |
| result.checked_car_status | enum | ['未处理','正在处理','已处理'] | 默认为未处理 |
**成功的响应示例**:
```js
{
code: 1
message: '成功',
result: {
result.checked_event_type: '碰撞',
result.checked_event_time:'2021/12/30 12:01:30',
result.checked_event_addr:'中山路',
result.checked_car_number:'赣88888',
result.checked_car_driver='张三',
result.checked_car_status='未处理',
}
}
```
## 4.4 管理员
### 4.4.1 用户模块管理
#### 1) 查询所有用户的数据
```http
GET http://{{host}}/API/V1/admin/gg_user
```
> 请求示例
```js
$.ajax({
type: 'GET',
url: baseURL + '/admin/gg_user',
})
```
> 响应示例
```js
{
code:0,
message:'获取所有用户信息成功',
result:{
data
}
}
```
#### 2) 根据id查询用户信息
```http
GET http://{{host}}/API/V1/admin/gg_user/:id
```
> 请求示例
```js
$.ajax({
type: 'GET',
url: baseURL + '/admin/gg_user/:id',
})
```
> 响应示例
```js
{
code:0,
message:'获取单个用户信息成功',
result:{
data
}
}
```
#### 3) 添加用户
```http
POST http://{{host}}/API/V1/admin/gg_user
```
> 请求示例
```js
$.ajax({
type: 'POST',
url: baseURL + '/admin/gg_user',
data: JSON.stringify({
password: newPas,
username: username,
usertype:usertype,
......
}),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
})
```
> 响应示例
```js
{
code:0,
message:'添加用户信息成功',
result:''
}
```
#### 4) 更新用户
```http
PUT http://{{host}}/API/V1/admin/gg_user/:id
```
> 请求示例
```js
$.ajax({
type: 'PUT',
url: baseURL + '/admin/gg_user/:id',
data: JSON.stringify({
userID: userID,
password: newPas,
username: username,
type:type,
......
}),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
})
```
> 响应示例
```js
{
code:0,
message:'更新用户信息成功',
result:{
data
}
}
```
#### 5) 删除用户
```http
DELETE http://{{host}}/API/V1/admin/gg_user/:id
```
> 请求示例
```js
DELETE /users/:id
$.ajax({
type: 'DELETE',
url: baseURL + '/admin/gg_user/:id',
data: JSON.stringify({
userID: userID,
}),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
})
```
> 响应示例
```js
{
code:0,
message:'删除用户信息成功',
result:''
}
```
####
# 5 项目实施
## 5.1 实时路况 currentRoadsLayer
> 操作说明
* 用户点击顶栏的实时路况, 则可开启实时路况的动态展示
* 再次点击, 则可关闭实时路况图层
#### 1) 随机数定时更新数据库
> 数据库每隔1秒自动更新车流量(随机数)
```sql
SET GLOBAL event_scheduler=1; //开启定时器
SHOW VARIABLES LIKE 'event_scheduler';
CREATE PROCEDURE update_gg_traffic() UPDATE gg_traffic set traffic_vehicleflow = floor(100 + rand()*600);
CREATE EVENT update_event
ON SCHEDULE EVERY 1 SECOND STARTS NOW() ON COMPLETION PRESERVE DO
CALL update_gg_traffic();
```
#### 2) 绘制openlayer线对象(几何+样式(分级设色)+属性)
> openlayer对象设置属性, 可以直接在实例化要素对象时设置
```js
//创建一个线要素(设置几何以及属性)
const currentRoadsFeature = new ol.Feature({
geometry: new ol.geom.LineString(line),
traffic_time,
traffic_road,
traffic_vehicleflow,
})
```
#### 3) 弹框显示属性值(地图点击事件获取要素对象)
## 5.2 事件查询 eventLayer
### 5.2.1 关键字查询
> 功能说明
用户在顶栏输入框输入要查询的关键字(如事件类型, 发生地点, 处理状态等)
点击提交按钮, 即可在地图上看到查询到的事件要素
在地图上点击事件要素, 可以查看对应的属性(不同角色看到的属性内容不同, 隐私保护)
点击清除按钮, 清除事件查询结果
> 流程说明
#### 1) 获取输入框值
#### 2) 中地属性查询接口
#### 3) 根据返回的数据绘制openlayer点要素对象(几何+属性+样式)
#### 4) 弹框
### 5.2.2 几何查询
> 操作说明
* 用户点击顶栏事件查询, 激活圆画笔
* 在地图上绘制需要查询的范围
* 绘制结束, 查询到的点会渲染到地图上, 点击可以查看事件属性
* 底部会出现弹框, 以表格的形式展示查询到的事件记录, 可以切换到统计分析或者热力图
* 点击右边的按钮可以控制折叠或显示弹框
* 点击`x`可以清除事件查询的结果并关闭弹框
## 5.3 公告
### 5.3.1 发布公告
> 操作说明(管理员/交管部门)
* 用户点击顶栏发布公告菜单, 即可获得交互式线画笔
* 绘制完施工道路, 弹出模态框, 用户可以看到施工道路影响区域的分析结果
* 在输入框中编辑公告内容(施工持续时间, 施工路段等信息)
* 点击发布公告按钮, 模态框关闭, 公告内容存入数据库
* 再次点击顶栏发布公告菜单, 缓冲分析+裁剪分析的图层移出地图
### 5.3.2 查看公告
> 操作说明(普通用户)
* 普通用户点击顶栏查看公告按钮,即可在模态框中查看当前最新的公告信息
## 5.4 小总结
#### 1) 鹰眼地图不显示的问题
在实例化鹰眼控件时, 需要加上view投影参数的设置
#### 2) 地图点击事件的监听
点击地图会返回搜索到的点击像元位置上的要素对象以及所属图层对象,
如果在实例化图层对象时加上name的设置, 就可以在map点击事件的回调中拿到图层名称layer.values_.name
这样可以方便根据不同的图层设置弹窗内容
#### 3) `ECharts`切换图表类型时, 配置合并的问题
```js
//第二个参数设置为true表示设置配置时不合并上次的配置, 默认是合并配置
myChart1.setOption(option, true)
```
#### 4) `tab`滑动门
切换tab标签时, 第一页显示正常, 但第二页显示时会加上第一页的高度
```css
/* 解决tab切换标签不正常显示的问题 */
.tab-content .tab-pane {
display: block; /* undo display:none */
height: 0; /* height:0 is also invisible */
overflow-y: hidden; /* no-overflow */
}
.tab-content .active {
height: auto; /* let the content decide it */
}
```
#### 5) 裁剪分析要素合并问题
裁剪分析有可能会出现将原来的一个面要素分割成两个面要素的问题, 目前还未找到中地相关接口来处理,
我的处理: 通过数组的方法, 将查询结果中重复的要素删除, 因为这里我希望在表格的展示中不会出现重复性区域, 也就是不重复通知受影响小区 (但最好的方法应该是在裁剪分析后合并被分割的要素, 或者采用其他空间分析方法)
```js
function removeDuplicate(arr) {
let len = arr.length
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i].AttValue[4] === arr[j].AttValue[4]) {
arr.splice(j, 1) //数组删除的方法, 改变了数组本身
len-- // 减少循环次数提高性能
j-- // 保证j的值自加后不变
}
}
}
return arr
}
```
#### 6) 动态生成的表格行 tr , 无法渲染出bootstrap样式效果
#### 7) 线要素缓冲分析的问题
```js
//注意中地接口构造线几何的方式(Point2D->Arc->AnyLine->Gline)
//线要素缓冲分析要设置线要素的几何信息Zondy.Object.FeatureGeometry({ LinGeom: [gline] })
const arc_points=[new Zondy.Object.Point2D(114, 36),...]
const gArc = new Zondy.Object.Arc(arc_points)
//构成线的折线
const gAnyLine = new Zondy.Object.AnyLine([gArc])
//设置线要素的几何信息
const gline = new Zondy.Object.GLine(gAnyLine)
//设置要素的几何信息
const fGeom = new Zondy.Object.FeatureGeometry({ LinGeom: [gline] })
```
#### 8) 项目改动说明-zj
* 添加了css, images, js/main, js/tools 文件夹
* interaction.js里面添加了绘制开始的回调
* style里添加了测量画布样式
* Tianditu.js里添加了支持导出图片跨域
* zd_docEdit.class.js修改了几何查询的方法, 添加了一个形参type
* index.html添加了控件/功能图层对象/画布, 定义了一些常量, 容器(弹框, footer, 发布和查看公告模态框), 引入文件js/css
## 5.5 合并的问题
地图点击事件冲突
画笔冲突(zj的那块)
导出图片画布污染