Commit cacdeb63bc88418fd3ec0c37a025c9ed1e948c2d

Authored by fengwotao
1 parent e9c0f349

refactor: 替换之前重构好的报表配置相关代码

1   -<template>
2   - <BasicDrawer
3   - :maskClosable="true"
4   - @close="handleClose"
5   - destroyOnClose
6   - v-bind="$attrs"
7   - @register="registerDrawer"
8   - showFooter
9   - :title="getTitle"
10   - width="30%"
11   - @ok="handleSubmit"
12   - >
13   - <BasicForm @register="registerForm">
14   - <template #devices="{ model, field }">
15   - <p style="display: none">{{ field }}</p>
16   - <p>{{ queryModeFunc(model['queryMode']) }}</p>
17   - <p>{{ orgFunc(model['organizationId']) }}</p>
18   - <p>{{ dataTypeFunc(model['dataType']) }}</p>
19   - <Select
20   - placeholder="请选择设备"
21   - v-model:value="selectDevice"
22   - style="width: 100%"
23   - :options="selectOptions"
24   - @change="handleDeviceChange"
25   - @deselect="handleDeselect"
26   - mode="multiple"
27   - labelInValue
28   - notFoundContent="请选择设备"
29   - />
30   - <div style="margin-top: 1.5vh"></div>
31   - <template v-for="(item, index) in deviceList" :key="item.value">
32   - <p style="display: none">{{ index }}</p>
33   - <DeviceAttrCpns
34   - :ref="bindDeviceRefObj.deviceAttrRef"
35   - :value="item"
36   - :orgId="organizationId || orgId"
37   - />
38   - </template>
39   - </template>
40   - </BasicForm>
41   - </BasicDrawer>
42   -</template>
43   -<script lang="ts" setup>
44   - import { ref, computed, unref, reactive, watch, Ref, nextTick } from 'vue';
45   - import { BasicForm, useForm } from '/@/components/Form';
46   - import { DataTypeEnum, formSchema, organizationId } from './config.data';
47   - import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
48   - import {
49   - createOrEditReportManage,
50   - putReportConfigManage,
51   - reportEditDetailPage,
52   - } from '/@/api/report/reportManager';
53   - import { useMessage } from '/@/hooks/web/useMessage';
54   - import moment from 'moment';
55   - import { screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';
56   - import { Select } from 'ant-design-vue';
57   - import DeviceAttrCpns from './cpns/DeviceAttrCpns.vue';
58   - import { SchemaFiled } from './config.data';
59   - import { QueryWay } from '../../device/localtion/cpns/TimePeriodForm/config';
60   - import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';
61   -
62   - type TDeviceList = {
63   - key?: string;
64   - value?: string;
65   - label?: string;
66   - attribute?: string;
67   - device?: string;
68   - name?: string;
69   - attributes?: string | undefined;
70   - deviceProfileId?: string;
71   - id?: string;
72   - };
73   - type TSelectOption = {
74   - value?: string;
75   - label?: string;
76   - deviceProfileId?: string;
77   - id?: string;
78   - };
79   - const emit = defineEmits(['success', 'register']);
80   - const bindDeviceRefObj = {
81   - deviceAttrRef: ref([]),
82   - };
83   - const isUpdate = ref(true);
84   - const editId = ref('');
85   - const orgId = ref('');
86   - const selectOptions: Ref<TSelectOption[]> = ref([]);
87   - const selectDevice = ref([]);
88   - const deviceList: Ref<TDeviceList[]> = ref([]);
89   - const editDeviceList: Ref<TDeviceList[]> = ref([]);
90   - let editResData: any = reactive({});
91   - const editDeviceAttr: any = ref([]);
92   - const orgFuncId = ref('');
93   - const queryModeStr = ref('');
94   - const dataTypeStr = ref(0);
95   - const orgFunc = (e) => {
96   - orgFuncId.value = e;
97   - };
98   - const queryModeFunc = (e) => {
99   - queryModeStr.value = e;
100   - };
101   - const dataTypeFunc = (e) => {
102   - dataTypeStr.value = e;
103   - };
104   - watch(
105   - () => dataTypeStr.value,
106   - (newValue) => {
107   - if (newValue == 0) {
108   - setFieldsValue({ limit: 100 });
109   - } else {
110   - }
111   - }
112   - );
113   - watch(
114   - () => queryModeStr.value,
115   - (newValue: string) => {
116   - if (newValue == 'latest') {
117   - setFieldsValue({ startTs: 1000 });
118   - setFieldsValue({ interval: 1000 });
119   - } else {
120   - }
121   - }
122   - );
123   - watch(
124   - () => orgFuncId.value,
125   - async (newValue: string) => {
126   - if (newValue) {
127   - //获取设备
128   - const { items } = await screenLinkPageByDeptIdGetDevice({
129   - organizationId: newValue,
130   - });
131   - selectOptions.value = items.map((item) => {
132   - if (item.deviceType !== 'GATEWAY')
133   - return {
134   - label: item.alias ? item.alias : item.name,
135   - value: item.tbDeviceId,
136   - id: item.id,
137   - deviceProfileId: item.deviceProfileId,
138   - };
139   - });
140   - }
141   - }
142   - );
143   - //设备Select选中
144   - const handleDeviceChange = (_, o) => {
145   - if (unref(isUpdate)) {
146   - //编辑
147   - let temp: any = [];
148   - editDeviceAttr.value.forEach((f) => {
149   - temp = [f, ...o];
150   - });
151   - let deWeightThree = () => {
152   - let map = new Map();
153   - for (let item of deviceList.value) {
154   - if (!map.has(item.value)) {
155   - map.set(item.value, item);
156   - }
157   - }
158   - return [...map.values()];
159   - };
160   - temp = deWeightThree();
161   - deviceList.value = temp;
162   - if (o.length !== 0) {
163   - deviceList.value = o;
164   - }
165   - } else {
166   - deviceList.value = o;
167   - }
168   - };
169   - //设备取消删除
170   - const handleDeselect = (e) => {
171   - if (unref(isUpdate)) {
172   - //编辑
173   - let deWeightThree = () => {
174   - let map = new Map();
175   - for (let item of deviceList.value) {
176   - if (!map.has(item.value)) {
177   - map.set(item.value, item);
178   - }
179   - }
180   - return [...map.values()];
181   - };
182   - deviceList.value = deWeightThree();
183   - const findEditValue = deviceList.value.findIndex((f) => f.value == e.value);
184   - if (findEditValue !== -1) deviceList.value.splice(findEditValue, 1);
185   - } else {
186   - const eDevice = e.key || e.value;
187   - const findValue = deviceList.value.findIndex((f) => f.value == eDevice);
188   - if (findValue !== -1) deviceList.value.splice(findValue, 1);
189   - }
190   - };
191   - const [registerForm, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] =
192   - useForm({
193   - labelWidth: 120,
194   - schemas: formSchema,
195   - showActionButtonGroup: false,
196   - fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],
197   - });
198   - const isViewDetail = ref(false);
199   -
200   - const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
201   - await nextTick();
202   - await resetFields();
203   - setDrawerProps({ confirmLoading: false });
204   - isUpdate.value = !!data?.isUpdate;
205   - isViewDetail.value = !!data?.isView;
206   - if (unref(isViewDetail)) {
207   - setDrawerProps({ showFooter: true });
208   - if (unref(isUpdate)) {
209   - setDrawerProps({ title: '编辑报表配置' });
210   - } else {
211   - setDrawerProps({ title: '新增报表配置' });
212   - }
213   - } else {
214   - setDrawerProps({ showFooter: false });
215   - setDrawerProps({ title: '查看报表配置' });
216   - }
217   - if (unref(isUpdate)) {
218   - //编辑回显数据
219   - editResData = await reportEditDetailPage(data.record.id);
220   - //回显基础数据
221   - editId.value = editResData.data.id;
222   - const spanDisance = editResData.data.executeContent?.split(' ');
223   - await setFieldsValue(editResData.data);
224   - //回显嵌套数据
225   - await setFieldsValue({
226   - dateGroupGap:
227   - editResData.data.queryCondition?.queryMode === 1
228   - ? editResData.data.queryCondition?.interval
229   - : null,
230   - agg: editResData.data.queryCondition?.agg,
231   - interval: editResData.data.queryCondition?.interval,
232   - limit: editResData.data.queryCondition?.limit,
233   - orderBy: editResData.data.queryCondition?.orderBy,
234   - useStrictDataTypes: editResData.data.queryCondition?.useStrictDataTypes,
235   - startTs: editResData.data.queryCondition?.startTs,
236   - endTs: editResData.data.queryCondition?.endTs,
237   - way: editResData.data?.way,
238   - queryMode: editResData.data.queryCondition?.queryMode === 0 ? 'latest' : 'timePeriod',
239   - cronTime:
240   - editResData.data?.cycle?.cycleType === 2
241   - ? spanDisance[2] < 10
242   - ? editResData.data.executeContent.slice(0, 7) + '* * ?'
243   - : editResData.data.executeContent.slice(0, 7) + ' ' + '* * ?'
244   - : editResData.data?.cycle?.cycleType === 1
245   - ? spanDisance[2] < 10
246   - ? editResData.data.executeContent.slice(0, 5) + ' ' + ' * * ?'
247   - : editResData.data.executeContent.slice(0, 6) + ' ' + ' * * ?'
248   - : editResData.data.executeContent,
249   - currentCycle: editResData.data?.cycle?.currentCycle,
250   - cycleTime: editResData.data?.cycle?.cycleTime,
251   - cycleType: editResData.data?.cycle?.cycleType,
252   - });
253   - const endTsTime = editResData.data.queryCondition?.endTs;
254   - const startTsTime = editResData.data.queryCondition?.startTs;
255   - const mathFloor = (endTsTime - startTsTime) / 10;
256   - const multTen = Math.floor(mathFloor) * 10;
257   - await setFieldsValue({
258   - startTs: multTen,
259   - });
260   - if (editResData.data.queryCondition?.queryMode == 1) {
261   - await setFieldsValue({
262   - dataRange: [
263   - editResData.data.queryCondition?.startTs,
264   - editResData.data.queryCondition?.endTs,
265   - ],
266   - });
267   - }
268   - //回显聚合条件
269   - const dataCompareOpions = [
270   - { label: '最小值', value: AggregateDataEnum.MIN },
271   - { label: '最大值', value: AggregateDataEnum.MAX },
272   - { label: '平均值', value: AggregateDataEnum.AVG },
273   - { label: '求和', value: AggregateDataEnum.SUM },
274   - { label: '计数', value: AggregateDataEnum.COUNT },
275   - { label: '空', value: AggregateDataEnum.NONE },
276   - ];
277   - const updateSchemaAgg = (options: {}) => {
278   - updateSchema({
279   - field: SchemaFiled.AGG,
280   - componentProps: {
281   - options,
282   - },
283   - });
284   - };
285   - if (editResData.data.dataType == 1) updateSchemaAgg(dataCompareOpions.slice(0, 5));
286   - else updateSchemaAgg(dataCompareOpions.slice(5, 6));
287   - //回显执行方式和查询周期
288   - const dataQueryOpions = [
289   - { label: '固定周期', value: QueryWay.LATEST },
290   - { label: '自定义周期', value: QueryWay.TIME_PERIOD },
291   - ];
292   - const updateSchemaQuery = (options: {}) => {
293   - updateSchema({
294   - field: SchemaFiled.WAY,
295   - componentProps: {
296   - options,
297   - },
298   - });
299   - };
300   - if (editResData.data.executeWay == 0) updateSchemaQuery(dataQueryOpions);
301   - else updateSchemaQuery(dataQueryOpions.slice(0, 1));
302   - //回显设备
303   - orgId.value = editResData.data.organizationId;
304   - const { items } = await screenLinkPageByDeptIdGetDevice({
305   - organizationId: editResData.data.organizationId,
306   - });
307   - selectOptions.value = items.map((item) => {
308   - if (item.deviceType !== 'GATEWAY')
309   - return {
310   - label: item.alias ? item.alias : item.name,
311   - value: item.tbDeviceId,
312   - id: item.id,
313   - deviceProfileId: item.deviceProfileId,
314   - };
315   - });
316   - const deviceIds = editResData.data.executeAttributes.map((m) => {
317   - return {
318   - label: m.name,
319   - key: m.device,
320   - };
321   - });
322   - selectDevice.value = deviceIds;
323   - //回显设备属性
324   - editDeviceAttr.value = editResData.data.executeAttributes?.map((item) => {
325   - const T = selectOptions.value.find((o) => {
326   - if (item.device === o.value) {
327   - return {
328   - id: o.id,
329   - deviceProfileId: o.deviceProfileId,
330   - };
331   - }
332   - });
333   - return {
334   - ...T,
335   - label: item.alias ? item.alias : item.name,
336   - value: item.device,
337   - attributes: item.attributes,
338   - };
339   - });
340   - deviceList.value = editDeviceAttr.value;
341   - editDeviceList.value = editResData.data.executeAttributes;
342   - } else {
343   - setFieldsValue({
344   - startTs: 1000,
345   - interval: 1000,
346   - });
347   - editId.value = '';
348   - orgId.value = '';
349   - selectDevice.value = [];
350   - selectOptions.value = [];
351   - deviceList.value = [];
352   - getAttrDevice.value = [];
353   - editDeviceList.value = [];
354   - editDeviceAttr.value = [];
355   - updateSchema({
356   - field: SchemaFiled.AGG,
357   - componentProps: {
358   - options: [],
359   - },
360   - });
361   - //新增显示执行方式和查询周期
362   - const dataQueryOpions = [
363   - { label: '固定周期', value: QueryWay.LATEST },
364   - { label: '自定义周期', value: QueryWay.TIME_PERIOD },
365   - ];
366   - const updateSchemaQuery = (options: {}) => {
367   - updateSchema({
368   - field: SchemaFiled.WAY,
369   - componentProps: {
370   - options,
371   - },
372   - });
373   - };
374   - if (getFieldsValue().executeWay == 0) updateSchemaQuery(dataQueryOpions);
375   - }
376   - });
377   - const handleClose = () => {
378   - deviceList.value = [];
379   - editId.value = '';
380   - orgId.value = '';
381   - selectDevice.value = [];
382   - selectOptions.value = [];
383   - getAttrDevice.value = [];
384   - editDeviceList.value = [];
385   - editDeviceAttr.value = [];
386   - };
387   - const getAttrDevice: Ref<TDeviceList[]> = ref([]);
388   - const getTitle = computed(() => (!unref(isUpdate) ? '新增报表配置' : '编辑报表配置'));
389   - let postObj: any = reactive({});
390   - let queryCondition: any = reactive({});
391   - let executeContent: any = reactive({});
392   - const startTs = ref(0);
393   - const endTs = ref(0);
394   -
395   - const getFormValueFunc = () => {
396   - const item: any = unref(bindDeviceRefObj.deviceAttrRef)?.map((item: any) => item.emitChange());
397   - getAttrDevice.value = item;
398   - };
399   -
400   - async function handleSubmit() {
401   - setDrawerProps({ confirmLoading: true });
402   - try {
403   - const { createMessage } = useMessage();
404   - const values = await validate();
405   - if (!values) return;
406   - getFormValueFunc();
407   - let hasAttr = false;
408   - if (!unref(isUpdate)) {
409   - if (getAttrDevice.value.length === 0) {
410   - return createMessage.error('请选择设备及其属性');
411   - } else {
412   - getAttrDevice.value.forEach((f: any) => {
413   - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;
414   - });
415   - }
416   - } else {
417   - if (getAttrDevice.value.length === 0) {
418   - return createMessage.error('请选择设备及其属性');
419   - } else {
420   - getAttrDevice.value.forEach((f: any) => {
421   - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;
422   - });
423   - }
424   - }
425   - if (hasAttr) return createMessage.error('请选择设备属性');
426   - if (values.executeWay == 0) {
427   - executeContent = null;
428   - } else {
429   - //拼接corn
430   - let joinCorn = '';
431   - if (values.cycleType === 1) {
432   - joinCorn = values.cronTime.slice(0, 6) + values.currentCycle.slice(5);
433   - executeContent = joinCorn;
434   - } else if (values.cycleType === 0) {
435   - executeContent = values.cronTime;
436   - } else if (values.cycleType === 2) {
437   - joinCorn = values.cronTime.slice(0, 6) + values.cycleTime.slice(5);
438   - executeContent = joinCorn;
439   - }
440   - }
441   - if (values.queryMode === QueryWay.LATEST) {
442   - startTs.value = moment().subtract(values.startTs, 'ms').valueOf();
443   - endTs.value = Date.now();
444   - } else {
445   - const fT = JSON.parse(JSON.stringify(values.dataRange));
446   - startTs.value = moment(fT[0]).valueOf();
447   - endTs.value = moment(fT[1]).valueOf();
448   - }
449   - queryCondition = {
450   - agg: values.agg,
451   - ...(values?.queryMode === QueryWay.LATEST && values?.dataType != DataTypeEnum.ORIGINAL
452   - ? { interval: values?.queryMode === 'latest' ? values.interval : values.dateGroupGap }
453   - : {}),
454   - limit: values.limit,
455   - ...{
456   - startTs: startTs.value,
457   - },
458   - ...{
459   - endTs: endTs.value,
460   - },
461   - queryMode: values?.queryMode === 'latest' ? 0 : 1,
462   - };
463   - const cycle: any = {};
464   - if (values.cycleType === 0) {
465   - cycle.cycleType = values.cycleType;
466   - cycle.cronTime = values.cronTime;
467   - }
468   - if (values.cycleType === 1) {
469   - cycle.cycleType = values.cycleType;
470   - cycle.currentCycle = values.currentCycle;
471   - cycle.cronTime = values.cronTime;
472   - }
473   - if (values.cycleType === 2) {
474   - cycle.cycleType = values.cycleType;
475   - cycle.cycleTime = values.cycleTime;
476   - cycle.cronTime = values.cronTime;
477   - }
478   - // const cycle = {
479   - // currentCycle: values.currentCycle,
480   - // cycleTime: values.cycleTime,
481   - // cronTime: values.cronTime,
482   - // cycleType: values.cycleType,
483   - // };
484   - delete values.devices;
485   - delete values.agg;
486   - delete values.interval;
487   - delete values.timeZone;
488   - delete values.cronTime;
489   - delete values.currentCycle;
490   - delete values.cycleTime;
491   - delete values.limit1;
492   - delete values.startTs;
493   - delete values.queryMode;
494   - delete values.cycleType;
495   - postObj = {
496   - ...values,
497   - ...{
498   - executeAttributes:
499   - getAttrDevice.value.length == 0 ? editDeviceList.value : getAttrDevice.value,
500   - },
501   - ...{ queryCondition },
502   - ...{ cycle },
503   - ...{ executeContent },
504   - ...{ id: editId.value !== '' ? editId.value : '' },
505   - };
506   - let saveMessage = '添加成功';
507   - let updateMessage = '修改成功';
508   - editId.value !== ''
509   - ? await putReportConfigManage(postObj)
510   - : await createOrEditReportManage(postObj);
511   -
512   - closeDrawer();
513   - emit('success');
514   - createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);
515   - handleClose();
516   - } finally {
517   - setTimeout(() => {
518   - setDrawerProps({ confirmLoading: false });
519   - }, 300);
520   - }
521   - }
522   -</script>
src/views/report/config/components/DevicePreviewModal.vue renamed from src/views/report/config/DevicePreviewModal.vue
... ... @@ -6,7 +6,6 @@
6 6 width="55rem"
7 7 @register="register"
8 8 title="执行设备及属性"
9   - @cancel="handleCancel"
10 9 :showOkBtn="false"
11 10 >
12 11 <div>
... ... @@ -19,10 +18,11 @@
19 18 import { ref, nextTick } from 'vue';
20 19 import { BasicModal, useModalInner } from '/@/components/Modal';
21 20 import { BasicTable, useTable } from '/@/components/Table';
22   - import { viewDeviceColumn } from './config.data';
  21 + import { viewDeviceColumn } from '../config';
