Skip to content

Commit 9ca5ffb

Browse files
YunaiVgitee-org
authored andcommitted
!726 【功能新增】IoT: 数据桥梁管理
Merge pull request !726 from puhui999/feature/iot
2 parents 3c52808 + 38f0aff commit 9ca5ffb

File tree

13 files changed

+8223
-5789
lines changed

13 files changed

+8223
-5789
lines changed

pnpm-lock.yaml

Lines changed: 7218 additions & 5788 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/iot/rule/databridge/index.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import request from '@/config/axios'
2+
3+
//数据桥梁 VO
4+
export interface DataBridgeVO {
5+
id?: number // 桥梁编号
6+
name?: string // 桥梁名称
7+
description?: string // 桥梁描述
8+
status?: number // 桥梁状态
9+
direction?: number // 桥梁方向
10+
type?: number // 桥梁类型
11+
config?:
12+
| HttpConfig
13+
| MqttConfig
14+
| RocketMQConfig
15+
| KafkaMQConfig
16+
| RabbitMQConfig
17+
| RedisStreamMQConfig // 桥梁配置
18+
}
19+
20+
interface Config {
21+
type: string
22+
}
23+
24+
/** HTTP 配置 */
25+
export interface HttpConfig extends Config {
26+
url: string
27+
method: string
28+
headers: Record<string, string>
29+
query: Record<string, string>
30+
body: string
31+
}
32+
33+
/** MQTT 配置 */
34+
export interface MqttConfig extends Config {
35+
url: string
36+
username: string
37+
password: string
38+
clientId: string
39+
topic: string
40+
}
41+
42+
/** RocketMQ 配置 */
43+
export interface RocketMQConfig extends Config {
44+
nameServer: string
45+
accessKey: string
46+
secretKey: string
47+
group: string
48+
topic: string
49+
tags: string
50+
}
51+
52+
/** Kafka 配置 */
53+
export interface KafkaMQConfig extends Config {
54+
bootstrapServers: string
55+
username: string
56+
password: string
57+
ssl: boolean
58+
topic: string
59+
}
60+
61+
/** RabbitMQ 配置 */
62+
export interface RabbitMQConfig extends Config {
63+
host: string
64+
port: number
65+
virtualHost: string
66+
username: string
67+
password: string
68+
exchange: string
69+
routingKey: string
70+
queue: string
71+
}
72+
73+
/** Redis Stream MQ 配置 */
74+
export interface RedisStreamMQConfig extends Config {
75+
host: string
76+
port: number
77+
password: string
78+
database: number
79+
topic: string
80+
}
81+
82+
/** 数据桥梁类型 */
83+
export const IoTDataBridgeConfigType = {
84+
HTTP: '1',
85+
TCP: '2',
86+
WEBSOCKET: '3',
87+
MQTT: '10',
88+
DATABASE: '20',
89+
REDIS_STREAM: '21',
90+
ROCKETMQ: '30',
91+
RABBITMQ: '31',
92+
KAFKA: '32'
93+
} as const
94+
95+
// 数据桥梁 API
96+
export const DataBridgeApi = {
97+
// 查询数据桥梁分页
98+
getDataBridgePage: async (params: any) => {
99+
return await request.get({ url: `/iot/data-bridge/page`, params })
100+
},
101+
102+
// 查询数据桥梁详情
103+
getDataBridge: async (id: number) => {
104+
return await request.get({ url: `/iot/data-bridge/get?id=` + id })
105+
},
106+
107+
// 新增数据桥梁
108+
createDataBridge: async (data: DataBridgeVO) => {
109+
return await request.post({ url: `/iot/data-bridge/create`, data })
110+
},
111+
112+
// 修改数据桥梁
113+
updateDataBridge: async (data: DataBridgeVO) => {
114+
return await request.put({ url: `/iot/data-bridge/update`, data })
115+
},
116+
117+
// 删除数据桥梁
118+
deleteDataBridge: async (id: number) => {
119+
return await request.delete({ url: `/iot/data-bridge/delete?id=` + id })
120+
},
121+
122+
// 导出数据桥梁 Excel
123+
exportDataBridge: async (params) => {
124+
return await request.download({ url: `/iot/data-bridge/export-excel`, params })
125+
}
126+
}

