前端测试更新

This commit is contained in:
kerwincui
2024-03-30 01:19:01 +08:00
parent 069641c573
commit b463bbc8c9
74 changed files with 7 additions and 6257 deletions

View File

@@ -1,43 +0,0 @@
<template>
<div class='kong'>
<slot></slot>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
};
},
props:{
data:{
type:Array,
default:()=>[]
}
},
computed: {},
methods: {
init(){
},
},
created() {
},
mounted() {
},
beforeDestroy() {
},
}
</script>
<style lang='scss' scoped>
.kong{
width: 100%;
height: 100%;
}
</style>

View File

@@ -1,30 +0,0 @@
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
created(){
},
mounted() {
},
methods: {
},
}
</script>
<style lang='scss' scoped>
</style>

View File

@@ -1,266 +0,0 @@
<template>
<div style="padding:6px;">
<el-card v-show="showSearch" style="margin-bottom:6px;">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" style="margin-bottom:-20px;">
<el-form-item label="告警名称" prop="alertName">
<el-input v-model="queryParams.alertName" placeholder="请输入告警名称" clearable size="small" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="告警级别" prop="alertLevel">
<el-select v-model="queryParams.alertLevel" placeholder="请选择告警级别" clearable size="small">
<el-option v-for="dict in dict.type.iot_alert_level" :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" placeholder="请选择处理状态" clearable size="small">
<el-option v-for="dict in dict.type.iot_process_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-card>
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="alertLogList" @selection-change="handleSelectionChange" border>
<el-table-column label="告警名称" align="center" prop="alertName" />
<el-table-column label="告警级别" align="center" prop="alertLevel">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_alert_level" :value="scope.row.alertLevel" />
</template>
</el-table-column>
<el-table-column label="处理状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_process_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="产品ID" align="center" prop="productId" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="设备ID" align="center" prop="deviceId" />
<el-table-column label="设备名称" align="center" prop="deviceName" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="处理结果" align="center" prop="remark" />
<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:alertLog:edit']">处理</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" />
<!-- 添加或修改设备告警对话框 -->
<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="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" rows="8" />
</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>
</el-card>
</div>
</template>
<script>
import {
listAlertLog,
getAlertLog,
delAlertLog,
addAlertLog,
updateAlertLog
} from "@/api/iot/alertLog";
export default {
name: "AlertLog",
dicts: ['iot_alert_level', 'iot_process_status'],
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 设备告警表格数据
alertLogList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
alertName: null,
alertLevel: null,
status: null,
productId: null,
productName: null,
deviceId: null,
deviceName: null,
},
// 表单参数
form: {},
// 表单校验
rules: {
alertName: [{
required: true,
message: "告警名称不能为空",
trigger: "blur"
}],
alertLevel: [{
required: true,
message: "告警级别不能为空",
trigger: "change"
}],
status: [{
required: true,
message: "处理状态(0=不需要处理,1=未处理,2=已处理)不能为空",
trigger: "change"
}],
productId: [{
required: true,
message: "产品ID不能为空",
trigger: "blur"
}],
productName: [{
required: true,
message: "产品名称不能为空",
trigger: "blur"
}],
deviceId: [{
required: true,
message: "设备ID不能为空",
trigger: "blur"
}],
deviceName: [{
required: true,
message: "设备名称不能为空",
trigger: "blur"
}],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询设备告警列表 */
getList() {
this.loading = true;
listAlertLog(this.queryParams).then(response => {
this.alertLogList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
alertLogId: null,
alertName: null,
alertLevel: null,
status: null,
productId: null,
productName: null,
deviceId: null,
deviceName: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: 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.alertLogId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加设备告警";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const alertLogId = row.alertLogId || this.ids
getAlertLog(alertLogId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改设备告警";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.alertLogId != null) {
updateAlertLog(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addAlertLog(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const alertLogIds = row.alertLogId || this.ids;
this.$modal.confirm('是否确认删除设备告警编号为"' + alertLogIds + '"的数据项?').then(function () {
return delAlertLog(alertLogIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('iot/alertLog/export', {
...this.queryParams
}, `alertLog_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -178,6 +178,12 @@
<device-monitor ref="deviceMonitor" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceStastic" :disabled="form.deviceId == 0"
v-if="form.deviceType !== 3 && hasShrarePerm('statistic')">
<span slot="label">监测统计</span>
<device-statistic ref="deviceStatistic" :device="form" />
</el-tab-pane>
<!-- 用于设置间距 -->
<el-tab-pane disabled>
<span slot="label">

View File

@@ -1,141 +0,0 @@
<template>
<span></span>
</template>
<script>
import mqtt from 'mqtt'
import {
getToken
} from "@/utils/auth";
export default {
name: "mqttClient",
props: {
publish: {
type: Object,
default: null
},
subscribes: {
type: Array,
default: null
}
},
watch: {
// 获取到父组件传递的值
publish: function (val, oldVal) {
this.mqttPublish(val.topic, val.message, val.name);
},
subscribes: function (val, oldVal) {
this.connectMqtt(val);
}
},
data() {
return {};
},
created() {
},
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: randomClientId,
connectTimeout: 10000
}
// 配置Mqtt地址
// let url = "ws://" + window.location.hostname + ":8083/mqtt";
console.log("mqtt地址", process.env.VUE_APP_EMQX_SERVER_URL);
this.client = mqtt.connect(process.env.VUE_APP_EMQX_SERVER_URL, options);
this.client.on("connect", (e) => {
console.log("客户端:" + randomClientId + ",成功连接服务器:", e);
// 订阅主题
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()
// 是否已经断开连接
this.mqttError()
// 监听获取信息
this.mqttSubscribe()
},
/** 发布消息 */
mqttPublish(topic, message, name) {
if (!this.client.connected) {
console.log('客户端未连接')
this.$modal.notifyError("Mqtt客户端未连接");
return
}
this.client.publish(topic, message, {
qos: 1
}, (err) => {
if (!err) {
console.log('成功发布主题:' + topic)
console.log('主题内容:' + message);
if (topic.indexOf('offline') > 0) {
this.$modal.notify("[ " + name + " ] 影子指令发送成功");
} else {
this.$modal.notifySuccess("[ " + name + " ] 指令发送成功");
}
}
})
},
/** 监听Mqtt消息 */
mqttSubscribe() {
this.client.on("message", (topic, message) => {
console.log('收到来自', topic, '的信息', message.toString())
// 传递信息到父组件
let data = {};
data.topic = topic;
data.message = JSON.parse(message.toString());
this.$emit('callbackEvent', data);
});
},
/** 监听服务器是否连接失败 */
mqttError() {
this.client.on('error', (error) => {
console.log('连接失败:', error)
this.$modal.notifyError("Mqtt客户端连接失败");
this.client.end();
})
},
/** 取消订阅 */
unsubscribeMqtt() {
this.client.unsubscribe(this.mtopic, (error) => {
console.log('主题为' + this.mtopic + '取消订阅成功', error)
})
},
/** 断开连接 */
unconnectMqtt() {
this.client.end()
this.client = null
console.log('服务器已断开连接!');
this.$modal.notifyError("Mqtt服务器已断开连接");
},
/** 监听服务器重新连接 */
reconnectMqtt() {
this.client.on('reconnect', (error) => {
console.log('正在重连:', error)
});
},
}
};
</script>

View File

@@ -1,327 +0,0 @@
<template>
<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="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>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="padding-bottom: 100px">
<el-table v-loading="loading" :data="clientList">
<el-table-column label="客户端ID" align="left" header-align="center" prop="clientid">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click.native="handleOpen(scope.row)">{{ scope.row.clientid }}</el-link>
</template>
</el-table-column>
<el-table-column label="节点" align="center" prop="node" width="120" />
<el-table-column label="IP地址" align="center" prop="ip_address" />
<el-table-column label="类型" align="center" prop="type">
<template slot-scope="scope">
<el-tag type="danger" v-if="scope.row.clientid.indexOf('server') == 0">服务端</el-tag>
<el-tag type="success" v-else-if="scope.row.clientid.indexOf('web') == 0">Web端</el-tag>
<el-tag type="warning" v-else-if="scope.row.clientid.indexOf('phone') == 0">移动端</el-tag>
<el-tag type="info" v-else-if="scope.row.clientid.indexOf('test') == 0">测试端</el-tag>
<el-tag type="primary" v-else>设备端</el-tag>
</template>
</el-table-column>
<el-table-column label="连接状态" align="center" prop="connected">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.connected">已连接</el-tag>
<el-tag type="info" v-else>已断开</el-tag>
</template>
</el-table-column>
<el-table-column label="心跳(秒)" align="center" prop="keepalive" width="100" />
<el-table-column label="会话过期间隔" align="center" prop="expiry_interval" width="100" />
<el-table-column label="当前订阅数量" align="center" prop="subscriptions_cnt" width="100" />
<el-table-column label="连接时间" align="center" prop="connected_at" />
<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="['iot:emqx:remove']" @click="handleDelete(scope.row)">
<svg-icon icon-class="disconnect" /> 断开连接
</el-button>
</template>
</el-table-column>
</el-table>
<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="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-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="清除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>
<el-descriptions-item label="会话创建时间">{{form.created_at}}</el-descriptions-item>
<el-descriptions-item label="订阅数量">{{ form.subscriptions_cnt }}/{{form.max_subscriptions}}</el-descriptions-item>
<el-descriptions-item label="IP地址">{{form.ip_address}}</el-descriptions-item>
<el-descriptions-item label="端口">{{form.port}}</el-descriptions-item>
<el-descriptions-item label="最大订阅数量">{{form.max_subscriptions}}</el-descriptions-item>
<el-descriptions-item label="飞行窗口">{{ form.inflight }}/{{ form.max_inflight }}</el-descriptions-item>
<el-descriptions-item label="心跳(秒)">{{form.keepalive}}</el-descriptions-item>
<el-descriptions-item label="是否为桥接">{{form.is_bridge}}</el-descriptions-item>
<el-descriptions-item label="最大飞行窗口">{{form.max_inflight}}</el-descriptions-item>
<el-descriptions-item label="消息队列">{{ form.mqueue_len }}/{{ form.max_mqueue }}</el-descriptions-item>
<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>
</el-descriptions-item>
<el-descriptions-item label="最大消息队列">{{form.max_mqueue}}</el-descriptions-item>
<el-descriptions-item label="未确认的PUBREC数据包计数">{{form.awaiting_rel}}</el-descriptions-item>
<el-descriptions-item label="Zone">{{form.zone}}</el-descriptions-item>
<el-descriptions-item label="最大未确认的PUBREC数据包计数">{{form.max_awaiting_rel}}</el-descriptions-item>
<el-descriptions-item label="接收的TCP报文数量">{{form.recv_cnt}}</el-descriptions-item>
<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-tab-pane>
<el-tab-pane name="subscribe">
<span slot="label">订阅列表</span>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-refresh" size="mini" @click="handleRefresh" v-hasPermi="['iot:emqx:query']">刷新</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-plus" size="mini" :disabled="single" @click="handleAdd" v-hasPermi="['iot:emqx:add']">添加订阅</el-button>
</el-col>
</el-row>
<el-table v-loading="loadSubscribeing" :data="subscribeList">
<el-table-column label="主题" align="center" prop="topic" />
<el-table-column label="QoS" align="center" prop="qos" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
<template slot-scope="scope">
<el-button size="small" type="danger" style="padding: 5px" v-hasPermi="['iot:emqx:remove']" @click="handleUnsubscribe(scope.row)">
<svg-icon icon-class="disconnect" /> 取消订阅
</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-dialog>
</el-card>
<!-- 添加或修改订阅对话框 -->
<el-dialog title="添加订阅" :visible.sync="subscribeOpen" width="800px" append-to-body>
<el-form ref="subscribeForm" :model="subscribeForm" :rules="rules" label-width="60px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="主题" prop="topic">
<el-input v-model="subscribeForm.topic" placeholder="请输入主题" />
</el-form-item>
<el-form-item label="Qos" prop="qos">
<el-select v-model="subscribeForm.qos" placeholder="请选择消息类型">
<el-option key="0" label="0" value="0"></el-option>
<el-option key="1" label="1" value="1"></el-option>
<el-option key="2" label="2" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancelSubscribe"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listMqttClient,
eliminateClient,
getClientDetails,
getSubscriptionsByClientId,
unsubscribe,
addSubscribe,
} from "@/api/iot/emqx";
export default {
name: "Category",
data() {
return {
// 非单个禁用
single: true,
// 遮罩层
loading: true,
loadSubscribeing: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 产品分类表格数据
clientList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否显示添加订阅弹出层
subscribeOpen: false,
// 查询参数
queryParams: {
_limit: 10,
_page: 1,
clientid:null,
},
// 表单参数
form: {},
// 选中选项卡
activeName: "basic",
//订阅列表数据
subscribeList: [],
//订阅数据
subscribe: {
topic: "",
clientid: "",
},
//添加订阅表单参数
subscribeForm: {
qos: "0",
},
//客户端ID
clientid: "",
// 表单校验
rules: {
topic: [{
required: true,
message: "主题不能为空",
trigger: "blur",
}, ],
},
};
},
created() {
this.getList();
},
methods: {
/** 查询客户端列表 */
getList() {
this.loading = true;
listMqttClient(this.queryParams).then((response) => {
this.clientList = response.data.data;
this.total = response.data.meta.count;
this.loading = false;
});
},
/** 查询客户端订阅列表 */
getSubscribeList(clientid) {
this.clientid = clientid;
this.loadSubscribeing = true;
getSubscriptionsByClientId(clientid).then((res) => {
this.subscribeList = res.data.data;
this.loadSubscribeing = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 断开客户端连接 */
handleDelete(row) {
const clientid = row.clientid;
this.$modal
.confirm('是否确认删除MQTT客户端编号为"' + clientid + '"的数据项?')
.then(function () {
return eliminateClient(clientid);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
//取消主题订阅
handleUnsubscribe(row) {
const clientid = row.clientid;
const topic = row.topic;
this.$modal
.confirm('是否确认取消订阅主题为"' + topic + '"的数据项?')
.then(function () {
const param = {};
param.topic = topic;
param.clientid = clientid;
return unsubscribe(param);
})
.then(() => {
this.getSubscribeList(clientid);
this.$modal.msgSuccess("取消订阅成功");
})
.catch(() => {});
},
//查看客户端详情
handleOpen(row) {
const clientid = row.clientid;
this.getSubscribeList(clientid);
getClientDetails(clientid).then((response) => {
this.form = response.data.data[0];
this.open = true;
this.title = "详情";
});
},
//刷新订阅列表
handleRefresh() {
this.getSubscribeList(this.clientid);
},
//添加订阅
handleAdd() {
this.subscribeOpen = true;
},
//提交添加订阅表单
submitForm() {
this.subscribeForm.clientid = this.clientid;
console.log(this.subscribeForm);
this.$refs["subscribeForm"].validate((valid) => {
if (valid) {
addSubscribe(this.subscribeForm).then((response) => {
this.$modal.msgSuccess("新增订阅成功");
this.subscribeOpen = false;
this.getSubscribeList(this.clientid);
});
}
});
},
cancelSubscribe() {
this.subscribeOpen = false;
this.resetForm("subscribeForm");
//刷新列表
this.getSubscribeList(this.clientid);
},
},
};
</script>

View File

@@ -1,80 +0,0 @@
<template>
<div style="padding:6px;">
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="listenerList">
<el-table-column label="协议" align="center" prop="protocol" />
<el-table-column label="监听地址" align="center" prop="listen_on" />
<el-table-column label="最大连接数" align="center" prop="max_conns" />
<el-table-column label="当前连接数" align="center" prop="current_conns"/>
<el-table-column label="连接成功数" align="center" prop="acceptors" />
<el-table-column label="账号错误数" align="center" prop="shutdown_count.bad_username_or_password" />
<el-table-column label="功能错误数" align="center" prop="shutdown_count.function_clause" />
<el-table-column label="SSL关闭数" align="center" prop="shutdown_count.ssl_closed" />
</el-table>
<!-- 添加或修改产品分类对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" placeholder="请输入产品分类名称" />
</el-form-item>
<el-form-item label="显示顺序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入显示顺序" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import{listMqttListener} from "@/api/iot/emqx"
export default {
name: "Category",
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 列表
listenerList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 表单参数
form: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询客户端列表 */
getList() {
this.loading = true;
listMqttListener().then(response => {
this.listenerList=response.data.data[0].listeners;
console.log(response);
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
}
};
</script>

View File

@@ -1,137 +0,0 @@
<template>
<div style="padding:6px;">
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="pluginList">
<el-table-column label="插件名称" align="center" prop="name" width="300" />
<el-table-column label="版本" align="center" prop="version" width="100" />
<el-table-column label="类型" align="center" prop="type" width="120" />
<el-table-column label="状态" align="center" prop="active" width="150">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.active">运行中</el-tag>
<el-tag type="info" v-else>已停止</el-tag>
</template>
</el-table-column>
<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="['iot:emqx:edit']">
<svg-icon icon-class="start" /> 启动
</el-button>
<el-button size="small" type="danger" style="padding:5px;"
@click="unloadMqttPlugin(scope.row.name)"
v-hasPermi="['iot:emqx:edit']"
v-if="scope.row.active"
:disabled="scope.row.name=='emqx_auth_http' || scope.row.name=='emqx_web_hook' || scope.row.name=='emqx_rule_engine' || scope.row.name=='emqx_management'">
<svg-icon icon-class="stop" /> 停止
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改产品分类对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" placeholder="请输入产品分类名称" />
</el-form-item>
<el-form-item label="显示顺序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入显示顺序" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import {
listMqttPlugin,
loadMqttPlugin,
unloadMqttPlugin
} from "@/api/iot/emqx"
export default {
name: "Category",
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 列表
pluginList: [],
// 节点名称
node: "",
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 表单参数
form: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询客户端列表 */
getList() {
this.loading = true;
listMqttPlugin().then(response => {
this.pluginList = response.data.data[0].plugins;
this.node = response.data.data[0].node;
this.loading = false;
});
},
/** 启用插件*/
loadMqttPlugin(plugin) {
this.$confirm('是否启用插件:' + plugin + ' ?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
loadMqttPlugin(this.node, plugin).then(response => {
if (response.data.code == 0) {
this.getList();
this.$message({
type: 'success',
message: '成功启用插件!'
});
}
})
}).catch(() => {});
},
/** 卸载插件*/
unloadMqttPlugin(plugin) {
this.$confirm('是否停止插件:' + plugin + ' ?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
unloadMqttPlugin(this.node, plugin).then(response => {
if (response.data.code == 0) {
this.getList();
this.$message({
type: 'success',
message: '成功停止插件!'
});
}
})
}).catch(() => {});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
}
};
</script>

View File

@@ -1,860 +0,0 @@
<template>
<div style="padding: 6px">
<el-card style="padding-bottom: 100px">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-refresh" size="mini" @click="getList" v-hasPermi="['iot:emqx:query']">刷新</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addResource" v-hasPermi="['iot:emqx:add']">新增</el-button>
</el-col>
</el-row>
<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" @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" width="200">
<template slot-scope="scope">
<el-button size="small" type="text" icon="el-icon-connection" style="padding: 5px" v-hasPermi="['iot:emqx:edit']" @click="checkStatus(scope.row)">状态
</el-button>
<el-button size="small" type="text" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['iot:emqx:remove']" @click="handleDelete(scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 资源详细 -->
<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">
<span>基础信息</span>
</div>
<el-row>
<el-col :span="20">
<el-form-item label="ID">{{ form.id }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="资源类型:">{{ form.type }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="备注:">{{ form.description }}</el-form-item>
</el-col>
</el-row>
</el-card>
<el-card style="padding-bottom: 10px; margin-top: 10px">
<div slot="header" class="clearfix">
<span>配置信息</span>
</div>
<el-row>
<el-col :span="20">
<el-form-item label="reconnect_interval">{{ form.config.reconnect_interval}}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="pool_size">{{ form.config.pool_size }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="mountpoint">{{ form.config.mountpoint}}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="disk_cache">{{ form.config.disk_cache }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="batch_size">{{ form.config.batch_size }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item label="address">{{ form.config.address}}</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="openView = false" type="success"> </el-button>
</div>
</el-dialog>
<!-- 测试重连 -->
<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="['iot:emqx:edit']" @click="checkNode(statusForm.id)">重新连接
</el-button>
</el-form>
</el-dialog>
<!-- 添加资源 -->
<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">
<span>择取资源类型</span>
</div>
<el-row>
<el-col :span="12">
<el-form-item label="资源类型" prop="resource.title">
<el-select v-model="addResourceForm.resource.title" @change="selectTitle" placeholder="请选择资源类型">
<el-option v-for="(resource, index) in addResourceForm.resource" :key="index" :label="resource.title.zh" :value="resource.name"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-button type="success" @click="testConnect('addResourceForm')">测试连接</el-button>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<el-form ref="EMQXForm" :model="EMQXForm" label-width="180px" :rules="ruleEMQX">
<el-card style="padding-bottom: 10px; margin-top: 10px" v-if="EMQXForm.params" v-show="openEMQXView">
<div slot="header" class="clearfix">
<span>具体信息</span>
</div>
<el-row>
<el-col :span="10">
<el-form-item prop="params.address.default">
<span slot="label">
<el-tooltip :content="EMQXForm.params.address.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
EMQ X节点名称
</span>
<el-input v-model="EMQXForm.params.address.default" />
</el-form-item>
<el-form-item prop="params.pool_size.default">
<span slot="label">
<el-tooltip :content="EMQXForm.params.pool_size.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
连接池大小
</span>
<el-input v-model="EMQXForm.params.pool_size.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="params.mountpoint.default">
<span slot="label">
<el-tooltip :content="EMQXForm.params.mountpoint.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
桥接挂载点
</span>
<el-input v-model="EMQXForm.params.mountpoint.default" />
</el-form-item>
<el-form-item prop="EMQreconnect_interval">
<span slot="label">
<el-tooltip :content="EMQXForm.params.reconnect_interval.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
重连间隔
</span>
<el-input v-model="EMQXForm.params.reconnect_interval.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="EMQbatch_size">
<span slot="label">
<el-tooltip :content="EMQXForm.params.batch_size.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
批处理大小
</span>
<el-input v-model="EMQXForm.params.batch_size.default" />
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="EMQXForm.description" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="EMQdisk_cache">
<span slot="label">
<el-tooltip :content="EMQXForm.params.disk_cache.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
磁盘缓存
</span>
<el-select v-model="EMQXForm.params.disk_cache.default">
<el-option v-for="(enums, index) in EMQXForm.params.disk_cache.enum" :key="index" :label="enums" :value="enums"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<el-form ref="MQTTForm" :model="MQTTForm" label-width="180px" :rules="ruleMQTT">
<el-card style="padding-bottom: 10px; margin-top: 10px" v-if="MQTTForm.params" v-show="openMQTTView">
<div slot="header" class="clearfix">
<span>具体信息</span>
</div>
<el-row>
<el-col :span="10">
<el-form-item prop="params.address.default">
<span slot="label">
<el-tooltip :content="MQTTForm.params.address.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
远程broker地址
</span>
<el-input v-model="MQTTForm.params.address.default" />
</el-form-item>
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.disk_cache.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
磁盘缓存
</span>
<el-select v-model="MQTTForm.params.disk_cache.default">
<el-option v-for="(enums, index) in MQTTForm.params.disk_cache.enum" :key="index" :label="enums" :value="enums"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.proto_ver.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
协议版本
</span>
<el-select v-model="MQTTForm.params.proto_ver.default">
<el-option v-for="(enums, index) in MQTTForm.params.proto_ver.enum" :key="index" :label="enums" :value="enums"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.clientid.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
客户端ID
</span>
<el-input v-model="MQTTForm.params.clientid.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.username.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
用户名
</span>
<el-input v-model="MQTTForm.params.username.default" />
</el-form-item>
<el-form-item prop="params.mountpoint.default">
<span slot="label">
<el-tooltip :content="MQTTForm.params.mountpoint.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
桥接挂载点
</span>
<el-input v-model="MQTTForm.params.mountpoint.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.password.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
密码
</span>
<el-input v-model="MQTTForm.params.password.default" />
</el-form-item>
<el-form-item prop="params.keepalive.default">
<span slot="label">
<el-tooltip :content="MQTTForm.params.keepalive.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
心跳间隔
</span>
<el-input v-model="MQTTForm.params.keepalive.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.reconnect_interval.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
重连间隔
</span>
<el-input v-model="MQTTForm.params.reconnect_interval.default" />
</el-form-item>
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.bridge_mode.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
桥接模式
</span>
<el-select v-model="MQTTForm.params.bridge_mode.default">
<el-option key="false" label="false" value="false"></el-option>
<el-option key="true" label="true" value="true"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.retry_interval.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
重传间隔
</span>
<el-input v-model="MQTTForm.params.retry_interval.default" />
</el-form-item>
<el-form-item prop="params.ssl.default">
<span slot="label">
<el-tooltip :content="MQTTForm.params.ssl.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
Bridge SSL
</span>
<el-select v-model="MQTTForm.params.ssl.default">
<el-option v-for="(enums, index) in MQTTForm.params.ssl.enum" :key="index" :label="enums" :value="enums"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.cacertfile.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
CA证书
</span>
<el-input v-model="MQTTForm.params.cacertfile.default" />
</el-form-item>
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.keyfile.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
SSL 密钥文件
</span>
<el-input v-model="MQTTForm.params.keyfile.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.certfile.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
SSL 客户端证书
</span>
<el-input v-model="MQTTForm.params.certfile.default" />
</el-form-item>
<el-form-item>
<span slot="label">
<el-tooltip :content="MQTTForm.params.ciphers.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
SSL 加密算法
</span>
<el-input v-model="MQTTForm.params.ciphers.default" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="备注:">
<el-input v-model="MQTTForm.description" />
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<el-form ref="WebHookForm" :model="WebHookForm" label-width="180px" :rules="ruleWebHook">
<el-card style="padding-bottom: 10px; margin-top: 10px" v-if="WebHookForm.params" v-show="openWebView">
<div slot="header" class="clearfix">
<span>具体信息</span>
</div>
<el-row>
<el-col :span="12">
<el-form-item prop="params.url.default">
<span slot="label">
<el-tooltip :content="WebHookForm.params.url.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
请求 URL
</span>
<el-input v-model="WebHookForm.params.url.default" placeholder="http://" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求方法:">
<span slot="label">
<el-tooltip :content="WebHookForm.params.method.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
请求方法
</span>
<el-select v-model="WebHookForm.params.method.default">
<el-option v-for="(enums, index) in WebHookForm.params.method.enum" :key="index" :label="enums" :value="enums"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="20">
<el-form-item label="请求头:" prop="ket_value">
<el-row v-for="(item, index) in ket_value" :key="index" style="margin-bottom: 10px">
<el-col :span="8">
<el-input v-model="item.key" placeholder="键" />
</el-col>
<el-col :span="12" :offset="1">
<el-input v-model="item.value" placeholder="值" />
</el-col>
<el-col :span="2" :offset="1" v-if="index != 0"><a style="color: #f56c6c" @click="removeHeaderItem(index)">删除</a></el-col>
</el-row>
<div>
+
<a style="color: #409eff" @click="addHeader()">添加请求头</a>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注:">
<el-input v-model="WebHookForm.description" />
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel"> </el-button>
<el-button type="success" @click="saveResource('EMQXForm')" v-if="openEMQXView" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveResource('MQTTForm')" v-if="openMQTTView" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveResource('WebHookForm')" v-if="openWebView" :loading="showloading">新建</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getResources,
getResourcesStatus,
getConnectResource,
deleteResource,
getResourcesType,
getResourcesConnect,
saveResources,
} from "@/api/iot/emqx";
export default {
name: "Resource",
data() {
return {
// 遮罩层
loading: true,
// 新建按钮等待效果
showloading: false,
// 总条数
total: 0,
// 规则表格数据
resourceList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否显示详细弹出层
openView: false,
// 是否显示检测状态弹出层
openStatusView: false,
// 是否显示添加资源弹出层
openAddView: false,
// 是否显示EMQX Bridge弹出层
openEMQXView: false,
// 是否显示MQTT Bridge弹出层
openMQTTView: false,
// 是否显示WebHook弹出层
openWebView: false,
//表单数据
form: {
config: {},
},
statusForm: {
status: [],
},
//添加资源表单数据
addResourceForm: {
resource: [],
type: "",
},
//添加EMQX资源表单数据
EMQXForm: {
description: "",
},
//添加MQTT资源表单数据
MQTTForm: {
description: "",
},
//添加WebHook资源表单数据
WebHookForm: {
description: "",
},
ket_value: [],
//添加资源表单数据
emqxParam: {
description: "",
name: "",
type: "",
config: {},
},
ruleEMQX: {
params: {
address: {
default: [{
required: true,
message: "请输入EMQ X节点名称",
trigger: "blur",
}, ],
},
pool_size: {
default: [{
required: true,
message: "请输入连接池大小",
trigger: "blur",
}, ],
},
mountpoint: {
default: [{
required: true,
message: "请输入桥接挂载点",
trigger: "blur",
}, ],
},
},
},
ruleMQTT: {
params: {
address: {
default: [{
required: true,
message: "请输入远程 broker 地址",
trigger: "blur",
}, ],
},
mountpoint: {
default: [{
required: true,
message: "请输入桥接挂载点",
trigger: "blur",
}, ],
},
ssl: {
default: [{
required: true,
message: "请选择Bridge SSL",
trigger: "change",
}, ],
},
keepalive: {
default: [{
required: true,
message: "请输入心跳间隔",
trigger: "blur",
}, ],
},
},
},
ruleWebHook: {
params: {
url: {
default: [{
required: true,
message: "请输入请求 URL",
trigger: "blur",
}, ],
},
},
},
rule: {
resource: {
title: [{
required: true,
message: "请选择资源类型",
trigger: "change"
}, ],
},
},
};
},
created() {
this.getList();
},
methods: {
/** 查询规则列表 */
getList() {
this.loading = true;
getResources("").then((response) => {
this.resourceList = response.data.data;
this.loading = false;
});
},
/** 查看按钮操作 */
handleQuery(row) {
this.form = row;
this.openView = true;
},
/** 状态按钮操作 */
checkStatus(row) {
let resourceId = row.id;
getResourcesStatus(resourceId).then((response) => {
this.statusForm = response.data.data;
this.openStatusView = true;
});
},
//删除按钮操作
handleDelete(row) {
let resourceId = row.id;
this.$modal
.confirm('是否确认删除ID为"' + resourceId + '"的规则引擎?')
.then(function () {
return deleteResource(resourceId);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除资源成功");
})
.catch(() => {});
},
/** 重新连接资源按钮操作 */
checkNode(resourceId) {
getConnectResource(resourceId).then((response) => {
let code = response.data.code;
if (code !== 0) {
this.$modal.msgError(response.data.message);
} else {
this.$modal.msgSuccess("连接资源成功");
}
});
},
/** 跳转添加资源页面 */
addResource() {
getResourcesType().then((res) => {
this.addResourceForm.resource = res.data.data;
this.EMQXForm.params = res.data.data[0].params;
this.MQTTForm.params = res.data.data[1].params;
this.WebHookForm.params = res.data.data[2].params;
this.openAddView = true;
});
},
/** 选择资源类型 */
selectTitle(val) {
this.addResourceForm.type = val;
if ("bridge_rpc" === val) {
this.openEMQXView = true;
this.openMQTTView = false;
this.openWebView = false;
} else if ("bridge_mqtt" === val) {
this.openEMQXView = false;
this.openMQTTView = true;
this.openWebView = false;
} else if ("web_hook" === val) {
this.openEMQXView = false;
this.openMQTTView = false;
this.openWebView = true;
}
},
// 取消按钮
cancel() {
//初始化
this.openEMQXView = false;
this.openMQTTView = false;
this.openWebView = false;
this.openAddView = false;
this.EMQXForm = {};
this.MQTTForm = {};
this.WebHookForm = {};
this.addResourceForm.resource = [];
this.addResourceForm.description = "";
this.$refs['addResourceForm'].resetFields();
},
//测试连接
testConnect(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.insertOrTestResourceUtils('test');
} else {
return false;
}
});
},
/** 添加请求头 */
addHeader() {
this.ket_value.push({
key: "",
value: "",
});
},
/** 删除请求头 */
removeHeaderItem(index) {
this.ket_value.splice(index, 1);
},
//新建资源
saveResource(formName) {
this.showloading = true;
//校验表单
this.$refs[formName].validate((valid) => {
if (valid) {
this.insertOrTestResourceUtils('save');
} else {
return false;
}
});
},
// 新增资源或者测试连接公共方法
insertOrTestResourceUtils(type) {
this.emqxParam.type = this.addResourceForm.type;
//判断选择的资源类型
if ("bridge_rpc" === this.addResourceForm.type) {
this.emqxParam.description = this.EMQXForm.description;
this.emqxParam.config.address = this.EMQXForm.params.address.default;
this.emqxParam.config.batch_size =
this.EMQXForm.params.batch_size.default;
this.emqxParam.config.disk_cache =
this.EMQXForm.params.disk_cache.default;
this.emqxParam.config.mountpoint =
this.EMQXForm.params.mountpoint.default;
this.emqxParam.config.pool_size =
this.EMQXForm.params.pool_size.default;
this.emqxParam.config.reconnect_interval =
this.EMQXForm.params.reconnect_interval.default;
if ("test" == type) {
getResourcesConnect(this.emqxParam).then((res) => {
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("连接成功");
} else {
this.$modal.msgError(res.data.message);
}
});
} else {
saveResources(this.emqxParam).then((res) => {
this.showloading = false;
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("添加资源成功");
this.getList();
this.cancel();
} else {
this.$modal.msgError(res.data.message);
}
});
}
} else if ("bridge_mqtt" === this.addResourceForm.type) {
this.emqxParam.description = this.MQTTForm.description;
this.emqxParam.config.address = this.MQTTForm.params.address.default;
this.emqxParam.config.bridge_mode =
this.MQTTForm.params.bridge_mode.default;
this.emqxParam.config.cacertfile =
this.MQTTForm.params.cacertfile.default;
this.emqxParam.config.certfile = this.MQTTForm.params.certfile.default;
this.emqxParam.config.ciphers = this.MQTTForm.params.ciphers.default;
this.emqxParam.config.clientid = this.MQTTForm.params.clientid.default;
this.emqxParam.config.disk_cache =
this.MQTTForm.params.disk_cache.default;
this.emqxParam.config.keepalive =
this.MQTTForm.params.keepalive.default;
this.emqxParam.config.keyfile = this.MQTTForm.params.keyfile.default;
this.emqxParam.config.mountpoint =
this.MQTTForm.params.mountpoint.default;
this.emqxParam.config.password = this.MQTTForm.params.password.default;
this.emqxParam.config.proto_ver =
this.MQTTForm.params.proto_ver.default;
this.emqxParam.config.reconnect_interval =
this.MQTTForm.params.reconnect_interval.default;
this.emqxParam.config.retry_interval =
this.MQTTForm.params.retry_interval.default;
this.emqxParam.config.ssl = this.MQTTForm.params.ssl.default;
this.emqxParam.config.username = this.MQTTForm.params.username.default;
if ("test" == type) {
getResourcesConnect(this.emqxParam).then((res) => {
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("连接成功");
} else {
this.$modal.msgError(res.data.message);
}
});
} else {
saveResources(this.emqxParam).then((res) => {
this.showloading = false;
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("添加资源成功");
this.getList();
this.cancel();
} else {
this.$modal.msgError(res.data.message);
}
});
}
} else if ("web_hook" === this.addResourceForm.type) {
this.emqxParam.description = this.WebHookForm.description;
this.emqxParam.config.url = this.WebHookForm.params.url.default;
this.emqxParam.config.method = this.WebHookForm.params.method.default;
//解析数据转换成后端需要的数据格式
let headers = {};
this.ket_value.forEach((item) => {
headers[item.key] = item.value;
});
this.emqxParam.config.headers = headers;
if ("test" == type) {
getResourcesConnect(this.emqxParam).then((res) => {
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("连接成功");
} else {
this.$modal.msgError(res.data.message);
}
});
} else {
saveResources(this.emqxParam).then((res) => {
this.showloading = false;
let code = res.data.code;
if (0 == code) {
this.$modal.msgSuccess("添加资源成功");
this.getList();
this.cancel();
} else {
this.$modal.msgError(res.data.message);
}
});
}
}
},
},
};
</script>

View File

@@ -1,770 +0,0 @@
<template>
<div style="padding: 6px">
<el-card style="padding-bottom: 100px">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-refresh" size="mini" @click="getList" v-hasPermi="['iot:emqx:query']">刷新</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="getAddRules" v-hasPermi="['iot:emqx:add']">新增</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="rulesList">
<el-table-column label="ID" align="center" header-align="center" prop="id" width="150">
<template slot-scope="scope">
<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">
<template slot-scope="scope">
<p v-for="(topic, index) in scope.row.for" :key="index">
<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" 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" 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="100">
<template slot-scope="scope">
<el-button size="small" type="danger" icon="el-icon-delete" style="padding: 5px" v-hasPermi="['iot:emqx:remove']" @click="handleDelete(scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 规则引擎详细 -->
<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">
<span>基本信息</span>
</div>
<el-row>
<el-col :span="20">
<el-form-item label="主题:">
<el-tag type="success" v-for="(topic, index) in form.for" :key="index">{{ topic }}</el-tag>
</el-form-item>
</el-col>
<el-col :span="20">
<el-form-item label="备注:">{{ form.description }}</el-form-item>
</el-col>
<el-col :span="20">
<el-form-item label="规则SQL:">{{ form.rawsql }}</el-form-item>
</el-col>
</el-row>
</el-card>
<el-card style="padding-bottom: 10px; margin-top: 10px">
<div slot="header" class="clearfix">
<span>度量指标</span>
</div>
<el-table :data="form.metrics">
<el-table-column label="节点" align="center" prop="node" />
<el-table-column label="已命中" align="center" prop="matched" />
<el-table-column label="命中速度" align="center" prop="speed" />
<el-table-column label="最大命中速度" align="center" prop="speed_max" />
<el-table-column label="5分钟平均速度" align="center" prop="speed_last5m" />
</el-table>
</el-card>
<el-card style="padding-bottom: 10px; margin-top: 10px">
<div slot="header" class="clearfix">
<span>响应动作</span>
</div>
<el-table :data="form.actions">
<el-table-column label="类型" align="center" prop="name" />
<el-table-column label="参数" align="center" prop="params">
<template slot-scope="scope">
{{scope.row.params}}
</template>
</el-table-column>
<el-table-column label="度量指标" align="center">
<template slot-scope="scope">
<el-tag type="success">{{ scope.row.metrics[0].node }}</el-tag><br />
合计 成功<el-tag type="success">{{ scope.row.metrics[0].success }}</el-tag>
失败<el-tag type="danger">{{ scope.row.metrics[0].failed }}</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="openView = false"> </el-button>
</div>
</el-dialog>
<!-- 添加规则引擎 -->
<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="400" style="border:1px solid #ddd;" />
</el-form-item>
<el-form-item prop="sql_example">
<span slot="label"> 备注 </span>
<el-input v-model="form.note" placeholder="e.g.消息转发到WebHook" />
</el-form-item>
<el-form-item prop="SQLtest">
<span slot="label">
SQL测试
</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>
</el-col>
<el-col :span="11">
<div class="sql-tips">
<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-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">
<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>
<el-table-column property="param" label="参数">
<template slot-scope="scope">
{{ scope.row.param }}
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="danger" @click="deleteAction(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 20px">
<el-button @click="addActionPage()">添加</el-button>
</div>
</el-card>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel"> </el-button>
<el-button type="success" @click="saveRule" :loading="addRuleLoading">新建</el-button>
</div>
</el-dialog>
<!-- 添加响应动作 -->
<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>
<el-form-item prop="actions.title">
<span slot="label">
动作
<el-tooltip :content="prompt" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-select v-model="actionForm.actions.title" @change="selectTitle" placeholder="请选择">
<el-option v-for="(action, index) in actionForm.actions" :key="index" :label="action.title.zh" :value="action.name"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-form ref="republishForm" :model="republishForm" label-width="180px" v-if="republishForm.params" v-show="republishView" :rules="ruleRepublish">
<el-row>
<el-col :span="20">
<el-form-item prop="params.target_topic.default">
<span slot="label">
目的主题
<el-tooltip :content="republishForm.params.target_topic.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="republishForm.params.target_topic.default" />
</el-form-item>
<el-form-item prop="params.target_qos.default">
<span slot="label">
目的 QoS
<el-tooltip :content="republishForm.params.target_qos.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="republishForm.params.target_qos.default" />
</el-form-item>
<el-form-item prop="params.payload_tmpl.default">
<span slot="label">
消息内容模板
<el-tooltip :content="republishForm.params.payload_tmpl.description.zh" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<textarea style="width: 300px; height: 120px" v-model="republishForm.params.payload_tmpl.default"></textarea>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-form ref="data_to_mqtt_broker_Form" :model="data_to_mqtt_broker_Form" label-width="180px" v-if="data_to_mqtt_broker_Form.params" v-show="data_to_mqtt_broker_View" :rules="rule_data_to_mqtt_broker">
<el-row>
<el-col :span="20">
<el-form-item prop="resourceId">
<span slot="label"> 关联资源 </span>
<el-select v-model="data_to_mqtt_broker_Form.resourceId" placeholder="请选择">
<el-option v-for="(
resource, index
) in data_to_mqtt_broker_Form.resources" :key="index" :label="resource.id" :value="resource.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="params.payload_tmpl.default" v-if="data_to_mqtt_broker_Form.params.payload_tmpl">
<span slot="label">
消息内容模板:
<el-tooltip :content="
data_to_mqtt_broker_Form.params.payload_tmpl.description.zh
" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<textarea style="width: 300px; height: 120px" v-model="data_to_mqtt_broker_Form.params.payload_tmpl.default"></textarea>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-form ref="data_to_webserver_Form" :model="data_to_webserver_Form" label-width="180px" v-if="data_to_webserver_Form.params" v-show="data_to_webserver_View" :rules="rule_data_to_webserver">
<el-row>
<el-col :span="20">
<el-form-item prop="resourceId">
<span slot="label"> 关联资源: </span>
<el-select v-model="data_to_webserver_Form.resourceId" placeholder="请选择">
<el-option v-for="(resource, index) in data_to_webserver_Form.resources" :key="index" :label="resource.id" :value="resource.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="params.payload_tmpl.default" v-if="data_to_webserver_Form.params.payload_tmpl">
<span slot="label">
消息内容模板:
<el-tooltip :content="
data_to_webserver_Form.params.payload_tmpl.description.zh
" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<textarea style="width: 300px; height: 120px" v-model="data_to_webserver_Form.params.payload_tmpl.default"></textarea>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancelAction">取 消</el-button>
<el-button type="success" @click="saveAction('republishForm')" v-if="republishView" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveAction('data_to_mqtt_broker_Form')" v-if="data_to_mqtt_broker_View" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveAction('data_to_webserver_Form')" v-if="data_to_webserver_View" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveAction('do_nothing_Form')" v-if="do_nothing_View" :loading="showloading">新建</el-button>
<el-button type="success" @click="saveAction('inspectForm')" v-if="inspectView" :loading="showloading">新建</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getRules,
deleteRule,
getRulesEvent,
getActionsEvent,
getResources,
saveRule,
testConnectRule,
} from "@/api/iot/emqx";
import CodeMirrorEditor from "@/components/Codemirror/index";
export default {
name: "Rules",
components: {
CodeMirrorEditor,
},
data() {
return {
// 遮罩层
loading: true,
//遮罩层
showloading: false,
// 遮罩层
addRuleLoading: false,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 规则表格数据
rulesList: [],
// 弹出层标题
title: "",
// 是否显示详细弹出层
openView: false,
// 是否显示添加规则弹出层
openAddView: false,
// 是否显示添加响应动作弹出层
openAddActionView: false,
//是否显示消息重新发布表单参数
republishView: false,
//是否显示桥接数据到 MQTT Broker表单参数
data_to_mqtt_broker_View: false,
//是否显示发送数据到 Web 服务表单参数
data_to_webserver_View: false,
//是否显示空动作 (调试)表单按钮
do_nothing_View: false,
//是否显示检查 (调试)表单按钮
inspectView: false,
// 添加规则表单参数
form: {
note: "",
SQLtest: false,
},
//测试结果
content: "",
// 响应动作列表
actions: [],
//响应动作列表表单参数
actionForm: {
actions: [],
},
//动作的提示语
prompt: "动作类型",
// 响应动作规则
ruleActions: {
actions: {
title: [{
required: true,
message: "请选择动作类型",
trigger: "change"
}, ],
},
},
ruleRepublish: {
params: {
target_topic: {
default: [{
required: true,
message: "请输入目的主题",
trigger: "blur"
}, ],
},
target_qos: {
default: [{
required: true,
message: "请输入目的 QoS",
trigger: "blur"
}, ],
},
payload_tmpl: {
default: [{
required: true,
message: "请输入消息内容模板",
trigger: "blur",
}, ],
},
},
},
rule_data_to_mqtt_broker: {
resourceId: [{
required: true,
message: "请关联资源类型",
trigger: "blur"
}, ],
},
rule_data_to_webserver: {
resourceId: [{
required: true,
message: "请关联资源类型",
trigger: "change"
}, ],
},
//空动作 (调试)表单参数
do_nothing_Form: {},
//检查 (调试)表单参数
inspectForm: {},
//消息重新发布表单参数
republishForm: {},
//桥接数据到 MQTT Broker表单参数
data_to_mqtt_broker_Form: {
resources: [],
resourceId: "",
},
//发送数据到 Web 服务表单参数
data_to_webserver_Form: {
resources: [],
resourceId: "",
},
};
},
created() {
this.getList();
},
methods: {
/** 查询规则列表 */
getList() {
this.loading = true;
getRules("").then((response) => {
this.rulesList = response.data.data;
// this.total = response.data.meta.count;
this.loading = false;
});
},
// 取消按钮
cancel() {
//初始化
this.openAddView = false;
this.actions = [];
this.$refs["form"].resetFields();
},
//关闭动作页面
cancelAction() {
//初始化所有数据
this.do_nothing_View = false;
this.republishView = false;
this.data_to_mqtt_broker_View = false;
this.data_to_webserver_View = false;
this.inspectView = false;
this.openAddActionView = false;
this.do_nothing_Form = {};
this.inspectForm = {};
this.republishForm = {};
this.data_to_mqtt_broker_Form.resources = [];
this.data_to_mqtt_broker_Form.resourceId = "";
this.data_to_mqtt_broker_Form = {};
this.data_to_webserver_Form.resources = [];
this.data_to_webserver_Form.resourceId = "";
this.data_to_webserver_Form = {};
this.actionForm.actions = [];
this.$refs["actionForm"].resetFields();
},
/** 查看按钮操作 */
handleQuery(row) {
let ruleId = row.id;
getRules(ruleId).then((response) => {
this.form = response.data.data;
this.openView = true;
});
},
//删除规则
handleDelete(row) {
debugger;
let ruleId = row.id;
this.$modal
.confirm('是否确认删除ID为"' + ruleId + '"的规则引擎?')
.then(function () {
return deleteRule(ruleId);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除规则引擎成功");
})
.catch(() => {});
},
//跳转到添加规则引擎页面
getAddRules() {
getRulesEvent().then((res) => {
this.form = res.data.data[0];
this.openAddView = true;
});
},
//添加响应动作
addActionPage() {
getActionsEvent().then((res) => {
//赋值
this.actionForm.actions = res.data.data;
this.do_nothing_Form = res.data.data[0];
//检查 (调试)表单参数
this.inspectForm = res.data.data[2];
//消息重新发布表单参数
this.republishForm = res.data.data[1];
//桥接数据到 MQTT Broker表单参数
this.data_to_mqtt_broker_Form = res.data.data[3];
//发送数据到 Web 服务表单参数
this.data_to_webserver_Form = res.data.data[4];
this.openAddActionView = true;
});
},
/** 选择响应动作类型 */
selectTitle(val) {
if ("do_nothing" === val) {
this.data_to_webserver_View = false;
this.data_to_mqtt_broker_View = false;
this.republishView = false;
this.inspectView = false;
this.do_nothing_View = true;
this.prompt = this.actionForm.actions[0].description.zh;
} else if ("republish" === val) {
this.data_to_webserver_View = false;
this.data_to_mqtt_broker_View = false;
this.do_nothing_View = false;
this.inspectView = false;
this.republishView = true;
this.prompt = this.actionForm.actions[1].description.zh;
} else if ("inspect" === val) {
this.data_to_webserver_View = false;
this.data_to_mqtt_broker_View = false;
this.do_nothing_View = false;
this.republishView = false;
this.inspectView = true;
this.prompt = this.actionForm.actions[2].description.zh;
} else if ("data_to_mqtt_broker" === val) {
getResources("").then((res) => {
this.data_to_mqtt_broker_Form.resources = res.data.data;
this.prompt = this.actionForm.actions[3].description.zh;
this.data_to_webserver_View = false;
this.do_nothing_View = false;
this.republishView = false;
this.inspectView = false;
this.data_to_mqtt_broker_View = true;
});
} else if ("data_to_webserver" === val) {
getResources("").then((res) => {
this.data_to_webserver_Form.resources = res.data.data;
this.prompt = this.actionForm.actions[4].description.zh;
this.data_to_mqtt_broker_View = false;
this.do_nothing_View = false;
this.republishView = false;
this.inspectView = false;
this.data_to_webserver_View = true;
});
}
},
//添加响应动作
saveAction(formName) {
const action = {};
const param = {};
if ("do_nothing_Form" === formName) {
action.name = this.do_nothing_Form.name;
action.params = {};
this.actions.push(action);
this.cancelAction();
} else if ("republishForm" === formName) {
//校验表单
this.$refs[formName].validate((valid) => {
if (valid) {
param.payload_tmpl = this.republishForm.params.payload_tmpl.default;
param.target_topic = this.republishForm.params.target_topic.default;
param.target_qos = this.republishForm.params.target_qos.default;
action.name = this.republishForm.name;
action.params = param;
this.actions.push(action);
this.cancelAction();
} else {
return false;
}
});
} else if ("inspectForm" === formName) {
action.name = this.inspectForm.name;
action.params = {};
this.actions.push(action);
this.cancelAction();
} else if ("data_to_mqtt_broker_Form" === formName) {
//校验表单
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) {
param.payload_tmpl =
this.data_to_mqtt_broker_Form.params.payload_tmpl.default;
}
action.params = param;
action.name = this.data_to_mqtt_broker_Form.name;
this.actions.push(action);
this.cancelAction();
} else {
return false;
}
});
} else if ("data_to_webserver_Form" === formName) {
//校验表单
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) {
param.payload_tmpl =
this.data_to_webserver_Form.params.payload_tmpl.default;
}
action.params = param;
action.name = this.data_to_webserver_Form.name;
this.actions.push(action);
this.cancelAction();
} else {
return false;
}
});
}
},
//删除动作参数
deleteAction(index) {
this.actions.splice(index, 1);
},
//添加规则引擎
saveRule() {
this.addRuleLoading = true;
this.insertOrTestRule("insert");
},
testConnect() {
this.insertOrTestRule("test");
},
//公共方法
insertOrTestRule(type) {
//将需要的参数进行赋值
const ruleParam = {
ctx: {}
};
ruleParam.description = this.form.note;
ruleParam.rawsql = this.form.sql_example;
ruleParam.actions = this.actions;
ruleParam.ctx.clientid = this.form.test_columns.clientid;
ruleParam.ctx.payload = this.form.test_columns.payload;
ruleParam.ctx.qos = this.form.test_columns.qos;
ruleParam.ctx.topic = this.form.test_columns.topic;
ruleParam.ctx.username = this.form.test_columns.username;
ruleParam.ctx.clientid = this.form.test_columns.clientid;
if ("test" === type) {
testConnectRule(ruleParam).then((res) => {
const code = res.data.code;
if (0 === code) {
this.content = JSON.stringify(res.data.data);
} else {
this.$modal.msgError(res.data.message);
}
});
} else {
saveRule(ruleParam).then((res) => {
const code = res.data.code;
if (0 === code) {
this.$modal.msgSuccess("添加规则引擎成功");
this.cancel();
this.getList();
} else {
this.$modal.msgError(res.data.message);
}
this.addRuleLoading = false;
});
}
},
},
};
</script>
<style scoped>
.sql-tips {
border: 4px dashed #d8d8d8;
color: #71737d;
font-size: 12px;
padding: 10px;
border-radius: 4px;
height: 510px;
overflow: hidden;
margin-right: -10px;
}
.code {
line-height: 1.4;
padding: 6px;
border-radius: 4px;
background-color: hsla(0, 0%, 87%, 0.8);
}
</style>

View File

@@ -1,123 +0,0 @@
<template>
<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>
<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-card>
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="subscribeList">
<el-table-column label="类型" align="center" prop="type" width="150">
<template slot-scope="scope">
<el-tag type="danger" v-if="scope.row.clientid.indexOf('server')==0">服务端</el-tag>
<el-tag type="success" v-else-if="scope.row.clientid.indexOf('web')==0">Web端</el-tag>
<el-tag type="warning" v-else-if="scope.row.clientid.indexOf('phone')==0">移动端</el-tag>
<el-tag type="info" v-else-if="scope.row.clientid.indexOf('test')==0">测试端</el-tag>
<el-tag type="primary" v-else>设备端</el-tag>
</template>
</el-table-column>
<el-table-column label="主题" align="left" header-align="center" prop="topic">
<template slot-scope="scope">
<span style="font-weight:bold">{{scope.row.topic}}</span>
</template>
</el-table-column>
<el-table-column label="客户端ID" align="center" header-align="center" prop="clientid">
<template slot-scope="scope">
<el-link :underline="false">{{scope.row.clientid}}</el-link>
</template>
</el-table-column>
<el-table-column label="Qos" align="center" prop="qos" width="100" />
<el-table-column label="节点" align="center" prop="node" />
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams._page" :limit.sync="queryParams._limit" @pagination="getList" />
<!-- 添加或修改产品分类对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" placeholder="请输入产品分类名称" />
</el-form-item>
<el-form-item label="显示顺序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入显示顺序" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import {
listMqttSubscribe
} from "@/api/iot/emqx"
export default {
name: "Category",
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 列表
subscribeList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
_limit: 10,
_page: 1,
},
// 表单参数
form: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询客户端列表 */
getList() {
this.loading = true;
listMqttSubscribe(this.queryParams).then(response => {
this.subscribeList = response.data.data;
this.total = response.data.meta.count;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
}
};
</script>

View File

@@ -1,103 +0,0 @@
<template>
<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="请输入主题" 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>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="topicList">
<el-table-column label="节点" align="center" prop="node" width="300"/>
<el-table-column label="主题" align="left" prop="topic" />
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams._page" :limit.sync="queryParams._limit" @pagination="getList" />
<!-- 添加或修改产品分类对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" placeholder="请输入产品分类名称" />
</el-form-item>
<el-form-item label="显示顺序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入显示顺序" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import{listMqttTopic} from "@/api/iot/emqx"
export default {
name: "Category",
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 列表
topicList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
_limit: 10,
_page: 1,
},
// 表单参数
form: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询客户端列表 */
getList() {
this.loading = true;
listMqttTopic(this.queryParams).then(response => {
this.topicList=response.data.data;
this.total=response.data.meta.count;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
}
};
</script>

View File

@@ -1,364 +0,0 @@
<template>
<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="firmwareName">
<el-input v-model="queryParams.firmwareName" placeholder="请输入固件名称" clearable size="small" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="queryParams.productName" placeholder="请输入产品名称" 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>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
<!-- <el-form-item style="float:right;">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['iot:firmware:add']">新增</el-button>
</el-form-item> -->
</el-form>
</el-card>
<el-card style="padding-bottom:100px;">
<el-table v-loading="loading" :data="firmwareList" @selection-change="handleSelectionChange">
<el-table-column label="固件名称" align="center" prop="firmwareName" />
<el-table-column label="固件版本" align="center" prop="version" width="120">
<template slot-scope="scope">
<span>Version </span> {{scope.row.version}}
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="isLatest" width="80">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.isLatest==1">最新</el-tag>
<el-tag type="info" v-else>默认</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" 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" prop="productName">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click="handleViewProduct(scope.row.productId)">{{scope.row.productName}}</el-link>
</template>
</el-table-column>
<el-table-column label="下载地址" align="center" prop="filePath" min-width="100">
<template slot-scope="scope">
<el-link :href="getDownloadUrl(scope.row.filePath)" :underline="false" type="success">{{getDownloadUrl(scope.row.filePath)}}</el-link>
</template>
</el-table-column>
<el-table-column label="固件描述" align="center" prop="remark" min-width="200" />
<!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button size="small" type="primary" style="padding:5px;" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['iot:firmware:edit']">修改</el-button>
<el-button size="small" type="danger" style="padding:5px;" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:firmware: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" />
<!-- 添加或修改产品固件对话框 -->
<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="firmwareName">
<el-input v-model="form.firmwareName" placeholder="请输入固件名称" />
</el-form-item>
<el-form-item label="所属产品" prop="productId">
<el-select v-model="form.productId" placeholder="请选择产品" @change="selectProduct">
<el-option v-for="product in productShortList" :key="product.id" :label="product.name" :value="product.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="固件版本" prop="version">
<el-input v-model="form.version" placeholder="请输入固件版本" type="number" />
</el-form-item>
<el-form-item label="固件上传" prop="filePath">
<fileUpload ref="file-upload" :value="form.filePath" :limit="1" :fileSize="10" :fileType='["bin", "zip", "pdf"]' @input="getFilePath($event)"></fileUpload>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</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>
</el-card>
</div>
</template>
<script>
import fileUpload from '../../../components/FileUpload/index'
import {
listShortProduct
} from "@/api/iot/product"
import {
listFirmware,
getFirmware,
delFirmware,
addFirmware,
updateFirmware
} from "@/api/iot/firmware";
import {
getToken
} from "@/utils/auth";
export default {
name: "Firmware",
dicts: ["iot_yes_no"],
components: {
fileUpload
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 产品固件表格数据
firmwareList: [],
// 产品简短列表
productShortList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
firmwareName: null,
productName: null,
tenantName: null,
isSys: null,
},
// 表单参数
form: {
version: 1.0
},
// 表单校验
rules: {
firmwareName: [{
required: true,
message: "固件名称不能为空",
trigger: "blur"
}],
productId: [{
required: true,
message: "产品ID不能为空",
trigger: "blur"
}],
productName: [{
required: true,
message: "产品名称不能为空",
trigger: "blur"
}],
version: [{
required: true,
message: "固件版本不能为空",
trigger: "blur"
}],
filePath: [{
required: true,
message: "文件路径不能为空",
trigger: "blur"
}],
},
// 上传参数
upload: {
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: {
Authorization: "Bearer " + getToken()
},
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/iot/tool/upload",
// 上传的文件列表
fileList: []
},
};
},
created() {
this.getList();
this.getProductShortList();
},
methods: {
/** 查看产品按钮操作 */
handleViewProduct(productId) {
this.$router.push({
path: '/iot/product-edit',
query: {
t: Date.now(),
productId: productId,
}
});
},
// 获取下载路径前缀
getDownloadUrl(path) {
return window.location.origin + process.env.VUE_APP_BASE_API + path;
},
/** 查询产品固件列表 */
getList() {
this.loading = true;
listFirmware(this.queryParams).then(response => {
this.firmwareList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 查询产品简短列表 */
getProductShortList() {
listShortProduct().then(response => {
this.productShortList = response.data;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
firmwareId: null,
firmwareName: null,
productId: null,
productName: null,
tenantId: null,
tenantName: null,
isSys: null,
version: 1.0,
filePath: null,
delFlag: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: 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.firmwareId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加产品固件";
this.upload.fileList = [];
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const firmwareId = row.firmwareId || this.ids
getFirmware(firmwareId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改产品固件";
this.upload.fileList = [{
name: this.form.firmwareName,
url: this.form.filePath
}];
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.firmwareId != null) {
updateFirmware(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addFirmware(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const firmwareIds = row.firmwareId || this.ids;
this.$modal.confirm('是否确认删除产品固件编号为"' + firmwareIds + '"的数据项?').then(function () {
return delFirmware(firmwareIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('iot/firmware/export', {
...this.queryParams
}, `firmware_${new Date().getTime()}.xlsx`)
},
/** 选择产品 */
selectProduct(val) {
for (var i = 0; i < this.productShortList.length; i++) {
if (this.productShortList[i].id == val) {
this.form.productName = this.productShortList[i].name;
return;
}
}
},
// 获取文件路径
getFilePath(data) {
console.log(data);
this.form.filePath = data;
},
// 文件提交处理
submitUpload() {
this.$refs.upload.submit();
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.isUploading = false;
this.form.filePath = response.url;
this.$modal.msgSuccess(response.msg);
},
// 文件下载处理
handleDownload(row) {
window.open(process.env.VUE_APP_BASE_API + row.filePath);
}
},
};
</script>

View File

@@ -1,636 +0,0 @@
<template>
<div style="padding-left:20px;">
<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:alert:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="getList">刷新</el-button>
</el-col>
<el-tag type="danger" style="margin-left:15px;">该功能暂不可用,后面版本发布</el-tag>
</el-row>
<el-table v-loading="loading" :data="alertList" @selection-change="handleSelectionChange" border size="mini">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="告警ID" align="center" prop="alertId" />
<el-table-column label="告警名称" align="center" prop="alertName" />
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.status==1">启动</el-tag>
<el-tag type="danger" v-if="scope.row.status==2">暂停</el-tag>
</template>
</el-table-column>
<el-table-column label="告警级别" align="center" prop="alertLevel">
<template slot-scope="scope">
<dict-tag :options="dict.type.iot_alert_level" :value="scope.row.alertLevel" />
</template>
</el-table-column>
<el-table-column label="触发器" align="center" prop="triggers" />
<el-table-column label="执行动作" align="center" prop="actions" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<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:alert:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:alert: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" />
<!-- 添加或修改设备告警对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<div class="el-divider el-divider--horizontal" style="margin-top: -25px;"></div>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row :gutter="50">
<el-col :span="12">
<el-form-item label="告警名称" prop="alertName">
<el-input v-model="form.alertName" placeholder="请输入告警名称" />
</el-form-item>
<el-form-item label="告警级别" prop="alertLevel">
<el-select v-model="form.alertLevel" placeholder="请选择告警级别" style="width:100%;">
<el-option v-for="dict in dict.type.iot_alert_level" :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"></el-option>
</el-select>
</el-form-item>
<el-form-item label="告警状态">
<el-switch v-model="form.status" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" rows="6" />
</el-form-item>
</el-col>
</el-row>
<el-divider></el-divider>
<el-form-item label="触发器" prop="griggers">
<el-select v-model="form.condition" placeholder="请选择" size="small" style="margin-bottom:10px;">
<el-option v-for="item in triggerConditions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<div v-for="(item,index) in form.triggers" :key="index" style="margin-bottom:15px;border:1px solid #ddd;padding:10px;">
<el-row>
<el-col :span="4">
<el-select v-model="item.source" placeholder="请选择" size="small" @change="changeTriggerSource">
<el-option v-for="subItem in triggerSource" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="16" :offset="1" v-if="item.source==2">
<el-time-picker v-model="timerTimeValue" size="small" value-format="HH:mm" placeholder="选择执行时间" @change="timeChange" :disabled="item.isAdvance==1"></el-time-picker>
</el-col>
<el-col :span="2" :offset="item.source==1?17:1" v-if="index!=0"><a style="color:#F56C6C" @click="removeTriggerItem(index)">删除</a></el-col>
</el-row>
<!--定时-->
<el-row v-if="item.source==2">
<el-col :span="24">
<el-row style="margin-bottom:5px;">
<el-col :span="4">
<el-select v-model="timerWeekRepeatValue" placeholder="请选择" @change="repeatChange" size="small" :disabled="item.isAdvance==1">
<el-option v-for="item in timerWeekRepeats" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
<el-col :span="15" :offset="1" v-if="timerWeekRepeatValue==3">
<el-select v-model="timerWeekValue" placeholder="请选择" multiple style="width:485px" @change="weekChange" size="small" :disabled="item.isAdvance==1">
<el-option v-for="item in timerWeeks" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<el-row>
<el-col :span="18">
<el-input v-model="item.cronExpression" placeholder="cron执行表达式" :disabled="item.isAdvance==0" size="small">
<template slot="append">
<el-button type="primary" @click="handleShowCron(item,index)" :disabled="item.isAdvance==0">
生成表达式
<i class="el-icon-time el-icon--right"></i>
</el-button>
</template>
</el-input>
</el-col>
<el-col :span="4" :offset="1">
<el-checkbox v-model="item.isAdvance" :true-label="1" :false-label="0" @change="customerCronChange">自定义表达式</el-checkbox>
</el-col>
</el-row>
</el-col>
</el-row>
<!--设备-->
<el-row>
<el-col :span="4">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="4" :offset="1">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="5" :offset="1">
<el-select v-model="item.operator" placeholder="请选择操作符" size="small">
<el-option key="=" label="等于(=)" value="=" />
<el-option key="!=" label="不等于(!=)" value="!=" />
<el-option key=">" label="大于(>)" value=">" />
<el-option key="<" label="小于(<)" value="<" />
<el-option key=">=" label="大于等于(>=)" value=">=" />
<el-option key="<=" label="小于等于(<=)" value="<=" />
<el-option key="contain" label="包含(contain)" value="contain" />
<el-option key="notcontain" label="不包含(not contain)" value="notcontain" />
</el-select>
</el-col>
<el-col :span="5" :offset="1">
<el-input v-model="item.value" placeholder="值" size="small" />
</el-col>
</el-row>
</div>
<div>+ <a style="color:#409EFF" @click="addTriggerItem()">添加触发器</a></div>
</el-form-item>
<el-divider></el-divider>
<el-form-item label="执行动作">
<el-row v-for="(item,index) in form.actions" :key="index" style="margin-bottom:10px;">
<el-col :span="4">
<el-select v-model="item.modelType" placeholder="请选择">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="4" :offset="1">
<el-select v-model="item.modelType" placeholder="请选择">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="11" :offset="1">
<el-input v-model="item.value" placeholder="值" />
</el-col>
<el-col :span="2" :offset="1" v-if="index!=0"><a style="color:#F56C6C" @click="removeActionItem(index)">删除</a></el-col>
</el-row>
<div>+ <a style="color:#409EFF" @click="addActionItem()">添加执行动作</a></div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" disabled> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
<crontab @hide="openCron=false" @fill="crontabFill" :expression="expression" style="padding-bottom:80px;"></crontab>
</el-dialog>
</div>
</template>
<script>
import {
listAlert,
getAlert,
delAlert,
addAlert,
updateAlert
} from "@/api/iot/alert";
import {
cacheJsonThingsModel
} from "@/api/iot/model";
import Crontab from '@/components/Crontab'
export default {
name: "device-alert",
dicts: ['iot_alert_level', 'sys_job_status'],
components: {
Crontab
},
props: {
product: {
type: Object,
default: null
}
},
watch: {
// 获取到父组件传递的productId后刷新列表
product: function (newVal, oldVal) {
this.productInfo = newVal;
if (this.productInfo && this.productInfo.productId != 0) {
this.queryParams.productId = this.productInfo.productId;
this.getList();
// 获取缓存的Json物模型
cacheJsonThingsModel(newVal.productId).then(response => {
this.thingsModel = JSON.parse(response.data);
});
}
}
},
data() {
return {
// 物模型JSON
thingsModel: {},
// 遮罩层
loading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 设备告警表格数据
alertList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否显示Cron表达式弹出层
openCron: false,
// 传入的表达式
expression: "",
// 触发器的索引,用于接收传入的表达式
triggerIndex: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
alertName: null,
alertLevel: null,
productId: null,
productName: null,
},
// 周
timerWeekRepeats: [{
value: '1',
label: '每天'
}, {
value: '2',
label: '仅此一次'
}, {
value: '3',
label: '指定'
}],
timerWeekRepeatValue: "1",
timerWeeks: [{
value: 1,
label: '周一'
}, {
value: 2,
label: '周二'
}, {
value: 3,
label: '周三'
}, {
value: 4,
label: '周四'
}, {
value: 5,
label: '周五'
}, {
value: 6,
label: '周六'
}, {
value: 7,
label: '周日'
}],
timerWeekValue: [1, 2, 3, 4, 5, 6, 7],
// 时间
timerTimeValue: '',
// 触发器源 1=设备2=定时3=告警输出
triggerSource: [{
value: 1,
label: '设备'
}, {
value: 2,
label: '定时'
}],
// 执行动作源
actionSource: [{
value: 1,
label: '设备'
}, {
value: 3,
label: '告警输出'
}],
// 物模型类别
modelTypes: [{
value: 1,
label: '属性'
}, {
value: 2,
label: '功能'
}],
// 触发器条件
triggerConditions: [{
value: "all",
label: '满足所有条件'
}, {
value: "any",
label: '满足任一条件'
}],
// 告警状态
alertType: [{
value: 1,
label: '启动'
}, {
value: 2,
label: '停止'
}],
// 表单参数
form: {
condition: "all", // 触发器条件
triggers: [],
actions: []
},
// 产品
productInfo: {},
// 表单校验
rules: {
alertName: [{
required: true,
message: "告警名称不能为空",
trigger: "blur"
}],
alertLevel: [{
required: true,
message: "告警级别不能为空",
trigger: "change"
}],
productId: [{
required: true,
message: "产品ID不能为空",
trigger: "blur"
}],
productName: [{
required: true,
message: "产品名称不能为空",
trigger: "blur"
}],
triggers: [{
required: true,
message: "触发器不能为空",
trigger: "blur"
}],
actions: [{
required: true,
message: "执行动作不能为空",
trigger: "blur"
}],
}
};
},
created() {
// this.getList();
},
methods: {
/** 查询设备告警列表 */
getList() {
this.loading = true;
listAlert(this.queryParams).then(response => {
this.alertList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
alertId: null,
alertName: null,
alertLevel: null,
productId: null,
productName: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
status: 1,
condition: "all", // 触发器条件
triggers: [{
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
jobId: 0,
cronExpression: "",
isAdvance: 0
}],
actions: [{
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
}]
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.alertId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加自定义告警";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const alertId = row.alertId || this.ids
getAlert(alertId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改设备告警";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.alertId != null) {
updateAlert(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addAlert(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const alertIds = row.alertId || this.ids;
this.$modal.confirm('是否确认删除设备告警编号为"' + alertIds + '"的数据项?').then(function () {
return delAlert(alertIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('iot/alert/export', {
...this.queryParams
}, `alert_${new Date().getTime()}.xlsx`)
},
/** 添加动作 */
addActionItem() {
this.form.actions.push({
id: "",
name: "",
value: ""
})
},
/** 删除动作 */
removeActionItem(index) {
this.form.actions.splice(index, 1);
},
/** 触发器源改变事件 **/
changeTriggerSource() {
this.setTriggerSource();
},
/** 设置触发器源 **/
setTriggerSource() {
// 触发器智能包含一个定时
let hasTimer = false;
for (let i = 0; i < this.form.triggers.length; i++) {
if (this.form.triggers[i].source == 2) {
hasTimer = true;
}
}
if (hasTimer) {
this.triggerSource = [{
value: 1,
label: '设备'
}];
} else {
//定时
this.triggerSource = [{
value: 1,
label: '设备'
}, {
value: 2,
label: '定时'
}];
}
},
/** 添加触发器 */
addTriggerItem() {
this.setTriggerSource();
this.form.triggers.push({
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
jobId: 0,
cronExpression: "",
isAdvance: 0
})
},
/** 删除触发器 */
removeTriggerItem(index) {
this.form.triggers.splice(index, 1);
this.setTriggerSource();
},
/** cron表达式按钮操作 */
handleShowCron(item, index) {
this.expression = item.cronExpression;
this.triggerIndex = index;
this.openCron = true;
},
/** 确定后回传值 */
crontabFill(value) {
this.form.triggers[this.triggerIndex].cronExpression = value;
},
/** 修改重复事件 **/
repeatChange(data) {
if (this.timerWeekRepeatValue == 1) {
// 每天
this.timerWeekValue = [1, 2, 3, 4, 5, 6, 7];
this.form.repeat = 1;
} else if (this.timerWeekRepeatValue == 2) {
// 仅此一次
this.timerWeekValue = [];
this.form.isRepeat = 0;
} else {
// 指定
this.form.isRepeat = 1;
}
this.gentCronExpression();
},
/** 星期改变事件 **/
weekChange(data) {
this.gentCronExpression();
},
/** 时间改变事件 **/
timeChange(data) {
this.gentCronExpression();
},
/**自定义cron表达式选项改变事件 */
customerCronChange(data) {
this.gentCronExpression();
},
/** 生成cron表达式**/
gentCronExpression() {
if (this.timerTimeValue == "") {
this.$modal.alertError("执行时间不能为空");
}
let minute = this.timerTimeValue.substring(0, 2);
let hour = this.timerTimeValue.substring(3);
let week = "*";
if (this.timerWeekValue.length > 0) {
week = this.timerWeekValue;
}
this.form.triggers[this.triggerIndex].cronExpression = "0 " + minute + " " + hour + " ? * " + week;
}
}
};
</script>

View File

@@ -1,322 +0,0 @@
<template>
<div style="padding-left:20px;">
<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:firmware:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="getList">刷新</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="firmwareList" @selection-change="handleSelectionChange" size="small">
<el-table-column label="固件名称" align="center" prop="firmwareName" />
<el-table-column label="固件版本" align="center" prop="version" width="120">
<template slot-scope="scope">
<span>Version </span> {{scope.row.version}}
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="isLatest" width="80">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.isLatest==1">最新</el-tag>
<el-tag type="info" v-else>默认</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" 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" prop="filePath" min-width="100">
<template slot-scope="scope">
<el-link :href="getDownloadUrl(scope.row.filePath)" :underline="false" type="success">{{getDownloadUrl(scope.row.filePath)}}</el-link>
</template>
</el-table-column>
<el-table-column label="固件描述" align="center" prop="remark" min-width="200" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button size="small" type="primary" style="padding:5px;" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['iot:firmware:edit']">修改</el-button>
<el-button size="small" type="danger" style="padding:5px;" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:firmware:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改产品固件对话框 -->
<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="firmwareName">
<el-input v-model="form.firmwareName" placeholder="请输入固件名称" />
</el-form-item>
<el-form-item label="固件版本" prop="version">
<el-input v-model="form.version" placeholder="请输入固件版本" type="number" step="0.1" />
</el-form-item>
<el-form-item label="最新固件" prop="isLatest">
<el-switch v-model="form.isLatest" active-text="" inactive-text="" :active-value="1" :inactive-value="0">
</el-switch>
<el-link type="info" :underline="false" style="font-size:12px;margin-left:15px;">提示产品中只能有一个最新固件</el-link>
</el-form-item>
<el-form-item label="固件上传" prop="filePath">
<fileUpload ref="file-upload" :value="form.filePath" :limit="1" :fileSize="10" :fileType='["bin", "zip", "pdf"]' @input="getFilePath($event)"></fileUpload>
</el-form-item>
<el-form-item label="固件描述" prop="remark">
<el-input v-model="form.remark" type="textarea" rows="4" placeholder="请输入固件信息" />
</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>
</template>
<script>
import fileUpload from '../../../components/FileUpload/index'
import {
listFirmware,
getFirmware,
delFirmware,
addFirmware,
updateFirmware
} from "@/api/iot/firmware";
import {
getToken
} from "@/utils/auth";
export default {
name: "product-firmware",
dicts: ["iot_yes_no"],
components: {
fileUpload
},
props: {
product: {
type: Object,
default: null
}
},
watch: {
// 获取到父组件传递的productId后刷新列表
product: function (newVal, oldVal) {
this.productInfo = newVal;
if (this.productInfo && this.productInfo.productId != 0) {
this.queryParams.productId = this.productInfo.productId;
this.form.productId = this.productInfo.productId;
this.form.productName = this.productInfo.productName;
this.getList();
}
}
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 产品固件表格数据
firmwareList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 100,
firmwareName: null,
productName: null,
productId: 0,
isSys: null,
},
// 产品
productInfo: {},
// 表单参数
form: {
version: 1.0
},
// 表单校验
rules: {
firmwareName: [{
required: true,
message: "固件名称不能为空",
trigger: "blur"
}],
version: [{
required: true,
message: "固件版本不能为空",
trigger: "blur"
}],
filePath: [{
required: true,
message: "文件路径不能为空",
trigger: "blur"
}],
},
// 上传参数
upload: {
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: {
Authorization: "Bearer " + getToken()
},
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/iot/tool/upload",
// 上传的文件列表
fileList: []
},
};
},
created() {},
methods: {
getDownloadUrl(path) {
return window.location.origin + process.env.VUE_APP_BASE_API + path;
},
/** 查询产品固件列表 */
getList() {
this.loading = true;
listFirmware(this.queryParams).then(response => {
this.firmwareList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
firmwareId: null,
firmwareName: null,
tenantId: null,
tenantName: null,
productId: this.form.productId,
productName: this.form.productName,
isSys: null,
isLatest: 0,
version: 1.0,
filePath: null,
delFlag: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: 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.firmwareId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加产品固件";
this.upload.fileList = [];
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const firmwareId = row.firmwareId || this.ids
getFirmware(firmwareId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改产品固件";
this.upload.fileList = [{
name: this.form.firmwareName,
url: this.form.filePath
}];
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.firmwareId != null) {
updateFirmware(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addFirmware(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const firmwareIds = row.firmwareId || this.ids;
this.$modal.confirm('是否确认删除产品固件编号为"' + firmwareIds + '"的数据项?').then(function () {
return delFirmware(firmwareIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('iot/firmware/export', {
...this.queryParams
}, `firmware_${new Date().getTime()}.xlsx`)
},
// 获取文件路径
getFilePath(data) {
this.form.filePath = data;
},
// 文件提交处理
submitUpload() {
this.$refs.upload.submit();
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.isUploading = false;
this.form.filePath = response.url;
this.$modal.msgSuccess(response.msg);
},
// 文件下载处理
handleDownload(row) {
window.open(process.env.VUE_APP_BASE_API + row.filePath);
}
},
};
</script>

View File

@@ -1,624 +0,0 @@
<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="场景名称" prop="sceneName">
<el-input v-model="queryParams.sceneName" placeholder="请输入场景名称" 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>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="padding-bottom:100px;">
<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:scene: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:scene:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" disabled @click="handleDelete" v-hasPermi="['iot:scene: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:scene:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="sceneList" @selection-change="handleSelectionChange" border>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="场景名称" align="center" prop="sceneName" />
<el-table-column label="用户ID" align="center" prop="userId" />
<el-table-column label="用户名称" align="center" prop="userName" />
<el-table-column label="触发器" align="center" prop="triggers" />
<el-table-column label="执行动作" align="center" prop="actions" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<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:scene:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:scene:remove']" disabled>删除</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" />
<!-- 添加或修改场景联动对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="16">
<el-form-item label="场景名称" prop="sceneName">
<el-input v-model="form.sceneName" placeholder="请输入场景名称" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="触发器" prop="griggers">
<el-select v-model="form.condition" placeholder="请选择" size="small" style="margin-bottom:10px;">
<el-option v-for="item in triggerConditions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<div v-for="(item,index) in form.triggers" :key="index" style="margin-bottom:15px;border:1px solid #ddd;padding:10px;">
<el-row>
<el-col :span="4">
<el-select v-model="item.source" placeholder="请选择" size="small" @change="changeTriggerSource">
<el-option v-for="subItem in triggerSource" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="16" :offset="1" v-if="item.source==1">
<el-link :underline="false">请选择一个设备<i class="el-icon-edit el-icon--right"></i></el-link>
</el-col>
<el-col :span="16" :offset="1" v-if="item.source==2">
<el-time-picker v-model="timerTimeValue" size="small" value-format="HH:mm" placeholder="选择执行时间" @change="timeChange" :disabled="item.isAdvance==1"></el-time-picker>
</el-col>
<el-col :span="2" :offset="1" v-if="index!=0"><a style="color:#F56C6C" @click="removeTriggerItem(index)">删除</a></el-col>
</el-row>
<!--设备-->
<el-row v-if="item.source==1">
<el-col :span="4">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="4" :offset="1">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="5" :offset="1">
<el-select v-model="item.operator" placeholder="请选择操作符" size="small">
<el-option key="=" label="等于(=)" value="=" />
<el-option key="!=" label="不等于(!=)" value="!=" />
<el-option key=">" label="大于(>)" value=">" />
<el-option key="<" label="小于(<)" value="<" />
<el-option key=">=" label="大于等于(>=)" value=">=" />
<el-option key="<=" label="小于等于(<=)" value="<=" />
<el-option key="contain" label="包含(contain)" value="contain" />
<el-option key="notcontain" label="不包含(not contain)" value="notcontain" />
</el-select>
</el-col>
<el-col :span="5" :offset="1">
<el-input v-model="item.value" placeholder="值" size="small" />
</el-col>
</el-row>
<!--定时-->
<el-row v-if="item.source==2">
<el-col :span="24">
<el-row style="margin-bottom:5px;">
<el-col :span="4">
<el-select v-model="timerWeekRepeatValue" placeholder="请选择" @change="repeatChange" size="small" :disabled="item.isAdvance==1">
<el-option v-for="item in timerWeekRepeats" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
<el-col :span="15" :offset="1" v-if="timerWeekRepeatValue==3">
<el-select v-model="timerWeekValue" placeholder="请选择" multiple style="width:485px" @change="weekChange" size="small" :disabled="item.isAdvance==1">
<el-option v-for="item in timerWeeks" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<el-row>
<el-col :span="18">
<el-input v-model="item.cronExpression" placeholder="cron执行表达式" :disabled="item.isAdvance==0" size="small">
<template slot="append">
<el-button type="primary" @click="handleShowCron(item,index)" :disabled="item.isAdvance==0">
生成表达式
<i class="el-icon-time el-icon--right"></i>
</el-button>
</template>
</el-input>
</el-col>
<el-col :span="4" :offset="1">
<el-checkbox v-model="item.isAdvance" :true-label="1" :false-label="0" @change="customerCronChange">自定义表达式</el-checkbox>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
<div>+ <a style="color:#409EFF" @click="addTriggerItem()">添加触发器</a></div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="执行动作">
<div v-for="(item,index) in form.actions" :key="index" style="margin-bottom:15px;border:1px solid #ddd;padding:10px;">
<el-row>
<el-col :span="4">
<el-select v-model="item.source" placeholder="请选择" size="small">
<el-option v-for="subItem in actionSource" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="10" :offset="1" v-if="item.source==1">
<el-link :underline="false">请选择一个设备<i class="el-icon-edit el-icon--right"></i></el-link>
</el-col>
</el-row>
<!---设备-->
<el-row v-if="item.source==1">
<el-col :span="4">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="4" :offset="1">
<el-select v-model="item.modelType" placeholder="请选择" size="small">
<el-option v-for="subItem in modelTypes" :key="subItem.value" :label="subItem.label" :value="subItem.value">
</el-option>
</el-select>
</el-col>
<el-col :span="11" :offset="1">
<el-input v-model="item.value" placeholder="值" size="small" />
</el-col>
<el-col :span="2" :offset="1" v-if="index!=0"><a style="color:#F56C6C" @click="removeActionItem(index)">删除</a></el-col>
</el-row>
<!--告警输出-->
<el-row v-if="item.source==3">
<el-col :span="4">
<el-select v-model="item.alertLevel" placeholder="告警级别" size="small">
<el-option v-for="dict in dict.type.iot_alert_level" :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"></el-option>
</el-select>
</el-col>
<el-col :span="16" :offset="1">
<el-input v-model="item.alertName" placeholder="请输入告警名称" size="small" />
</el-col>
</el-row>
</div>
<div>+ <a style="color:#409EFF" @click="addActionItem()">添加执行动作</a></div>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" disabled> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
<crontab @hide="openCron=false" @fill="crontabFill" :expression="expression" style="padding-bottom:80px;"></crontab>
</el-dialog>
</el-card>
</div>
</template>
<script>
import {
listScene,
getScene,
delScene,
addScene,
updateScene
} from "@/api/iot/scene";
import Crontab from '@/components/Crontab'
export default {
components: {
Crontab
},
name: "Scene",
dicts: ['iot_alert_level'],
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 场景联动表格数据
sceneList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否显示Cron表达式弹出层
openCron: false,
// 传入的表达式
expression: "",
// 触发器的索引,用于接收传入的表达式
triggerIndex:0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
sceneName: null,
userId: null,
userName: null,
},
// 周
timerWeekRepeats: [{
value: '1',
label: '每天'
}, {
value: '2',
label: '仅此一次'
}, {
value: '3',
label: '指定'
}],
timerWeekRepeatValue: "1",
timerWeeks: [{
value: 1,
label: '周一'
}, {
value: 2,
label: '周二'
}, {
value: 3,
label: '周三'
}, {
value: 4,
label: '周四'
}, {
value: 5,
label: '周五'
}, {
value: 6,
label: '周六'
}, {
value: 7,
label: '周日'
}],
timerWeekValue: [1, 2, 3, 4, 5, 6, 7],
// 时间
timerTimeValue: '',
// 触发器源 1=设备2=定时3=告警输出
triggerSource: [{
value: 1,
label: '设备'
}, {
value: 2,
label: '定时'
}],
// 执行动作源
actionSource: [{
value: 1,
label: '设备'
}, {
value: 3,
label: '告警输出'
}],
// 物模型类别
modelTypes: [{
value: 1,
label: '属性'
}, {
value: 2,
label: '功能'
}],
// 触发器条件
triggerConditions: [{
value: "all",
label: '满足所有条件'
}, {
value: "any",
label: '满足任一条件'
}],
// 表单参数
form: {
condition: "all", // 触发器条件
triggers: [],
actions: []
},
// 表单校验
rules: {
sceneName: [{
required: true,
message: "场景名称不能为空",
trigger: "blur"
}],
userId: [{
required: true,
message: "用户ID不能为空",
trigger: "blur"
}],
userName: [{
required: true,
message: "用户名称不能为空",
trigger: "blur"
}],
triggers: [{
required: true,
message: "触发器不能为空",
trigger: "blur"
}],
actions: [{
required: true,
message: "执行动作不能为空",
trigger: "blur"
}],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询场景联动列表 */
getList() {
this.loading = true;
listScene(this.queryParams).then(response => {
this.sceneList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
sceneId: null,
sceneName: null,
userId: null,
userName: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
condition: "all", // 触发器条件
triggers: [{
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
jobId: 0,
cronExpression: "",
isAdvance: 0
}],
actions: [{
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
}]
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.sceneId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加场景联动";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const sceneId = row.sceneId || this.ids
getScene(sceneId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改场景联动";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.sceneId != null) {
updateScene(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addScene(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const sceneIds = row.sceneId || this.ids;
this.$modal.confirm('是否确认删除场景联动编号为"' + sceneIds + '"的数据项?').then(function () {
return delScene(sceneIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('iot/scene/export', {
...this.queryParams
}, `scene_${new Date().getTime()}.xlsx`)
},
/** 添加动作 */
addActionItem() {
this.form.actions.push({
id: "",
name: "",
value: ""
})
},
/** 删除动作 */
removeActionItem(index) {
this.form.actions.splice(index, 1);
},
/** 触发器源改变事件 **/
changeTriggerSource(data) {
this.setTriggerSource();
},
/** 设置触发器源 **/
setTriggerSource() {
// 触发器智能包含一个定时
let hasTimer = false;
for (let i = 0; i < this.form.triggers.length; i++) {
if (this.form.triggers[i].source == 2) {
hasTimer = true;
this.triggerIndex=i;
}
}
if (hasTimer) {
this.triggerSource = [{
value: 1,
label: '设备'
}];
} else {
//定时
this.triggerSource = [{
value: 1,
label: '设备'
}, {
value: 2,
label: '定时'
}];
}
},
/** 添加触发器 */
addTriggerItem() {
this.setTriggerSource();
this.form.triggers.push({
id: "",
name: "",
value: "",
deviceId: 0,
deviceName: "请选择一个设备",
source: 1, //1=设备2=定时3=告警输出
modelType: 1, // 1=属性2=功能
jobId: 0,
cronExpression: "",
isAdvance: 0
})
},
/** 删除触发器 */
removeTriggerItem(index) {
this.form.triggers.splice(index, 1);
this.setTriggerSource();
},
/** cron表达式按钮操作 */
handleShowCron(item,index) {
this.expression=item.cronExpression;
this.triggerIndex=index;
this.openCron = true;
},
/** 确定后回传值 */
crontabFill(value) {
this.form.triggers[this.triggerIndex].cronExpression = value;
},
/** 修改重复事件 **/
repeatChange(data) {
if (this.timerWeekRepeatValue == 1) {
// 每天
this.timerWeekValue = [1, 2, 3, 4, 5, 6, 7];
this.form.isRepeat = 1;
} else if (this.timerWeekRepeatValue == 2) {
// 仅此一次
this.timerWeekValue = [];
this.form.isRepeat = 0;
} else {
// 指定
this.form.isRepeat = 1;
}
this.gentCronExpression();
},
/** 星期改变事件 **/
weekChange(data) {
this.gentCronExpression();
},
/** 时间改变事件 **/
timeChange(data) {
this.gentCronExpression();
},
/**自定义cron表达式选项改变事件 */
customerCronChange(data){
this.gentCronExpression();
},
/** 生成cron表达式**/
gentCronExpression() {
if (this.timerTimeValue == "") {
this.$modal.alertError("执行时间不能为空");
}
let minute = this.timerTimeValue.substring(0, 2);
let hour = this.timerTimeValue.substring(3);
let week = "*";
if (this.timerWeekValue.length > 0) {
week = this.timerWeekValue;
}
this.form.triggers[this.triggerIndex].cronExpression = "0 " + minute + " " + hour + " ? * " + week;
}
}
};
</script>