From 4259deb19122a4807d50c99ed4a95405ebe4a47c Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期五, 10 四月 2026 08:40:18 +0800
Subject: [PATCH] #

---
 rsf-design/src/utils/ui/iconify-loader.js |  163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/rsf-design/src/utils/ui/iconify-loader.js b/rsf-design/src/utils/ui/iconify-loader.js
index e69de29..f62f06e 100644
--- a/rsf-design/src/utils/ui/iconify-loader.js
+++ b/rsf-design/src/utils/ui/iconify-loader.js
@@ -0,0 +1,163 @@
+import { addCollection } from '@iconify/vue/offline'
+import { LOCAL_ICON_COLLECTIONS } from '../../plugins/iconify.collections.js'
+
+const FULL_ICON_COLLECTION_LOADERS = Object.freeze({
+  fluent: () => import('@iconify-json/fluent').then((module) => module.icons),
+  'icon-park-outline': () =>
+    import('@iconify-json/icon-park-outline').then((module) => module.icons),
+  iconamoon: () => import('@iconify-json/iconamoon').then((module) => module.icons),
+  ix: () => import('@iconify-json/ix').then((module) => module.icons),
+  'line-md': () => import('@iconify-json/line-md').then((module) => module.icons),
+  ri: () => import('@iconify-json/ri').then((module) => module.icons),
+  solar: () => import('@iconify-json/solar').then((module) => module.icons),
+  'svg-spinners': () => import('@iconify-json/svg-spinners').then((module) => module.icons),
+  'system-uicons': () => import('@iconify-json/system-uicons').then((module) => module.icons),
+  vaadin: () => import('@iconify-json/vaadin').then((module) => module.icons)
+})
+
+const fullyRegisteredPrefixes = new Set()
+const pendingPrefixLoads = new Map()
+
+function parseIconName(icon) {
+  if (typeof icon !== 'string') {
+    return null
+  }
+
+  const normalizedIcon = icon.trim()
+  if (!normalizedIcon) {
+    return null
+  }
+
+  const separatorIndex = normalizedIcon.indexOf(':')
+  if (separatorIndex <= 0 || separatorIndex >= normalizedIcon.length - 1) {
+    return null
+  }
+
+  return {
+    prefix: normalizedIcon.slice(0, separatorIndex),
+    name: normalizedIcon.slice(separatorIndex + 1)
+  }
+}
+
+function hasBundledIcon(icon) {
+  const parsedIcon = parseIconName(icon)
+  if (!parsedIcon) {
+    return false
+  }
+
+  const collection = LOCAL_ICON_COLLECTIONS[parsedIcon.prefix]
+  if (!collection) {
+    return false
+  }
+
+  return Boolean(collection.icons?.[parsedIcon.name] || collection.aliases?.[parsedIcon.name])
+}
+
+function loadFullIconCollection(prefix) {
+  if (fullyRegisteredPrefixes.has(prefix)) {
+    return Promise.resolve(true)
+  }
+
+  const currentTask = pendingPrefixLoads.get(prefix)
+  if (currentTask) {
+    return currentTask
+  }
+
+  const loader = FULL_ICON_COLLECTION_LOADERS[prefix]
+  if (!loader) {
+    return Promise.resolve(false)
+  }
+
+  const loadTask = loader()
+    .then((collection) => {
+      addCollection(collection)
+      fullyRegisteredPrefixes.add(prefix)
+      pendingPrefixLoads.delete(prefix)
+      return true
+    })
+    .catch((error) => {
+      pendingPrefixLoads.delete(prefix)
+      throw error
+    })
+
+  pendingPrefixLoads.set(prefix, loadTask)
+  return loadTask
+}
+
+function collectRuntimeIcons(source, iconNames = new Set()) {
+  if (!Array.isArray(source)) {
+    return iconNames
+  }
+
+  source.forEach((item) => {
+    if (!item || typeof item !== 'object') {
+      return
+    }
+
+    const icon = item.meta?.icon || item.icon
+    if (typeof icon === 'string' && icon.includes(':') && !hasBundledIcon(icon)) {
+      iconNames.add(icon)
+    }
+
+    if (Array.isArray(item.children) && item.children.length > 0) {
+      collectRuntimeIcons(item.children, iconNames)
+    }
+  })
+
+  return iconNames
+}
+
+function scheduleIdleTask(task, delay = 0) {
+  const invoke = () => {
+    if (globalThis.requestIdleCallback) {
+      globalThis.requestIdleCallback(task, { timeout: 1000 })
+      return
+    }
+    setTimeout(task, 0)
+  }
+
+  if (delay > 0) {
+    setTimeout(invoke, delay)
+    return
+  }
+
+  invoke()
+}
+
+async function ensureIconRegistered(icon) {
+  const parsedIcon = parseIconName(icon)
+  if (!parsedIcon) {
+    return false
+  }
+
+  if (hasBundledIcon(icon) || fullyRegisteredPrefixes.has(parsedIcon.prefix)) {
+    return true
+  }
+
+  return loadFullIconCollection(parsedIcon.prefix)
+}
+
+function warmRuntimeIcons(iconNames, delay = 120) {
+  const icons = [...new Set(Array.isArray(iconNames) ? iconNames : [])].filter(Boolean)
+  if (icons.length === 0) {
+    return
+  }
+
+  scheduleIdleTask(() => {
+    icons.forEach((icon) => {
+      void ensureIconRegistered(icon)
+    })
+  }, delay)
+}
+
+function warmMenuIcons(menuList, delay = 120) {
+  warmRuntimeIcons([...collectRuntimeIcons(menuList)], delay)
+}
+
+export {
+  collectRuntimeIcons,
+  ensureIconRegistered,
+  hasBundledIcon,
+  warmMenuIcons,
+  warmRuntimeIcons
+}

--
Gitblit v1.9.1