diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index 816a752493a..b18dcddc372 100644 --- a/ui/src/assets/iconfont.js +++ b/ui/src/assets/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_5200172='',(l=>{var a=(h=(h=document.getElementsByTagName("script"))[h.length-1]).getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var o,v,t,i,c,d=function(a,h){h.parentNode.insertBefore(a,h)};if(a&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}o=function(){var a,h=document.createElement("div");h.innerHTML=l._iconfont_svg_string_5200172,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?d(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),o()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(t=o,i=l.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,e())})}function e(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}e()}})(window); \ No newline at end of file +window._iconfont_svg_string_5200172='',(h=>{var a=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var o,v,t,i,c,d=function(a,l){l.parentNode.insertBefore(a,l)};if(a&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}o=function(){var a,l=document.createElement("div");l.innerHTML=h._iconfont_svg_string_5200172,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?d(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),o()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(t=o,i=h.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,e())})}function e(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}e()}})(window); \ No newline at end of file diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index 98ece809cfe..eb80c597cd4 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -941,9 +941,10 @@ const formValue = ref>({}) ### FolderTree Workspace 的文件夹虚拟树业务组件。组件根据当前资源上下文和 `source` 调用统一文件夹接口,负责 -文件夹树查询、搜索、排序、创建、编辑、移动和删除。通过 `v-model` 控制当前文件夹 ID,选择 -文件夹时触发 `select`。`showAll`、`showShared` 分别控制全部和共享入口,`rootLabel` 可覆盖根入口 -文案,`disabledFolderIds` 用于只选场景中禁用指定节点。 +文件夹树查询、搜索、排序、创建、编辑、移动和删除。通过 `v-model` 控制当前文件夹 ID,首次加载 +完成后通过 `loaded` 返回该 ID 对应的完整文件夹,选择文件夹时触发 `select`。传入的 ID 不存在时, +优先回退到“全部”入口,否则回退到首个可用文件夹。`showAll`、`showShared` 分别控制全部和共享入口, +`rootLabel` 可覆盖根入口文案,`disabledFolderIds` 用于只选场景中禁用指定节点。 ```vue - + ``` 页面顶部需要触发根目录创建时,通过页面语义处理方法调用组件暴露的 `openCreate()`;外部数据变化 diff --git a/ui/src/components/business/folder-tree/index.vue b/ui/src/components/business/folder-tree/index.vue index 6b8aa0bed84..87f93748f78 100644 --- a/ui/src/components/business/folder-tree/index.vue +++ b/ui/src/components/business/folder-tree/index.vue @@ -29,7 +29,7 @@ const props = withDefaults( const currentNodeKey = defineModel({ default: FOLDER_ENTRY_ID.ALL }) -const emit = defineEmits<{ select: [folder: FolderItem] }>() +const emit = defineEmits<{ loaded: [folder?: FolderItem]; select: [folder: FolderItem] }>() const folderEntries = computed(() => FOLDER_ENTRIES[props.source]) const rootFolderEntry = computed(() => ({ ...folderEntries.value.all, name: props.rootLabel || folderEntries.value.all.name })) @@ -250,6 +250,13 @@ function findFolderById(folders: FolderItem[], folderId: string): FolderItem | u } } +function resolveCurrentFolder() { + if (currentNodeKey.value === FOLDER_ENTRY_ID.ALL && props.showAll) return rootFolderEntry.value + if (currentNodeKey.value === FOLDER_ENTRY_ID.SHARED && props.showShared) return folderEntries.value.shared + + return findFolderById(folderTreeData.value, currentNodeKey.value) ?? (props.showAll ? rootFolderEntry.value : sortTreeData.value[0]) +} + function getFolderDeleteContext(folder: FolderItem) { const deletedFolder = findFolderById(folderTreeData.value, folder.id) ?? folder const positionCache = readCustomPositions() @@ -314,7 +321,11 @@ onMounted(() => { if (Object.values(FOLDER_SORT).includes(savedSort as FolderSort)) { currentSort.value = savedSort as FolderSort } - loadFolders() + void loadFolders().then(() => { + const currentFolder = resolveCurrentFolder() + if (currentFolder) currentNodeKey.value = currentFolder.id + emit('loaded', currentFolder) + }) }) defineExpose({ refresh: loadFolders, openCreate: handleOpenCreateFolder }) diff --git a/ui/src/components/business/workspace-dropdown/index.vue b/ui/src/components/business/workspace-dropdown/index.vue index 17a5c62304d..83d6ae5cb97 100644 --- a/ui/src/components/business/workspace-dropdown/index.vue +++ b/ui/src/components/business/workspace-dropdown/index.vue @@ -12,7 +12,7 @@ const emit = defineEmits<{ select: [option: WorkspaceItem] }>()