Commit 0109c9c52e6535cca35112013e83da468790635c

Authored by xp.Huang
2 parents c62eeb71 edc2a8ba

Merge branch 'perf/device-list' into 'main_dev'

perf: 设备列表新增告警状态提示 && 变更收藏样式

See merge request yunteng/thingskit-front!1160
@@ -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>