
乌兰察布市智慧公路管理平台
项目介绍 Link to 项目介绍
本系统涵盖多个子系统,每个子系统拥有独立的部门和角色数据。所有用户数据均在主系统中集中管理。 所有的子系统包含各自的业务模块,单独部署,方便维护和扩展并且支持第三方平台的接入。 其中资产管理系统、养护管理系统、信息发布系统均由原先的系统迁移过来,并做相应的修改,详情可以点击标题查看具体介绍。
- 门户主系统
- 控制子系统的访问权限,同时可以接入第三方平台。
- 一张图系统
- 所有子系统的图表显示,如路段状态、气象信息、车辆位置、视频播放等。
项目难点 Link to 项目难点
单点登录 Link to 单点登录
由于每个子系统部署在不同的服务器上,存在域名、端口号和协议不一致的情况。然而,所有用户数据均在主系统中集中管理。 为了解决这一问题,我们采用了通过地址栏加密传输token和projectId的方式来判断用户进入的是哪个子系统,类似于QQ中点击QQ邮箱可以实现免登的效果。
mqtt订阅 Link to mqtt订阅
系统需要获取路段上配置的雷达设备编号来订阅MQTT主题,实现实时展示车辆在路段上的行驶轨迹。地图上通过marker实时更新车辆位置, 并且在点击路段时打开弹窗展示路段详情,同时在弹窗中也展示车辆的实时位置。
海康视频流播放 Link to 海康视频流播放
系统默认使用video.js插件播放视频。如果用户安装了海康视频播放插件,则使用海康插件播放【video.js通过调用接口的形式实现,而海康插件则自带了这些功能仅需项目中引入SDK即可】 并支持以下功能:
- 旋转
- 聚焦
- 截图
- 回放
- 自主码流切换
- 录像
- 喊话
百度地图 Link to 百度地图
项目中存在大量的图层交互事件,因此我们在百度地图API的基础上封装了一套更通用化的百度地图Vue组件库,以方便后续维护。该组件库主要支持以下功能:
- 图层管理:添加和删除图层,包括点、线、多边形、文字、图片和自定义图层。
- 交互事件:支持图层的交互事件,例如点击点位时将该点位替换图标以区分是否选中。
- 图层动效:提供多种图层动效,如点位闪烁(预警效果)、区域边界绘制和线段动画。
- 点聚合:
- 支持指定层级聚合。
- 支持自定义聚合效果。
- 支持自定义聚合规则。
- 支持自定义聚合图标。
- 暴露鼠标事件以便进一步操作。
文件上传 Link to 文件上传
前面提到了利用海康视频插件来播放直播流,系统中就有个维护附件资源的功能, 其中海康插件内存占用大于500MB,导致上传附件时频繁崩溃,因此我们利用webwork实现大文件分片上传。
扫码登录 Link to 扫码登录
浙政钉、微信扫码登录【用户在后台扫码绑定微信或浙政钉授权码,绑定成功后,就可以通过扫码登录系统】
信息屏硬件对接 Link to 信息屏硬件对接
- 系统中配置好节目单【图片、文本、视频】
- 选择系统中维护的信息屏
- 调用硬件厂商提供的接口
- 实现信息屏节目的实时更新。
h5第三方授权免登 Link to h5第三方授权免登
养护h5是嵌套在第三方微信小程序里的,因此需实现第三方免登进入系统。 前提:第三方微信小程序登录账号的手机号在我们系统中已经注册 主要实现流程:
- 微信小程序登录,点击养护管理入口
- 小程序端将token和appid传给h5
- h5调用第三方系统接口,获取用户的手机号
- h5调用本系统接口,获取用户token和其他基础信息
- 成功免登跳转至系统首页
代码示例 Link to 代码示例
mqtt通用操作 Link to mqtt通用操作
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
var MqttTopics = [];
var MqttClients = [];
var connectUrl = CONFIG_g.VUE_APP_MQTT;
let Mqttserver = null;
// 接收mqtt
function screenMqtt(_topic, hostname, callback) {
connectUrl = CONFIG_sreen.VUE_APP_MQTT[hostname];
Mqtt(_topic, callback, hostname);
}
function Mqtt(_topic, callback, hostName) {
if (typeof _topic === "string") {
let MqttServer = getMqttServer(_topic, hostName);
MqttServer.client.on("message", (topic, message, packet) => {
if (callback) {
let payloadStr = new TextDecoder("utf-8").decode(message);
let msg = JSON.parse(payloadStr);
if(msg.data && typeof msg.data === 'string'){
msg.data = JSON.parse(msg.data)
}
callback(topic, msg, packet);
}
});
} else {
if (Array.isArray(_topic)) {
let topics = _topic;
topics.forEach((topic) => {
let MqttServer = getMqttServer(topic, hostName);
// console.log(MqttServer,'MqttServer');
MqttServer.client.subscribe(topic, (err) => {
if (!err) {
console.log("订阅成功");
}
});
// MqttServer.subscribe(topic, (err) => {
// if (!err) {
// console.log("订阅成功");
// }
// });
MqttServer.client.on("message", (topic, message, packet) => {
if (callback) {
let payloadStr = new TextDecoder("utf-8").decode(message);
if (!payloadStr) {
return;
}
let msg = JSON.parse(payloadStr);
if(msg.data && typeof msg.data === 'string'){
msg.data = JSON.parse(msg.data)
}
callback(topic, msg, packet);
}
});
});
} else {
console.log("_topic格式错误");
}
}
}
// 发送mqtt
function screenMqttPublish(_topic, hostname, message) {
connectUrl = CONFIG_sreen.VUE_APP_MQTT[hostname];
MqttPublish(_topic, message);
}
function MqttPublish(_topic, message) {
if (typeof _topic === "string") {
let MqttServer = getMqttServer(_topic);
MqttServer.publish(_topic, message);
} else {
if (Array.isArray(_topic)) {
let topics = _topic;
topics.forEach((topic) => {
let MqttServer = getMqttServer(topic);
MqttServer.publish(topic, message);
});
} else {
console.log("_topic格式错误");
}
}
}
// 取消订阅mqtt
function screenMqttUnsubscribe(_topic, hostname) {
connectUrl = CONFIG_sreen.VUE_APP_MQTT[hostname];
MqttUnsubscribe(_topic);
}
function MqttUnsubscribe(_topic) {
return new Promise((resolve) => {
if (typeof _topic === "string") {
let MqttServer = getMqttServer(_topic);
if (MqttServer.client && MqttServer.client.connected) {
MqttServer.unsubscribe(_topic);
removeMqttServer(_topic);
resolve();
}
} else {
if (Array.isArray(_topic)) {
let topics = _topic;
topics.forEach((topic) => {
let MqttServer = getMqttServer(topic);
if (MqttServer.client && MqttServer.client.connected) {
MqttServer.unsubscribe(topic);
removeMqttServer(topic);
resolve();
}
});
} else {
console.log("_topic格式错误");
}
}
});
}
function getMqttServer(_topic,hostName) {
if(hostName){
Mqttserver = MqttClients.find(clients => clients.hostName === hostName)
if(Mqttserver) {
return Mqttserver
}else{
// 没有订阅过该topic
console.log("未订阅=>" + _topic);
Mqttserver = new MqttApi(connectUrl, _topic, hostName);
MqttTopics.push(_topic);
MqttClients.push(Mqttserver);
return Mqttserver
}
}
if (MqttTopics.indexOf(_topic) != -1) {
// 已经订阅过该topic
console.log("已订阅=>" + _topic);
MqttTopics.forEach((topic, index) => {
if (topic === _topic) {
Mqttserver = MqttClients[index];
}
});
} else {
// 没有订阅过该topic
console.log("未订阅=>" + _topic);
Mqttserver = new MqttApi(connectUrl, _topic, hostName);
MqttTopics.push(_topic);
MqttClients.push(Mqttserver);
}
return Mqttserver;
}
function removeMqttServer(_topic) {
MqttTopics.forEach((topic, index) => {
if (topic === _topic) {
MqttTopics.splice(index, 1);
MqttClients.splice(index, 1);
return;
}
});
console.log(MqttTopics);
console.log(MqttClients);
}
class MqttApi {
client = null;
hostName;
constructor(connectUrl, topic, hostName) {
console.log(connectUrl,'connectUrl');
this.hostName = hostName
const options = {
keepalive: 60, // 默认60秒,设置0为禁用
clean: true, // 设置为false以在脱机时接收QoS 1和2消息
clientId: "mqttjs_" + Math.random().toString(16).substr(2, 8),
protocolId: "MQTT",
protocolVersion: 4, //MQTT 协议版本号,默认为 4(v3.1.1)可以修改为 3(v3.1)和 5(v5.0)
reconnectPeriod: 4000, //设置多长时间进行重新连接 单位毫秒 两次重新连接之间的时间间隔。通过将设置为,禁用自动重新连接0
connectTimeout: 30 * 1000, // 收到CONNACK之前等待的时间
};
this.client = mqtt.connect(connectUrl, options);
this.client.on("connect", (connack) => {
console.log("链接成功");
if (topic) {
this.client.subscribe(topic, (err) => {
if (!err) {
console.log("订阅成功");
}
});
}
});
this.client.on("reconnect", function (error) {
if (error) {
// console.log(error)
} else {
console.log("正在重连.....");
}
});
this.client.on("close", function (error) {
if (error) {
// console.log(error)
} else {
console.log("客户端已断开.....");
}
});
this.client.on("offline", function (error) {
if (error) {
console.log(error);
} else {
console.log("offline.....");
}
});
//当客户端无法连接或出现错误时触发回调
this.client.on("error", (error) => {
console.log("客户端出现错误....." + error);
});
this.client.on("packetsend", (packet) => {
if (packet && packet.payload) {
console.log("客户端已发出数据包....." + packet.payload);
}
});
}
// 断开链接
disconnect() {
try {
if (this.client && this.client.connected) {
console.log("断开连接");
this.client.end();
}
} catch (error) {
console.log(error);
}
}
// 重新链接
reconnect() {
this.client.reconnect();
}
// 关闭
close() {
try {
if (this.client && this.client.connected) {
this.client.end();
this.client = null;
}
} catch (error) {
console.log(error);
}
}
// 发布消息
publish(topic, message) {
// if (this.client && this.client.connected) {
if (this.client) {
this.client.publish(topic, JSON.stringify(message), (error) => {
if (error) {
console.log(error);
} else {
console.log("发布消息成功");
}
});
}
}
// 订阅主题
subscribe(topic) {
if (this.client && this.client.connected) {
console.log(this,'clicent');
this.client.subscribe(topic, function (error, granted) {
if (error) {
console.log(error,'error');
} else {
console.log(`${granted[0].topic} 订阅成功`);
}
});
}
}
// 取消订阅
unsubscribe(topic) {
if (this.client && this.client.connected) {
this.client.unsubscribe(topic, (error) => {
if (error) {
console.log(error);
} else {
console.log("取消订阅成功");
}
});
}
}
}
乌兰察布市智慧公路管理平台
Copyright © 毛杭飞 2025 - All Rights Reserved