周玉环 1 päivä sitten
vanhempi
commit
5a933a9c9f
28 muutettua tiedostoa jossa 325 lisäystä ja 120 poistoa
  1. 6 0
      frontend/containers/Ai/locales/en.json
  2. 6 0
      frontend/containers/Ai/locales/ja-JP.json
  3. 6 0
      frontend/containers/Ai/locales/zh-CN.json
  4. 6 0
      frontend/containers/Ai/router/index.js
  5. 6 0
      frontend/containers/Ai/views/llm-image/components/List.vue
  6. 254 0
      frontend/containers/Ai/views/llm-image/import-community/index.vue
  7. 0 42
      frontend/containers/Compute/router/index.js
  8. 0 5
      frontend/containers/Compute/views/app-package/index.vue
  9. 0 5
      frontend/containers/Compute/views/gpu/index.vue
  10. 2 2
      frontend/containers/Compute/views/image/components/List.vue
  11. 0 5
      frontend/containers/Compute/views/image/index.vue
  12. 2 18
      frontend/containers/Helm/router/index.js
  13. 2 11
      frontend/containers/Network/router/index.js
  14. 0 3
      frontend/containers/Storage/router/index.js
  15. 0 5
      frontend/containers/Storage/views/blockstorage/index.vue
  16. 0 5
      frontend/package.json
  17. 1 1
      frontend/scope/layouts/Navbar/index.vue
  18. 5 0
      frontend/src/assets/images/llm-images/comfyui.svg
  19. 4 0
      frontend/src/assets/images/llm-images/default.svg
  20. 4 0
      frontend/src/assets/images/llm-images/dify.svg
  21. 4 0
      frontend/src/assets/images/llm-images/ollama.svg
  22. 5 0
      frontend/src/assets/images/llm-images/openclaw.svg
  23. 4 0
      frontend/src/assets/images/llm-images/vllm.svg
  24. 1 2
      frontend/src/permission.js
  25. 4 8
      frontend/src/store/modules/auth.js
  26. 1 2
      frontend/src/store/modules/common.js
  27. 2 3
      frontend/src/store/modules/monitor.js
  28. 0 3
      frontend/src/store/modules/scopedPolicy.js

+ 6 - 0
frontend/containers/Ai/locales/en.json

@@ -15,6 +15,12 @@
   "aice.llm_image.community_registry_fetch_failed": "Failed to fetch community model list",
   "aice.llm_image.community_registry_platform": "Provided by platform interface",
   "aice.llm_image.community_import_success": "Imported {0}, failed {1}",
+  "aice.llm_image.import_community_image": "Import Community Image",
+  "aice.llm_image.community_image_registry": "Community Container Image Registry",
+  "aice.llm_image.community_image_platform": "Provided by platform API",
+  "aice.llm_image.community_image_fetch_failed": "Failed to fetch community images",
+  "aice.llm_image.filter_by_type": "Filter by type",
+  "aice.llm_image.imported": "Imported",
   "aice.instant_app": "Inference Model Library",
   "aice.instant_app.install": "Install Model Data",
   "aice.llm_sku": "Inference Template",

+ 6 - 0
frontend/containers/Ai/locales/ja-JP.json

@@ -15,6 +15,12 @@
   "aice.llm_image.community_registry_fetch_failed": "コミュニティモデル一覧の取得に失敗しました",
   "aice.llm_image.community_registry_platform": "プラットフォームインターフェースによって提供されます",
   "aice.llm_image.community_import_success": "{0}件をインポート、失敗{1}件",
+  "aice.llm_image.import_community_image": "コミュニティイメージをインポート",
+  "aice.llm_image.community_image_registry": "コミュニティコンテナイメージレジストリ",
+  "aice.llm_image.community_image_platform": "プラットフォーム API から提供",
+  "aice.llm_image.community_image_fetch_failed": "コミュニティイメージの取得に失敗しました",
+  "aice.llm_image.filter_by_type": "タイプでフィルタ",
+  "aice.llm_image.imported": "インポート済み",
   "aice.instant_app": "推論モデルライブラリ",
   "aice.instant_app.install": "モデルデータをインストール",
   "aice.llm_sku": "推論テンプレート",

+ 6 - 0
frontend/containers/Ai/locales/zh-CN.json

