浏览代码

feat(status-area): modify battery icon in status region

sw 1 月之前
父节点
当前提交
b3cbf93e3c

+ 4 - 0
src/assets/Icons/base/module-device/theme-default/1x/battery-empty.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="6" width="18" height="12" rx="2" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M20 10H21.5C21.7761 10 22 10.2239 22 10.5V13.5C22 13.7761 21.7761 14 21.5 14H20V10Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 8 - 0
src/assets/Icons/base/module-device/theme-default/1x/battery-full.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 9L6 15" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9 9L9 15" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12 9L12 15" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M15 9L15 15" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M21 10L21 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<rect x="3" y="6" width="15" height="12" rx="1" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 7 - 0
src/assets/Icons/base/module-device/theme-default/1x/battery-high.svg

@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="6" width="18" height="12" rx="2" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M15 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M20 10H21.5C21.7761 10 22 10.2239 22 10.5V13.5C22 13.7761 21.7761 14 21.5 14H20V10Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 5 - 0
src/assets/Icons/base/module-device/theme-default/1x/battery-low.svg

@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="6" width="18" height="12" rx="2" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M20 10H21.5C21.7761 10 22 10.2239 22 10.5V13.5C22 13.7761 21.7761 14 21.5 14H20V10Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 6 - 0
src/assets/Icons/base/module-device/theme-default/1x/battery-medium.svg

@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="6" width="18" height="12" rx="2" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M20 10H21.5C21.7761 10 22 10.2239 22 10.5V13.5C22 13.7761 21.7761 14 21.5 14H20V10Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11 10V14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 31 - 28
src/components/Icon/iconRegistry.ts

@@ -1,3 +1,4 @@
+/* eslint-disable */
 /* src/components/Icon/iconRegistry.ts */
 import React from 'react';
 
@@ -26,13 +27,13 @@ interface RawAsset {
   size: Density;
   fileName: string;
   ext: string;
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+   
   source: string | React.ComponentType<any>;
   reqPath: string; // require.context key (如 './base/module-common/.../icon.svg')
 }
 
 export type ResolvedIcon =
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+   
   | { kind: 'svg'; Component: React.ComponentType<any>; meta: RawAsset }
   | { kind: 'raster'; src: string; srcSet?: string; meta: RawAsset };
 
@@ -44,7 +45,7 @@ interface WebpackRequireContext {
   resolve(id: string): string;
   id: string;
 }
-  /* eslint-enable */
+/* eslint-enable */
 
 // ---- 构建索引 ----
 const defaultExtPriority = ['.svg', '.webp', '.png', '.jpg', '.jpeg'];
