Commit 72f924ee95ccddd3f39aa45e5cc9fd84d98ae65b

Authored by xp.Huang
2 parents fa8080ad b1cb3fac

Merge branch 'ww' into 'main'

fix: BUG in teambition

See merge request huang/yun-teng-iot-front!410
... ... @@ -9,7 +9,7 @@ export const getDeviceProfile = () => {
9 9 };
10 10
11 11 // 获取历史数据
12   -export const getDeviceHistoryInfo = (params) => {
  12 +export const getDeviceHistoryInfo = (params: Recordable) => {
13 13 return defHttp.get<HistoryData>(
14 14 {
15 15 url: `/plugins/telemetry/DEVICE/${params.entityId}/values/timeseries`,
... ...
... ... @@ -10,6 +10,7 @@ import {
10 10 } from './tenantInfo';
11 11 import { defHttp } from '/@/utils/http/axios';
12 12 import { BasicPageParams } from '/@/api/model/baseModel';
  13 +import { PaginationResult } from '/#/axios';
13 14 export type QueryTenantProfilesParam = BasicPageParams & OtherParams;
14 15 export type DeleteTenantProfilesParam = OtherParams;
15 16 export type OtherParams = {
... ... @@ -47,7 +48,7 @@ export async function deleteTenantProfileApi(ids: string) {
47 48 }
48 49
49 50 export const getTableTenantProfileApi = (params?: QueryTenantProfilesParam) => {
50   - return defHttp.get({
  51 + return defHttp.get<PaginationResult>({
51 52 url: Api.getTenantProfile,
52 53 params,
53 54 });
... ... @@ -67,12 +68,12 @@ export const setTenantProfileIsDefaultApi = (id: string, v, params?: {}) => {
67 68 };
68 69
69 70 export const selectTenantProfileApi = async (params?: QueryTenantProfilesParam) => {
70   - const { items } = await getTableTenantProfileApi(params);
  71 + const { items, total } = await getTableTenantProfileApi(params);
71 72 items.forEach((item) => {
72 73 item.label = item.name;
73 74 item.value = item.id.id;
74 75 });
75   - return Promise.resolve<any[]>(items);
  76 + return { items, total };
76 77 };
77 78
78 79 export async function saveTenantProfileApi(params: tenantProfileDTO) {
... ...
... ... @@ -37,6 +37,7 @@ import ApiUpload from './components/ApiUpload.vue';
37 37 import ApiSearchSelect from './components/ApiSearchSelect.vue';
38 38 import CustomMinMaxInput from './externalCompns/components/CustomMinMaxInput.vue';
39 39 import StructForm from './externalCompns/components/StructForm/StructForm.vue';
  40 +import ApiSelectScrollLoad from './components/ApiSelectScrollLoad.vue';
40 41
41 42 const componentMap = new Map<ComponentType, Component>();
42 43
... ... @@ -81,6 +82,7 @@ componentMap.set('ApiUpload', ApiUpload);
81 82 componentMap.set('ApiSearchSelect', ApiSearchSelect);
82 83 componentMap.set('CustomMinMaxInput', CustomMinMaxInput);
83 84 componentMap.set('StructForm', StructForm);
  85 +componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad);
84 86
85 87 export function add(compName: ComponentType, component: Component) {
86 88 componentMap.set(compName, component);
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: true,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import { ref, watchEffect, computed, unref, watch, reactive } from 'vue';
  8 + import { Select, Spin } from 'ant-design-vue';
  9 + import { isFunction } from '/@/utils/is';
  10 + import { useRuleFormItem } from '/@/hooks/component/useFormItem';
  11 + import { useAttrs } from '/@/hooks/core/useAttrs';
  12 + import { get, omit } from 'lodash-es';
  13 + import { LoadingOutlined } from '@ant-design/icons-vue';
  14 + import { useI18n } from '/@/hooks/web/useI18n';
  15 + import { PaginationResult } from '/#/axios';
  16 + import { useDebounceFn } from '@vueuse/core';
  17 +
  18 + type OptionsItem = { label: string; value: string; disabled?: boolean };
  19 +
  20 + type Pagination = Record<'page' | 'pageSize', number>;
  21 +
  22 + const emit = defineEmits(['options-change', 'change']);
  23 + const props = withDefaults(
  24 + defineProps<{
  25 + value?: Recordable | number | string;
  26 + numberToString?: boolean;
  27 + api?: (arg?: Recordable) => Promise<PaginationResult<OptionsItem>>;
  28 + params?: Recordable;
  29 + resultField?: string;
  30 + labelField?: string;
  31 + valueField?: string;
  32 + immediate?: boolean;
  33 + pagenation?: Pagination;
  34 + queryEmptyDataAgin?: boolean;
  35 + }>(),
  36 + {
  37 + resultField: '',
  38 + labelField: 'label',
  39 + valueField: 'value',
  40 + immediate: true,
  41 + queryEmptyDataAgin: true,
  42 + pagenation: () => ({ page: 1, pageSize: 10 }),
  43 + }
  44 + );
  45 +
  46 + const OptionsItem = (_, { attrs }: { attrs: { vNode: any } }) => attrs.vNode;
  47 +
  48 + const options = ref<OptionsItem[]>([]);
  49 + const pagination = reactive(Object.assign({ total: 0, page: 1, pageSize: 10 }, props.pagenation));
  50 + const scrollLoading = ref(false);
  51 + const lock = ref(false);
  52 + const loading = ref(false);
  53 + const isFirstLoad = ref(true);
  54 + const emitData = ref<any[]>([]);
  55 + const attrs = useAttrs();
  56 + const { t } = useI18n();
  57 +
  58 + // Embedded in the form, just use the hook binding to perform form verification
  59 + const [state] = useRuleFormItem(props, 'value', 'change', emitData);
  60 +
  61 + const getOptions = computed(() => {
  62 + const { labelField, valueField, numberToString } = props;
  63 +
  64 + return unref(options).reduce((prev, next: Recordable) => {
  65 + if (next) {
  66 + const value = get(next, valueField);
  67 + prev.push({
  68 + label: next[labelField],
  69 + value: numberToString ? `${value}` : value,
  70 + ...omit(next, [labelField, valueField]),
  71 + });
  72 + }
  73 + return prev;
  74 + }, [] as OptionsItem[]);
  75 + });
  76 +
  77 + watchEffect(() => {
  78 + props.immediate && isFirstLoad.value && fetch();
  79 + });
  80 +
  81 + watch(
  82 + () => props.params,
  83 + () => {
  84 + !unref(isFirstLoad) && fetch();
  85 + },
  86 + { deep: true }
  87 + );
  88 +
  89 + async function fetch() {
  90 + const api = props.api;
  91 + if (!api || !isFunction(api)) return;
  92 + try {
  93 + !unref(getOptions).length ? (loading.value = true) : (scrollLoading.value = true);
  94 + lock.value = true;
  95 + const { total, items } = await api({
  96 + ...props.params,
  97 + page: pagination.page,
  98 + pageSize: pagination.pageSize,
  99 + });
  100 +
  101 + pagination.total = total;
  102 + if (Array.isArray(items)) {
  103 + options.value = [...options.value, ...items];
  104 + emitChange();
  105 + return;
  106 + }
  107 + if (props.resultField) {
  108 + options.value = [...options.value, ...(get(items, props.resultField) || [])];
  109 + }
  110 + emitChange();
  111 + } catch (error) {
  112 + pagination.page = Math.ceil(unref(getOptions).length / pagination.pageSize);
  113 + console.warn(error);
  114 + } finally {
  115 + isFirstLoad.value = false;
  116 + loading.value = false;
  117 + scrollLoading.value = false;
  118 + lock.value = false;
  119 + }
  120 + }
  121 +
  122 + async function handleFetch() {
  123 + if (!props.immediate && unref(isFirstLoad)) {
  124 + await fetch();
  125 + isFirstLoad.value = false;
  126 + }
  127 + }
  128 +
  129 + function emitChange() {
  130 + emit('options-change', unref(getOptions));
  131 + }
  132 +
  133 + function handleChange(_, ...args) {
  134 + emitData.value = args;
  135 + }
  136 +
  137 + async function handlePopupScroll(event: MouseEvent) {
  138 + const { scrollHeight, scrollTop, clientHeight } = event.target as HTMLDivElement;
  139 + if (scrollTop + clientHeight >= scrollHeight) {
  140 + if (unref(getOptions).length < pagination.total && !unref(lock)) {
  141 + pagination.page = pagination.page + 1;
  142 + await fetch();
  143 + }
  144 + }
  145 + }
  146 +
  147 + const debounceHandlePopupScroll = useDebounceFn(handlePopupScroll, 100);
  148 +</script>
  149 +
  150 +<template>
  151 + <Select
  152 + @dropdownVisibleChange="handleFetch"
  153 + v-bind="attrs"
  154 + @change="handleChange"
  155 + :options="getOptions"
  156 + v-model:value="state"
  157 + @popup-scroll="debounceHandlePopupScroll"
  158 + >
  159 + <template #[item]="data" v-for="item in Object.keys($slots)">
  160 + <slot :name="item" v-bind="data || {}"></slot>
  161 + </template>
  162 + <template #suffixIcon v-if="loading">
  163 + <LoadingOutlined spin />
  164 + </template>
  165 + <template #notFoundContent v-if="loading">
  166 + <span>
  167 + <LoadingOutlined spin class="mr-1" />
  168 + {{ t('component.form.apiSelectNotFound') }}
  169 + </span>
  170 + </template>
  171 + <template #dropdownRender="{ menuNode }">
  172 + <OptionsItem :vNode="menuNode" />
  173 + <div v-show="scrollLoading" class="flex justify-center">
  174 + <Spin size="small" />
  175 + </div>
  176 + </template>
  177 + </Select>
  178 +</template>
... ...
... ... @@ -118,4 +118,5 @@ export type ComponentType =
118 118 | 'IconDrawer'
119 119 | 'ApiUpload'
120 120 | 'ApiSearchSelect'
121   - | 'StructForm';
  121 + | 'StructForm'
  122 + | 'ApiSelectScrollLoad';
... ...
1 1 <script lang="ts" setup>
2   - import moment from 'moment';
3 2 import { nextTick, onMounted, onUnmounted, Ref, ref, unref } from 'vue';
4   - import { getDeviceDataKeys, getDeviceHistoryInfo } from '/@/api/alarm/position';
  3 + import { getDeviceHistoryInfo } from '/@/api/alarm/position';
5 4 import { Empty, Spin } from 'ant-design-vue';
6 5 import { useECharts } from '/@/hooks/web/useECharts';
7   - import { dateUtil } from '/@/utils/dateUtil';
8   - import {
9   - AggregateDataEnum,
10   - eChartOptions,
11   - selectDeviceAttrSchema,
12   - } from '/@/views/device/localtion/config.data';
  6 + import { AggregateDataEnum, selectDeviceAttrSchema } from '/@/views/device/localtion/config.data';
13 7 import { useTimePeriodForm } from '/@/views/device/localtion/cpns/TimePeriodForm';
14   - import { defaultSchemas, QueryWay } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
  8 + import { defaultSchemas } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
15 9 import TimePeriodForm from '/@/views/device/localtion/cpns/TimePeriodForm/TimePeriodForm.vue';
16 10 import { SchemaFiled } from '/@/views/report/config/config.data';
17 11 import { useGridLayout } from '/@/hooks/component/useGridLayout';
18 12 import { ColEx } from '/@/components/Form/src/types';
  13 + import { useHistoryData } from '../../hook/useHistoryData';
19 14
20 15 interface DeviceDetail {
21 16 tbDeviceId: string;
  17 + deviceProfileId: string;
22 18 }
23 19
24 20 const props = defineProps<{
... ... @@ -28,36 +24,12 @@
28 24
29 25 const chartRef = ref();
30 26
31   - const deviceAttrs = ref<string[]>([]);
32   -
33 27 const loading = ref(false);
34 28
35 29 const isNull = ref(false);
36 30
37   - function getSearchParams(value: Recordable) {
38   - const { startTs, endTs, interval, agg, limit, keys, way } = value;
39   - if (way === QueryWay.LATEST) {
40   - return {
41   - entityId: props.deviceDetail.tbDeviceId,
42   - keys: keys ? keys : unref(deviceAttrs).join(),
43   - startTs: moment().subtract(startTs, 'ms').valueOf(),
44   - endTs: Date.now(),
45   - interval,
46   - agg,
47   - limit,
48   - };
49   - } else {
50   - return {
51   - entityId: props.deviceDetail.tbDeviceId,
52   - keys: keys ? keys : unref(deviceAttrs).join(),
53   - startTs: moment(startTs).valueOf(),
54   - endTs: moment(endTs).valueOf(),
55   - interval,
56   - agg,
57   - limit,
58   - };
59   - }
60   - }
  31 + const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } =
  32 + useHistoryData();
61 33
62 34 function hasDeviceAttr() {
63 35 if (!unref(deviceAttrs).length) {
... ... @@ -69,28 +41,6 @@
69 41
70 42 const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
71 43
72   - function setChartOptions(data, keys?) {
73   - const dataArray: any[] = [];
74   - for (const key in data) {
75   - for (const item1 of data[key]) {
76   - let { ts, value } = item1;
77   - const time = dateUtil(ts).format('YYYY-MM-DD HH:mm:ss');
78   - value = Number(value).toFixed(2);
79   - dataArray.push([time, value, key]);
80   - }
81   - }
82   - keys = keys ? [keys] : unref(deviceAttrs);
83   - const series: any = keys.map((item) => {
84   - return {
85   - name: item,
86   - type: 'line',
87   - data: dataArray.filter((item1) => item1[2] === item),
88   - };
89   - });
90   - // 设置数据
91   - setOptions(eChartOptions(series, keys));
92   - }
93   -
94 44 const [register, method] = useTimePeriodForm({
95 45 schemas: [...defaultSchemas, ...selectDeviceAttrSchema],
96 46 baseColProps: useGridLayout(2, 3, 4) as unknown as ColEx,
... ... @@ -103,7 +53,10 @@
103 53 if (!hasDeviceAttr()) return;
104 54 // 发送请求
105 55 loading.value = true;
106   - const res = await getDeviceHistoryInfo(searchParams);
  56 + const res = await getDeviceHistoryInfo({
  57 + ...searchParams,
  58 + entityId: props.deviceDetail.tbDeviceId,
  59 + });
107 60 // 判断数据对象是否为空
108 61 if (!Object.keys(res).length) {
109 62 isNull.value = false;
... ... @@ -111,16 +64,19 @@
111 64 } else {
112 65 isNull.value = true;
113 66 }
114   - setChartOptions(res, value.keys);
  67 +
  68 + const selectedKeys = unref(deviceAttrs).find(
  69 + (item) => item.identifier === value[SchemaFiled.KEYS]
  70 + );
  71 +
  72 + setOptions(setChartOptions(res, selectedKeys));
115 73 loading.value = false;
116 74 },
117 75 });
118 76
119 77 const getDeviceDataKey = async () => {
120   - const { tbDeviceId } = props.deviceDetail || {};
121 78 try {
122   - deviceAttrs.value = (await getDeviceDataKeys(tbDeviceId)) || [];
123   -
  79 + await getDeviceAttribute(props.deviceDetail);
124 80 if (props.attr) {
125 81 method.setFieldsValue({ keys: props.attr });
126 82 }
... ... @@ -132,7 +88,7 @@
132 88 method.updateSchema({
133 89 field: 'keys',
134 90 componentProps: {
135   - options: unref(deviceAttrs).map((item) => ({ label: item, value: item })),
  91 + options: unref(deviceAttrs).map((item) => ({ label: item.name, value: item.identifier })),
136 92 },
137 93 });
138 94
... ... @@ -144,7 +100,7 @@
144 100
145 101 if (!hasDeviceAttr()) return;
146 102
147   - const keys = props.attr ? props.attr : unref(deviceAttrs).join();
  103 + const keys = props.attr ? props.attr : unref(getDeviceKeys).join();
148 104
149 105 const res = await getDeviceHistoryInfo({
150 106 entityId: props.deviceDetail.tbDeviceId,
... ... @@ -162,7 +118,9 @@
162 118 } else {
163 119 isNull.value = true;
164 120 }
165   - setChartOptions(res, props.attr);
  121 + const selectedKeys = unref(deviceAttrs).find((item) => item.identifier === props.attr);
  122 +
  123 + setOptions(setChartOptions(res, selectedKeys));
166 124 };
167 125
168 126 onMounted(async () => {
... ...
... ... @@ -233,7 +233,9 @@
233 233 <div>{{ item.value || '--' }}</div>
234 234 <div>{{ item.unit }}</div>
235 235 </div>
236   - <div class="text-dark-800 text-xs">{{ formatToDateTime(item.time) || '--' }}</div>
  236 + <div class="text-dark-800 text-xs">
  237 + {{ item.value ? formatToDateTime(item.time) : '--' }}
  238 + </div>
237 239 </section>
238 240 </Card>
239 241 </List.Item>
... ...
  1 +import { EChartsOption } from 'echarts';
  2 +import moment from 'moment';
  3 +import { computed, ref, unref } from 'vue';
  4 +import { eChartOptions } from '../../localtion/config.data';
  5 +import { HistoryData } from '/@/api/alarm/position/model';
  6 +import { getDeviceAttributes } from '/@/api/dataBoard';
  7 +import { DeviceAttributeRecord } from '/@/api/dataBoard/model';
  8 +import { dateUtil } from '/@/utils/dateUtil';
  9 +import { QueryWay } from '/@/views/report/config/config.data';
  10 +import { SchemaFiled } from '/@/views/visual/board/detail/config/historyTrend.config';
  11 +import { DEFAULT_DATE_FORMAT } from '/@/views/visual/board/detail/config/util';
  12 +
  13 +interface DeviceOption {
  14 + deviceProfileId: string;
  15 +}
  16 +
  17 +export function useHistoryData() {
  18 + const deviceAttrs = ref<DeviceAttributeRecord[]>([]);
  19 +
  20 + const getDeviceKeys = computed(() => {
  21 + return unref(deviceAttrs).map((item) => item.identifier);
  22 + });
  23 +
  24 + const getDeviceAttribute = async (record: DeviceOption) => {
  25 + try {
  26 + const { deviceProfileId } = record;
  27 + deviceAttrs.value = (await getDeviceAttributes({ deviceProfileId })) || [];
  28 + } catch (error) {
  29 + throw error;
  30 + }
  31 + };
  32 +
  33 + function getSearchParams(value: Partial<Record<SchemaFiled, string>>) {
  34 + const { startTs, endTs, interval, agg, limit, keys, way, deviceId } = value;
  35 + const basicRecord = {
  36 + entityId: deviceId,
  37 + keys: keys ? keys : unref(getDeviceKeys).join(),
  38 + interval,
  39 + agg,
  40 + limit,
  41 + };
  42 + if (way === QueryWay.LATEST) {
  43 + return Object.assign(basicRecord, {
  44 + startTs: moment().subtract(startTs, 'ms').valueOf(),
  45 + endTs: Date.now(),
  46 + });
  47 + } else {
  48 + return Object.assign(basicRecord, {
  49 + startTs: moment(startTs).valueOf(),
  50 + endTs: moment(endTs).valueOf(),
  51 + });
  52 + }
  53 + }
  54 +
  55 + function setChartOptions(
  56 + data: HistoryData,
  57 + keys?: DeviceAttributeRecord | DeviceAttributeRecord[]
  58 + ) {
  59 + const dataArray: [string, string, string][] = [];
  60 + for (const key in data) {
  61 + for (const item of data[key]) {
  62 + let { value } = item;
  63 + const { ts } = item;
  64 + const time = dateUtil(ts).format(DEFAULT_DATE_FORMAT);
  65 + value = Number(value).toFixed(2);
  66 + dataArray.push([time, value, key as string]);
  67 + }
  68 + }
  69 +
  70 + keys = keys ? [keys as DeviceAttributeRecord] : unref(deviceAttrs);
  71 + const legend = keys.map((item) => item.name);
  72 +
  73 + const series: EChartsOption['series'] = (keys as DeviceAttributeRecord[]).map((item) => {
  74 + return {
  75 + name: item.name,
  76 + type: 'line',
  77 + data: dataArray.filter((temp) => temp[2] === item.identifier),
  78 + };
  79 + });
  80 +
  81 + return eChartOptions(series, legend);
  82 + }
  83 +
  84 + return {
  85 + deviceAttrs,
  86 + getDeviceKeys,
  87 + getDeviceAttribute,
  88 + getSearchParams,
  89 + setChartOptions,
  90 + };
  91 +}
... ...
... ... @@ -78,11 +78,7 @@
78 78 import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
79 79 import { useModal, BasicModal } from '/@/components/Modal';
80 80 import { useECharts } from '/@/hooks/web/useECharts';
81   - import {
82   - getDeviceHistoryInfo,
83   - getDeviceDataKeys,
84   - getDeviceActiveTime,
85   - } from '/@/api/alarm/position';
  81 + import { getDeviceHistoryInfo, getDeviceActiveTime } from '/@/api/alarm/position';
86 82 import { useDrawer } from '/@/components/Drawer';
87 83 import DeviceDetailDrawer from '/@/views/device/list/cpns/modal/DeviceDetailDrawer.vue';
88 84 import moment from 'moment';
... ... @@ -96,12 +92,12 @@
96 92 import lx1 from '/@/assets/images/lx1.png';
97 93 import Loading from '/@/components/Loading/src/Loading.vue';
98 94 import { TimePeriodForm, useTimePeriodForm } from './cpns/TimePeriodForm';
99   - import { selectDeviceAttrSchema, eChartOptions } from './config.data';
  95 + import { selectDeviceAttrSchema } from './config.data';
100 96 import { defaultSchemas } from './cpns/TimePeriodForm/config';
101 97 import { QueryWay, SchemaFiled, AggregateDataEnum } from './cpns/TimePeriodForm/config';
102   - import { dateUtil } from '/@/utils/dateUtil';
103 98 import { Spin } from 'ant-design-vue';
104 99 import { useAsyncQueue } from './useAsyncQueue';
  100 + import { useHistoryData } from '../list/hook/useHistoryData';
105 101
106 102 interface DeviceInfo {
107 103 alarmStatus: 0 | 1;
... ... @@ -112,6 +108,7 @@
112 108 deviceProfile: { default: boolean; enabled: boolean; name: string; transportType: string };
113 109 deviceInfo: { longitude: string; latitude: string; address: string };
114 110 deviceType?: string;
  111 + deviceProfileId: string;
115 112 }
116 113 type MarkerList = DeviceInfo & { marker: any; label: any };
117 114
... ... @@ -142,8 +139,7 @@
142 139 let globalRecord: any = {};
143 140 const wrapRef = ref<HTMLDivElement | null>(null);
144 141 const chartRef = ref<HTMLDivElement | null>(null);
145   - const deviceAttrs = ref<string[]>([]);
146   - const { setOptions, getInstance, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
  142 + const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
147 143 const isNull = ref(true);
148 144 const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
149 145 const [registerDetailDrawer, { openDrawer }] = useDrawer();
... ... @@ -154,6 +150,9 @@
154 150
155 151 const loading = ref(false);
156 152
  153 + const { deviceAttrs, getDeviceKeys, getDeviceAttribute, getSearchParams, setChartOptions } =
  154 + useHistoryData();
  155 +
157 156 const [registerTable] = useTable({
158 157 api: devicePage,
159 158 columns,
... ... @@ -259,7 +258,7 @@
259 258 entityId = record.tbDeviceId;
260 259 globalRecord = record;
261 260 try {
262   - deviceAttrs.value = (await getDeviceDataKeys(entityId)) || [];
  261 + await getDeviceAttribute(record);
263 262 } catch (error) {}
264 263
265 264 const options = {
... ... @@ -350,7 +349,7 @@
350 349 if (!hasDeviceAttr()) return;
351 350 // 发送请求
352 351 loading.value = true;
353   - const res = await getDeviceHistoryInfo(searchParams);
  352 + const res = await getDeviceHistoryInfo({ ...searchParams, entityId });
354 353 loading.value = false;
355 354 // 判断数据对象是否为空
356 355 if (!Object.keys(res).length) {
... ... @@ -359,35 +358,13 @@
359 358 } else {
360 359 isNull.value = true;
361 360 }
362   - setChartOptions(res, value.keys);
  361 + const selectedKeys = unref(deviceAttrs).find(
  362 + (item) => item.identifier === value[SchemaFiled.KEYS]
  363 + );
  364 + setOptions(setChartOptions(res, selectedKeys));
363 365 },
364 366 });
365 367
366   - function getSearchParams(value: Recordable) {
367   - const { startTs, endTs, interval, agg, limit, keys, way } = value;
368   - if (way === QueryWay.LATEST) {
369   - return {
370   - entityId,
371   - keys: keys ? keys : unref(deviceAttrs).join(),
372   - startTs: moment().subtract(startTs, 'ms').valueOf(),
373   - endTs: Date.now(),
374   - interval,
375   - agg,
376   - limit,
377   - };
378   - } else {
379   - return {
380   - entityId,
381   - keys: keys ? keys : unref(deviceAttrs).join(),
382   - startTs: moment(startTs).valueOf(),
383   - endTs: moment(endTs).valueOf(),
384   - interval,
385   - agg,
386   - limit,
387   - };
388   - }
389   - }
390   -
391 368 const openHistoryModal = async () => {
392 369 openModal(true);
393 370
... ... @@ -395,7 +372,10 @@
395 372 method.updateSchema({
396 373 field: 'keys',
397 374 componentProps: {
398   - options: unref(deviceAttrs).map((item) => ({ label: item, value: item })),
  375 + options: unref(deviceAttrs).map((item) => ({
  376 + label: item.name,
  377 + value: item.identifier,
  378 + })),
399 379 },
400 380 });
401 381
... ... @@ -409,7 +389,7 @@
409 389
410 390 const res = await getDeviceHistoryInfo({
411 391 entityId,
412   - keys: unref(deviceAttrs).join(),
  392 + keys: unref(getDeviceKeys).join(),
413 393 startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
414 394 endTs: Date.now(),
415 395 agg: AggregateDataEnum.NONE,
... ... @@ -423,7 +403,7 @@
423 403 } else {
424 404 isNull.value = true;
425 405 }
426   - setChartOptions(res);
  406 + setOptions(setChartOptions(res));
427 407 };
428 408 function hasDeviceAttr() {
429 409 if (!unref(deviceAttrs).length) {
... ... @@ -435,29 +415,6 @@
435 415 }
436 416 }
437 417
438   - function setChartOptions(data, keys?) {
439   - const dataArray: any[] = [];
440   - for (const key in data) {
441   - for (const item1 of data[key]) {
442   - let { ts, value } = item1;
443   - const time = dateUtil(ts).format('YYYY-MM-DD HH:mm:ss');
444   - value = Number(value).toFixed(2);
445   - dataArray.push([time, value, key]);
446   - }
447   - }
448   - keys = keys ? [keys] : unref(deviceAttrs);
449   - const series: any = keys.map((item) => {
450   - return {
451   - name: item,
452   - type: 'line',
453   - data: dataArray.filter((item1) => item1[2] === item),
454   - };
455   - });
456   - resize();
457   - // 设置数据
458   - setOptions(eChartOptions(series, keys));
459   - }
460   -
461 418 const handleCancelModal = () => {
462 419 method.setFieldsValue({
463 420 [SchemaFiled.WAY]: QueryWay.LATEST,
... ...
1 1 import { BasicColumn } from '/@/components/Table/src/types/table';
2 2 import { FormSchema } from '/@/components/Form';
3 3 import { getAllRoleList } from '/@/api/system/system';
4   -import { selectTenantProfileApi } from '/@/api/tenant/tenantApi';
  4 +import { getTableTenantProfileApi, QueryTenantProfilesParam } from '/@/api/tenant/tenantApi';
5 5 import { RoleEnum } from '/@/enums/roleEnum';
6 6
7 7 export function getBasicColumns(): BasicColumn[] {
... ... @@ -123,16 +123,26 @@ export const tenantFormSchema: FormSchema[] = [
123 123 {
124 124 field: 'tenantProfileId',
125 125 label: '租户配置',
126   - component: 'ApiSelect',
  126 + component: 'ApiSelectScrollLoad',
127 127 required: true,
128   - defaultValue: 'Default',
129   - componentProps: {
130   - api: selectTenantProfileApi,
131   - showSearch: true,
132   - params: {
133   - page: 1,
134   - pageSize: 100,
135   - },
  128 + componentProps: ({ formActionType }) => {
  129 + const { setFieldsValue } = formActionType;
  130 + return {
  131 + api: async (params: QueryTenantProfilesParam) => {
  132 + const { items, total } = await getTableTenantProfileApi(params);
  133 + const firstRecord = items.at(0);
  134 + if (firstRecord) {
  135 + setFieldsValue({ tenantProfileId: firstRecord.id.id });
  136 + }
  137 + return { items, total };
  138 + },
  139 + showSearch: true,
  140 + labelField: 'name',
  141 + valueField: 'id.id',
  142 + filterOption: (inputValue: string, options: Record<'label' | 'value', string>) => {
  143 + return options.label.toLowerCase().includes(inputValue.toLowerCase());
  144 + },
  145 + };
136 146 },
137 147 },
138 148 {
... ...
... ... @@ -15,10 +15,10 @@
15 15 const emit = defineEmits(['register', 'ok']);
16 16
17 17 const [registerForm, { updateSchema, setFieldsValue, validate, getFieldsValue }] = useForm({
18   - schemas: formSchema,
  18 + schemas: formSchema(),
19 19 showActionButtonGroup: false,
20 20 fieldMapToTime: [
21   - [SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS], 'YYYY-MM-DD HH:ss'],
  21 + [SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS], 'YYYY-MM-DD HH:mm:ss'],
22 22 ],
23 23 });
24 24
... ...
... ... @@ -214,7 +214,7 @@
214 214 </script>
215 215
216 216 <template>
217   - <div class="w-full h-full flex justify-center items-center flex-col p-2 no-drag">
  217 + <div class="w-full h-full flex justify-center items-center flex-col p-2">
218 218 <div
219 219 class="w-full flex"
220 220 v-if="props.layout?.componentType === FrontComponent.MAP_COMPONENT_TRACK_HISTORY"
... ... @@ -241,8 +241,12 @@
241 241 </span>
242 242 </Button>
243 243 </div>
244   - <Spin class="w-full h-full" :spinning="!prepare" tip="Loading..." />
245   - <div ref="wrapRef" :id="wrapId" class="w-full h-full"></div>
  244 + <Spin
  245 + class="w-full h-full !flex flex-col justify-center items-center pointer-events-none"
  246 + :spinning="!prepare"
  247 + tip="地图加载中..."
  248 + />
  249 + <div v-show="prepare" ref="wrapRef" :id="wrapId" class="w-full h-full no-drag"></div>
246 250 <HistoryDataModel @register="register" @ok="handleRenderHistroyData" />
247 251 </div>
248 252 </template>
... ...
... ... @@ -267,12 +267,7 @@
267 267 <h3 class="w-24 flex-shrink-0 text-right pr-2 my-4">选择数据源</h3>
268 268 <section ref="formListEl">
269 269 <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50">
270   - <div
271   - class="w-24 text-right leading-30px pr-8px flex right"
272   - style="flex: 0 0 96px; justify-content: right"
273   - >
274   - 选择设备
275   - </div>
  270 + <div class="w-24 text-right flex right justify-end"> 选择设备 </div>
276 271 <div class="pl-2 flex-auto">
277 272 <component
278 273 :frontId="$props.frontId"
... ...
1 1 <script lang="ts" setup>
2   - import moment from 'moment';
3 2 import { nextTick, Ref, ref, unref } from 'vue';
4 3 import { getDeviceHistoryInfo } from '/@/api/alarm/position';
5 4 import { Empty } from 'ant-design-vue';
6 5 import { useECharts } from '/@/hooks/web/useECharts';
7   - import { dateUtil } from '/@/utils/dateUtil';
8   - import { AggregateDataEnum, eChartOptions } from '/@/views/device/localtion/config.data';
  6 + import { AggregateDataEnum } from '/@/views/device/localtion/config.data';
9 7 import { useGridLayout } from '/@/hooks/component/useGridLayout';
10 8 import { ColEx } from '/@/components/Form/src/types';
11   - import { DataSource, DeviceAttributeRecord } from '/@/api/dataBoard/model';
  9 + import { DataSource } from '/@/api/dataBoard/model';
12 10 import { useForm, BasicForm } from '/@/components/Form';
13   - import { formSchema, QueryWay, SchemaFiled } from '../config/historyTrend.config';
14   - import { DEFAULT_DATE_FORMAT } from '../config/util';
  11 + import { formSchema, SchemaFiled } from '../config/historyTrend.config';
15 12 import { Loading } from '/@/components/Loading';
16 13 import BasicModal from '/@/components/Modal/src/BasicModal.vue';
17 14 import { useModalInner } from '/@/components/Modal';
18   - import { getAllDeviceByOrg, getDeviceAttributes } from '/@/api/dataBoard';
19   - import { HistoryData } from '/@/api/alarm/position/model';
20   - import { EChartsOption } from 'echarts';
  15 + import { getAllDeviceByOrg } from '/@/api/dataBoard';
  16 + import { useHistoryData } from '/@/views/device/list/hook/useHistoryData';
21 17
22 18 type DeviceOption = Record<'label' | 'value' | 'organizationId', string>;
23 19
... ... @@ -25,37 +21,14 @@
25 21
26 22 const chartRef = ref();
27 23
28   - const deviceAttrs = ref<DeviceAttributeRecord[]>([]);
29   -
30 24 const loading = ref(false);
31 25
32 26 const isNull = ref(false);
33 27
34   - function getSearchParams(value: Recordable) {
35   - const { startTs, endTs, interval, agg, limit, keys, way, deviceId } = value;
36   - const basicRecord = {
37   - entityId: deviceId,
38   - keys: keys
39   - ? keys
40   - : unref(deviceAttrs)
41   - .map((item) => item.identifier)
42   - .join(),
43   - interval,
44   - agg,
45   - limit,
46   - };
47   - if (way === QueryWay.LATEST) {
48   - return Object.assign(basicRecord, {
49   - startTs: moment().subtract(startTs, 'ms').valueOf(),
50   - endTs: Date.now(),
51   - });
52   - } else {
53   - return Object.assign(basicRecord, {
54   - startTs: moment(startTs).valueOf(),
55   - endTs: moment(endTs).valueOf(),
56   - });
57   - }
58   - }
  28 + const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } =
  29 + useHistoryData();
  30 +
  31 + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
59 32
60 33 function hasDeviceAttr() {
61 34 if (!unref(deviceAttrs).length) {
... ... @@ -65,32 +38,8 @@
65 38 }
66 39 }
67 40
68   - function setChartOptions(data: HistoryData, keys?: string | string[]) {
69   - const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
70   -
71   - const dataArray: [string, string, string][] = [];
72   - for (const key in data) {
73   - for (const item1 of data[key]) {
74   - let { ts, value } = item1;
75   - const time = dateUtil(ts).format(DEFAULT_DATE_FORMAT);
76   - value = Number(value).toFixed(2);
77   - dataArray.push([time, value, key as string]);
78   - }
79   - }
80   - keys = keys ? [keys as string] : unref(deviceAttrs).map((item) => item.identifier);
81   - const series: EChartsOption['series'] = (keys as string[]).map((item) => {
82   - return {
83   - name: item,
84   - type: 'line',
85   - data: dataArray.filter((temp) => temp[2] === item),
86   - };
87   - });
88   - // 设置数据
89   - setOptions(eChartOptions(series, keys));
90   - }
91   -
92 41 const [register, method] = useForm({
93   - schemas: formSchema,
  42 + schemas: formSchema(),
94 43 baseColProps: useGridLayout(2, 3, 4) as unknown as ColEx,
95 44 rowProps: {
96 45 gutter: 10,
... ... @@ -119,7 +68,11 @@
119 68 } else {
120 69 isNull.value = true;
121 70 }
122   - setChartOptions(res, value.keys);
  71 +
  72 + const selectedKeys = unref(deviceAttrs).find(
  73 + (item) => item.identifier === value[SchemaFiled.KEYS]
  74 + );
  75 + setOptions(setChartOptions(res, selectedKeys));
123 76 },
124 77 });
125 78
... ... @@ -128,8 +81,7 @@
128 81 try {
129 82 const options = await getAllDeviceByOrg(organizationId);
130 83 const record = options.find((item) => item.id === value);
131   - const { deviceProfileId } = record!;
132   - deviceAttrs.value = (await getDeviceAttributes({ deviceProfileId })) || [];
  84 + await getDeviceAttribute(record!);
133 85 await nextTick();
134 86 method.updateSchema({
135 87 field: SchemaFiled.KEYS,
... ... @@ -157,9 +109,7 @@
157 109
158 110 const res = await getDeviceHistoryInfo({
159 111 entityId: deviceId,
160   - keys: unref(deviceAttrs)
161   - .map((item) => item.identifier)
162   - .join(),
  112 + keys: unref(getDeviceKeys).join(),
163 113 startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
164 114 endTs: Date.now(),
165 115 agg: AggregateDataEnum.NONE,
... ... @@ -173,7 +123,7 @@
173 123 } else {
174 124 isNull.value = true;
175 125 }
176   - setChartOptions(res);
  126 + setOptions(setChartOptions(res));
177 127 };
178 128
179 129 const generateDeviceOptions = (dataSource: DataSource[]) => {
... ...
... ... @@ -35,171 +35,173 @@ export enum AggregateDataEnum {
35 35 COUNT = 'COUNT',
36 36 NONE = 'NONE',
37 37 }
38   -export const formSchema: FormSchema[] = [
39   - {
40   - field: SchemaFiled.DEVICE_ID,
41   - label: '设备名称',
42   - component: 'Select',
43   - rules: [{ required: true, message: '设备名称为必选项', type: 'string' }],
44   - componentProps({ formActionType }) {
45   - const { setFieldsValue } = formActionType;
46   - return {
47   - placeholder: '请选择设备',
48   - onChange() {
49   - setFieldsValue({ [SchemaFiled.KEYS]: null });
50   - },
51   - };
  38 +export const formSchema = (): FormSchema[] => {
  39 + return [
  40 + {
  41 + field: SchemaFiled.DEVICE_ID,
  42 + label: '设备名称',
  43 + component: 'Select',
  44 + rules: [{ required: true, message: '设备名称为必选项', type: 'string' }],
  45 + componentProps({ formActionType }) {
  46 + const { setFieldsValue } = formActionType;
  47 + return {
  48 + placeholder: '请选择设备',
  49 + onChange() {
  50 + setFieldsValue({ [SchemaFiled.KEYS]: null });
  51 + },
  52 + };
  53 + },
52 54 },
53   - },
54   - {
55   - field: SchemaFiled.WAY,
56   - label: '查询方式',
57   - component: 'RadioGroup',
58   - defaultValue: QueryWay.LATEST,
59   - componentProps({ formActionType }) {
60   - const { setFieldsValue } = formActionType;
61   - return {
62   - options: [
63   - { label: '最后', value: QueryWay.LATEST },
64   - { label: '时间段', value: QueryWay.TIME_PERIOD },
65   - ],
66   - onChange(event: ChangeEvent) {
67   - (event.target as HTMLInputElement).value === QueryWay.LATEST
68   - ? setFieldsValue({
69   - [SchemaFiled.DATE_RANGE]: [],
70   - [SchemaFiled.START_TS]: null,
71   - [SchemaFiled.END_TS]: null,
72   - })
73   - : setFieldsValue({ [SchemaFiled.START_TS]: null });
74   - },
75   - getPopupContainer: () => document.body,
76   - };
  55 + {
  56 + field: SchemaFiled.WAY,
  57 + label: '查询方式',
  58 + component: 'RadioGroup',
  59 + defaultValue: QueryWay.LATEST,
  60 + componentProps({ formActionType }) {
  61 + const { setFieldsValue } = formActionType;
  62 + return {
  63 + options: [
  64 + { label: '最后', value: QueryWay.LATEST },
  65 + { label: '时间段', value: QueryWay.TIME_PERIOD },
  66 + ],
  67 + onChange(event: ChangeEvent) {
  68 + (event.target as HTMLInputElement).value === QueryWay.LATEST
  69 + ? setFieldsValue({
  70 + [SchemaFiled.DATE_RANGE]: [],
  71 + [SchemaFiled.START_TS]: null,
  72 + [SchemaFiled.END_TS]: null,
  73 + })
  74 + : setFieldsValue({ [SchemaFiled.START_TS]: null });
  75 + },
  76 + getPopupContainer: () => document.body,
  77 + };
  78 + },
77 79 },
78   - },
79   - {
80   - field: SchemaFiled.START_TS,
81   - label: '最后数据',
82   - component: 'Select',
83   - ifShow({ values }) {
84   - return values[SchemaFiled.WAY] === QueryWay.LATEST;
  80 + {
  81 + field: SchemaFiled.START_TS,
  82 + label: '最后数据',
  83 + component: 'Select',
  84 + ifShow({ values }) {
  85 + return values[SchemaFiled.WAY] === QueryWay.LATEST;
  86 + },
  87 + componentProps({ formActionType }) {
  88 + const { setFieldsValue } = formActionType;
  89 + return {
  90 + options: intervalOption,
  91 + onChange() {
  92 + setFieldsValue({ [SchemaFiled.INTERVAL]: null });
  93 + },
  94 + getPopupContainer: () => document.body,
  95 + };
  96 + },
  97 + rules: [{ required: true, message: '最后数据为必选项', type: 'number' }],
85 98 },
86   - componentProps({ formActionType }) {
87   - const { setFieldsValue } = formActionType;
88   - return {
89   - options: intervalOption,
90   - onChange() {
91   - setFieldsValue({ [SchemaFiled.INTERVAL]: null });
92   - },
93   - getPopupContainer: () => document.body,
94   - };
95   - },
96   - rules: [{ required: true, message: '最后数据为必选项', type: 'number' }],
97   - },
98   - {
99   - field: SchemaFiled.DATE_RANGE,
100   - label: '时间段',
101   - component: 'RangePicker',
102   - ifShow({ values }) {
103   - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD;
  99 + {
  100 + field: SchemaFiled.DATE_RANGE,
  101 + label: '时间段',
  102 + component: 'RangePicker',
  103 + ifShow({ values }) {
  104 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD;
  105 + },
  106 + rules: [{ required: true, message: '时间段为必选项' }],
  107 + componentProps({ formActionType }) {
  108 + const { setFieldsValue } = formActionType;
  109 + let dates: Moment[] = [];
  110 + return {
  111 + showTime: {
  112 + defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
  113 + },
  114 + onCalendarChange(value: Moment[]) {
  115 + dates = value;
  116 + },
  117 + disabledDate(current: Moment) {
  118 + if (!dates || dates.length === 0 || !current) {
  119 + return false;
  120 + }
  121 + const diffDate = current.diff(dates[0], 'years', true);
  122 + return Math.abs(diffDate) > 1;
  123 + },
  124 + onChange() {
  125 + dates = [];
  126 + setFieldsValue({ [SchemaFiled.INTERVAL]: null });
  127 + },
  128 + getPopupContainer: () => document.body,
  129 + };
  130 + },
  131 + colProps: useGridLayout(2, 2, 2, 2, 2, 2) as unknown as ColEx,
104 132 },
105   - rules: [{ required: true, message: '时间段为必选项' }],
106   - componentProps({ formActionType }) {
107   - const { setFieldsValue } = formActionType;
108   - let dates: Moment[] = [];
109   - return {
110   - showTime: {
111   - defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
112   - },
113   - onCalendarChange(value: Moment[]) {
114   - dates = value;
115   - },
116   - disabledDate(current: Moment) {
117   - if (!dates || dates.length === 0 || !current) {
118   - return false;
119   - }
120   - const diffDate = current.diff(dates[0], 'years', true);
121   - return Math.abs(diffDate) > 1;
122   - },
123   - onChange() {
124   - dates = [];
125   - setFieldsValue({ [SchemaFiled.INTERVAL]: null });
126   - },
  133 + {
  134 + field: SchemaFiled.AGG,
  135 + label: '数据聚合功能',
  136 + component: 'Select',
  137 + componentProps: {
127 138 getPopupContainer: () => document.body,
128   - };
129   - },
130   - colProps: useGridLayout(2, 2, 2, 2, 2, 2) as unknown as ColEx,
131   - },
132   - {
133   - field: SchemaFiled.AGG,
134   - label: '数据聚合功能',
135   - component: 'Select',
136   - componentProps: {
137   - getPopupContainer: () => document.body,
138   - options: [
139   - { label: '最小值', value: AggregateDataEnum.MIN },
140   - { label: '最大值', value: AggregateDataEnum.MAX },
141   - { label: '平均值', value: AggregateDataEnum.AVG },
142   - { label: '求和', value: AggregateDataEnum.SUM },
143   - { label: '计数', value: AggregateDataEnum.COUNT },
144   - { label: '空', value: AggregateDataEnum.NONE },
145   - ],
146   - },
147   - },
148   - {
149   - field: SchemaFiled.INTERVAL,
150   - label: '分组间隔',
151   - component: 'Select',
152   - dynamicRules: ({ model }) => {
153   - return [
154   - {
155   - required: model[SchemaFiled.AGG] !== AggregateDataEnum.NONE,
156   - message: '分组间隔为必填项',
157   - type: 'number',
158   - },
159   - ];
160   - },
161   - ifShow({ values }) {
162   - return values[SchemaFiled.AGG] !== AggregateDataEnum.NONE;
  139 + options: [
  140 + { label: '最小值', value: AggregateDataEnum.MIN },
  141 + { label: '最大值', value: AggregateDataEnum.MAX },
  142 + { label: '平均值', value: AggregateDataEnum.AVG },
  143 + { label: '求和', value: AggregateDataEnum.SUM },
  144 + { label: '计数', value: AggregateDataEnum.COUNT },
  145 + { label: '空', value: AggregateDataEnum.NONE },
  146 + ],
  147 + },
163 148 },
164   - componentProps({ formModel, formActionType }) {
165   - const options =
166   - formModel[SchemaFiled.WAY] === QueryWay.LATEST
167   - ? getPacketIntervalByValue(formModel[SchemaFiled.START_TS])
168   - : getPacketIntervalByRange(formModel[SchemaFiled.DATE_RANGE]);
169   - if (formModel[SchemaFiled.AGG] !== AggregateDataEnum.NONE) {
170   - formActionType.setFieldsValue({ [SchemaFiled.LIMIT]: null });
171   - }
172   - return {
173   - options,
174   - getPopupContainer: () => document.body,
175   - };
  149 + {
  150 + field: SchemaFiled.INTERVAL,
  151 + label: '分组间隔',
  152 + component: 'Select',
  153 + dynamicRules: ({ model }) => {
  154 + return [
  155 + {
  156 + required: model[SchemaFiled.AGG] !== AggregateDataEnum.NONE,
  157 + message: '分组间隔为必填项',
  158 + type: 'number',
  159 + },
  160 + ];
  161 + },
  162 + ifShow({ values }) {
  163 + return values[SchemaFiled.AGG] !== AggregateDataEnum.NONE;
  164 + },
  165 + componentProps({ formModel, formActionType }) {
  166 + const options =
  167 + formModel[SchemaFiled.WAY] === QueryWay.LATEST
  168 + ? getPacketIntervalByValue(formModel[SchemaFiled.START_TS])
  169 + : getPacketIntervalByRange(formModel[SchemaFiled.DATE_RANGE]);
  170 + if (formModel[SchemaFiled.AGG] !== AggregateDataEnum.NONE) {
  171 + formActionType.setFieldsValue({ [SchemaFiled.LIMIT]: null });
  172 + }
  173 + return {
  174 + options,
  175 + getPopupContainer: () => document.body,
  176 + };
  177 + },
176 178 },
177   - },
178   - {
179   - field: SchemaFiled.LIMIT,
180   - label: '最大条数',
181   - component: 'InputNumber',
182   - ifShow({ values }) {
183   - return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;
  179 + {
  180 + field: SchemaFiled.LIMIT,
  181 + label: '最大条数',
  182 + component: 'InputNumber',
  183 + ifShow({ values }) {
  184 + return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;
  185 + },
  186 + helpMessage: ['根据查询条件,查出的数据条数不超过这个值'],
  187 + componentProps() {
  188 + return {
  189 + max: 50000,
  190 + min: 7,
  191 + getPopupContainer: () => document.body,
  192 + };
  193 + },
184 194 },
185   - helpMessage: ['根据查询条件,查出的数据条数不超过这个值'],
186   - componentProps() {
187   - return {
188   - max: 50000,
189   - min: 7,
  195 + {
  196 + field: SchemaFiled.KEYS,
  197 + label: '设备属性',
  198 + component: 'Select',
  199 + componentProps: {
190 200 getPopupContainer: () => document.body,
191   - };
192   - },
193   - },
194   - {
195   - field: SchemaFiled.KEYS,
196   - label: '设备属性',
197   - component: 'Select',
198   - componentProps: {
199   - getPopupContainer: () => document.body,
  201 + },
200 202 },
201   - },
202   -];
  203 + ];
  204 +};
203 205
204 206 export function getHistorySearchParams(value: Recordable) {
205 207 const { startTs, endTs, interval, agg, limit, way, keys, deviceId } = value;
... ...