23 22 import { reportEditDetailPage } from '/@/api/report/reportManager';
24 23
25   - const tableData: any = ref([]);
  24 + const tableData = ref([]);
  25 +
26 26 const [registerTable] = useTable({
27 27 columns: viewDeviceColumn,
28 28 showIndexColumn: false,
... ... @@ -30,22 +30,20 @@
30 30 showTableSetting: false,
31 31 bordered: true,
32 32 });
  33 +
33 34 const [register] = useModalInner((data) => {
34 35 const getTableData = async () => {
35   - const res: any = await reportEditDetailPage(data.record.id);
36   - const resMap = res.data.executeAttributes.map((d) => {
37   - return {
38   - device: d.name,
39   - attribute: d.attributes.join(','),
40   - };
41   - });
  36 + const res = (await reportEditDetailPage(data.record?.id)) as any;
  37 + const resMap = res?.data?.executeAttributes?.map((item) => ({
  38 + device: item.name,
  39 + attribute: item.attributes.join(','),
  40 + }));
42 41 tableData.value = resMap;
43 42 };
44 43 nextTick(() => {
45 44 getTableData();
46 45 });
47 46 });
48   - const handleCancel = () => {};
49 47 </script>
50 48 <style lang="less" scoped>
51 49 :deep(.ant-table-body) {
... ...
  1 +<template>
  2 + <BasicDrawer
  3 + destroyOnClose
  4 + v-bind="$attrs"
  5 + showFooter
  6 + width="35%"
  7 + :maskClosable="true"
  8 + :title="businessText"
  9 + @register="registerDrawer"
  10 + @ok="handleSubmit"
  11 + @close="handleClose"
  12 + >
  13 + <BasicForm @register="registerForm">
  14 + <!-- 设备选择 -->
  15 + <template #devices="{ model }">
  16 + <span class="hidden">{{ handleChangeOrg(model['organizationId']) }}</span>
  17 + <SelectDevice ref="selectDeviceRef" :selectOptions="selectOptions" />
  18 + </template>
  19 + </BasicForm>
  20 + </BasicDrawer>
  21 +</template>
  22 +<script lang="ts" setup>
  23 + import { ref, reactive, Ref, nextTick, watch } from 'vue';
  24 + import { BasicForm, useForm } from '/@/components/Form';
  25 + import { formSchema } from '../config';
  26 + import { SchemaFiled, BusinessReportConfigTextEnum, BusinessExecutewayEnum } from '../enum';
  27 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  28 + import {
  29 + createOrEditReportManage,
  30 + putReportConfigManage,
  31 + reportEditDetailPage,
  32 + } from '/@/api/report/reportManager';
  33 + import { useMessage } from '/@/hooks/web/useMessage';
  34 + import { TSelectOption } from '../type';
  35 + import { SelectDevice } from './index';
  36 + import { useHooks } from '../hooks/index.hooks';
  37 + import { useThrottleFn } from '@vueuse/shared';
  38 +
  39 + const emits = defineEmits(['success', 'register']);
  40 +
  41 + const selectDeviceRef = ref<InstanceType<typeof SelectDevice>>();
  42 +
  43 + const { createMessage } = useMessage();
  44 +
  45 + const {
  46 + getDeviceList,
  47 + getQueryCondition,
  48 + removeFields,
  49 + setDefaultTime,
  50 + setQueryCondition,
  51 + setAggByDateType,
  52 + disableCustomWeekly,
  53 + setPropsForModal,
  54 + validateSelectDevice,
  55 + } = useHooks();
  56 +
  57 + const selectOptions: Ref<TSelectOption[]> = ref([]);
  58 +
  59 + const orgId = ref('');
  60 +
  61 + const handleChangeOrg = (e) => {
  62 + orgId.value = e;
  63 + //放在这里的话,会造成发出很多请求,原因不是很清楚
  64 + // getDeviceListByOrg(orgId.value);
  65 + };
  66 +
  67 + const getDeviceListByOrg = async (organizationId) => {
  68 + selectOptions.value = await getDeviceList(organizationId);
  69 + };
  70 +
  71 + watch(
  72 + () => orgId.value,
  73 + (newValue: string) => {
  74 + if (newValue) {
  75 + //获取设备
  76 + selectDeviceRef.value?.resetValue();
  77 + getDeviceListByOrg(newValue);
  78 + }
  79 + },
  80 + {
  81 + immediate: true,
  82 + }
  83 + );
  84 +
  85 + const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({
  86 + labelWidth: 120,
  87 + schemas: formSchema,
  88 + showActionButtonGroup: false,
  89 + fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],
  90 + });
  91 +
  92 + const businessText = ref('');
  93 +
  94 + const restData = reactive({
  95 + data: {},
  96 + });
  97 +
  98 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  99 + try {
  100 + await nextTick();
  101 + handleClose();
  102 + businessText.value = data.text;
  103 + setFieldsValue(setDefaultTime());
  104 + updateSchema(disableCustomWeekly(BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE));
  105 + setDrawerProps(setPropsForModal(businessText.value));
  106 + if (businessText.value === BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT) return;
  107 + const rest = await reportEditDetailPage(data.record?.id);
  108 + restData.data = rest['data'] ?? {};
  109 + const {
  110 + organizationId,
  111 + executeAttributes,
  112 + queryCondition,
  113 + dataType,
  114 + executeWay,
  115 + cycle,
  116 + executeContent,
  117 + } = restData.data as any;
  118 + await setFieldsValue({
  119 + ...restData.data,
  120 + ...setQueryCondition(queryCondition, cycle, executeContent),
  121 + });
  122 + if (organizationId) {
  123 + await getDeviceListByOrg(organizationId);
  124 + selectDeviceRef.value?.setValue(executeAttributes);
  125 + }
  126 + await updateSchema(setAggByDateType(dataType));
  127 + await updateSchema(disableCustomWeekly(executeWay));
  128 + } finally {
  129 + setDrawerProps({ loading: false });
  130 + }
  131 + });
  132 +
  133 + const handleClose = () => resetValue();
  134 +
  135 + const useThrottle = useThrottleFn(() => {
  136 + getValue();
  137 + }, 2000);
  138 +
  139 + const handleSubmit = () => {
  140 + useThrottle();
  141 + };
  142 +
  143 + const getValue = async () => {
  144 + try {
  145 + setDrawerProps({ confirmLoading: true });
  146 + const values = await validate();
  147 + if (!values) return;
  148 + const [queryCondition, cycle, executeContent] = getQueryCondition(values);
  149 + const executeAttributes = selectDeviceRef.value?.getSelectAttributes();
  150 + validateSelectDevice(executeAttributes);
  151 + const data = {
  152 + ...values,
  153 + executeAttributes,
  154 + queryCondition,
  155 + cycle,
  156 + executeContent,
  157 + };
  158 + removeFields.forEach((item) => {
  159 + Reflect.deleteProperty(data, item);
  160 + });
  161 + businessText.value === BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT
  162 + ? await createOrEditReportManage(data)
  163 + : putReportConfigManage({ ...restData.data, ...data });
  164 + emits('success');
  165 + createMessage.success(`${businessText.value}成功`);
  166 + closeDrawer();
  167 + handleClose();
  168 + } finally {
  169 + setDrawerProps({ confirmLoading: false });
  170 + }
  171 + };
  172 +
  173 + //重置表单
  174 + const resetValue = () => {
  175 + resetFields();
  176 + selectOptions.value = [];
  177 + selectDeviceRef.value?.resetValue();
  178 + };
  179 +</script>
