Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
e6a5bb02
authored
Dec 30, 2024
by
安浩浩
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【功能新增】IOT: 添加插件管理功能,包括插件列表、详情、状态更新及文件上传功能
parent
5d2adcac
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
239 additions
and
126 deletions
+239
-126
src/api/iot/plugininfo/index.ts
+10
-0
src/router/modules/remaining.ts
+11
-0
src/views/iot/plugin/PluginInfoForm.vue
+0
-0
src/views/iot/plugin/detail/PluginImportForm.vue
+99
-0
src/views/iot/plugin/detail/index.vue
+102
-0
src/views/iot/plugin/index.vue
+17
-82
src/views/iot/plugininfo/detail.vue
+0
-44
No files found.
src/api/iot/plugininfo/index.ts
View file @
e6a5bb02
...
@@ -47,5 +47,15 @@ export const PluginInfoApi = {
...
@@ -47,5 +47,15 @@ export const PluginInfoApi = {
// 导出IoT 插件信息 Excel
// 导出IoT 插件信息 Excel
exportPluginInfo
:
async
(
params
)
=>
{
exportPluginInfo
:
async
(
params
)
=>
{
return
await
request
.
download
({
url
:
`/iot/plugin-info/export-excel`
,
params
})
return
await
request
.
download
({
url
:
`/iot/plugin-info/export-excel`
,
params
})
},
// 修改IoT 插件状态
updatePluginStatus
:
async
(
data
:
any
)
=>
{
return
await
request
.
put
({
url
:
`/iot/plugin-info/update-status`
,
data
})
},
// 上传Jar包
uploadPluginFile
:
async
(
data
:
any
)
=>
{
return
await
request
.
post
({
url
:
`/iot/plugin-info/upload-file`
,
data
})
}
}
}
}
src/router/modules/remaining.ts
View file @
e6a5bb02
...
@@ -638,6 +638,17 @@ const remainingRouter: AppRouteRecordRaw[] = [
...
@@ -638,6 +638,17 @@ const remainingRouter: AppRouteRecordRaw[] = [
activeMenu
:
'/iot/device'
activeMenu
:
'/iot/device'
},
},
component
:
()
=>
import
(
'@/views/iot/device/device/detail/index.vue'
)
component
:
()
=>
import
(
'@/views/iot/device/device/detail/index.vue'
)
},
{
path
:
'plugin/detail/:id'
,
name
:
'IoTPluginDetail'
,
meta
:
{
title
:
'插件详情'
,
noCache
:
true
,
hidden
:
true
,
activeMenu
:
'/iot/plugin'
},
component
:
()
=>
import
(
'@/views/iot/plugin/detail/index.vue'
)
}
}
]
]
}
}
...
...
src/views/iot/plugin
info
/PluginInfoForm.vue
→
src/views/iot/plugin/PluginInfoForm.vue
View file @
e6a5bb02
File moved
src/views/iot/plugin/detail/PluginImportForm.vue
0 → 100644
View file @
e6a5bb02
<
template
>
<Dialog
v-model=
"dialogVisible"
title=
"插件导入"
width=
"400"
>
<el-upload
ref=
"uploadRef"
v-model:file-list=
"fileList"
:action=
"importUrl + '?id=' + props.id"
:auto-upload=
"false"
:disabled=
"formLoading"
:headers=
"uploadHeaders"
:limit=
"1"
:on-error=
"submitFormError"
:on-exceed=
"handleExceed"
:on-success=
"submitFormSuccess"
accept=
".jar"
drag
>
<Icon
icon=
"ep:upload"
/>
<div
class=
"el-upload__text"
>
将文件拖到此处,或
<em>
点击上传
</em></div>
</el-upload>
<template
#
footer
>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
{
getAccessToken
,
getTenantId
}
from
'@/utils/auth'
defineOptions
({
name
:
'PluginImportForm'
})
const
props
=
defineProps
<
{
id
:
number
}
>
()
// 接收 id 作为 props
const
message
=
useMessage
()
// 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
formLoading
=
ref
(
false
)
// 表单的加载中
const
uploadRef
=
ref
()
const
importUrl
=
import
.
meta
.
env
.
VITE_BASE_URL
+
import
.
meta
.
env
.
VITE_API_URL
+
'/iot/plugin-info/upload-file'
const
uploadHeaders
=
ref
()
// 上传 Header 头
const
fileList
=
ref
([])
// 文件列表
/** 打开弹窗 */
const
open
=
()
=>
{
dialogVisible
.
value
=
true
fileList
.
value
=
[]
resetForm
()
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
const
submitForm
=
async
()
=>
{
if
(
fileList
.
value
.
length
==
0
)
{
message
.
error
(
'请上传文件'
)
return
}
// 提交请求
uploadHeaders
.
value
=
{
Authorization
:
'Bearer '
+
getAccessToken
(),
'tenant-id'
:
getTenantId
()
}
formLoading
.
value
=
true
uploadRef
.
value
!
.
submit
()
}
/** 文件上传成功 */
const
emits
=
defineEmits
([
'success'
])
const
submitFormSuccess
=
(
response
:
any
)
=>
{
if
(
response
.
code
!==
0
)
{
message
.
error
(
response
.
msg
)
formLoading
.
value
=
false
return
}
message
.
alert
(
'上传成功'
)
formLoading
.
value
=
false
dialogVisible
.
value
=
false
// 发送操作成功的事件
emits
(
'success'
)
}
/** 上传错误提示 */
const
submitFormError
=
():
void
=>
{
message
.
error
(
'上传失败,请您重新上传!'
)
formLoading
.
value
=
false
}
/** 重置表单 */
const
resetForm
=
async
():
Promise
<
void
>
=>
{
// 重置上传状态和文件
formLoading
.
value
=
false
await
nextTick
()
uploadRef
.
value
?.
clearFiles
()
}
/** 文件数超出提示 */
const
handleExceed
=
():
void
=>
{
message
.
error
(
'最多只能上传一个文件!'
)
}
</
script
>
src/views/iot/plugin/detail/index.vue
0 → 100644
View file @
e6a5bb02
<
template
>
<div>
<div
class=
"flex items-start justify-between"
>
<div>
<el-col>
<el-row>
<span
class=
"text-xl font-bold"
>
插件详情
</span>
</el-row>
</el-col>
</div>
</div>
<ContentWrap
class=
"mt-10px"
>
<el-descriptions
:column=
"2"
direction=
"horizontal"
>
<el-descriptions-item
label=
"插件名称"
>
{{
pluginInfo
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"插件ID"
>
{{
pluginInfo
.
pluginId
}}
</el-descriptions-item>
<el-descriptions-item
label=
"版本号"
>
{{
pluginInfo
.
version
}}
</el-descriptions-item>
<el-descriptions-item
label=
"状态"
>
<el-switch
v-model=
"pluginInfo.status"
:active-value=
"1"
:inactive-value=
"0"
@
change=
"handleStatusChange"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"插件描述"
>
{{
pluginInfo
.
description
}}
</el-descriptions-item>
</el-descriptions>
</ContentWrap>
<ContentWrap
class=
"mt-10px"
>
<el-button
type=
"warning"
plain
@
click=
"handleImport"
v-hasPermi=
"['system:user:import']"
>
<Icon
icon=
"ep:upload"
/>
上传插件包
</el-button>
</ContentWrap>
</div>
<!-- 插件导入对话框 -->
<PluginImportForm
ref=
"importFormRef"
:id=
"Number(pluginInfo.id)"
@
success=
"getPluginInfo(Number(pluginInfo.id))"
/>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
PluginInfoApi
,
PluginInfoVO
}
from
'@/api/iot/plugininfo'
import
{
useRoute
}
from
'vue-router'
import
{
ref
,
onMounted
}
from
'vue'
import
PluginImportForm
from
'./PluginImportForm.vue'
const
message
=
useMessage
()
const
route
=
useRoute
()
const
pluginInfo
=
ref
<
PluginInfoVO
>
({})
const
isInitialLoad
=
ref
(
true
)
// 初始化标志位
onMounted
(()
=>
{
const
id
=
Number
(
route
.
params
.
id
)
if
(
id
)
{
getPluginInfo
(
id
).
then
(()
=>
{
isInitialLoad
.
value
=
false
// 数据加载完成后,设置标志位为 false
})
}
})
const
getPluginInfo
=
async
(
id
:
number
)
=>
{
const
data
=
await
PluginInfoApi
.
getPluginInfo
(
id
)
pluginInfo
.
value
=
data
}
/** 处理状态变更 */
const
handleStatusChange
=
async
(
status
:
number
)
=>
{
if
(
isInitialLoad
.
value
)
{
return
}
try
{
// 修改状态的二次确认
const
text
=
status
===
1
?
'启用'
:
'停用'
await
message
.
confirm
(
'确认要"'
+
text
+
'"插件吗?'
)
await
PluginInfoApi
.
updatePluginStatus
({
id
:
pluginInfo
.
value
.
id
,
status
})
message
.
success
(
'更新状态成功'
)
getPluginInfo
(
Number
(
pluginInfo
.
value
.
id
))
}
catch
(
error
)
{
pluginInfo
.
value
.
status
=
status
===
1
?
0
:
1
message
.
error
(
'更新状态失败'
)
}
}
/** 插件导入 */
const
importFormRef
=
ref
()
const
handleImport
=
()
=>
{
importFormRef
.
value
.
open
()
}
</
script
>
\ No newline at end of file
src/views/iot/plugin
info
/index.vue
→
src/views/iot/plugin/index.vue
View file @
e6a5bb02
...
@@ -45,25 +45,11 @@
...
@@ -45,25 +45,11 @@
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
</el-button>
</el-form-item>
</el-form-item>
<!-- 视图切换按钮 -->
<el-form-item
class=
"float-right !mr-0 !mb-0"
>
<el-button-group>
<el-button
:type=
"viewType === 'card' ? 'primary' : 'default'"
@
click=
"viewType = 'card'"
>
<Icon
icon=
"ep:grid"
/>
</el-button>
<el-button
:type=
"viewType === 'table' ? 'primary' : 'default'"
@
click=
"viewType = 'table'"
>
<Icon
icon=
"ep:list"
/>
</el-button>
</el-button-group>
</el-form-item>
</el-form>
</el-form>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
<ContentWrap
v-if=
"viewType === 'table'"
>
<ContentWrap>
<el-table
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
>
<el-table
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
>
<el-table-column
label=
"插件名称"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"插件名称"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"组件id"
align=
"center"
prop=
"pluginId"
/>
<el-table-column
label=
"组件id"
align=
"center"
prop=
"pluginId"
/>
...
@@ -91,65 +77,15 @@
...
@@ -91,65 +77,15 @@
<el-button
<el-button
link
link
type=
"primary"
type=
"primary"
@
click=
"openForm('update', scope.row.id)"
@
click=
"openDetail(scope.row.id)"
v-hasPermi=
"['iot:plugin-info:update']"
v-hasPermi=
"['iot:product:query']"
>
编辑
</el-button>
<el-button
link
type=
"danger"
@
click=
"handleDelete(scope.row.id)"
v-hasPermi=
"['iot:plugin-info:delete']"
>
删除
</el-button>
<el-button
link
type=
"info"
@
click=
"viewDetail(scope.row.id)"
>
>
详情
查看
</el-button>
</el-button>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total=
"total"
v-model:page=
"queryParams.pageNo"
v-model:limit=
"queryParams.pageSize"
@
pagination=
"getList"
/>
</ContentWrap>
<!-- 卡片视图 -->
<ContentWrap
v-else
>
<div
class=
"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"
>
<el-card
v-for=
"item in list"
:key=
"item.pluginId"
class=
"cursor-pointer hover:shadow-lg transition-shadow"
>
<div
class=
"flex items-center mb-4"
>
<div
class=
"flex-1"
>
<div
class=
"font-bold text-lg"
>
{{ item.name }}
</div>
<div
class=
"text-gray-500 text-sm"
>
组件ID: {{ item.pluginId }}
</div>
</div>
</div>
<div
class=
"text-sm text-gray-500"
>
<div>
Jar包: {{ item.file }}
</div>
<div>
版本号: {{ item.version }}
</div>
<div
>
部署方式:
<dict-tag
:type=
"DICT_TYPE.IOT_PLUGIN_DEPLOY_TYPE"
:value=
"item.deployType"
/></div>
<div>
状态:
<dict-tag
:type=
"DICT_TYPE.IOT_PLUGIN_STATUS"
:value=
"item.status"
/></div>
</div>
<div
class=
"flex justify-end mt-4"
>
<el-button
<el-button
link
link
type=
"primary"
type=
"primary"
@
click
.
stop=
"openForm('update', item
.id)"
@
click
=
"openForm('update', scope.row
.id)"
v-hasPermi=
"['iot:plugin-info:update']"
v-hasPermi=
"['iot:plugin-info:update']"
>
>
编辑
编辑
...
@@ -157,14 +93,14 @@
...
@@ -157,14 +93,14 @@
<el-button
<el-button
link
link
type=
"danger"
type=
"danger"
@
click
.
stop=
"handleDelete(item
.id)"
@
click
=
"handleDelete(scope.row
.id)"
v-hasPermi=
"['iot:plugin-info:delete']"
v-hasPermi=
"['iot:plugin-info:delete']"
>
>
删除
删除
</el-button>
</el-button>
</
div
>
</
template
>
</el-
card
>
</el-
table-column
>
</
div
>
</
el-table
>
<!-- 分页 -->
<!-- 分页 -->
<Pagination
<Pagination
:total=
"total"
:total=
"total"
...
@@ -185,7 +121,7 @@ import { PluginInfoApi, PluginInfoVO } from '@/api/iot/plugininfo'
...
@@ -185,7 +121,7 @@ import { PluginInfoApi, PluginInfoVO } from '@/api/iot/plugininfo'
import
PluginInfoForm
from
'./PluginInfoForm.vue'
import
PluginInfoForm
from
'./PluginInfoForm.vue'
/** IoT 插件信息 列表 */
/** IoT 插件信息 列表 */
defineOptions
({
name
:
'
PluginInfo
'
})
defineOptions
({
name
:
'
IoTPlugin
'
})
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
{
t
}
=
useI18n
()
// 国际化
const
{
t
}
=
useI18n
()
// 国际化
...
@@ -200,7 +136,6 @@ const queryParams = reactive({
...
@@ -200,7 +136,6 @@ const queryParams = reactive({
status
:
undefined
status
:
undefined
})
})
const
queryFormRef
=
ref
()
// 搜索的表单
const
queryFormRef
=
ref
()
// 搜索的表单
const
viewType
=
ref
<
'card'
|
'table'
>
(
'table'
)
// 视图类型,默认为表格视图
/** 查询列表 */
/** 查询列表 */
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
...
@@ -232,6 +167,12 @@ const openForm = (type: string, id?: number) => {
...
@@ -232,6 +167,12 @@ const openForm = (type: string, id?: number) => {
formRef
.
value
.
open
(
type
,
id
)
formRef
.
value
.
open
(
type
,
id
)
}
}
/** 打开详情 */
const
{
push
}
=
useRouter
()
const
openDetail
=
(
id
:
number
)
=>
{
push
({
name
:
'IoTPluginDetail'
,
params
:
{
id
}
})
}
/** 删除按钮操作 */
/** 删除按钮操作 */
const
handleDelete
=
async
(
id
:
number
)
=>
{
const
handleDelete
=
async
(
id
:
number
)
=>
{
try
{
try
{
...
@@ -245,13 +186,8 @@ const handleDelete = async (id: number) => {
...
@@ -245,13 +186,8 @@ const handleDelete = async (id: number) => {
}
catch
{}
}
catch
{}
}
}
/** 查看详情操作 */
const
viewDetail
=
(
id
:
number
)
=>
{
router
.
push
({
path
:
`/iot/plugininfo/detail/
${
id
}
`
})
}
/** 初始化 **/
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
getList
()
getList
()
})
})
</
script
>
</
script
>
\ No newline at end of file
src/views/iot/plugininfo/detail.vue
deleted
100644 → 0
View file @
5d2adcac
<
template
>
<ContentWrap>
<el-descriptions
title=
"插件详情"
:column=
"2"
border
>
<el-descriptions-item
label=
"插件名称"
>
{{
pluginInfo
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"组件ID"
>
{{
pluginInfo
.
pluginId
}}
</el-descriptions-item>
<el-descriptions-item
label=
"Jar包"
>
{{
pluginInfo
.
file
}}
</el-descriptions-item>
<el-descriptions-item
label=
"版本号"
>
{{
pluginInfo
.
version
}}
</el-descriptions-item>
<el-descriptions-item
label=
"部署方式"
>
<dict-tag
:type=
"DICT_TYPE.IOT_PLUGIN_DEPLOY_TYPE"
:value=
"pluginInfo.deployType"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"状态"
>
<dict-tag
:type=
"DICT_TYPE.IOT_PLUGIN_STATUS"
:value=
"pluginInfo.status"
/>
</el-descriptions-item>
</el-descriptions>
<el-button
type=
"primary"
@
click=
"goBack"
>
返回
</el-button>
</ContentWrap>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
PluginInfoApi
,
PluginInfoVO
}
from
'@/api/iot/plugininfo'
import
{
useRoute
,
useRouter
}
from
'vue-router'
const
route
=
useRoute
()
const
router
=
useRouter
()
const
pluginInfo
=
ref
<
PluginInfoVO
>
({})
const
getPluginInfo
=
async
(
id
:
number
)
=>
{
const
data
=
await
PluginInfoApi
.
getPluginInfo
(
id
)
pluginInfo
.
value
=
data
}
const
goBack
=
()
=>
{
router
.
back
()
}
onMounted
(()
=>
{
const
id
=
Number
(
route
.
params
.
id
)
if
(
id
)
{
getPluginInfo
(
id
)
}
})
</
script
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment