Skip to content

Commit ffe8a49

Browse files
committed
refactor: 将MainWorkSpace单/双屏的渲染统一
- 删除了MainWorkSpace中原单/双屏的两套模板,通过v-for渲染workspacePanes - 将ChunkListPanel/SearchPanel中有关pane的替换收到了windowStore的统一入口
1 parent ea27510 commit ffe8a49

5 files changed

Lines changed: 81 additions & 100 deletions

File tree

src/components/panels/ChunkListPanel.vue

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -336,18 +336,8 @@ function handleChunkSelect(chunkId: string, event: MouseEvent) {
336336
337337
if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
338338
if (windowStore.isInSplitMode()) {
339-
const activeViewId = windowStore.currentActiveView.windowId;
340-
const splitPanes = windowStore.splitPanes;
341-
342-
// 判断最后活跃的视图是左侧还是右侧,并在对应的 pane 中打开新的 Chunk
343-
if (splitPanes[0]?.windowId === activeViewId) {
344-
windowStore.setPaneView(0, 'chunkView', chunkId);
345-
} else if (splitPanes[1]?.windowId === activeViewId) {
346-
windowStore.setPaneView(1, 'chunkView', chunkId);
347-
} else {
348-
// 兜底逻辑:如果找不到对应关系,默认在左侧打开
349-
windowStore.setPaneView(0, 'chunkView', chunkId);
350-
}
339+
const activePaneIndex = windowStore.getActivePaneIndex() ?? 0;
340+
windowStore.setPaneView(activePaneIndex, 'chunkView', chunkId);
351341
} else {
352342
// 单窗口模式,直接使用 setActiveChunk 切换视图
353343
windowStore.setActiveChunk(chunkId);

src/components/workspace/MainWorkspace.vue

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,45 @@
11
<template>
22
<div class="main-workspace">
33
<FileImporter v-if="isWorkspaceEmpty" />
4-
<template v-else-if="windowStore.splitMode === 'single'">
5-
<component
6-
:is="getViewComponent(currentActiveView.windowName)"
7-
v-if="currentActiveView"
8-
:key="currentActiveView.windowId"
9-
v-bind="getComponentProps(currentActiveView)"
10-
/>
11-
<DefaultView v-else />
12-
</template>
13-
144
<template v-else>
155
<div
166
class="split-container"
177
:class="{
188
'split-vertical': windowStore.splitDirection === 'vertical',
199
}"
2010
>
21-
<div
22-
class="split-pane"
23-
:style="getPaneStyle(0)"
24-
@pointerdown.capture="handlePaneClick(0)"
25-
>
26-
<component
27-
:is="getViewComponent(leftPane.windowName)"
28-
v-if="leftPane"
29-
:key="leftPane.windowId"
30-
v-bind="getComponentProps(leftPane)"
31-
/>
32-
</div>
33-
34-
<div
35-
v-if="rightPane"
36-
class="split-resize-handle"
37-
:class="{
38-
'resize-vertical':
39-
windowStore.splitDirection === 'vertical',
40-
}"
41-
@mousedown="startResize"
42-
></div>
43-
44-
<div
45-
class="split-pane"
46-
:style="getPaneStyle(1)"
47-
@pointerdown.capture="handlePaneClick(1)"
48-
>
49-
<component
50-
:is="getViewComponent(rightPane.windowName)"
51-
v-if="rightPane"
52-
:key="rightPane.windowId"
53-
v-bind="getComponentProps(rightPane)"
54-
/>
55-
</div>
11+
<template v-for="pane in workspacePanes" :key="pane.paneIndex">
12+
<div
13+
class="split-pane"
14+
:style="getPaneStyle(pane.paneIndex)"
15+
@pointerdown.capture="handlePaneClick(pane.paneIndex)"
16+
>
17+
<component
18+
:is="getViewComponent(pane.instance?.windowName)"
19+
v-if="pane.instance"
20+
:key="pane.instance.windowId"
21+
v-bind="getComponentProps(pane.instance)"
22+
/>
23+
<DefaultView v-else />
24+
</div>
25+
26+
<div
27+
v-if="shouldRenderResizeHandle(pane.paneIndex)"
28+
class="split-resize-handle"
29+
:class="{
30+
'resize-vertical':
31+
windowStore.splitDirection === 'vertical',
32+
}"
33+
@mousedown="startResize"
34+
></div>
35+
</template>
5636
</div>
5737
</template>
5838
</div>
5939
</template>
6040