... ...
src/views/report/config/components/SelectAttributes.vue renamed from src/views/report/config/cpns/DeviceAttrCpns.vue
1 1 <template>
2 2 <div
  3 + class="flex"
3 4 v-for="param in dynamicInput.params"
4 5 :key="param.key"
5   - style="display: flex; margin-top: 0.25vh"
  6 + style="margin-top: 1.25vh"
6 7 >
7   - <a-input
8   - :disabled="true"
9   - v-model:value="param.name"
10   - style="width: 38%; margin-bottom: 5px; margin-left: 1vh"
11   - @change="emitChange"
12   - />
  8 + <a-input :disabled="true" v-model:value="param.name" style="width: 38%; margin-bottom: 5px" />
13 9 <Select
14 10 placeholder="请选择设备属性"
15 11 v-model:value="param.attributes"
16   - style="width: 160px; margin-left: 1.8vw"
  12 + style="width: 38%; margin-left: 1.8vw"
17 13 :options="selectOptions"
18 14 @change="emitChange"
19 15 mode="multiple"
... ... @@ -26,72 +22,66 @@
26 22 inheritAttrs: false,
27 23 };
28 24 </script>
29   -<script lang="ts" setup>
  25 +<script lang="ts" setup name="SelectAttributes">
30 26 import { reactive, UnwrapRef, watchEffect, ref } from 'vue';
31 27 import { propTypes } from '/@/utils/propTypes';
32 28 import { Select } from 'ant-design-vue';
33   - import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
  29 + import { Params } from '../type/';
  30 + import { useHooks } from '../hooks/index.hooks';
34 31
35   - interface Params {
36   - [x: string]: string;
37   - attributes: any;
38   - device: string;
39   - }
40 32 const props = defineProps({
41 33 value: propTypes.object.def({}),
42   - orgId: propTypes.string.def(''),
43 34 });
  35 +
44 36 const selectOptions: any = ref([]);
45   - //获取对应设备属性
46   - const getAttr = async (orgId, _) => {
47   - if (orgId) {
48   - const res = await getAttribute(orgId);
49   - if (Array.isArray(res)) {
50   - selectOptions.value = res.map((o) => {
51   - let obj: any = {};
52   - if (o?.identifier !== null) {
53   - obj = {
54   - label: o?.identifier,
55   - value: o?.identifier,
56   - };
57   - return obj;
58   - }
59   - });
60   - //如果服务端返回的数组里含有null 过滤null值
61   - const excludeNull = selectOptions.value.filter(Boolean);
62   - selectOptions.value = excludeNull;
63   - }
64   - }
65   - };
  37 +
  38 + const { getDeviceAttr } = useHooks();
  39 +
66 40 //动态数据
67 41 const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] });
68   - const rEffect = watchEffect(() => {
69   - initVal();
70   - });
71   - rEffect();
72   - /**
73   - * 初始化数值
74   - */
75   - async function initVal() {
  42 +
  43 + const initVal = async () => {
76 44 if (props.value) {
77   - await getAttr(props.value?.deviceProfileId, props.value?.id);
  45 + selectOptions.value = await getDeviceAttr(props.value?.deviceProfileId);
78 46 dynamicInput.params.push({
79 47 name: props.value.label,
80 48 device: props.value.value,
81   - attributes: props.value?.attributes == [] ? [] : props.value.attributes,
  49 + attributes: props.value.attributes,
82 50 });
83 51 }
84   - }
85   - /**
86   - * 数值改变
87   - */
88   - function emitChange() {
  52 + };
  53 +
  54 + //数值改变
  55 + const valEffect = watchEffect(() => {
  56 + initVal();
  57 + });
  58 +
  59 + valEffect();
  60 +
  61 + //chang改变
  62 + const emitChange = () => {
89 63 return dynamicInput.params[0];
90   - }
  64 + };
91 65 defineExpose({
92 66 emitChange,
93 67 });
94 68 </script>
95 69 <style scoped lang="css">
96   - @import './deviceAttrCpns.css';
  70 + .dynamic-delete-button {
  71 + cursor: pointer;
  72 + position: relative;
  73 + top: 4px;
  74 + font-size: 24px;
  75 + color: #999;
  76 + transition: all 0.3s;
  77 + }
  78 +
  79 + .dynamic-delete-button:hover {
  80 + color: #777;
  81 + }
  82 +
  83 + .dynamic-delete-button[disabled] {
  84 + cursor: not-allowed;
  85 + opacity: 0.5;
  86 + }
97 87 </style>
... ...
  1 +<template>
  2 + <Select
  3 + placeholder="请选择设备"
  4 + v-model:value="selectValue"
  5 + style="width: 100%"
  6 + :options="selectOptions"
  7 + @change="handleDeviceChange"
  8 + mode="multiple"
  9 + labelInValue
  10 + />
  11 + <template v-for="(item, index) in deviceList" :key="item.value">
  12 + <SelectAttributes :ref="bindDeviceRef.deviceAttrRef" :value="item" :index="index" />
  13 + </template>
  14 +</template>
  15 +<script lang="ts" setup name="SelectDevice">
  16 + import { ref, Ref, PropType, unref } from 'vue';
  17 + import { Select } from 'ant-design-vue';
  18 + import SelectAttributes from './SelectAttributes.vue';
  19 + import { TDeviceList, TSelectOption } from '../type';
  20 +
  21 + const props = defineProps({
  22 + selectOptions: {
  23 + type: Array as PropType<TSelectOption[]>,
  24 + required: true,
  25 + },
  26 + });
  27 +
  28 + const selectValue = ref([]);
  29 +
  30 + const bindDeviceRef = {
  31 + deviceAttrRef: ref([]),
  32 + };
  33 +
  34 + const deviceList: Ref<TDeviceList[]> = ref([]);
  35 +
  36 + const getSelectAttributes = () => {
  37 + return unref(bindDeviceRef.deviceAttrRef)?.map((item: any) => item.emitChange());
  38 + };
  39 +
  40 + const handleDeviceChange = (_, options) => {
  41 + deviceList.value = options;
  42 + };
  43 +
  44 + const setValue = (value) => {
  45 + selectValue.value = value.map((item) => ({
  46 + label: item.name,
  47 + key: item.device,
  48 + }));
  49 + deviceList.value = value?.map((item) => {
  50 + const T = props.selectOptions.find((o) => {
  51 + if (item.device === o.value) {
  52 + return {
  53 + id: o.id,
  54 + deviceProfileId: o.deviceProfileId,
  55 + };
  56 + }
  57 + });
  58 + return {
  59 + ...T,
  60 + label: item.alias ? item.alias : item.name,
  61 + value: item.device,
  62 + attributes: item.attributes,
  63 + };
  64 + });
  65 + };
  66 +
  67 + const resetValue = () => {
  68 + selectValue.value = [];
  69 + deviceList.value = [];
  70 + };
  71 + defineExpose({
  72 + getSelectAttributes,
  73 + setValue,
  74 + resetValue,
  75 + });
  76 +</script>
  77 +<style scoped lang="css"></style>
... ...
  1 +import SelectDevice from './SelectDevice.vue';
  2 +import SelectAttributes from './SelectAttributes.vue';
  3 +import DevicePreviewModal from './DevicePreviewModal.vue';
  4 +import ReportConfigDrawer from './ReportConfigDrawer.vue';
  5 +
  6 +export { SelectDevice, SelectAttributes, DevicePreviewModal, ReportConfigDrawer };
... ...
src/views/report/config/config.ts renamed from src/views/report/config/config.data.ts
1   -import { ref } from 'vue';
2   -import { BasicColumn, FormSchema } from '/@/components/Table';
3   -import { FormSchema as QFormSchema, useComponentRegister } from '/@/components/Form/index';
  1 +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table';
  2 +import { FormSchema as BFormSchema, useComponentRegister } from '/@/components/Form/index';
