From 793c641e1c4bbb8ea3ce14915cac173576c07676 Mon Sep 17 00:00:00 2001 From: neko engineer <34001432+nmnmtttt@users.noreply.github.com> Date: Fri, 13 Jun 2025 00:08:36 +0800 Subject: [PATCH] feat: Optimize assistant drag-and-drop effect (#7115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 优化助手拖拽效果 增加组内,组件,跨组拖拽效果 * feat: 提交注释 --------- Co-authored-by: linshuhao --- .../src/components/DragableList/index.tsx | 38 ++-- src/renderer/src/hooks/useTags.ts | 3 +- .../src/pages/home/Tabs/AssistantsTab.tsx | 205 +++++++++++++----- 3 files changed, 174 insertions(+), 72 deletions(-) diff --git a/src/renderer/src/components/DragableList/index.tsx b/src/renderer/src/components/DragableList/index.tsx index 68a948cbaa..4240b8452a 100644 --- a/src/renderer/src/components/DragableList/index.tsx +++ b/src/renderer/src/components/DragableList/index.tsx @@ -51,23 +51,27 @@ const DragableList: FC> = ({ {(item, index) => { const id = item.id || item - return ( - - {(provided) => ( -
- {children(item, index)} -
- )} -
- ) + if (!item.disabled) { + return ( + + {(provided) => ( +
+ {children(item, index)} +
+ )} +
+ ) + } else { + return
{children(item, index)}
+ } }}
{provided.placeholder} diff --git a/src/renderer/src/hooks/useTags.ts b/src/renderer/src/hooks/useTags.ts index 44d43377c1..24b6080873 100644 --- a/src/renderer/src/hooks/useTags.ts +++ b/src/renderer/src/hooks/useTags.ts @@ -23,7 +23,7 @@ export const useTags = () => { // 计算所有标签 const allTags = useMemo(() => { - const tags = uniq(flatMap(assistants, (assistant) => assistant.tags || [])) + const tags = uniq(flatMap(assistants, (assistant) => assistant?.tags || [])) if (savedTagsOrder.length > 0) { return [ ...savedTagsOrder.filter((tag) => tags.includes(tag)), @@ -69,6 +69,7 @@ export const useTags = () => { // 按标签分组并构建结果 const grouped = Object.entries(groupBy(assistantsByTags, 'tag')).map(([tag, group]) => ({ + id: tag, tag, assistants: group.map((g) => g.assistant) })) diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index baba355ad6..183f3118a8 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -1,4 +1,5 @@ import { DownOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons' +import { Draggable, Droppable, DropResult } from '@hello-pangea/dnd' import DragableList from '@renderer/components/DragableList' import Scrollbar from '@renderer/components/Scrollbar' import { useAgents } from '@renderer/hooks/useAgents' @@ -30,7 +31,7 @@ const Assistants: FC = ({ const [collapsedTags, setCollapsedTags] = useState>({}) const { addAgent } = useAgents() const { t } = useTranslation() - const { getGroupedAssistants } = useTags() + const { getGroupedAssistants, allTags, updateTagsOrder } = useTags() const { assistantsTabSortType = 'list', setAssistantsTabSortType } = useAssistantsTabSortType() const containerRef = useRef(null) @@ -59,72 +60,168 @@ const Assistants: FC = ({ }, [setAssistantsTabSortType] ) - + // 修改tag的方式得调整 + // 多条修改 同时修改assistants的tag const handleGroupReorder = useCallback( - (tag: string, newGroupList: Assistant[]) => { - let insertIndex = 0 - const newGlobal = assistants.map((a) => { - const tags = a.tags?.length ? a.tags : [t('assistants.tags.untagged')] - if (tags.includes(tag)) { - const replaced = newGroupList[insertIndex] - insertIndex += 1 - return replaced + (newGroupList: { tag: string; newGroup: Assistant[] }[], _assistants: Assistant[]) => { + const insertIndexMap = {} + + newGroupList.map((_) => { + insertIndexMap[_.tag] = 0 + }) + + const newGlobal = _assistants.map((a) => { + const tag = (a.tags?.length ? a.tags : [t('assistants.tags.untagged')])[0] + for (const group of newGroupList) { + if (group.tag === tag) { + const replaced = group.newGroup[insertIndexMap[tag]] + insertIndexMap[tag] += 1 + return replaced + } } return a }) updateAssistants(newGlobal) }, - [assistants, t, updateAssistants] + [t, updateAssistants] ) + const handleGroupDragEnd = useCallback( + (result: DropResult) => { + const { type, source, destination } = result + if (!destination) return // 没有目标视作放弃移动 或者后续可以改成删除? + if (type === 'ASSISTANT') { + const sourceTag = source.droppableId + const destTag = destination?.droppableId + if (sourceTag !== destTag) { + // 组件移动的时候要修改tag再移动 + // 移动到不同组 + const sourceGroup = getGroupedAssistants.find((g) => g.id === sourceTag) + const sourceGroupAssistants = [...sourceGroup!.assistants] + const destGroup = getGroupedAssistants.find((g) => g.id === destTag) + const destGroupAssistants = [...destGroup!.assistants] + + // 未分组的情况 分组的加上 + const sourceAssitant = { + ...sourceGroupAssistants.splice(source.index, 1)[0] + } + if (destTag === t('assistants.tags.untagged')) { + delete sourceAssitant.tags + } else { + sourceAssitant.tags = [destGroup!.tag] + } + + // 修改对应tag + const _assistants = assistants.map((_) => { + if (_.id === sourceAssitant.id) { + const newAssistant = { ..._ } + if (destTag === t('assistants.tags.untagged')) { + delete newAssistant.tags + } else { + newAssistant.tags = [destGroup!.tag] + } + return newAssistant + } + return _ + }) + + // 进行置换 + destGroupAssistants?.splice(destination.index, 0, sourceAssitant) + + return handleGroupReorder( + [ + { tag: sourceTag, newGroup: sourceGroupAssistants }, + { tag: destTag, newGroup: destGroupAssistants } + ], + _assistants + ) + } + if (sourceTag === destTag) { + // 移动到同一组 + const sourceGroup = getGroupedAssistants.find((g) => g.id === sourceTag) + const sourceAssitant = sourceGroup!.assistants.splice(source.index, 1) + sourceGroup!.assistants.splice(destination.index, 0, sourceAssitant[0]) + + return handleGroupReorder([{ tag: sourceTag, newGroup: sourceGroup!.assistants }], assistants) + } + } else if (type === 'TAG') { + const items = Array.from(allTags) + const [reorderedItem] = items.splice(source.index - 1, 1) + items.splice(destination.index - 1, 0, reorderedItem) + updateTagsOrder(items) + } + result + return + }, + [allTags, assistants, getGroupedAssistants, handleGroupReorder, t, updateTagsOrder] + ) + //尝试过使用两个DragableList 但是会有问题 + //也试过不用DragList 直接写 但是会有问题 + //发现只有这样写是符合预期效果的 if (assistantsTabSortType === 'tags') { return (
- {getGroupedAssistants.map((group) => ( - - {group.tag !== t('assistants.tags.untagged') && ( - toggleTagCollapse(group.tag)}> - - - {collapsedTags[group.tag] ? ( - - ) : ( - - )} - {group.tag} - - - - - )} - {!collapsedTags[group.tag] && ( -
- handleGroupReorder(group.tag, newList)} - style={{ paddingBottom: dragging ? '34px' : 0 }} - onDragStart={() => setDragging(true)} - onDragEnd={() => setDragging(false)}> - {(assistant) => ( - + ({ + ..._, + disabled: _.tag === t('assistants.tags.untagged') + }))} + onUpdate={() => {}} + onDragEnd={handleGroupDragEnd} + style={{ paddingBottom: 0 }}> + {(group) => ( + + {(provided) => ( + + {group.tag !== t('assistants.tags.untagged') && ( + toggleTagCollapse(group.tag)}> + + + {collapsedTags[group.tag] ? ( + + ) : ( + + )} + {group.tag} + + + + )} - -
- )} -
- ))} + {!collapsedTags[group.tag] && ( +
+ {group.assistants.map((assistant, index) => ( + + {(provided) => ( +
+ {}} + /> +
+ )} +
+ ))} +
+ )} + {provided.placeholder} + + )} + + )} +