feat:修改绑定相机
This commit is contained in:
1 parent
b1397a182e
commit
2cb3da7f83
7 files changed
+252
-11
No files matched your search
@@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<!-- @visible-change="(e: boolean) => e && getOptions()" -->
|
||||
<el-tree-select class="stafftree" :props="{
|
||||
label: 'treeLabel',
|
||||
children: 'deviceChannelList',
|
||||
}" node-key="treeValue" v-model="state.selectId" :placeholder="props.placeholder" :clearable="props.clearable"
|
||||
:loading="state.loading" :data="state.options" :render-after-expand="false" show-checkbox multiple
|
||||
style="width: 100%" filterable default-expand-all />
|
||||
style="width: 100%" filterable default-expand-all @visible-change="(e: boolean) => e && getOptions()" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="select-tree-channel">
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<el-tree-select class="radio-tree-select" :props="{
|
||||
label: 'treeLabel',
|
||||
children: 'deviceChannelList',
|
||||
}" node-key="treeValue" v-model="state.selectId" :placeholder="props.placeholder" :clearable="props.clearable"
|
||||
:disabled="props.disabled" :loading="state.loading" :data="state.options" :render-after-expand="false"
|
||||
style="width: 100%" filterable default-expand-all @node-click="handleNodeClick" @clear="handleClear"
|
||||
@visible-change="(e: boolean) => e && getOptions()" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="select-tree-channel-radio">
|
||||
import * as DeviceManageApi from '/@/api/device/deviceManage'
|
||||
|
||||
const emit = defineEmits(["change"])
|
||||
|
||||
const selectId = defineModel()
|
||||
|
||||
type Props = {
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
clearable?: boolean
|
||||
autoFirst?: boolean
|
||||
apiParams?: any
|
||||
/** 是否只允许选择叶子节点 */
|
||||
checkStrictly?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<Props>(),
|
||||
{
|
||||
placeholder: "请选择设备通道",
|
||||
disabled: false,
|
||||
clearable: true,
|
||||
autoFirst: false,
|
||||
apiParams: {},
|
||||
checkStrictly: false,
|
||||
},
|
||||
)
|
||||
|
||||
const queryForm = reactive<any>({
|
||||
name: "",
|
||||
})
|
||||
|
||||
const state = reactive<any>({
|
||||
loading: true,
|
||||
selectId: selectId,
|
||||
options: [],
|
||||
})
|
||||
|
||||
// 监听外部传入的 selectId 变化
|
||||
watch(
|
||||
selectId,
|
||||
(newVal, oldValue) => {
|
||||
if (newVal === oldValue) return
|
||||
state.selectId = newVal
|
||||
if (!state.options.length) {
|
||||
getOptions()
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 监听内部 selectId 变化,同步到外部
|
||||
watch(
|
||||
() => state.selectId,
|
||||
(newVal) => {
|
||||
if (newVal !== selectId.value) {
|
||||
selectId.value = newVal
|
||||
emit("change", newVal)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 处理节点点击事件
|
||||
const handleNodeClick = (data: any, node: any) => {
|
||||
// 如果设置了 checkStrictly,只允许选择叶子节点
|
||||
if (props.checkStrictly && node.childNodes && node.childNodes.length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// 单选模式,直接设置选中的值
|
||||
state.selectId = data.treeValue
|
||||
}
|
||||
|
||||
// 处理清空事件
|
||||
const handleClear = () => {
|
||||
state.selectId = null
|
||||
}
|
||||
|
||||
// 获取选项数据
|
||||
async function getOptions() {
|
||||
try {
|
||||
state.loading = true
|
||||
const _pa = {
|
||||
...queryForm,
|
||||
...props.apiParams,
|
||||
}
|
||||
const { data } = await DeviceManageApi.channelTree(_pa)
|
||||
state.options = data ?? []
|
||||
|
||||
// 如果设置了 autoFirst 且有数据,自动选择第一个
|
||||
if (props.autoFirst && state.options.length > 0) {
|
||||
const firstSelectableNode = findFirstSelectableNode(state.options)
|
||||
if (firstSelectableNode) {
|
||||
state.selectId = firstSelectableNode.treeValue
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取设备通道树数据失败:', error)
|
||||
state.options = []
|
||||
} finally {
|
||||
setTimeout(() => (state.loading = false), 500)
|
||||
}
|
||||
}
|
||||
|
||||
// 查找第一个可选择的节点(如果设置了 checkStrictly,则查找第一个叶子节点)
|
||||
const findFirstSelectableNode = (nodes: any[]): any => {
|
||||
for (const node of nodes) {
|
||||
if (props.checkStrictly) {
|
||||
// 只选择叶子节点
|
||||
if (!node.deviceChannelList || node.deviceChannelList.length === 0) {
|
||||
return node
|
||||
}
|
||||
// 递归查找子节点
|
||||
if (node.deviceChannelList && node.deviceChannelList.length > 0) {
|
||||
const childResult = findFirstSelectableNode(node.deviceChannelList)
|
||||
if (childResult) return childResult
|
||||
}
|
||||
} else {
|
||||
// 可以选择任意节点
|
||||
return node
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 获取当前选中的节点信息
|
||||
const getSelectedNode = () => {
|
||||
if (!state.selectId) return null
|
||||
|
||||
const findNode = (nodes: any[], targetValue: any): any => {
|
||||
for (const node of nodes) {
|
||||
if (node.treeValue === targetValue) {
|
||||
return node
|
||||
}
|
||||
if (node.deviceChannelList && node.deviceChannelList.length > 0) {
|
||||
const childResult = findNode(node.deviceChannelList, targetValue)
|
||||
if (childResult) return childResult
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return findNode(state.options, state.selectId)
|
||||
}
|
||||
|
||||
// 暴露方法给父组件使用
|
||||
defineExpose({
|
||||
getSelectedNode,
|
||||
refresh: getOptions,
|
||||
clearSelection: handleClear
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.radio-tree-select {
|
||||
.el-tree-select__tags {
|
||||
|
||||
// 单选模式下隐藏多选标签样式
|
||||
.el-tag {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏复选框,因为我们使用单选模式
|
||||
.el-tree-node__content .el-checkbox {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 添加单选样式指示
|
||||
.el-tree-node__content {
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-tree-node-hover-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
// 选中状态样式
|
||||
.el-tree-node.is-current>.el-tree-node__content {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -26,6 +26,7 @@ import SelectArea from "/@/components/Select/SelectArea.vue"
|
||||
import SelectDevice from "/@/components/Select/SelectDevice.vue"
|
||||
import SelectDutyType from "/@/components/Select/SelectDutyType.vue"
|
||||
import SelectTreeChannel from "/@/components/Select/SelectTreeChannel.vue"
|
||||
import SelectTreeChannelRadio from "/@/components/Select/SelectTreeChannelRadio.vue"
|
||||
|
||||
import ColumnBtn from "/@/components/Column/ColumnBtn.vue"
|
||||
|
||||
@@ -82,6 +83,7 @@ export default {
|
||||
app.component('SelectDevice', SelectDevice);
|
||||
app.component('SelectDutyType', SelectDutyType);
|
||||
app.component('SelectTreeChannel', SelectTreeChannel);
|
||||
app.component('SelectTreeChannelRadio', SelectTreeChannelRadio);
|
||||
|
||||
app.component('ColumnBtn', ColumnBtn);
|
||||
|
||||
|
||||
Reference in new issue
Block a user