4 3 import { findDictItemByCode } from '/@/api/system/dict';
5   -import { isTiming, isWeek, isMonth, isFixedTime } from './timeConfig';
6   -import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';
  4 +import { AggregateDataEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
7 5 import {
8 6 getPacketIntervalByRange,
9 7 getPacketIntervalByValue,
10 8 intervalOption,
11   -} from '../../device/localtion/cpns/TimePeriodForm/helper';
  9 +} from '/@/views/device/localtion/cpns/TimePeriodForm/helper';
12 10 import moment, { Moment } from 'moment';
13 11 import { OrgTreeSelect } from '../../common/OrgTreeSelect';
  12 +import {
  13 + BusinessExecutewayEnum,
  14 + BusinessReportConfigTextEnum,
  15 + CycleTypeEnum,
  16 + DataTypeEnum,
  17 + DataTypeNameEnum,
  18 + ExecuteWayNameEnum,
  19 + QueryWay,
  20 + SchemaFiled,
  21 + businesAggOptions,
  22 + businesCycleTypeOptions,
  23 + businesDataTypeOptions,
  24 + businesLimitValue,
  25 + businesQueryCycleOptions,
  26 + businesWayOptions,
  27 + businessExecuteWayOptions,
  28 + cycleTypeIsMonthly,
  29 + cycleTypeIsWeekly,
  30 + cycleTypeSetDefault,
  31 + exectueIsImmed,
  32 + exectueIsSchedule,
  33 +} from './enum';
14 34 useComponentRegister('OrgTreeSelect', OrgTreeSelect);
15   -export enum QueryWay {
16   - LATEST = 'latest',
17   - TIME_PERIOD = 'timePeriod',
18   -}
19   -export enum SchemaFiled {
20   - WAY = 'queryMode',
21   - TIME_PERIOD = 'timePeriod',
22   - KEYS = 'keys',
23   - DATE_RANGE = 'dataRange',
24   - START_TS = 'startTs',
25   - END_TS = 'endTs',
26   - INTERVAL = 'interval',
27   - LIMIT = 'limit',
28   - AGG = 'agg',
29   - ORDER_BY = 'orderBy',
30   - DATA_TYPE = 'dataType',
31   -}
32   -
33   -export enum DataTypeEnum {
34   - ORIGINAL = 0,
35   - AGG = 1,
36   -}
37   -
38   -export enum DataTypeNameEnum {
39   - ORIGINAL = '原始数据',
40   - AGG = '聚合数据',
41   -}
42   -
43   -export const organizationId = ref('');
44 35
45   -// 表格配置
  36 +// 表格配置
