实现设备数据下拉框分页搜索
This commit is contained in:
parent
686c3c0275
commit
f131a34f1e
@ -111,6 +111,7 @@ export type ComponentType =
|
|||||||
| 'CheckboxGroup'
|
| 'CheckboxGroup'
|
||||||
| 'DatePicker'
|
| 'DatePicker'
|
||||||
| 'DefaultButton'
|
| 'DefaultButton'
|
||||||
|
| 'DeviceSelect'
|
||||||
| 'Divider'
|
| 'Divider'
|
||||||
| 'IconPicker'
|
| 'IconPicker'
|
||||||
| 'Input'
|
| 'Input'
|
||||||
@ -168,6 +169,10 @@ async function initComponentAdapter() {
|
|||||||
Checkbox,
|
Checkbox,
|
||||||
CheckboxGroup,
|
CheckboxGroup,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
|
// 自定义设备选择组件
|
||||||
|
DeviceSelect: defineAsyncComponent(() =>
|
||||||
|
import('../../views/dataManger/deviceData/DeviceSelect.vue')
|
||||||
|
),
|
||||||
// 自定义默认按钮
|
// 自定义默认按钮
|
||||||
DefaultButton: (props, { attrs, slots }) => {
|
DefaultButton: (props, { attrs, slots }) => {
|
||||||
return h(Button, { ...props, attrs, type: 'default' }, slots);
|
return h(Button, { ...props, attrs, type: 'default' }, slots);
|
||||||
|
|||||||
160
apps/web-antd/src/views/dataManger/deviceData/DeviceSelect.vue
Normal file
160
apps/web-antd/src/views/dataManger/deviceData/DeviceSelect.vue
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch } from 'vue';
|
||||||
|
import { Select, Divider, Row } from 'ant-design-vue';
|
||||||
|
import { ChevronLeft, ChevronRight } from '@vben/icons';
|
||||||
|
import { postMetersPage } from '#/api-client';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
allowClear?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
placeholder: $t('common.pleaseSelect') + $t('abp.log.deviceInfo'),
|
||||||
|
disabled: false,
|
||||||
|
allowClear: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:value': [string];
|
||||||
|
change: [string];
|
||||||
|
'device-change': [any]; // 添加设备信息变化事件
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const VNodes = (_, { attrs }: any) => {
|
||||||
|
return attrs.vnodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = ref<any[]>([]);
|
||||||
|
const query = ref({
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
meterName: '',
|
||||||
|
});
|
||||||
|
const total = ref(0);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
|
||||||
|
// 最大页码
|
||||||
|
const maxPage = computed(() => {
|
||||||
|
return Math.ceil(total.value / query.value.pageSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备列表数据
|
||||||
|
*/
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const { data } = await postMetersPage({
|
||||||
|
body: {
|
||||||
|
pageIndex: query.value.pageIndex,
|
||||||
|
pageSize: query.value.pageSize,
|
||||||
|
meterName: query.value.meterName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data?.items) {
|
||||||
|
options.value = data.items.map((item) => ({
|
||||||
|
label: item.meterName,
|
||||||
|
value: item.id,
|
||||||
|
...item, // 保留完整数据
|
||||||
|
}));
|
||||||
|
total.value = data.totalCount || 0;
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设备列表失败:', error);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下页
|
||||||
|
* @param type 1: 下一页, 0: 上一页
|
||||||
|
*/
|
||||||
|
const changePage = (type: number) => {
|
||||||
|
if (type === 1) {
|
||||||
|
if (query.value.pageIndex >= maxPage.value) return;
|
||||||
|
query.value.pageIndex += 1;
|
||||||
|
fetchData();
|
||||||
|
} else {
|
||||||
|
if (query.value.pageIndex <= 1) return;
|
||||||
|
query.value.pageIndex -= 1;
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备搜索
|
||||||
|
*/
|
||||||
|
const fetchDevice = useDebounceFn((value: string) => {
|
||||||
|
query.value.pageIndex = 1;
|
||||||
|
query.value.meterName = value;
|
||||||
|
fetchData();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// 处理值变化
|
||||||
|
const handleValueChange = (value: string) => {
|
||||||
|
emit('update:value', value);
|
||||||
|
emit('change', value);
|
||||||
|
|
||||||
|
// 发送选中的设备信息
|
||||||
|
if (value) {
|
||||||
|
const selectedDevice = options.value.find(option => option.value === value);
|
||||||
|
if (selectedDevice) {
|
||||||
|
emit('device-change', selectedDevice);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit('device-change', null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化加载数据
|
||||||
|
fetchData();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Select
|
||||||
|
:value="value"
|
||||||
|
:showSearch="true"
|
||||||
|
@search="fetchDevice"
|
||||||
|
:options="options"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:filter-option="false"
|
||||||
|
:disabled="disabled"
|
||||||
|
:allowClear="allowClear"
|
||||||
|
:loading="loading"
|
||||||
|
@change="handleValueChange"
|
||||||
|
>
|
||||||
|
<template #dropdownRender="{ menuNode: menu }">
|
||||||
|
<v-nodes :vnodes="menu" />
|
||||||
|
<Divider style="margin: 4px 0" />
|
||||||
|
<div @mousedown="(e) => e.preventDefault()">
|
||||||
|
<Row type="flex" justify="space-around" align="middle">
|
||||||
|
<ChevronLeft
|
||||||
|
@click="changePage(0)"
|
||||||
|
:class="{ 'text-gray-400': query.pageIndex <= 1 }"
|
||||||
|
style="cursor: pointer;"
|
||||||
|
/>
|
||||||
|
<div>{{ `${query.pageIndex}/${maxPage}` }}</div>
|
||||||
|
<ChevronRight
|
||||||
|
@click="changePage(1)"
|
||||||
|
:class="{ 'text-gray-400': query.pageIndex >= maxPage }"
|
||||||
|
style="cursor: pointer;"
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.text-gray-400 {
|
||||||
|
color: #9ca3af;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
120
apps/web-antd/src/views/dataManger/deviceData/index copy.vue
Normal file
120
apps/web-antd/src/views/dataManger/deviceData/index copy.vue
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
|
import { message, Select, Divider, Row } from 'ant-design-vue';
|
||||||
|
import { getUserListApi } from '/@/api/sys/user';
|
||||||
|
import { baggageClerkFormSchema } from '../baggageClerk.data';
|
||||||
|
import type { SelectProps } from 'ant-design-vue';
|
||||||
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
const isUpdate = ref(true);
|
||||||
|
const [registerForm] = useForm({
|
||||||
|
labelWidth: 130,
|
||||||
|
baseColProps: { span: 24 },
|
||||||
|
schemas: baggageClerkFormSchema,
|
||||||
|
showActionButtonGroup: false,
|
||||||
|
actionColOptions: {
|
||||||
|
span: 23,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 代码实现:---------------------------------------------------------------------
|
||||||
|
|
||||||
|
const VNodes = (_, { attrs }) => {
|
||||||
|
return attrs.vnodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = ref<SelectProps['options']>([]);
|
||||||
|
const query = ref({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
name: '',
|
||||||
|
});
|
||||||
|
const total = ref(0);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
|
||||||
|
// 最大页码
|
||||||
|
const maxPage = computed(() => {
|
||||||
|
return Math.ceil(total.value / query.value.pageSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户列表数据
|
||||||
|
*/
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getUserListApi({
|
||||||
|
page: query.value.page,
|
||||||
|
pageSize: query.value.pageSize,
|
||||||
|
name: query.value.name,
|
||||||
|
});
|
||||||
|
loading.value = false;
|
||||||
|
options.value = res.items.map(({ id: value, nickname: label }) => ({ label, value }));
|
||||||
|
total.value = res.total;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
message.error('数据加载失败!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下页
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
const changePage = (type) => {
|
||||||
|
if (type === 1) {
|
||||||
|
if (query.value.page >= maxPage.value) return;
|
||||||
|
query.value.page += 1;
|
||||||
|
fetchData();
|
||||||
|
} else {
|
||||||
|
if (query.value.page == 1) return;
|
||||||
|
query.value.page -= 1;
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户搜索
|
||||||
|
*/
|
||||||
|
const fetchUser = useDebounceFn((value) => {
|
||||||
|
query.value.page = 1;
|
||||||
|
query.value.name = value;
|
||||||
|
fetchData();
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- 注意 :
|
||||||
|
这里要把filter-option设为false,因为select的filter-option默认为true,
|
||||||
|
当使用onSearch获取的数据后,会将数据再过滤一遍,导致获取到数据,视图无变化
|
||||||
|
-->
|
||||||
|
<BasicForm @register="registerForm">
|
||||||
|
<template #adminIdSlot="{ model, field }">
|
||||||
|
<Select
|
||||||
|
v-model:value="model[field]"
|
||||||
|
:showSearch="true"
|
||||||
|
@search="fetchUser"
|
||||||
|
:options="options"
|
||||||
|
placeholder="请选择管理员"
|
||||||
|
:filter-option="false"
|
||||||
|
:disabled="isUpdate"
|
||||||
|
>
|
||||||
|
<template #dropdownRender="{ menuNode: menu }">
|
||||||
|
<v-nodes :vnodes="menu" />
|
||||||
|
<Divider style="margin: 4px 0" />
|
||||||
|
<div @mousedown="(e) => e.preventDefault()">
|
||||||
|
<Row type="flex" justify="space-around" align="middle">
|
||||||
|
<LeftOutlined @click="changePage(0)" />
|
||||||
|
<div>{{ `${query.page}/${maxPage}` }}</div>
|
||||||
|
<RightOutlined @click="changePage(1)" />
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Select>
|
||||||
|
</template>
|
||||||
|
</BasicForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
@ -20,8 +20,10 @@ defineOptions({
|
|||||||
|
|
||||||
// 存储设备信息选项的完整数据
|
// 存储设备信息选项的完整数据
|
||||||
const deviceOptions = ref<any[]>([]);
|
const deviceOptions = ref<any[]>([]);
|
||||||
|
// 当前选中的设备信息
|
||||||
|
const selectedDeviceInfo = ref<any>(null);
|
||||||
|
|
||||||
// 获取设备信息的完整数据
|
// 获取设备信息的完整数据(用于根据设备ID获取设备信息)
|
||||||
const fetchDeviceOptions = async () => {
|
const fetchDeviceOptions = async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await postMetersPage({
|
const { data } = await postMetersPage({
|
||||||
@ -45,6 +47,12 @@ const getDeviceInfoById = (deviceId: string) => {
|
|||||||
return deviceOptions.value.find((device) => device.id === deviceId);
|
return deviceOptions.value.find((device) => device.id === deviceId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理设备选择变化
|
||||||
|
const handleDeviceChange = (deviceInfo: any) => {
|
||||||
|
selectedDeviceInfo.value = deviceInfo;
|
||||||
|
console.log('设备选择变化:', deviceInfo);
|
||||||
|
};
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { DeviceType, DeviceId, FocusAddress, SystemName } = route.query;
|
const { DeviceType, DeviceId, FocusAddress, SystemName } = route.query;
|
||||||
|
|
||||||
@ -122,6 +130,10 @@ const formOptions: VbenFormProps = {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 添加事件处理函数
|
||||||
|
events: {
|
||||||
|
handleDeviceChange,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const gridOptions: VxeGridProps<any> = {
|
const gridOptions: VxeGridProps<any> = {
|
||||||
@ -173,20 +185,20 @@ const gridOptions: VxeGridProps<any> = {
|
|||||||
// 处理DeviceId,当设备类型为集中器(10)时,使用focusId
|
// 处理DeviceId,当设备类型为集中器(10)时,使用focusId
|
||||||
let finalDeviceId = formValues.DeviceId || DeviceId;
|
let finalDeviceId = formValues.DeviceId || DeviceId;
|
||||||
let finalFocusAddress = formValues.FocusAddress;
|
let finalFocusAddress = formValues.FocusAddress;
|
||||||
if (formValues.DeviceId) {
|
|
||||||
const deviceInfo = getDeviceInfoById(formValues.DeviceId);
|
// 优先使用选中的设备信息
|
||||||
if (deviceInfo) {
|
const deviceInfo = selectedDeviceInfo.value || (formValues.DeviceId ? getDeviceInfoById(formValues.DeviceId) : null);
|
||||||
finalFocusAddress = deviceInfo.focusAddress;
|
if (deviceInfo) {
|
||||||
if (deviceTypeNumber === 10) {
|
finalFocusAddress = deviceInfo.focusAddress;
|
||||||
// 集中器类型使用focusId
|
if (deviceTypeNumber === 10) {
|
||||||
if (deviceInfo.focusId) {
|
// 集中器类型使用focusId
|
||||||
finalDeviceId = deviceInfo.focusId;
|
if (deviceInfo.focusId) {
|
||||||
}
|
finalDeviceId = deviceInfo.focusId;
|
||||||
} else {
|
}
|
||||||
// 其他设备类型使用meterId
|
} else {
|
||||||
if (deviceInfo.meterId) {
|
// 其他设备类型使用meterId
|
||||||
finalDeviceId = deviceInfo.meterId;
|
if (deviceInfo.meterId) {
|
||||||
}
|
finalDeviceId = deviceInfo.meterId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,46 +106,13 @@ export const querySchema = computed(() => [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: 'ApiSelect',
|
component: 'DeviceSelect',
|
||||||
fieldName: 'DeviceId',
|
fieldName: 'DeviceId',
|
||||||
label: $t('abp.log.deviceInfo'),
|
label: $t('abp.log.deviceInfo'),
|
||||||
componentProps: {
|
componentProps: {
|
||||||
api: postMetersPage,
|
|
||||||
params: {
|
|
||||||
body: {
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 1000, // 获取足够多的数据用于下拉选择
|
|
||||||
},
|
|
||||||
},
|
|
||||||
labelField: 'meterName',
|
|
||||||
valueField: 'id', // 使用id作为值,这样可以获取完整的对象
|
|
||||||
optionsPropName: 'options',
|
|
||||||
immediate: true,
|
|
||||||
showSearch: true,
|
|
||||||
allowClear: true,
|
|
||||||
placeholder: $t('common.pleaseSelect') + $t('abp.log.deviceInfo'),
|
placeholder: $t('common.pleaseSelect') + $t('abp.log.deviceInfo'),
|
||||||
filterOption: false, // 禁用本地过滤,使用服务端搜索
|
allowClear: true,
|
||||||
optionFilterProp: 'label', // 根据 label 进行过滤
|
onDeviceChange: 'handleDeviceChange',
|
||||||
afterFetch: (res: any) => {
|
|
||||||
// 确保返回的是数组格式
|
|
||||||
if (Array.isArray(res)) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
// 如果是包装在 items 中的,提取出来
|
|
||||||
if (res && Array.isArray(res.items)) {
|
|
||||||
return res.items;
|
|
||||||
}
|
|
||||||
// 如果是包装在 data 中的,提取出来
|
|
||||||
if (res && Array.isArray(res.data)) {
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
// 如果是包装在 data.items 中的,提取出来
|
|
||||||
if (res && res.data && Array.isArray(res.data.items)) {
|
|
||||||
return res.data.items;
|
|
||||||
}
|
|
||||||
// 如果都不是,返回空数组
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user