mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-17 08:25:53 +08:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java # springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java # springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java # springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml # springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
- EMQ管理: Mqtt客户端、监听器、消息主题、消息订阅、插件管理、规则引擎、资源
|
||||
- 硬件 SDK: 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报监测数据、AES加密、NTP时间等
|
||||
- 物模型管理: 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端)
|
||||
- 其他(开发中):第三方登录,设备分享、设备告警、场景联动(进度50%),智能音箱、多租户、APP界面自定义(进度40%),时序数据库、分布式集群部署、Granfa监控(进度30%),视频流处理、桌面端模拟器/监控、安卓端模拟器/监控(进度20%)
|
||||
- 其他(开发中):第三方登录,设备分享、设备告警、场景联动(进度50%); 智能音箱、多租户、APP界面自定义(进度40%); 时序数据库、分布式集群部署、Granfa监控(进度30%); 视频流处理、桌面端模拟器/监控、安卓端模拟器/监控(进度20%)
|
||||
|
||||
|
||||
### 四、技术栈
|
||||
@@ -74,7 +74,7 @@
|
||||
* [权限管理系统ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue)
|
||||
* [Mqtt消息服务器EMQX4.0](https://github.com/emqx/emqx)
|
||||
* [ESP8266 Core For Arduino](https://github.com/esp8266/Arduino)
|
||||
* [uCharts高性能跨平台图标库](https://www.ucharts.cn)
|
||||
* [uCharts高性能跨平台图表库](https://www.ucharts.cn)
|
||||
##### Docker快速安装
|
||||
* Mysql中创建wumei-smart数据库,[导入Sql脚本](https://gitee.com/kerwincui/wumei-smart/tree/master/springboot/sql)
|
||||
* 修改命令中的Mysql配置,并执行
|
||||
@@ -104,8 +104,8 @@ kerwincui/wumei-smart:1.1
|
||||
|
||||
##### 项目贡献者
|
||||
|
||||
|[小驿物联](https://gitee.com/iot-xiaoyi) |[Guanshubiao](https://gitee.com/guanshubiao)|[CrazyDull](https://gitee.com/crazyDull) |[Kami0314](https://github.com/kami0314)|
|
||||
|--|--|--|--|
|
||||
|[小驿物联](https://gitee.com/iot-xiaoyi) |[Guanshubiao](https://gitee.com/guanshubiao)|[CrazyDull](https://gitee.com/crazyDull) |[Kami0314](https://github.com/kami0314)|[YBZX](https://github.com/YBZX)
|
||||
|--|--|--|--|--|
|
||||
|
||||
| [SXH](https://gitee.com/sixiaohu) | [Redamancy_zxp](https://gitee.com/redamancy-zxp) | [LEE](https://gitee.com/yueming188) | [LemonTree](https://gitee.com/fishhunterplus) | [Tang](https://gitee.com/mexiaotang)
|
||||
|--|--|--|--|--|
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#### 四、通过赞助、贡献代码、推广可以加入项目内部,里面包含移动端源码和更多相关教程,并且获得一年的免费更新。目前项目还在完善,教程暂无,赞助费暂定1500元。可以通过官网[http://wumei.live/](http://wumei.live/) 注册账号,联系作者加入项目内部。
|
||||
|
||||
##### 项目开发交流群:【946029159】,作者QQ: 【164770707】
|
||||
##### 项目开发交流群:【946029159】,项目互助交流群:【1073236354】,作者QQ: 【164770707】
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
## 硬件端树莓派SDK说明
|
||||
|
||||
#### 一、运行环境
|
||||
- Python 3.7.2 (其他python3的版本一般也可以)
|
||||
- 开发板:树莓派4b(没有加入硬件相关代码,安装好python3环境,win下,linux下都能运行)
|
||||
- 库 需要安装库
|
||||
|
||||
1. mqtt库
|
||||
|
||||
```
|
||||
pip install paho-mqtt
|
||||
```
|
||||
|
||||
2. ase加密库
|
||||
|
||||
```
|
||||
# 前面两个卸载命令是为了防止一些安装环境问题
|
||||
pip uninstall crypto
|
||||
pip uninstall pycryptodome
|
||||
pip install pycryptodome
|
||||
```
|
||||
|
||||
|
||||
3. 报错缺少xx库,命令
|
||||
|
||||
```
|
||||
pip install xx
|
||||
```
|
||||
|
||||
|
||||
#### 二、运行程序
|
||||
|
||||
```
|
||||
python3 main_sdk.py
|
||||
|
||||
# 备注:程序运行依赖aes.py文件,保证该文件和main_sdk.py在同一目录
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 三、开发参考资料:
|
||||
|
||||
- [Eclipse Paho MQTT Python Client 使用手册](https://www.cooooder.com/archives/20210303)
|
||||
- 更多参考资料,下载目录中的文本文件查看
|
||||
|
||||
|
||||
210
sdk/RaspberryPi/aes.py
Normal file
210
sdk/RaspberryPi/aes.py
Normal file
@@ -0,0 +1,210 @@
|
||||
from Crypto.Cipher import AES
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
|
||||
# 数据类
|
||||
class MData():
|
||||
def __init__(self, data = b"",characterSet='utf-8'):
|
||||
# data肯定为bytes
|
||||
self.data = data
|
||||
self.characterSet = characterSet
|
||||
|
||||
def saveData(self,FileName):
|
||||
with open(FileName,'wb') as f:
|
||||
f.write(self.data)
|
||||
|
||||
def fromString(self,data):
|
||||
self.data = data.encode(self.characterSet)
|
||||
return self.data
|
||||
|
||||
def fromBase64(self,data):
|
||||
self.data = base64.b64decode(data.encode(self.characterSet))
|
||||
return self.data
|
||||
|
||||
def fromHexStr(self,data):
|
||||
self.data = binascii.a2b_hex(data)
|
||||
return self.data
|
||||
|
||||
def toString(self):
|
||||
return self.data.decode(self.characterSet)
|
||||
|
||||
def toBase64(self):
|
||||
return base64.b64encode(self.data).decode() #decode()转成字符串形式,否则为字节型数据
|
||||
|
||||
def toHexStr(self):
|
||||
return binascii.b2a_hex(self.data).decode()
|
||||
|
||||
def toBytes(self):
|
||||
return self.data
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
return self.toString()
|
||||
except Exception:
|
||||
return self.toBase64()
|
||||
|
||||
|
||||
### 封装类
|
||||
class AEScryptor():
|
||||
def __init__(self,key,mode,iv = '',paddingMode= "NoPadding",characterSet ="utf-8"):
|
||||
'''
|
||||
构建一个AES对象
|
||||
key: 秘钥,字节型数据
|
||||
mode: 使用模式,只提供两种,AES.MODE_CBC, AES.MODE_ECB
|
||||
iv: iv偏移量,字节型数据
|
||||
paddingMode: 填充模式,默认为NoPadding, 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
|
||||
characterSet: 字符集编码
|
||||
'''
|
||||
self.key = key
|
||||
self.mode = mode
|
||||
self.iv = iv
|
||||
self.characterSet = characterSet
|
||||
self.paddingMode = paddingMode
|
||||
self.data = ""
|
||||
|
||||
def __ZeroPadding(self,data):
|
||||
data += b'\x00'
|
||||
while len(data) % 16 != 0:
|
||||
data += b'\x00'
|
||||
return data
|
||||
|
||||
def __StripZeroPadding(self,data):
|
||||
data = data[:-1]
|
||||
while len(data) % 16 != 0:
|
||||
data = data.rstrip(b'\x00')
|
||||
if data[-1] != b"\x00":
|
||||
break
|
||||
return data
|
||||
|
||||
def __PKCS5_7Padding(self,data):
|
||||
needSize = 16-len(data) % 16
|
||||
if needSize == 0:
|
||||
needSize = 16
|
||||
return data + needSize.to_bytes(1,'little')*needSize
|
||||
|
||||
def __StripPKCS5_7Padding(self,data):
|
||||
paddingSize = data[-1]
|
||||
return data.rstrip(paddingSize.to_bytes(1,'little'))
|
||||
|
||||
def __paddingData(self,data):
|
||||
if self.paddingMode == "NoPadding":
|
||||
if len(data) % 16 == 0:
|
||||
return data
|
||||
else:
|
||||
return self.__ZeroPadding(data)
|
||||
elif self.paddingMode == "ZeroPadding":
|
||||
return self.__ZeroPadding(data)
|
||||
elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
|
||||
return self.__PKCS5_7Padding(data)
|
||||
else:
|
||||
print("不支持Padding")
|
||||
|
||||
def __stripPaddingData(self,data):
|
||||
if self.paddingMode == "NoPadding":
|
||||
return self.__StripZeroPadding(data)
|
||||
elif self.paddingMode == "ZeroPadding":
|
||||
return self.__StripZeroPadding(data)
|
||||
|
||||
elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
|
||||
return self.__StripPKCS5_7Padding(data)
|
||||
else:
|
||||
print("不支持Padding")
|
||||
|
||||
def setCharacterSet(self,characterSet):
|
||||
'''
|
||||
设置字符集编码
|
||||
characterSet: 字符集编码
|
||||
'''
|
||||
self.characterSet = characterSet
|
||||
|
||||
def setPaddingMode(self,mode):
|
||||
'''
|
||||
设置填充模式
|
||||
mode: 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
|
||||
'''
|
||||
self.paddingMode = mode
|
||||
|
||||
def decryptFromBase64(self,entext):
|
||||
'''
|
||||
从base64编码字符串编码进行AES解密
|
||||
entext: 数据类型str
|
||||
'''
|
||||
mData = MData(characterSet=self.characterSet)
|
||||
self.data = mData.fromBase64(entext)
|
||||
return self.__decrypt()
|
||||
|
||||
def decryptFromHexStr(self,entext):
|
||||
'''
|
||||
从hexstr编码字符串编码进行AES解密
|
||||
entext: 数据类型str
|
||||
'''
|
||||
mData = MData(characterSet=self.characterSet)
|
||||
self.data = mData.fromHexStr(entext)
|
||||
return self.__decrypt()
|
||||
|
||||
def decryptFromString(self,entext):
|
||||
'''
|
||||
从字符串进行AES解密
|
||||
entext: 数据类型str
|
||||
'''
|
||||
mData = MData(characterSet=self.characterSet)
|
||||
self.data = mData.fromString(entext)
|
||||
return self.__decrypt()
|
||||
|
||||
def decryptFromBytes(self,entext):
|
||||
'''
|
||||
从二进制进行AES解密
|
||||
entext: 数据类型bytes
|
||||
'''
|
||||
self.data = entext
|
||||
return self.__decrypt()
|
||||
|
||||
def encryptFromString(self,data):
|
||||
'''
|
||||
对字符串进行AES加密
|
||||
data: 待加密字符串,数据类型为str
|
||||
'''
|
||||
self.data = data.encode(self.characterSet)
|
||||
return self.__encrypt()
|
||||
|
||||
def __encrypt(self):
|
||||
if self.mode == AES.MODE_CBC:
|
||||
aes = AES.new(self.key,self.mode,self.iv)
|
||||
elif self.mode == AES.MODE_ECB:
|
||||
aes = AES.new(self.key,self.mode)
|
||||
else:
|
||||
print("不支持这种模式")
|
||||
return
|
||||
|
||||
data = self.__paddingData(self.data)
|
||||
enData = aes.encrypt(data)
|
||||
return MData(enData)
|
||||
|
||||
def __decrypt(self):
|
||||
if self.mode == AES.MODE_CBC:
|
||||
aes = AES.new(self.key,self.mode,self.iv)
|
||||
elif self.mode == AES.MODE_ECB:
|
||||
aes = AES.new(self.key,self.mode)
|
||||
else:
|
||||
print("不支持这种模式")
|
||||
return
|
||||
data = aes.decrypt(self.data)
|
||||
# mData = MData(self.__stripPaddingData(data),characterSet=self.characterSet)
|
||||
# return mData()
|
||||
return MData(self.__stripPaddingData(data),characterSet=self.characterSet)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
key = b"1234567812345678"
|
||||
iv = b"0000000000000000"
|
||||
aes = AEScryptor(key,AES.MODE_CBC,iv,paddingMode= "ZeroPadding",characterSet='utf-8')
|
||||
|
||||
data = "好好学习"
|
||||
rData = aes.encryptFromString(data)
|
||||
print("密文:",rData.toBase64())
|
||||
rData = aes.decryptFromBase64(rData.toBase64())
|
||||
print("明文:",rData)
|
||||
# ————————————————
|
||||
# 版权声明:本文为CSDN博主「Hello_wshuo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
||||
# 原文链接:https://blog.csdn.net/chouzhou9701/article/details/122019967
|
||||
335
sdk/RaspberryPi/main_sdk.py
Normal file
335
sdk/RaspberryPi/main_sdk.py
Normal file
@@ -0,0 +1,335 @@
|
||||
# /***********************************************************
|
||||
# * author: xiaoY [物美智能 wumei-smart]
|
||||
# * create: 2022-05-10
|
||||
# * email:qimint@outlook.com
|
||||
# * source:https://github.com/kerwincui/wumei-smart
|
||||
# * board:raspberry 4b
|
||||
# ***********************************************************/
|
||||
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
from aes import AEScryptor,AES
|
||||
import paho.mqtt.client as mqtt
|
||||
import random
|
||||
import threading #导入线程模块,用作定时器
|
||||
|
||||
#################################################################
|
||||
# 需要连接好外部网络
|
||||
#################################################################
|
||||
|
||||
# 作为python的AES的iv,应该为16位,字节型数据
|
||||
wumei_iv = b"wumei-smart-open"
|
||||
|
||||
# NTP地址(用于获取时间,可选的修改为自己部署项目的地址)
|
||||
ntpServer = "http://120.24.218.158:8080/iot/tool/ntp?deviceSendTime="
|
||||
|
||||
# 设备信息配置
|
||||
deviceNum = "DW43CI6RM8GMG23H"
|
||||
userId = "1"
|
||||
productId = "4"
|
||||
firmwareVersion = "1.0"
|
||||
# Mqtt配置
|
||||
mqttHost = "120.24.218.158"
|
||||
|
||||
mqttPort = 1883
|
||||
mqttUserName = "wumei-smart"
|
||||
mqttPwd = "P261I5G3RY3MCIGG"
|
||||
# 作为python的AES的key,应该为16位,字节型数据
|
||||
mqttSecret = b"K2IB784BM0O01GG6"
|
||||
|
||||
monitorCount =5 #发布监测数据的最大次数
|
||||
# 使用esp8266单片机时,服务器传来的间隔单位为毫秒,本程序由于定时运行需要的是秒,将转化为秒,如需毫秒运行,自行更改程序
|
||||
monitorInterval =5 # 发布监测数据的间隔,默认5秒
|
||||
|
||||
g_rc=-1 # 连接成功标志位
|
||||
|
||||
global t2 #全局变量,管理定时监测
|
||||
|
||||
|
||||
|
||||
|
||||
# 订阅的主题
|
||||
prefix = "/" + productId + "/" + deviceNum
|
||||
sOtaTopic = prefix + "/ota/get"
|
||||
sNtpTopic = prefix + "/ntp/get"
|
||||
sPropertyTopic = prefix + "/property/get"
|
||||
sFunctionTopic = prefix + "/function/get"
|
||||
sPropertyOnline = prefix + "/property-online/get"
|
||||
sFunctionOnline = prefix + "/function-online/get"
|
||||
sMonitorTopic = prefix + "/monitor/get"
|
||||
# 发布的主题
|
||||
pInfoTopic = prefix + "/info/post"
|
||||
pNtpTopic = prefix + "/ntp/post"
|
||||
pPropertyTopic = prefix + "/property/post"
|
||||
pFunctionTopic = prefix + "/function/post"
|
||||
pMonitorTopic = prefix + "/monitor/post"
|
||||
pEventTopic = prefix + "/event/post"
|
||||
|
||||
# 初始化
|
||||
# 连接(客户端ID = 设备编号 & 产品ID)
|
||||
clientId = deviceNum + "&" + productId
|
||||
client=mqtt.Client(clientId)
|
||||
|
||||
#加密 (AES-CBC-128-pkcs5padding)
|
||||
def encrypt(plain_data,wumei_key,wumei_iv):
|
||||
aes=AEScryptor(wumei_key,AES.MODE_CBC,wumei_iv,paddingMode="PKCS5Padding",characterSet='utf-8')
|
||||
rData=aes.encryptFromString(plain_data)
|
||||
printMsg("密码(已加密):"+rData.toBase64())
|
||||
return rData.toBase64()
|
||||
|
||||
#回调函数。当尝试与MQTT broker 建立连接时,触发该函数。
|
||||
#client 是本次连接的客户端实例。
|
||||
#userdata 是用户的信息,一般为空。但如果有需要,也可以通过 user_data_set 函数设置。
|
||||
#flags 保存服务器响应标志的字典
|
||||
#rc 是响应码。
|
||||
# 0: 连接成功
|
||||
# 1: 连接失败-不正确的协议版本
|
||||
# 2: 连接失败-无效的客户端标识符
|
||||
# 3: 连接失败-服务器不可用
|
||||
# 4: 连接失败-错误的用户名或密码
|
||||
# 5: 连接失败-未授权
|
||||
# 6-255: 未定义.
|
||||
#一般情况下,我们只需要关注rc响应码是否为0就可以了。
|
||||
def on_connect(client,userdata,flags,rc):
|
||||
if rc==0:
|
||||
printMsg("连接成功")
|
||||
# 放在on_connect下可以保证重连重新订阅
|
||||
# 订阅(OTA、NTP、属性、功能、实时监测)
|
||||
|
||||
client.subscribe(sOtaTopic, 1)
|
||||
client.subscribe(sNtpTopic, 1)
|
||||
client.subscribe(sPropertyTopic, 1)
|
||||
client.subscribe(sFunctionTopic, 1)
|
||||
client.subscribe(sPropertyOnline, 1)
|
||||
client.subscribe(sFunctionOnline, 1)
|
||||
client.subscribe(sMonitorTopic, 1)
|
||||
|
||||
printMsg("订阅主题:" + sOtaTopic)
|
||||
printMsg("订阅主题:" + sNtpTopic)
|
||||
printMsg("订阅主题:" + sPropertyTopic)
|
||||
printMsg("订阅主题:" + sFunctionTopic)
|
||||
printMsg("订阅主题:" + sPropertyOnline)
|
||||
printMsg("订阅主题:" + sFunctionOnline)
|
||||
printMsg("订阅主题:" + sMonitorTopic)
|
||||
# 发布设备信息
|
||||
publishInfo()
|
||||
global g_rc
|
||||
g_rc=0
|
||||
else:
|
||||
printMsg("连接失败,rc="+str(rc))
|
||||
printMsg("3秒后重连...")
|
||||
time.sleep(3)
|
||||
connectMqtt()
|
||||
|
||||
# 物模型-属性处理
|
||||
def processProperty(payload):
|
||||
data=json.loads(payload)
|
||||
for item in data:
|
||||
# 匹配云端定义的属性(不包含属性中的监测数据)
|
||||
id = item["id"]
|
||||
value=item["value"]
|
||||
printMsg(str(id)+":"+str(value))
|
||||
# 最后发布属性,服务端订阅存储(重要)
|
||||
publishProperty(json.dumps(data))
|
||||
|
||||
# 物模型-功能处理
|
||||
def processFunction(payload):
|
||||
data=json.loads(payload)
|
||||
for item in data:
|
||||
# 匹配云端定义的功能
|
||||
id = item["id"]
|
||||
value=item["value"]
|
||||
if(id=="switch"):
|
||||
printMsg("开关 switch:"+ str(value))
|
||||
elif(id=="gear"):
|
||||
printMsg("档位 gear:"+ str(value))
|
||||
elif(id=="light_color"):
|
||||
printMsg("灯光颜色 light_color:"+ str(value))
|
||||
elif(id=="message"):
|
||||
printMsg("屏显消息 message:"+ str(value))
|
||||
elif(id=="report_monitor"):
|
||||
msg=randomPropertyData();
|
||||
printMsg("订阅到上报监测数据指令,上报数据:")
|
||||
printMsg(msg)
|
||||
publishProperty(msg)
|
||||
# 最后发布属性,服务端订阅存储(重要)
|
||||
publishProperty(json.dumps(data))
|
||||
|
||||
# 回调函数,在客户端订阅的主题上接收到消息时调用,“message”变量是一个MQTT消息描述所有消息特征
|
||||
def on_message(client,userdata,msg):
|
||||
printMsg("接收数据:"+msg.topic+" "+str(msg.payload))
|
||||
if(msg.topic==sOtaTopic):
|
||||
printMsg("订阅到设备升级指令...")
|
||||
elif(msg.topic==sNtpTopic):
|
||||
printMsg("订阅到NTP时间...");
|
||||
jsonData=json.loads(msg.payload)
|
||||
deviceSendTime = jsonData["deviceSendTime"]
|
||||
serverSendTime = jsonData["serverSendTime"]
|
||||
serverRecvTime = jsonData["serverRecvTime"]
|
||||
deviceRecvTime = round(time.time()*1000)
|
||||
now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2
|
||||
printMsg("当前时间:"+str(round(now)))
|
||||
elif(msg.topic==sPropertyTopic or msg.topic==sPropertyOnline):
|
||||
printMsg("订阅到属性指令...")
|
||||
processProperty(msg.payload)
|
||||
elif(msg.topic==sFunctionTopic or msg.topic==sFunctionOnline):
|
||||
printMsg("订阅到功能指令...")
|
||||
processFunction(msg.payload)
|
||||
elif(msg.topic==sMonitorTopic):
|
||||
# python全局变量的使用
|
||||
global t2
|
||||
global monitorCount
|
||||
global monitorInterval
|
||||
printMsg("订阅到实时监测指令...")
|
||||
jsonData=json.loads(msg.payload)
|
||||
monitorCount = jsonData["count"]
|
||||
monitorInterval = jsonData["interval"]/1000
|
||||
t2.cancel()
|
||||
t2=threading.Timer(monitorInterval,timing_publishMonitor)
|
||||
t2.start()
|
||||
|
||||
# 1.发布设备信息
|
||||
def publishInfo():
|
||||
# rssi值 树莓派中暂时不处理wifi信号问题
|
||||
# 信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85])
|
||||
# status值 (1-未激活,2-禁用,3-在线,4-离线)
|
||||
doc={"rssi":1,"firmwareVersion":firmwareVersion,"status":3,"userId":userId}
|
||||
# client.publish('raspberry/topic',payload=i,qos=0,retain=False)
|
||||
jsonData=json.dumps(doc)
|
||||
printMsg("发布设备信息:"+pInfoTopic+" "+jsonData)
|
||||
client.publish(pInfoTopic,jsonData)
|
||||
|
||||
# 2.发布时钟同步信,用于获取当前时间(可选)
|
||||
def publishNtp():
|
||||
data={"deviceSendTime":round(time.time()*1000)}
|
||||
jsonData=json.dumps(data)
|
||||
printMsg("发布NTP信息"+jsonData)
|
||||
client.publish(pNtpTopic,jsonData)
|
||||
|
||||
# 3.发布属性
|
||||
# msg 接收格式json
|
||||
def publishProperty(msg):
|
||||
printMsg("发布属性:" + msg)
|
||||
client.publish(pPropertyTopic, msg)
|
||||
|
||||
# 4.发布功能
|
||||
def publishFunction( msg):
|
||||
printMsg("发布功能:" + msg)
|
||||
client.publish(pFunctionTopic, msg)
|
||||
|
||||
# 5.发布事件
|
||||
def publishEvent():
|
||||
objTmeperature={"id":"height_temperature","value":40,"remark":"温度过高警告"}
|
||||
objException={"id":"exception","value":"异常消息,消息内容XXXXXXXX","remark":"设备发生错误"}
|
||||
data=[objTmeperature,objException]
|
||||
jsonData=json.dumps(data)
|
||||
printMsg("发布事件:"+jsonData)
|
||||
client.publish(pEventTopic,jsonData)
|
||||
|
||||
# 6.发布实时监测数据
|
||||
def publishMonitor():
|
||||
msg=randomPropertyData()
|
||||
# 发布为实时监测数据,不会存储
|
||||
printMsg("发布实时监测数据:"+msg)
|
||||
client.publish(pMonitorTopic,msg)
|
||||
|
||||
# 随机生成监测值
|
||||
def randomPropertyData():
|
||||
# 匹配云端定义的监测数据,随机数代替监测结果
|
||||
# random.randint(0,10) #生成数据包括0,10
|
||||
# random.uniform(30,60)生成数据为浮点型
|
||||
objTmeperature={"id":"temperature","value":str(round(random.uniform(10,30),2)),"remark":""}
|
||||
objHumidity={"id":"humidity","value":str(round(random.uniform(30,60),2)),"remark":""}
|
||||
objCo2={"id":"co2","value":str(random.randint(400,1000)),"remark":""}
|
||||
objBrightness={"id":"brightness","value":str(random.randint(1000,10000)),"remark":""}
|
||||
printMsg("随机生成监测数据值:")
|
||||
data=[objTmeperature,objHumidity,objCo2,objBrightness]
|
||||
print(json.dumps(data))
|
||||
return json.dumps(data)
|
||||
|
||||
#连接mqtt
|
||||
def connectMqtt():
|
||||
printMsg("连接Mqtt服务器")
|
||||
# 生成mqtt认证密码(密码 = mqtt密码 & 用户ID & 过期时间)
|
||||
password = generationPwd()
|
||||
encryptPassword=encrypt(password,mqttSecret,wumei_iv)
|
||||
# 生成mqtt认证密码(密码 = mqtt密码 & 用户ID & 过期时间)
|
||||
client.username_pw_set(mqttUserName,encryptPassword)
|
||||
client.on_connect=on_connect
|
||||
client.on_message=on_message
|
||||
client.connect(mqttHost,mqttPort,10)
|
||||
|
||||
|
||||
|
||||
|
||||
#打印提示信息
|
||||
def printMsg(msg):
|
||||
print("[{}] {}".format(time.strftime("%Y-%m-%d %H:%M:%S"),msg))
|
||||
# 生成密码
|
||||
def generationPwd():
|
||||
try:
|
||||
doc=json.loads(getTime())
|
||||
except:
|
||||
printMsg("Json解析失败")
|
||||
exit()
|
||||
deviceSendTime = doc["deviceSendTime"]
|
||||
serverSendTime = doc["serverSendTime"]
|
||||
serverRecvTime = doc["serverRecvTime"]
|
||||
deviceRecvTime = round(time.time()*1000)
|
||||
now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2
|
||||
expireTime = int(now + 1 * 60 * 60 * 1000)
|
||||
password = mqttPwd + "&" + userId + "&" + str(expireTime)
|
||||
printMsg("密码(未加密):" + password)
|
||||
return password
|
||||
# HTTP获取时间
|
||||
def getTime():
|
||||
try:
|
||||
r=requests.get(ntpServer+str(round(time.time()*1000)))
|
||||
if(r.status_code>0):
|
||||
if(r.status_code==200 or r.status_code==301):
|
||||
printMsg("获取时间成功,data:"+r.text)
|
||||
return r.text
|
||||
else:
|
||||
printMsg("获取时间失败,error:"+r.status_code)
|
||||
except:
|
||||
printMsg("连接Http失败")
|
||||
|
||||
|
||||
def timing_publishProperty():
|
||||
printMsg("执行定时上报")
|
||||
#发布事件
|
||||
publishEvent()
|
||||
#发布时钟同步
|
||||
publishNtp()
|
||||
# 发布属性(监测值)
|
||||
msg=randomPropertyData()
|
||||
publishProperty(msg)
|
||||
t1=threading.Timer(60,timing_publishProperty)
|
||||
t1.start()
|
||||
def timing_publishMonitor():
|
||||
global monitorCount
|
||||
monitorCount=monitorCount-1
|
||||
printMsg("执行监测")
|
||||
publishMonitor()
|
||||
if(monitorCount>0):
|
||||
t2=threading.Timer(monitorInterval,timing_publishMonitor)
|
||||
t2.start()
|
||||
|
||||
if __name__ == '__main__':
|
||||
connectMqtt()
|
||||
client.loop_start()
|
||||
printMsg("等待连接MQTT")
|
||||
while(g_rc!=0):
|
||||
print("-",end=" ")
|
||||
time.sleep(1)
|
||||
t1=threading.Timer(60,timing_publishProperty)
|
||||
t1.setDaemon(True) #当主线程被关闭后,子线程也关闭
|
||||
t1.start()
|
||||
t2=threading.Timer(monitorInterval,timing_publishMonitor)
|
||||
t2.setDaemon(True) #当主线程被关闭后,子线程也关闭
|
||||
t2.start()
|
||||
|
||||
while True:
|
||||
time.sleep(10) #定时上报、检测上报都是线程执行,主线程可以做自己的任务
|
||||
|
||||
26
sdk/RaspberryPi/更多参考教程.txt
Normal file
26
sdk/RaspberryPi/更多参考教程.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
Eclipse Paho MQTT Python Client 使用手册
|
||||
https://www.cooooder.com/archives/20210303
|
||||
|
||||
Python 实现AES加密
|
||||
https://zhuanlan.zhihu.com/p/261694311
|
||||
|
||||
python实现AES加密解密
|
||||
https://blog.csdn.net/chouzhou9701/article/details/122019967
|
||||
|
||||
使用python time()方法
|
||||
http://www.py.cn/jishu/jichu/20424.html
|
||||
|
||||
python 线程定时器Timer
|
||||
https://zhuanlan.zhihu.com/p/91412537
|
||||
|
||||
浅谈Python的格式化输出
|
||||
https://www.jb51.net/article/225609.htm
|
||||
|
||||
Python Request库入门
|
||||
https://www.jianshu.com/p/d78982126318
|
||||
|
||||
Python JSON
|
||||
https://www.runoob.com/python/python-json.html
|
||||
|
||||
Python random() 函数
|
||||
https://www.runoob.com/python/func-number-random.html
|
||||
@@ -1,21 +1,34 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import javax.servlet.*;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
import com.ruoyi.common.enums.DataSourceType;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.framework.config.properties.DruidProperties;
|
||||
import com.ruoyi.framework.datasource.DynamicDataSource;
|
||||
import org.apache.ibatis.io.VFS;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -34,8 +47,8 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class MyBatisConfig
|
||||
{
|
||||
@MapperScan(basePackages = {"com.ruoyi.iot.mapper", "com.ruoyi.system.mapper", "com.ruoyi.quartz.mapper", "com.ruoyi.generator.mapper"}, sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
|
||||
public class MyBatisConfig {
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@@ -119,10 +132,11 @@ public class MyBatisConfig
|
||||
|
||||
@Bean(name = "mysqlSessionFactory")
|
||||
@Primary
|
||||
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
|
||||
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception
|
||||
{
|
||||
String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
|
||||
String mapperLocations = env.getProperty("mybatis.mapperLocations");
|
||||
String typeAliasesPackage = "com.ruoyi.**.domain";//env.getProperty("mybatis.typeAliasesPackage");
|
||||
String mapperLocations = "classpath:mapper/iot/*Mapper.xml,classpath:mapper/system/*Mapper.xml,classpath:mapper/quartz/*Mapper.xml";
|
||||
// String typeAliasesPackage = "com.ruoyi.**.domain";
|
||||
String configLocation = env.getProperty("mybatis.configLocation");
|
||||
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
|
||||
VFS.addImplClass(SpringBootVFS.class);
|
||||
@@ -146,4 +160,5 @@ public class MyBatisConfig
|
||||
public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
|
||||
return new SqlSessionTemplate(sqlSessionFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -138,13 +138,13 @@ public class ToolController extends BaseController {
|
||||
// 设备端
|
||||
String[] clientInfo = clientid.split("&");
|
||||
if (clientInfo.length != 2) {
|
||||
// 设备未加密认证
|
||||
// 设备简单认证
|
||||
String deviceNum = clientInfo[0];
|
||||
Device device = deviceService.selectShortDeviceBySerialNumber(deviceNum);
|
||||
if (device !=null && mqttConfig.getusername().equals(username) && mqttConfig.getpassword().equals(password)) {
|
||||
System.out.println("-----------认证成功,clientId:" + clientid + "---------------");
|
||||
ProductAuthorize authorize = new ProductAuthorize(null, device.getProductId(), device.getDeviceId(), device.getSerialNumber(), 1L, "admin");
|
||||
authorizeService.boundProductAuthorize(authorize);
|
||||
// ProductAuthorize authorize = new ProductAuthorize(null, device.getProductId(), device.getDeviceId(), device.getSerialNumber(), 1L, "admin");
|
||||
// authorizeService.boundProductAuthorize(authorize);
|
||||
return ResponseEntity.ok().body("ok");
|
||||
}
|
||||
return returnUnauthorized(clientid, username, password, "认证信息有误");
|
||||
@@ -178,16 +178,16 @@ public class ToolController extends BaseController {
|
||||
// 设备状态验证 (1-未激活,2-禁用,3-在线,4-离线)
|
||||
if (model.getDeviceId() != null && model.getDeviceId() != 0 && model.getStatus() != 2) {
|
||||
System.out.println("-----------认证成功,clientId:" + clientid + "---------------");
|
||||
ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin");
|
||||
authorizeService.boundProductAuthorize(authorize);
|
||||
// ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin");
|
||||
// authorizeService.boundProductAuthorize(authorize);
|
||||
return ResponseEntity.ok().body("ok");
|
||||
} else {
|
||||
// 自动添加设备
|
||||
int result = deviceService.insertDeviceAuto(deviceNum, userId, productId);
|
||||
if (result == 1) {
|
||||
System.out.println("-----------认证成功,clientId:" + clientid + "---------------");
|
||||
ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin");
|
||||
authorizeService.boundProductAuthorize(authorize);
|
||||
// ProductAuthorize authorize = new ProductAuthorize(null, model.getProductId(), model.getDeviceId(), model.getSerialNumber(), 1L, "admin");
|
||||
// authorizeService.boundProductAuthorize(authorize);
|
||||
return ResponseEntity.ok().body("ok");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.ruoyi.iot.init;
|
||||
|
||||
|
||||
//import com.ruoyi.mysql.config.TDengineConfig;
|
||||
|
||||
//import com.ruoyi.iot.tdengine.config.TDengineConfig;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.ruoyi.iot.tdengine.config.TDengineConfig;
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.mapper.DeviceMapper;
|
||||
import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 类名: ApplicationStarted
|
||||
* 描述: TODO
|
||||
* 时间: 2022/5/18,0018 1:41
|
||||
* 开发人: wxy
|
||||
*/
|
||||
@Component
|
||||
public class ApplicationStarted implements ApplicationRunner {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationStarted.class);
|
||||
|
||||
@Autowired
|
||||
private TDengineConfig dengineConfig;
|
||||
|
||||
@Autowired
|
||||
private TDDeviceLogMapper deviceLogMapper;
|
||||
|
||||
@Autowired
|
||||
private DeviceMapper deviceMapper;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
deviceMapper.selectDeviceByDeviceId(0L);
|
||||
System.out.println("初始化MySql链接成功");
|
||||
initTDengine();
|
||||
System.out.println("初始化TDengine链接成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method
|
||||
* @Description 开始初始化加载系统参数,创建数据库和超级表
|
||||
* @Param null
|
||||
* @return
|
||||
* @date 2022/5/22,0022 14:27
|
||||
* @author wxy
|
||||
*
|
||||
*/
|
||||
public void initTDengine() {
|
||||
try {
|
||||
String dbName = dengineConfig.getDbName();
|
||||
int db = deviceLogMapper.createDB(dbName);
|
||||
deviceLogMapper.createSTable(dbName);
|
||||
|
||||
System.out.println(db);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("ERROR");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruoyi.iot.log.service;
|
||||
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
|
||||
import com.ruoyi.iot.model.MonitorModel;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @package iot.iot.log
|
||||
* 类名: LogService
|
||||
* 描述: 设备日志记录接口
|
||||
* 时间: 2022/5/19,0019 18:04
|
||||
* 开发人: admin
|
||||
*/
|
||||
public interface ILogService {
|
||||
|
||||
int saveDeviceLog(DeviceLog deviceLog);
|
||||
|
||||
List<DeviceLog> selectDeviceLogList(DeviceLog deviceLog);
|
||||
|
||||
List<MonitorModel> selectMonitorList(DeviceLog deviceLog);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.ruoyi.iot.log.service.factory;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.framework.config.MyBatisConfig;
|
||||
import com.ruoyi.iot.log.service.impl.MySqlLogServiceImpl;
|
||||
import com.ruoyi.iot.log.service.impl.TdengineLogServiceImpl;
|
||||
import com.ruoyi.iot.model.MonitorModel;
|
||||
import com.ruoyi.iot.tdengine.config.TDengineConfig;
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.log.service.ILogService;
|
||||
import com.ruoyi.iot.mapper.DeviceLogMapper;
|
||||
import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper;
|
||||
import com.ruoyi.iot.util.SnowflakeIdWorker;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类名: DeviceLogServiceImpl
|
||||
* 描述: TODO
|
||||
* 时间: 2022/5/19,0019 18:09
|
||||
* 开发人: wxy
|
||||
*/
|
||||
@Component
|
||||
public class LogServiceFactory {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public ILogService getLogService() {
|
||||
//先获取TDengine的配置,检测TDengine是否已经配置
|
||||
if (containBean(TDengineConfig.class)) {
|
||||
TDengineConfig tDengineConfig = applicationContext.getBean(TDengineConfig.class);
|
||||
TDDeviceLogMapper tDDeviceLogMapper = applicationContext.getBean(TDDeviceLogMapper.class);
|
||||
ILogService logService = new TdengineLogServiceImpl(tDengineConfig, tDDeviceLogMapper);
|
||||
return logService;
|
||||
} else if (containBean(MyBatisConfig.class)) {
|
||||
//没有配置TDengine,那么使用MySQL的日志配置
|
||||
DeviceLogMapper deviceLogMapper = applicationContext.getBean( DeviceLogMapper.class);
|
||||
ILogService logService = new MySqlLogServiceImpl(deviceLogMapper);
|
||||
return logService;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method containBean
|
||||
* @Description 根据类判断是否有对应bean
|
||||
* @Param 类
|
||||
* @return
|
||||
* @date 2022/5/22,0022 14:12
|
||||
* @author wxy
|
||||
*
|
||||
*/
|
||||
private boolean containBean(@Nullable Class<?> T) {
|
||||
String[] beans = applicationContext.getBeanNamesForType(T);
|
||||
if (beans == null || beans.length == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ruoyi.iot.log.service.impl;
|
||||
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.log.service.ILogService;
|
||||
import com.ruoyi.iot.mapper.DeviceLogMapper;
|
||||
import com.ruoyi.iot.model.MonitorModel;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类名: MySqlLogServiceImpl
|
||||
* 描述: MySQL存储日志实现类
|
||||
* 时间: 2022/5/22,0022 13:37
|
||||
* 开发人: admin
|
||||
*/
|
||||
public class MySqlLogServiceImpl implements ILogService {
|
||||
|
||||
private DeviceLogMapper deviceLogMapper;
|
||||
|
||||
public MySqlLogServiceImpl(DeviceLogMapper _deviceLogMapper){
|
||||
this.deviceLogMapper=_deviceLogMapper;
|
||||
}
|
||||
@Override
|
||||
public int saveDeviceLog(DeviceLog deviceLog) {
|
||||
return deviceLogMapper.insertDeviceLog(deviceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceLog> selectDeviceLogList(DeviceLog deviceLog) {
|
||||
return deviceLogMapper.selectDeviceLogList(deviceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MonitorModel> selectMonitorList(DeviceLog deviceLog) {
|
||||
return deviceLogMapper.selectMonitorList(deviceLog);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ruoyi.iot.log.service.impl;
|
||||
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.log.service.ILogService;
|
||||
import com.ruoyi.iot.model.MonitorModel;
|
||||
import com.ruoyi.iot.tdengine.config.TDengineConfig;
|
||||
import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper;
|
||||
import com.ruoyi.iot.util.SnowflakeIdWorker;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类名: TdengineLogServiceImpl
|
||||
* 描述: TDengine存储日志数据实现类
|
||||
* 时间: 2022/5/22,0022 13:38
|
||||
* 开发人: admin
|
||||
*/
|
||||
public class TdengineLogServiceImpl implements ILogService {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private TDDeviceLogMapper tdDeviceLogMapper;
|
||||
|
||||
private TDengineConfig tDengineConfig;
|
||||
|
||||
private SnowflakeIdWorker snowflakeIdWorker;
|
||||
|
||||
private String dbName;
|
||||
|
||||
public TdengineLogServiceImpl(TDengineConfig _tDengineConfig,TDDeviceLogMapper _tdDeviceLogMapper) {
|
||||
this.tdDeviceLogMapper = _tdDeviceLogMapper;
|
||||
this.tDengineConfig = _tDengineConfig;
|
||||
snowflakeIdWorker=new SnowflakeIdWorker(1);
|
||||
this.dbName=_tDengineConfig.getDbName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int saveDeviceLog(DeviceLog deviceLog) {
|
||||
long logId = snowflakeIdWorker.nextId();
|
||||
deviceLog.setLogId(logId);
|
||||
return tdDeviceLogMapper.save(dbName,deviceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceLog> selectDeviceLogList(DeviceLog deviceLog) {
|
||||
return tdDeviceLogMapper.selectDeviceLogList(dbName,deviceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MonitorModel> selectMonitorList(DeviceLog deviceLog) {
|
||||
return tdDeviceLogMapper.selectMonitorList(dbName,deviceLog);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class EmqxClient {
|
||||
token.waitForCompletion();
|
||||
}catch (Exception e){
|
||||
logger.error("=====>>>>>mqtt连接失败 message={}",e.getMessage());
|
||||
throw new ServiceException("mqtt客户端连接错误"+e.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class EmqxClient {
|
||||
logger.debug("====>>>mqtt客户端启动成功");
|
||||
}catch (MqttException e){
|
||||
logger.error("mqtt客户端连接错误 error={}",e.getMessage());
|
||||
throw new ServiceException("mqtt客户端连接错误"+e.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@ package com.ruoyi.iot.mqtt;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ruoyi.iot.domain.Device;
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.tdengine.service.ILogService;
|
||||
import com.ruoyi.iot.log.service.ILogService;
|
||||
import com.ruoyi.iot.model.NtpModel;
|
||||
import com.ruoyi.iot.model.ThingsModels.IdentityAndName;
|
||||
import com.ruoyi.iot.model.ThingsModels.ThingsModelValueItem;
|
||||
import com.ruoyi.iot.model.ThingsModels.ThingsModelValueRemarkItem;
|
||||
import com.ruoyi.iot.model.ThingsModels.ThingsModelValuesInput;
|
||||
import com.ruoyi.iot.service.IDeviceLogService;
|
||||
import com.ruoyi.iot.service.IDeviceService;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.ruoyi.iot.tdengine.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.iot.tdengine.dao.TDDeviceLogMapper;
|
||||
import com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
@@ -31,7 +31,7 @@ import java.util.List;
|
||||
* 开发人: wxy
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan(basePackages = {"com.ruoyi.iot.tdengine.dao"}, sqlSessionTemplateRef = "tdengineSqlSessionTemplate")
|
||||
@MapperScan(basePackages = {"com.ruoyi.iot.tdengine.mapper"}, sqlSessionTemplateRef = "tdengineSqlSessionTemplate")
|
||||
@ConditionalOnProperty(name = "spring.datasource.druid.tdengine-server.enabled", havingValue = "true")
|
||||
public class TDengineConfig {
|
||||
|
||||
@@ -64,6 +64,16 @@ public class TDengineConfig {
|
||||
return new SqlSessionTemplate(sqlSessionFactory);
|
||||
}
|
||||
|
||||
|
||||
// @Bean
|
||||
// @ConditionalOnProperty(name = "spring.datasource.druid.tdengine-server.enabled", havingValue = "true")
|
||||
// public TDDeviceLogMapper genTdengineLogMapper(@Qualifier("tDengineDataSource") TDDeviceLogMapper mapper) {
|
||||
// if(this.deviceLogMapper==null){
|
||||
// this.deviceLogMapper=mapper;
|
||||
// }
|
||||
// return this.deviceLogMapper;
|
||||
// }
|
||||
|
||||
public TDDeviceLogMapper getTDengineLogMapper() {
|
||||
return deviceLogMapper;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruoyi.iot.tdengine.mapper;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @package com.ruoyi.mysql.mysql.tdengine
|
||||
* 类名: DatabaseMapper
|
||||
* 描述: TODO
|
||||
* 时间: 2022/5/16,0016 1:27
|
||||
* 开发人: wxy
|
||||
*/
|
||||
@Repository
|
||||
public interface DatabaseMapper {
|
||||
|
||||
int createDB();
|
||||
|
||||
int dropDatabase();
|
||||
|
||||
int useDatabase();
|
||||
|
||||
int createTable();
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ruoyi.iot.tdengine.mapper;
|
||||
|
||||
import com.ruoyi.iot.domain.DeviceLog;
|
||||
import com.ruoyi.iot.model.MonitorModel;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.lang.management.MonitorInfo;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @package com.ruoyi.mysql.mysql.tdengine
|
||||
* 类名: DatabaseMapper
|
||||
* 描述: TODO
|
||||
* 时间: 2022/5/16,0016 1:27
|
||||
* 开发人: wxy
|
||||
*/
|
||||
@Repository
|
||||
public interface TDDeviceLogMapper {
|
||||
|
||||
|
||||
int createDB( String database);
|
||||
|
||||
int createSTable(String database);
|
||||
|
||||
int createTable(String database,String deviceId);
|
||||
|
||||
int save(@Param("database") String database,@Param("device") DeviceLog deviceLog);
|
||||
|
||||
List<DeviceLog> selectSTable(String database,DeviceLog deviceLog);
|
||||
|
||||
int delete(String dbName, DeviceLog deviceLog);
|
||||
|
||||
// List<DeviceLog> selectLogListByPage(String dbName, Integer pageSize, Integer pageNum, String deviceNum, Date beginDate, Date endDate);
|
||||
|
||||
List<DeviceLog> selectLogList(String dbName, Long deviceId, String serialNumber, Long isMonitor, Long logType, Date beginDate, Date endDate);
|
||||
|
||||
List<MonitorModel> selectMonitorList(@Param("database") String database, @Param("device") DeviceLog deviceLog);
|
||||
|
||||
List<DeviceLog> selectDeviceLogList(@Param("database") String database,@Param("device") DeviceLog deviceLog);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.iot.tdengine.dao.DatabaseMapper">
|
||||
<mapper namespace="com.ruoyi.iot.tdengine.mapper.DatabaseMapper">
|
||||
|
||||
<!-- 创建数据库-->
|
||||
<update id="createDB" parameterType="java.lang.String">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.iot.tdengine.dao.TDDeviceLogMapper">
|
||||
<mapper namespace="com.ruoyi.iot.tdengine.mapper.TDDeviceLogMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.ruoyi.iot.domain.DeviceLog">
|
||||
<id column="ts" property="ts"/>
|
||||
|
||||
BIN
vue/src/assets/images/code.jpg
Normal file
BIN
vue/src/assets/images/code.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -1,5 +1,45 @@
|
||||
<template>
|
||||
<div class="app-container home">
|
||||
<el-row :gutter="40" style="margin-bottom:10px;">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="14" :xl="14">
|
||||
<el-card shadow="hover" style="margin:-10px;margin-bottom:20px;font-size:14px;min-height:170px;">
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:18px;">物美智能生活物联网平台</div>
|
||||
<div style="display:table;margin-bottom:10px;">
|
||||
<div style="width:70px;font-weight: bold;display:table-cell;">个人用户:</div>
|
||||
<div style="display:table-cell;line-height:22px;"><b style="color:#F56C6C">可用于个人学习和使用,非商业用途。</b>不提供移动端源码,后期可以通过两种方式使用移动端:1.免费托管设备到平台;2.使用移动端开放的接口连接自己搭建的系统。</div>
|
||||
</div>
|
||||
<div style="display:table;">
|
||||
<div style="width:70px;font-weight: bold;display:table-cell;">企业用户:</div>
|
||||
<div style="display:table-cell;line-height:22px;"><b style="color:#F56C6C">可用于商业用途,并提供移动端源码,通过赞助方式获取企业授权。</b>但是不能低价或批量转售源码,不能随意分发源码。目前赞助费为1500元,项目不断完善后会对应增加费用。</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="10" :xl="10">
|
||||
<el-card shadow="hover" style="margin:-10px;margin-bottom:20px;font-size:14px;min-height:170px;">
|
||||
<div style="float:left;width:170px;">
|
||||
<el-image style="width:154px;" :src="require('@/assets/images/code.jpg')"></el-image>
|
||||
</div>
|
||||
<div style="float:left;">
|
||||
<div style="font-size:16px;font-weight:bold;margin:16px 0;">微信扫一扫,查看小程序端</div>
|
||||
<div style="display:table;margin-bottom:10px;">
|
||||
<div style="width:70px;font-weight: bold;display:table-cell;">官方网站</div>
|
||||
<div style="display:table-cell;">
|
||||
<span>www.wumei.live</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:table;margin-bottom:15px;">
|
||||
<div style="width:70px;font-weight: bold;display:table-cell;">系统源码</div>
|
||||
<div style="display:table-cell;">
|
||||
<el-link target="_blank" href="https://gitee.com/kerwincui/wumei-smart" type="danger">Gitee源码</el-link>
|
||||
<el-link target="_blank" href="https://github.com/kerwincui/wumei-smart" style="margin-left:20px;">Github源码</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="40" style="margin-bottom:80px;">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="14" :xl="14">
|
||||
<el-card style="margin:-10px;" shadow="hover" body-style="background-color:#F8F8F8;">
|
||||
@@ -141,13 +181,6 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div style="margin:-21px;margin-top:100px;bottom:0;border:1px solid #ccc;padding:10px;margin-bottom:-21px;">
|
||||
<div>
|
||||
<el-link href="http://wumei.live" target="_blank" type="primary" style="margin-left:20px;">开源生活物联网平台 >></el-link>
|
||||
<el-link href="https://github.com/kerwincui/wumei-smart" target="_blank" type="danger" style="margin-left:30px;">Github源码 >></el-link>
|
||||
<el-link href="https://gitee.com/kerwincui/wumei-smart" target="_blank" type="success" style="margin-left:30px;">码云源码 >></el-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div style="padding: 6px">
|
||||
<el-card v-show="showSearch" style="margin-bottom: 6px">
|
||||
<div style="height:50px; color:#F56C6C;margin-left:20px;">该功能下个版本发布</div>
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" style="margin-bottom:-20px;">
|
||||
<el-form-item label="客户端ID" prop="clientId">
|
||||
<el-input v-model="queryParams.clientId" placeholder="请输入客户端ID" clearable size="small" @keyup.enter.native="handleQuery" />
|
||||
@@ -14,6 +13,7 @@
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
<el-tag type="danger" style="margin-left:15px;">该功能暂不可用,后面版本发布</el-tag>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
@@ -392,6 +392,7 @@ export default {
|
||||
mqttSubscribe(list) {
|
||||
// 订阅当前页面设备状态和实时监测
|
||||
let topics = [];
|
||||
// 订阅数太多,会导致emqx连接中断或者订阅缓慢
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let topicStatus = "/" + list[i].productId + "/" + list[i].serialNumber + "/status/post";
|
||||
let topicMonitor = "/" + list[i].productId + "/" + list[i].serialNumber + "/monitor/post";
|
||||
@@ -451,9 +452,9 @@ export default {
|
||||
this.queryParams.params["endActiveTime"] = this.daterangeActiveTime[1];
|
||||
}
|
||||
// 判断是否是admin角色
|
||||
if (this.$store.state.user.roles.indexOf("admin") === -1) {
|
||||
this.queryParams.userId = this.$store.state.user.userId
|
||||
}
|
||||
// if (this.$store.state.user.roles.indexOf("admin") === -1) {
|
||||
// this.queryParams.userId = this.$store.state.user.userId
|
||||
// }
|
||||
listDeviceShort(this.queryParams).then(response => {
|
||||
this.deviceList = response.rows;
|
||||
this.total = response.total;
|
||||
@@ -519,6 +520,7 @@ export default {
|
||||
// 筛选监测数据
|
||||
this.monitorThings = thingsModel.properties.filter(item => item.isMonitor == 1);
|
||||
// 监测数据集合初始化
|
||||
this.dataList=[];
|
||||
for (let i = 0; i < this.monitorThings.length; i++) {
|
||||
this.dataList.push({
|
||||
id: this.monitorThings[i].id,
|
||||
|
||||
@@ -23,15 +23,14 @@ export default {
|
||||
watch: {
|
||||
// 获取到父组件传递的值
|
||||
publish: function (val, oldVal) {
|
||||
this.mqttPublish(val.topic, val.message,val.name);
|
||||
this.mqttPublish(val.topic, val.message, val.name);
|
||||
},
|
||||
subscribes: function (val, oldVal) {
|
||||
this.connectMqtt(val);
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
return {};
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -39,12 +38,13 @@ export default {
|
||||
methods: {
|
||||
/** 连接Mqtt */
|
||||
connectMqtt(subscribeTopics) {
|
||||
let randomClientId='web-' + Math.random().toString(16).substr(2);
|
||||
let options = {
|
||||
username: "wumei-smart",
|
||||
password: getToken(),
|
||||
cleanSession: false,
|
||||
keepAlive: 30,
|
||||
clientId: 'web-' + Math.random().toString(16).substr(2),
|
||||
clientId: randomClientId,
|
||||
connectTimeout: 10000
|
||||
}
|
||||
// 配置Mqtt地址
|
||||
@@ -53,18 +53,20 @@ export default {
|
||||
console.log("mqtt地址:", url);
|
||||
this.client = mqtt.connect(url, options);
|
||||
this.client.on("connect", (e) => {
|
||||
console.log("成功连接服务器:", e);
|
||||
console.log("客户端:"+randomClientId+",成功连接服务器:", e);
|
||||
// 订阅主题
|
||||
this.client.subscribe(subscribeTopics, {
|
||||
qos: 1
|
||||
}, (err) => {
|
||||
if (!err) {
|
||||
console.log("订阅成功");
|
||||
console.log(subscribeTopics.join(", "));
|
||||
} else {
|
||||
console.log('消息订阅失败!')
|
||||
}
|
||||
});
|
||||
if (subscribeTopics != '' && subscribeTopics.length > 0) {
|
||||
this.client.subscribe(subscribeTopics, {
|
||||
qos: 1
|
||||
}, (err) => {
|
||||
if (!err) {
|
||||
console.log("订阅成功");
|
||||
console.log(subscribeTopics.join(", "));
|
||||
} else {
|
||||
console.log('消息订阅失败!')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 重新连接
|
||||
this.reconnectMqtt()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div style="padding: 6px">
|
||||
<el-card v-show="showSearch" style="margin-bottom: 6px">
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px" style="margin-bottom: -20px">
|
||||
<el-form-item label="客户端" prop="categoryName">
|
||||
<el-input v-model="queryParams.categoryName" placeholder="请输入客户端ID" clearable size="small" @keyup.enter.native="handleQuery" />
|
||||
<el-form-item label="客户端" prop="clientid">
|
||||
<el-input v-model="queryParams.clientid" placeholder="请输入客户端ID" clearable size="small" @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
@@ -43,7 +43,7 @@
|
||||
<el-table-column label="会话创建时间" align="center" prop="created_at" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="danger" v-if="scope.row.connected" style="padding: 5px" v-hasPermi="['monitor:client:edit']" @click="handleDelete(scope.row)">
|
||||
<el-button size="small" type="danger" v-if="scope.row.connected" style="padding: 5px" v-hasPermi="['iot:product:remove']" @click="handleDelete(scope.row)">
|
||||
<svg-icon icon-class="disconnect" /> 断开连接
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -53,16 +53,14 @@
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams._page" :limit.sync="queryParams._limit" @pagination="getList" />
|
||||
|
||||
<!-- MQTT客户端详细 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="50%" append-to-body>
|
||||
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
|
||||
<el-tabs v-model="activeName" tab-position="top" style="padding: 10px">
|
||||
<el-tab-pane name="basic">
|
||||
<span slot="label">基本信息</span>
|
||||
<el-form ref="form" :model="form" label-width="120px" size="mini">
|
||||
|
||||
<el-descriptions class="margin-top" title="基本信息" :column="4" direction="vertical">
|
||||
<el-descriptions class="margin-top" :column="2" border size="medium">
|
||||
<el-descriptions-item label="节点">{{form.node }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户端ID">{{form.clientid}}</el-descriptions-item>
|
||||
<el-descriptions-item label="Clean Session">{{form.clean_start}}</el-descriptions-item>
|
||||
<el-descriptions-item label="清除Session">{{form.clean_start}}</el-descriptions-item>
|
||||
<el-descriptions-item label="会话过期间隔(秒)">{{form.expiry_interval}}</el-descriptions-item>
|
||||
<el-descriptions-item label="用户名">{{form.username}}</el-descriptions-item>
|
||||
<el-descriptions-item label="协议类型">{{form.proto_ver}}</el-descriptions-item>
|
||||
@@ -79,11 +77,11 @@
|
||||
<el-descriptions-item label="连接时间">{{form.connected_at}}</el-descriptions-item>
|
||||
<el-descriptions-item label="连接状态">
|
||||
<div v-if="form.connected == true" style="color: green">
|
||||
已连接
|
||||
</div>
|
||||
<div v-else-if="form.connected == false" style="color: red">
|
||||
已断开
|
||||
</div>
|
||||
已连接
|
||||
</div>
|
||||
<div v-else-if="form.connected == false" style="color: red">
|
||||
已断开
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最大消息队列">{{form.max_mqueue}}</el-descriptions-item>
|
||||
<el-descriptions-item label="未确认的PUBREC数据包计数">{{form.awaiting_rel}}</el-descriptions-item>
|
||||
@@ -93,14 +91,11 @@
|
||||
<el-descriptions-item label="接收的PUBLISH报文数量">{{form.recv_msg}}</el-descriptions-item>
|
||||
<el-descriptions-item label="接收的字节数量">{{form.recv_oct}}</el-descriptions-item>
|
||||
<el-descriptions-item label="接收的MQTT报文数量">{{form.recv_pkt}}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="发送的TCP报文数量">{{form.send_cnt}}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送的PUBLISH报文数量">{{form.send_msg}}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送的字节数量">{{form.send_oct}}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送的MQTT报文数量">{{form.send_pkt}}</el-descriptions-item>
|
||||
|
||||
</el-descriptions>
|
||||
</el-form>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="subscribe">
|
||||
@@ -190,6 +185,7 @@ export default {
|
||||
queryParams: {
|
||||
_limit: 10,
|
||||
_page: 1,
|
||||
clientid:null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
<el-table-column label="描述" align="left" prop="description" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="success" style="padding:5px;" @click="loadMqttPlugin(scope.row.name)" v-if="!scope.row.active" v-hasPermi="['monitor:online:edit']">
|
||||
<el-button size="small" type="success" style="padding:5px;" @click="loadMqttPlugin(scope.row.name)" v-if="!scope.row.active" v-hasPermi="['iot:product:remove']">
|
||||
<svg-icon icon-class="start" /> 启动
|
||||
</el-button>
|
||||
<el-button size="small" type="danger" style="padding:5px;" @click="unloadMqttPlugin(scope.row.name)" v-else v-hasPermi="['monitor:online:edit']">
|
||||
<el-button size="small" type="danger" style="padding:5px;" @click="unloadMqttPlugin(scope.row.name)" v-else v-hasPermi="['iot:product:remove']">
|
||||
<svg-icon icon-class="stop" /> 停止
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
@@ -12,19 +12,16 @@
|
||||
<el-table v-loading="loading" :data="resourceList">
|
||||
<el-table-column label="ID" align="center" header-align="center" prop="id">
|
||||
<template slot-scope="scope">
|
||||
<el-link :underline="false" type="primary">{{ scope.row.id }}</el-link>
|
||||
<el-link :underline="false" type="primary" @click="handleQuery(scope.row)">{{ scope.row.id }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="资源类型" align="center" prop="type" />
|
||||
<el-table-column label="备注" align="center" prop="description" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<el-table-column label="操作" align="center" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="text" style="padding: 5px" v-hasPermi="['monitor:resource:query']" @click="handleQuery(scope.row)">
|
||||
查看
|
||||
<el-button size="small" type="text" icon="el-icon-connection" style="padding: 5px" v-hasPermi="['monitor:resource:checkStatus']" @click="checkStatus(scope.row)">状态
|
||||
</el-button>
|
||||
<el-button size="small" type="text" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['monitor:resource:delete']" @click="handleDelete(scope.row)">删除
|
||||
</el-button>
|
||||
<el-button size="small" type="text" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['monitor:resource:checkStatus']" @click="checkStatus(scope.row)">状态
|
||||
<el-button size="small" type="text" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['iot:product:remove']" @click="handleDelete(scope.row)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -32,7 +29,7 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 资源详细 -->
|
||||
<el-dialog title="资源详细" :visible.sync="openView" width="50%" append-to-body>
|
||||
<el-dialog title="资源详细" :visible.sync="openView" width="800px" append-to-body>
|
||||
<el-form ref="form" :model="form" label-width="180px" size="mini">
|
||||
<el-card style="padding-bottom: 10px">
|
||||
<div slot="header" class="clearfix">
|
||||
@@ -96,22 +93,18 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 测试重连 -->
|
||||
<el-dialog title="检测状态" :visible.sync="openStatusView" width="40%" append-to-body>
|
||||
<el-form ref="statusForm" :model="statusForm" label-width="180px" size="mini">
|
||||
<el-row>
|
||||
<el-col :span="12" v-if="statusForm.status[0]">
|
||||
{{ statusForm.status[0].node }}
|
||||
<el-tag type="success" v-if="statusForm.status[0].is_alive == true" style="margin-left: 10px">可用</el-tag>
|
||||
<el-tag type="danger" v-if="statusForm.status[0].is_alive == false" style="margin-left: 10px">不可用</el-tag>
|
||||
<el-button size="small" type="primary" icon="el-icon-connection" style="padding: 5px; margin-left: 10px" v-hasPermi="['monitor:resource:connect']" @click="checkNode(statusForm.id)">重新连接
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog title="检测状态" :visible.sync="openStatusView" width="600px" append-to-body>
|
||||
<el-form ref="statusForm" :model="statusForm" label-width="180px" size="mini" v-if="statusForm.status[0]">
|
||||
{{ statusForm.status[0].node }}
|
||||
<el-tag type="success" v-if="statusForm.status[0].is_alive == true" style="margin-left: 10px">可用</el-tag>
|
||||
<el-tag type="danger" v-if="statusForm.status[0].is_alive == false" style="margin-left: 10px">不可用</el-tag>
|
||||
<el-button size="small" type="primary" icon="el-icon-connection" style="padding: 5px; margin-left: 10px" v-hasPermi="['monitor:resource:connect']" @click="checkNode(statusForm.id)">重新连接
|
||||
</el-button>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加资源 -->
|
||||
<el-dialog title="资源管理" :visible.sync="openAddView" width="50%" append-to-body :before-close="cancel">
|
||||
<el-dialog title="资源管理" :visible.sync="openAddView" width="800px" append-to-body :before-close="cancel">
|
||||
<el-form ref="addResourceForm" :model="addResourceForm" label-width="180px" :rules="rule">
|
||||
<el-card style="padding-bottom: 10px">
|
||||
<div slot="header" class="clearfix">
|
||||
|
||||
@@ -10,37 +10,34 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-table v-loading="loading" :data="rulesList">
|
||||
<el-table-column label="ID" align="center" header-align="center" prop="id">
|
||||
<el-table-column label="ID" align="center" header-align="center" prop="id" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-link :underline="false" type="primary">{{scope.row.id }}</el-link>
|
||||
<el-link :underline="false" type="primary" @click="handleQuery(scope.row)">{{scope.row.id }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主题" align="center" prop="for" width="120">
|
||||
<el-table-column label="主题" align="center" prop="for">
|
||||
<template slot-scope="scope">
|
||||
<p v-for="(topic, index) in scope.row.for" :key="index">
|
||||
<el-tag type="success">{{ topic }}</el-tag>
|
||||
<el-tag type="warning">{{ topic }}</el-tag>
|
||||
</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="SQL" align="center" prop="rawsql" />
|
||||
<el-table-column label="响应动作" align="center" prop="actions">
|
||||
<el-table-column label="响应动作" align="center" prop="actions" width="250">
|
||||
<template slot-scope="scope">
|
||||
<p v-for="(action, index) in scope.row.actions" :key="index">
|
||||
<el-tag type="success">{{ action.name }}</el-tag>
|
||||
</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已命中" align="center" prop="matched">
|
||||
<el-table-column label="已命中" align="center" prop="matched" width="100">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.metrics[0].matched }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="text" style="padding: 5px" v-hasPermi="['monitor:rules:query']" @click="handleQuery(scope.row)">
|
||||
查看
|
||||
</el-button>
|
||||
<el-button size="small" type="text" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['monitor:rules:delete']" @click="handleDelete(scope.row)">删除
|
||||
<el-button size="small" type="danger" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['iot:product:remove']" @click="handleDelete(scope.row)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -48,7 +45,7 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 规则引擎详细 -->
|
||||
<el-dialog title="规则引擎详细" :visible.sync="openView" width="50%" append-to-body>
|
||||
<el-dialog title="规则引擎详细" :visible.sync="openView" width="800px" append-to-body>
|
||||
<el-form ref="form" :model="form" label-width="120px" size="mini">
|
||||
<el-card style="padding-bottom: 10px">
|
||||
<div slot="header" class="clearfix">
|
||||
@@ -107,20 +104,18 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加规则引擎 -->
|
||||
<el-dialog title="资源管理" :visible.sync="openAddView" width="60%" append-to-body :before-close="cancel">
|
||||
<el-form ref="form" :model="form" label-width="180px">
|
||||
<el-card style="padding-bottom: 10px">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>
|
||||
<h2>条件</h2>
|
||||
<h6>使用 SQL 定义规则条件与数据处理方式</h6>
|
||||
</span>
|
||||
</div>
|
||||
<el-row :gutter="50">
|
||||
<el-col :span="12">
|
||||
<el-dialog title="添加规则引擎" :visible.sync="openAddView" width="1000px" append-to-body :before-close="cancel">
|
||||
<el-card style="margin-bottom:10px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-size:16px;font-weight:bold;">条件</span>
|
||||
<span style="font-size:12px;margin-left:12px;">使用 SQL 定义规则条件与数据处理方式</span>
|
||||
</div>
|
||||
<el-form ref="form" :model="form" label-width="90px">
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="13">
|
||||
<el-form-item prop="sql_example">
|
||||
<span slot="label"> 规则 SQL: </span>
|
||||
<CodeMirrorEditor :value="form.sql_example" myMode="text/x-mysql" height="420" />
|
||||
<CodeMirrorEditor :value="form.sql_example" myMode="text/x-mysql" height="400" style="border:1px solid #ddd;" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="sql_example">
|
||||
<span slot="label"> 备注: </span>
|
||||
@@ -129,106 +124,103 @@
|
||||
<el-form-item prop="SQLtest">
|
||||
<span slot="label">
|
||||
SQL测试:
|
||||
<el-tooltip content="自定义模拟数据进行 SQL 命令测试,仅用于测试功能" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-switch v-model="form.SQLtest" active-text="" inactive-text="" :active-value="true" :inactive-value="false" active-color="#13ce66">
|
||||
</el-switch>
|
||||
<span style="font-size:12px;margin-left:10px;">自定义模拟数据进行 SQL 命令测试,仅用于测试功能</span>
|
||||
</el-form-item>
|
||||
<div v-if="form.SQLtest">
|
||||
<el-form-item prop="test_columns.username" v-if="form.test_columns">
|
||||
<span slot="label"> username: </span>
|
||||
<el-input v-model="form.test_columns.username" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.topic" v-if="form.test_columns">
|
||||
<span slot="label"> topic: </span>
|
||||
<el-input v-model="form.test_columns.topic" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.qos" v-if="form.test_columns">
|
||||
<span slot="label"> qos: </span>
|
||||
<el-input v-model="form.test_columns.qos" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.clientid" v-if="form.test_columns">
|
||||
<span slot="label"> clientid: </span>
|
||||
<el-input v-model="form.test_columns.clientid" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.payload" v-if="form.test_columns">
|
||||
<span slot="label"> payload: </span>
|
||||
<CodeMirrorEditor :value="form.test_columns.payload" myMode="application/json" height="150" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.test_columns">
|
||||
<el-button @click="testConnect" type="success" size="mini">测 试</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.test_columns">
|
||||
<span slot="label"> 测试结果: </span>
|
||||
<textarea style="width: 497px; height: 70px" v-model="content">
|
||||
</textarea>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-col :span="11">
|
||||
<div class="sql-tips">
|
||||
<div class="title">编写 SQL 进行条件过滤与数据处理</div>
|
||||
<div class="el-scrollbar">
|
||||
<div class="doc-wrapper" style="margin-bottom: -17px; margin-right: -17px">
|
||||
<div class="el-scrollbar__view">
|
||||
<div>
|
||||
<p>
|
||||
EMQ X
|
||||
在消息发布、事件触发时将触发规则引擎,满足触发条件的规则将执行各自的
|
||||
SQL 语句筛选并处理消息和事件的上下文信息。
|
||||
</p>
|
||||
<p class="item">
|
||||
规则引擎借助响应动作可将特定主题的消息处理结果存储到数据库,发送到
|
||||
HTTP Server,转发到消息队列 Kafka 或
|
||||
RabbitMQ,重新发布到新的主题甚至是另一个 Broker
|
||||
集群中,每个规则可以配置多个响应动作。
|
||||
</p>
|
||||
<p>
|
||||
1. 选择发布到 't/#' 主题的消息,并筛选出全部字段:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT * FROM "t/#"</code>
|
||||
</div>
|
||||
<p>
|
||||
2. 选择发布到 't/a' 主题的消息,并从 JSON
|
||||
格式的消息内容中筛选出 "x" 字段:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT payload.x as x FROM "t/a"</code>
|
||||
</div>
|
||||
<p class="item">
|
||||
规则引擎使用 $events/ 开头的虚拟主题(事件主题)处理
|
||||
EMQ X
|
||||
内置事件,内置事件提供更精细的消息控制和客户端动作处理能力,可用在
|
||||
QoS 1 QoS 2 的消息抵达记录、设备上下线记录等业务中。
|
||||
</p>
|
||||
<p>
|
||||
1. 选择客户端连接事件,筛选 Username 为 'emqx'
|
||||
的设备并获取连接信息:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT clientid, connected_at FROM
|
||||
"$events/client_connected" WHERE username =
|
||||
'emqx'</code>
|
||||
</div>
|
||||
<p>规则引擎和 SQL 语句的详细教程参见 EMQ X 文档。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>编写 SQL 进行条件过滤与数据处理</div>
|
||||
<div class="doc-wrapper">
|
||||
<p>
|
||||
EMQ X
|
||||
在消息发布、事件触发时将触发规则引擎,满足触发条件的规则将执行各自的
|
||||
SQL 语句筛选并处理消息和事件的上下文信息。
|
||||
</p>
|
||||
<p>
|
||||
规则引擎借助响应动作可将特定主题的消息处理结果存储到数据库,发送到
|
||||
HTTP Server,转发到消息队列 Kafka 或
|
||||
RabbitMQ,重新发布到新的主题甚至是另一个 Broker
|
||||
集群中,每个规则可以配置多个响应动作。
|
||||
</p>
|
||||
<p>
|
||||
1. 选择发布到 't/#' 主题的消息,并筛选出全部字段:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT * FROM "t/#"</code>
|
||||
</div>
|
||||
<p>
|
||||
2. 选择发布到 't/a' 主题的消息,并从 JSON
|
||||
格式的消息内容中筛选出 "x" 字段:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT payload.x as x FROM "t/a"</code>
|
||||
</div>
|
||||
<p>
|
||||
规则引擎使用 $events/ 开头的虚拟主题(事件主题)处理
|
||||
EMQ X
|
||||
内置事件,内置事件提供更精细的消息控制和客户端动作处理能力,可用在
|
||||
QoS 1 QoS 2 的消息抵达记录、设备上下线记录等业务中。
|
||||
</p>
|
||||
<p>
|
||||
1. 选择客户端连接事件,筛选 Username 为 'emqx'
|
||||
的设备并获取连接信息:
|
||||
</p>
|
||||
<div class="code">
|
||||
<code>SELECT clientid, connected_at FROM
|
||||
"$events/client_connected" WHERE username =
|
||||
'emqx'</code>
|
||||
</div>
|
||||
<p>规则引擎和 SQL 语句的详细教程参见 EMQ X 文档。</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<el-row v-if="form.SQLtest" style="background-color:#f8f8f8;margin:-20px;">
|
||||
<el-col :span="13">
|
||||
<el-form-item prop="test_columns.username" v-if="form.test_columns">
|
||||
<span slot="label"> username </span>
|
||||
<el-input v-model="form.test_columns.username" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.topic" v-if="form.test_columns">
|
||||
<span slot="label"> topic</span>
|
||||
<el-input v-model="form.test_columns.topic" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.payload" v-if="form.test_columns">
|
||||
<span slot="label"> payload</span>
|
||||
<CodeMirrorEditor :value="form.test_columns.payload" myMode="application/json" height="150" style="border:1px solid #ddd;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="test_columns.clientid" v-if="form.test_columns">
|
||||
<span slot="label"> clientid </span>
|
||||
<el-input v-model="form.test_columns.clientid" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="test_columns.qos" v-if="form.test_columns">
|
||||
<span slot="label"> qos </span>
|
||||
<el-input v-model="form.test_columns.qos" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.test_columns">
|
||||
<span slot="label"> 测试结果: </span>
|
||||
<el-input type="textarea" v-model="content" :rows="4"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.test_columns">
|
||||
<el-button @click="testConnect" type="success" size="mini" style="width:100px;">测 试</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card style="padding-bottom: 10px">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>
|
||||
<h2>响应动作</h2>
|
||||
<h6>处理命中规则的消息</h6>
|
||||
</span>
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-size:16px;font-weight:bold;">响应动作</span>
|
||||
<span style="font-size:12px;margin-left:12px;">处理命中规则的消息</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-table ref="singleTable" :data="actions" highlight-current-row>
|
||||
<el-table-column property="name" label="类型"> </el-table-column>
|
||||
@@ -254,10 +246,10 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加响应动作 -->
|
||||
<el-dialog title="响应动作" :visible.sync="openAddActionView" width="40%" append-to-body :before-close="cancelAction">
|
||||
<el-dialog title="响应动作" :visible.sync="openAddActionView" width="600px" append-to-body :before-close="cancelAction">
|
||||
<el-form ref="actionForm" :model="actionForm" label-width="180px" v-if="actionForm.actions" :rules="ruleActions">
|
||||
<el-row>
|
||||
<el-col :span="20">
|
||||
<el-col>
|
||||
<el-form-item prop="actions.title">
|
||||
<span slot="label">
|
||||
动作:
|
||||
@@ -486,8 +478,7 @@ export default {
|
||||
//检查 (调试)表单参数
|
||||
inspectForm: {},
|
||||
//消息重新发布表单参数
|
||||
republishForm: {
|
||||
},
|
||||
republishForm: {},
|
||||
//桥接数据到 MQTT Broker表单参数
|
||||
data_to_mqtt_broker_Form: {
|
||||
resources: [],
|
||||
@@ -672,9 +663,9 @@ export default {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
param.$resource = this.data_to_mqtt_broker_Form.resourceId;
|
||||
if(this.data_to_mqtt_broker_Form.params.payload_tmpl != null){
|
||||
if (this.data_to_mqtt_broker_Form.params.payload_tmpl != null) {
|
||||
param.payload_tmpl =
|
||||
this.data_to_mqtt_broker_Form.params.payload_tmpl.default;
|
||||
this.data_to_mqtt_broker_Form.params.payload_tmpl.default;
|
||||
}
|
||||
action.params = param;
|
||||
action.name = this.data_to_mqtt_broker_Form.name;
|
||||
@@ -689,9 +680,9 @@ export default {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
param.$resource = this.data_to_webserver_Form.resourceId;
|
||||
if(this.data_to_webserver_Form.params.payload_tmpl != null){
|
||||
if (this.data_to_webserver_Form.params.payload_tmpl != null) {
|
||||
param.payload_tmpl =
|
||||
this.data_to_webserver_Form.params.payload_tmpl.default;
|
||||
this.data_to_webserver_Form.params.payload_tmpl.default;
|
||||
}
|
||||
action.params = param;
|
||||
action.name = this.data_to_webserver_Form.name;
|
||||
@@ -762,54 +753,18 @@ export default {
|
||||
.sql-tips {
|
||||
border: 4px dashed #d8d8d8;
|
||||
color: #71737d;
|
||||
}
|
||||
|
||||
.sql-tips {
|
||||
padding: 20px 0;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 15px;
|
||||
max-height: 480px;
|
||||
}
|
||||
|
||||
.sql-tips .title {
|
||||
padding: 0 20px 12px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 510px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sql-tips .doc-wrapper {
|
||||
max-height: 400px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.sql-tips .el-scrollbar__wrap {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.el-scrollbar__wrap {
|
||||
overflow: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.code {
|
||||
line-height: 1.4;
|
||||
padding: 6px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.code {
|
||||
background-color: hsla(0, 0%, 87%, 0.8);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,411 +1,338 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :inline="true" :model="queryParams" label-width="85px">
|
||||
<el-form-item label="第三方平台" prop="platform">
|
||||
<el-select v-model="queryParams.platform" clearable placeholder="请选择第三方平台" size="small">
|
||||
<el-option
|
||||
v-for="dict in dict.type.iot_social_platform"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" clearable placeholder="请选择 0:启用 ,1:禁用" size="small">
|
||||
<el-option
|
||||
v-for="dict in dict.type.iot_social_platform_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台" prop="platform">
|
||||
<el-select v-model="queryParams.platform" clearable placeholder="请选择平台" size="small">
|
||||
<el-option v-for="dict in dict.type.iot_social_platform" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" clearable placeholder="请选择状态" size="small">
|
||||
<el-option v-for="dict in dict.type.iot_social_platform_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['iot:platform:add']"
|
||||
>新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['iot:platform:edit']"
|
||||
>修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['iot:platform:remove']"
|
||||
>删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['iot:platform:export']"
|
||||
>导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['iot:platform:add']">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['iot:platform:edit']">修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['iot:platform:remove']">删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['iot:platform:export']">导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="platformList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center"/>
|
||||
<el-table-column align="center" label="平台主键" prop="socialPlatformId" width="75"/>
|
||||
<el-table-column align="center" label="平台名称" prop="platform" width="95">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.iot_social_platform" :value="scope.row.platform"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column align="center" label="平台名称" prop="platform">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.iot_social_platform" :value="scope.row.platform" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="状态" prop="status" width="75">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.iot_social_platform_status" :value="scope.row.status"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台申请Id" align="center" prop="clientId"/>
|
||||
<el-table-column label="平台密钥" align="center" prop="secretKey" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="跳转地址" align="center" prop="redirectUri" width="180" :show-overflow-tooltip="true"/>
|
||||
|
||||
<el-table-column align="center" label="绑定登录uri" prop="bindUri" :show-tooltip-when-overflow="true"
|
||||
:render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.bindId)"/>
|
||||
<el-table-column align="center" label="跳转登录uri" prop="redirectLoginUri" :show-tooltip-when-overflow="true"
|
||||
:render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.redirectLogin)"/>
|
||||
<el-table-column align="center" label="错误提示uri" prop="errorMsgUri" :show-tooltip-when-overflow="true"
|
||||
:render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.errorId)"/>
|
||||
<el-table-column align="center" label="备注" prop="remark" width="75" :show-tooltip-when-overflow="true"/>
|
||||
<el-table-column align="center" label="创建者" prop="createBy"/>
|
||||
<el-table-column align="center" label="创建时间" prop="createTime" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="更新者" prop="updateBy"/>
|
||||
<el-table-column align="center" label="更新时间" prop="updateTime" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['iot:platform:edit']"
|
||||
>修改
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['iot:platform:remove']"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="状态" prop="status" width="75">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.iot_social_platform_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台申请ID" align="center" prop="clientId" />
|
||||
<el-table-column label="跳转地址" align="center" prop="redirectUri" width="180" :show-overflow-tooltip="true" />
|
||||
<el-table-column align="center" label="绑定登录uri" prop="bindUri" :show-tooltip-when-overflow="true" :render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.bindId)" />
|
||||
<el-table-column align="center" label="跳转登录uri" prop="redirectLoginUri" :show-tooltip-when-overflow="true" :render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.redirectLogin)" />
|
||||
<el-table-column align="center" label="错误提示uri" prop="errorMsgUri" :show-tooltip-when-overflow="true" :render-header="(h,column)=>renderHeaderMethods(h,column,columnTips.errorId)" />
|
||||
<el-table-column align="center" label="创建时间" prop="createTime" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['iot:platform:edit']">修改
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:platform:remove']">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<!-- 添加或修改第三方登录平台控制对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="第三方平台" prop="platform">
|
||||
<el-select v-model="form.platform" placeholder="请选择第三方平台">
|
||||
<el-option
|
||||
v-for="dict in dict.type.iot_social_platform"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label=" 0:启用 ,1:禁用" prop="status">
|
||||
<el-select v-model="form.status" placeholder="请选择 0:启用 ,1:禁用">
|
||||
<el-option
|
||||
v-for="dict in dict.type.iot_social_platform_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台申请Id" prop="clientId">
|
||||
<el-input v-model="form.clientId" placeholder="请输入第三方平台申请Id"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台密钥" prop="secretKey">
|
||||
<el-input v-model="form.secretKey" placeholder="请输入第三方平台密钥"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户认证后跳转地址" prop="redirectUri">
|
||||
<el-input v-model="form.redirectUri" placeholder="请输入用户认证后跳转地址"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="删除标记位(0代表存在,2代表删除)" prop="delFlag">
|
||||
<el-input v-model="form.delFlag" placeholder="请输入删除标记位(0代表存在,2代表删除)"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入内容" type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="绑定注册登录uri,http://localhost/login?bindId=" prop="bindUri">
|
||||
<el-input v-model="form.bindUri" placeholder="请输入绑定注册登录uri,http://localhost/login?bindId="/>
|
||||
</el-form-item>
|
||||
<el-form-item label="跳转登录uri,http://localhost/login?loginId=" prop="redirectLoginUri">
|
||||
<el-input v-model="form.redirectLoginUri" placeholder="请输入跳转登录uri,http://localhost/login?loginId="/>
|
||||
</el-form-item>
|
||||
<el-form-item label="错误提示uri,http://localhost/login?errorId=" prop="errorMsgUri">
|
||||
<el-input v-model="form.errorMsgUri" placeholder="请输入错误提示uri,http://localhost/login?errorId="/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
|
||||
<el-form-item label="第三方平台名称" prop="platform">
|
||||
<el-select v-model="form.platform" placeholder="请选择第三方平台">
|
||||
<el-option v-for="dict in dict.type.iot_social_platform" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台状态" prop="status">
|
||||
<el-select v-model="form.status" placeholder="请选择状态">
|
||||
<el-option v-for="dict in dict.type.iot_social_platform_status" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台申请ID" prop="clientId">
|
||||
<el-input v-model="form.clientId" placeholder="请输入第三方平台申请Id" />
|
||||
</el-form-item>
|
||||
<el-form-item label="第三方平台密钥" prop="secretKey">
|
||||
<el-input v-model="form.secretKey" placeholder="请输入第三方平台密钥" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户认证跳转地址" prop="redirectUri">
|
||||
<el-input v-model="form.redirectUri" placeholder="请输入用户认证后跳转地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="绑定注册登录URI" prop="bindUri">
|
||||
<el-input v-model="form.bindUri" placeholder="请输入绑定注册登录uri,http://localhost/login?bindId=" />
|
||||
</el-form-item>
|
||||
<el-form-item label="跳转登录URI" prop="redirectLoginUri">
|
||||
<el-input v-model="form.redirectLoginUri" placeholder="请输入跳转登录uri,http://localhost/login?loginId=" />
|
||||
</el-form-item>
|
||||
<el-form-item label="错误提示URI" prop="errorMsgUri">
|
||||
<el-input v-model="form.errorMsgUri" placeholder="请输入错误提示uri,http://localhost/login?errorId=" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入内容" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {addPlatform, delPlatform, getPlatform, listPlatform, updatePlatform} from "@/api/iot/platform";
|
||||
import {
|
||||
addPlatform,
|
||||
delPlatform,
|
||||
getPlatform,
|
||||
listPlatform,
|
||||
updatePlatform
|
||||
} from "@/api/iot/platform";
|
||||
|
||||
export default {
|
||||
name: "Platform",
|
||||
dicts: ['iot_social_platform', 'iot_social_platform_status'],
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 第三方登录平台控制表格数据
|
||||
platformList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
platform: null,
|
||||
status: null,
|
||||
},
|
||||
columnTips: {
|
||||
bindId: "绑定登录uri, http://localhost/login?bindId=,域名换成对应域名即可,本地开发不需要更改",
|
||||
redirectLogin: "跳转登录uri,http://localhost/login?loginId=,域名换成对应域名即可,本地开发不需要更改",
|
||||
errorId: "错误提示获取uri,http://localhost/login?errorId=,域名换成对应域名即可,本地开发不需要更改"
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
platform: [
|
||||
{required: true, message: "第三方平台不能为空", trigger: "change"}
|
||||
],
|
||||
status: [
|
||||
{required: true, message: " 0:启用 ,1:禁用不能为空", trigger: "change"}
|
||||
],
|
||||
clientId: [
|
||||
{required: true, message: "第三方平台申请Id不能为空", trigger: "blur"}
|
||||
],
|
||||
secretKey: [
|
||||
{required: true, message: "第三方平台密钥不能为空", trigger: "blur"}
|
||||
],
|
||||
redirectUri: [
|
||||
{required: true, message: "用户认证后跳转地址不能为空", trigger: "blur"}
|
||||
],
|
||||
bindUri: [
|
||||
{required: true, message: "绑定注册登录uri,http://localhost/login?bindId=不能为空", trigger: "blur"}
|
||||
],
|
||||
redirectLoginUri: [
|
||||
{required: true, message: "跳转登录uri,http://localhost/login?loginId=不能为空", trigger: "blur"}
|
||||
],
|
||||
errorMsgUri: [
|
||||
{required: true, message: "错误提示uri,http://localhost/login?errorId=不能为空", trigger: "blur"}
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
renderHeaderMethods(h, {column}, content) {
|
||||
return h(
|
||||
'div', [
|
||||
h('span', column.label),
|
||||
h('el-tooltip', {
|
||||
props: {
|
||||
effect: 'dark',
|
||||
content: content,
|
||||
placement: 'top'
|
||||
name: "Platform",
|
||||
dicts: ['iot_social_platform', 'iot_social_platform_status'],
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 第三方登录平台控制表格数据
|
||||
platformList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
platform: null,
|
||||
status: null,
|
||||
},
|
||||
}, [
|
||||
h('i', {
|
||||
class: 'el-icon-question',
|
||||
style: 'color:#409EFF;margin-left:5px;'
|
||||
})
|
||||
])
|
||||
]
|
||||
);
|
||||
columnTips: {
|
||||
bindId: "绑定登录uri, http://localhost/login?bindId=,域名换成对应域名即可,本地开发不需要更改",
|
||||
redirectLogin: "跳转登录uri,http://localhost/login?loginId=,域名换成对应域名即可,本地开发不需要更改",
|
||||
errorId: "错误提示获取uri,http://localhost/login?errorId=,域名换成对应域名即可,本地开发不需要更改"
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
platform: [{
|
||||
required: true,
|
||||
message: "第三方平台不能为空",
|
||||
trigger: "change"
|
||||
}],
|
||||
status: [{
|
||||
required: true,
|
||||
message: " 0:启用 ,1:禁用不能为空",
|
||||
trigger: "change"
|
||||
}],
|
||||
clientId: [{
|
||||
required: true,
|
||||
message: "第三方平台申请Id不能为空",
|
||||
trigger: "blur"
|
||||
}],
|
||||
secretKey: [{
|
||||
required: true,
|
||||
message: "第三方平台密钥不能为空",
|
||||
trigger: "blur"
|
||||
}],
|
||||
redirectUri: [{
|
||||
required: true,
|
||||
message: "用户认证后跳转地址不能为空",
|
||||
trigger: "blur"
|
||||
}],
|
||||
bindUri: [{
|
||||
required: true,
|
||||
message: "绑定注册登录uri,http://localhost/login?bindId=不能为空",
|
||||
trigger: "blur"
|
||||
}],
|
||||
redirectLoginUri: [{
|
||||
required: true,
|
||||
message: "跳转登录uri,http://localhost/login?loginId=不能为空",
|
||||
trigger: "blur"
|
||||
}],
|
||||
errorMsgUri: [{
|
||||
required: true,
|
||||
message: "错误提示uri,http://localhost/login?errorId=不能为空",
|
||||
trigger: "blur"
|
||||
}]
|
||||
}
|
||||
};
|
||||
},
|
||||
/** 查询第三方登录平台控制列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listPlatform(this.queryParams).then(response => {
|
||||
this.platformList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
,
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
}
|
||||
,
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
socialPlatformId: null,
|
||||
platform: null,
|
||||
status: null,
|
||||
clientId: null,
|
||||
secretKey: null,
|
||||
redirectUri: null,
|
||||
delFlag: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateTime: null,
|
||||
updateBy: null,
|
||||
remark: null,
|
||||
bindUri: null,
|
||||
redirectLoginUri: null,
|
||||
errorMsgUri: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
}
|
||||
,
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
}
|
||||
,
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
}
|
||||
,
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.socialPlatformId)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
}
|
||||
,
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加第三方登录平台控制";
|
||||
}
|
||||
,
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const socialPlatformId = row.socialPlatformId || this.ids
|
||||
getPlatform(socialPlatformId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改第三方登录平台控制";
|
||||
});
|
||||
}
|
||||
,
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.socialPlatformId != null) {
|
||||
updatePlatform(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addPlatform(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
,
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const socialPlatformIds = row.socialPlatformId || this.ids;
|
||||
this.$modal.confirm('是否确认删除第三方登录平台控制编号为"' + socialPlatformIds + '"的数据项?').then(function () {
|
||||
return delPlatform(socialPlatformIds);
|
||||
}).then(() => {
|
||||
created() {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
renderHeaderMethods(h, {
|
||||
column
|
||||
}, content) {
|
||||
return h(
|
||||
'div', [
|
||||
h('span', column.label),
|
||||
h('el-tooltip', {
|
||||
props: {
|
||||
effect: 'dark',
|
||||
content: content,
|
||||
placement: 'top'
|
||||
},
|
||||
}, [
|
||||
h('i', {
|
||||
class: 'el-icon-question',
|
||||
style: 'color:#409EFF;margin-left:5px;'
|
||||
})
|
||||
])
|
||||
]
|
||||
);
|
||||
},
|
||||
/** 查询第三方登录平台控制列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listPlatform(this.queryParams).then(response => {
|
||||
this.platformList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
socialPlatformId: null,
|
||||
platform: null,
|
||||
status: null,
|
||||
clientId: null,
|
||||
secretKey: null,
|
||||
redirectUri: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateTime: null,
|
||||
updateBy: null,
|
||||
remark: null,
|
||||
bindUri: null,
|
||||
redirectLoginUri: null,
|
||||
errorMsgUri: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.socialPlatformId)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加第三方登录平台控制";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const socialPlatformId = row.socialPlatformId || this.ids
|
||||
getPlatform(socialPlatformId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改第三方登录平台控制";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.socialPlatformId != null) {
|
||||
updatePlatform(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addPlatform(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const socialPlatformIds = row.socialPlatformId || this.ids;
|
||||
this.$modal.confirm('是否确认删除第三方登录平台控制编号为"' + socialPlatformIds + '"的数据项?').then(function () {
|
||||
return delPlatform(socialPlatformIds);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('iot/platform/export', {
|
||||
...this.queryParams
|
||||
}, `platform_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
,
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('iot/platform/export', {
|
||||
...this.queryParams
|
||||
}, `platform_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,369 +1,356 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<div class="login">
|
||||
|
||||
<div style="width:520px;padding:20px;">
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<div class="login-top">
|
||||
<h1>物美智能 - 开源生活物联网平台</h1>
|
||||
<h2>wumei smart open source living iot platform</h2>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" style="z-index:1000">
|
||||
<h3 class="title" v-if="!bindAccount">账号登录
|
||||
<span style="font-size:16px;color:#eee">( 演示账号:wumei<span style="margin:0 10px;">123456 )</span></span>
|
||||
</h3>
|
||||
<h3 class="bindAccountTitle" v-else>绑定物美智能账户
|
||||
</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
|
||||
@keyup.enter.native="handleLogin">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaOnOff">
|
||||
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
|
||||
@keyup.enter.native="handleLogin">
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;color:#000;">记住密码</el-checkbox>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button v-if="!bindAccount" :loading="loading" size="medium" type="primary" style="width:100%;"
|
||||
@click.native.prevent="handleLogin">
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
<el-button v-else :loading="loading" size="medium" type="primary" style="width:100%;"
|
||||
@click.native.prevent="handleLogin">
|
||||
<span v-if="!loading">绑定</span>
|
||||
<span v-else>绑 定 中...</span>
|
||||
</el-button>
|
||||
<div style="margin-top:20px;" v-if="!bindAccount">
|
||||
<div v-if="!bindAccount" style=";text-align: center ">
|
||||
|
||||
<el-button type="success" circle title="微信登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="wechat"/>
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" circle title="QQ登录" size="small" @click="qqLogin">
|
||||
<svg-icon icon-class="qq"/>
|
||||
</el-button>
|
||||
<el-button type="primary" circle title="支付宝登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="zhifubao"/>
|
||||
</el-button>
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<div class="login-top">
|
||||
<h1>物美智能 - 开源生活物联网平台</h1>
|
||||
<h2>wumei smart open source living iot platform</h2>
|
||||
</div>
|
||||
</div>
|
||||
<a style="margin-right:20px;color:#222" target="_blank" href="http://wumei.live">返回官网</a>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" style="z-index:1000">
|
||||
<h3 class="title" v-if="!bindAccount">账号登录
|
||||
<span style="font-size:16px;color:#eee">( 演示账号:wumei<span style="margin:0 10px;">123456 )</span></span>
|
||||
</h3>
|
||||
<h3 class="bindAccountTitle" v-else>绑定物美智能账户
|
||||
</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaOnOff">
|
||||
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin">
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;color:#000;">记住密码</el-checkbox>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button v-if="!bindAccount" :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin">
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
<el-button v-else :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin">
|
||||
<span v-if="!loading">绑定</span>
|
||||
<span v-else>绑 定 中...</span>
|
||||
</el-button>
|
||||
<div style="margin-top:30px;" v-if="!bindAccount">
|
||||
<div v-if="!bindAccount" style="float:left;">
|
||||
<span style="color:#fff;margin-right:10px;">第三方登录</span>
|
||||
<el-button type="success" circle title="微信登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="wechat" />
|
||||
</el-button>
|
||||
|
||||
<div style="float: right;margin-top:10px;" v-if="register">
|
||||
<el-button type="danger" circle title="QQ登录" size="small" @click="qqLogin">
|
||||
<svg-icon icon-class="qq" />
|
||||
</el-button>
|
||||
<el-button type="primary" circle title="支付宝登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="zhifubao" />
|
||||
</el-button>
|
||||
</div>
|
||||
<div style="float:right;" v-if="register">
|
||||
<router-link style="color:#333;font-size:16px;" :to='{path:"/register",query: this.$route.query }'>立即注册>>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<router-link style="color:#fff;font-size:16px;" :to='{path:"/register",query: this.$route.query }'>立即注册
|
||||
>>
|
||||
</router-link>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>Copyright © 2018-2021 <a target="_blank"
|
||||
href="http://wumei.live">wumei smart</a> All Rights Reserved.</span>
|
||||
<span>Copyright © 2018-2021 <a target="_blank" href="http://wumei.live">wumei smart</a> All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getCodeImg,
|
||||
checkBindId,
|
||||
getErrorMsg
|
||||
getCodeImg,
|
||||
checkBindId,
|
||||
getErrorMsg
|
||||
} from "@/api/login";
|
||||
import Cookies from "js-cookie";
|
||||
import {
|
||||
encrypt,
|
||||
decrypt
|
||||
encrypt,
|
||||
decrypt
|
||||
} from '@/utils/jsencrypt'
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
codeUrl: "",
|
||||
loginForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: "",
|
||||
bindId: ""
|
||||
},
|
||||
loginRules: {
|
||||
username: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的账号"
|
||||
}],
|
||||
password: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的密码"
|
||||
}],
|
||||
code: [{
|
||||
required: true,
|
||||
trigger: "change",
|
||||
message: "请输入验证码"
|
||||
}]
|
||||
},
|
||||
loading: false,
|
||||
// 验证码开关
|
||||
captchaOnOff: true,
|
||||
bindAccount: false,
|
||||
// 注册开关
|
||||
register: true,
|
||||
redirect: undefined
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function (route) {
|
||||
this.redirect = route.query && route.query.redirect;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let loginId = this.$route.query.loginId;
|
||||
if (loginId === undefined || loginId === null) {
|
||||
this.checkBind();
|
||||
this.checkErrorMsg();
|
||||
this.getCode();
|
||||
this.getCookie();
|
||||
} else {
|
||||
this.redirectLogin(loginId);
|
||||
}
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
codeUrl: "",
|
||||
loginForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: "",
|
||||
bindId: ""
|
||||
},
|
||||
loginRules: {
|
||||
username: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的账号"
|
||||
}],
|
||||
password: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的密码"
|
||||
}],
|
||||
code: [{
|
||||
required: true,
|
||||
trigger: "change",
|
||||
message: "请输入验证码"
|
||||
}]
|
||||
},
|
||||
loading: false,
|
||||
// 验证码开关
|
||||
captchaOnOff: true,
|
||||
bindAccount: false,
|
||||
// 注册开关
|
||||
register: true,
|
||||
redirect: undefined
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function (route) {
|
||||
this.redirect = route.query && route.query.redirect;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let loginId = this.$route.query.loginId;
|
||||
if (loginId === undefined || loginId === null) {
|
||||
this.checkBind();
|
||||
this.checkErrorMsg();
|
||||
this.getCode();
|
||||
this.getCookie();
|
||||
} else {
|
||||
this.redirectLogin(loginId);
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
redirectLogin(loginId) {
|
||||
this.loading = true;
|
||||
this.$store.dispatch("RedirectLogin", loginId).then(() => {
|
||||
this.$router.push({
|
||||
path: this.redirect || "/"
|
||||
}).catch(() => {
|
||||
});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
});
|
||||
},
|
||||
checkBind() {
|
||||
let query = this.$route.query;
|
||||
let bindId = query.bindId;
|
||||
if (bindId === undefined || bindId === null) {
|
||||
this.bindAccount = false;
|
||||
} else {
|
||||
this.bindAccount = true;
|
||||
checkBindId(bindId).then(res => {
|
||||
this.bindAccount = res.bindAccount === undefined ? true : res.bindAccount
|
||||
if (this.bindAccount) {
|
||||
this.loginForm.bindId = bindId;
|
||||
} else {
|
||||
this.loginForm.bindId = "";
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
checkErrorMsg() {
|
||||
let errorId = this.$route.query.errorId;
|
||||
if (errorId !== undefined && errorId !== null) {
|
||||
getErrorMsg(errorId).then(res => {
|
||||
}).catch(err => {
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
|
||||
if (this.captchaOnOff) {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.loginForm.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
},
|
||||
getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
const password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get('rememberMe')
|
||||
this.loginForm = {
|
||||
username: username === undefined ? this.loginForm.username : username,
|
||||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
},
|
||||
qqLogin() {
|
||||
window.location.href = "http://localhost:8080/auth/render/qq";
|
||||
},
|
||||
authLogin() {
|
||||
this.$alert('第三方登录正在集成中...', '提示消息', {
|
||||
confirmButtonText: '确定',
|
||||
callback: action => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `action: ${action}`
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.loginForm.rememberMe) {
|
||||
Cookies.set("username", this.loginForm.username, {
|
||||
expires: 30
|
||||
});
|
||||
Cookies.set("password", encrypt(this.loginForm.password), {
|
||||
expires: 30
|
||||
});
|
||||
Cookies.set('rememberMe', this.loginForm.rememberMe, {
|
||||
expires: 30
|
||||
});
|
||||
} else {
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
console.log(this.loginForm)
|
||||
this.$store.dispatch("Login", this.loginForm).then(() => {
|
||||
this.$router.push({
|
||||
path: this.redirect || "/"
|
||||
methods: {
|
||||
redirectLogin(loginId) {
|
||||
this.loading = true;
|
||||
this.$store.dispatch("RedirectLogin", loginId).then(() => {
|
||||
this.$router.push({
|
||||
path: this.redirect || "/"
|
||||
}).catch(() => {});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
},
|
||||
checkBind() {
|
||||
let query = this.$route.query;
|
||||
let bindId = query.bindId;
|
||||
if (bindId === undefined || bindId === null) {
|
||||
this.bindAccount = false;
|
||||
} else {
|
||||
this.bindAccount = true;
|
||||
checkBindId(bindId).then(res => {
|
||||
this.bindAccount = res.bindAccount === undefined ? true : res.bindAccount
|
||||
if (this.bindAccount) {
|
||||
this.loginForm.bindId = bindId;
|
||||
} else {
|
||||
this.loginForm.bindId = "";
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
checkErrorMsg() {
|
||||
let errorId = this.$route.query.errorId;
|
||||
if (errorId !== undefined && errorId !== null) {
|
||||
getErrorMsg(errorId).then(res => {}).catch(err => {
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
|
||||
if (this.captchaOnOff) {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.loginForm.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
},
|
||||
getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
const password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get('rememberMe')
|
||||
this.loginForm = {
|
||||
username: username === undefined ? this.loginForm.username : username,
|
||||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
},
|
||||
qqLogin() {
|
||||
window.location.href = "http://localhost:8080/auth/render/qq";
|
||||
},
|
||||
authLogin() {
|
||||
this.$alert('第三方登录正在集成中...', '提示消息', {
|
||||
confirmButtonText: '确定',
|
||||
callback: action => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `action: ${action}`
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.loginForm.rememberMe) {
|
||||
Cookies.set("username", this.loginForm.username, {
|
||||
expires: 30
|
||||
});
|
||||
Cookies.set("password", encrypt(this.loginForm.password), {
|
||||
expires: 30
|
||||
});
|
||||
Cookies.set('rememberMe', this.loginForm.rememberMe, {
|
||||
expires: 30
|
||||
});
|
||||
} else {
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
console.log(this.loginForm)
|
||||
this.$store.dispatch("Login", this.loginForm).then(() => {
|
||||
this.$router.push({
|
||||
path: this.redirect || "/"
|
||||
}).catch(() => {});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.login {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: linear-gradient(303deg, #48c6ef 10%, #6f86d6 80%);
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: linear-gradient(303deg, #48c6ef 10%, #6f86d6 80%);
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.bindAccountTitle {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.login-top {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-top: 100px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-top: 100px;
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 21px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 21px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form {
|
||||
border-radius: 6px;
|
||||
background-color: rgba(250, 250, 250, 0.2);
|
||||
border: 1px solid #fff;
|
||||
padding: 25px 25px 5px 25px;
|
||||
margin: 20px;
|
||||
margin-bottom: 100px;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(250, 250, 250, 0.2);
|
||||
border: 1px solid #fff;
|
||||
padding: 25px 25px 5px 25px;
|
||||
margin: 20px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
.el-input {
|
||||
height: 38px;
|
||||
.el-input {
|
||||
height: 38px;
|
||||
|
||||
input {
|
||||
height: 38px;
|
||||
input {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.login-code-img {
|
||||
height: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,360 +1,343 @@
|
||||
<template>
|
||||
<div class="register">
|
||||
<div class="register">
|
||||
|
||||
<div style="width:520px;padding:20px;">
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<div class="login-top">
|
||||
<h1>物美智能 - 开源生活物联网平台</h1>
|
||||
<h2>wumei smart open source living iot platform</h2>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form"
|
||||
style="z-index:1000">
|
||||
<h3 class="title" v-if="!bindAccount">注册账号</h3>
|
||||
<h3 class="title" v-else>注册绑定物美智能账户</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="phonenumber">
|
||||
<el-input v-model="registerForm.phonenumber" type="text" auto-complete="off" placeholder="手机号码">
|
||||
<svg-icon slot="prefix" icon-class="phone" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="registerForm.password" type="password" auto-complete="off" placeholder="密码"
|
||||
@keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input v-model="registerForm.confirmPassword" type="password" auto-complete="off" placeholder="确认密码"
|
||||
@keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaOnOff">
|
||||
<el-input v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
|
||||
@keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon"/>
|
||||
</el-input>
|
||||
<div class="register-code">
|
||||
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button v-if="!bindAccount" :loading="loading" size="medium" type="primary" style="width:100%;"
|
||||
@click.native.prevent="handleRegister">
|
||||
<span v-if="!loading">注 册</span>
|
||||
<span v-else>注 册 中...</span>
|
||||
</el-button>
|
||||
<el-button v-else :loading="loading" size="medium" type="primary" style="width:100%;"
|
||||
@click.native.prevent="handleRegister">
|
||||
<span v-if="!loading">绑 定</span>
|
||||
<span v-else>绑 定 中...</span>
|
||||
</el-button>
|
||||
<div style="margin-top:20px;">
|
||||
|
||||
<div v-if="!bindAccount" style=" margin-bottom: 10px;text-align: center ">
|
||||
<!-- <span style="color:#fff;margin-right:10px; float: left">快速登录</span>-->
|
||||
|
||||
<el-button type="success" circle title="微信登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="wechat"/>
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" circle title="QQ登录" size="small" @click="qqLogin">
|
||||
<svg-icon icon-class="qq"/>
|
||||
</el-button>
|
||||
<el-button type="primary" circle title="支付宝登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="zhifubao"/>
|
||||
</el-button>
|
||||
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<div class="login-top">
|
||||
<h1>物美智能 - 开源生活物联网平台</h1>
|
||||
<h2>wumei smart open source living iot platform</h2>
|
||||
</div>
|
||||
<router-link style="float:left;color:#fff;font-size:16px;"
|
||||
:to='{path:"/login",query: this.$route.query }'>使用已有账户登录 >>
|
||||
</router-link>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form" style="z-index:1000">
|
||||
<h3 class="title" v-if="!bindAccount">注册账号</h3>
|
||||
<h3 class="title" v-else>注册绑定物美智能账户</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="phonenumber">
|
||||
<el-input v-model="registerForm.phonenumber" type="text" auto-complete="off" placeholder="手机号码">
|
||||
<svg-icon slot="prefix" icon-class="phone" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="registerForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input v-model="registerForm.confirmPassword" type="password" auto-complete="off" placeholder="确认密码" @keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaOnOff">
|
||||
<el-input v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleRegister">
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
<div class="register-code">
|
||||
<img :src="codeUrl" @click="getCode" class="register-code-img" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button v-if="!bindAccount" :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleRegister">
|
||||
<span v-if="!loading">注 册</span>
|
||||
<span v-else>注 册 中...</span>
|
||||
</el-button>
|
||||
<el-button v-else :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleRegister">
|
||||
<span v-if="!loading">绑 定</span>
|
||||
<span v-else>绑 定 中...</span>
|
||||
</el-button>
|
||||
<div style="margin-top:30px;">
|
||||
<div v-if="!bindAccount" style=" margin-bottom: 10px;text-align: center ;float:left;">
|
||||
<span style="color:#fff;margin-right:10px;">第三方登录</span>
|
||||
<el-button type="success" circle title="微信登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="wechat" />
|
||||
</el-button>
|
||||
<el-button type="danger" circle title="QQ登录" size="small" @click="qqLogin">
|
||||
<svg-icon icon-class="qq" />
|
||||
</el-button>
|
||||
<el-button type="primary" circle title="支付宝登录" size="small" @click="authLogin">
|
||||
<svg-icon icon-class="zhifubao" />
|
||||
</el-button>
|
||||
</div>
|
||||
<router-link style="float:right;color:#333;font-size:16px;" :to='{path:"/login",query: this.$route.query }'>已有账户登录 >>
|
||||
</router-link>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
|
||||
<div style="float: right">
|
||||
<a style="margin-right:20px;" target="_blank" href="http://wumei.live">返回官网</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 底部 -->
|
||||
<div class="el-register-footer">
|
||||
<span>Copyright © 2018-2021 <a target="_blank"
|
||||
href="http://wumei.live">wumei smart</a> All Rights Reserved.</span>
|
||||
<span>Copyright © 2018-2021 <a target="_blank" href="http://wumei.live">wumei smart</a> All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getCodeImg, checkBindId, bindRegister
|
||||
getCodeImg,
|
||||
checkBindId,
|
||||
bindRegister
|
||||
} from "@/api/login";
|
||||
import {
|
||||
register
|
||||
register
|
||||
} from '@/api/iot/tool';
|
||||
|
||||
export default {
|
||||
name: "Register",
|
||||
data() {
|
||||
const equalToPassword = (rule, value, callback) => {
|
||||
if (this.registerForm.password !== value) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
codeUrl: "",
|
||||
registerForm: {
|
||||
username: "",
|
||||
phonenumber: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
code: "",
|
||||
uuid: "",
|
||||
bindId: ""
|
||||
},
|
||||
registerRules: {
|
||||
username: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的账号"
|
||||
},
|
||||
{
|
||||
min: 2,
|
||||
max: 20,
|
||||
message: '用户账号长度必须介于 2 和 20 之间',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
phonenumber: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的手机号码"
|
||||
},
|
||||
{
|
||||
min: 11,
|
||||
max: 11,
|
||||
message: '手机号码长度为11',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的密码"
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: '用户密码长度必须介于 5 和 20 之间',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
confirmPassword: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请再次输入您的密码"
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
validator: equalToPassword,
|
||||
trigger: "blur"
|
||||
}
|
||||
],
|
||||
code: [{
|
||||
required: true,
|
||||
trigger: "change",
|
||||
message: "请输入验证码"
|
||||
}]
|
||||
},
|
||||
loading: false,
|
||||
captchaOnOff: true,
|
||||
bindAccount: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.checkBind();
|
||||
this.getCode();
|
||||
},
|
||||
methods: {
|
||||
checkBind() {
|
||||
let query = this.$route.query;
|
||||
let bindId = query.bindId;
|
||||
if (bindId === undefined || bindId === null) {
|
||||
this.bindAccount = false;
|
||||
} else {
|
||||
this.bindAccount = true;
|
||||
checkBindId(bindId).then(res => {
|
||||
this.bindAccount = res.bindAccount === undefined ? true : res.bindAccount
|
||||
if (this.bindAccount) {
|
||||
this.registerForm.bindId = bindId;
|
||||
} else {
|
||||
this.registerForm.bindId = "";
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
name: "Register",
|
||||
data() {
|
||||
const equalToPassword = (rule, value, callback) => {
|
||||
if (this.registerForm.password !== value) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
codeUrl: "",
|
||||
registerForm: {
|
||||
username: "",
|
||||
phonenumber: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
code: "",
|
||||
uuid: "",
|
||||
bindId: ""
|
||||
},
|
||||
registerRules: {
|
||||
username: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的账号"
|
||||
},
|
||||
{
|
||||
min: 2,
|
||||
max: 20,
|
||||
message: '用户账号长度必须介于 2 和 20 之间',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
phonenumber: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的手机号码"
|
||||
},
|
||||
{
|
||||
min: 11,
|
||||
max: 11,
|
||||
message: '手机号码长度为11',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请输入您的密码"
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: '用户密码长度必须介于 5 和 20 之间',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
confirmPassword: [{
|
||||
required: true,
|
||||
trigger: "blur",
|
||||
message: "请再次输入您的密码"
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
validator: equalToPassword,
|
||||
trigger: "blur"
|
||||
}
|
||||
],
|
||||
code: [{
|
||||
required: true,
|
||||
trigger: "change",
|
||||
message: "请输入验证码"
|
||||
}]
|
||||
},
|
||||
loading: false,
|
||||
captchaOnOff: true,
|
||||
bindAccount: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.checkBind();
|
||||
this.getCode();
|
||||
},
|
||||
methods: {
|
||||
checkBind() {
|
||||
let query = this.$route.query;
|
||||
let bindId = query.bindId;
|
||||
if (bindId === undefined || bindId === null) {
|
||||
this.bindAccount = false;
|
||||
} else {
|
||||
this.bindAccount = true;
|
||||
checkBindId(bindId).then(res => {
|
||||
this.bindAccount = res.bindAccount === undefined ? true : res.bindAccount
|
||||
if (this.bindAccount) {
|
||||
this.registerForm.bindId = bindId;
|
||||
} else {
|
||||
this.registerForm.bindId = "";
|
||||
this.$router.push({
|
||||
query: {}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
|
||||
if (this.captchaOnOff) {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.registerForm.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
},
|
||||
qqLogin() {
|
||||
window.location.href = "http://localhost:8080/auth/render/qq";
|
||||
},
|
||||
authLogin() {
|
||||
this.$alert('第三方登录正在集成中...', '提示消息', {
|
||||
confirmButtonText: '确定',
|
||||
callback: action => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `action: ${action}`
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleRegister() {
|
||||
this.$refs.registerForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.bindAccount) {
|
||||
bindRegister(this.registerForm).then(res => {
|
||||
this.innerRegister(res)
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
|
||||
if (this.captchaOnOff) {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.registerForm.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
register(this.registerForm).then(res => {
|
||||
this.innerRegister(res)
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
qqLogin() {
|
||||
window.location.href = "http://localhost:8080/auth/render/qq";
|
||||
},
|
||||
authLogin() {
|
||||
this.$alert('第三方登录正在集成中...', '提示消息', {
|
||||
confirmButtonText: '确定',
|
||||
callback: action => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `action: ${action}`
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleRegister() {
|
||||
this.$refs.registerForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.bindAccount) {
|
||||
bindRegister(this.registerForm).then(res => {
|
||||
this.innerRegister(res)
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
register(this.registerForm).then(res => {
|
||||
this.innerRegister(res)
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaOnOff) {
|
||||
this.getCode();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
innerRegister(res) {
|
||||
const username = this.registerForm.username;
|
||||
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
type: 'success'
|
||||
}).then(() => {
|
||||
this.$router.push("/login");
|
||||
}).catch(() => {});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
innerRegister(res) {
|
||||
const username = this.registerForm.username;
|
||||
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
type: 'success'
|
||||
}).then(() => {
|
||||
this.$router.push("/login");
|
||||
}).catch(() => {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.register {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background: linear-gradient(303deg, #48c6ef 10%, #6f86d6 80%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background: linear-gradient(303deg, #48c6ef 10%, #6f86d6 80%);
|
||||
}
|
||||
|
||||
.login-top {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-top: 100px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-top: 100px;
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 21px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 21px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
background-color: rgba(250, 250, 250, 0.2);
|
||||
border: 1px solid #fff;
|
||||
padding: 25px 25px 5px 25px;
|
||||
margin: 20px;
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
background-color: rgba(250, 250, 250, 0.2);
|
||||
border: 1px solid #fff;
|
||||
padding: 25px 25px 5px 25px;
|
||||
margin: 20px;
|
||||
|
||||
.el-input {
|
||||
height: 38px;
|
||||
.el-input {
|
||||
height: 38px;
|
||||
|
||||
input {
|
||||
height: 38px;
|
||||
input {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.register-code {
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.el-register-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.register-code-img {
|
||||
height: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user