@@ -25,6 +25,12 @@
   "aice.llm_image.community_registry_platform": "由平台接口提供",
   "aice.llm_image.community_registry_fetch_failed": "获取社区模型列表失败",
   "aice.llm_image.community_import_success": "已导入{0}个,失败{1}个",
+  "aice.llm_image.import_community_image": "导入社区镜像",
+  "aice.llm_image.community_image_registry": "社区容器镜像仓库",
+  "aice.llm_image.community_image_platform": "由平台接口提供",
+  "aice.llm_image.community_image_fetch_failed": "获取社区镜像列表失败",
+  "aice.llm_image.filter_by_type": "按类型筛选",
+  "aice.llm_image.imported": "已导入",
   "aice.instant_app": "推理模型库",
   "aice.instant_app.install": "安装模型数据",
   "aice.llm_sku": "推理模板",

+ 6 - 0
frontend/containers/Ai/router/index.js

@@ -11,6 +11,7 @@ const LlmSkuCreate = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefet
 const LlmInstantmodel = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefetch: true */ '@Ai/views/llm-instantmodel')
 const LlmImage = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefetch: true */ '@Ai/views/llm-image')
 const LlmInstantmodelImportCommunity = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefetch: true */ '@Ai/views/llm-instantmodel/import-community')
+const LlmImageImportCommunity = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefetch: true */ '@Ai/views/llm-image/import-community')
 const LlmCreate = () => import(/* webpackChunkName: "k8s" */ /* webpackPrefetch: true */ '@Ai/views/llm/create')
 export default {
   index: 61,
@@ -184,6 +185,11 @@ export default {
               path: '',
               component: LlmImage,
             },
+            {
+              name: 'LlmImageImportCommunity',
+              path: 'import-community',
+              component: LlmImageImportCommunity,
+            },
           ],
         },
       ],

+ 6 - 0
frontend/containers/Ai/views/llm-image/components/List.vue

