Commit 95403b74f74061acfee77997164af33afc9dfb7a
Merge branch 'main_dev' of http://git.yunteng.com/yunteng/thingskit-front into f…
…ix/board-style-issues
Showing
16 changed files
with
187 additions
and
49 deletions
| ... | ... | @@ -28,6 +28,8 @@ enum DeviceManagerApi { |
| 28 | 28 | |
| 29 | 29 | DEVICE_ALARM_URL = '/alarm', |
| 30 | 30 | |
| 31 | + ALARM_BATCH_ACK = '/alarm/batch/ack', | |
| 32 | + | |
| 31 | 33 | DEVICE_CREDENTIALS = '/device/credentials', |
| 32 | 34 | |
| 33 | 35 | COMMAND_ISSUANCE = '/rpc', |
| ... | ... | @@ -346,3 +348,13 @@ export const getDevicesByDeviceIds = (ids: string[]) => { |
| 346 | 348 | data: ids, |
| 347 | 349 | }); |
| 348 | 350 | }; |
| 351 | + | |
| 352 | +export const doBatchAckAlarm = (ids: string[]) => { | |
| 353 | + return defHttp.post( | |
| 354 | + { | |
| 355 | + url: DeviceManagerApi.ALARM_BATCH_ACK, | |
| 356 | + data: { alarmIds: ids }, | |
| 357 | + }, | |
| 358 | + { joinPrefix: false } | |
| 359 | + ); | |
| 360 | +}; | ... | ... |
| ... | ... | @@ -18,6 +18,9 @@ |
| 18 | 18 | 查看告警详情 |
| 19 | 19 | </a-button> |
| 20 | 20 | </template> |
| 21 | + <template #toolbar> | |
| 22 | + <Button @click="handleBatchAck" type="primary">批量处理</Button> | |
| 23 | + </template> | |
| 21 | 24 | </BasicTable> |
| 22 | 25 | <AlarmDetailDrawer @register="registerDetailDrawer" @success="handleSuccess" /> |
| 23 | 26 | </div> |
| ... | ... | @@ -26,10 +29,10 @@ |
| 26 | 29 | import { defineComponent, nextTick, h } from 'vue'; |
| 27 | 30 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
| 28 | 31 | import { alarmColumns, alarmSearchSchemas } from './config/detail.config'; |
| 29 | - import { getDeviceAlarm } from '/@/api/device/deviceManager'; | |
| 32 | + import { doBatchAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; | |
| 30 | 33 | import { useDrawer } from '/@/components/Drawer'; |
| 31 | 34 | import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue'; |
| 32 | - import { Modal } from 'ant-design-vue'; | |
| 35 | + import { Modal, Button } from 'ant-design-vue'; | |
| 33 | 36 | import { JsonPreview } from '/@/components/CodeEditor'; |
| 34 | 37 | import { getDeviceDetail } from '/@/api/device/deviceManager'; |
| 35 | 38 | import { getAttribute } from '/@/api/ruleengine/ruleengineApi'; |
| ... | ... | @@ -38,17 +41,21 @@ |
| 38 | 41 | operationString, |
| 39 | 42 | operationBoolean, |
| 40 | 43 | } from '/@/views/rule/linkedge/config/formatData'; |
| 44 | + import { AlarmLogItem } from '/@/api/device/model/deviceConfigModel'; | |
| 45 | + import { AlarmStatus } from '/@/enums/alarmEnum'; | |
| 46 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
| 41 | 47 | |
| 42 | 48 | export default defineComponent({ |
| 43 | 49 | name: 'AlarmCenter', |
| 44 | 50 | components: { |
| 51 | + Button, | |
| 45 | 52 | BasicTable, |
| 46 | 53 | TableAction, |
| 47 | 54 | AlarmDetailDrawer, |
| 48 | 55 | }, |
| 49 | 56 | |
| 50 | 57 | setup() { |
| 51 | - const [registerTable, { reload }] = useTable({ | |
| 58 | + const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({ | |
| 52 | 59 | title: '告警记录列表', |
| 53 | 60 | api: getDeviceAlarm, |
| 54 | 61 | columns: alarmColumns, |
| ... | ... | @@ -61,6 +68,14 @@ |
| 61 | 68 | bordered: true, |
| 62 | 69 | showIndexColumn: false, |
| 63 | 70 | showTableSetting: true, |
| 71 | + rowSelection: { | |
| 72 | + type: 'checkbox', | |
| 73 | + getCheckboxProps: (record: AlarmLogItem) => { | |
| 74 | + return { | |
| 75 | + disabled: record.status === AlarmStatus.CLEARED_ACK, | |
| 76 | + }; | |
| 77 | + }, | |
| 78 | + }, | |
| 64 | 79 | actionColumn: { |
| 65 | 80 | width: 200, |
| 66 | 81 | title: '操作', |
| ... | ... | @@ -148,12 +163,24 @@ |
| 148 | 163 | attribute, |
| 149 | 164 | }; |
| 150 | 165 | }; |
| 166 | + | |
| 167 | + const { createMessage } = useMessage(); | |
| 168 | + const handleBatchAck = async () => { | |
| 169 | + const ids = getSelectRows<AlarmLogItem>().map((item) => item.id); | |
| 170 | + | |
| 171 | + await doBatchAckAlarm(ids); | |
| 172 | + createMessage.success('操作成功'); | |
| 173 | + clearSelectedRowKeys(); | |
| 174 | + reload(); | |
| 175 | + }; | |
| 176 | + | |
| 151 | 177 | return { |
| 152 | 178 | registerTable, |
| 153 | 179 | registerDetailDrawer, |
| 154 | 180 | handleDetail, |
| 155 | 181 | handleSuccess, |
| 156 | 182 | handleViewAlarmDetails, |
| 183 | + handleBatchAck, | |
| 157 | 184 | }; |
| 158 | 185 | }, |
| 159 | 186 | }); | ... | ... |
| ... | ... | @@ -91,7 +91,7 @@ export const formSchema: FormSchema[] = [ |
| 91 | 91 | valueField: 'fileList', |
| 92 | 92 | componentProps: () => { |
| 93 | 93 | return { |
| 94 | - // listType: 'picture-card', | |
| 94 | + listType: 'picture-card', | |
| 95 | 95 | maxFileLimit: 1, |
| 96 | 96 | api: async (file: File) => { |
| 97 | 97 | try { |
| ... | ... | @@ -110,10 +110,10 @@ export const formSchema: FormSchema[] = [ |
| 110 | 110 | onPreview: (fileList: FileItem) => { |
| 111 | 111 | createImgPreview({ imageList: [fileList.url!] }); |
| 112 | 112 | }, |
| 113 | - showUploadList: { | |
| 114 | - showDownloadIcon: true, | |
| 115 | - showRemoveIcon: true, | |
| 116 | - }, | |
| 113 | + // showUploadList: { | |
| 114 | + // showDownloadIcon: true, | |
| 115 | + // showRemoveIcon: true, | |
| 116 | + // }, | |
| 117 | 117 | }; |
| 118 | 118 | }, |
| 119 | 119 | }, | ... | ... |
| ... | ... | @@ -22,7 +22,7 @@ |
| 22 | 22 | watch( |
| 23 | 23 | () => props.customerList, |
| 24 | 24 | (newValue) => { |
| 25 | - const transferResult = newValue.map((item) => [item.ts, item.value]); | |
| 25 | + const transferResult = newValue.map((item) => [item.date, item.value]); | |
| 26 | 26 | |
| 27 | 27 | setOptions({ |
| 28 | 28 | tooltip: { |
| ... | ... | @@ -35,7 +35,7 @@ |
| 35 | 35 | }, |
| 36 | 36 | }, |
| 37 | 37 | xAxis: { |
| 38 | - type: 'time', | |
| 38 | + type: 'category', | |
| 39 | 39 | splitLine: { |
| 40 | 40 | show: true, |
| 41 | 41 | lineStyle: { |
| ... | ... | @@ -90,7 +90,7 @@ |
| 90 | 90 | trend: props.type, |
| 91 | 91 | }); |
| 92 | 92 | |
| 93 | - const transferResult = res.map((item) => [item.ts, item.value]); | |
| 93 | + const transferResult = res.map((item) => [item.date, item.value]); | |
| 94 | 94 | setOptions({ |
| 95 | 95 | tooltip: { |
| 96 | 96 | trigger: 'axis', | ... | ... |
| ... | ... | @@ -31,7 +31,7 @@ |
| 31 | 31 | }, |
| 32 | 32 | }, |
| 33 | 33 | xAxis: { |
| 34 | - type: 'time', | |
| 34 | + type: 'category', | |
| 35 | 35 | splitLine: { |
| 36 | 36 | show: true, |
| 37 | 37 | lineStyle: { |
| ... | ... | @@ -79,11 +79,11 @@ |
| 79 | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
| 80 | 80 | onMounted(async () => { |
| 81 | 81 | const res = await getTrendData({ |
| 82 | - ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), | |
| 82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_1_MONTH), | |
| 83 | 83 | trend: 'CUSTOMER_TREND', |
| 84 | 84 | }); |
| 85 | 85 | |
| 86 | - const transferResult = res.map((item) => [item.ts, item.value]); | |
| 86 | + const transferResult = res.map((item) => [item.date, item.value]); | |
| 87 | 87 | setOptions({ |
| 88 | 88 | tooltip: { |
| 89 | 89 | trigger: 'axis', |
| ... | ... | @@ -95,7 +95,7 @@ |
| 95 | 95 | }, |
| 96 | 96 | }, |
| 97 | 97 | xAxis: { |
| 98 | - type: 'time', | |
| 98 | + type: 'category', | |
| 99 | 99 | splitLine: { |
| 100 | 100 | show: true, |
| 101 | 101 | lineStyle: { | ... | ... |
| ... | ... | @@ -37,7 +37,15 @@ |
| 37 | 37 | <DatePicker |
| 38 | 38 | @change="(_, DateString) => onDateChange(_, DateString, role === RoleEnum.CUSTOMER_USER)" |
| 39 | 39 | v-model:value="dateValue" |
| 40 | - /> | |
| 40 | + > | |
| 41 | + <Button | |
| 42 | + type="link" | |
| 43 | + class="!px-0" | |
| 44 | + :style="dateValue ? { color: '#0960bd', fontWeight: 500 } : { color: '#000000d9' }" | |
| 45 | + > | |
| 46 | + {{ dateValue ? (dateValue as moment.Moment).format('YYYY-MM-DD') : '自定义' }} | |
| 47 | + </Button> | |
| 48 | + </DatePicker> | |
| 41 | 49 | </div> |
| 42 | 50 | </template> |
| 43 | 51 | <div v-if="activeKey === '1'"> |
| ... | ... | @@ -99,13 +107,13 @@ |
| 99 | 107 | <Tooltip :overlayStyle="{ maxWidth: '340px' }"> |
| 100 | 108 | <template #title> |
| 101 | 109 | <section> |
| 102 | - <div>30天: 查询最近30天的数据,间隔时间为1天.</div> | |
| 110 | + <div>最近一个月: 查询最近一个月的数据,间隔时间为1天.</div> | |
| 103 | 111 | <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div> |
| 104 | - <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div> | |
| 112 | + <div>最近一年: 查询最近一年的数据,间隔时间为1月.</div> | |
| 105 | 113 | <div> |
| 106 | 114 | 间隔时间: |
| 107 | 115 | <span class="font-bold underline"> 以当天的(最后时间)作为结束时间 </span> |
| 108 | - ,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | |
| 116 | + ,往前推移对应天数或月的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | |
| 109 | 117 | </div> |
| 110 | 118 | </section> |
| 111 | 119 | </template> |
| ... | ... | @@ -120,9 +128,28 @@ |
| 120 | 128 | </template> |
| 121 | 129 | <DatePicker.RangePicker |
| 122 | 130 | @change="onDateCustomerChange" |
| 131 | + :disabledDate="handleDisableDate" | |
| 132 | + @calendarChange="handleCalendarChange" | |
| 123 | 133 | size="small" |
| 124 | 134 | v-model:value="customerDateValue" |
| 125 | - /> | |
| 135 | + > | |
| 136 | + <Button | |
| 137 | + type="link" | |
| 138 | + class="!px-0" | |
| 139 | + :style=" | |
| 140 | + customerDateValue && customerDateValue.length | |
| 141 | + ? { color: '#0960bd', fontWeight: 500 } | |
| 142 | + : { color: '#000000d9' } | |
| 143 | + " | |
| 144 | + >{{ | |
| 145 | + customerDateValue && customerDateValue.length | |
| 146 | + ? `${(customerDateValue?.[0] as moment.Moment)?.format('YYYY-MM-DD')} | |
| 147 | + ~ | |
| 148 | + ${(customerDateValue?.[1] as moment.Moment)?.format('YYYY-MM-DD')}` | |
| 149 | + : '自定义' | |
| 150 | + }}</Button | |
| 151 | + > | |
| 152 | + </DatePicker.RangePicker> | |
| 126 | 153 | </div> |
| 127 | 154 | </template> |
| 128 | 155 | <CustomerTrend :customerTrendList="customerTrendList" /> |
| ... | ... | @@ -130,8 +157,8 @@ |
| 130 | 157 | </div> |
| 131 | 158 | </template> |
| 132 | 159 | <script lang="ts" setup> |
| 133 | - import { ref, reactive } from 'vue'; | |
| 134 | - import { Card, DatePicker, Tooltip } from 'ant-design-vue'; | |
| 160 | + import { ref, reactive, unref } from 'vue'; | |
| 161 | + import { Card, DatePicker, Tooltip, Button } from 'ant-design-vue'; | |
| 135 | 162 | import VisitAnalysis from './VisitAnalysis.vue'; |
| 136 | 163 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
| 137 | 164 | import { RoleEnum, isAdmin } from '/@/enums/roleEnum'; |
| ... | ... | @@ -146,6 +173,7 @@ |
| 146 | 173 | import { getTrendData } from '/@/api/dashboard'; |
| 147 | 174 | import { useGlobSetting } from '/@/hooks/setting'; |
| 148 | 175 | import { QuestionCircleOutlined } from '@ant-design/icons-vue'; |
| 176 | + import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface'; | |
| 149 | 177 | |
| 150 | 178 | defineExpose({ |
| 151 | 179 | isAdmin, |
| ... | ... | @@ -496,6 +524,18 @@ |
| 496 | 524 | // onDateTenantChange, |
| 497 | 525 | onDateCustomerChange, |
| 498 | 526 | } = useDate(); |
| 527 | + | |
| 528 | + const handleCalendarChange = (val: RangePickerValue) => { | |
| 529 | + customerDateValue.value = val as any; | |
| 530 | + }; | |
| 531 | + | |
| 532 | + const handleDisableDate = (current: moment.Moment) => { | |
| 533 | + if (!unref(customerDateValue) || unref(customerDateValue).length === 0) { | |
| 534 | + return false; | |
| 535 | + } | |
| 536 | + const diffDate = current.diff(unref(customerDateValue)[0], 'days'); | |
| 537 | + return Math.abs(diffDate) > 30; | |
| 538 | + }; | |
| 499 | 539 | </script> |
| 500 | 540 | |
| 501 | 541 | <style lang="less"> | ... | ... |
| ... | ... | @@ -47,7 +47,15 @@ |
| 47 | 47 | <DatePicker |
| 48 | 48 | @change="(_, DateString) => onDateChange(_, DateString, role === RoleEnum.CUSTOMER_USER)" |
| 49 | 49 | v-model:value="dateValue" |
| 50 | - /> | |
| 50 | + > | |
| 51 | + <Button | |
| 52 | + type="link" | |
| 53 | + class="!px-0" | |
| 54 | + :style="dateValue ? { color: '#0960bd', fontWeight: 500 } : { color: '#000000d9' }" | |
| 55 | + > | |
| 56 | + {{ dateValue ? (dateValue as moment.Moment).format('YYYY-MM-DD') : '自定义' }} | |
| 57 | + </Button> | |
| 58 | + </DatePicker> | |
| 51 | 59 | </div> |
| 52 | 60 | </template> |
| 53 | 61 | <!-- <div v-if="activeKey === '1'"> |
| ... | ... | @@ -84,13 +92,13 @@ |
| 84 | 92 | <Tooltip :overlayStyle="{ maxWidth: '340px' }"> |
| 85 | 93 | <template #title> |
| 86 | 94 | <section> |
| 87 | - <div>30天: 查询最近30天的数据,间隔时间为1天.</div> | |
| 95 | + <div>最近一个月: 查询最近一个月的数据,间隔时间为1天.</div> | |
| 88 | 96 | <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div> |
| 89 | - <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div> | |
| 97 | + <div>最近一年: 查询最近一年的数据,间隔时间为1月.</div> | |
| 90 | 98 | <div> |
| 91 | 99 | 间隔时间: |
| 92 | 100 | <span class="font-bold underline"> 以当天的(最后时间)作为结束时间 </span> |
| 93 | - ,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | |
| 101 | + ,往前推移对应天数或月的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | |
| 94 | 102 | </div> |
| 95 | 103 | </section> |
| 96 | 104 | </template> |
| ... | ... | @@ -106,8 +114,27 @@ |
| 106 | 114 | <DatePicker.RangePicker |
| 107 | 115 | @change="onDateTenantChange" |
| 108 | 116 | size="small" |
| 117 | + @calendarChange="handleCalendarChange" | |
| 118 | + :disabledDate="handleDisableDate" | |
| 109 | 119 | v-model:value="tenantDateValue" |
| 110 | - /> | |
| 120 | + > | |
| 121 | + <Button | |
| 122 | + type="link" | |
| 123 | + class="!px-0" | |
| 124 | + :style=" | |
| 125 | + tenantDateValue && tenantDateValue.length | |
| 126 | + ? { color: '#0960bd', fontWeight: 500 } | |
| 127 | + : { color: '#000000d9' } | |
| 128 | + " | |
| 129 | + >{{ | |
| 130 | + tenantDateValue && tenantDateValue.length | |
| 131 | + ? `${(tenantDateValue?.[0] as moment.Moment)?.format('YYYY-MM-DD')} | |
| 132 | + ~ | |
| 133 | + ${(tenantDateValue?.[1] as moment.Moment)?.format('YYYY-MM-DD')}` | |
| 134 | + : '自定义' | |
| 135 | + }}</Button | |
| 136 | + > | |
| 137 | + </DatePicker.RangePicker> | |
| 111 | 138 | </div> |
| 112 | 139 | </template> |
| 113 | 140 | <TenantTrend :tenantTrendList="tenantTrendList" /> |
| ... | ... | @@ -139,8 +166,8 @@ |
| 139 | 166 | </div> |
| 140 | 167 | </template> |
| 141 | 168 | <script lang="ts" setup> |
| 142 | - import { ref, reactive } from 'vue'; | |
| 143 | - import { Card, DatePicker, Tooltip } from 'ant-design-vue'; | |
| 169 | + import { ref, reactive, unref } from 'vue'; | |
| 170 | + import { Card, DatePicker, Tooltip, Button } from 'ant-design-vue'; | |
| 144 | 171 | import { QuestionCircleOutlined } from '@ant-design/icons-vue'; |
| 145 | 172 | // import VisitAnalysis from './VisitAnalysis.vue'; |
| 146 | 173 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
| ... | ... | @@ -155,6 +182,7 @@ |
| 155 | 182 | import { useDate } from '../hooks/useDate'; |
| 156 | 183 | import { getTrendData } from '/@/api/dashboard'; |
| 157 | 184 | import { useGlobSetting } from '/@/hooks/setting'; |
| 185 | + import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface'; | |
| 158 | 186 | |
| 159 | 187 | defineExpose({ |
| 160 | 188 | isAdmin, |
| ... | ... | @@ -514,6 +542,18 @@ |
| 514 | 542 | onDateTenantChange, |
| 515 | 543 | // onDateCustomerChange, |
| 516 | 544 | } = useDate(); |
| 545 | + | |
| 546 | + const handleCalendarChange = (val: RangePickerValue) => { | |
| 547 | + tenantDateValue.value = val as any; | |
| 548 | + }; | |
| 549 | + | |
| 550 | + const handleDisableDate = (current: moment.Moment) => { | |
| 551 | + if (!unref(tenantDateValue) || unref(tenantDateValue).length === 0) { | |
| 552 | + return false; | |
| 553 | + } | |
| 554 | + const diffDate = current.diff(unref(tenantDateValue)[0], 'days'); | |
| 555 | + return Math.abs(diffDate) > 30; | |
| 556 | + }; | |
| 517 | 557 | </script> |
| 518 | 558 | |
| 519 | 559 | <style lang="less"> | ... | ... |
| ... | ... | @@ -31,7 +31,7 @@ |
| 31 | 31 | }, |
| 32 | 32 | }, |
| 33 | 33 | xAxis: { |
| 34 | - type: 'time', | |
| 34 | + type: 'category', | |
| 35 | 35 | splitLine: { |
| 36 | 36 | show: true, |
| 37 | 37 | lineStyle: { |
| ... | ... | @@ -79,10 +79,10 @@ |
| 79 | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
| 80 | 80 | onMounted(async () => { |
| 81 | 81 | const res = await getTrendData({ |
| 82 | - ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), | |
| 82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_1_MONTH), | |
| 83 | 83 | trend: 'TENANT_TREND', |
| 84 | 84 | }); |
| 85 | - const transferResult = res.map((item) => [item.ts, item.value]); | |
| 85 | + const transferResult = res.map((item) => [item.date, item.value]); | |
| 86 | 86 | setOptions({ |
| 87 | 87 | tooltip: { |
| 88 | 88 | trigger: 'axis', |
| ... | ... | @@ -94,7 +94,7 @@ |
| 94 | 94 | }, |
| 95 | 95 | }, |
| 96 | 96 | xAxis: { |
| 97 | - type: 'time', | |
| 97 | + type: 'category', | |
| 98 | 98 | splitLine: { |
| 99 | 99 | show: true, |
| 100 | 100 | lineStyle: { | ... | ... |
| 1 | 1 | import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; |
| 2 | 2 | import { ref } from 'vue'; |
| 3 | 3 | import { getTrendData } from '/@/api/dashboard'; |
| 4 | +import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface'; | |
| 4 | 5 | |
| 5 | 6 | export enum ShortcutQueryKeyEnum { |
| 6 | - LATEST_30_DAY = 'LATEST_30_DAY', | |
| 7 | + LATEST_1_MONTH = 'LATEST_1_MONTH', | |
| 7 | 8 | LATEST_3_MONTH = 'LATEST_3_MONTH', |
| 8 | 9 | LATEST_1_YEAR = 'LATEST_1_YEAR', |
| 9 | 10 | } |
| 10 | 11 | |
| 11 | 12 | export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) { |
| 12 | 13 | const mapping = { |
| 13 | - [ShortcutQueryKeyEnum.LATEST_30_DAY]: () => { | |
| 14 | + [ShortcutQueryKeyEnum.LATEST_1_MONTH]: () => { | |
| 14 | 15 | return { |
| 15 | - startTs: dateUtil().subtract(30, 'day').startOf('day').valueOf(), | |
| 16 | + startTs: dateUtil().subtract(1, 'month').startOf('day').valueOf(), | |
| 16 | 17 | interval: 24 * 60 * 60 * 1000, |
| 17 | 18 | }; |
| 18 | 19 | }, |
| ... | ... | @@ -40,13 +41,13 @@ export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) { |
| 40 | 41 | |
| 41 | 42 | export function useDate() { |
| 42 | 43 | const tenantDateValue = ref([]); |
| 43 | - const customerDateValue = ref([]); | |
| 44 | + const customerDateValue = ref<RangePickerValue>([]); | |
| 44 | 45 | const tenantTrendList = ref([]); |
| 45 | 46 | const customerTrendList = ref([]); |
| 46 | 47 | const activeTenantIndex = ref(0); |
| 47 | 48 | const activeCustomerIndex = ref(0); |
| 48 | 49 | const TenantOrCustomerDateList = ref([ |
| 49 | - { label: '30天', value: ShortcutQueryKeyEnum.LATEST_30_DAY }, | |
| 50 | + { label: '最近一个月', value: ShortcutQueryKeyEnum.LATEST_1_MONTH }, | |
| 50 | 51 | { label: '最近三个月', value: ShortcutQueryKeyEnum.LATEST_3_MONTH }, |
| 51 | 52 | { label: '最近一年', value: ShortcutQueryKeyEnum.LATEST_1_YEAR }, |
| 52 | 53 | ]); |
| ... | ... | @@ -65,7 +66,7 @@ export function useDate() { |
| 65 | 66 | ...getDateByShortcutQueryKey(value), |
| 66 | 67 | trend: 'TENANT_TREND', |
| 67 | 68 | }); |
| 68 | - tenantTrendList.value = res.map((item) => [item.ts, item.value]); | |
| 69 | + tenantTrendList.value = res.map((item) => [item.date, item.value]); | |
| 69 | 70 | } else { |
| 70 | 71 | if (activeCustomerIndex.value === index) return; |
| 71 | 72 | activeCustomerIndex.value = index; |
| ... | ... | @@ -74,7 +75,7 @@ export function useDate() { |
| 74 | 75 | ...getDateByShortcutQueryKey(value), |
| 75 | 76 | trend: 'CUSTOMER_TREND', |
| 76 | 77 | }); |
| 77 | - customerTrendList.value = res.map((item) => [item.ts, item.value]); | |
| 78 | + customerTrendList.value = res.map((item) => [item.date, item.value]); | |
| 78 | 79 | } |
| 79 | 80 | } |
| 80 | 81 | ... | ... |
| ... | ... | @@ -103,7 +103,9 @@ |
| 103 | 103 | const value = { |
| 104 | 104 | ['触发属性']: findName, |
| 105 | 105 | ['触发条件']: `${findLogin}${curr.value.logicValue}`, |
| 106 | - ['触发值']: `${curr.value.realValue}${findAttribute.detail?.dataType?.specs?.unit?.key}`, | |
| 106 | + ['触发值']: `${curr.value.realValue}${ | |
| 107 | + findAttribute.detail?.dataType?.specs?.unit?.key ?? '' | |
| 108 | + }`, | |
| 107 | 109 | }; |
| 108 | 110 | const data = { |
| 109 | 111 | [item.name]: value, | ... | ... |
| ... | ... | @@ -60,7 +60,7 @@ |
| 60 | 60 | span: 12, |
| 61 | 61 | }, |
| 62 | 62 | componentProps: { |
| 63 | - maxLength: 255, | |
| 63 | + maxLength: 64, | |
| 64 | 64 | placeholder: '请输入邮件主题', |
| 65 | 65 | }, |
| 66 | 66 | }, |
| ... | ... | @@ -72,7 +72,7 @@ |
| 72 | 72 | colProps: { |
| 73 | 73 | span: 12, |
| 74 | 74 | }, |
| 75 | - rules: [...emailRule, { required: true ,message:'主送人不能为空'}], | |
| 75 | + rules: [...emailRule, { required: true, message: '主送人不能为空' }], | |
| 76 | 76 | componentProps: { |
| 77 | 77 | maxLength: 255, |
| 78 | 78 | placeholder: '请输入主送', | ... | ... |
| ... | ... | @@ -43,7 +43,7 @@ |
| 43 | 43 | <div |
| 44 | 44 | v-show="!item.notFoundData" |
| 45 | 45 | :id="`chart-${item.device}`" |
| 46 | - style="width: 100%; height: 400px" | |
| 46 | + class="w-full h-96" | |
| 47 | 47 | ></div> |
| 48 | 48 | </div> |
| 49 | 49 | </div> |
| ... | ... | @@ -273,6 +273,9 @@ |
| 273 | 273 | series, |
| 274 | 274 | xAxis: { data: xAxisData }, |
| 275 | 275 | } as echarts.EChartsOption); |
| 276 | + | |
| 277 | + await nextTick(); | |
| 278 | + resize(); | |
| 276 | 279 | } catch (error) { |
| 277 | 280 | } finally { |
| 278 | 281 | loading.value = false; | ... | ... |
| ... | ... | @@ -576,7 +576,17 @@ export const actionSchema: FormSchema[] = [ |
| 576 | 576 | const { setFieldsValue } = formActionType; |
| 577 | 577 | return { |
| 578 | 578 | placeholder: '请选择类型', |
| 579 | - api: findDictItemByCode, | |
| 579 | + api: async (parmas: Recordable) => { | |
| 580 | + try { | |
| 581 | + const record = await findDictItemByCode(parmas); | |
| 582 | + return record.filter( | |
| 583 | + (item) => | |
| 584 | + item.itemValue !== CommandTypeEnum.ATTRIBUTE.toString() || item.itemText != '属性' | |
| 585 | + ); | |
| 586 | + } catch (error) { | |
| 587 | + return []; | |
| 588 | + } | |
| 589 | + }, | |
| 580 | 590 | labelField: 'itemText', |
| 581 | 591 | valueField: 'itemValue', |
| 582 | 592 | params: { | ... | ... |
| ... | ... | @@ -267,8 +267,10 @@ |
| 267 | 267 | const validate = getFieldsValue(); |
| 268 | 268 | //ft-add-2022-11-22 |
| 269 | 269 | const type = validate?.outTarget; |
| 270 | - if (type === 'DEVICE_OUT' && validate.device == 'PART') { | |
| 271 | - if (validate.deviceId == undefined) return createMessage.error('请选择设备'); | |
| 270 | + if (type === 'DEVICE_OUT') { | |
| 271 | + if (!validate.deviceProfileId) return createMessage.error('请选择产品'); | |
| 272 | + if (validate.device == 'PART' && validate.deviceId == undefined) | |
| 273 | + return createMessage.error('请选择设备'); | |
| 272 | 274 | } |
| 273 | 275 | //ft-add-2022-11-22 |
| 274 | 276 | //TODO-fengtao-设备验证 | ... | ... |
| ... | ... | @@ -191,7 +191,8 @@ |
| 191 | 191 | const updateFn: DataFetchUpdateFn = (message, attribute) => { |
| 192 | 192 | const { data = {} } = message; |
| 193 | 193 | const [latest] = data[attribute] || []; |
| 194 | - const [_, value] = latest; | |
| 194 | + const [name, value] = latest; | |
| 195 | + if (!name && !value) return; | |
| 195 | 196 | noSendValue.value = getNumberValue(value); |
| 196 | 197 | sliderValue.value = getNumberValue(value); |
| 197 | 198 | }; | ... | ... |