@@ -164,36 +165,38 @@ export function resolveIcon(opts: IconOptions): ResolvedIcon | undefined {
                   : `base|${moduleName}|${th}|${sz}|${fileName}`;
               const asset = assetIndex.get(key);
               if (asset) {
-                if (
-                  asset.ext === '.svg' ||
-                  typeof asset.source === 'function'
-                ) {
+                // ADD: 如果是 SVG 且 source 不是字符串(即被 svgr 转换为 React 组件),则当作 svg 组件返回
+                if (asset.ext === '.svg' && typeof asset.source !== 'string') {
                   // eslint-disable-next-line @typescript-eslint/no-explicit-any
                   const Component = asset.source as React.ComponentType<any>;
                   return { kind: 'svg', Component, meta: asset };
-                } else {
-                  const densities: Density[] = ['1x', '2x', '3x'];
-                  const srcSetParts: string[] = [];
-                  for (const d of densities) {
-                    const k =
-                      layer === 'custom'
-                        ? `custom|${asset.userId}|${asset.moduleName}|${asset.theme}|${d}|${asset.fileName}`
-                        : `base|${asset.moduleName}|${asset.theme}|${d}|${asset.fileName}`;
-                    const a = assetIndex.get(k);
-                    if (a && typeof a.source === 'string') {
-                      srcSetParts.push(`${a.source} ${d}`);
-                    }
+                }
+
+                // ADD: 否则把它当作 raster 处理(包括那些被 loader 输出为 URL/base64 的 SVG)
+                const densities: Density[] = ['1x', '2x', '3x'];
+                const srcSetParts: string[] = [];
+                for (const d of densities) {
+                  const k =
+                    layer === 'custom'
+                      ? `custom|${asset.userId}|${asset.moduleName}|${asset.theme}|${d}|${asset.fileName}`
+                      : `base|${asset.moduleName}|${asset.theme}|${d}|${asset.fileName}`;
+                  const a = assetIndex.get(k);
+                  if (a && typeof a.source === 'string') {
+                    // 注意:srcSet descriptor 我们保留 '1x'/'2x'/'3x' 字符串(可按需改成 '1x' -> '1x' 等)
+                    srcSetParts.push(`${a.source} ${d}`);
                   }
-                  const srcSet = srcSetParts.length
-                    ? srcSetParts.join(', ')
-                    : undefined;
-                  return {
-                    kind: 'raster',
-                    src: asset.source as string,
-                    srcSet,
-                    meta: asset,
-                  };
                 }
+                const srcSet = srcSetParts.length
+                  ? srcSetParts.join(', ')
+                  : undefined;
+
+                // asset.source 在此处应为 string(URL 或 base64)
+                return {
+                  kind: 'raster',
+                  src: asset.source as string,
+                  srcSet,
+                  meta: asset,
+                };
               }
             }
           }

+ 57 - 2
src/components/Icon/index.tsx

@@ -12,7 +12,7 @@ type AntdIconType = React.ComponentType<{
 
 function tryLoadAntdIcon(): AntdIconType | undefined {
   try {
-     
+
     const mod = require('@ant-design/icons') as { default?: AntdIconType };
     return mod?.default;
   } catch {
@@ -63,9 +63,63 @@ const Icon: React.FC<IconProps> = ({
     return null;
   }
 
+  // if (resolved.kind === 'svg') {
+  //   console.log(`解析到了svg图标`);
+  //   const Svg = resolved.Component;
+  //   console.log(`打印一下 resolved.Component 看是什么 === ${Svg}`)
+  //   if (useAntdIcon) {
+  //     const AntdIcon = tryLoadAntdIcon();
+  //     if (AntdIcon) {
+  //       return (
+  //         <AntdIcon
+  //           component={Svg}
+  //           className={className}
+  //           style={{
+  //             width: widthPx ?? undefined,
+  //             height: widthPx ?? undefined,
+  //             ...style,
+  //           }}
+  //         />
+  //       );
+  //     }
+  //   }
+
+  //   // 没有 antd 或 useAntdIcon=false,则直接渲染 svg
+  //   return (
+  //     <Svg
+  //       width={widthPx ?? undefined}
+  //       height={widthPx ?? undefined}
+  //       role={alt ? 'img' : 'presentation'}
+  //       aria-label={alt}
+  //       className={className}
+  //       style={style}
+  //     />
+  //   );
+  // }
   if (resolved.kind === 'svg') {
     const Svg = resolved.Component;
 
+    //运行时保护 — 若 resolved.Component 非函数/非组件(意外情况),尝试降级为 <img />
+    if (Svg == null || typeof Svg !== 'function') {
+      // 尝试从 meta.source 拿到可用的 URL(可能是 svg 被打包为 URL 的情况)
+      const maybeSrc = (resolved.meta && (resolved.meta.source as unknown)) ?? null;
+      if (typeof maybeSrc === 'string') {
+        return (
+          <img
+            src={maybeSrc}
+            alt={alt ?? name}
+            width={widthPx ?? undefined}
+            height={widthPx ?? undefined}
+            className={className}
+            style={style}
+            {...imgProps}
+          />
+        );
+      }
+      // 无法降级则安全返回 null
+      return null;
+    }
+
     if (useAntdIcon) {
       const AntdIcon = tryLoadAntdIcon();
       if (AntdIcon) {
@@ -83,7 +137,7 @@ const Icon: React.FC<IconProps> = ({
       }
     }
 
-    // 没有 antd 或 useAntdIcon=false,则直接渲染 svg
+    // 直接渲染 svg 组件
     return (
       <Svg
         width={widthPx ?? undefined}
@@ -96,6 +150,7 @@ const Icon: React.FC<IconProps> = ({
     );
   }
 
+
   // raster 图片
   return (
     <img

+ 15 - 7
src/layouts/StateBar.tsx

@@ -5,12 +5,8 @@ import { useEffect } from 'react';
 import { useDispatch } from 'react-redux';
 import { setQuota } from '../states/security/quotaSlice';
 import { getQuota } from '../API/security/quotaActions';
-import {
-  HddOutlined,
-  WifiOutlined,
-  FireOutlined,
-  BarChartOutlined,
-} from '@ant-design/icons';
+import { HddOutlined, WifiOutlined, FireOutlined } from '@ant-design/icons';
+import Icon from '@/components/Icon';
 
 // 定义状态类型
 interface StatusBarProps {
@@ -63,7 +59,19 @@ const BatteryStatus: React.FC<{ level: number }> = ({ level }) => {
 
   return (
     <Tooltip title={`电量: ${level}%`}>
-      <BarChartOutlined className={`${color}  h-full`} />
+      {/* <BarChartOutlined className={`${color}  h-full`} /> */}
+
+      <Icon
+        module="module-device"
+        name="battery-full"
+        userId="base"
+        theme="default"
+        size="2x"
+        state="normal"
+        useAntdIcon={false}
+        className={`${color}  h-[1em] w-[1em]`}
+      />
+
       <span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-xs text-white">
         {level}
       </span>