46 37 export const columns: BasicColumn[] = [
47 38 {
48 39 title: '配置名称',
... ... @@ -75,7 +66,9 @@ export const columns: BasicColumn[] = [
75 66 dataIndex: 'executeWay',
76 67 width: 160,
77 68 format: (_text: string, record: Recordable) => {
78   - return record.executeWay === 0 ? '立即执行' : '定时执行';
  69 + return record.executeWay === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE
  70 + ? ExecuteWayNameEnum.EXECUTEWAY_IMMEDIATE
  71 + : ExecuteWayNameEnum.EXECUTEWAY_SCHEDULED;
79 72 },
80 73 },
81 74 {
... ... @@ -95,20 +88,8 @@ export const columns: BasicColumn[] = [
95 88 width: 180,
96 89 },
97 90 ];
98   -export const viewDeviceColumn: BasicColumn[] = [
99   - {
100   - title: '设备',
101   - dataIndex: 'device',
102   - width: 80,
103   - },
104   - {
105   - title: '属性',
106   - dataIndex: 'attribute',
107   - width: 120,
108   - },
109   -];
110 91
111   -// 查询配置
  92 +// 表格查询配置
112 93 export const searchFormSchema: FormSchema[] = [
113 94 {
114 95 field: 'name',
... ... @@ -152,8 +133,45 @@ export const searchFormSchema: FormSchema[] = [
152 133 },
153 134 ];
154 135
155   -// 新增编辑配置
156   -export const formSchema: QFormSchema[] = [
  136 +//表格通用属性配置
  137 +export const defaultTableAttribtes: BasicTableProps = {
  138 + title: '报表列表',
  139 + columns,
  140 + showIndexColumn: false,
  141 + clickToRowSelect: false,
  142 + formConfig: {
  143 + labelWidth: 120,
  144 + schemas: searchFormSchema,
  145 + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
  146 + },
  147 + useSearchForm: true,
  148 + showTableSetting: true,
  149 + bordered: true,
  150 + rowKey: 'id',
  151 + actionColumn: {
  152 + width: 200,
  153 + title: '操作',
  154 + dataIndex: 'action',
  155 + slots: { customRender: 'action' },
  156 + fixed: 'right',
  157 + },
  158 +};
  159 +
  160 +export const viewDeviceColumn: BasicColumn[] = [
  161 + {
  162 + title: '设备',
  163 + dataIndex: 'device',
  164 + width: 80,
  165 + },
  166 + {
  167 + title: '属性',
  168 + dataIndex: 'attribute',
  169 + width: 120,
  170 + },
  171 +];
  172 +
  173 +// 表单配置
  174 +export const formSchema: BFormSchema[] = [
157 175 {
158 176 field: 'name',
159 177 label: '报表名称',
... ... @@ -171,13 +189,6 @@ export const formSchema: QFormSchema[] = [
171 189 colProps: { span: 24 },
172 190 component: 'OrgTreeSelect',
173 191 required: true,
174   - componentProps: () => {
175   - return {
176   - async onChange(e) {
177   - organizationId.value = e;
178   - },
179   - };
180   - },
181 192 },
182 193 {
183 194 field: 'remark',
... ... @@ -192,64 +203,48 @@ export const formSchema: QFormSchema[] = [
192 203 {
193 204 field: 'executeWay',
194 205 component: 'RadioGroup',
195   - helpMessage: [
196   - `立即执行,在创建完报表配置后,启用配置即执行。
197   - 定时执行,用户定义执行时间,启用后,
198   - 在满足执行时间条件后,自动执行。`,
199   - ],
  206 + helpMessage: [BusinessReportConfigTextEnum.BUSINESS_EXECUTEWAY_HELPMESSAGE_TEXT],
200 207 label: '执行方式',
201 208 colProps: {
202 209 span: 24,
203 210 },
204   - defaultValue: 0,
  211 + defaultValue: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
205 212 componentProps: ({ formActionType }) => {
206 213 const { updateSchema, setFieldsValue } = formActionType;
207   - const options = [
208   - {
209   - label: '立即执行',
210   - value: 0,
211   - },
212   - {
213   - label: '定时执行',
214   - value: 1,
215   - },
216   - ];
217 214 return {
218   - options,
  215 + options: businessExecuteWayOptions,
219 216 placeholder: '请选择执行方式',
220 217 onChange(e) {
221   - let dataCompareOpions: any = [];
222   - setFieldsValue({
223   - startTs: 1000,
224   - interval: 1000,
225   - });
226   - if (e.target.value == 0) {
227   - setFieldsValue({ queryMode: QueryWay.LATEST });
228   - dataCompareOpions = [
229   - { label: '固定周期', value: QueryWay.LATEST },
230   - { label: '自定义周期', value: QueryWay.TIME_PERIOD },
231   - ];
  218 + //动态切换 最近时间 间隔时间变化
  219 + const setDefaultTime = (startTs, interval, queryMode) => {
  220 + setFieldsValue({
  221 + startTs,
  222 + interval,
  223 + queryMode,
  224 + });
  225 + };
  226 + //动态切换 查询周期变化
  227 + const setQueryMode = (defaultValue, field = SchemaFiled.WAY, comObJ) => {
232 228 updateSchema({
233   - field: SchemaFiled.WAY,
234   - componentProps: {
235   - options: dataCompareOpions,
236   - },
  229 + defaultValue,
  230 + field,
  231 + componentProps: comObJ,
  232 + });
  233 + };
  234 + if (e.target.value == BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE) {
  235 + //业务 选择立即执行
  236 + setDefaultTime(1000, 1000, QueryWay.LATEST);
  237 + setQueryMode(null, SchemaFiled.WAY, {
  238 + options: businesQueryCycleOptions,
237 239 });
238 240 } else {
239   - setFieldsValue({ queryMode: QueryWay.LATEST });
240   - setFieldsValue({ startTs: 5000 });
241   - setFieldsValue({ interval: 1000 });
242   - dataCompareOpions = [{ label: '固定周期', value: QueryWay.LATEST }];
243   - updateSchema({
244   - defaultValue: QueryWay.LATEST,
245   - field: SchemaFiled.WAY,
246   - componentProps: {
247   - options: dataCompareOpions,
248   - },
  241 + //业务 选择定时执行
  242 + setDefaultTime(5000, 1000, QueryWay.LATEST);
  243 + setQueryMode(QueryWay.LATEST, SchemaFiled.WAY, {
  244 + options: businesQueryCycleOptions.filter((item) => item.value === QueryWay.LATEST),
249 245 });
250 246 }
251 247 },
252   - maxLength: 250,
253 248 };
254 249 },
255 250 },
... ... @@ -259,16 +254,12 @@ export const formSchema: QFormSchema[] = [
259 254 label: '周期',
260 255 required: true,
261 256 colProps: { span: 24 },
262   - defaultValue: 0,
  257 + defaultValue: CycleTypeEnum.DAILY,
263 258 componentProps: {
264 259 placeholder: '请选择周期',
265   - options: [
266   - { label: '每日', value: 0 },
267   - { label: '每周', value: 1 },
268   - { label: '每月', value: 2 },
269   - ],
  260 + options: businesCycleTypeOptions,
270 261 },
271   - ifShow: ({ values }) => isTiming(values.executeWay),
  262 + ifShow: ({ values }) => exectueIsSchedule(values.executeWay),
272 263 },
273 264 {
274 265 field: 'currentCycle',
... ... @@ -276,7 +267,7 @@ export const formSchema: QFormSchema[] = [
276 267 label: '每周',
277 268 required: true,
278 269 colProps: { span: 24 },
279   - defaultValue: '0 0 0 ? * MON',
  270 + defaultValue: cycleTypeSetDefault.WEEKLY,
280 271 componentProps: {
281 272 placeholder: '请选择周期',
282 273 api: findDictItemByCode,
... ... @@ -286,7 +277,8 @@ export const formSchema: QFormSchema[] = [
286 277 labelField: 'itemText',
287 278 valueField: 'itemValue',
288 279 },
289   - ifShow: ({ values }) => isWeek(values.cycleType),
  280 + ifShow: ({ values }) =>
  281 + exectueIsSchedule(values.executeWay) && cycleTypeIsWeekly(values.cycleType),
290 282 },
291 283 {
292 284 field: 'cycleTime',
... ... @@ -294,7 +286,7 @@ export const formSchema: QFormSchema[] = [
294 286 label: '每月',
295 287 required: true,
296 288 colProps: { span: 24 },
297   - defaultValue: '0 0 0 1 * ? *',
  289 + defaultValue: cycleTypeSetDefault.MONTHLY,
298 290 componentProps: {
299 291 placeholder: '请选择月份',
300 292 api: findDictItemByCode,
... ... @@ -304,7 +296,8 @@ export const formSchema: QFormSchema[] = [
304 296 labelField: 'itemText',
305 297 valueField: 'itemValue',
306 298 },
307   - ifShow: ({ values }) => isMonth(values.cycleType),
  299 + ifShow: ({ values }) =>
  300 + exectueIsSchedule(values.executeWay) && cycleTypeIsMonthly(values.cycleType),
308 301 },
309 302 {
310 303 field: 'cronTime',
... ... @@ -312,7 +305,7 @@ export const formSchema: QFormSchema[] = [
312 305 label: '时间',
313 306 required: true,
314 307 colProps: { span: 24 },
315   - defaultValue: '0 0 0 * * ?',
  308 + defaultValue: cycleTypeSetDefault.DAILY,
316 309 componentProps: {
317 310 placeholder: '请选择时间',
318 311 api: findDictItemByCode,
... ... @@ -322,12 +315,13 @@ export const formSchema: QFormSchema[] = [
322 315 labelField: 'itemText',
323 316 valueField: 'itemValue',
324 317 },
325   - ifShow: ({ values }) => isTiming(values.executeWay),
  318 + ifShow: ({ values }) =>
  319 + exectueIsSchedule(values.executeWay) && exectueIsSchedule(values.executeWay),
326 320 },
327 321 {
328 322 field: 'devices',
329 323 label: '设备',
330   - component: 'Select',
  324 + component: 'Input',
331 325 slot: 'devices',
332 326 colProps: { span: 24 },
333 327 },
... ... @@ -338,42 +332,37 @@ export const formSchema: QFormSchema[] = [
338 332 component: 'Select',
339 333 componentProps: ({ formActionType }) => {
340 334 const { updateSchema, setFieldsValue } = formActionType;
341   - const options = [
342   - { label: DataTypeNameEnum.ORIGINAL, value: DataTypeEnum.ORIGINAL },
343   - { label: DataTypeNameEnum.AGG, value: DataTypeEnum.AGG },
344   - ];
345 335 return {
346   - options,
  336 + options: businesDataTypeOptions,
347 337 onSelect(e) {
348   - let dataCompareOpions: any = [];
349   - if (e == 0) {
350   - setFieldsValue({ agg: 'NONE' });
351   - dataCompareOpions = [{ label: '空', value: AggregateDataEnum.NONE }];
  338 + setFieldsValue({
  339 + [SchemaFiled.DATE_RANGE]: [],
  340 + [SchemaFiled.START_TS]: null,
  341 + [SchemaFiled.END_TS]: null,
  342 + [SchemaFiled.INTERVAL]: null,
  343 + dateGroupGap: null,
  344 + });
  345 + const setAgg = (agg, field = SchemaFiled.AGG, comObj) => {
  346 + setFieldsValue({ agg });
352 347 updateSchema({
353   - field: SchemaFiled.AGG,
354   - componentProps: {
355   - options: dataCompareOpions,
356   - },
  348 + field,
  349 + componentProps: comObj,
  350 + });
  351 + };
  352 + if (e == DataTypeEnum.ORIGINAL) {
  353 + //业务 选择原始数据
  354 + setAgg('NONE', SchemaFiled.AGG, {
  355 + options: businesAggOptions.filter((item) => item.value === AggregateDataEnum.NONE),
357 356 });
  357 + setFieldsValue({ limit: businesLimitValue.default });
358 358 } else {
359   - setFieldsValue({ agg: '' });
360   - dataCompareOpions = [
361   - { label: '最小值', value: AggregateDataEnum.MIN },
362   - { label: '最大值', value: AggregateDataEnum.MAX },
363   - { label: '平均值', value: AggregateDataEnum.AVG },
364   - { label: '求和', value: AggregateDataEnum.SUM },
365   - { label: '计数', value: AggregateDataEnum.COUNT },
366   - ];
367   - updateSchema({
368   - field: SchemaFiled.AGG,
369   - componentProps: {
370   - options: dataCompareOpions,
371   - },
  359 + //业务 选择聚合数据
  360 + setAgg('', SchemaFiled.AGG, {
  361 + options: businesAggOptions.filter((item) => item.value !== AggregateDataEnum.NONE),
372 362 });
373 363 }
374 364 },
375   - maxLength: 250,
376   - placeholder: '请选择属性性质',
  365 + placeholder: '请选择数据类型',
377 366 };
378 367 },
379 368 colProps: { span: 24 },
... ... @@ -393,15 +382,15 @@ export const formSchema: QFormSchema[] = [
393 382 required: true,
394 383 label: '最大条数',
395 384 component: 'InputNumber',
396   - defaultValue: 100,
  385 + defaultValue: businesLimitValue.default,
397 386 ifShow({ values }) {
398 387 return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;
399 388 },
400   - colProps: { span: 12 },
401 389 componentProps: {
  390 + style: { width: '10vw' },
402 391 placeholder: '请输入最大条数',
403   - min: 7,
404   - max: 50000,
  392 + min: businesLimitValue.min,
  393 + max: businesLimitValue.max,
405 394 },
406 395 },
407 396 {
... ... @@ -414,18 +403,20 @@ export const formSchema: QFormSchema[] = [
414 403 const { setFieldsValue } = formActionType;
415 404 return {
416 405 placeholder: '请选择查询周期',
417   - options: [
418   - { label: '固定周期', value: QueryWay.LATEST },
419   - { label: '自定义周期', value: QueryWay.TIME_PERIOD },
420   - ],
  406 + options: businesWayOptions,
421 407 onChange(value) {
422 408 value === QueryWay.LATEST
423 409 ? setFieldsValue({
424 410 [SchemaFiled.DATE_RANGE]: [],
425 411 [SchemaFiled.START_TS]: null,
426 412 [SchemaFiled.END_TS]: null,
  413 + [SchemaFiled.INTERVAL]: null,
  414 + dateGroupGap: null,
427 415 })
428   - : setFieldsValue({ [SchemaFiled.START_TS]: null });
  416 + : setFieldsValue({
  417 + [SchemaFiled.START_TS]: null,
  418 + [SchemaFiled.INTERVAL]: null,
  419 + });
429 420 },
430 421 };
431 422 },
... ... @@ -436,7 +427,7 @@ export const formSchema: QFormSchema[] = [
436 427 component: 'RangePicker',
437 428 required: true,
438 429 ifShow({ values }) {
439   - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay);
  430 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && exectueIsImmed(values.executeWay);
440 431 },
441 432 componentProps({ formActionType }) {
442 433 const { setFieldsValue } = formActionType;
... ... @@ -462,14 +453,12 @@ export const formSchema: QFormSchema[] = [
462 453 getPopupContainer: () => document.body,
463 454 };
464 455 },
465   - colProps: {
466   - span: 10,
467   - },
468 456 },
469 457 {
470 458 field: 'dateGroupGap',
471 459 label: '分组间隔',
472 460 component: 'Select',
  461 + colProps: { span: 24 },
473 462 dynamicRules: ({ model }) => {
474 463 return [
475 464 {
... ... @@ -480,7 +469,7 @@ export const formSchema: QFormSchema[] = [
480 469 ];
481 470 },
482 471 ifShow({ values }) {
483   - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay);
  472 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && exectueIsImmed(values.executeWay);
484 473 },
485 474 componentProps({ formModel, formActionType }) {
486 475 const options =
... ... @@ -542,3 +531,5 @@ export const formSchema: QFormSchema[] = [
542 531 },
543 532 },
544 533 ];
  534 +
  535 +export { SchemaFiled };
... ...
1   -.dynamic-delete-button {
2   - cursor: pointer;
3   - position: relative;
4   - top: 4px;
5   - font-size: 24px;
6   - color: #999;
7   - transition: all 0.3s;
8   -}
9   -
10   -.dynamic-delete-button:hover {
11   - color: #777;
12   -}
13   -
14   -.dynamic-delete-button[disabled] {
15   - cursor: not-allowed;
16   - opacity: 0.5;
17   -}
  1 +/**
  2 + * 报表配置相关枚举值定义
  3 + */
  4 +import { AggregateDataEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
  5 +
  6 +//业务权限配置枚举
  7 +export enum PermissionReportConfigEnum {
  8 + PERMISSION_POST = 'api:yt:report_form:config:post',
  9 + PERMISSION_GET = 'api:yt:report:get',
  10 + PERMISSION_DELETE = 'api:yt:report_form:config:delete',
  11 + PERMISSION_UPDATE = 'api:yt:report_form:config:update',
  12 +}
  13 +
  14 +//业务文字描述配置枚举
  15 +export enum BusinessReportConfigTextEnum {
  16 + BUSINESS_ADD_TEXT = '新增报表',
  17 + BUSINESS_EXPORT_TEXT = '下载报表',
  18 + BUSINESS_DELETE_TEXT = '批量删除',
  19 + BUSINESS_VIEW_DEVICE_TEXT = '查看设备',
  20 + BUSINESS_UPDATE_TEXT = '编辑报表',
  21 + BUSINESS_ENABLE_TEXT = '启用',
  22 + BUSINESS_DISABLE_TEXT = '禁用',
  23 + BUSINESS_VIEW_TEXT = '查看报表',
  24 + BUSINESS_EXECUTEWAY_HELPMESSAGE_TEXT = `立即执行,在创建完报表配置后,启用配置即执行;
  25 + 定时执行,用户定义执行时间,启用后,
  26 + 在满足执行时间条件后,自动执行。
  27 + `,
  28 +}
  29 +
  30 +//业务表格状态配置枚举
  31 +export enum BusinessReportConfigStatusEnum {
  32 + BUSINESS_ENABLE = 0,
  33 + BUSINESS_DISABLE = 1,
  34 +}
  35 +
  36 +//业务表单执行方式配置枚举
  37 +export enum BusinessExecutewayEnum {
  38 + BUSINESS_EXECUTEWAY_IMMEDIATE = 0,
  39 + BUSINESS_EXECUTEWAY_SCHEDULED = 1,
  40 +}
  41 +
  42 +//业务表单查询周期配置枚举
  43 +export enum QueryWay {
  44 + LATEST = 'latest',
  45 + TIME_PERIOD = 'timePeriod',
  46 +}
  47 +
  48 +//业务表单周期配置枚举
  49 +export enum CycleTypeEnum {
  50 + DAILY = 0,
  51 + WEEKLY = 1,
  52 + MONTHLY = 2,
  53 +}
  54 +
  55 +export enum SchemaFiled {
  56 + WAY = 'queryMode',
  57 + TIME_PERIOD = 'timePeriod',
  58 + KEYS = 'keys',
  59 + DATE_RANGE = 'dataRange',
  60 + START_TS = 'startTs',
  61 + END_TS = 'endTs',
  62 + INTERVAL = 'interval',
  63 + LIMIT = 'limit',
  64 + AGG = 'agg',
  65 + ORDER_BY = 'orderBy',
  66 + DATA_TYPE = 'dataType',
  67 +}
  68 +
  69 +export enum DataTypeEnum {
  70 + ORIGINAL = 0,
  71 + AGG = 1,
  72 +}
  73 +
  74 +export enum DataTypeNameEnum {
  75 + ORIGINAL = '原始数据',
  76 + AGG = '聚合数据',
  77 +}
  78 +
  79 +//映射执行方式文本值
  80 +export enum ExecuteWayNameEnum {
  81 + EXECUTEWAY_IMMEDIATE = '立即执行',
  82 + EXECUTEWAY_SCHEDULED = '定时执行',
  83 +}
  84 +
  85 +//业务表单执行方式配置项
  86 +export const businessExecuteWayOptions = [
  87 + {
  88 + label: '立即执行',
  89 + value: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
  90 + },
  91 + {
  92 + label: '定时执行',
  93 + value: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED,
  94 + },
  95 +];
  96 +
  97 +//业务表单查询周期配置项
  98 +export const businesQueryCycleOptions = [
  99 + {
  100 + label: '固定周期',
  101 + value: QueryWay.LATEST,
  102 + },
  103 + {
  104 + label: '自定义周期',
  105 + value: QueryWay.TIME_PERIOD,
  106 + },
  107 +];
  108 +
  109 +//业务表单周期配置项
  110 +export const businesCycleTypeOptions = [
  111 + { label: '每日', value: CycleTypeEnum.DAILY },
  112 + { label: '每周', value: CycleTypeEnum.WEEKLY },
  113 + { label: '每月', value: CycleTypeEnum.MONTHLY },
  114 +];
  115 +
  116 +//业务表单动态判断是否为定时执行配置项
  117 +export const exectueIsSchedule = (type: number) => {
  118 + return type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED;
  119 +};
  120 +
  121 +//业务表单动态判断是否为立即执行配置项
  122 +export const exectueIsImmed = (type: number) => {
  123 + return type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE;
  124 +};
  125 +
  126 +//业务表单动态判断是否为每周配置项
  127 +export const cycleTypeIsWeekly = (type: number) => {
  128 + return type === CycleTypeEnum.WEEKLY;
  129 +};
  130 +
  131 +//业务表单动态判断是否为每月配置项
  132 +export const cycleTypeIsMonthly = (type: number) => {
  133 + return type === CycleTypeEnum.MONTHLY;
  134 +};
  135 +
  136 +//业务表单每周每日每月默认值配置
  137 +export const cycleTypeSetDefault = {
  138 + DAILY: '0 0 0 * * ?',
  139 + WEEKLY: '0 0 0 ? * MON',
  140 + MONTHLY: '0 0 0 1 * ? *',
  141 +};
  142 +
  143 +//业务表单数据类型配置项
  144 +export const businesDataTypeOptions = [
  145 + { label: DataTypeNameEnum.ORIGINAL, value: DataTypeEnum.ORIGINAL },
  146 + { label: DataTypeNameEnum.AGG, value: DataTypeEnum.AGG },
  147 +];
  148 +
  149 +//业务表单聚合条件配置项
  150 +export const businesAggOptions = [
  151 + { label: '最小值', value: AggregateDataEnum.MIN },
  152 + { label: '最大值', value: AggregateDataEnum.MAX },
  153 + { label: '平均值', value: AggregateDataEnum.AVG },
  154 + { label: '求和', value: AggregateDataEnum.SUM },
  155 + { label: '计数', value: AggregateDataEnum.COUNT },
  156 + { label: '空', value: AggregateDataEnum.NONE },
  157 +];
  158 +
  159 +//业务表单最大条数配置项
  160 +export const businesLimitValue = {
  161 + default: 100,
  162 + min: 7,
  163 + max: 50000,
  164 +};
  165 +
  166 +//业务查询周期配置项
  167 +export const businesWayOptions = [
  168 + { label: '固定周期', value: QueryWay.LATEST },
  169 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  170 +];
... ...
  1 +/**
  2 + * 报表配置所需hooks
  3 + */
  4 +
  5 +import { ref } from 'vue';
  6 +import {
  7 + DataTypeEnum,
  8 + QueryWay,
  9 + SchemaFiled,
  10 + businesAggOptions,
  11 + BusinessExecutewayEnum,
  12 + businesWayOptions,
  13 + CycleTypeEnum,
  14 + BusinessReportConfigTextEnum,
  15 +} from '../enum';
  16 +import moment from 'moment';
  17 +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  18 +import { getAttribute, screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';
  19 +import { TSelectOption } from '../type';
  20 +import { AggregateDataEnum } from '/@/views/device/localtion/config.data';
  21 +import { useMessage } from '/@/hooks/web/useMessage';
  22 +
  23 +export const useHooks = () => {
  24 + const { createMessage } = useMessage();
  25 +
  26 + //获取设备
  27 + const getDeviceList = async (organizationId) => {
  28 + const { items } = await screenLinkPageByDeptIdGetDevice({
  29 + organizationId,
  30 + });
  31 + return items?.map((item) => {
  32 + if (item.deviceType !== DeviceTypeEnum.GATEWAY)
  33 + return {
  34 + label: item.alias ? item.alias : item.name,
  35 + value: item.tbDeviceId,
  36 + id: item.id,
  37 + deviceProfileId: item.deviceProfileId,
  38 + };
  39 + });
  40 + };
  41 +
  42 + //获取对应设备属性
  43 + const getDeviceAttr = async (deviceProfileId) => {
  44 + //业务 根据产品id
  45 + if (!deviceProfileId) return;
  46 + const res = await getAttribute(deviceProfileId);
  47 + if (!Array.isArray(res)) return;
  48 + return res.map((items) => {
  49 + const item = ref<TSelectOption>();
  50 + if (items?.identifier !== null) {
  51 + item.value = {
  52 + label: items?.identifier,
  53 + value: items?.identifier,
  54 + };
  55 + return item.value;
  56 + }
  57 + });
  58 + };
  59 +
  60 + //映射查询周期值
  61 + const mapQueryMode = (queryMode) => {
  62 + return queryMode === QueryWay.LATEST ? 0 : 1;
  63 + };
  64 +
  65 + //映射查询周期文本
  66 + const mapQueryModeText = (queryMode) => {
  67 + return queryMode === 0 ? QueryWay.LATEST : QueryWay.TIME_PERIOD;
  68 + };
  69 +
  70 + //要删除的字段,不需要传给服务端
  71 + const removeFields = [
  72 + 'agg',
  73 + 'interval',
  74 + 'queryMode',
  75 + 'startTs',
  76 + 'devices',
  77 + 'dataRange',
  78 + 'cycleType',
  79 + 'currentCycle',
  80 + 'cycleTime',
  81 + 'cronTime',
  82 + 'limit',
  83 + 'dateGroupGap',
  84 + ];
  85 +
  86 + //获取表单部分字段组合成queryCondition和cycle对象和根据cron表达式生成executeContent
  87 + const getQueryCondition = (values) => {
  88 + const {
  89 + agg,
  90 + queryMode,
  91 + startTs,
  92 + interval,
  93 + dateGroupGap,
  94 + cycleType,
  95 + currentCycle,
  96 + cycleTime,
  97 + cronTime,
  98 + limit,
  99 + } = values;
  100 + const startTsValue = ref();
  101 + const endTsValue = ref();
  102 + const intervalValue = ref();
  103 + if (queryMode === QueryWay.LATEST) {
  104 + //业务 查询周期为固定周期
  105 + startTsValue.value = moment().subtract(startTs, 'ms').valueOf();
  106 + endTsValue.value = Date.now();
  107 + intervalValue.value = interval;
  108 + } else {
  109 + //业务 查询周期为自定义周期
  110 + const defineDate = JSON.parse(JSON.stringify(values.dataRange));
  111 + startTsValue.value = moment(defineDate[0]).valueOf();
  112 + endTsValue.value = moment(defineDate[1]).valueOf();
  113 + intervalValue.value = dateGroupGap;
  114 + }
  115 + const executeContent = ref('');
  116 + if (cycleType === CycleTypeEnum.WEEKLY) {
  117 + executeContent.value = cronTime.slice(0, 6) + currentCycle.slice(5);
  118 + } else if (cycleType === CycleTypeEnum.DAILY) {
  119 + executeContent.value = cronTime;
  120 + } else if (cycleType === CycleTypeEnum.MONTHLY) {
  121 + executeContent.value = cronTime.slice(0, 6) + cycleTime.slice(5);
  122 + }
  123 + return [
  124 + {
  125 + limit,
  126 + agg,
  127 + interval: intervalValue.value,
  128 + queryMode: mapQueryMode(queryMode),
  129 + startTs: startTsValue.value,
  130 + endTs: endTsValue.value,
  131 + },
  132 + {
  133 + cycleType,
  134 + currentCycle,
  135 + cycleTime,
  136 + cronTime,
  137 + },
  138 + executeContent.value,
  139 + ];
  140 + };
  141 +
  142 + //新增默认设置部分字段(执行方式,查询周期,最近时间,间隔时间)
  143 + const setDefaultTime = () => {
  144 + return {
  145 + executeWay: BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_IMMEDIATE,
  146 + [SchemaFiled.WAY]: QueryWay.LATEST,
  147 + [SchemaFiled.START_TS]: 1000,
  148 + [SchemaFiled.INTERVAL]: 1000,
  149 + };
  150 + };
  151 +
  152 + //编辑回显queryCondition和cycle对象
  153 + const setQueryCondition = (value, cycle, executeContent) => {
  154 + const conditionObj = ref({});
  155 + //业务 查询周期是固定周期
  156 + if (value?.queryMode === 0) {
  157 + const formatNumber = (value?.endTs - value?.startTs) / 10;
  158 + const transNumber = Math.floor(formatNumber) * 10;
  159 + conditionObj.value = {
  160 + interval: value?.interval,
  161 + startTs: transNumber,
  162 + endTs: value?.endTs,
  163 + };
  164 + } else {
  165 + conditionObj.value = {
  166 + dataRange: [value?.startTs, value?.endTs],
  167 + dateGroupGap: value?.interval,
  168 + };
  169 + }
  170 + const spanDisance = executeContent?.split(' ');
  171 + const cronTime =
  172 + cycle?.cycleType === 2
  173 + ? spanDisance[2] < 10
  174 + ? executeContent.slice(0, 7) + '* * ?'
  175 + : executeContent.slice(0, 7) + ' ' + '* * ?'
  176 + : cycle?.cycleType === 1
  177 + ? spanDisance[2] < 10
  178 + ? executeContent.slice(0, 5) + ' ' + ' * * ?'
  179 + : executeContent.slice(0, 6) + ' ' + ' * * ?'
  180 + : executeContent;
  181 + return {
  182 + ...value,
  183 + ...conditionObj.value,
  184 + ...cycle,
  185 + cronTime,
  186 + queryMode: mapQueryModeText(value?.queryMode),
  187 + };
  188 + };
  189 +
  190 + //业务 回显聚合条件如果数据类型是原始数据则只有空
  191 + const setAggByDateType = (dataType) => {
  192 + const options = ref([]);
  193 + if (dataType === DataTypeEnum.ORIGINAL) {
  194 + options.value = businesAggOptions.filter(
  195 + (item) => item.value === AggregateDataEnum.NONE
  196 + ) as any;
  197 + } else
  198 + options.value = businesAggOptions.filter(
  199 + (item) => item.value !== AggregateDataEnum.NONE
  200 + ) as any;
  201 + return {
  202 + field: SchemaFiled.AGG,
  203 + componentProps: {
  204 + options: options.value,
  205 + },
  206 + };
  207 + };
  208 +
  209 + //业务 执行方式为定时执行 查询周期只有固定周期
  210 + const disableCustomWeekly = (type) => {
  211 + const options = ref([]);
  212 + if (type === BusinessExecutewayEnum.BUSINESS_EXECUTEWAY_SCHEDULED) {
  213 + options.value = businesWayOptions.filter((item) => item.value === QueryWay.LATEST) as any;
  214 + } else {
  215 + options.value = businesWayOptions as any;
  216 + }
  217 + return {
  218 + field: SchemaFiled.WAY,
  219 + componentProps: {
  220 + options: options.value,
  221 + },
  222 + };
  223 + };
  224 +
  225 + //Modal弹窗属性
  226 + const setPropsForModal = (text) => {
  227 + return {
  228 + loading: true,
  229 + title: text,
  230 + showOkBtn: text !== BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  231 + showCancelBtn: text !== BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  232 + };
  233 + };
  234 +
  235 + //验证设备以及所选属性
  236 + const validateSelectDevice = (values) => {
  237 + const throwErrorMsg = () => {
  238 + createMessage.error('请选择设备及其属性');
  239 + throw new Error('请选择设备及其属性');
  240 + };
  241 + if (Array.isArray(values) && values.length === 0) throwErrorMsg();
  242 + else {
  243 + values.forEach((f) => {
  244 + if (!f.attributes || f.attributes.length == 0) throwErrorMsg();
  245 + });
  246 + }
  247 + };
  248 +
  249 + return {
  250 + getDeviceList,
  251 + getQueryCondition,
  252 + removeFields,
  253 + setDefaultTime,
  254 + getDeviceAttr,
  255 + setQueryCondition,
  256 + setAggByDateType,
  257 + disableCustomWeekly,
  258 + setPropsForModal,
  259 + validateSelectDevice,
  260 + };
  261 +};
... ...
1 1 <template>
2 2 <div>
3   - <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo">
  3 + <BasicTable :clickToRowSelect="false" @register="registerTable">
4 4 <template #toolbar>
5   - <Authority value="api:yt:report_form:config:post">
6   - <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增报表 </a-button>
  5 + <Authority :value="PermissionReportConfigEnum.PERMISSION_POST">
  6 + <a-button
  7 + type="primary"
  8 + @click="handleBussinessDrawer(BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT, null)"
  9 + >
  10 + {{ BusinessReportConfigTextEnum.BUSINESS_ADD_TEXT }}
  11 + </a-button>
7 12 </Authority>
8   - <Authority value="api:yt:report:get">
9   - <a-button type="primary" @click="go('/report/export')"> 下载报表 </a-button>
  13 + <Authority :value="PermissionReportConfigEnum.PERMISSION_GET">
  14 + <a-button type="primary" @click="go('/report/export')">
  15 + {{ BusinessReportConfigTextEnum.BUSINESS_EXPORT_TEXT }}
  16 + </a-button>
10 17 </Authority>
11   - <Authority value="api:yt:report_form:config:delete">
  18 + <Authority :value="PermissionReportConfigEnum.PERMISSION_DELETE">
12 19 <Popconfirm
13 20 title="您确定要批量删除数据"
14 21 ok-text="确定"
15 22 cancel-text="取消"
16 23 @confirm="handleDeleteOrBatchDelete(null)"
17 24 >
18   - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
  25 + <a-button type="primary" color="error" :disabled="hasBatchDelete">
  26 + {{ BusinessReportConfigTextEnum.BUSINESS_DELETE_TEXT }}
  27 + </a-button>
19 28 </Popconfirm>
20 29 </Authority>
21 30 </template>
22 31 <template #doDeviceSlot="{ record }">
23 32 <a-button type="text" @click="handleDeviceView(record)">
24   - <span style="color: #377dff">查看设备</span>
  33 + <span style="color: #377dff">{{
  34 + BusinessReportConfigTextEnum.BUSINESS_VIEW_DEVICE_TEXT
  35 + }}</span>
25 36 </a-button>
26 37 </template>
27 38 <template #action="{ record }">
28 39 <TableAction
29 40 :actions="[
30 41 {
31   - label: '查看',
  42 + label: BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT.slice(0, 2),
32 43 icon: 'ant-design:eye-outlined',
33   - onClick: handleViewDetail.bind(null, record),
  44 + onClick: handleBussinessDrawer.bind(
  45 + null,
  46 + BusinessReportConfigTextEnum.BUSINESS_VIEW_TEXT,
  47 + record
  48 + ),
34 49 ifShow: record.status === 1,
35 50 },
36 51 {
37   - label: '编辑',
  52 + label: BusinessReportConfigTextEnum.BUSINESS_UPDATE_TEXT.slice(0, 2),
38 53 icon: 'clarity:note-edit-line',
39   - auth: 'api:yt:report_form:config:update',
40   - onClick: handleCreateOrEdit.bind(null, record),
  54 + auth: PermissionReportConfigEnum.PERMISSION_UPDATE,
  55 + onClick: handleBussinessDrawer.bind(
  56 + null,
  57 + BusinessReportConfigTextEnum.BUSINESS_UPDATE_TEXT,
  58 + record
  59 + ),
41 60 ifShow: record.status === 0,
42 61 },
43 62 {
44   - label: '删除',
  63 + label: BusinessReportConfigTextEnum.BUSINESS_DELETE_TEXT.slice(2),
45 64 icon: 'ant-design:delete-outlined',
46   - auth: 'api:yt:report_form:config:delete',
  65 + auth: PermissionReportConfigEnum.PERMISSION_DELETE,
47 66 color: 'error',
48 67 ifShow: record.status === 0,
49 68 popConfirm: {
... ... @@ -59,8 +78,8 @@
59 78 :disabled="disabledSwitch"
60 79 :checked="record.status === 1"
61 80 :loading="record.pendingStatus"
62   - checkedChildren="启用"
63   - unCheckedChildren="禁用"
  81 + :checkedChildren="BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT"
  82 + :unCheckedChildren="BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT"
64 83 @change="(checked: boolean) => statusChange(checked, record)"
65 84 />
66 85 </template>
... ... @@ -71,130 +90,96 @@
71 90 </template>
72 91
73 92 <script lang="ts" setup>
74   - import { reactive, nextTick, ref } from 'vue';
  93 + import { nextTick, ref } from 'vue';
75 94 import { BasicTable, useTable, TableAction } from '/@/components/Table';
76 95 import { useDrawer } from '/@/components/Drawer';
77   - import ReportConfigDrawer from './ReportConfigDrawer.vue';
78   - import DevicePreviewModal from './DevicePreviewModal.vue';
79 96 import {
80 97 reportPage,
81 98 deleteReportManage,
82 99 putReportByidAndStatusManage,
83 100 } from '/@/api/report/reportManager';
84   - import { searchFormSchema, columns } from './config.data';
  101 + import { defaultTableAttribtes } from './config';
85 102 import { Authority } from '/@/components/Authority';
86 103 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
87 104 import { Popconfirm, Switch } from 'ant-design-vue';
88 105 import { useModal } from '/@/components/Modal';
89 106 import { useGo } from '/@/hooks/web/usePage';
90 107 import { useMessage } from '/@/hooks/web/useMessage';
  108 + import { ReportConfigDrawer, DevicePreviewModal } from './components';
  109 + import {
  110 + PermissionReportConfigEnum,
  111 + BusinessReportConfigTextEnum,
  112 + BusinessReportConfigStatusEnum,
  113 + } from './enum';
91 114
92   - const searchInfo = reactive<Recordable>({});
93 115 const disabledSwitch = ref(false);
94 116
95 117 const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({
96   - title: '报表列表',
97 118 api: reportPage,
98   - columns,
99   - showIndexColumn: false,
100   - clickToRowSelect: false,
101   - formConfig: {
102   - labelWidth: 120,
103   - schemas: searchFormSchema,
104   - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
105   - },
106   - useSearchForm: true,
107   - showTableSetting: true,
108   - bordered: true,
109   - rowKey: 'id',
110   - actionColumn: {
111   - width: 200,
112   - title: '操作',
113   - dataIndex: 'action',
114   - slots: { customRender: 'action' },
115   - fixed: 'right',
116   - },
  119 + ...defaultTableAttribtes,
117 120 });
118 121
119   - // 弹框
  122 + // 业务弹窗
120 123 const [registerDrawer, { openDrawer }] = useDrawer();
  124 +
121 125 const { createMessage } = useMessage();
122 126
123   - // 刷新
124 127 const handleSuccess = () => {
125 128 reload();
126 129 };
127 130
128 131 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
129   - useBatchDelete(deleteReportManage, handleSuccess, setProps);
  132 + useBatchDelete(deleteReportManage, handleSuccess, setProps) as any;
130 133 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
131   - // Demo:status为1的选择框禁用
132   - if (record.status === 1) {
  134 + //业务 status为1 选择框则禁用
  135 + if (record.status === BusinessReportConfigStatusEnum.BUSINESS_DISABLE)
133 136 return { disabled: true };
134   - } else {
135   - return { disabled: false };
136   - }
  137 + else return { disabled: false };
137 138 };
138 139
139 140 nextTick(() => {
140 141 setProps(selectionOptions);
141 142 });
142 143
143   - // 新增或编辑
144   - const handleCreateOrEdit = (record: Recordable | null) => {
145   - if (record) {
146   - openDrawer(true, {
147   - isUpdate: true,
148   - record,
149   - isView: true,
150   - });
151   - } else {
152   - openDrawer(true, {
153   - isUpdate: false,
154   - isView: true,
155   - });
156   - }
157   - };
158   - const handleViewDetail = (record: Recordable) => {
159   - if (record) {
160   - openDrawer(true, {
161   - isUpdate: true,
162   - record,
163   - isView: false,
164   - });
165   - }
  144 + // 业务弹窗
  145 + const handleBussinessDrawer = (text, record) => {
  146 + const modalParams = {
  147 + text,
  148 + record,
  149 + };
  150 + openDrawer(true, modalParams);
166 151 };
167 152
168 153 //查看设备
169 154 const [registerModal, { openModal }] = useModal();
  155 +
170 156 const handleDeviceView = (record) => {
171 157 openModal(true, {
172 158 isUpdate: true,
173 159 record,
174 160 });
175 161 };
  162 +
  163 + const setPropsLoading = (loading) => {
  164 + setProps({
  165 + loading,
  166 + });
  167 + setSelectedRowKeys([]);
  168 + resetSelectedRowKeys();
  169 + };
  170 +
176 171 const statusChange = async (checked, record) => {
177 172 try {
178   - setProps({
179   - loading: true,
180   - });
181   - setSelectedRowKeys([]);
182   - resetSelectedRowKeys();
  173 + setPropsLoading(true);
183 174 disabledSwitch.value = true;
184 175 const newStatus = checked ? 1 : 0;
185 176 const res = await putReportByidAndStatusManage(record.id, newStatus);
186   - if (res && newStatus) {
187   - createMessage.success(`启用成功`);
188   - } else {
189   - createMessage.success('禁用成功');
190   - }
  177 + if (res && newStatus)
  178 + createMessage.success(`${BusinessReportConfigTextEnum.BUSINESS_ENABLE_TEXT}成功`);
  179 + else createMessage.success(`${BusinessReportConfigTextEnum.BUSINESS_DISABLE_TEXT}成功`);
191 180 } finally {
192   - setTimeout(() => {
193   - setProps({
194   - loading: false,
195   - });
196   - disabledSwitch.value = false;
197   - }, 500);
  181 + setPropsLoading(false);
  182 + disabledSwitch.value = false;
198 183 reload();
199 184 }
200 185 };
... ...
1   -interface IOptionConfig {
2   - label: string;
3   - value: number;
4   -}
5   -
6   -export const optionsConfig: IOptionConfig[] = [
7   - {
8   - label: '1秒',
9   - value: 1000,
10   - },
11   - {
12   - label: '5秒',
13   - value: 5000,
14   - },
15   - {
16   - label: '10秒',
17   - value: 10000,
18   - },
19   - {
20   - label: '15秒',
21   - value: 15000,
22   - },
23   - {
24   - label: '30秒',
25   - value: 30000,
26   - },
27   - {
28   - label: '1分钟',
29   - value: 60000,
30   - },
31   - {
32   - label: '2分钟',
33   - value: 120000,
34   - },
35   - {
36   - label: '5分钟',
37   - value: 300000,
38   - },
39   - {
40   - label: '10分钟',
41   - value: 600000,
42   - },
43   - {
44   - label: '15分钟',
45   - value: 900000,
46   - },
47   - {
48   - label: '30分钟',
49   - value: 1800000,
50   - },
51   - {
52   - label: '1小时',
53   - value: 3600000,
54   - },
55   - {
56   - label: '2小时',
57   - value: 7200000,
58   - },
59   - {
60   - label: '5小时',
61   - value: 18000000,
62   - },
63   - {
64   - label: '10小时',
65   - value: 36000000,
66   - },
67   - {
68   - label: '12小时',
69   - value: 43200000,
70   - },
71   - {
72   - label: '1天',
73   - value: 86400000,
74   - },
75   -];
76   -
77   -export enum TypeEnum {
78   - IS_TIMING = 1,
79   - IS_WEEK = 1,
80   - IS_MONTH = 2,
81   - IS_EMPTY = 'NONE',
82   - IS_DEFAULT_WEEK = 'defaultIsWeek',
83   - IS_FIXED_WEEK = '2',
84   - IS_MIN = 'MIN',
85   - IS_MAX = 'MAX',
86   - IS_AVG = 'AVG',
87   - IS_SUM = 'SUM',
88   - COUNT = 'COUNT',
89   - IS_FIXED_TIME = 1,
90   -}
91   -
92   -export enum AggregateDataEnum {
93   - MIN = 'MIN',
94   - MAX = 'MAX',
95   - AVG = 'AVG',
96   - SUM = 'SUM',
97   - COUNT = 'COUNT',
98   - NONE = 'NONE',
99   -}
100   -export const isFixedTime = (type: string) => {
101   - return type === TypeEnum.IS_FIXED_TIME;
102   -};
103   -
104   -export const isTiming = (type: string) => {
105   - return type === TypeEnum.IS_TIMING;
106   -};
107   -
108   -export const isWeek = (type: string) => {
109   - return type === TypeEnum.IS_WEEK;
110   -};
111   -
112   -export const isMonth = (type: string) => {
113   - return type === TypeEnum.IS_MONTH;
114   -};
115   -
116   -export const isEmpty = (type: string) => {
117   - return type === TypeEnum.IS_EMPTY;
118   -};
119   -
120   -export const isDefultWeek = (type: string) => {
121   - return type === TypeEnum.IS_DEFAULT_WEEK;
122   -};
123   -export const isFixedWeek = (type: string) => {
124   - return type === TypeEnum.IS_FIXED_WEEK;
125   -};
126   -
127   -export const isMin = (type: string) => {
128   - return type === TypeEnum.IS_MIN;
129   -};
130   -
131   -export const isMax = (type: string) => {
132   - return type === TypeEnum.IS_MAX;
133   -};
134   -
135   -export const isAvg = (type: string) => {
136   - return type === TypeEnum.IS_AVG;
137   -};
138   -export const isSum = (type: string) => {
139   - return type === TypeEnum.IS_SUM;
140   -};
141   -
142   -export const isCountAll = (type: string) => {
143   - return type === TypeEnum.COUNT;
144   -};
  1 +/**
  2 + * 报表配置相关类型定义
  3 + */
  4 +
  5 +//设备列表类型定义
  6 +export type TDeviceList = {
  7 + key?: string;
  8 + value?: string;
  9 + label?: string;
  10 + attribute?: string;
  11 + device?: string;
  12 + name?: string;
  13 + attributes?: string | undefined;
  14 + deviceProfileId?: string;
  15 + id?: string;
  16 +};
  17 +
  18 +//设备下拉框类型定义
  19 +export type TSelectOption = {
  20 + label: string;
  21 + value: string;
  22 + deviceProfileId?: string;
  23 + id?: string;
  24 +};
  25 +
  26 +//设备属性
  27 +export interface Params {
  28 + [x: string]: string;
  29 + attributes: any;
  30 + device: string;
  31 +}
... ...
1   -.wrapper {
2   - margin: 10px 60px 60px 60px;
3   -}
4   -
5   -.inner {
6   - width: 400px;
7   - height: 400px;
8   -}
9   -
10   -.item {
11   - text-align: center;
12   - font-size: 200%;
13   - color: #fff;
14   -}
src/views/report/export/components/ReportPreviewModal.vue renamed from src/views/report/export/ReportPreviewModal.vue
... ... @@ -306,7 +306,20 @@
306 306 });
307 307 </script>
308 308 <style lang="less" scoped>
309   - @import url('./ReportPreviewModal.less');
  309 + .wrapper {
  310 + margin: 10px 60px 60px 60px;
  311 + }
  312 +
  313 + .inner {
  314 + width: 400px;
  315 + height: 400px;
  316 + }
  317 +
  318 + .item {
  319 + text-align: center;
  320 + font-size: 200%;
  321 + color: #fff;
  322 + }
310 323
311 324 .chart-style {
312 325 display: flex;
... ...
  1 +import ReportPreviewModal from './ReportPreviewModal.vue';
  2 +
  3 +export { ReportPreviewModal };
... ...
src/views/report/export/config.ts renamed from src/views/report/export/config.data.ts
1   -import { BasicColumn, FormSchema } from '/@/components/Table';
  1 +import { BasicColumn, BasicTableProps, FormSchema } from '/@/components/Table';
2 2 import moment from 'moment';
3 3 import { h } from 'vue';
4 4 import { Tag } from 'ant-design-vue';
  5 +import { DataTypeNameEnum, ExecuteWayNameEnum } from '../config/enum';
5 6
6 7 // 表格配置
7 8 export const columns: BasicColumn[] = [
... ... @@ -20,7 +21,7 @@ export const columns: BasicColumn[] = [
20 21 dataIndex: 'dataType',
21 22 width: 120,
22 23 format: (_text: string, record: Recordable) => {
23   - return record.dataCompare === 0 ? '原始数据' : '聚合数据';
  24 + return record.dataCompare === 0 ? DataTypeNameEnum.ORIGINAL : DataTypeNameEnum.AGG;
24 25 },
25 26 },
26 27 {
... ... @@ -28,7 +29,9 @@ export const columns: BasicColumn[] = [
28 29 dataIndex: 'executeWay',
29 30 width: 120,
30 31 format: (_text: string, record: Recordable) => {
31   - return record.executeWay === 0 ? '立即执行' : '定时执行';
  32 + return record.executeWay === 0
  33 + ? ExecuteWayNameEnum.EXECUTEWAY_IMMEDIATE
  34 + : ExecuteWayNameEnum.EXECUTEWAY_SCHEDULED;
32 35 },
33 36 },
34 37 {
... ... @@ -49,7 +52,7 @@ export const columns: BasicColumn[] = [
49 52 },
50 53 ];
51 54
52   -// 查询配置
  55 +// 表格查询配置
53 56 export const searchFormSchema: FormSchema[] = [
54 57 {
55 58 field: 'reportConfigName',
... ... @@ -96,3 +99,27 @@ export const searchFormSchema: FormSchema[] = [
96 99 colProps: { span: 6 },
97 100 },
98 101 ];
  102 +
  103 +//表格通用属性配置
  104 +export const defaultTableAttribtes: BasicTableProps = {
  105 + title: '报表导出列表',
  106 + columns,
  107 + showIndexColumn: false,
  108 + clickToRowSelect: false,
  109 + formConfig: {
  110 + labelWidth: 120,
  111 + schemas: searchFormSchema,
  112 + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
  113 + },
  114 + useSearchForm: true,
  115 + showTableSetting: true,
  116 + bordered: true,
  117 + rowKey: 'id',
  118 + actionColumn: {
  119 + width: 200,
  120 + title: '操作',
  121 + dataIndex: 'action',
  122 + slots: { customRender: 'action' },
  123 + fixed: 'right',
  124 + },
  125 +};
... ...
  1 +/**
  2 + * 报表导出相关枚举值定义
  3 + */
  4 +
  5 +//业务权限配置枚举
  6 +export enum PermissionReportExportEnum {
  7 + PERMISSION_GET = 'api:yt:reportExport:get',
  8 + PERMISSION_EXPORT = 'api:yt:reportExport:export',
  9 + PERMISSION_DELETE = 'api:yt:report:generate:record:delete',
  10 +}
  11 +
  12 +//业务文字描述配置枚举
  13 +export enum BusinessReportExportTextEnum {
  14 + BUSINESS_EXPORT_TEXT = '报表导出',
  15 + BUSINESS_DELETE_TEXT = '批量删除',
  16 + BUSINESS_VIEW_TEXT = '报表查看',
  17 +}
... ...
1 1 <template>
2 2 <div>
3   - <BasicTable :clickToRowSelect="false" @register="registerTable" :searchInfo="searchInfo">
  3 + <BasicTable :clickToRowSelect="false" @register="registerTable">
4 4 <template #toolbar>
5   - <Authority value="api:yt:report:generate:record:delete">
  5 + <Authority :value="PermissionReportExportEnum.PERMISSION_DELETE">
6 6 <Popconfirm
7 7 title="您确定要批量删除数据"
8 8 ok-text="确定"
9 9 cancel-text="取消"
10 10 @confirm="handleDeleteOrBatchDelete(null)"
11 11 >
12   - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button>
  12 + <a-button type="primary" color="error" :disabled="hasBatchDelete">
  13 + {{ BusinessReportExportTextEnum.BUSINESS_DELETE_TEXT }}
  14 + </a-button>
13 15 </Popconfirm>
14 16 </Authority>
15 17 </template>
... ... @@ -17,9 +19,9 @@
17 19 <TableAction
18 20 :actions="[
19 21 {
20   - label: '报表导出',
  22 + label: BusinessReportExportTextEnum.BUSINESS_EXPORT_TEXT,
21 23 icon: 'ant-design:dot-chart-outlined',
22   - auth: 'api:yt:reportExport:export',
  24 + auth: PermissionReportExportEnum.PERMISSION_EXPORT,
23 25 ifShow: record.executeStatus === 1,
24 26 popConfirm: {
25 27 title: '是否需要导出',
... ... @@ -27,15 +29,15 @@
27 29 },
28 30 },
29 31 {
30   - label: '报表查看',
  32 + label: BusinessReportExportTextEnum.BUSINESS_VIEW_TEXT,
31 33 icon: 'clarity:note-edit-line',
32   - auth: 'api:yt:reportExport:get',
  34 + auth: PermissionReportExportEnum.PERMISSION_GET,
33 35 onClick: handleView.bind(null, record),
34 36 },
35 37 {
36   - label: '删除',
  38 + label: BusinessReportExportTextEnum.BUSINESS_DELETE_TEXT.slice(2),
37 39 icon: 'ant-design:delete-outlined',
38   - auth: 'api:yt:report:generate:record:delete',
  40 + auth: PermissionReportExportEnum.PERMISSION_DELETE,
39 41 color: 'error',
40 42 popConfirm: {
41 43 title: '是否确认删除',
... ... @@ -51,40 +53,21 @@
51 53 </template>
52 54
53 55 <script lang="ts" setup>
54   - import { reactive, nextTick } from 'vue';
  56 + import { nextTick } from 'vue';
55 57 import { BasicTable, useTable, TableAction } from '/@/components/Table';
56   - import { searchFormSchema, columns } from './config.data';
  58 + import { defaultTableAttribtes } from './config';
57 59 import { Authority } from '/@/components/Authority';
58 60 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
59 61 import { Popconfirm } from 'ant-design-vue';
60 62 import { useModal } from '/@/components/Modal';
61   - import ReportPreviewModal from './ReportPreviewModal.vue';
  63 + import { ReportPreviewModal } from './components';
62 64 import { exportPage, deleteExportManage } from '/@/api/export/exportManager';
63 65 import { downloadByUrl } from '/@/utils/file/download';
  66 + import { PermissionReportExportEnum, BusinessReportExportTextEnum } from './enum';
64 67
65   - const searchInfo = reactive<Recordable>({});
66 68 const [registerTable, { reload, setProps }] = useTable({
67   - title: '报表导出列表',
68 69 api: exportPage,
69   - columns,
70   - showIndexColumn: false,
71   - clickToRowSelect: false,
72   - formConfig: {
73   - labelWidth: 120,
74   - schemas: searchFormSchema,
75   - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']],
76   - },
77   - useSearchForm: true,
78   - showTableSetting: true,
79   - bordered: true,
80   - rowKey: 'id',
81   - actionColumn: {
82   - width: 200,
83   - title: '操作',
84   - dataIndex: 'action',
85   - slots: { customRender: 'action' },
86   - fixed: 'right',
87   - },
  70 + ...defaultTableAttribtes,
88 71 });
89 72
90 73 const handleSuccess = () => {
... ... @@ -101,19 +84,23 @@
101 84 setProps(selectionOptions);
102 85 });
103 86
  87 + //业务弹窗
104 88 const [registerModal, { openModal }] = useModal();
  89 +
105 90 const handleView = (record) => {
106 91 openModal(true, {
107 92 isUpdate: true,
108 93 record,
109 94 });
110 95 };
  96 +
111 97 const exportUrlsFunc = (fUrl) => {
112 98 const options: any = {
113 99 url: fUrl,
114 100 };
115 101 downloadByUrl(options);
116 102 };
  103 +
117 104 const handleExport = (record) => {
118 105 if (record.reportPath) {
119 106 const urls = record.reportPath.split(',');
... ...