src/utils/dict.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,5 +242,7 @@ export enum DICT_TYPE {
242242
IOT_RW_TYPE = 'iot_rw_type', // IOT 读写类型
243243
IOT_PLUGIN_DEPLOY_TYPE = 'iot_plugin_deploy_type', // IOT 插件部署类型
244244
IOT_PLUGIN_STATUS = 'iot_plugin_status', // IOT 插件状态
245-
IOT_PLUGIN_TYPE = 'iot_plugin_type' // IOT 插件类型
245+
IOT_PLUGIN_TYPE = 'iot_plugin_type', // IOT 插件类型
246+
IOT_DATA_BRIDGE_DIRECTION_ENUM = 'iot_data_bridge_direction_enum', // 桥梁方向
247+
IOT_DATA_BRIDGE_TYPE_ENUM = 'iot_data_bridge_type_enum' // 桥梁类型
246248
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
<template>
2+
<Dialog v-model="dialogVisible" :title="dialogTitle">
3+
<el-form
4+
ref="formRef"
5+
v-loading="formLoading"
6+
:model="formData"
7+
:rules="formRules"
8+
label-width="120px"
9+
>
10+
<el-form-item label="桥梁名称" prop="name">
11+
<el-input v-model="formData.name" placeholder="请输入桥梁名称" />
12+
</el-form-item>
13+
<el-form-item label="桥梁方向" prop="direction">
14+
<el-radio-group v-model="formData.direction">
15+
<el-radio
16+
v-for="dict in getIntDictOptions(DICT_TYPE.IOT_DATA_BRIDGE_DIRECTION_ENUM)"
17+
:key="dict.value"
18+
:label="dict.value"
19+
>
20+
{{ dict.label }}
21+
</el-radio>
22+
</el-radio-group>
23+
</el-form-item>
24+
<el-form-item label="桥梁类型" prop="type">
25+
<el-radio-group :model-value="formData.type" @change="handleTypeChange">
26+
<el-radio
27+
v-for="dict in getIntDictOptions(DICT_TYPE.IOT_DATA_BRIDGE_TYPE_ENUM)"
28+
:key="dict.value"
29+
:label="dict.value"
30+
>
31+
{{ dict.label }}
32+
</el-radio>
33+
</el-radio-group>
34+
</el-form-item>
35+
<HttpConfigForm v-if="showConfig(IoTDataBridgeConfigType.HTTP)" v-model="formData.config" />
36+
<MqttConfigForm v-if="showConfig(IoTDataBridgeConfigType.MQTT)" v-model="formData.config" />
37+
<RocketMQConfigForm
38+
v-if="showConfig(IoTDataBridgeConfigType.ROCKETMQ)"
39+
v-model="formData.config"
40+
/>
41+
<KafkaMQConfigForm
42+
v-if="showConfig(IoTDataBridgeConfigType.KAFKA)"
43+
v-model="formData.config"
44+
/>
45+
<RabbitMQConfigForm
46+
v-if="showConfig(IoTDataBridgeConfigType.RABBITMQ)"
47+
v-model="formData.config"
48+
/>
49+
<RedisStreamMQConfigForm
50+
v-if="showConfig(IoTDataBridgeConfigType.REDIS_STREAM)"
51+
v-model="formData.config"
52+
/>
53+
<el-form-item label="桥梁状态" prop="status">
54+
<el-radio-group v-model="formData.status">
55+
<el-radio
56+
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
57+
:key="dict.value"
58+
:label="dict.value"
59+
>
60+
{{ dict.label }}
61+
</el-radio>
62+
</el-radio-group>
63+
</el-form-item>
64+
<el-form-item label="桥梁描述" prop="description">
65+
<el-input v-model="formData.description" height="150px" type="textarea" />
66+
</el-form-item>
67+
</el-form>
68+
<template #footer>
69+
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
70+
<el-button @click="dialogVisible = false">取 消</el-button>
71+
</template>
72+
</Dialog>
73+
</template>
74+
<script lang="ts" setup>
75+
import { DICT_TYPE, getDictObj, getIntDictOptions } from '@/utils/dict'
76+
import { DataBridgeApi, DataBridgeVO, IoTDataBridgeConfigType } from '@/api/iot/rule/databridge'
77+
import {
78+
HttpConfigForm,
79+
KafkaMQConfigForm,
80+
MqttConfigForm,
81+
RabbitMQConfigForm,
82+
RedisStreamMQConfigForm,
83+
RocketMQConfigForm
84+
} from './config'
85+
86+
/** IoT 数据桥梁 表单 */
87+
defineOptions({ name: 'IoTDataBridgeForm' })
88+
89+
const { t } = useI18n() // 国际化
90+
const message = useMessage() // 消息弹窗
91+
92+
const dialogVisible = ref(false) // 弹窗的是否展示
93+
const dialogTitle = ref('') // 弹窗的标题
94+
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
95+
const formType = ref('') // 表单的类型:create - 新增;update - 修改
96+
const formData = ref<DataBridgeVO>({
97+
status: 0,
98+
direction: 1,
99+
type: 1,
100+
config: {} as any
101+
})
102+
const formRules = reactive({
103+
/** 通用字段 */
104+
name: [{ required: true, message: '桥梁名称不能为空', trigger: 'blur' }],
105+
status: [{ required: true, message: '桥梁状态不能为空', trigger: 'blur' }],
106+
direction: [{ required: true, message: '桥梁方向不能为空', trigger: 'blur' }],
107+
type: [{ required: true, message: '桥梁类型不能为空', trigger: 'change' }],
108+
/** HTTP 配置 */
109+
'config.url': [{ required: true, message: '请求地址不能为空', trigger: 'blur' }],
110+
'config.method': [{ required: true, message: '请求方法不能为空', trigger: 'blur' }],
111+
/** MQTT 配置 */
112+
'config.username': [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
113+
'config.password': [{ required: true, message: '密码不能为空', trigger: 'blur' }],
114+
'config.clientId': [{ required: true, message: '客户端ID不能为空', trigger: 'blur' }],
115+
'config.topic': [{ required: true, message: '主题不能为空', trigger: 'blur' }],
116+
/** RocketMQ 配置 */
117+
'config.nameServer': [{ required: true, message: 'NameServer 地址不能为空', trigger: 'blur' }],
118+
'config.accessKey': [{ required: true, message: 'AccessKey 不能为空', trigger: 'blur' }],
119+
'config.secretKey': [{ required: true, message: 'SecretKey 不能为空', trigger: 'blur' }],
120+
'config.group': [{ required: true, message: '消费组不能为空', trigger: 'blur' }],
121+
/** Kafka 配置 */
122+
'config.bootstrapServers': [{ required: true, message: '服务地址不能为空', trigger: 'blur' }],
123+
'config.ssl': [{ required: true, message: 'SSL 配置不能为空', trigger: 'change' }],
124+
/** RabbitMQ 配置 */
125+
'config.host': [{ required: true, message: '主机地址不能为空', trigger: 'blur' }],
126+
'config.port': [
127+
{ required: true, message: '端口不能为空', trigger: 'blur' },
128+
{ type: 'number', min: 1, max: 65535, message: '端口号范围 1-65535', trigger: 'blur' }
129+
],
130+
'config.virtualHost': [{ required: true, message: '虚拟主机不能为空', trigger: 'blur' }],
131+
'config.exchange': [{ required: true, message: '交换机不能为空', trigger: 'blur' }],
132+
'config.routingKey': [{ required: true, message: '路由键不能为空', trigger: 'blur' }],
133+
'config.queue': [{ required: true, message: '队列不能为空', trigger: 'blur' }],
134+
/** Redis Stream 配置 */
135+
'config.database': [
136+
{ required: true, message: '数据库索引不能为空', trigger: 'blur' },
137+
{ type: 'number', min: 0, message: '数据库索引必须是非负整数', trigger: 'blur' }
138+
]
139+
})
140+
141+
const formRef = ref() // 表单 Ref
142+
const showConfig = computed(() => (val: string) => {
143+
const dict = getDictObj(DICT_TYPE.IOT_DATA_BRIDGE_TYPE_ENUM, formData.value.type)
144+
return dict && dict.value + '' === val
145+
}) // 显示对应的 Config 配置项
146+
/** 打开弹窗 */
147+
const open = async (type: string, id?: number) => {
148+
dialogVisible.value = true
149+
dialogTitle.value = t('action.' + type)
150+
formType.value = type
151+
resetForm()
152+
// 修改时,设置数据
153+
if (id) {
154+
formLoading.value = true
155+
try {
156+
formData.value = await DataBridgeApi.getDataBridge(id)
157+
} finally {
158+
formLoading.value = false
159+
}
160+
}
161+
}
162+
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
163+
164+
/** 提交表单 */
165+
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
166+
const submitForm = async () => {
167+
// 校验表单
168+
await formRef.value.validate()
169+
// 提交请求
170+
formLoading.value = true
171+
try {
172+
const data = formData.value as unknown as DataBridgeVO
173+
if (formType.value === 'create') {
174+
await DataBridgeApi.createDataBridge(data)
175+
message.success(t('common.createSuccess'))
176+
} else {
177+
await DataBridgeApi.updateDataBridge(data)
178+
message.success(t('common.updateSuccess'))
179+
}
180+
dialogVisible.value = false
181+
// 发送操作成功的事件
182+
emit('success')
183+
} finally {
184+
formLoading.value = false
185+
}
186+
}
187+
188+
/** 处理类型切换事件 */
189+
const handleTypeChange = (val: number) => {
190+
formData.value.type = val
191+
// 切换类型时重置配置
192+
formData.value.config = {} as any
193+
}
194+
195+
/** 重置表单 */
196+
const resetForm = () => {
197+
formData.value = {
198+
status: 0,
199+
direction: 1,
200+
type: 1,
201+
config: {} as any
202+
}
203+
formRef.value?.resetFields()
204+
}
205+
</script>

0 commit comments

Comments
 (0)