2025-07-16 15:07:58 +08:00
|
|
|
<script setup lang="ts">
|
2025-07-16 15:12:35 +08:00
|
|
|
import { ref, computed } from 'vue';
|
2025-07-16 15:07:58 +08:00
|
|
|
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,
|
2025-07-16 15:37:23 +08:00
|
|
|
SearchKeyword: '',
|
2025-07-16 15:07:58 +08:00
|
|
|
});
|
|
|
|
|
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,
|
2025-07-16 15:37:23 +08:00
|
|
|
SearchKeyword: query.value.SearchKeyword,
|
2025-07-16 15:07:58 +08:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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;
|
2025-07-16 15:37:23 +08:00
|
|
|
query.value.SearchKeyword = value;
|
2025-07-16 15:07:58 +08:00
|
|
|
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();
|
2025-07-16 16:11:21 +08:00
|
|
|
|
|
|
|
|
// 暴露方法给父组件调用
|
|
|
|
|
defineExpose({
|
|
|
|
|
getSelectedDevice: () => {
|
|
|
|
|
if (props.value) {
|
|
|
|
|
return options.value.find(option => option.value === props.value);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-07-16 15:07:58 +08:00
|
|
|
</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 }"
|
2025-07-16 15:12:35 +08:00
|
|
|
style="cursor: pointer; width: 16px; height: 16px;"
|
2025-07-16 15:07:58 +08:00
|
|
|
/>
|
|
|
|
|
<div>{{ `${query.pageIndex}/${maxPage}` }}</div>
|
|
|
|
|
<ChevronRight
|
|
|
|
|
@click="changePage(1)"
|
|
|
|
|
:class="{ 'text-gray-400': query.pageIndex >= maxPage }"
|
2025-07-16 15:12:35 +08:00
|
|
|
style="cursor: pointer; width: 16px; height: 16px;"
|
2025-07-16 15:07:58 +08:00
|
|
|
/>
|
|
|
|
|
</Row>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</Select>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.text-gray-400 {
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
cursor: not-allowed !important;
|
|
|
|
|
}
|
|
|
|
|
</style>
|