@@ -49,6 +49,12 @@ export default {
           },
         },
         {
+          label: this.$t('aice.llm_image.import_community_image'),
+          action: () => {
+            this.$router.push({ name: 'LlmImageImportCommunity' })
+          },
+        },
+        {
           label: this.$t('table.action.delete'),
           action: () => {
             this.createDialog('DeleteResDialog', {

+ 254 - 0
frontend/containers/Ai/views/llm-image/import-community/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <div>
+    <page-header :title="$t('aice.llm_image.import_community_image')" />
+    <a-form-model class="mt-3 mb-2" v-bind="layout">
+      <a-form-model-item>
+        <a-radio-group v-model="form.llm_type" size="large">
+          <a-radio-button v-for="item in typeList" :key="item.value" :value="item.value" style="width:80px;height:80px;text-align:center;line-height:80px;vertical-align:middle;padding:0;">
+            <img v-if="item.icon" :src="item.icon" style="height:56px;" />
+          </a-radio-button>
+        </a-radio-group>
+      </a-form-model-item>
+    </a-form-model>
+    <page-list
+      :list="list"
+      :columns="columns"
+      :single-actions="singleActions"
+      :showSearchbox="false"
+      :showGroupActions="false"
+      :showPage="false" />
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+import yaml from 'js-yaml'
+import marked from 'marked'
+import WindowsMixin from '@/mixins/windows'
+import ListMixin from '@/mixins/list'
+
+const LLM_IMAGES_URL = 'http://localhost:3000/llmimages.yaml'
+
+const LLM_TYPE_ICONS = {
+  openclaw: require('@/assets/images/llm-images/openclaw.svg'),
+  ollama: require('@/assets/images/llm-images/ollama.svg'),
+  vllm: require('@/assets/images/llm-images/vllm.svg'),
+  dify: require('@/assets/images/llm-images/dify.svg'),
+  comfyui: require('@/assets/images/llm-images/comfyui.svg'),
+}
+const DEFAULT_ICON = require('@/assets/images/llm-images/default.svg')
+
+function getTypeIcon (llmType) {
+  return LLM_TYPE_ICONS[llmType] || DEFAULT_ICON
+}
+
+function parseImageField (imageStr) {
+  const idx = imageStr.lastIndexOf(':')
+  if (idx > 0) {
+    return { image_name: imageStr.substring(0, idx), image_label: imageStr.substring(idx + 1) }
+  }
+  return { image_name: imageStr, image_label: 'latest' }
+}
+
+export default {
+  name: 'LlmImageImportCommunityPage',
+  mixins: [WindowsMixin, ListMixin],
+  data () {
+    return {
+      allItems: [],
+      existingImages: {},
+      layout: {
+        wrapperCol: { span: 20 },
+        labelCol: { span: 4 },
+      },
+      form: {
+        llm_type: '',
+      },
+      list: this.$list.createList(this, {
+        id: 'LlmImageImportCommunity',
+        resource: 'llm_images',
+        responseData: { data: [] },
+      }),
+    }
+  },
+  computed: {
+    typeList () {
+      const seen = {}
+      const ret = []
+      this.allItems.forEach(item => {
+        const t = item.llm_type
+        if (t && !seen[t]) {
+          seen[t] = true
+          ret.push({ value: t, label: t, icon: getTypeIcon(t) })
+        }
+      })
+      return ret
+    },
+    columns () {
+      return [
+        {
+          field: 'image',
+          title: this.$t('aice.llm_image.name'),
+          minWidth: 300,
+          showOverflow: 'tooltip',
+        },
+        {
+          field: 'llm_type',
+          title: this.$t('aice.llm_type.app'),
+          width: 120,
+          slots: {
+            default: ({ row }, h) => {
+              return [h('span', this.$t(`aice.llm_type.${row.llm_type}`) || row.llm_type)]
+            },
+          },
+        },
+        {
+          field: 'description',
+          title: this.$t('common.description'),
+          minWidth: 200,
+          slots: {
+            default: ({ row }, h) => {
+              const html = this.renderMarkdown(row.description)
+              return [h('div', { class: 'md-desc', domProps: { innerHTML: html } })]
+            },
+          },
+        },
+        {
+          field: '_action_import',
+          title: this.$t('common.action'),
+          width: 100,
+          resizable: false,
+          slots: {
+            default: ({ row }, h) => {
+              if (this.isImported(row)) {
+                return [h('a-button', { props: { size: 'small', disabled: true } }, this.$t('aice.llm_image.imported'))]
+              }
+              return [h('a-button', {
+                props: { type: 'primary', size: 'small' },
+                on: { click: () => this.handleImport(row) },
+              }, this.$t('aice.import'))]
+            },
+          },
+        },
+      ]
+    },
+    singleActions () {
+      return []
+    },
+  },
+  watch: {
+    'form.llm_type' (val) {
+      this.fetchExistingByType(val).then(() => {
+        this.refreshList()
+      })
+    },
+    typeList (val) {
+      if (val.length && !val.some(item => item.value === this.form.llm_type)) {
+        this.form.llm_type = val[0].value
+      }
+    },
+  },
+  created () {
+    this.fetchData()
+  },
+  methods: {
+    async fetchExistingByType (llmType) {
+      if (!llmType) return
+      try {
+        const manager = new this.$Manager('llm_images')
+        const res = await manager.list({ params: { limit: 0, llm_type: llmType } })
+        const images = res.data?.data || []
+        // 先清除该类型旧数据
+        const prefix = `${llmType}:`
+        Object.keys(this.existingImages).forEach(key => {
+          if (key.startsWith(prefix)) {
+            this.$delete(this.existingImages, key)
+          }
+        })
+        // 写入最新数据
+        images.forEach(img => {
+          const key = `${img.llm_type}:${img.image_name}:${img.image_label}`
+          this.$set(this.existingImages, key, true)
+        })
+      } catch (e) {
+        // ignore
+      }
+    },
+    isImported (record) {
+      return !!this.existingImages[`${record.llm_type}:${record.image_name}:${record.image_label}`]
+    },
+    getFilteredItems () {
+      if (!this.form.llm_type) return this.allItems
+      return this.allItems.filter(item => item.llm_type === this.form.llm_type)
+    },
+    refreshList () {
+      const filtered = this.getFilteredItems()
+      this.list.responseData = { data: filtered, total: filtered.length }
+      this.list.fetchData()
+    },
+    async fetchData () {
+      this.list.loading = true
+      try {
+        const res = await axios.get(LLM_IMAGES_URL)
+        const items = yaml.safeLoad(res.data)
+        if (!Array.isArray(items)) { this.list.loading = false; return }
+        this.allItems = items.filter(i => i?.image).map((item, index) => {
+          const { image_name, image_label } = parseImageField(item.image)
+          return {
+            id: String(index + 1),
+            image: item.image,
+            image_name,
+            image_label,
+            llm_type: item.llm_type || '',
+            description: item.description || '-',
+            icon: getTypeIcon(item.llm_type || ''),
+          }
+        })
+        // 查询当前选中类型的已导入镜像
+        await this.fetchExistingByType(this.form.llm_type)
+        this.refreshList()
+      } catch (err) {
+        this.list.loading = false
+        this.$message.error(this.$t('aice.llm_image.community_image_fetch_failed'))
+        throw err
+      }
+    },
+    renderMarkdown (text) {
+      if (!text || text === '-') return text || '-'
+      return marked(text)
+    },
+    async handleImport (record) {
+      try {
+        const createData = {
+          generate_name: `${record.llm_type}-${record.image_label}`,
+          llm_type: record.llm_type,
+          image_name: record.image_name,
+          image_label: record.image_label,
+        }
+        await new this.$Manager('llm_images').create({ data: createData })
+        this.$set(this.existingImages, `${record.llm_type}:${record.image_name}:${record.image_label}`, true)
+        this.$message.success(this.$t('common.success'))
+      } catch (err) {
+        throw err
+      }
+    },
+  },
+}
+</script>
+
+<style scoped>
+.mt-3 {
+  margin-top: 12px;
+}
+.mb-2 {
+  margin-bottom: 8px;
+}
+</style>
+<style>
+.md-desc p {
+  margin-bottom: 0;
+}
+.md-desc a {
+  color: #1890ff;
+}
+</style>

+ 0 - 42
frontend/containers/Compute/router/index.js

@@ -78,9 +78,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.vminstance')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'private', 'public', 'vmware'])
             },
           },
@@ -147,9 +144,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.baremetal')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['baremetal'])
             },
           },
