tplink摄像头区域信息优化
This commit is contained in:
parent
d65bb8248c
commit
090e633030
|
@ -14,8 +14,17 @@ enum Api {
|
|||
getDictItems = '/sys/dict/getDictItems/',
|
||||
getTableList = '/sys/user/queryUserComponentData',
|
||||
getCategoryData = '/sys/category/loadAllData',
|
||||
getNuList = '/iot/cameraInfo/nuList',//后期调整
|
||||
}
|
||||
|
||||
/**
|
||||
* 护理单元列表
|
||||
* @param params
|
||||
*/
|
||||
export const getNuList = (params) => {
|
||||
return defHttp.get({ url: Api.getNuList, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传父路径
|
||||
*/
|
||||
|
|
|
@ -45,6 +45,7 @@ import JImageUpload from './jeecg/components/JImageUpload.vue';
|
|||
import JDictSelectTag from './jeecg/components/JDictSelectTag.vue';
|
||||
import JSelectDept from './jeecg/components/JSelectDept.vue';
|
||||
import JAreaSelect from './jeecg/components/JAreaSelect.vue';
|
||||
import JSelectNu from './jeecg/components/JSelectNu.vue';
|
||||
import JEditor from './jeecg/components/JEditor.vue';
|
||||
// import JMarkdownEditor from './jeecg/components/JMarkdownEditor.vue';
|
||||
import JSelectInput from './jeecg/components/JSelectInput.vue';
|
||||
|
@ -127,6 +128,7 @@ componentMap.set('JImageUpload', JImageUpload);
|
|||
componentMap.set('JDictSelectTag', JDictSelectTag);
|
||||
componentMap.set('JSelectDept', JSelectDept);
|
||||
componentMap.set('JAreaSelect', JAreaSelect);
|
||||
componentMap.set('JSelectNu', JSelectNu);
|
||||
// componentMap.set(
|
||||
// 'JEditor',
|
||||
// createAsyncComponent(() => import('./jeecg/components/JEditor.vue'))
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
<!--职务选择组件-->
|
||||
<template>
|
||||
<div class="JSelectNu">
|
||||
<JSelectBiz @handleOpen="handleOpen" :loading="loadingEcho" v-bind="attrs"></JSelectBiz>
|
||||
<!-- update-begin--author:liaozhiyang---date:20240515---for:【QQYUN-9260】必填模式下会影响到弹窗内antd组件的样式 -->
|
||||
<a-form-item>
|
||||
<NuSelectModal @register="regModal" @getSelectResult="setValue" v-bind="getBindValue" :isRadioSelection="selectType"></NuSelectModal>
|
||||
</a-form-item>
|
||||
<!-- update-end--author:liaozhiyang---date:20240515---for:【QQYUN-9260】必填模式下会影响到弹窗内antd组件的样式 -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import NuSelectModal from './modal/NuSelectModal.vue';
|
||||
import JSelectBiz from './base/JSelectBiz.vue';
|
||||
import { defineComponent, ref, reactive, watchEffect, watch, provide, computed, unref } from 'vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { SelectValue } from 'ant-design-vue/es/select';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JSelectNu',
|
||||
components: {
|
||||
NuSelectModal,
|
||||
JSelectBiz,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
|
||||
rowKey: {
|
||||
type: String,
|
||||
default: 'nuId',
|
||||
},
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: 'nuName',
|
||||
},
|
||||
selectType: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
emits: ['options-change', 'change', 'update:value'],
|
||||
setup(props, { emit, refs }) {
|
||||
const emitData = ref<any[]>();
|
||||
//注册model
|
||||
const [regModal, { openModal }] = useModal();
|
||||
//表单值
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
//下拉框选项值
|
||||
const selectOptions = ref<SelectValue>([]);
|
||||
//下拉框选中值
|
||||
let selectValues = reactive<object>({
|
||||
value: [],
|
||||
change: false,
|
||||
});
|
||||
// 是否正在加载回显数据
|
||||
const loadingEcho = ref<boolean>(false);
|
||||
//下发 selectOptions,xxxBiz组件接收
|
||||
provide('selectOptions', selectOptions);
|
||||
//下发 selectValues,xxxBiz组件接收
|
||||
provide('selectValues', selectValues);
|
||||
//下发 loadingEcho,xxxBiz组件接收
|
||||
provide('loadingEcho', loadingEcho);
|
||||
|
||||
const tag = ref(false);
|
||||
const attrs = useAttrs();
|
||||
/**
|
||||
* 监听组件值
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props.value && initValue();
|
||||
});
|
||||
|
||||
/**
|
||||
* 监听selectValues变化
|
||||
*/
|
||||
watch(selectValues, () => {
|
||||
if (selectValues) {
|
||||
state.value = selectValues.value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 打卡弹出框
|
||||
*/
|
||||
function handleOpen() {
|
||||
tag.value = true;
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串值转化为数组
|
||||
*/
|
||||
function initValue() {
|
||||
let value = props.value ? props.value : [];
|
||||
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
|
||||
state.value = value.split(',');
|
||||
selectValues.value = value.split(',');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置下拉框的值
|
||||
*/
|
||||
function setValue(options, values) {
|
||||
selectOptions.value = options;
|
||||
//emitData.value = values.join(",");
|
||||
state.value = values;
|
||||
selectValues.value = values;
|
||||
//update-begin-author:liusq date:20230517 for:选择职务组件v-model方式绑定值不生效
|
||||
emit('update:value', values.join(','));
|
||||
//update-begin-author:liusq date:20230517 for:选择职务组件v-model方式绑定值不生效
|
||||
|
||||
}
|
||||
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
return {
|
||||
state,
|
||||
getBindValue,
|
||||
attrs,
|
||||
selectOptions,
|
||||
selectValues,
|
||||
loadingEcho,
|
||||
tag,
|
||||
regModal,
|
||||
setValue,
|
||||
handleOpen,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// update-begin--author:liaozhiyang---date:20240515---for:【QQYUN-9260】必填模式下会影响到弹窗内antd组件的样式
|
||||
.JSelectNu {
|
||||
> .ant-form-item {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240515---for:【QQYUN-9260】必填模式下会影响到弹窗内antd组件的样式
|
||||
.j-select-row {
|
||||
@width: 82px;
|
||||
|
||||
.left {
|
||||
width: calc(100% - @width - 8px);
|
||||
}
|
||||
|
||||
.right {
|
||||
width: @width;
|
||||
}
|
||||
|
||||
.full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-select-search__field) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,190 @@
|
|||
<!--职务选择框-->
|
||||
<template>
|
||||
<div>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="register"
|
||||
:title="modalTitle"
|
||||
width="1100px"
|
||||
wrapClassName="j-user-select-modal"
|
||||
@ok="handleOk"
|
||||
destroyOnClose
|
||||
@visible-change="visibleChange"
|
||||
>
|
||||
<a-row>
|
||||
<a-col :span="showSelected ? 18 : 24">
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:bordered="true"
|
||||
:useSearchForm="true"
|
||||
:formConfig="formConfig"
|
||||
:api="getNuList"
|
||||
:searchInfo="searchInfo"
|
||||
:rowSelection="rowSelection"
|
||||
:indexColumnProps="indexColumnProps"
|
||||
v-bind="getBindValue"
|
||||
></BasicTable>
|
||||
</a-col>
|
||||
<a-col :span="showSelected ? 6 : 0">
|
||||
<BasicTable
|
||||
v-bind="selectedTable"
|
||||
:dataSource="selectRows"
|
||||
:useSearchForm="true"
|
||||
:formConfig="{ showActionButtonGroup: false, baseRowStyle: { minHeight: '40px' } }"
|
||||
>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<a href="javascript:void(0)" @click="handleDeleteSelected(record)"><Icon icon="ant-design:delete-outlined"></Icon></a>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</BasicModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { getNuList } from '/@/api/common/api';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { useSelectBiz } from '/@/components/Form/src/jeecg/hooks/useSelectBiz';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { selectProps } from '/@/components/Form/src/jeecg/props/props';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NuSelectModal',
|
||||
components: {
|
||||
//此处需要异步加载BasicTable
|
||||
BasicModal,
|
||||
BasicTable: createAsyncComponent(() => import('/@/components/Table/src/BasicTable.vue'), {
|
||||
loading: true,
|
||||
}),
|
||||
},
|
||||
props: {
|
||||
...selectProps,
|
||||
//选择框标题
|
||||
modalTitle: {
|
||||
type: String,
|
||||
default: '护理单元选择',
|
||||
},
|
||||
},
|
||||
emits: ['register', 'getSelectResult'],
|
||||
setup(props, { emit, refs }) {
|
||||
//注册弹框
|
||||
const [register, { closeModal }] = useModalInner();
|
||||
const attrs = useAttrs();
|
||||
//表格配置
|
||||
const config = {
|
||||
canResize: false,
|
||||
bordered: true,
|
||||
size: 'small',
|
||||
//改成读取rowKey,自定义传递参数
|
||||
rowKey: props.rowKey,
|
||||
};
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs), config);
|
||||
const [{ rowSelection, visibleChange, indexColumnProps, getSelectResult, handleDeleteSelected, selectRows }] = useSelectBiz(
|
||||
getNuList,
|
||||
getBindValue
|
||||
);
|
||||
const searchInfo = ref(props.params);
|
||||
//查询form
|
||||
const formConfig = {
|
||||
labelCol: {
|
||||
span: 4,
|
||||
},
|
||||
baseColProps: {
|
||||
xs: 24,
|
||||
sm: 10,
|
||||
md: 10,
|
||||
lg: 10,
|
||||
xl: 10,
|
||||
xxl: 10,
|
||||
},
|
||||
//update-begin-author:liusq date:2023-10-30 for: [issues/5514]组件页面显示错位
|
||||
actionColOptions: {
|
||||
xs: 24,
|
||||
sm: 8,
|
||||
md: 8,
|
||||
lg: 8,
|
||||
xl: 8,
|
||||
xxl: 8,
|
||||
},
|
||||
//update-end-author:liusq date:2023-10-30 for: [issues/5514]组件页面显示错位
|
||||
schemas: [
|
||||
{
|
||||
label: '护理单元名称',
|
||||
field: 'nuName',
|
||||
component: 'JInput',
|
||||
colProps: { span: 10 },
|
||||
},
|
||||
],
|
||||
};
|
||||
//定义表格列
|
||||
const columns = [
|
||||
{
|
||||
title: '护理单元ID',
|
||||
dataIndex: 'nuId',
|
||||
width: 180,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: '护理单元名称',
|
||||
dataIndex: 'nuName',
|
||||
// width: 180,
|
||||
},
|
||||
];
|
||||
//已选择的table信息
|
||||
const selectedTable = {
|
||||
pagination: false,
|
||||
showIndexColumn: false,
|
||||
scroll: { y: 390 },
|
||||
size: 'small',
|
||||
canResize: false,
|
||||
bordered: true,
|
||||
rowKey: 'nuId',
|
||||
columns: [
|
||||
{
|
||||
title: '护理单元名称',
|
||||
dataIndex: 'nuName',
|
||||
width: 40,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 40,
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* 确定选择
|
||||
*/
|
||||
function handleOk() {
|
||||
getSelectResult((options, values) => {
|
||||
//回传选项和已选择的值
|
||||
emit('getSelectResult', options, values);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
});
|
||||
}
|
||||
return {
|
||||
handleOk,
|
||||
getNuList,
|
||||
register,
|
||||
visibleChange,
|
||||
getBindValue,
|
||||
formConfig,
|
||||
indexColumnProps,
|
||||
columns,
|
||||
rowSelection,
|
||||
|
||||
selectedTable,
|
||||
selectRows,
|
||||
handleDeleteSelected,
|
||||
searchInfo,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -156,5 +156,6 @@ export type ComponentType =
|
|||
| 'linkRecordSelect'
|
||||
| 'RangeTime'
|
||||
| 'JRangeNumber'
|
||||
| 'JInputSelect';
|
||||
| 'JInputSelect'
|
||||
| 'JSelectNu';
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<template>
|
||||
<a-card :bordered="false" style="height: 100%">
|
||||
<a-spin :spinning="syncoading">
|
||||
<div class="j-table-operator" style="width: 100%">
|
||||
<!-- <a-button preIcon="ant-design:sync-outlined" @click="loadRootTreeData">刷新</a-button>-->
|
||||
<a-button type="primary" preIcon="ant-design:sync-outlined" @click="syncProjectInfo">同步项目</a-button>
|
||||
<template v-if="currentRegion !=null">
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="syncRegionInfo">同步区域</a-button>
|
||||
</template>
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="loadRootTreeData">刷新</a-button>
|
||||
<!-- <a-button type="primary" preIcon="ant-design:sync-outlined" @click="syncProjectInfo">同步项目</a-button>-->
|
||||
<!-- <template v-if="currentRegion !=null">-->
|
||||
<!-- <a-button preIcon="ant-design:sync-outlined" @click="syncRegionInfo">同步区域</a-button>-->
|
||||
<!-- </template>-->
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<!--区域树-->
|
||||
|
@ -25,6 +26,7 @@
|
|||
</template>
|
||||
<a-empty v-else description="暂无数据" />
|
||||
</a-spin>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
|
@ -37,6 +39,7 @@
|
|||
import { queryProjectTreeSync, queryRegionTreeSync, syncProject, syncRegion } from '@/views/iot/tplink/camera/camera.api';
|
||||
|
||||
const emit = defineEmits(['select', 'rootTreeData']);
|
||||
const syncoading = ref<boolean>(false);
|
||||
const loading = ref<boolean>(false);
|
||||
// 区域树列表数据
|
||||
const treeData = ref<any[]>([]);
|
||||
|
@ -78,6 +81,7 @@
|
|||
emit('rootTreeData', treeData.value);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
syncoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,24 +176,29 @@
|
|||
/**
|
||||
* 同步项目
|
||||
*/
|
||||
async function syncProjectInfo(){
|
||||
await syncProject();
|
||||
await loadRootTreeData();
|
||||
}
|
||||
// async function syncProjectInfo(){
|
||||
// syncoading.value = true;
|
||||
// await syncProject();
|
||||
// await loadRootTreeData();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 同步区域
|
||||
*/
|
||||
async function syncRegionInfo(){
|
||||
let data = currentRegion.value;
|
||||
if (data == null) {
|
||||
createMessage.warning('请先选择一个区域');
|
||||
return;
|
||||
}
|
||||
const record = { projectId: data.projectId };
|
||||
await syncRegion(record);
|
||||
await loadRootTreeData();
|
||||
}
|
||||
// async function syncRegionInfo(){
|
||||
// let data = currentRegion.value;
|
||||
// if (data == null) {
|
||||
// createMessage.warning('请先选择一个区域');
|
||||
// return;
|
||||
// }
|
||||
// const record = {
|
||||
// projectId: data.projectId,
|
||||
// regionId: data.regionId
|
||||
// };
|
||||
// syncoading.value = true;
|
||||
// await syncRegion(record);
|
||||
// await loadRootTreeData();
|
||||
// }
|
||||
|
||||
defineExpose({
|
||||
loadRootTreeData,
|
||||
|
|
|
@ -128,3 +128,7 @@ export const formSchema: FormSchema[] = [
|
|||
},
|
||||
];
|
||||
|
||||
// 项目基础表单
|
||||
export const projectFormSchema: FormSchema[] = [
|
||||
|
||||
];
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<a-spin :spinning="loading">
|
||||
<BasicForm @register="registerForm" />
|
||||
<div class="j-box-bottom-button offset-20" style="margin-top: 30px">
|
||||
<div class="j-box-bottom-button-float">
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="onReset">重置</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:save-filled" @click="onSubmit">保存</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, computed, inject, ref, unref, onMounted } from 'vue';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { saveOrUpdateRegion } from '@/views/iot/tplink/region/RegionInfo.api';
|
||||
import { formSchema } from '@/views/iot/tplink/region/RegionInfo.data';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const props = defineProps({
|
||||
data: { type: Object, default: () => ({}) },
|
||||
rootTreeData: { type: Array, default: () => [] },
|
||||
});
|
||||
const loading = ref<boolean>(false);
|
||||
// 当前是否是更新模式
|
||||
const isUpdate = ref<boolean>(true);
|
||||
// 当前的弹窗数据
|
||||
const model = ref<object>({});
|
||||
|
||||
//注册表单
|
||||
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false
|
||||
});
|
||||
|
||||
// const categoryOptions = computed(() => {
|
||||
// if (!!props?.data?.parentId) {
|
||||
// return orgCategoryOptions.child;
|
||||
// } else {
|
||||
// return orgCategoryOptions.root;
|
||||
// }
|
||||
// });
|
||||
|
||||
onMounted(() => {
|
||||
// 禁用字段
|
||||
updateSchema([
|
||||
{ field: 'parentId', componentProps: { disabled: true } },
|
||||
{ field: 'orgCode', componentProps: { disabled: true } },
|
||||
]);
|
||||
// data 变化,重填表单
|
||||
watch(
|
||||
() => props.data,
|
||||
async () => {
|
||||
let record = unref(props.data);
|
||||
if (typeof record !== 'object') {
|
||||
record = {};
|
||||
}
|
||||
model.value = record;
|
||||
await resetFields();
|
||||
await setFieldsValue({ ...record });
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
});
|
||||
|
||||
// 重置表单
|
||||
async function onReset() {
|
||||
await resetFields();
|
||||
await setFieldsValue({ ...model.value });
|
||||
}
|
||||
|
||||
// 提交事件
|
||||
async function onSubmit() {
|
||||
try {
|
||||
loading.value = true;
|
||||
let values = await validate();
|
||||
values = Object.assign({}, model.value, values);
|
||||
//提交表单
|
||||
await saveOrUpdateRegion(values, isUpdate.value);
|
||||
//刷新列表
|
||||
emit('success');
|
||||
Object.assign(model.value, values);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
|
||||
|
||||
</style>
|
|
@ -6,7 +6,7 @@
|
|||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="handleSync"> 同步</a-button>
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="handleSync"> 同步下级</a-button>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
|
@ -25,14 +25,16 @@
|
|||
import {ref, reactive, createVNode, h} from 'vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns,searchFormSchema } from './RegionInfo.data';
|
||||
import { list, sync, deleteRegion } from './RegionInfo.api';
|
||||
import { columns,searchFormSchema } from '@/views/iot/tplink/region/RegionInfo.data';
|
||||
import { list, sync, deleteRegion } from '@/views/iot/tplink/region/RegionInfo.api';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useDrawer } from "@/components/Drawer";
|
||||
import RegionInfoDrawer from './components/RegionInfoDrawer.vue';
|
||||
import RegionInfoDrawer from './RegionInfoDrawer.vue';
|
||||
import {Modal} from "ant-design-vue";
|
||||
import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
|
||||
import {useMessage} from "@/hooks/web/useMessage";
|
||||
const { createMessage } = useMessage();
|
||||
//注册drawer
|
||||
const [registerDrawer, { openDrawer }] = useDrawer();
|
||||
let router = useRouter();
|
||||
|
@ -47,10 +49,10 @@
|
|||
api: list,
|
||||
columns,
|
||||
canResize:false,
|
||||
formConfig: {
|
||||
// labelWidth: 200,
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
// formConfig: {
|
||||
// // labelWidth: 200,
|
||||
// schemas: searchFormSchema,
|
||||
// },
|
||||
actionColumn: {
|
||||
width: 160,
|
||||
fixed: 'right',
|
|
@ -0,0 +1,214 @@
|
|||
<template>
|
||||
<a-card :bordered="false" style="height: 100%">
|
||||
<a-spin :spinning="syncoading">
|
||||
<div class="j-table-operator" style="width: 100%">
|
||||
<!-- <a-button preIcon="ant-design:sync-outlined" @click="loadRootTreeData">刷新</a-button>-->
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="syncProjectInfo">新增</a-button>
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="syncProjectInfo">同步</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="syncProjectInfo">新增下级</a-button>
|
||||
<template v-if="currentRegion !=null">
|
||||
<a-button preIcon="ant-design:sync-outlined" @click="syncRegionInfo">同步下级</a-button>
|
||||
</template>
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<a-input-search placeholder="按名称搜索…" style="margin-bottom: 10px" @search="onSearch" />
|
||||
<!--区域树-->
|
||||
<template v-if="treeData.length > 0">
|
||||
<a-tree
|
||||
v-if="!treeReloading"
|
||||
:clickRowToExpand="false"
|
||||
:treeData="treeData"
|
||||
:selectedKeys="selectedKeys"
|
||||
:checkStrictly="checkStrictly"
|
||||
:load-data="loadChildrenTreeData"
|
||||
:checkedKeys="checkedKeys"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
@select="onSelect"
|
||||
>
|
||||
</a-tree>
|
||||
</template>
|
||||
<a-empty v-else description="暂无数据" />
|
||||
</a-spin>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, ref } from 'vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useMethods } from '/@/hooks/system/useMethods';
|
||||
const { createMessage } = useMessage();
|
||||
import { queryProjectTreeSync, queryRegionTreeSync, syncProject, syncRegion } from '@/views/iot/tplink/camera/camera.api';
|
||||
|
||||
const emit = defineEmits(['select', 'rootTreeData']);
|
||||
const syncoading = ref<boolean>(false);
|
||||
const loading = ref<boolean>(false);
|
||||
// 区域树列表数据
|
||||
const treeData = ref<any[]>([]);
|
||||
// 当前选中的项
|
||||
const checkedKeys = ref<any[]>([]);
|
||||
// 当前展开的项
|
||||
const expandedKeys = ref<any[]>([]);
|
||||
// 当前选中的项
|
||||
const selectedKeys = ref<any[]>([]);
|
||||
// 树组件重新加载
|
||||
const treeReloading = ref<boolean>(false);
|
||||
// 树父子是否关联
|
||||
const checkStrictly = ref<boolean>(true);
|
||||
// 当前选中的区域
|
||||
const currentRegion = ref<any>(null);
|
||||
|
||||
// 加载顶级区域信息
|
||||
async function loadRootTreeData() {
|
||||
try {
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
const result = await queryProjectTreeSync();
|
||||
if (Array.isArray(result)) {
|
||||
treeData.value = result;
|
||||
}
|
||||
if (expandedKeys.value.length === 0) {
|
||||
autoExpandParentNode();
|
||||
} else {
|
||||
if (selectedKeys.value.length === 0) {
|
||||
let item = treeData.value[0];
|
||||
if (item) {
|
||||
// 默认选中第一个
|
||||
setSelectedKey(item.id, item);
|
||||
}
|
||||
} else {
|
||||
emit('select', currentRegion.value);
|
||||
}
|
||||
}
|
||||
emit('rootTreeData', treeData.value);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
syncoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
loadRootTreeData();
|
||||
|
||||
/**
|
||||
* 加载子级区域信息
|
||||
*/
|
||||
async function loadChildrenTreeData(treeNode) {
|
||||
try {
|
||||
const result = await queryRegionTreeSync({
|
||||
parentId: treeNode.dataRef.id,
|
||||
projectId: treeNode.dataRef.projectId,
|
||||
});
|
||||
if (result.length == 0) {
|
||||
treeNode.dataRef.isLeaf = true;
|
||||
} else {
|
||||
treeNode.dataRef.children = result;
|
||||
if (expandedKeys.value.length > 0) {
|
||||
// 判断获取的子级是否有当前展开的项
|
||||
let subKeys: any[] = [];
|
||||
for (let key of expandedKeys.value) {
|
||||
if (result.findIndex((item) => item.id === key) !== -1) {
|
||||
subKeys.push(key);
|
||||
}
|
||||
}
|
||||
if (subKeys.length > 0) {
|
||||
expandedKeys.value = [...expandedKeys.value];
|
||||
}
|
||||
}
|
||||
}
|
||||
treeData.value = [...treeData.value];
|
||||
emit('rootTreeData', treeData.value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动展开父节点,只展开一级
|
||||
*/
|
||||
function autoExpandParentNode() {
|
||||
let item = treeData.value[0];
|
||||
if (item) {
|
||||
if (!item.isLeaf) {
|
||||
expandedKeys.value = [item.key];
|
||||
}
|
||||
// 默认选中第一个
|
||||
setSelectedKey(item.id, item);
|
||||
reloadTree();
|
||||
} else {
|
||||
emit('select', null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载树组件,防止无法默认展开数据
|
||||
*/
|
||||
async function reloadTree() {
|
||||
await nextTick();
|
||||
treeReloading.value = true;
|
||||
await nextTick();
|
||||
treeReloading.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前选中的行
|
||||
*/
|
||||
function setSelectedKey(key: string, data?: object) {
|
||||
console.log('setSelectedKey: ', key);
|
||||
selectedKeys.value = [key];
|
||||
if (data) {
|
||||
currentRegion.value = data;
|
||||
emit('select', data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 树选择事件
|
||||
*/
|
||||
function onSelect(selKeys, event) {
|
||||
console.log('onSelect: ', selKeys, event);
|
||||
if (selKeys.length > 0 && selectedKeys.value[0] !== selKeys[0]) {
|
||||
setSelectedKey(selKeys[0], event.selectedNodes[0]);
|
||||
} else {
|
||||
// 这样可以防止用户取消选择
|
||||
setSelectedKey(selectedKeys.value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步项目
|
||||
*/
|
||||
// async function syncProjectInfo(){
|
||||
// syncoading.value = true;
|
||||
// await syncProject();
|
||||
// await loadRootTreeData();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 同步区域
|
||||
*/
|
||||
async function syncRegionInfo(){
|
||||
let data = currentRegion.value;
|
||||
if (data == null) {
|
||||
createMessage.warning('请先选择一个节点');
|
||||
return;
|
||||
}
|
||||
const record = {
|
||||
projectId: data.projectId,
|
||||
regionId: data.regionId
|
||||
};
|
||||
syncoading.value = true;
|
||||
await syncRegion(record);
|
||||
await loadRootTreeData();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadRootTreeData,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
|
||||
</style>
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<a-row class="p-2" type="flex" :gutter="10">
|
||||
<a-col :xl="12" :lg="24" :md="24" style="margin-bottom: 10px">
|
||||
<RegionLeftTree ref="leftTree" @select="onTreeSelect" @rootTreeData="onRootTreeData" />
|
||||
</a-col>
|
||||
<a-col :xl="12" :lg="24" :md="24" style="margin-bottom: 10px">
|
||||
<div style="height: 100%;" class="form-content">
|
||||
<a-tabs v-show="regionData != null" defaultActiveKey="base-info">
|
||||
<a-tab-pane tab="基本信息" key="base-info" forceRender style="position: relative">
|
||||
<div style="padding: 20px">
|
||||
<RegionForm :data="regionData" :rootTreeData="rootTreeData" @success="onSuccess" />
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<div v-show="regionData == null" style="padding-top: 40px">
|
||||
<a-empty description="请选择区域" />
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="iot-nuIotRegionInfo" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import RegionLeftTree from './components/RegionLeftTree.vue'
|
||||
import RegionForm from "@/views/iot/tplink/region/components/RegionForm.vue";
|
||||
|
||||
// 给子组件定义一个ref变量
|
||||
const leftTree = ref();
|
||||
// 当前选中的区域信息
|
||||
const regionData = ref({});
|
||||
const rootTreeData = ref<any[]>([]);
|
||||
// 左侧树选择后触发
|
||||
function onTreeSelect(data) {
|
||||
console.log('onTreeSelect: ', data);
|
||||
regionData.value = data;
|
||||
}
|
||||
// 左侧树rootTreeData触发
|
||||
function onRootTreeData(data) {
|
||||
rootTreeData.value = data;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.p-2{
|
||||
height: calc(100vh - 120px);
|
||||
}
|
||||
|
||||
.form-content{
|
||||
background-color: #ffffff;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-nav ){
|
||||
padding: 0 20px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue