feat:土地分类接口对接完成

This commit is contained in:
李想 2025-03-14 17:33:44 +08:00
parent 151f1e0221
commit beacba1950
10 changed files with 660 additions and 136 deletions

View File

@ -1,4 +1,5 @@
import request from '@/utils/axios';
import { method } from 'lodash';
//基础信息维护——字典项管理
@ -73,8 +74,6 @@ export function delPlanCrop(params) {
// #endregion
// #region
export function savePlanStage(data) {
return request('land-resource/baseInfo/stageTypeSave', {
method: 'POST',
@ -83,6 +82,7 @@ export function savePlanStage(data) {
}
/* ------ 土壤类型 ------ */
// #region
/* 获取土壤类型列表 */
export function getSoilType(params) {
@ -114,9 +114,53 @@ export function delSoilType(id) {
}
/* 导出土壤类型 */
export function exportSoilType() {
return request('/land-resource/baseInfo/soilTypeExport', {
return request('/land-resource/baseInfo/soilTypeExport/', {
method: 'GET',
responseType: 'blob',
});
}
// #endregion
/* ------ 土地类型 ------ */
// #region
/* 新增土地类型 */
export function landTypeSave(data) {
return request('land-resource/baseInfo/landTypeSave', {
method: 'POST',
data,
});
}
/* 土地类型树 */
export function getLandTypeTree(params) {
return request('land-resource/baseInfo/landTree', {
params,
});
}
/* 土地类型列表 */
export function getLandType(params) {
return request('land-resource/baseInfo/landType', {
params,
});
}
/* 土地类型导出 */
export function exportLandType(params) {
return request('land-resource/baseInfo/landTypeExport', {
params,
responseType: 'blob',
});
}
/* 土地类型删除 */
export function delLandType(id) {
return request(`land-resource/baseInfo/landTypeDelete/${id}`, {
method: 'DELETE',
});
}
/* 土地类型编辑 */
export function editLandType(data) {
return request('land-resource/baseInfo/landTypeEdit', {
method: 'PUT',
data,
});
}
// #endregion

View File

@ -13,7 +13,7 @@ const landsRoutes = [
path: '/sub-government-affairs-service/landsManage',
name: 'landsManage',
component: () => import('@/views/landManage/component/landsManage/index.vue'),
meta: { title: '土地管理', icon: 'Document' },
meta: { title: '土地信息登记', icon: 'Document' },
},
{
path: '/sub-government-affairs-service/plantPlan',

View File

@ -2,10 +2,24 @@
<CustomCard>
<div>
<el-row :gutter="20">
<el-col :span="6">
<el-tree style="max-width: 600px" :data="typeTree" :props="{ children: 'children', label: 'label' }" @node-click="handleNodeClick" />
<el-col :span="4">
<el-tree
style="max-width: 600px"
:data="treeData"
node-key="id"
:default-expanded-keys="[selectTreeNode.id]"
:props="{ value: 'id' }"
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<template #default="{ data }">
<div class="tree_node_" :class="{ nodeActive: data.id == selectTreeNode.id || data.id == selectTreeNode.pId }">
{{ data.label }}
</div>
</template>
</el-tree>
</el-col>
<el-col :span="18">
<el-col :span="20">
<avue-crud
ref="crudRef"
v-model="state.form"
@ -39,22 +53,27 @@
</CustomCard>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ref, reactive, onMounted, nextTick } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import CustomCard from '@/components/CustomCard.vue';
import { getLandTypeTree, landTypeSave, getLandType, exportLandType, delLandType, editLandType } from '@/apis/baseInfo';
import { ElMessage } from 'element-plus';
const { VITE_APP_BASE_API } = import.meta.env;
const app = useApp();
/* --------------- data --------------- */
// #region
const selectTreeNode = ref({
id: '',
label: '',
pId: '',
pName: '',
level: 0,
});
const landTypesDic = ref([]);
const crudRef = ref(null);
const landUsedOptions = reactive([
{ label: '农用地', value: '0' },
{ label: '建设用地', value: '1' },
{ label: '住宅用地', value: '2' },
]);
const state = reactive({
loading: false,
query: {
@ -67,25 +86,61 @@ const state = reactive({
...CRUD_OPTIONS,
addBtnText: '',
addBtn: false,
dialogWidth: 680,
selection: false,
refreshBtn: false,
column: [
{ label: '编号', prop: 'gridManager', addDisplay: false, editDisplay: false },
{ label: '编号', prop: 'id', addDisplay: false, editDisplay: false },
{
label: '土地分类',
prop: 'gridManager',
dicData: landUsedOptions,
label: '用地分类',
prop: 'landType',
dicData: landTypesDic,
// type: 'select',
multiple: true,
rules: {
required: true,
message: '请选择',
trigger: 'blur',
span: 23,
props: {
value: 'id',
label: 'childLandCategory',
},
rules: [
{
required: true,
message: '请输入',
trigger: 'blur',
},
],
render: ({ row }) => {
return row.landType;
},
},
{ label: '土地类别', prop: 'gridManager' },
{ label: '状态', prop: 'gridManager', addDisplay: false, editDisplay: false },
{
label: '土地类别',
prop: 'landCategory',
addDisplay: false,
rules: [
{
required: true,
message: '请输入',
trigger: 'blur',
},
],
render: ({ row }) => {
return row.landCategory;
},
},
{
label: '状态',
prop: 'status',
render: ({ row }) => {
return row.status == '1' ? '启用' : '禁用';
},
addDisplay: false,
editDisplay: false,
},
],
actions: [
{
name: (row) => getStatusButtonText(row.status),
name: ({ row }) => `${row.status == '0' ? '启' : '禁'}`,
icon: 'edit',
event: ({ row }) => rowStatus(row),
},
@ -111,57 +166,65 @@ const state = reactive({
currentRow: {},
});
let typeTree = reactive([
{
label: '农用地',
id: '0',
children: [
{ label: '耕地', id: '01', children: [], pId: '0' },
{ label: '园地', children: [], id: '02', pId: '0' },
],
},
{
label: '建设用地',
id: '1',
children: [{ label: '城乡建设用地', children: [], id: '11', pId: '10' }],
},
{
label: '住宅用地',
id: '2',
children: [],
},
]);
const treeData = ref([]);
// #endregion
/* --------------- methods --------------- */
const loadData = () => {
//state.loading = true;
// getAnnualList(state.query)
// .then((res) => {
// if (res.code === 200) {
// const { current, size, total, records } = res.data;
// state.data = records;
// state.pageData = {
// currentPage: current || 1,
// pageSize: size || 10,
// total: total,
// };
// }
// })
// .catch((err) => {
// app.$message.error(err.msg);
// state.data = [];
// })
// .finally(() => {
// state.loading = false;
// });
state.loading = true;
getLandType({
pid: selectTreeNode.value.id,
...state.query,
})
.then((res) => {
if (res.code === 200) {
const { current, size, total, records } = res.data;
state.data = records;
state.pageData = {
currentPage: current || 1,
pageSize: size || 10,
total: total,
};
}
})
.catch((err) => {
app.$message.error(err.msg);
state.data = [];
})
.finally(() => {
state.loading = false;
});
};
onMounted(() => {
loadData();
getLandTree();
});
async function getLandTree() {
let res = await getLandTypeTree();
if (res.code == 200) {
treeData.value = newTree(res.data, 0);
landTypesDic.value = res.data.map((v) => {
return {
id: v.id,
label: v.prentLandType,
};
});
console.log('treeData', treeData.value);
}
}
function newTree(arr, i) {
arr.forEach((v) => {
if (i == 0) {
v.label = v.prentLandType;
} else {
v.label = v.childLandCategory;
}
if (v.children) v.children = newTree(v.children, i + 1);
});
return arr;
}
//
const currentChange = (current) => {
state.query.current = current;
@ -170,6 +233,7 @@ const currentChange = (current) => {
//
const sizeChange = (size) => {
state.query.current = 1;
state.query.size = size;
loadData();
};
@ -193,24 +257,67 @@ const selectionChange = (rows) => {
state.selection = rows;
};
const handleNodeClick = (data) => {
console.log('handleNodeClick', data);
};
//
const rowStatus = (row) => {
console.info('操作状态');
};
const rowDel = (row) => {};
const getStatusButtonText = (status) => {
switch (status) {
case 'active':
return '启用';
case 'inactive':
return '禁用';
const handleNodeClick = (data, node) => {
const { id } = data;
if (selectTreeNode.value.id != id) {
if (node.level < 2) {
selectTreeNode.value = handleNodeData({ data, level: node.level });
} else selectTreeNode.value = handleNodeData({ data: node.parent.data, level: node.level });
loadData();
} else {
selectTreeNode.value = { id: '', label: '', level: 0 };
state.data = [];
}
if (selectTreeNode.value.level < 1) {
state.options.dialogWidth = 680;
state.options.column[1].span = 23;
state.options.column[2].addDisplay = false;
delete state.options.column[1].addDisabled;
delete state.options.column[1].value;
} else {
state.options.column[2].addDisplay = true;
state.options.column[1].addDisabled = true;
state.options.column[1].value = selectTreeNode.value.label;
delete state.options.dialogWidth;
delete state.options.column[1].type;
delete state.options.column[1].span;
}
};
function handleNodeData({ data, level }) {
return {
id: data.id,
label: data.label,
level,
};
}
//
async function rowStatus(row) {
console.info('操作状态', row.$index);
const { id } = row;
let status = row.status == '1' ? '0' : '1';
let params = {
id,
status,
};
let res = await editLandType(params);
if (res.code == 200) {
ElMessage.success('操作成功');
nextTick(() => {
state.data[row.$index].status = status;
loadData();
});
}
}
async function rowDel(row, done, loading) {
let res = await delLandType(row.id);
if (res.code === 200) {
app.$message.success('已删除!');
loadData();
done();
}
loading();
}
const rowEdit = (row) => {
crudRef.value && crudRef.value.rowEdit(row);
@ -219,9 +326,43 @@ const rowEdit = (row) => {
const onAdd = () => {
crudRef.value && crudRef.value.rowAdd();
};
const onExport = () => {};
const rowSave = (row, done, loading) => {
// console.info('', row);
async function onExport() {
console.log('test ---');
if (selectTreeNode.value.level < 1) return ElMessage.warning('请选择用地分类');
let res = await exportLandType({
pid: selectTreeNode.value.id,
});
console.log('edxport', res);
if (res.status == 200) {
let a = document.createElement('a');
let blob = new Blob([res.data]);
let link = window.URL.createObjectURL(blob);
a.href = link;
a.download = '用地分类.xlsx';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(link);
}
}
const rowSave = async (val, done, loading) => {
console.info('新增', val);
let data = {};
if (selectTreeNode.value.level < 1) {
data.landType = val.landType;
} else {
data = {
pid: selectTreeNode.value.id,
landCategory: val.landCategory,
};
}
let res = await landTypeSave(data);
if (res.code == 200) {
ElMessage.success('创建成功');
getLandTree();
if (selectTreeNode.value.level > 0) loadData();
done();
}
// saveOperationRecord(row)
// .then((res) => {
// if (res.code === 200) {
@ -236,29 +377,50 @@ const rowSave = (row, done, loading) => {
// .finally(() => {
// loading();
// });
loading();
};
const rowUpdate = (row, index, done, loading) => {
console.info('更新');
// editOperationRecord(row)
// .then((res) => {
// if (res.code === 200) {
// app.$message.success('');
// done();
// loadData();
// }
// })
// .catch((err) => {
// app.$message.error(err.msg);
// })
// .finally(() => {
// loading();
// });
console.log('row', row);
editLandType({
id: row.id,
landCategory: row.landCategory,
}).then((res) => {
if (res.code === 200) {
app.$message.success('更新成功!');
loadData();
done();
}
});
loading();
};
// #region
// #endregion
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.tree_node_ {
padding: 0 6px;
display: flex;
align-items: center;
height: calc(100% - 4px);
border-radius: 2px;
user-select: none;
}
.nodeActive {
background-color: rgb(172, 223, 243);
}
::v-deep() {
.is-current {
.el-tree-node__content {
background-color: rgba($color: #000000, $alpha: 0);
}
}
.el-tree-node__content {
&:hover {
background-color: rgba($color: #000000, $alpha: 0);
}
}
}
</style>

View File

@ -2,7 +2,7 @@
<CustomCard>
<div>
<el-row :gutter="20">
<el-col :span="6">
<el-col :span="4">
<el-tree
style="max-width: 600px"
:data="typeTree"
@ -11,7 +11,7 @@
@node-click="handleNodeClick"
/>
</el-col>
<el-col :span="18">
<el-col :span="20">
<avue-crud
ref="crudRef"
v-model="state.form"

View File

@ -0,0 +1,46 @@
<template>
<el-sub-menu :index="types.value" :popper-offset="2">
<template #title>{{ types.label }}</template>
<template v-for="item in types.children" :key="`type_menu_${item.value}`">
<el-menu-item v-if="!item.children" :index="item.value">{{ item.label }}</el-menu-item>
<SubMenu v-else :types="item" />
</template>
</el-sub-menu>
</template>
<script setup>
import { ref } from 'vue';
import SubMenu from './SubMenu.vue';
defineProps({
types: {
type: Object,
default: () => {
return {
// label: '1',
// value: '1',
// children: [
// {
// label: '1-1',
// value: '1-1',
// },
// {
// label: '1-2',
// value: '1-2',
// },
// ],
};
},
},
});
/* --------------- data --------------- */
// #region
// #endregion
/* --------------- methods --------------- */
// #region
// #endregion
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,74 @@
<template>
<el-menu mode="horizontal" class="input_supplies_type_menu_" @select="handleTypeSelect">
<template v-for="item in types" :key="`type_menu_${item.value}`">
<el-menu-item v-if="!item.children" :index="item.value">{{ item.label }}</el-menu-item>
<SubMenu v-else :types="item" />
</template>
</el-menu>
</template>
<script setup>
import SubMenu from './SubMenu.vue';
const emit = defineEmits(['update:type']);
defineProps({
types: {
type: Array,
default: () => [
{
label: '全部',
value: '',
},
{
label: '类型1',
value: '1',
children: [
{
label: '类型1-1',
value: '1-1',
},
{
label: '类型1-2',
value: '1-2',
},
],
},
{
label: '类型2',
value: '2',
children: [
{
label: '类型2-1',
value: '2-1',
},
{
label: '类型2-2',
value: '2-2',
children: [
{
label: '类型2-2-1',
value: '2-2-1',
},
{
label: '类型2-2-2',
value: '2-2-2',
},
],
},
],
},
],
},
});
function handleTypeSelect(key) {
emit('update:type', key);
}
</script>
<style lang="scss" scoped>
.input_supplies_type_menu_ {
height: 50px;
border: none;
font-weight: bold;
}
</style>

View File

@ -1,16 +1,72 @@
<template>
<CustomCard>
<section>肥料</section>
<h2>肥料基本信息</h2>
<TypeMenu v-model:type="type" />
<br />
<avue-crud ref="crud" v-model:page="pageData" :data="data" :option="option"></avue-crud>
</CustomCard>
</template>
<script setup>
import { ref } from 'vue';
import { ref, watch } from 'vue';
import CustomCard from '@/components/CustomCard.vue';
import TypeMenu from '../../common/TypeMenu.vue';
import { CRUD_OPTIONS } from '@/config';
/* --------------- data --------------- */
// #region
const type = ref('');
watch(
() => type.value,
() => {
console.log(type.value);
},
{
deep: true,
}
);
const crud = ref();
const data = ref([]);
const pageData = ref({
total: 0,
currentPage: 1,
pageSize: 10,
});
const option = ref({
CRUD_OPTIONS,
selection: false,
column: [
{
prop: '',
label: '编号',
},
{
prop: '',
label: '名称',
},
{
prop: '',
label: '厂家',
},
{
prop: '',
label: '经销商',
},
{
prop: '',
label: '化学成分',
},
{
prop: '',
label: '产品规格',
},
{
prop: '',
label: '保质期',
},
],
});
// #endregion
/* --------------- methods --------------- */
@ -19,4 +75,10 @@ import CustomCard from '@/components/CustomCard.vue';
// #endregion
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
h2 {
font-size: 24px;
font-weight: bold;
font-family: '黑体';
}
</style>

View File

@ -1,15 +1,84 @@
<template>
<CustomCard>
<section>农药</section>
<h2>农药基本信息</h2>
<TypeMenu v-model:type="type" />
<br />
<avue-crud ref="crud" v-model:page="pageData" :data="data" :option="option"></avue-crud>
</CustomCard>
</template>
<script setup>
import { ref } from 'vue';
import { ref, watch } from 'vue';
import CustomCard from '@/components/CustomCard.vue';
import TypeMenu from '../../common/TypeMenu.vue';
import { CRUD_OPTIONS } from '@/config';
/* --------------- data --------------- */
// #region
const type = ref('');
watch(
() => type.value,
() => {
console.log(type.value);
},
{
deep: true,
}
);
const crud = ref();
const data = ref([]);
const pageData = ref({
total: 0,
currentPage: 1,
pageSize: 10,
});
const option = ref({
CRUD_OPTIONS,
selection: false,
column: [
{
prop: '',
label: '农药编号',
},
{
prop: '',
label: '名称',
},
{
prop: '',
label: '厂家',
},
{
prop: '',
label: '经销商',
},
{
prop: '',
label: '防治对象',
},
{
prop: '',
label: '化学成分',
},
{
prop: '',
label: '加工剂型',
},
{
prop: '',
label: '产品规格',
},
{
prop: '',
label: '毒性',
},
{
prop: '',
label: '保质期',
},
],
});
// #endregion
/* --------------- methods --------------- */
@ -18,4 +87,10 @@ import CustomCard from '@/components/CustomCard.vue';
// #endregion
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
h2 {
font-size: 24px;
font-weight: bold;
font-family: '黑体';
}
</style>

View File

@ -27,8 +27,8 @@
{{ row.isUpload != '1' ? '是' : '否' }}
</template>
<template #menu-left>
<el-button type="success" icon="upload" @click="handleImport">导入</el-button>
<el-button type="success" icon="download" @click="handleExport">导出</el-button>
<el-button type="success" icon="upload" @click="onUpload">导入</el-button>
</template>
<template #menu="{ row }">
<el-button type="info" link @click="handleView(row)">查看</el-button>
@ -51,6 +51,12 @@
<Attrs v-model:attrs="landAttrs" :view="type" />
</template>
</avue-crud>
<custom-import-excel
ref="importExcelRef"
:template-url="getAssetsFile('template/土地模版表.xlsx')"
@on-download="onDownloadExcel"
@on-confirm="onUploadExcel"
/>
</CustomCard>
</template>
@ -60,22 +66,28 @@ import CustomCard from '@/components/CustomCard';
import { CRUD_OPTIONS } from '@/config';
import { useUserStore } from '@/store/modules/user';
import { getLandsList, exportLands, delLand, saveLand, importLands } from '@/apis/land.js';
import { getLandTypeTree } from '@/apis/baseInfo';
import { ElMessage } from 'element-plus';
import useLandHook from './useLandHook';
import Attrs from './common/Attrs.vue';
import { getAssetsFile, downloadFile } from '@/utils';
import { useApp } from '@/hooks';
const { landType, landsType, landClassificationType, handleIficationType } = useLandHook();
const app = useApp();
const { landType, landsType } = useLandHook();
const { VITE_APP_BASE_API } = import.meta.env;
const UserStore = useUserStore();
onMounted(() => {
getList();
getLandTree();
});
const params = ref({
zoom: 10,
});
const local_ = ref([102.833669, 24.88149, '昆明市']);
const local = ref(JSON.parse(JSON.stringify(local_.value)));
const landTreeDic = ref([]);
/* --------------- data --------------- */
// #region
const loading = ref(false);
@ -127,7 +139,7 @@ const option = reactive({
label: '农用地分类',
prop: 'landClassificationType',
select: 'select',
dicData: landClassificationType,
dicData: landTreeDic,
addDisplay: false,
display: false,
editDisplay: false,
@ -166,6 +178,9 @@ const option = reactive({
addDisplay: false,
display: false,
editDisplay: false,
render: ({ row }) => {
return row.soilType;
},
},
{
label: '是否上传附件',
@ -219,9 +234,9 @@ const option = reactive({
},
{
label: '用地分类',
prop: 'landClassificationType',
type: 'select',
dicData: landClassificationType,
prop: 'landTypeId',
type: 'cascader',
dicData: landTreeDic,
viewDisplay: false,
rules: [
{
@ -233,7 +248,7 @@ const option = reactive({
},
{
label: '用地分类',
prop: 'landClassificationTypeView',
prop: 'landClassificationType',
addDisplay: false,
},
{
@ -288,9 +303,29 @@ const option = reactive({
label: '产权人',
prop: 'owner',
},
{
label: '土壤类型',
prop: 'soilTypeId',
type: 'select',
viewDisplay: false,
dicUrl: `${VITE_APP_BASE_API}/land-resource/baseInfo/soilTypePage`,
dicQuery: {
current: 1,
size: 9999,
},
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res.data.records ?? [],
props: {
value: 'id',
label: 'soilType',
},
},
{
label: '土壤类型',
prop: 'soilType',
addDisplay: false,
},
],
},
@ -369,6 +404,7 @@ const attrs = ref([]);
const landOwnerAttrs = ref([]);
const landAttrs = ref([]);
const rowData = ref([]);
const importExcelRef = ref();
// #endregion
/* --------------- methods --------------- */
@ -390,7 +426,6 @@ async function getList() {
data.value.forEach((v) => {
v.isTransfer = v.landTransfer || 1;
v.isTransferView = v.landTransfer == 1 ? '否' : '是';
v.landClassificationTypeView = handleIficationType(v.handleIficationType);
v.coordinateView = v.coordinate;
});
pageData.value.total = total;
@ -421,24 +456,6 @@ async function handleResetSearch() {
await getList();
}
const attrNames = reactive(landsType.map((v) => v.label));
function handleImport() {
let inp = document.createElement('input');
inp.type = 'file';
inp.onchange = fileUp;
document.body.appendChild(inp);
inp.click();
document.body.removeChild(inp);
}
async function fileUp(e) {
let formData = new FormData();
formData.append('file', e.target.files[0]);
formData.append('landType', landType.value);
const res = await importLands(formData);
if (res.code == 200) {
ElMessage.success('导入成功');
getList();
}
}
async function handleExport() {
let res = await exportLands({
landType: landType.value,
@ -500,7 +517,6 @@ function handleCloseFrom(done) {
local.value = JSON.parse(JSON.stringify(local_.value));
done();
}
async function handleRowSave(val, done, loading) {
let data = JSON.parse(JSON.stringify(val));
data.isDraftsSave = 0;
@ -521,6 +537,7 @@ async function handleRowSave(val, done, loading) {
data.landCertificateUrl = landOwnerUrls.join();
data.landUrl = landUrls.join();
data.villageCode = data.villageCode[data.villageCode.length - 1] || '';
data.landTypeId = data.landTypeId[data.landTypeId.length - 1];
if (local.value.length != 0) {
data.coordinate = `${local.value[0]}E,${local.value[1]}N`;
}
@ -534,6 +551,50 @@ async function handleRowSave(val, done, loading) {
done();
}
}
//
const onUpload = () => {
importExcelRef?.value && importExcelRef.value.show();
};
const onDownloadExcel = (url) => {
downloadFile(url, `土地模版表.xlsx`);
};
const onUploadExcel = (formData) => {
formData.append('landType', landType.value);
importLands(formData)
.then((res) => {
if (res.status === 200) {
app.$message.success('导入成功!');
}
})
.catch((err) => {
app.$message.error('导入失败!');
importExcelRef.value.clear();
})
.finally(() => {
importExcelRef.value.hide();
});
};
async function getLandTree() {
let res = await getLandTypeTree();
if (res.code == 200) {
landTreeDic.value = newTree(res.data, 0);
console.log('landTreeDic', landTreeDic.value);
}
}
function newTree(arr, i) {
arr.forEach((v) => {
if (i == 0) {
v.value = v.id;
v.label = v.prentLandType;
v.disabled = !v.children || !v.children.length;
} else {
v.value = v.id;
v.label = v.childLandCategory;
}
if (v.children) v.children = newTree(v.children, i + 1);
});
return arr;
}
// #endregion
</script>