Commit 0109c9c52e6535cca35112013e83da468790635c
Merge branch 'perf/device-list' into 'main_dev'
perf: 设备列表新增告警状态提示 && 变更收藏样式 See merge request yunteng/thingskit-front!1160
Showing
6 changed files
with
85 additions
and
17 deletions
@@ -187,6 +187,7 @@ export interface DeviceRecord { | @@ -187,6 +187,7 @@ export interface DeviceRecord { | ||
187 | brand?: string; | 187 | brand?: string; |
188 | deviceProfileId: string; | 188 | deviceProfileId: string; |
189 | organizationId: string; | 189 | organizationId: string; |
190 | + alarmStatus: number; | ||
190 | deviceProfile: { | 191 | deviceProfile: { |
191 | default: boolean; | 192 | default: boolean; |
192 | name: string; | 193 | name: string; |
@@ -4,12 +4,12 @@ | @@ -4,12 +4,12 @@ | ||
4 | <Tooltip v-if="action.tooltip" v-bind="getTooltip(action.tooltip)"> | 4 | <Tooltip v-if="action.tooltip" v-bind="getTooltip(action.tooltip)"> |
5 | <PopConfirmButton v-bind="action"> | 5 | <PopConfirmButton v-bind="action"> |
6 | <Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" /> | 6 | <Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" /> |
7 | - <template v-if="action.label">{{ action.label }}</template> | 7 | + <template v-if="action.label"><Label :label="action.label" /></template> |
8 | </PopConfirmButton> | 8 | </PopConfirmButton> |
9 | </Tooltip> | 9 | </Tooltip> |
10 | <PopConfirmButton v-else v-bind="action"> | 10 | <PopConfirmButton v-else v-bind="action"> |
11 | <Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" /> | 11 | <Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" /> |
12 | - <template v-if="action.label">{{ action.label }}</template> | 12 | + <template v-if="action.label"><Label :label="action.label" /> </template> |
13 | </PopConfirmButton> | 13 | </PopConfirmButton> |
14 | <Divider | 14 | <Divider |
15 | type="vertical" | 15 | type="vertical" |
@@ -36,7 +36,7 @@ | @@ -36,7 +36,7 @@ | ||
36 | </div> | 36 | </div> |
37 | </template> | 37 | </template> |
38 | <script lang="ts"> | 38 | <script lang="ts"> |
39 | - import { defineComponent, PropType, computed, toRaw, unref } from 'vue'; | 39 | + import { defineComponent, PropType, computed, toRaw, unref, VNode } from 'vue'; |
40 | // import { MoreOutlined } from '@ant-design/icons-vue'; | 40 | // import { MoreOutlined } from '@ant-design/icons-vue'; |
41 | import { Divider, Tooltip, TooltipProps } from 'ant-design-vue'; | 41 | import { Divider, Tooltip, TooltipProps } from 'ant-design-vue'; |
42 | import Icon from '/@/components/Icon/index'; | 42 | import Icon from '/@/components/Icon/index'; |
@@ -52,7 +52,14 @@ | @@ -52,7 +52,14 @@ | ||
52 | 52 | ||
53 | export default defineComponent({ | 53 | export default defineComponent({ |
54 | name: 'TableAction', | 54 | name: 'TableAction', |
55 | - components: { Icon, PopConfirmButton, Divider, Dropdown, Tooltip }, | 55 | + components: { |
56 | + Icon, | ||
57 | + PopConfirmButton, | ||
58 | + Divider, | ||
59 | + Dropdown, | ||
60 | + Tooltip, | ||
61 | + Label: (props: { label: VNode | string }) => props.label, | ||
62 | + }, | ||
56 | props: { | 63 | props: { |
57 | actions: { | 64 | actions: { |
58 | type: Array as PropType<ActionItem[]>, | 65 | type: Array as PropType<ActionItem[]>, |
1 | import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; | 1 | import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; |
2 | import { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip'; | 2 | import { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip'; |
3 | import { RoleEnum } from '/@/enums/roleEnum'; | 3 | import { RoleEnum } from '/@/enums/roleEnum'; |
4 | +import { VNode } from 'vue'; | ||
4 | export interface ActionItem extends ButtonProps { | 5 | export interface ActionItem extends ButtonProps { |
5 | onClick?: Fn; | 6 | onClick?: Fn; |
6 | - label?: string; | 7 | + label?: string | VNode; |
7 | color?: 'success' | 'error' | 'warning'; | 8 | color?: 'success' | 'error' | 'warning'; |
8 | icon?: string; | 9 | icon?: string; |
9 | popConfirm?: PopConfirm; | 10 | popConfirm?: PopConfirm; |
@@ -70,6 +70,7 @@ export const columns: BasicColumn[] = [ | @@ -70,6 +70,7 @@ export const columns: BasicColumn[] = [ | ||
70 | title: '状态', | 70 | title: '状态', |
71 | dataIndex: 'deviceState', | 71 | dataIndex: 'deviceState', |
72 | width: 110, | 72 | width: 110, |
73 | + className: 'device-status', | ||
73 | slots: { customRender: 'deviceState' }, | 74 | slots: { customRender: 'deviceState' }, |
74 | }, | 75 | }, |
75 | { | 76 | { |
@@ -19,7 +19,20 @@ | @@ -19,7 +19,20 @@ | ||
19 | <Tabs.TabPane key="modelOfMatter" tab="物模型数据"> | 19 | <Tabs.TabPane key="modelOfMatter" tab="物模型数据"> |
20 | <ModelOfMatter :deviceDetail="deviceDetail" /> | 20 | <ModelOfMatter :deviceDetail="deviceDetail" /> |
21 | </Tabs.TabPane> | 21 | </Tabs.TabPane> |
22 | - <Tabs.TabPane key="3" tab="告警"> | 22 | + <Tabs.TabPane key="3"> |
23 | + <template #tab> | ||
24 | + <Badge :offset="[2, -5]" style="color: inherit"> | ||
25 | + <span>告警</span> | ||
26 | + <template #count> | ||
27 | + <div | ||
28 | + :style="{ visibility: deviceDetail.alarmStatus ? 'visible' : 'hidden' }" | ||
29 | + class="w-3.5 h-3.5 !flex justify-center items-center rounded-1 border-red-400 border" | ||
30 | + > | ||
31 | + <Icon icon="mdi:bell-warning" color="#f46161" :size="12" class="!mr-0" /> | ||
32 | + </div> | ||
33 | + </template> | ||
34 | + </Badge> | ||
35 | + </template> | ||
23 | <AlarmLog :device-id="deviceDetail.id" class="bg-gray-100" /> | 36 | <AlarmLog :device-id="deviceDetail.id" class="bg-gray-100" /> |
24 | </Tabs.TabPane> | 37 | </Tabs.TabPane> |
25 | <Tabs.TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'"> | 38 | <Tabs.TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'"> |
@@ -51,7 +64,7 @@ | @@ -51,7 +64,7 @@ | ||
51 | <script lang="ts" setup> | 64 | <script lang="ts" setup> |
52 | import { ref, computed } from 'vue'; | 65 | import { ref, computed } from 'vue'; |
53 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | 66 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
54 | - import { Tabs } from 'ant-design-vue'; | 67 | + import { Tabs, Badge } from 'ant-design-vue'; |
55 | import Detail from '../tabs/Detail.vue'; | 68 | import Detail from '../tabs/Detail.vue'; |
56 | import ChildDevice from '../tabs/ChildDevice.vue'; | 69 | import ChildDevice from '../tabs/ChildDevice.vue'; |
57 | import TBoxDetail from '../tabs/TBoxDetail.vue'; | 70 | import TBoxDetail from '../tabs/TBoxDetail.vue'; |
@@ -62,6 +75,7 @@ | @@ -62,6 +75,7 @@ | ||
62 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; | 75 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
63 | import Task from '../tabs/Task.vue'; | 76 | import Task from '../tabs/Task.vue'; |
64 | import AlarmLog from '/@/views/alarm/log/index.vue'; | 77 | import AlarmLog from '/@/views/alarm/log/index.vue'; |
78 | + import { Icon } from '/@/components/Icon'; | ||
65 | 79 | ||
66 | const emit = defineEmits(['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail']); | 80 | const emit = defineEmits(['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail']); |
67 | 81 |
@@ -106,13 +106,17 @@ | @@ -106,13 +106,17 @@ | ||
106 | </Tag> | 106 | </Tag> |
107 | </template> | 107 | </template> |
108 | <template #deviceState="{ record }"> | 108 | <template #deviceState="{ record }"> |
109 | - <!-- <HeartOutlined v-if="!record.isCollect" class="mr-1" style="color: red" /> --> | ||
110 | - <Tooltip> | ||
111 | - <template #title> 我的收藏</template> | ||
112 | - <HeartTwoTone v-if="record.isCollect" class="mr-1" twoToneColor="#3B82F6" /> | ||
113 | - </Tooltip> | 109 | + <div v-if="record.isCollect"> |
110 | + <div class="absolute top-0 left-0 device-collect"> </div> | ||
111 | + <Icon | ||
112 | + icon="ph:star-fill" | ||
113 | + class="fill-light-50 absolute top-0.5 left-0.5" | ||
114 | + color="#fff" | ||
115 | + :size="12" | ||
116 | + /> | ||
117 | + </div> | ||
118 | + | ||
114 | <Tag | 119 | <Tag |
115 | - :style="{ marginLeft: !record.isCollect ? '17px' : '' }" | ||
116 | :color=" | 120 | :color=" |
117 | record.deviceState == DeviceState.INACTIVE | 121 | record.deviceState == DeviceState.INACTIVE |
118 | ? 'warning' | 122 | ? 'warning' |
@@ -135,7 +139,7 @@ | @@ -135,7 +139,7 @@ | ||
135 | <TableAction | 139 | <TableAction |
136 | :actions="[ | 140 | :actions="[ |
137 | { | 141 | { |
138 | - label: '详情', | 142 | + label: AlarmDetailActionButton({ hasAlarm: !!record.alarmStatus }), |
139 | icon: 'ant-design:eye-outlined', | 143 | icon: 'ant-design:eye-outlined', |
140 | auth: DeviceListAuthEnum.DETAIL, | 144 | auth: DeviceListAuthEnum.DETAIL, |
141 | onClick: handleDetail.bind(null, record), | 145 | onClick: handleDetail.bind(null, record), |
@@ -232,7 +236,7 @@ | @@ -232,7 +236,7 @@ | ||
232 | </div> | 236 | </div> |
233 | </template> | 237 | </template> |
234 | <script lang="ts" setup> | 238 | <script lang="ts" setup> |
235 | - import { reactive, onMounted, ref } from 'vue'; | 239 | + import { reactive, onMounted, ref, h, CSSProperties } from 'vue'; |
236 | import { | 240 | import { |
237 | DeviceModel, | 241 | DeviceModel, |
238 | DeviceRecord, | 242 | DeviceRecord, |
@@ -241,8 +245,7 @@ | @@ -241,8 +245,7 @@ | ||
241 | } from '/@/api/device/model/deviceModel'; | 245 | } from '/@/api/device/model/deviceModel'; |
242 | import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; | 246 | import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; |
243 | import { columns, DeviceListAuthEnum, searchFormSchema } from './config/device.data'; | 247 | import { columns, DeviceListAuthEnum, searchFormSchema } from './config/device.data'; |
244 | - import { Tag, Popover, Button, Tooltip } from 'ant-design-vue'; | ||
245 | - import { HeartTwoTone } from '@ant-design/icons-vue'; | 248 | + import { Tag, Popover, Button, Badge } from 'ant-design-vue'; |
246 | import { | 249 | import { |
247 | deleteDevice, | 250 | deleteDevice, |
248 | devicePage, | 251 | devicePage, |
@@ -278,6 +281,7 @@ | @@ -278,6 +281,7 @@ | ||
278 | } from './cpns/modal/BatchUpdateProductModal'; | 281 | } from './cpns/modal/BatchUpdateProductModal'; |
279 | import { DataActionModeEnum } from '/@/enums/toolEnum'; | 282 | import { DataActionModeEnum } from '/@/enums/toolEnum'; |
280 | import { AuthDropDown } from '/@/components/Widget'; | 283 | import { AuthDropDown } from '/@/components/Widget'; |
284 | + import Icon from '/@/components/Icon'; | ||
281 | 285 | ||
282 | const { isCustomer } = useAuthDeviceDetail(); | 286 | const { isCustomer } = useAuthDeviceDetail(); |
283 | const { createMessage } = useMessage(); | 287 | const { createMessage } = useMessage(); |
@@ -294,6 +298,32 @@ | @@ -294,6 +298,32 @@ | ||
294 | const [registerImportModal, { openModal: openImportModal }] = useModal(); | 298 | const [registerImportModal, { openModal: openImportModal }] = useModal(); |
295 | const [registerBatchUpdateProductModal, { openModal: openBatchUpdateProductModal }] = useModal(); | 299 | const [registerBatchUpdateProductModal, { openModal: openBatchUpdateProductModal }] = useModal(); |
296 | 300 | ||
301 | + const AlarmDetailActionButton = ({ hasAlarm }: { hasAlarm?: boolean }) => | ||
302 | + h( | ||
303 | + Badge, | ||
304 | + { offset: [0, -5] }, | ||
305 | + { | ||
306 | + default: () => h('span', { style: { color: '#377dff' } }, '详情'), | ||
307 | + count: () => | ||
308 | + h( | ||
309 | + 'div', | ||
310 | + { | ||
311 | + style: { | ||
312 | + visibility: hasAlarm ? 'visible' : 'hidden', | ||
313 | + width: '14px', | ||
314 | + height: '14px', | ||
315 | + display: 'flex', | ||
316 | + justifyContent: 'center', | ||
317 | + alignItems: 'center', | ||
318 | + border: '1px solid #f46161', | ||
319 | + borderRadius: '50%', | ||
320 | + } as CSSProperties, | ||
321 | + }, | ||
322 | + h(Icon, { icon: 'mdi:bell-warning', color: '#f46161', size: 12 }) | ||
323 | + ), | ||
324 | + } | ||
325 | + ); | ||
326 | + | ||
297 | const batchUpdateProductFlag = ref(true); | 327 | const batchUpdateProductFlag = ref(true); |
298 | 328 | ||
299 | const [ | 329 | const [ |
@@ -336,6 +366,7 @@ | @@ -336,6 +366,7 @@ | ||
336 | rowKey: 'id', | 366 | rowKey: 'id', |
337 | searchInfo: searchInfo, | 367 | searchInfo: searchInfo, |
338 | clickToRowSelect: false, | 368 | clickToRowSelect: false, |
369 | + rowClassName: (record) => ((record as DeviceRecord).alarmStatus ? 'device-alarm-badge' : ''), | ||
339 | actionColumn: { | 370 | actionColumn: { |
340 | width: 200, | 371 | width: 200, |
341 | title: '操作', | 372 | title: '操作', |
@@ -566,3 +597,16 @@ | @@ -566,3 +597,16 @@ | ||
566 | } | 597 | } |
567 | } | 598 | } |
568 | </style> | 599 | </style> |
600 | + | ||
601 | +<style lang="less"> | ||
602 | + .device-status { | ||
603 | + position: relative; | ||
604 | + | ||
605 | + .device-collect { | ||
606 | + width: 0; | ||
607 | + height: 0; | ||
608 | + border-top: 30px solid #377dff; | ||
609 | + border-right: 30px solid transparent; | ||
610 | + } | ||
611 | + } | ||
612 | +</style> |