@@ -199,9 +193,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.servertemplate')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'azure'])
             },
           },
@@ -236,9 +227,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.scalinggroup')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'azure'])
             },
           },
@@ -305,9 +293,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.host_image')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack'])
             },
           },
@@ -329,9 +314,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.image')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion !== 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'private', 'public', 'baremetal', 'vmware'])
             },
           },
@@ -409,9 +391,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.disk_snapshot')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'private', 'public'])
             },
           },
@@ -434,9 +413,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.instance_snapshot')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'vmware'])
             },
           },
@@ -459,9 +435,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.snapshotpolicy')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'aliyun', 'qcloud'])
             },
           },
@@ -490,9 +463,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.disk_backup')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack'])
             },
           },
@@ -514,9 +484,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.instance_backup')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack'])
             },
           },
@@ -629,9 +596,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.tap_service')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !(hasSetupKey(['onestack']) && store.getters.isAdminMode)
             },
           },
@@ -665,9 +629,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.keypair')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'public', 'private', 'baremetal', 'vmware'])
             },
           },
@@ -697,9 +658,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.sku')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['onestack', 'private', 'vmware', 'public'])
             },
           },

+ 0 - 5
frontend/containers/Compute/views/app-package/index.vue

@@ -56,11 +56,6 @@ export default {
   },
   computed: {
     cloudEnvOptions () {
-      if (this.$store.getters?.globalSetting?.value?.productVersion === 'AI') {
-        return [
-          { label: this.$t('dictionary.onpremise_env'), key: 'onpremise' },
-        ]
-      }
       return [
         { label: this.$t('dictionary.onpremise_env'), key: 'onpremise' },
         { label: this.$t('dictionary.private_env'), key: 'private' },

+ 0 - 5
frontend/containers/Compute/views/gpu/index.vue

@@ -25,11 +25,6 @@ export default {
   },
   computed: {
     tabOptions () {
-      if (this.$store.getters?.globalSetting?.value?.productVersion === 'AI') {
-        return [
-          { label: this.$t('compute.pci.passthrough_device'), key: 'gpu-list' },
-        ]
-      }
       return [
         { label: this.$t('compute.pci.passthrough_device'), key: 'gpu-list' },
         { label: this.$t('compute.pci.passthrough_device_type'), key: 'pci-list' },

+ 2 - 2
frontend/containers/Compute/views/image/components/List.vue

@@ -120,7 +120,7 @@ export default {
           // eslint-disable-next-line vue/no-side-effects-in-computed-properties
           this.$router.push({ name: 'ImageImportCe' })
         },
-        hidden: () => this.$isScopedPolicyMenuHidden('image_hidden_menus.image_store') || this.$store.getters?.globalSetting?.value?.productVersion === 'AI',
+        hidden: () => this.$isScopedPolicyMenuHidden('image_hidden_menus.image_store'),
       }
       const ImageUpload = {
         label: this.$t('compute.text_643'),
@@ -135,7 +135,7 @@ export default {
         meta: () => ({
           buttonType: 'primary',
         }),
-        hidden: () => this.$isScopedPolicyMenuHidden('image_hidden_menus.image_upload') || this.$store.getters?.globalSetting?.value?.productVersion === 'AI',
+        hidden: () => this.$isScopedPolicyMenuHidden('image_hidden_menus.image_upload'),
       }
       const batchActions = [
         {

+ 0 - 5
frontend/containers/Compute/views/image/index.vue

@@ -56,11 +56,6 @@ export default {
   },
   computed: {
     cloudEnvOptions () {
-      if (this.$store.getters?.globalSetting?.value?.productVersion === 'AI') {
-        return [
-          { label: this.$t('dictionary.onpremise_env'), key: 'onpremise' },
-        ]
-      }
       return [
         { label: this.$t('dictionary.onpremise_env'), key: 'onpremise' },
         { label: this.$t('dictionary.private_env'), key: 'private' },

+ 2 - 18
frontend/containers/Helm/router/index.js

@@ -1,10 +1,9 @@
 // import AnsibleTemplate from '@Compute/views/ansible-template'
 // import AnsibleTemplateCreate from '@Compute/views/ansible-template/create'
 import Layout from '@/layouts/RouterView'
-import { setupKeys, isBaremetalProduct } from '@/utils/auth'
+import { setupKeys } from '@/utils/auth'
 import i18n from '@/locales'
 import { isScopedPolicyMenuHidden } from '@/utils/scopedPolicy'
-import store from '@/store'
 
 const VmRelase = () => import(/* webpackChunkName: "helm" */ /* webpackPrefetch: true */ '@Helm/views/vm-release')
 const VmReleaseUpdate = () => import(/* webpackChunkName: "helm" */ /* webpackPrefetch: true */ '@Helm/views/vm-release/update')
@@ -43,13 +42,10 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.scheduledtask')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return process.env.VUE_APP_IS_PRIVATE ? !setupKeys.hasVersionedSetupKey({
                 '3.0': ['monitor'],
                 default: ['onestack', 'private', 'public', 'vmware'],
-              }) : (!setupKeys.hasVersionedSetupKey({ '3.0': ['onecloud'] }) || isBaremetalProduct())
+              }) : (!setupKeys.hasVersionedSetupKey({ '3.0': ['onecloud'] }))
             },
             label: i18n.t('helm.text_8'),
             permission: 'scheduledtasks_list',
@@ -105,9 +101,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.vm_release')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return process.env.VUE_APP_IS_PRIVATE ? !setupKeys.hasVersionedSetupKey({
                 '3.0': ['monitor'],
                 default: ['onestack', 'openstack', 'dstack', 'zstack', 'public', 'k8s', 'vmware', 'hcso', 'hcs'],
@@ -138,9 +131,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.k8s_release')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !setupKeys.hasAllVersionedSetupKey({
                 '3.0': ['monitor', 'k8s'],
                 default: ['k8s'],
@@ -170,9 +160,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.k8s_chart')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return process.env.VUE_APP_IS_PRIVATE ? !setupKeys.hasVersionedSetupKey({
                 '3.0': ['monitor'],
                 default: ['onestack', 'openstack', 'dstack', 'zstack', 'public', 'k8s', 'vmware', 'hcso', 'hcs'],
@@ -203,9 +190,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.k8s_repo')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return process.env.VUE_APP_IS_PRIVATE ? !setupKeys.hasVersionedSetupKey({
                 '3.0': ['monitor'],
                 default: ['onestack', 'openstack', 'dstack', 'zstack', 'public', 'k8s', 'vmware', 'hcso', 'hcs'],

+ 2 - 11
frontend/containers/Network/router/index.js

@@ -4,7 +4,7 @@
 // import LoadbalancerclusterList from '@Network/views/ssh-service'
 
 import Layout from '@/layouts/RouterView'
-import { hasSetupKey, isBaremetalProduct } from '@/utils/auth'
+import { hasSetupKey } from '@/utils/auth'
 import i18n from '@/locales'
 import store from '@/store'
 import { isScopedPolicyMenuHidden } from '@/utils/scopedPolicy'
@@ -196,10 +196,7 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.vpc')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'LightEdge') {
-                return true
-              }
-              return isBaremetalProduct() || !hasSetupKey(['openstack', 'onestack', 'zstack', 'dstack', 'public', 'baremetal', 'apsara', 'hcso', 'hcs', 'bingocloud'])
+              return !hasSetupKey(['openstack', 'onestack', 'zstack', 'dstack', 'public', 'baremetal', 'apsara', 'hcso', 'hcs', 'bingocloud'])
             },
           },
           component: Layout,
@@ -533,9 +530,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.ssh_proxy')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return !hasSetupKey(['private', 'vmware', 'public'])
             },
           },
@@ -562,9 +556,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.ssh_agent')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               return store.getters.isDomainMode || !hasSetupKey(['private', 'vmware', 'public'])
             },
           },

