Alsmile 1 سال پیش
والد
کامیت
77c04759d7
4فایلهای تغییر یافته به همراه446 افزوده شده و 238 حذف شده
  1. 3 4
      src/services/api.ts
  2. 136 33
      src/services/pinyin.ts
  3. 36 23
      src/services/png.ts
  4. 271 178
      src/views/components/Graphics.vue

+ 3 - 4
src/services/api.ts

@@ -1,9 +1,8 @@
 //所有的接口请求
 import axios from 'axios';
-export const cdn = '';
-// import.meta.env.VITE_ROUTER_BASE
-// ? ""
-// : "https://assets.le5lecdn.com";
+export const cdn = import.meta.env.VITE_ROUTER_BASE
+  ? ''
+  : 'https://assets.le5lecdn.com';
 
 export const upCdn = import.meta.env.VITE_ROUTER_BASE
   ? ''

+ 136 - 33
src/services/pinyin.ts

@@ -405,16 +405,16 @@ const pinyinDictNotone = {
   nou: '耨',
 };
 
-const chineseDist: Record<string, string> = {};
+const chineseDist: Record<string, Array<string>> = {};
 
 if (!chineseDist.一) {
-  // tslint:disable-next-line: forin
   for (const i in pinyinDictNotone) {
-    const temp: string = pinyinDictNotone[i];
+    const temp = pinyinDictNotone[i];
     for (let j = 0; j < temp.length; ++j) {
       if (!chineseDist[temp[j]]) {
-        chineseDist[temp[j]] = i;
+        chineseDist[temp[j]] = [];
       }
+      chineseDist[temp[j]].push(i);
     }
   }
 }
@@ -424,55 +424,158 @@ export function getPinyin(chinese: string, short?: boolean) {
     return '';
   }
 
