feat:【antd】【iot】添加设备状态和颜色映射功能,优化设备卡片样式
This commit is contained in:
@@ -2,8 +2,9 @@
|
|||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
import { getDictLabel } from '@vben/hooks';
|
import { getDictLabel, getDictObj } from '@vben/hooks';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
import { isValidColor, TinyColor } from '@vben/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -52,6 +53,91 @@ const queryParams = ref({
|
|||||||
pageSize: 12,
|
pageSize: 12,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DEFAULT_STATUS_MAP: Record<
|
||||||
|
'default' | number,
|
||||||
|
{ bgColor: string; borderColor: string; color: string; text: string }
|
||||||
|
> = {
|
||||||
|
[DeviceStateEnum.ONLINE]: {
|
||||||
|
text: '在线',
|
||||||
|
color: '#52c41a',
|
||||||
|
bgColor: '#f6ffed',
|
||||||
|
borderColor: '#b7eb8f',
|
||||||
|
},
|
||||||
|
[DeviceStateEnum.OFFLINE]: {
|
||||||
|
text: '离线',
|
||||||
|
color: '#faad14',
|
||||||
|
bgColor: '#fffbe6',
|
||||||
|
borderColor: '#ffe58f',
|
||||||
|
},
|
||||||
|
[DeviceStateEnum.INACTIVE]: {
|
||||||
|
text: '未激活',
|
||||||
|
color: '#ff4d4f',
|
||||||
|
bgColor: '#fff1f0',
|
||||||
|
borderColor: '#ffccc7',
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
text: '未知状态',
|
||||||
|
color: '#595959',
|
||||||
|
bgColor: '#fafafa',
|
||||||
|
borderColor: '#d9d9d9',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLOR_TYPE_PRESETS: Record<
|
||||||
|
string,
|
||||||
|
{ bgColor: string; borderColor: string; color: string }
|
||||||
|
> = {
|
||||||
|
success: {
|
||||||
|
color: '#52c41a',
|
||||||
|
bgColor: '#f6ffed',
|
||||||
|
borderColor: '#b7eb8f',
|
||||||
|
},
|
||||||
|
processing: {
|
||||||
|
color: '#1890ff',
|
||||||
|
bgColor: '#e6f7ff',
|
||||||
|
borderColor: '#91d5ff',
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
color: '#faad14',
|
||||||
|
bgColor: '#fffbe6',
|
||||||
|
borderColor: '#ffe58f',
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
color: '#ff4d4f',
|
||||||
|
bgColor: '#fff1f0',
|
||||||
|
borderColor: '#ffccc7',
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
color: '#595959',
|
||||||
|
bgColor: '#fafafa',
|
||||||
|
borderColor: '#d9d9d9',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeColorType(colorType?: string) {
|
||||||
|
switch (colorType) {
|
||||||
|
case 'danger': {
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
case 'default':
|
||||||
|
case 'error':
|
||||||
|
case 'processing':
|
||||||
|
case 'success':
|
||||||
|
case 'warning': {
|
||||||
|
return colorType;
|
||||||
|
}
|
||||||
|
case 'info': {
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
case 'primary': {
|
||||||
|
return 'processing';
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取产品名称
|
// 获取产品名称
|
||||||
function getProductName(productId: number) {
|
function getProductName(productId: number) {
|
||||||
const product = props.products.find((p: any) => p.id === productId);
|
const product = props.products.find((p: any) => p.id === productId);
|
||||||
@@ -90,21 +176,41 @@ function getDeviceTypeColor(deviceType: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取设备状态信息
|
// 获取设备状态信息
|
||||||
function getStatusInfo(state: number) {
|
function getStatusInfo(state: number | string | null | undefined) {
|
||||||
if (state === DeviceStateEnum.ONLINE) {
|
const parsedState = Number(state);
|
||||||
|
const hasNumericState = Number.isFinite(parsedState);
|
||||||
|
const fallback = hasNumericState
|
||||||
|
? DEFAULT_STATUS_MAP[parsedState] || DEFAULT_STATUS_MAP.default
|
||||||
|
: DEFAULT_STATUS_MAP.default;
|
||||||
|
const dict = getDictObj(
|
||||||
|
DICT_TYPE.IOT_DEVICE_STATE,
|
||||||
|
hasNumericState ? parsedState : state,
|
||||||
|
);
|
||||||
|
if (dict) {
|
||||||
|
if (!dict.colorType && !dict.cssClass) {
|
||||||
|
return {
|
||||||
|
...fallback,
|
||||||
|
text: dict.label || fallback.text,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const presetKey = normalizeColorType(dict.colorType);
|
||||||
|
if (isValidColor(dict.cssClass)) {
|
||||||
|
const baseColor = new TinyColor(dict.cssClass);
|
||||||
|
return {
|
||||||
|
text: dict.label || fallback.text,
|
||||||
|
color: baseColor.toHexString(),
|
||||||
|
bgColor: baseColor.clone().setAlpha(0.15).toRgbString(),
|
||||||
|
borderColor: baseColor.clone().lighten(30).toHexString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const preset = COLOR_TYPE_PRESETS[presetKey] || COLOR_TYPE_PRESETS.default;
|
||||||
return {
|
return {
|
||||||
text: '在线',
|
text: dict.label || fallback.text,
|
||||||
color: '#52c41a',
|
...preset,
|
||||||
bgColor: '#f6ffed',
|
|
||||||
borderColor: '#b7eb8f',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
text: '未激活',
|
return fallback;
|
||||||
color: '#ff4d4f',
|
|
||||||
bgColor: '#fff1f0',
|
|
||||||
borderColor: '#ffccc7',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -290,21 +396,21 @@ defineExpose({
|
|||||||
.device-card {
|
.device-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #fff;
|
background: hsl(var(--card) / 0.95);
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid hsl(var(--border) / 0.6);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 1px 2px 0 rgb(0 0 0 / 3%),
|
0 1px 2px 0 hsl(var(--foreground) / 0.04),
|
||||||
0 1px 6px -1px rgb(0 0 0 / 2%),
|
0 1px 6px -1px hsl(var(--foreground) / 0.05),
|
||||||
0 2px 4px 0 rgb(0 0 0 / 2%);
|
0 2px 4px 0 hsl(var(--foreground) / 0.05);
|
||||||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #e6e6e6;
|
border-color: hsl(var(--border));
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 1px 2px -2px rgb(0 0 0 / 16%),
|
0 1px 2px -2px hsl(var(--foreground) / 0.12),
|
||||||
0 3px 6px 0 rgb(0 0 0 / 12%),
|
0 3px 6px 0 hsl(var(--foreground) / 0.1),
|
||||||
0 5px 12px 4px rgb(0 0 0 / 9%);
|
0 5px 12px 4px hsl(var(--foreground) / 0.08);
|
||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +473,7 @@ defineExpose({
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
color: #262626;
|
color: hsl(var(--foreground) / 0.9);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +496,7 @@ defineExpose({
|
|||||||
.label {
|
.label {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #8c8c8c;
|
color: hsl(var(--foreground) / 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
@@ -399,17 +505,17 @@ defineExpose({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #262626;
|
color: hsl(var(--foreground) / 0.85);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&.link {
|
&.link {
|
||||||
color: #1890ff;
|
color: hsl(var(--primary));
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #40a9ff;
|
color: hsl(var(--primary) / 0.85);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +524,7 @@ defineExpose({
|
|||||||
'SF Mono', Monaco, Inconsolata, 'Fira Code', Consolas, monospace;
|
'SF Mono', Monaco, Inconsolata, 'Fira Code', Consolas, monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #595959;
|
color: hsl(var(--foreground) / 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +537,7 @@ defineExpose({
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #f5f5f5;
|
border-top: 1px solid hsl(var(--border) / 0.4);
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -445,7 +551,7 @@ defineExpose({
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid;
|
border: 1px solid transparent;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
|
||||||
@@ -454,52 +560,60 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.btn-edit {
|
&.btn-edit {
|
||||||
color: #1890ff;
|
color: hsl(var(--primary));
|
||||||
background: #e6f7ff;
|
background: hsl(var(--primary) / 0.12);
|
||||||
border-color: #91d5ff;
|
border-color: hsl(var(--primary) / 0.25);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: hsl(var(--primary-foreground));
|
||||||
background: #1890ff;
|
background: hsl(var(--primary));
|
||||||
border-color: #1890ff;
|
border-color: hsl(var(--primary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.btn-view {
|
&.btn-view {
|
||||||
color: #faad14;
|
color: hsl(var(--warning));
|
||||||
background: #fffbe6;
|
background: hsl(var(--warning) / 0.12);
|
||||||
border-color: #ffe58f;
|
border-color: hsl(var(--warning) / 0.25);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #faad14;
|
background: hsl(var(--warning));
|
||||||
border-color: #faad14;
|
border-color: hsl(var(--warning));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.btn-data {
|
&.btn-data {
|
||||||
color: #722ed1;
|
color: hsl(var(--accent-foreground));
|
||||||
background: #f9f0ff;
|
background: color-mix(
|
||||||
border-color: #d3adf7;
|
in srgb,
|
||||||
|
hsl(var(--accent)) 40%,
|
||||||
|
hsl(var(--card)) 60%
|
||||||
|
);
|
||||||
|
border-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
hsl(var(--accent)) 55%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: hsl(var(--accent-foreground));
|
||||||
background: #722ed1;
|
background: hsl(var(--accent));
|
||||||
border-color: #722ed1;
|
border-color: hsl(var(--accent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.btn-delete {
|
&.btn-delete {
|
||||||
flex: 0 0 32px;
|
flex: 0 0 32px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
color: #ff4d4f;
|
color: hsl(var(--destructive));
|
||||||
background: #fff1f0;
|
background: hsl(var(--destructive) / 0.12);
|
||||||
border-color: #ffa39e;
|
border-color: hsl(var(--destructive) / 0.3);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: hsl(var(--destructive-foreground));
|
||||||
background: #ff4d4f;
|
background: hsl(var(--destructive));
|
||||||
border-color: #ff4d4f;
|
border-color: hsl(var(--destructive));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -553,15 +553,17 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
|||||||
|
|
||||||
.toolbar-wrapper {
|
.toolbar-wrapper {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background-color: #fafafa;
|
background-color: hsl(var(--card) / 0.9);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
border: 1px solid hsl(var(--border) / 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container,
|
.chart-container,
|
||||||
.table-container {
|
.table-container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background-color: #fff;
|
background-color: hsl(var(--card));
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
border: 1px solid hsl(var(--border) / 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user