parent
47f9230ab1
commit
8dffb3fe8f
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,385 @@ |
||||
<template> |
||||
<div class="app-container"> |
||||
<el-card shadow="never"> |
||||
<template #header> |
||||
<div class="flex justify-between"> |
||||
<div style="display: flex; align-items: center"> |
||||
<el-icon><Grid /></el-icon> <span |
||||
style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||
>设备参数树</span |
||||
> |
||||
</div> |
||||
<div style="display: flex; align-items: center" v-if="loading"> |
||||
<div class="rotate mr-0.5"> |
||||
<el-icon><Loading /></el-icon> |
||||
</div> |
||||
<span style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||
>正在加载,请稍后...</span |
||||
> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<el-scrollbar max-height="300"> |
||||
<el-tree |
||||
ref="deviceTreeRef" |
||||
:highlight-current="true" |
||||
:data="treeList" |
||||
:props="{ |
||||
children: 'children', |
||||
label: 'label', |
||||
}" |
||||
:expand-on-click-node="false" |
||||
default-expand-all |
||||
> |
||||
<template #default="{ node, data }"> |
||||
<div class="custom-tree-node"> |
||||
<div style="display: flex; justify-content: flex-start"> |
||||
<div v-if="data.childNode === true"> |
||||
<div style="margin-top: 1px" @click="handleNodeClick(data)"> |
||||
<svg-icon class="mr-5px" size="15" icon-class="folder" /> |
||||
</div> |
||||
</div> |
||||
<div v-else> |
||||
<div style="margin-top: 1px"> |
||||
<svg-icon class="mr-5px" size="15" icon-class="file" /> |
||||
</div> |
||||
</div> |
||||
<div @click="changeCurrentTree(data)">{{ node.label }}</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
</el-tree> |
||||
</el-scrollbar> |
||||
</el-card> |
||||
<el-card shadow="never" class="mt-1"> |
||||
<template #header> |
||||
<div style="display: flex; align-items: center"> |
||||
<el-icon><Grid /></el-icon> <span |
||||
style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||
>设备操作</span |
||||
> |
||||
</div> |
||||
</template> |
||||
<div v-if="currentTree.childNode === false"> |
||||
<el-form :model="currentTree" v-loading="loading"> |
||||
<el-descriptions :column="1" border> |
||||
<el-descriptions-item |
||||
label="参数名称" |
||||
label-align="left" |
||||
align="left" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
{{ currentTree?.nodePath }} |
||||
</el-descriptions-item> |
||||
<el-descriptions-item |
||||
label="参数值" |
||||
label-align="left" |
||||
align="center" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
<el-form-item> |
||||
<el-input v-model="currentTree.value" /> |
||||
</el-form-item> |
||||
</el-descriptions-item> |
||||
</el-descriptions> |
||||
</el-form> |
||||
</div> |
||||
|
||||
<div v-else> |
||||
<el-descriptions :column="1" border> |
||||
<el-descriptions-item |
||||
label="路径" |
||||
label-align="center" |
||||
align="left" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
{{ currentTree?.nodePath }} |
||||
</el-descriptions-item> |
||||
</el-descriptions> |
||||
</div> |
||||
<template #footer> |
||||
<div class="flex-center"> |
||||
<div v-if="!currentTree.childNode"> |
||||
<el-button type="primary" @click="saveParam">保存参数</el-button> |
||||
<el-button type="primary" @click="openParamAttribute" |
||||
>参数属性</el-button |
||||
> |
||||
</div> |
||||
<div v-else> |
||||
<div v-if="currentTree.label != 'InternetGatewayDevice'"> |
||||
<el-button type="primary" @click="addInstanceNode" |
||||
>新增实例</el-button |
||||
> |
||||
<el-button type="primary" @click="deleteInstanceNode" |
||||
>删除实例</el-button |
||||
> |
||||
</div> |
||||
</div> |
||||
<div class="ml-2"> |
||||
<el-button type="danger" plain @click="reboot">远程重启</el-button> |
||||
<el-button type="danger" plain @click="factoryReset" |
||||
>恢复出厂</el-button |
||||
> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
</el-card> |
||||
<tree-param-attribute ref="treeParamAttributeRef" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { Grid, Loading } from "@element-plus/icons-vue"; |
||||
import { OptionTree } from "@/api/remote/types"; |
||||
import { |
||||
remoteAddInstanceNode, |
||||
remoteDeleteInstanceNode, |
||||
remoteFactoryReset, |
||||
remoteGetParameterValues, |
||||
remoteReboot, |
||||
remoteSetParameterValues, |
||||
remoteTreeNode, |
||||
} from "@/api/remote"; |
||||
import { confirm } from "@/utils/confirm"; |
||||
import TreeParamAttribute from "@/views/family/operate/remote-operation/components/TreeParamAttribute.vue"; |
||||
|
||||
const route = useRoute(); |
||||
let devId: number = parseInt(<string>route.params.devId); |
||||
const treeParamAttributeRef = ref(); |
||||
const deviceTreeRef = ref(); |
||||
const loading = ref<boolean>(false); |
||||
const treeList = ref<OptionTree[]>([ |
||||
{ |
||||
label: "InternetGatewayDevice", |
||||
nodePath: "InternetGatewayDevice.", |
||||
childNode: true, |
||||
children: [], |
||||
}, |
||||
]); |
||||
const currentTree = ref<OptionTree>({ |
||||
label: "InternetGatewayDevice", |
||||
nodePath: "InternetGatewayDevice.", |
||||
childNode: true, |
||||
children: [], |
||||
}); |
||||
const handleNodeClick = (data_: OptionTree) => { |
||||
loading.value = true; |
||||
let nodePath = data_.nodePath; |
||||
remoteTreeNode(devId, nodePath) |
||||
.then(({ data }) => { |
||||
if (!data_.children) { |
||||
data_.children = []; |
||||
} |
||||
data_.children = data; |
||||
treeList.value = [...treeList.value]; |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}; |
||||
|
||||
const changeCurrentTree = (data: OptionTree) => { |
||||
currentTree.value = data; |
||||
if (data.childNode) { |
||||
return; |
||||
} |
||||
let nodePath = data.nodePath; |
||||
loading.value = true; |
||||
remoteGetParameterValues(devId, nodePath) |
||||
.then(({ data }) => { |
||||
currentTree.value.value = data.value; |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}; |
||||
const saveParam = () => { |
||||
confirm("确定保存该节点参数", () => { |
||||
loading.value = true; |
||||
remoteSetParameterValues( |
||||
devId, |
||||
currentTree.value.nodePath, |
||||
<string>currentTree.value.value |
||||
) |
||||
.then(() => { |
||||
ElMessage({ |
||||
message: "操作成功", |
||||
duration: 1000, |
||||
type: "success", |
||||
}); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
const openParamAttribute = () => { |
||||
treeParamAttributeRef.value.open(devId, currentTree.value.nodePath); |
||||
}; |
||||
const childNode = ref<OptionTree>({}); |
||||
const addInstanceNode = () => { |
||||
confirm("确定添加实例吗", () => { |
||||
loading.value = true; |
||||
remoteAddInstanceNode(devId, currentTree.value.nodePath) |
||||
.then(({ data }) => { |
||||
childNode.value = data; |
||||
addInstanceNode_(treeList.value[0], currentTree.value.nodePath); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
const deleteInstanceNode = () => { |
||||
confirm(`确定删除${currentTree.value.label}实例吗`, () => { |
||||
loading.value = true; |
||||
remoteDeleteInstanceNode(devId, currentTree.value.nodePath) |
||||
.then(() => { |
||||
removeInstanceNode_(treeList.value[0], currentTree.value.nodePath); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
// 查找节点函数 |
||||
const addInstanceNode_ = (tree: OptionTree, nodePath?: string) => { |
||||
// 如果当前节点的 nodePath 匹配,返回当前节点 |
||||
if (tree.nodePath === nodePath) { |
||||
if (!tree.children) { |
||||
tree.children = []; |
||||
} |
||||
tree.children?.push(childNode.value); |
||||
console.log(treeList.value[0]); |
||||
return; |
||||
} |
||||
// 如果当前节点有子节点,则递归查找子节点 |
||||
if (tree.children) { |
||||
for (const child of tree.children) { |
||||
const result = addInstanceNode_(child, nodePath); |
||||
if (result) { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
// 如果未找到匹配节点,返回 undefined |
||||
return undefined; |
||||
}; |
||||
const removeInstanceNode_ = (tree: OptionTree, nodePath?: string) => { |
||||
if (!tree.children) return false; |
||||
|
||||
for (let i = 0; i < tree.children.length; i++) { |
||||
const child = tree.children[i]; |
||||
if (child.nodePath === nodePath) { |
||||
// 找到并删除节点 |
||||
tree.children.splice(i, 1); |
||||
return true; |
||||
} |
||||
// 递归删除子节点 |
||||
const result = removeInstanceNode_(child, nodePath); |
||||
if (result) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
}; |
||||
const reboot = () => { |
||||
confirm("确认重启设备吗", () => { |
||||
loading.value = true; |
||||
remoteReboot(devId) |
||||
.then(() => { |
||||
ElMessage({ |
||||
message: "操作成功", |
||||
duration: 1000, |
||||
type: "success", |
||||
}); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
const factoryReset = () => { |
||||
confirm("确认恢复出厂设置吗", () => { |
||||
loading.value = true; |
||||
remoteFactoryReset(devId) |
||||
.then(() => { |
||||
ElMessage({ |
||||
message: "操作成功", |
||||
duration: 1000, |
||||
type: "success", |
||||
}); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
:deep(.el-card__body) { |
||||
padding: 10px 0; |
||||
} |
||||
:deep(.my-label) { |
||||
width: 50px !important; |
||||
text-align: center !important; |
||||
background: var(--el-color-white) !important; |
||||
} |
||||
.rotate { |
||||
animation: rotate 10s linear infinite; |
||||
-webkit-animation: rotate 10s linear infinite; |
||||
} |
||||
@keyframes rotate { |
||||
0% { |
||||
transform: rotate(0); |
||||
} |
||||
|
||||
25% { |
||||
transform: rotate(90deg); |
||||
} |
||||
|
||||
50% { |
||||
transform: rotate(180deg); |
||||
} |
||||
|
||||
75% { |
||||
transform: rotate(270deg); |
||||
} |
||||
|
||||
100% { |
||||
transform: rotate(360deg); |
||||
} |
||||
} |
||||
|
||||
@-webkit-keyframes rotate { |
||||
0% { |
||||
transform: rotate(0); |
||||
} |
||||
|
||||
25% { |
||||
transform: rotate(90deg); |
||||
} |
||||
|
||||
50% { |
||||
transform: rotate(180deg); |
||||
} |
||||
|
||||
75% { |
||||
transform: rotate(270deg); |
||||
} |
||||
|
||||
100% { |
||||
transform: rotate(360deg); |
||||
} |
||||
} |
||||
:deep(.el-form-item--default) { |
||||
margin-bottom: 0; |
||||
} |
||||
</style> |
@ -0,0 +1,165 @@ |
||||
<template> |
||||
<el-dialog class="com-dialog" v-model="openFlag" title="修改参数属性"> |
||||
<el-form :model="formData" v-loading="loading"> |
||||
<el-descriptions :column="1" border> |
||||
<el-descriptions-item |
||||
label="参数名称" |
||||
label-align="center" |
||||
align="left" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
InternetGatewayDevice.DeviceSummary |
||||
</el-descriptions-item> |
||||
<el-descriptions-item |
||||
label="NotificationChange" |
||||
label-align="center" |
||||
align="left" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
<div class="flex justify-between"> |
||||
<el-form-item> |
||||
<el-checkbox-group v-model="formData.notification"> |
||||
<el-checkbox value="true">Notification</el-checkbox> |
||||
</el-checkbox-group> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-radio-group |
||||
v-model="formData.param1" |
||||
:disabled="formData.notification?.length != 1" |
||||
> |
||||
<el-radio value="0">OFF</el-radio> |
||||
<el-radio value="1">PASSIVE</el-radio> |
||||
<el-radio value="2">ACTIVE</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
</div> |
||||
</el-descriptions-item> |
||||
<el-descriptions-item |
||||
label="AccessListChange" |
||||
label-align="center" |
||||
align="left" |
||||
label-class-name="my-label" |
||||
class-name="my-content" |
||||
width="15px" |
||||
> |
||||
<div class="flex justify-between"> |
||||
<el-form-item> |
||||
<el-checkbox-group v-model="formData.accessList"> |
||||
<el-checkbox value="true">AccessList</el-checkbox> |
||||
</el-checkbox-group> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-checkbox-group |
||||
v-model="formData.param2" |
||||
:disabled="formData.accessList?.length != 1" |
||||
> |
||||
<el-checkbox value="Subscriber">Subscriber</el-checkbox> |
||||
<el-checkbox value="customAttribute" |
||||
><el-input v-model="customAttribute" style="width: 130px" |
||||
/></el-checkbox> |
||||
</el-checkbox-group> |
||||
</el-form-item> |
||||
</div> |
||||
</el-descriptions-item> |
||||
</el-descriptions> |
||||
</el-form> |
||||
<template #footer> |
||||
<el-button type="primary" @click="submitForm">确定</el-button> |
||||
<el-button @click="openFlag = false">取消</el-button> |
||||
</template> |
||||
</el-dialog> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { |
||||
remoteGetParameterAttributes, |
||||
remoteSetParameterAttributes, |
||||
} from "@/api/remote"; |
||||
import { confirm } from "@/utils/confirm"; |
||||
|
||||
interface ParamAttribute { |
||||
accessList?: string[]; |
||||
notification?: string[]; |
||||
param1?: string; |
||||
param2?: string[]; |
||||
} |
||||
const devId = ref<number>(0); |
||||
const nodePath = ref<string>(""); |
||||
const loading = ref<boolean>(false); |
||||
const openFlag = ref<boolean>(false); |
||||
const formData = ref<ParamAttribute>({}); |
||||
const customAttribute = ref<string>(""); |
||||
const open = (devId_: number, nodePath_: string) => { |
||||
formData.value = { |
||||
accessList: [], |
||||
notification: [], |
||||
}; |
||||
devId.value = devId_; |
||||
nodePath.value = nodePath_; |
||||
getData(devId_, nodePath_); |
||||
openFlag.value = true; |
||||
}; |
||||
const getData = (devId?: number, nodePath?: string) => { |
||||
loading.value = true; |
||||
remoteGetParameterAttributes(devId, nodePath) |
||||
.then(({ data }) => { |
||||
let value_: string = <string>data.value; |
||||
let attributes = value_.split("|"); |
||||
formData.value.param1 = attributes[0]; |
||||
formData.value.param2 = [attributes[1]]; |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}; |
||||
defineExpose({ open }); |
||||
const submitForm = () => { |
||||
confirm("确定修改参数属性吗", () => { |
||||
let argValue = []; |
||||
if (formData.value.notification?.length === 1) { |
||||
argValue.push("true"); |
||||
} else { |
||||
argValue.push("false"); |
||||
} |
||||
argValue.push(formData.value.param1); |
||||
if (formData.value.accessList?.length === 1) { |
||||
argValue.push("true"); |
||||
} else { |
||||
argValue.push("false"); |
||||
} |
||||
if (formData.value.param2?.length === 1) { |
||||
argValue.push(formData.value.param2[0]); |
||||
} else if (formData.value.param2?.length === 2) { |
||||
argValue.push(formData.value.param2[0] + "~" + customAttribute.value); |
||||
} |
||||
loading.value = true; |
||||
remoteSetParameterAttributes( |
||||
devId.value, |
||||
nodePath.value, |
||||
argValue.join("|") |
||||
) |
||||
.then(() => { |
||||
ElMessage({ |
||||
message: "操作成功", |
||||
duration: 1000, |
||||
type: "success", |
||||
}); |
||||
}) |
||||
.finally(() => { |
||||
loading.value = false; |
||||
}); |
||||
}); |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
:deep(.my-label) { |
||||
width: 50px !important; |
||||
text-align: center !important; |
||||
background: var(--el-color-white) !important; |
||||
} |
||||
</style> |
Loading…
Reference in new issue