+ 0 - 3
frontend/containers/Storage/router/index.js

@@ -202,9 +202,6 @@ export default {
               if (isScopedPolicyMenuHidden('sub_hidden_menus.backup_storage')) {
                 return true
               }
-              if (store.getters?.globalSetting?.value?.productVersion === 'AI') {
-                return true
-              }
               if (store.getters.isProjectMode) return true
               return !hasSetupKey(['onestack'])
             },

+ 0 - 5
frontend/containers/Storage/views/blockstorage/index.vue

@@ -40,11 +40,6 @@ export default {
   },
   computed: {
     cloudEnvOptions () {
-      if (this.$store.getters?.globalSetting?.value?.productVersion === 'AI') {
-        return [
-          { key: 'host', label: this.$t('compute.text_111') },
-        ]
-      }
       return [
         { key: 'host', label: this.$t('compute.text_111') },
         { key: 'baremetal', label: this.$t('compute.text_112') },

+ 0 - 5
frontend/package.json

@@ -13,8 +13,6 @@
     "deploy": "node ./upload/upload.js"
   },
   "dependencies": {
-    "@interactjs/interactjs": "^1.10.27",
-    "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "^1.0.2",
     "ajv": "^6.12.3",
@@ -23,12 +21,10 @@
     "ant-design-vue": "^1.6.4",
     "axios": "^0.19.0",
     "chalk": "^4.1.0",
-    "classnames": "^2.5.1",
     "clipboard": "^2.0.11",
     "codemirror": "^5.52.2",
     "compressing": "^1.5.1",
     "core-js": "^3.6.5",
-    "cropperjs": "1.5.13",
     "crypto-js": "^4.0.0",
     "custom-protocol-detection": "^1.0.1",
     "echarts": "^4.4.0",
@@ -56,7 +52,6 @@
     "resize-observer-polyfill": "^1.5.1",
     "shelljs": "^0.8.4",
     "socket.io-client": "^2.3.0",
-    "sortablejs": "^1.15.7",
     "uplot": "1.5.2",
     "v-charts": "^1.19.0",
     "vue": "^2.7.14",

+ 1 - 1
frontend/scope/layouts/Navbar/index.vue

@@ -267,7 +267,7 @@ export default {
     },
     globalSettingSetupKeys () {
       const { globalSetting } = this.$store.state
-      if (globalSetting && globalSetting.value && globalSetting.value.setupKeys) {
+      if (globalSetting && globalSetting.value) {
         return globalSetting.value.setupKeys
       }
       return []

+ 5 - 0
frontend/src/assets/images/llm-images/comfyui.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#22c55e"/>
+  <text x="32" y="26" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#fff" text-anchor="middle">Comfy</text>
+  <text x="32" y="42" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#fff" text-anchor="middle">UI</text>
+</svg>

+ 4 - 0
frontend/src/assets/images/llm-images/default.svg

@@ -0,0 +1,4 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#9ca3af"/>
+  <text x="32" y="40" font-family="Arial,sans-serif" font-size="18" font-weight="bold" fill="#fff" text-anchor="middle">LLM</text>
+</svg>

+ 4 - 0
frontend/src/assets/images/llm-images/dify.svg

@@ -0,0 +1,4 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#1570ef"/>
+  <text x="32" y="40" font-family="Arial,sans-serif" font-size="18" font-weight="bold" fill="#fff" text-anchor="middle">Dify</text>
+</svg>

+ 4 - 0
frontend/src/assets/images/llm-images/ollama.svg

@@ -0,0 +1,4 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#1a1a2e"/>
+  <text x="32" y="38" font-family="Arial,sans-serif" font-size="12" font-weight="bold" fill="#fff" text-anchor="middle">Ollama</text>
+</svg>

+ 5 - 0
frontend/src/assets/images/llm-images/openclaw.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#6366f1"/>
+  <text x="32" y="26" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#fff" text-anchor="middle">Open</text>
+  <text x="32" y="42" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#fff" text-anchor="middle">Claw</text>
+</svg>

+ 4 - 0
frontend/src/assets/images/llm-images/vllm.svg

@@ -0,0 +1,4 @@
+<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
+  <rect width="64" height="64" rx="12" fill="#0ea5e9"/>
+  <text x="32" y="38" font-family="Arial,sans-serif" font-size="14" font-weight="bold" fill="#fff" text-anchor="middle">vLLM</text>
+</svg>

+ 1 - 2
frontend/src/permission.js

@@ -137,8 +137,7 @@ router.beforeEach(async (to, from, next) => {
     // !hasGlobalServices && await store.dispatch('common/fetchGlobalServices')
     !hasMonitorResourceAlerts && await store.dispatch('monitor/loadMonitorResourceAlerts')
   } catch (error) {
-    // 忽略错误,确保页面可以正常渲染
-    console.warn('Initialization error:', error)
+    throw error
   } finally {
     const { canRenderDefaultLayout = true } = to.meta
     if (canRenderDefaultLayout) {

+ 4 - 8
frontend/src/store/modules/auth.js

@@ -394,8 +394,7 @@ export default {
         await commit('SET_CAPABILITY', data)
         return response.data
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('getCapabilities error:', error)
+        throw error
       }
     },
     async getStats ({ commit, state }) {
@@ -409,8 +408,7 @@ export default {
         await commit('SET_STATS', data)
         return response.data.data
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('getStats error:', error)
+        throw error
       }
     },
     async getPermission ({ commit, state }) {
@@ -420,8 +418,7 @@ export default {
         await commit('SET_PERMISSION', response.data)
         return response.data
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('getPermission error:', error)
+        throw error
       }
     },
     async getScopeResource ({ commit }) {
@@ -433,8 +430,7 @@ export default {
         await commit('SET_SCOPERESOURCE', data)
         return response.data
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('getScopeResource error:', error)
+        throw error
       }
     },
     async getRegions ({ commit, state }, params) {

+ 1 - 2
frontend/src/store/modules/common.js

@@ -267,8 +267,7 @@ export default {
           commit('SET_GLOBAL_SERVICE', data)
         }
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('fetchGlobalServices error:', error)
+        throw error
       }
     },
   },

+ 2 - 3
frontend/src/store/modules/monitor.js

@@ -23,13 +23,12 @@ export default {
           limit: 1,
           scope: getScopeFromCookie() || 'project',
           ...payload,
-          ignoreErrorStatusCode: [403, 404],
+          ignoreErrorStatusCode: [403],
         }
         const { data: { data = [] } } = await new Manager('monitorresourcealerts', 'v1').list({ params })
         commit('setMonitorResourceAlerts', data)
       } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        commit('setMonitorResourceAlerts', [])
+        throw error
       }
     },
   },

+ 0 - 3
frontend/src/store/modules/scopedPolicy.js

@@ -49,9 +49,6 @@ export default {
         } else {
           return {}
         }
-      } catch (error) {
-        // 忽略错误,避免阻塞页面渲染
-        console.warn('scopedPolicy get error:', error)
       } finally {
         onFinally && onFinally()
       }