6141
<script setup lang="ts">
62-
import { computed, ref } from 'vue';
42+
import { computed } from 'vue';
6343
import { useLogStore } from '@/stores/logStore';
6444
import { useWindowStore } from '@/stores/windowStore';
6545
import type { WindowInstance, WindowName } from '@/types/window';
@@ -71,13 +51,7 @@ import DefaultView from './DefaultView.vue';
7151
const logStore = useLogStore();
7252
const windowStore = useWindowStore();
7353
const isWorkspaceEmpty = computed(() => logStore.documents.length === 0);
74-
const currentActiveView = computed(() => windowStore.currentActiveView);
75-
76-
// 分屏数据映射
77-
const leftPane = computed(() => windowStore.splitPanes[0]);
78-
const rightPane = computed(() => windowStore.splitPanes[1]);
79-
80-
const splitSizes = ref<[number, number]>(windowStore.splitSizes);
54+
const workspacePanes = computed(() => windowStore.workspacePanes);
8155
8256
const viewComponentMap: Partial<Record<WindowName, any>> = {
8357
chunkView: ChunkView,
@@ -86,7 +60,8 @@ const viewComponentMap: Partial<Record<WindowName, any>> = {
8660
};
8761
8862
// 根据 WindowName 获取对应的 Vue 组件
89-
function getViewComponent(name: WindowName) {
63+
function getViewComponent(name?: WindowName) {
64+
if (!name) return DefaultView;
9065
return viewComponentMap[name] || DefaultView;
9166
}
9267
@@ -99,28 +74,35 @@ function getComponentProps(instance: WindowInstance) {
9974
10075
function getPaneStyle(index: 0 | 1): Record<string, string> {
10176
const isHorizontal = windowStore.splitDirection === 'horizontal';
102-
const size = splitSizes.value[index];
77+
const size =
78+
workspacePanes.value.length === 1 ? 100 : windowStore.splitSizes[index];
10379
10480
return isHorizontal
10581
? { width: `${size}%`, height: '100%' }
10682
: { width: '100%', height: `${size}%` };
10783
}
10884
10985
function handlePaneClick(paneIndex: 0 | 1) {
110-
const pane = paneIndex === 0 ? leftPane.value : rightPane.value;
111-
if (pane) {
112-
windowStore.setFocus(pane.windowId);
86+
const pane = workspacePanes.value.find(
87+
(item) => item.paneIndex === paneIndex,
88+
);
89+
if (pane?.instance) {
90+
windowStore.setFocus(pane.instance.windowId);
11391
}
11492
}
11593
94+
function shouldRenderResizeHandle(paneIndex: 0 | 1) {
95+
return paneIndex < workspacePanes.value.length - 1;
96+
}
97+
11698
function startResize(e: MouseEvent) {
11799
e.preventDefault();
118100
const isHorizontal = windowStore.splitDirection === 'horizontal';
119101
const container = (e.target as HTMLElement).parentElement;
120102
if (!container) return;
121103
122104
const startPos = isHorizontal ? e.clientX : e.clientY;
123-
const startSizes = [...splitSizes.value];
105+
const startSizes = [...windowStore.splitSizes];
124106
const containerSize = isHorizontal
125107
? container.clientWidth
126108
: container.clientHeight;
@@ -136,8 +118,6 @@ function startResize(e: MouseEvent) {
136118
Math.max(20, startSizes[0] + deltaPercent),
137119
);
138120
const newRightSize = 100 - newLeftSize;
139-
140-
splitSizes.value = [newLeftSize, newRightSize];
141121
windowStore.splitSizes = [newLeftSize, newRightSize];
142122
}
143123

src/composables/useCommandDispatcher.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,8 @@ export function useCommandDispatcher() {
336336
windowStore.requestMessageReveal(chunkId, target.messageId);
337337

338338
if (windowStore.isInSplitMode()) {
339-
const activeViewId = windowStore.currentActiveView.windowId;
340-
const splitPanes = windowStore.splitPanes;
341-
342-
if (splitPanes[0]?.windowId === activeViewId) {
343-
windowStore.setPaneView(0, 'chunkView', chunkId);
344-
} else if (splitPanes[1]?.windowId === activeViewId) {
345-
windowStore.setPaneView(1, 'chunkView', chunkId);
346-
} else {
347-
windowStore.setPaneView(0, 'chunkView', chunkId);
348-
}
339+
const activePaneIndex = windowStore.getActivePaneIndex() ?? 0;
340+
windowStore.setPaneView(activePaneIndex, 'chunkView', chunkId);
349341
return;
350342
}
351343

src/stores/windowStore.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
WindowInstance,
77
SplitMode,
88
SplitDirection,
9+
WorkspacePane,
910
} from '@/types/window';
1011
import { generateId } from '@/utils/id';
1112

@@ -168,9 +169,8 @@ function windowStore() {
168169
// 如果当前活跃窗口本身就是预览窗口,直接在当前位置切换模板
169170
if (currentView.windowName === 'exportPreview') {
170171
if (splitMode.value === 'double') {
171-
const activePos = getActivePanePosition();
172172
setPaneView(
173-
activePos === 'left' ? 0 : 1,
173+
getActivePaneIndex() ?? 0,
174174
'exportPreview',
175175
formatId,
176176
);
@@ -190,8 +190,8 @@ function windowStore() {
190190
}
191191
if (splitMode.value === 'double') {
192192
// 已在双屏:找到不活跃的那一侧并替换
193-
const activePos = getActivePanePosition();
194-
const targetPaneIndex = activePos === 'left' ? 1 : 0;
193+
const activePaneIndex = getActivePaneIndex() ?? 0;
194+
const targetPaneIndex = activePaneIndex === 0 ? 1 : 0;
195195
setPaneView(targetPaneIndex, 'exportPreview', formatId);
196196
} else {
197197
// 单屏模式:直接开启分屏预览
@@ -253,16 +253,35 @@ function windowStore() {
253253
);
254254
});
255255

256+
const workspacePanes = computed((): WorkspacePane[] => {
257+
if (splitMode.value === 'double') {
258+
return ([0, 1] as const).map((paneIndex) => {
259+
const instance = splitPanes.value[paneIndex];
260+
return {
261+
paneIndex,
262+
instance,
263+
isActive: instance?.windowId === activeFocus.value,
264+
};
265+
});
266+
}
267+
268+
const instance = currentActiveView.value;
269+
return [
270+
{
271+
paneIndex: 0,
272+
instance,
273+
isActive: instance.windowId === activeFocus.value,
274+
},
275+
];
276+
});
277+
256278
function isInSplitMode(): boolean {
257279
return splitMode.value === 'double';
258280
}
259281

260-
function getActivePanePosition(): 'left' | 'right' | null {
261-
if (splitMode.value !== 'double') return null;
262-
const activeId = activeFocus.value;
263-
if (splitPanes.value[0]?.windowId === activeId) return 'left';
264-
if (splitPanes.value[1]?.windowId === activeId) return 'right';
265-
return null;
282+
function getActivePaneIndex(): 0 | 1 | null {
283+
const activePane = workspacePanes.value.find((pane) => pane.isActive);
284+
return activePane?.paneIndex ?? null;
266285
}
267286

268287
// 打开帮助弹窗
@@ -391,10 +410,10 @@ function windowStore() {
391410
rightSidebarVisible,
392411
currentActiveWindow,
393412
currentActiveView,
413+
workspacePanes,
394414
isHelpOpen,
395415
splitMode,
396416
splitDirection,
397-
splitPanes,
398417
splitSizes,
399418
pendingMessageReveal,
400419

@@ -416,6 +435,7 @@ function windowStore() {
416435
setPaneView,
417436
closePane,
418437
isInSplitMode,
438+
getActivePaneIndex,
419439
requestMessageReveal,
420440
clearPendingMessageReveal,
421441
};

src/types/window.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ export interface WindowInstance {
2626

2727
export type SplitDirection = 'horizontal' | 'vertical';
2828
export type SplitMode = 'single' | 'double';
29-
// TODO: 未来会把这里的单/双窗口统一
30-
export interface SplitState {
31-
mode: SplitMode;
32-
direction: SplitDirection;
33-
panes: [WindowInstance, WindowInstance | null];
34-
sizes: [number, number];
29+
30+
export interface WorkspacePane {
31+
paneIndex: 0 | 1;
32+
instance: WindowInstance | null;
33+
isActive: boolean;
3534
}

0 commit comments

Comments
 (0)