-  const result = [];
-  let noChinese = '';
+  // 汉字拼音列表
+  let pyList = [];
+
   for (let i = 0, len = chinese.length; i < len; i++) {
-    const temp = chinese.charAt(i);
-    const pinyin = chineseDist[temp];
-    if (pinyin) {
-      // tslint:disable-next-line:no-unused-expression
-      noChinese && (result.push(noChinese), (noChinese = ''));
+    // 单个汉字
+    const c = chinese.charAt(i);
+
+    // 单个汉字多音字拼音列表。如果没有多音字,列表长度为1
+    const cPinyinList = [];
+    const pys = chineseDist[c];
+    if (pys) {
+      for (const py of pys) {
+        if (short) {
+          cPinyinList.push(py[0]);
+        } else {
+          cPinyinList.push(py);
+        }
+      }
+    } else if (c && !/^ +$/g.test(c)) {
       if (short) {
-        result.push(pinyin[0]);
+        cPinyinList.push(c[0].toLowerCase());
       } else {
-        result.push(pinyin);
+        cPinyinList.push(c.toLowerCase());
+      }
+    }
+
+    if (pyList.length) {
+      if (cPinyinList.length) {
+        const results = [];
+        for (const item1 of pyList) {
+          for (const item2 of cPinyinList) {
+            results.push(item1 + item2);
+          }
+        }
+        pyList = results;
       }
-    } else if (!temp || /^ +$/g.test(temp)) {
-      // tslint:disable-next-line:no-unused-expression
-      noChinese && (result.push(noChinese), (noChinese = ''));
     } else {
-      noChinese += temp;
+      pyList = cPinyinList;
     }
   }
 
-  if (noChinese) {
-    result.push(noChinese);
-    noChinese = '';
+  return pyList;
+}
+
+export function getObjectPinyin(obj: any, prop: string) {
+  if (!obj) {
+    return;
   }
-  let resultText = result
-    .join('')
-    .toLowerCase()
-    .replace(/[^0-9a-z_]/g, '');
-  if (resultText[0] === '_') {
-    resultText = resultText.replace('_', '');
+
+  // 简拼
+  obj.pyList = [];
+  // 全拼
+  obj.pinyinList = [];
+
+  const chinese = obj[prop];
+  if (typeof chinese !== 'string' || /^ +$/g.test(chinese)) {
+    return;
+  }
+
+  for (let i = 0, len = chinese.length; i < len; i++) {
+    // 单个汉字
+    const c = chinese.charAt(i);
+
+    // 单个汉字多音字拼音列表。如果没有多音字,列表长度为1
+    const cPyList = [];
+    const cPinyinList = [];
+    const pys = chineseDist[c];
+    if (pys) {
+      for (const py of pys) {
+        cPyList.push(py[0]);
+        cPinyinList.push(py);
+      }
+    } else if (c && !/^ +$/g.test(c)) {
+      cPyList.push(c[0].toLowerCase());
+      cPinyinList.push(c.toLowerCase());
+    }
+
+    if (obj.pyList.length) {
+      if (cPyList.length) {
+        const results = [];
+        for (const item1 of obj.pyList) {
+          for (const item2 of cPyList) {
+            results.push(item1 + item2);
+          }
+        }
+        obj.pyList = results;
+      }
+    } else {
+      obj.pyList = cPyList;
+    }
+
+    if (obj.pinyinList.length) {
+      if (cPinyinList.length) {
+        const results = [];
+        for (const item1 of obj.pinyinList) {
+          for (const item2 of cPinyinList) {
+            results.push(item1 + item2);
+          }
+        }
+        obj.pinyinList = results;
+      }
+    } else {
+      obj.pinyinList = cPinyinList;
+    }
   }
-  return resultText;
 }
 
-export function inSearch(text: string, keyword: string) {
+export function searchPinyin(text: string, keyword: string) {
   if (text.indexOf(keyword) >= 0) {
     return true;
   }
 
-  let py = getPinyin(text, true);
-  if (py.indexOf(keyword) >= 0) {
-    return true;
+  let pys = getPinyin(text, true);
+  for (const py of pys) {
+    if (py.indexOf(keyword) >= 0) {
+      return true;
+    }
   }
 
-  py = getPinyin(text);
-  if (py.indexOf(keyword) >= 0) {
+  pys = getPinyin(text);
+  for (const py of pys) {
+    if (py.indexOf(keyword) >= 0) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+export function searchObjectPinyin(obj: any, prop: string, keyword: string) {
+  if (!obj || !obj[prop]) {
+    return false;
+  }
+  if (obj[prop].indexOf(keyword) >= 0) {
     return true;
   }
 
+  if (!obj.pyList) {
+    getObjectPinyin(obj, prop);
+  }
+
+  for (const py of obj.pyList) {
+    if (py.indexOf(keyword) >= 0) {
+      return true;
+    }
+  }
+
+  for (const py of obj.pyList) {
+    if (py.indexOf(keyword) >= 0) {
+      return true;
+    }
+  }
+
   return false;
 }

+ 36 - 23
src/services/png.ts

@@ -9,31 +9,37 @@ export function filename(str: string) {
   return str.substring(0, i);
 }
 
-export async function getFolders(name: string, svg?: boolean) {
-  const folder = baseurl + name + '/';
-  const ret = (await axios.get(folder)) as any[];
-
-  if (!ret || !ret.map) {
+export async function getFolders(name: string, isSvg?: boolean) {
+  const path = 'v/' + name;
+  const folders: any = await axios.post('/api/assets/folders', {
+    path,
+  });
+  if (!folders) {
     return [];
   }
-  return await Promise.all(
-    ret.map(async (c: any) => {
-      const files = (await axios.get(folder + c.name + '/')) as any[];
-      return {
-        folder,
-        name: globalThis.folderJson
-          ? globalThis.folderJson[c.name]
-            ? globalThis.folderJson[c.name]
-            : c.name
-          : c.name,
-        pinyin: globalThis.folderJson ? c.name : null,
-        show: true,
-        list: [],
-        count: files.length,
-        svg,
-      };
-    })
-  );
+
+  const files: any = await axios.post('/api/assets/files', {
+    path,
+  });
+
+  const results = [];
+  for (const item of folders.list) {
+    const list = [];
+    for (const f of files.list) {
+      if (f.indexOf(item) >= 0) {
+        const elem: any = {
+          name: filename(f.replace(path + '/' + item + '/', '')),
+          image: cdn + '/' + f.replace('v/', ''),
+          isSvg,
+        };
+        list.push(elem);
+      }
+    }
+
+    results.push({ name: item, list });
+  }
+
+  return results;
 }
 
 export async function getFiles(folder: string) {
@@ -58,6 +64,13 @@ export async function getFiles(folder: string) {
   });
 }
 
+export async function makeSvg(elem: any) {
+  const svgDom: string = await axios.get(elem.image);
+  let _svgDom = svgDom.replaceAll('#333;', '#fff;');
+  elem.svg = _svgDom;
+  elem.data = parseSvg(_svgDom);
+}
+
 export async function getIcons(folder: string) {
   const files = (await axios.get(folder)) as any[];
   return await Promise.all(files.map((f) => svgToPens(f, folder)));

+ 271 - 178
src/views/components/Graphics.vue

@@ -10,6 +10,17 @@
         @enter="onSearch"
         placeholder="搜索"
       />
+
+      <div class="ml-16">
+        <t-tooltip content="展开/折叠">
+          <t-icon
+            name="menu-fold"
+            class="hover"
+            style="font-size: 16px"
+            @click="onFold"
+          />
+        </t-tooltip>
+      </div>
     </div>
     <div class="groups-panel">
       <div class="groups">
@@ -23,60 +34,61 @@
         </div>
       </div>
       <div class="list" :class="groupType ? 'two-columns' : ''">
-        <div v-if="activedGroup === '我的'" class="px-16 mt-12 mb-8 ml-4">
-          <a @click="onCreateFolder">+ 新建文件夹</a>
+        <div v-if="loading">
+          <t-loading
+            text="加载中..."
+            size="small"
+            style="margin: 32px 0 4px 32px"
+          />
         </div>
-        <t-collapse
-          v-if="groupType < 2"
-          v-model:value="activedPanel"
-          @change="onChangeGroupPanel"
-        >
-          <t-collapse-panel
-            :value="item.name"
-            v-for="item in subGroups"
-            :key="item.name"
+        <template v-else>
+          <div v-if="activedGroup === '我的'" class="px-16 mt-12 mb-8 ml-4">
+            <a @click="onCreateFolder">+ 新建文件夹</a>
+          </div>
+          <t-collapse
+            v-if="groupType < 2"
+            v-model="activedPanels[activedGroup]"
+            @change="onChangeGroupPanel"
           >
-            <template #header>
-              <div class="flex middle mr-8">
-                <div v-if="item.edited" @click.stop>
-                  <t-input
-                    v-model="item.label"
-                    style="width: 140px"
-                    @blur="createFoder"
-                    @enter="createFoder"
-                    @keyup="onKeyHeader"
-                  />
-                </div>
-                <div v-else class="ellipsis" style="width: 140px">
-                  {{ item.name }}
+            <t-collapse-panel
+              :value="item.name"
+              v-for="item in subGroups"
+              :key="item.name"
+            >
+              <template #header>
+                <div class="flex middle mr-8">
+                  <div v-if="item.edited" @click.stop>
+                    <t-input
+                      v-model="item.label"
+                      style="width: 140px"
+                      @blur="createFoder"
+                      @enter="createFoder"
+                      @keyup="onKeyHeader"
+                    />
+                  </div>
+                  <div v-else class="ellipsis">
+                    {{ item.name }}
+                  </div>
                 </div>
-              </div>
-            </template>
-            <template #headerRightContent v-if="item.canEdited">
-              <t-space size="small" @click.stop>
-                <t-icon
-                  name="edit"
-                  class="hover mr-4"
-                  @click="onEditHeader(item)"
-                />
+              </template>
+              <template #headerRightContent v-if="item.canEdited">
+                <t-space size="small" @click.stop>
+                  <t-icon
+                    name="edit"
+                    class="hover mr-4"
+                    @click="onEditHeader(item)"
+                  />
+
+                  <t-popconfirm
+                    content="确认删除该文件夹吗"
+                    placement="left"
+                    @confirm=""
+                  >
+                    <t-icon name="delete" class="hover" />
+                  </t-popconfirm>
+                </t-space>
+              </template>
 
-                <t-popconfirm
-                  content="确认删除该文件夹吗"
-                  placement="left"
-                  @confirm=""
-                >
-                  <t-icon name="delete" class="hover" />
-                </t-popconfirm>
-              </t-space>
-            </template>
-            <div v-if="item.loading">
-              <t-loading
-                text="加载中..."
-                size="small"
-                style="margin-left: 32px; margin-bottom: 4px"
-              />
-            </div>
-            <template v-else>
               <template v-for="elem in item.list">
                 <div
                   v-show="elem.visible !== false"
@@ -88,10 +100,11 @@
                   @contextmenu="onContextMenu($event, item, elem)"
                 >
                   <t-image
-                    v-if="elem.image"
+                    v-if="!elem.svg && elem.image"
                     :src="elem.image"
                     :lazy="true"
                     fit="contain"
+                    @load="loadImage(elem)"
                   />
                   <div class="svg-box" v-else-if="elem.svg" v-html="elem.svg" />
                   <svg v-else class="l-icon" aria-hidden="true">
@@ -108,44 +121,46 @@
                 class="gray center"
                 style="white-space: nowrap; margin-left: 32px"
               >
-                暂无数据,待更新
+                暂无数据
+              </div>
+            </t-collapse-panel>
+          </t-collapse>
+          <div v-else class="t-collapse-panel__content" style="padding: 8px">
+            <template v-for="elem in subGroups">
+              <div
+                class="graphic"
+                :draggable="true"
+                v-show="elem.visible !== false"
+                @dragstart="dragStart($event, elem)"
+                @click.stop="dragStart($event, elem)"
+                @dblclick.stop="open(elem)"
+              >
+                <t-image
+                  v-if="elem.image"
+                  :src="elem.image"
+                  :lazy="true"
+                  fit="contain"
+                />
+                <div class="svg-box" v-else-if="elem.svg" v-html="elem.svg" />
+                <svg v-else class="l-icon" aria-hidden="true">
+                  <use :xlink:href="'#' + elem.icon"></use>
+                </svg>
+                <p :title="elem.name">{{ elem.name }}</p>
+                <div class="price" v-if="elem.price > 0">
+                  ¥{{ elem.price }}
+                </div>
               </div>
             </template>
-          </t-collapse-panel>
-        </t-collapse>
-        <div v-else class="t-collapse-panel__content" style="padding: 8px">
-          <template v-for="elem in subGroups">
+
             <div
-              class="graphic"
-              :draggable="true"
-              v-show="elem.visible !== false"
-              @dragstart="dragStart($event, elem)"
-              @click.stop="dragStart($event, elem)"
-              @dblclick.stop="open(elem)"
+              v-if="!subGroups.length"
+              class="gray center"
+              style="white-space: nowrap; margin-left: 32px"
             >
-              <t-image
-                v-if="elem.image"
-                :src="elem.image"
-                :lazy="true"
-                fit="contain"
-              />
-              <div class="svg-box" v-else-if="elem.svg" v-html="elem.svg" />
-              <svg v-else class="l-icon" aria-hidden="true">
-                <use :xlink:href="'#' + elem.icon"></use>
-              </svg>
-              <p :title="elem.name">{{ elem.name }}</p>
-              <div class="price" v-if="elem.price > 0">¥{{ elem.price }}</div>
+              暂无数据
             </div>
-          </template>
-
-          <div
-            v-if="!subGroups.length"
-            class="gray center"
-            style="white-space: nowrap; margin-left: 32px"
-          >
-            暂无数据,待更新
           </div>
-        </div>
+        </template>
       </div>
     </div>
 
@@ -240,14 +255,14 @@ import axios from 'axios';
 
 import { cases, shapes, formComponents } from '@/services/defaults';
 import { charts } from '@/services/echarts';
-import { getFolders, getFiles, getIcons } from '@/services/png';
+import { getFolders, getFiles, makeSvg } from '@/services/png';
 import { getComponentsList, getLe5leV, updateCollection } from '@/services/api';
 import { convertPen } from '@/services/upgrade';
 import { deepClone } from '@meta2d/core';
 import { isGif } from '@/services/utils';
 import { autoSave, delAttrs } from '@/services/common';
 import { debounce } from '@/services/debouce';
-import { inSearch } from '@/services/pinyin';
+import { searchObjectPinyin } from '@/services/pinyin';
 
 import WechatPay from './WechatPay.vue';
 
@@ -300,9 +315,9 @@ const groups = reactive([
 ]);
 const subGroups = ref<any[]>([]);
 const groupType = ref(0);
-const activedPanel = ref([]);
+const activedPanels = reactive<any>({});
 
-const caseCaches = reactive<any>({});
+const caseCaches = ref<any[]>([]);
 const templates = ref([]);
 const materials = ref([]);
 const pngs = ref([]);
@@ -316,23 +331,29 @@ const wechatPayDialog = reactive<any>({
 
 const search = ref('');
 
+const loading = ref(false);
+
 const groupChange = async (name: string) => {
-  activedPanel.value = [];
   activedGroup.value = name;
   groupType.value = 0;
   switch (name) {
     case '场景':
       groupType.value = 1;
-      subGroups.value = cases;
-      subGroups.value[0].loading = true;
-      if (!caseCaches[name + cases[0].name]) {
-        caseCaches[name + cases[0].name] = await getCaseProjects(
-          name,
-          cases[0].name
-        );
+      if (!caseCaches.value.length) {
+        loading.value = true;
+        caseCaches.value = await getCaseProjects(name);
+        for (const group of cases) {
+          group.list = [];
+          for (const item of caseCaches.value) {
+            if (item.case === group.name) {
+              group.list.push(item);
+            }
+          }
+        }
+        loading.value = false;
       }
-      subGroups.value[0].list = caseCaches[name + cases[0].name];
-      subGroups.value[0].loading = false;
+      subGroups.value = cases;
+
       break;
     case '模板':
       groupType.value = 2;
@@ -361,10 +382,9 @@ const groupChange = async (name: string) => {
       }
       subGroups.value.push(...pngs.value);
       if (!icons.value.length) {
-        icons.value = await getFolders('svg');
+        icons.value = await getFolders('svg', true);
       }
       subGroups.value.push(...icons.value);
-      onChangeGroupPanel([subGroups.value[0].name]);
       break;
     case '图形':
       subGroups.value = shapes;
@@ -375,20 +395,32 @@ const groupChange = async (name: string) => {
       onChangeGroupPanel([subGroups.value[0].name]);
       break;
   }
-  activedPanel.value = [subGroups.value[0].name];
+
+  if (!activedPanels[name]) {
+    activedPanels[name] = [];
+    for (const item of subGroups.value) {
+      activedPanels[name].push(item.name);
+    }
+  }
+
+  searchGraphics();
 };
 
-const getCaseProjects = async (name: string, group?: string) => {
+const getCaseProjects = async (name: string, current = 1, pageSize = 1000) => {
   const query: any = { tags: name };
-  if (group) {
-    query.case = group;
-  }
+
   const ret: any = await axios.post(
-    '/api/data/le5leV/list?current=1&pageSize=100',
+    '/api/data/le5leV/list',
     {
       query,
       shared: 'true',
-      projection: { id: 1, _id: 1, name: 1, image: 1, price: 1 },
+      projection: { id: 1, _id: 1, name: 1, image: 1, price: 1, case: 1 },
+    },
+    {
+      params: {
+        current,
+        pageSize,
+      },
     }
   );
 
@@ -473,20 +505,6 @@ const dragStart = async (event: DragEvent | MouseEvent, item: any) => {
       externElement: true,
       iframe: 'https://view3d.le5le.com/?id=' + (item._id || item.id),
     };
-    //获取3d数据
-    //获取3d数据
-    // if (!item.data) {
-    //   let ret = await getLe5le3d(item._id || item.id);
-    //   item.data = ret.data;
-    // }
-    // data = {
-    //   name: 'threeDSence',
-    //   externElement: true,
-    //   width: 500,
-    //   height: 400,
-    //   data: item.data,
-    //   //3d场景的其他信息
-    // };
   } else if (item.component) {
     // 我的组件
     if (!item.componentDatas && !item.componentData) {
@@ -584,42 +602,6 @@ const onChangeGroupPanel = async (val: string[]) => {
   if (val?.length) {
     for (const name of val) {
       switch (activedGroup.value) {
-        case '场景':
-          if (
-            !caseCaches[activedGroup.value + name] ||
-            !caseCaches[activedGroup.value + name].length
-          ) {
-            for (const item of subGroups.value) {
-              if (item.name === name) {
-                item.loading = true;
-              }
-            }
-            caseCaches[activedGroup.value + name] = await getCaseProjects(
-              activedGroup.value,
-              name
-            );
-            for (const item of subGroups.value) {
-              if (item.name === name) {
-                item.list = caseCaches[activedGroup.value + name];
-                item.loading = false;
-              }
-            }
-          }
-          break;
-        case '图元':
-          for (const item of subGroups.value) {
-            if (item.name === name && !item.list.length) {
-              item.loading = true;
-              if (item.svg) {
-                item.list = await getIcons(item.folder);
-              } else {
-                item.list = await getFiles(item.folder + item.name);
-              }
-              item.loading = false;
-            }
-          }
-          break;
-
         case '我的':
           for (const item of subGroups.value) {
             if (!item.list.length) {
@@ -943,57 +925,161 @@ const onSearch = () => {
 const searchGraphics = async () => {
   switch (activedGroup.value) {
     case '场景':
-      for (const group in caseCaches) {
-        for (const item of caseCaches[group]) {
-          if (search.value) {
-            item.visible = inSearch(item.name, search.value);
-          } else {
-            item.visible = true;
-          }
+      if (search.value) {
+        activedPanels[activedGroup.value] = [];
+        for (const item of cases) {
+          activedPanels[activedGroup.value].push(item.name);
+        }
+      }
+      for (const item of caseCaches.value) {
+        if (search.value) {
+          item.visible = searchObjectPinyin(item, 'name', search.value);
+        } else {
+          item.visible = true;
         }
       }
       break;
     case '模板':
       for (const item of templates.value) {
         if (search.value) {
-          item.visible = inSearch(item.name, search.value);
+          item.visible = searchObjectPinyin(item, 'name', search.value);
         } else {
           item.visible = true;
         }
       }
       break;
     case '图表':
+      subGroups.value = [];
+      if (search.value) {
+        activedPanels[activedGroup.value] = [];
+      }
+      for (const group of charts) {
+        if (search.value) {
+          activedPanels[activedGroup.value].push(group.name);
+        }
+        for (const item of group.list) {
+          if (search.value) {
+            // @ts-ignore
+            item.visible = searchObjectPinyin(item, 'name', search.value);
+          } else {
+            // @ts-ignore
+            item.visible = true;
+          }
+        }
+      }
+      setTimeout(() => {
+        subGroups.value = charts;
+      });
+
       break;
     case '控件':
-      subGroups.value = formComponents;
+      subGroups.value = [];
+      if (search.value) {
+        activedPanels[activedGroup.value] = [];
+      }
+      for (const group of formComponents) {
+        if (search.value) {
+          activedPanels[activedGroup.value].push(group.name);
+        }
+        for (const item of group.list) {
+          if (search.value) {
+            // @ts-ignore
+            item.visible = searchObjectPinyin(item, 'name', search.value);
+          } else {
+            // @ts-ignore
+            item.visible = true;
+          }
+        }
+      }
+      setTimeout(() => {
+        subGroups.value = formComponents;
+      });
+
       break;
     case '素材':
-      groupType.value = 2;
-      if (!materials.value.length) {
-        materials.value = await getFiles('material/');
+      for (const item of materials.value) {
+        if (search.value) {
+          item.visible = searchObjectPinyin(item, 'name', search.value);
+        } else {
+          item.visible = true;
+        }
       }
-      subGroups.value = materials.value;
       break;
     case '图元':
-      subGroups.value = [];
-      if (!pngs.value.length) {
-        pngs.value = await getFolders('png');
+      if (search.value) {
+        activedPanels[activedGroup.value] = [];
+        for (const group of subGroups.value) {
+          activedPanels[activedGroup.value].push(group.name);
+        }
       }
-      subGroups.value.push(...pngs.value);
-      if (!icons.value.length) {
-        icons.value = await getFolders('svg');
+
+      for (const item of pngs.value) {
+        if (search.value) {
+          item.visible = searchObjectPinyin(item, 'name', search.value);
+        } else {
+          item.visible = true;
+        }
+      }
+
+      for (const item of icons.value) {
+        if (search.value) {
+          item.visible = searchObjectPinyin(item, 'name', search.value);
+        } else {
+          item.visible = true;
+        }
       }
-      subGroups.value.push(...icons.value);
-      onChangeGroupPanel([subGroups.value[0].name]);
       break;
     case '图形':
-      subGroups.value = shapes;
+      subGroups.value = [];
+      if (search.value) {
+        activedPanels[activedGroup.value] = [];
+      }
+      for (const group of shapes) {
+        if (search.value) {
+          activedPanels[activedGroup.value].push(group.name);
+        }
+        for (const item of group.list) {
+          if (search.value) {
+            // @ts-ignore
+            item.visible = searchObjectPinyin(item, 'name', search.value);
+          } else {
+            // @ts-ignore
+            item.visible = true;
+          }
+        }
+      }
+      setTimeout(() => {
+        subGroups.value = shapes;
+      });
+
       break;
     case '我的':
       break;
   }
 };
 
+const onFold = () => {
+  if (!activedPanels[activedGroup.value]) {
+    return;
+  }
+
+  if (activedPanels[activedGroup.value].length) {
+    activedPanels[activedGroup.value] = [];
+  } else {
+    activedPanels[activedGroup.value] = [];
+    for (const item of subGroups.value) {
+      activedPanels[activedGroup.value].push(item.name);
+    }
+  }
+};
+
+const loadImage = (elem: any) => {
+  console.log(elem.isSvg, elem);
+  if (elem.isSvg) {
+    makeSvg(elem);
+  }
+};
+
 onMounted(() => {
   groupChange('场景');
   document.addEventListener('dragstart', dragstart, false);
@@ -1078,6 +1164,10 @@ onUnmounted(() => {
         &:hover {
           color: var(--color-primary);
         }
+
+        .ellipsis {
+          width: 200px;
+        }
       }
 
       :deep(.t-collapse-panel__body) {
@@ -1162,6 +1252,9 @@ onUnmounted(() => {
             width: 100%;
             .cls-1 {
               stroke: var(--color) !important;
+              stroke-width: 4px;
+              fill: none;
+              stroke-dasharray: none;
             }
           }
         }