feat(脑图): 脑图基础组件支持快捷键&测试计划和功能用例脑图快捷键拦截
This commit is contained in:
parent
b9128515e1
commit
cbd069ca0a
|
@ -432,7 +432,10 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
||||||
} else if (node.data?.resource?.includes(prerequisiteTag) && (!node.children || node.children.length === 0)) {
|
} else if (node.data?.resource?.includes(prerequisiteTag) && (!node.children || node.children.length === 0)) {
|
||||||
// 当前节点是前置操作,则默认添加一个文本节点
|
// 当前节点是前置操作,则默认添加一个文本节点
|
||||||
execInert('AppendChildNode');
|
execInert('AppendChildNode');
|
||||||
} else {
|
} else if (
|
||||||
|
(!node.data?.resource || node.data?.resource?.length === 0) &&
|
||||||
|
(!node.parent?.data?.resource || node.parent?.data?.resource?.length === 0)
|
||||||
|
) {
|
||||||
// 文本节点下可添加文本节点
|
// 文本节点下可添加文本节点
|
||||||
execInert('AppendChildNode');
|
execInert('AppendChildNode');
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,6 +373,12 @@
|
||||||
* @param value 插入值
|
* @param value 插入值
|
||||||
*/
|
*/
|
||||||
function insertNode(node: PlanMinderNode, type: string) {
|
function insertNode(node: PlanMinderNode, type: string) {
|
||||||
|
if (
|
||||||
|
(node.data?.level === 2 && type === 'AppendChildNode') ||
|
||||||
|
(node.data?.level === 1 && type === 'AppendSiblingNode')
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let child: PlanMinderNodeData | undefined;
|
let child: PlanMinderNodeData | undefined;
|
||||||
// 用例数子节点
|
// 用例数子节点
|
||||||
const caseCountNodeData = {
|
const caseCountNodeData = {
|
||||||
|
@ -633,6 +639,15 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => minderStore.event.eventId,
|
||||||
|
() => {
|
||||||
|
if ([MinderEventName.EXPAND, MinderEventName.COLLAPSE].includes(minderStore.event.name)) {
|
||||||
|
setCustomPriorityView(priorityTextMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function handleConfigCancel() {
|
function handleConfigCancel() {
|
||||||
clearSelectedCases();
|
clearSelectedCases();
|
||||||
extraVisible.value = false;
|
extraVisible.value = false;
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||||
|
import { getGenerateId } from '@/utils';
|
||||||
|
|
||||||
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
|
import type { MinderJsonNode } from '../props';
|
||||||
|
import { markDeleteNode, resetNodes } from '../script/tool/utils';
|
||||||
|
|
||||||
|
interface IData {
|
||||||
|
getRegisterProtocol(protocol: string): {
|
||||||
|
encode: (nodes: Array<MinderJsonNode>) => Array<MinderJsonNode>;
|
||||||
|
decode: (nodes: Array<MinderJsonNode>) => Array<MinderJsonNode>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MinderOperationProps {
|
||||||
|
insertNode?: (node: MinderJsonNode, command: string, value?: string) => void;
|
||||||
|
canShowMoreMenuNodeOperation?: boolean;
|
||||||
|
canShowPasteMenu?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useMinderOperation({
|
||||||
|
insertNode,
|
||||||
|
canShowMoreMenuNodeOperation,
|
||||||
|
canShowPasteMenu,
|
||||||
|
}: MinderOperationProps) {
|
||||||
|
const minderStore = useMinderStore();
|
||||||
|
|
||||||
|
function encode(nodes: Array<MinderJsonNode>): string {
|
||||||
|
const { editor } = window;
|
||||||
|
const { minder, MimeType } = editor;
|
||||||
|
const Data: IData = window.kityminder.data;
|
||||||
|
const kmencode = MimeType.getMimeTypeProtocol('application/km');
|
||||||
|
const _nodes = [];
|
||||||
|
for (let i = 0, l = nodes.length; i < l; i++) {
|
||||||
|
// @ts-ignore
|
||||||
|
_nodes.push(minder.exportNode(nodes[i]));
|
||||||
|
}
|
||||||
|
return kmencode(Data.getRegisterProtocol('json').encode(_nodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行复制
|
||||||
|
*/
|
||||||
|
const minderCopy = (e?: ClipboardEvent) => {
|
||||||
|
if (!canShowMoreMenuNodeOperation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { editor } = window;
|
||||||
|
const { minder, fsm } = editor;
|
||||||
|
const state = fsm.state();
|
||||||
|
switch (state) {
|
||||||
|
case 'input': {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'normal': {
|
||||||
|
const selectedNodes = minder.getSelectedNodes();
|
||||||
|
minderStore.dispatchEvent(MinderEventName.COPY_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
minder.execCommand('Copy');
|
||||||
|
e?.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行剪切
|
||||||
|
*/
|
||||||
|
const minderCut = (e?: ClipboardEvent) => {
|
||||||
|
if (!canShowMoreMenuNodeOperation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { editor } = window;
|
||||||
|
const { minder, fsm } = editor;
|
||||||
|
if (minder.getStatus() !== 'normal') {
|
||||||
|
e?.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = fsm.state();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 'input': {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'normal': {
|
||||||
|
markDeleteNode(minder);
|
||||||
|
const selectedNodes = minder.getSelectedNodes();
|
||||||
|
if (selectedNodes.length) {
|
||||||
|
e?.clipboardData?.setData('text/plain', encode(selectedNodes));
|
||||||
|
minder.execCommand('Cut');
|
||||||
|
}
|
||||||
|
e?.preventDefault();
|
||||||
|
minderStore.dispatchEvent(MinderEventName.CUT_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行粘贴
|
||||||
|
*/
|
||||||
|
const minderPaste = (e?: ClipboardEvent) => {
|
||||||
|
if (!canShowMoreMenuNodeOperation || !canShowPasteMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { editor } = window;
|
||||||
|
const { minder, fsm, MimeType } = editor;
|
||||||
|
const Data: IData = window.kityminder.data;
|
||||||
|
const { decode } = Data.getRegisterProtocol('json');
|
||||||
|
if (minder.getStatus() !== 'normal') {
|
||||||
|
e?.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = fsm.state();
|
||||||
|
const textData = e?.clipboardData?.getData('text/plain');
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 'input': {
|
||||||
|
// input状态下如果格式为application/km则不进行paste操作
|
||||||
|
if (!MimeType.isPureText(textData)) {
|
||||||
|
e?.preventDefault();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'normal': {
|
||||||
|
/*
|
||||||
|
* 针对normal状态下通过对选中节点粘贴导入子节点文本进行单独处理
|
||||||
|
*/
|
||||||
|
const sNodes = minder.getSelectedNodes();
|
||||||
|
const selectedNodes: MinderJsonNode[] = [];
|
||||||
|
minderStore.dispatchEvent(MinderEventName.PASTE_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
if (MimeType.whichMimeType(textData) === 'application/km') {
|
||||||
|
const nodes = decode(MimeType.getPureText(textData));
|
||||||
|
sNodes.forEach((node: MinderJsonNode) => {
|
||||||
|
const noFakeNodeTree = resetNodes(nodes); // 每次粘贴复制的节点集合到新的节点之前,都需要重置节点集合的信息
|
||||||
|
let _node;
|
||||||
|
// 由于粘贴逻辑中为了排除子节点重新排序导致逆序,因此复制的时候倒过来
|
||||||
|
for (let i = noFakeNodeTree.length - 1; i >= 0; i--) {
|
||||||
|
_node = minder.createNode(null, node);
|
||||||
|
minder.importNode(_node, noFakeNodeTree[i]);
|
||||||
|
selectedNodes.push(_node);
|
||||||
|
node.appendChild(_node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.minder.execCommand('Expand'); // 展开当前所有选中的节点,避免无子节点的节点在粘贴后还是折叠状态
|
||||||
|
minder.select(selectedNodes, true);
|
||||||
|
minder.refresh();
|
||||||
|
} else if (e?.clipboardData && e.clipboardData.items[0].type.indexOf('image') > -1) {
|
||||||
|
const imageFile = e?.clipboardData.items[0].getAsFile();
|
||||||
|
const serverService = window.angular.element(document.body).injector().get('server');
|
||||||
|
|
||||||
|
return serverService.uploadImage(imageFile).then((json: Record<string, any>) => {
|
||||||
|
const resp = json.data;
|
||||||
|
if (resp.errno === 0) {
|
||||||
|
minder.execCommand('image', resp.data.url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sNodes.forEach((node: MinderJsonNode) => {
|
||||||
|
minder.Text2Children(node, textData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
e?.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行插入
|
||||||
|
* @param command 插入命令
|
||||||
|
* @param value 携带的参数
|
||||||
|
*/
|
||||||
|
const execInsertCommand = (command: string, value?: string) => {
|
||||||
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
if (insertNode) {
|
||||||
|
insertNode(node, command, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (window.minder.queryCommandState(command) !== -1) {
|
||||||
|
window.minder.execCommand(command);
|
||||||
|
nextTick(() => {
|
||||||
|
const newNode: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
if (!newNode.data) {
|
||||||
|
newNode.data = {
|
||||||
|
id: getGenerateId(),
|
||||||
|
text: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
newNode.data.isNew = true; // 新建的节点标记为新建
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入子节点
|
||||||
|
* @param selectedNodes 当前选中的节点集合
|
||||||
|
* @param value 携带的参数
|
||||||
|
*/
|
||||||
|
const appendChildNode = (selectedNodes: MinderJsonNode[], value?: string) => {
|
||||||
|
execInsertCommand('AppendChildNode', value);
|
||||||
|
minderStore.dispatchEvent(MinderEventName.INSERT_CHILD, value, undefined, undefined, selectedNodes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入兄弟节点
|
||||||
|
* @param selectedNodes 当前选中的节点集合
|
||||||
|
* @param value 携带的参数
|
||||||
|
*/
|
||||||
|
const appendSiblingNode = (selectedNodes: MinderJsonNode[], value?: string) => {
|
||||||
|
execInsertCommand('AppendSiblingNode', value);
|
||||||
|
minderStore.dispatchEvent(MinderEventName.INSERT_SIBLING, value, undefined, undefined, selectedNodes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除节点
|
||||||
|
* @param selectedNodes 当前选中的节点集合
|
||||||
|
*/
|
||||||
|
const minderDelete = (selectedNodes: MinderJsonNode[]) => {
|
||||||
|
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
window.minder.execCommand('RemoveNode');
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
minderCopy,
|
||||||
|
minderCut,
|
||||||
|
minderPaste,
|
||||||
|
appendChildNode,
|
||||||
|
appendSiblingNode,
|
||||||
|
minderDelete,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1 +1,70 @@
|
||||||
export default function useShortCut() {}
|
import useMinderOperation, { type MinderOperationProps } from './useMinderOperation';
|
||||||
|
|
||||||
|
type ShortcutKey = 'expand' | 'enter' | 'appendSiblingNode' | 'appendChildNode' | 'undo' | 'redo' | 'delete';
|
||||||
|
// 快捷键事件映射,combinationShortcuts中定义了组合键事件,key为组合键,value为事件名称;
|
||||||
|
type Shortcuts = {
|
||||||
|
[key in ShortcutKey]?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useShortCut(shortcuts: Shortcuts, options: MinderOperationProps) {
|
||||||
|
const { minderCopy, minderCut, minderPaste } = useMinderOperation(options);
|
||||||
|
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
const key = event.key.toLowerCase();
|
||||||
|
const isCtrlOrCmd = event.ctrlKey || event.metaKey;
|
||||||
|
|
||||||
|
// 定义组合键事件
|
||||||
|
const combinationShortcuts: { [key: string]: ShortcutKey } = {
|
||||||
|
z: 'undo', // 撤销
|
||||||
|
y: 'redo', // 重做
|
||||||
|
enter: 'enter', // 进入节点
|
||||||
|
};
|
||||||
|
// 定义单键事件
|
||||||
|
const singleShortcuts: { [key: string]: ShortcutKey } = {
|
||||||
|
'/': 'expand', // 展开/折叠
|
||||||
|
'enter': 'appendSiblingNode',
|
||||||
|
'tab': 'appendChildNode',
|
||||||
|
'backspace': 'delete',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isCtrlOrCmd && combinationShortcuts[key]) {
|
||||||
|
// 执行组合键事件
|
||||||
|
event.preventDefault();
|
||||||
|
const action = combinationShortcuts[key];
|
||||||
|
if (shortcuts[action]) {
|
||||||
|
shortcuts[action]!();
|
||||||
|
}
|
||||||
|
} else if (singleShortcuts[key]) {
|
||||||
|
// 执行单键事件
|
||||||
|
event.preventDefault();
|
||||||
|
const action = singleShortcuts[key];
|
||||||
|
if (shortcuts[action]) {
|
||||||
|
shortcuts[action]!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const minderContainer = document.querySelector('.ms-minder-container');
|
||||||
|
if (minderContainer) {
|
||||||
|
minderContainer.addEventListener('keydown', (e) => handleKeyDown(e as KeyboardEvent));
|
||||||
|
minderContainer.addEventListener('copy', (e) => minderCopy(e as ClipboardEvent));
|
||||||
|
minderContainer.addEventListener('cut', (e) => minderCut(e as ClipboardEvent));
|
||||||
|
minderContainer.addEventListener('paste', (e) => minderPaste(e as ClipboardEvent));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function unbindShortcuts() {
|
||||||
|
const minderContainer = document.querySelector('.ms-minder-container');
|
||||||
|
if (minderContainer) {
|
||||||
|
minderContainer.removeEventListener('keydown', (e) => handleKeyDown(e as KeyboardEvent));
|
||||||
|
minderContainer.removeEventListener('copy', (e) => minderCopy(e as ClipboardEvent));
|
||||||
|
minderContainer.removeEventListener('cut', (e) => minderCut(e as ClipboardEvent));
|
||||||
|
minderContainer.removeEventListener('paste', (e) => minderPaste(e as ClipboardEvent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
unbindShortcuts,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
editMenuProps,
|
editMenuProps,
|
||||||
floatMenuProps,
|
floatMenuProps,
|
||||||
headerProps,
|
headerProps,
|
||||||
insertProps,
|
|
||||||
mainEditorProps,
|
mainEditorProps,
|
||||||
MinderJson,
|
MinderJson,
|
||||||
MinderJsonNode,
|
MinderJsonNode,
|
||||||
|
@ -66,7 +65,6 @@
|
||||||
...headerProps,
|
...headerProps,
|
||||||
...floatMenuProps,
|
...floatMenuProps,
|
||||||
...editMenuProps,
|
...editMenuProps,
|
||||||
...insertProps,
|
|
||||||
...mainEditorProps,
|
...mainEditorProps,
|
||||||
...tagProps,
|
...tagProps,
|
||||||
...priorityProps,
|
...priorityProps,
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<MsIcon type="icon-icon_aiming" class="text-[var(--color-text-4)]" />
|
<MsIcon type="icon-icon_aiming" class="text-[var(--color-text-4)]" />
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<!-- <a-trigger
|
<a-trigger
|
||||||
:popup-translate="[5, -105]"
|
:popup-translate="[5, -105]"
|
||||||
position="right"
|
position="right"
|
||||||
class="ms-minder-shortcut-trigger"
|
class="ms-minder-shortcut-trigger"
|
||||||
|
@ -87,16 +87,16 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
||||||
Shift+Tab
|
Tab
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.main.history.undo') }}</div>
|
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
<icon-command :size="14" />
|
<icon-command :size="14" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">Z</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">X</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
@ -111,12 +111,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.main.history.redo') }}</div>
|
<div>{{ t('minder.main.history.undo') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
<icon-command :size="14" />
|
<icon-command :size="14" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">Y</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">Z</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
@ -125,9 +125,18 @@
|
||||||
<MsIcon type="icon-icon_carriage_return1" />
|
<MsIcon type="icon-icon_carriage_return1" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('minder.main.history.redo') }}</div>
|
||||||
|
<div class="flex items-center gap-[4px]">
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
|
<icon-command :size="14" />
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon">Y</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-trigger> -->
|
</a-trigger>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isNavOpen" ref="navPreviewer" class="ms-minder-navigator-previewer" />
|
<div v-show="isNavOpen" ref="navPreviewer" class="ms-minder-navigator-previewer" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -325,7 +334,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// const shortcutTriggerVisible = ref(false);
|
const shortcutTriggerVisible = ref(false);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-button
|
|
||||||
class="arco-btn-outline--secondary mb-[4px]"
|
|
||||||
:disabled="removeNodeDisabled"
|
|
||||||
type="outline"
|
|
||||||
size="small"
|
|
||||||
@click="del"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-minus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
{{ t('minder.commons.delete') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="edit_del" setup>
|
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
|
||||||
import { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
|
||||||
|
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
|
||||||
|
|
||||||
import { delProps, MinderJsonNode } from '../../props';
|
|
||||||
import { isDeleteDisableNode } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const minderStore = useMinderStore();
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const props = defineProps(delProps);
|
|
||||||
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
const removeNodeDisabled = ref(true);
|
|
||||||
|
|
||||||
function checkDisabled() {
|
|
||||||
try {
|
|
||||||
if (!minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const node = minder.getSelectedNode();
|
|
||||||
removeNodeDisabled.value = !node || !!isDeleteDisableNode(minder) || node.parent === null;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
minder.on('selectionchange', () => {
|
|
||||||
checkDisabled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function del() {
|
|
||||||
if (removeNodeDisabled.value || !minder.queryCommandState || !minder.execCommand) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const nodes: MinderJsonNode[] = minder.getSelectedNodes();
|
|
||||||
if (nodes.length > 0) {
|
|
||||||
if (props.delConfirm) {
|
|
||||||
props.delConfirm(nodes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const box = nodes[0].getRenderBox();
|
|
||||||
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, box, nodes[0].rc.node, nodes);
|
|
||||||
}
|
|
||||||
minder.forceRemoveNode();
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,117 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="menu-container">
|
|
||||||
<div class="menu-group">
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-button class="arco-btn-outline--secondary mb-[4px]" type="outline" size="small" @click="expand">
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
{{ t('minder.menu.expand.expand') }}
|
|
||||||
</div>
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-button class="arco-btn-outline--secondary mb-[4px]" type="outline" size="small" @click="folding">
|
|
||||||
<template #icon>
|
|
||||||
<icon-minus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
{{ t('minder.menu.expand.folding') }}
|
|
||||||
</div>
|
|
||||||
<move-box :move-enable="props.moveEnable" :move-confirm="props.moveConfirm" />
|
|
||||||
<insert-box :insert-node="props.insertNode" />
|
|
||||||
<edit-del :del-confirm="props.delConfirm" />
|
|
||||||
</div>
|
|
||||||
<tag-box
|
|
||||||
v-if="props.tagEnable"
|
|
||||||
:tags="props.tags"
|
|
||||||
:tag-disable-check="props.tagDisableCheck"
|
|
||||||
:tag-edit-check="props.tagEditCheck"
|
|
||||||
:distinct-tags="props.distinctTags"
|
|
||||||
:replaceable-tags="props.replaceableTags"
|
|
||||||
:single-tag="props.singleTag"
|
|
||||||
:after-tag-edit="props.afterTagEdit"
|
|
||||||
/>
|
|
||||||
<div class="menu-group">
|
|
||||||
<sequence-box
|
|
||||||
v-if="props.sequenceEnable"
|
|
||||||
:priority-prefix="props.priorityPrefix"
|
|
||||||
:priority-count="props.priorityCount"
|
|
||||||
:priority-disable-check="props.priorityDisableCheck"
|
|
||||||
:priority-start-with-zero="props.priorityStartWithZero"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="menu-group">
|
|
||||||
<mold v-if="props.moldEnable" :default-mold="props.defaultMold" @mold-change="handleMoldChange" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="editMenu" setup>
|
|
||||||
import mold from '../view/mold.vue';
|
|
||||||
import editDel from './editDel.vue';
|
|
||||||
import insertBox from './insertBox.vue';
|
|
||||||
import moveBox from './moveBox.vue';
|
|
||||||
import sequenceBox from './sequenceBox.vue';
|
|
||||||
import TagBox from './tagBox.vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import { delProps, editMenuProps, insertProps, moleProps, priorityProps, tagProps, viewMenuProps } from '../../props';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
...editMenuProps,
|
|
||||||
...insertProps,
|
|
||||||
...priorityProps,
|
|
||||||
...tagProps,
|
|
||||||
...delProps,
|
|
||||||
...viewMenuProps,
|
|
||||||
...moleProps,
|
|
||||||
});
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'moldChange', data: number): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const hasSelectedNode = ref(false);
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
if (minder.on) {
|
|
||||||
minder.on('selectionchange', () => {
|
|
||||||
hasSelectedNode.value = Object.keys(minder).length > 0 && minder.getSelectedNode();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 展开
|
|
||||||
*/
|
|
||||||
function expand() {
|
|
||||||
const state = window.minder?.queryCommandState('Expand');
|
|
||||||
if (state === 0) {
|
|
||||||
// 有选中的节点
|
|
||||||
window.minder?.execCommand('Expand');
|
|
||||||
} else {
|
|
||||||
window.minder?.execCommand('ExpandToLevel', 999);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 收起
|
|
||||||
*/
|
|
||||||
function folding() {
|
|
||||||
if (hasSelectedNode.value) {
|
|
||||||
window.minder?.execCommand('Collapse');
|
|
||||||
} else {
|
|
||||||
window.minder?.execCommand('ExpandToLevel', 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMoldChange(data: number) {
|
|
||||||
emit('moldChange', data);
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,22 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="expand-group">
|
|
||||||
<a-button class="tab-icons expand" type="text" @click="expand" />
|
|
||||||
{{ t('minder.menu.expand.expand') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="expand" setup>
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
function expand() {
|
|
||||||
window.minder?.execCommand('Expand', 9999);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.dropdown-link {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,91 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-dropdown @select="handleCommand">
|
|
||||||
<a-button
|
|
||||||
class="arco-btn-outline--secondary mb-[4px]"
|
|
||||||
:disabled="appendChildNodeDisabled && appendParentNodeDisabled && appendSiblingNodeDisabled"
|
|
||||||
type="outline"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<template #content>
|
|
||||||
<a-doption :disabled="appendChildNodeDisabled" value="down">{{ t('minder.menu.insert.down') }}</a-doption>
|
|
||||||
<a-doption :disabled="appendParentNodeDisabled" value="up">{{ t('minder.menu.insert.up') }}</a-doption>
|
|
||||||
<a-doption :disabled="appendSiblingNodeDisabled" value="same">{{ t('minder.menu.insert.same') }}</a-doption>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
{{ t('minder.menu.insert.insert') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="insertBox" setup>
|
|
||||||
import { nextTick, onMounted, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import { insertProps, MinderJsonNode } from '../../props';
|
|
||||||
import { isDisableNode } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
...insertProps,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const minder = ref<any>({});
|
|
||||||
const appendChildNodeDisabled = ref(false);
|
|
||||||
const appendParentNodeDisabled = ref(false);
|
|
||||||
const appendSiblingNodeDisabled = ref(false);
|
|
||||||
|
|
||||||
function checkDisabled() {
|
|
||||||
try {
|
|
||||||
if (Object.keys(minder.value).length === 0) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
appendChildNodeDisabled.value = minder.value.queryCommandState('AppendChildNode') === -1;
|
|
||||||
const node = minder.value.getSelectedNode();
|
|
||||||
appendSiblingNodeDisabled.value = !node || !!isDisableNode(minder.value) || node.parent === null;
|
|
||||||
appendParentNodeDisabled.value = !node || node.parent === null;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder.value = window.minder;
|
|
||||||
minder.value.on('selectionchange', () => {
|
|
||||||
checkDisabled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function execCommand(command: string) {
|
|
||||||
const node: MinderJsonNode = minder.value.getSelectedNode();
|
|
||||||
if (props.insertNode) {
|
|
||||||
props.insertNode(node, command);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (minder.value.queryCommandState(command) !== -1) {
|
|
||||||
minder.value.execCommand(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCommand(val: string | number | Record<string, any> | undefined) {
|
|
||||||
switch (val) {
|
|
||||||
case 'down':
|
|
||||||
execCommand('AppendChildNode');
|
|
||||||
break;
|
|
||||||
case 'up':
|
|
||||||
execCommand('AppendParentNode');
|
|
||||||
break;
|
|
||||||
case 'same':
|
|
||||||
execCommand('AppendSiblingNode');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,81 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-button
|
|
||||||
class="arco-btn-outline--secondary mb-[4px]"
|
|
||||||
:disabled="arrangeUpDisabled"
|
|
||||||
type="outline"
|
|
||||||
size="small"
|
|
||||||
@click="execCommand('ArrangeUp')"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
{{ t('minder.menu.move.up') }}
|
|
||||||
</div>
|
|
||||||
<div class="menu-item">
|
|
||||||
<a-button
|
|
||||||
class="arco-btn-outline--secondary mb-[4px]"
|
|
||||||
:disabled="arrangeDownDisabled"
|
|
||||||
type="outline"
|
|
||||||
size="small"
|
|
||||||
@click="execCommand('ArrangeDown')"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
{{ t('minder.menu.move.down') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="moveBox" setup>
|
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import { isDisableNode } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
moveEnable: boolean;
|
|
||||||
moveConfirm: any;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
const arrangeUpDisabled = ref(true);
|
|
||||||
const arrangeDownDisabled = ref(true);
|
|
||||||
|
|
||||||
function checkDisabled() {
|
|
||||||
try {
|
|
||||||
if (Object.keys(minder).length === 0) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const node = minder.getSelectedNode();
|
|
||||||
if (!props.moveEnable || !node || node.parent === null || isDisableNode(minder)) {
|
|
||||||
arrangeUpDisabled.value = true;
|
|
||||||
arrangeDownDisabled.value = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (window.minder.queryCommandState) {
|
|
||||||
arrangeUpDisabled.value = window.minder.queryCommandState('ArrangeUp') === -1;
|
|
||||||
arrangeDownDisabled.value = window.minder.queryCommandState('ArrangeDown') === -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
minder.on('selectionchange', () => {
|
|
||||||
checkDisabled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function execCommand(command: string) {
|
|
||||||
if (window.minder.queryCommandState(command) !== -1) window.minder.execCommand(command);
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,97 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="progress-group">
|
|
||||||
<ul>
|
|
||||||
<ul :disabled="commandDisabled">
|
|
||||||
<li
|
|
||||||
v-for="(item, index) in items"
|
|
||||||
:key="item.text"
|
|
||||||
class="menu-btn"
|
|
||||||
:class="classArray(index)"
|
|
||||||
:title="title(index)"
|
|
||||||
@click="execCommand(index)"
|
|
||||||
/>
|
|
||||||
</ul>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="progressBox" setup>
|
|
||||||
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import { isDisableNode } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
const commandValue = ref('');
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{ text: '0' },
|
|
||||||
{ text: '1' },
|
|
||||||
{ text: '2' },
|
|
||||||
{ text: '3' },
|
|
||||||
{ text: '4' },
|
|
||||||
{ text: '5' },
|
|
||||||
{ text: '6' },
|
|
||||||
{ text: '7' },
|
|
||||||
{ text: '8' },
|
|
||||||
{ text: '9' },
|
|
||||||
];
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const commandDisabled = computed(() => {
|
|
||||||
if (Object.keys(minder).length === 0 || !minder.on) return true;
|
|
||||||
minder.on('interactchange', () => {
|
|
||||||
commandValue.value = minder.queryCommandValue && minder.queryCommandValue('progress');
|
|
||||||
});
|
|
||||||
if (isDisableNode(minder)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return minder.queryCommandState && minder.queryCommandState('progress') === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
function execCommand(index: number) {
|
|
||||||
if (!commandDisabled.value && minder.execCommand) {
|
|
||||||
minder.execCommand('progress', index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function classArray(index: number) {
|
|
||||||
const isActive = minder.queryCommandValue && minder.queryCommandValue('progress') === index;
|
|
||||||
const sequence = `progress-${index}`;
|
|
||||||
|
|
||||||
// 用数组返回多个class
|
|
||||||
const arr = [
|
|
||||||
{
|
|
||||||
active: isActive,
|
|
||||||
},
|
|
||||||
sequence,
|
|
||||||
];
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
function title(index: number) {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
return t('minder.menu.progress.remove_progress');
|
|
||||||
case 1:
|
|
||||||
return t('minder.menu.progress.prepare');
|
|
||||||
case 9:
|
|
||||||
return t('minder.menu.progress.complete_all');
|
|
||||||
default:
|
|
||||||
return `${t('minder.menu.progress.complete') + (index - 1)}/8`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.progress-group li {
|
|
||||||
background-image: url('@/assets/images/minder/iconprogress.png');
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,123 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="selection-group">
|
|
||||||
<a-button type="text" class="tab-icons selection" @click="selectAll" />
|
|
||||||
<a-dropdown :popup-max-height="false" @select="handleCommand">
|
|
||||||
<span class="dropdown-link">
|
|
||||||
{{ t('minder.menu.selection.all') }}
|
|
||||||
<icon-caret-down />
|
|
||||||
</span>
|
|
||||||
<template #content>
|
|
||||||
<a-doption value="1">{{ t('minder.menu.selection.invert') }}</a-doption>
|
|
||||||
<a-doption value="2">{{ t('minder.menu.selection.sibling') }}</a-doption>
|
|
||||||
<a-doption value="3">{{ t('minder.menu.selection.same') }}</a-doption>
|
|
||||||
<a-doption value="4">{{ t('minder.menu.selection.path') }}</a-doption>
|
|
||||||
<a-doption value="5">{{ t('minder.menu.selection.subtree') }}</a-doption>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="selection" setup>
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
function selectAll() {
|
|
||||||
const selection: any[] = [];
|
|
||||||
window.minder.getRoot().traverse((node: any) => {
|
|
||||||
selection.push(node);
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectRevert() {
|
|
||||||
const selected = window.minder.getSelectedNodes();
|
|
||||||
const selection: any[] = [];
|
|
||||||
window.minder.getRoot().traverse((node: any) => {
|
|
||||||
if (selected.indexOf(node) === -1) {
|
|
||||||
selection.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectSiblings() {
|
|
||||||
const selected = window.minder.getSelectedNodes();
|
|
||||||
const selection: any[] = [];
|
|
||||||
selected.forEach((node: any) => {
|
|
||||||
if (!node.parent) return;
|
|
||||||
node.parent.children.forEach((sibling: string) => {
|
|
||||||
if (selection.indexOf(sibling) === -1) selection.push(sibling);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectLevel() {
|
|
||||||
const selectedLevel = window.minder.getSelectedNodes().map((node: any) => node.getLevel());
|
|
||||||
const selection: any[] = [];
|
|
||||||
window.minder.getRoot().traverse((node: any) => {
|
|
||||||
if (selectedLevel.indexOf(node.getLevel()) !== -1) {
|
|
||||||
selection.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectPath() {
|
|
||||||
const selected = window.minder.getSelectedNodes();
|
|
||||||
const selection: any[] = [];
|
|
||||||
selected.forEach((node: any) => {
|
|
||||||
let tempNode = node;
|
|
||||||
while (tempNode && selection.indexOf(tempNode) === -1) {
|
|
||||||
selection.push(tempNode);
|
|
||||||
tempNode = node.parent;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectTree() {
|
|
||||||
const selected = window.minder.getSelectedNodes();
|
|
||||||
const selection: any[] = [];
|
|
||||||
selected.forEach((parent: any) => {
|
|
||||||
parent.traverse((node: any) => {
|
|
||||||
if (selection.indexOf(node) === -1) selection.push(node);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
window.minder.select(selection, true);
|
|
||||||
window.minder.fire('receiverfocus');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCommand(value: string | number | Record<string, any> | undefined) {
|
|
||||||
switch (value) {
|
|
||||||
case 1:
|
|
||||||
selectRevert();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
selectSiblings();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
selectLevel();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
selectPath();
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
selectTree();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.dropdown-link {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,157 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<a-button
|
|
||||||
:disabled="commandDisabled"
|
|
||||||
class="delete-btn !mx-[4px] !my-0 !h-[23px] !w-[23px] !p-[2px]"
|
|
||||||
shape="circle"
|
|
||||||
@click="execCommand()"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-delete />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<template v-for="(item, pIndex) in priorityCount + 1">
|
|
||||||
<a-button
|
|
||||||
v-if="pIndex != 0"
|
|
||||||
:key="item"
|
|
||||||
:disabled="commandDisabled"
|
|
||||||
class="priority-btn mr-[4px] h-[22px] w-[22px] rounded-[8px] pr-[5px] text-[12px] leading-[16px]"
|
|
||||||
:class="'priority-btn_' + pIndex"
|
|
||||||
size="small"
|
|
||||||
@click="execCommand(pIndex)"
|
|
||||||
>
|
|
||||||
{{ priorityPrefix }}{{ priorityStartWithZero ? pIndex - 1 : pIndex }}
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="sequenceBox" setup>
|
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import { priorityProps } from '../../props';
|
|
||||||
import { isDisableNode, setPriorityView } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const props = defineProps(priorityProps);
|
|
||||||
|
|
||||||
const commandValue = ref('');
|
|
||||||
const commandDisabled = ref(true);
|
|
||||||
const minder = reactive<any>({});
|
|
||||||
|
|
||||||
const isDisable = (): boolean => {
|
|
||||||
if (Object.keys(minder).length === 0) return true;
|
|
||||||
nextTick(() => {
|
|
||||||
setPriorityView(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
});
|
|
||||||
if (minder.on) {
|
|
||||||
minder.on('interactchange', () => {
|
|
||||||
commandValue.value = minder.queryCommandValue && minder.queryCommandValue('priority');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const node = minder.getSelectedNode();
|
|
||||||
if (isDisableNode(minder) || !node || node.parent === null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (props.priorityDisableCheck) {
|
|
||||||
return props.priorityDisableCheck(node);
|
|
||||||
}
|
|
||||||
return !!minder.queryCommandState && minder.queryCommandState('priority') === -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// onMounted(() => {
|
|
||||||
// nextTick(() => {
|
|
||||||
// minder = window.minder;
|
|
||||||
// const freshFuc = setPriorityView;
|
|
||||||
// if (minder.on) {
|
|
||||||
// minder.on('contentchange', () => {
|
|
||||||
// // 异步执行,否则执行完,还会被重置
|
|
||||||
// setTimeout(() => {
|
|
||||||
// freshFuc(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
// }, 0);
|
|
||||||
// });
|
|
||||||
// minder.on('selectionchange', () => {
|
|
||||||
// commandDisabled.value = isDisable();
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
function execCommand(index?: number) {
|
|
||||||
if (index && minder.execCommand) {
|
|
||||||
if (!commandDisabled.value) {
|
|
||||||
minder.execCommand('priority', index);
|
|
||||||
}
|
|
||||||
setPriorityView(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
} else if (minder.execCommand && !commandDisabled.value) {
|
|
||||||
minder.execCommand('priority');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.delete-btn {
|
|
||||||
border-color: #909399;
|
|
||||||
background-color: #909399;
|
|
||||||
i {
|
|
||||||
width: 1em !important;
|
|
||||||
height: 1em !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.priority-btn {
|
|
||||||
@apply border-none p-0 italic text-white;
|
|
||||||
}
|
|
||||||
.priority-btn_1 {
|
|
||||||
border-bottom: 3px solid #840023;
|
|
||||||
background-color: #ff1200;
|
|
||||||
}
|
|
||||||
.priority-btn_1:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #840023;
|
|
||||||
color: white;
|
|
||||||
background-color: #ff1200;
|
|
||||||
}
|
|
||||||
.priority-btn_2 {
|
|
||||||
border-bottom: 3px solid #01467f;
|
|
||||||
background-color: #0074ff;
|
|
||||||
}
|
|
||||||
.priority-btn_2:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #01467f;
|
|
||||||
color: white;
|
|
||||||
background-color: #0074ff;
|
|
||||||
}
|
|
||||||
.priority-btn_3 {
|
|
||||||
border-bottom: 3px solid #006300;
|
|
||||||
background-color: #00af00;
|
|
||||||
}
|
|
||||||
.priority-btn_3:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #006300;
|
|
||||||
color: white;
|
|
||||||
background-color: #00af00;
|
|
||||||
}
|
|
||||||
.priority-btn_4 {
|
|
||||||
border-bottom: 3px solid #b25000;
|
|
||||||
background-color: #ff962e;
|
|
||||||
}
|
|
||||||
.priority-btn_4:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #b25000;
|
|
||||||
color: white;
|
|
||||||
background-color: #ff962e;
|
|
||||||
}
|
|
||||||
.priority-btn_5 {
|
|
||||||
border-bottom: 3px solid #4720c4;
|
|
||||||
background-color: #a464ff;
|
|
||||||
}
|
|
||||||
.priority-btn_5:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #4720c4;
|
|
||||||
color: white;
|
|
||||||
background-color: #a464ff;
|
|
||||||
}
|
|
||||||
.priority-btn_6 {
|
|
||||||
border-bottom: 3px solid #515151;
|
|
||||||
background-color: #a3a3a3;
|
|
||||||
}
|
|
||||||
.priority-btn_6:hover:not(:disabled) {
|
|
||||||
border-bottom: 3px solid #515151;
|
|
||||||
color: white;
|
|
||||||
background-color: #a3a3a3;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,130 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-if="tagList.length > 0" class="menu-group flex items-center">
|
|
||||||
<a-tag
|
|
||||||
v-for="item in tagList"
|
|
||||||
:key="item"
|
|
||||||
:color="getResourceColor(item)"
|
|
||||||
:class="commandDisabled ? 'disabledTag' : ''"
|
|
||||||
@click="editResource(item)"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</a-tag>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="TagBox" setup>
|
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
|
||||||
|
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
|
||||||
|
|
||||||
import { MinderJsonNode, tagProps } from '../../props';
|
|
||||||
import { isDisableNode, isTagEnable } from '../../script/tool/utils';
|
|
||||||
|
|
||||||
const props = defineProps(tagProps);
|
|
||||||
const minderStore = useMinderStore();
|
|
||||||
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
const commandDisabled = ref(true);
|
|
||||||
|
|
||||||
const isDisable = (): boolean => {
|
|
||||||
if (Object.keys(minder).length === 0 || !minder.on) return true;
|
|
||||||
if (isDisableNode(minder) && !isTagEnable(minder)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (props.tagDisableCheck) {
|
|
||||||
return props.tagDisableCheck();
|
|
||||||
}
|
|
||||||
return !!minder.queryCommandState && minder.queryCommandState('resource') === -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tagList = ref(props.tags);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
minder.on('selectionchange', () => {
|
|
||||||
commandDisabled.value = isDisable();
|
|
||||||
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
|
||||||
if (commandDisabled.value) {
|
|
||||||
tagList.value = [];
|
|
||||||
} else if (props.replaceableTags) {
|
|
||||||
tagList.value = props.replaceableTags(nodes);
|
|
||||||
} else {
|
|
||||||
tagList.value = [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function getResourceColor(resource: string) {
|
|
||||||
if (minder.getResourceColor) {
|
|
||||||
return minder.getResourceColor(resource).toHEX();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function editResource(resourceName: string) {
|
|
||||||
if (commandDisabled.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (props.tagEditCheck) {
|
|
||||||
const nodes: MinderJsonNode[] = minder.getSelectedNodes();
|
|
||||||
if (!props.tagEditCheck(nodes, resourceName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!resourceName || !/\S/.test(resourceName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const origin = window.minder.queryCommandValue('resource');
|
|
||||||
if (props.singleTag) {
|
|
||||||
origin.splice(0, origin.length, resourceName);
|
|
||||||
} else {
|
|
||||||
const index = origin.indexOf(resourceName);
|
|
||||||
// 先删除排他的标签
|
|
||||||
if (props.distinctTags.indexOf(resourceName) > -1) {
|
|
||||||
for (let i = 0; i < origin.length; i++) {
|
|
||||||
if (props.distinctTags.indexOf(origin[i]) > -1) {
|
|
||||||
origin.splice(i, 1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index !== -1) {
|
|
||||||
origin.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
origin.push(resourceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.minder.execCommand('resource', origin);
|
|
||||||
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
|
||||||
minderStore.dispatchEvent(MinderEventName.SET_TAG, undefined, undefined, undefined, nodes);
|
|
||||||
if (props.replaceableTags) {
|
|
||||||
tagList.value = props.replaceableTags(nodes);
|
|
||||||
}
|
|
||||||
if (props.afterTagEdit) {
|
|
||||||
props.afterTagEdit(nodes, resourceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.arco-tag {
|
|
||||||
@apply border-none text-black;
|
|
||||||
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
.arco-tag:hover {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
|
||||||
.arco-tag:first-child {
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
.disabledTag {
|
|
||||||
@apply !cursor-not-allowed;
|
|
||||||
|
|
||||||
color: var(--color-text-4);
|
|
||||||
background-color: var(--color-secondary-disabled);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -195,25 +195,17 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
||||||
import { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
import { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
||||||
import { getGenerateId, sleep } from '@/utils';
|
import { sleep } from '@/utils';
|
||||||
|
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
import {
|
import useMinderOperation from '../hooks/useMinderOperation';
|
||||||
floatMenuProps,
|
import { floatMenuProps, mainEditorProps, MinderJsonNode, priorityProps, tagProps } from '../props';
|
||||||
insertProps,
|
|
||||||
mainEditorProps,
|
|
||||||
MinderJsonNode,
|
|
||||||
MinderJsonNodeData,
|
|
||||||
priorityProps,
|
|
||||||
tagProps,
|
|
||||||
} from '../props';
|
|
||||||
import { isDisableNode, isNodeInMinderView, setPriorityView } from '../script/tool/utils';
|
import { isDisableNode, isNodeInMinderView, setPriorityView } from '../script/tool/utils';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
...mainEditorProps,
|
...mainEditorProps,
|
||||||
...floatMenuProps,
|
...floatMenuProps,
|
||||||
...insertProps,
|
|
||||||
...tagProps,
|
...tagProps,
|
||||||
...priorityProps,
|
...priorityProps,
|
||||||
});
|
});
|
||||||
|
@ -277,31 +269,6 @@
|
||||||
const priorityMenuVisible = ref(false);
|
const priorityMenuVisible = ref(false);
|
||||||
const moreMenuVisible = ref(false);
|
const moreMenuVisible = ref(false);
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行插入
|
|
||||||
* @param command 插入命令
|
|
||||||
*/
|
|
||||||
function execInsertCommand(command: string, value?: string) {
|
|
||||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
|
||||||
if (props.insertNode) {
|
|
||||||
props.insertNode(node, command, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (window.minder.queryCommandState(command) !== -1) {
|
|
||||||
window.minder.execCommand(command);
|
|
||||||
nextTick(() => {
|
|
||||||
const newNode: MinderJsonNode = window.minder.getSelectedNode();
|
|
||||||
if (!newNode.data) {
|
|
||||||
newNode.data = {
|
|
||||||
id: getGenerateId(),
|
|
||||||
text: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newNode.data.isNew = true; // 新建的节点标记为新建
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换标签
|
* 切换标签
|
||||||
* @param value 切换后的标签
|
* @param value 切换后的标签
|
||||||
|
@ -359,6 +326,10 @@
|
||||||
return !!window.minder.queryCommandState && window.minder.queryCommandState('priority') === -1;
|
return !!window.minder.queryCommandState && window.minder.queryCommandState('priority') === -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { minderCopy, minderCut, minderPaste, appendChildNode, appendSiblingNode, minderDelete } = useMinderOperation({
|
||||||
|
insertNode: props.insertNode,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理快捷菜单选择
|
* 处理快捷菜单选择
|
||||||
* @param type 选择的菜单项
|
* @param type 选择的菜单项
|
||||||
|
@ -368,48 +339,22 @@
|
||||||
if (selectedNodes.length > 0) {
|
if (selectedNodes.length > 0) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'AppendChildNode':
|
case 'AppendChildNode':
|
||||||
execInsertCommand('AppendChildNode', value);
|
appendChildNode(selectedNodes, value);
|
||||||
minderStore.dispatchEvent(MinderEventName.INSERT_CHILD, value, undefined, undefined, selectedNodes);
|
|
||||||
break;
|
break;
|
||||||
case 'AppendSiblingNode':
|
case 'AppendSiblingNode':
|
||||||
execInsertCommand('AppendSiblingNode', value);
|
appendSiblingNode(selectedNodes, value);
|
||||||
minderStore.dispatchEvent(MinderEventName.INSERT_SIBLING, value, undefined, undefined, selectedNodes);
|
|
||||||
break;
|
break;
|
||||||
case 'copy':
|
case 'copy':
|
||||||
minderStore.dispatchEvent(MinderEventName.COPY_NODE, undefined, undefined, undefined, selectedNodes);
|
minderCopy();
|
||||||
window.minder.execCommand('Copy');
|
|
||||||
break;
|
break;
|
||||||
case 'cut':
|
case 'cut':
|
||||||
minderStore.dispatchEvent(MinderEventName.CUT_NODE, undefined, undefined, undefined, selectedNodes);
|
minderCut();
|
||||||
window.minder.execCommand('Cut');
|
|
||||||
break;
|
break;
|
||||||
case 'paste':
|
case 'paste':
|
||||||
minderStore.dispatchEvent(MinderEventName.PASTE_NODE, undefined, undefined, undefined, selectedNodes);
|
minderPaste();
|
||||||
window.minder.execCommand('Paste');
|
|
||||||
let pastedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
|
||||||
if (pastedNodes.length > 0) {
|
|
||||||
pastedNodes = pastedNodes
|
|
||||||
.filter((e) => {
|
|
||||||
if (e.data?.id !== 'fakeNode' && e.data?.type !== 'tmp') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
window.minder.removeNode(e);
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
.map((e) => {
|
|
||||||
e.data = {
|
|
||||||
...(e.data as MinderJsonNodeData),
|
|
||||||
isNew: true,
|
|
||||||
id: getGenerateId(),
|
|
||||||
count: e.children?.length || 0,
|
|
||||||
};
|
|
||||||
return e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, undefined, undefined, selectedNodes);
|
minderDelete(selectedNodes);
|
||||||
window.minder.execCommand('RemoveNode');
|
|
||||||
break;
|
break;
|
||||||
case 'enterNode':
|
case 'enterNode':
|
||||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
||||||
|
|
|
@ -34,12 +34,13 @@
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
import useMinderEventListener from './hooks/useMinderEventListener';
|
import useMinderEventListener from './hooks/useMinderEventListener';
|
||||||
|
import useMinderOperation from './hooks/useMinderOperation';
|
||||||
|
import useShortCut from './hooks/useShortCut';
|
||||||
import {
|
import {
|
||||||
delProps,
|
delProps,
|
||||||
editMenuProps,
|
editMenuProps,
|
||||||
floatMenuProps,
|
floatMenuProps,
|
||||||
headerProps,
|
headerProps,
|
||||||
insertProps,
|
|
||||||
mainEditorProps,
|
mainEditorProps,
|
||||||
MinderEvent,
|
MinderEvent,
|
||||||
MinderJson,
|
MinderJson,
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
tagProps,
|
tagProps,
|
||||||
viewMenuProps,
|
viewMenuProps,
|
||||||
} from './props';
|
} from './props';
|
||||||
import { isNodeInMinderView } from './script/tool/utils';
|
import { isNodeInMinderView, setPriorityView } from './script/tool/utils';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'moldChange', data: number): void;
|
(e: 'moldChange', data: number): void;
|
||||||
|
@ -66,7 +67,6 @@
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
...headerProps,
|
...headerProps,
|
||||||
...floatMenuProps,
|
...floatMenuProps,
|
||||||
...insertProps,
|
|
||||||
...editMenuProps,
|
...editMenuProps,
|
||||||
...mainEditorProps,
|
...mainEditorProps,
|
||||||
...moleProps,
|
...moleProps,
|
||||||
|
@ -115,6 +115,63 @@
|
||||||
emit('save', data, callback);
|
emit('save', data, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { appendChildNode, appendSiblingNode, minderDelete } = useMinderOperation({
|
||||||
|
insertNode: props.insertNode,
|
||||||
|
});
|
||||||
|
const { unbindShortcuts } = useShortCut(
|
||||||
|
{
|
||||||
|
undo: () => {
|
||||||
|
window.minderHistory?.undo();
|
||||||
|
},
|
||||||
|
redo: () => {
|
||||||
|
window.minderHistory?.redo();
|
||||||
|
},
|
||||||
|
enter: () => {
|
||||||
|
if (props.canShowEnterNode) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete: () => {
|
||||||
|
if (props.canShowMoreMenuNodeOperation && props.canShowDeleteMenu) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
minderDelete(selectedNodes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expand: () => {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
if (selectedNodes.every((node) => node.isExpanded())) {
|
||||||
|
// 选中的节点集合全部展开,则全部收起
|
||||||
|
window.minder.execCommand('Collapse');
|
||||||
|
minderStore.dispatchEvent(MinderEventName.COLLAPSE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
} else {
|
||||||
|
// 选中的节点集合中有一个节点未展开,则全部展开
|
||||||
|
window.minder.execCommand('Expand');
|
||||||
|
if (!props.customPriority) {
|
||||||
|
// 展开后,需要设置一次优先级展示,避免展开后优先级显示成脑图内置文案;如果设置了自定义优先级,则不在此设置,由外部自行处理
|
||||||
|
setPriorityView(props.priorityStartWithZero, props.priorityPrefix);
|
||||||
|
}
|
||||||
|
minderStore.dispatchEvent(MinderEventName.EXPAND, undefined, undefined, undefined, selectedNodes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
appendChildNode: () => {
|
||||||
|
if (props.insertSonMenus.length > 0 || props.insertNode) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
appendChildNode(selectedNodes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
appendSiblingNode: () => {
|
||||||
|
if (props.insertSiblingMenus.length > 0 || props.insertNode) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
appendSiblingNode(selectedNodes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
insertNode: props.insertNode,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.minderProps = props;
|
window.minderProps = props;
|
||||||
useMinderEventListener({
|
useMinderEventListener({
|
||||||
|
@ -157,6 +214,10 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
unbindShortcuts();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -64,6 +64,10 @@ export const mainEditorProps = {
|
||||||
minderKey: String as PropType<MinderKeyEnum>,
|
minderKey: String as PropType<MinderKeyEnum>,
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
extractContentTabList: Array as PropType<{ label: string; value: string }[]>,
|
extractContentTabList: Array as PropType<{ label: string; value: string }[]>,
|
||||||
|
insertNode: {
|
||||||
|
type: Function as PropType<(node: MinderJsonNode, type: string, value?: string) => void>,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const headerProps = {
|
export const headerProps = {
|
||||||
|
@ -207,13 +211,6 @@ export const floatMenuProps = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const insertProps = {
|
|
||||||
insertNode: {
|
|
||||||
type: Function as PropType<(node: MinderJsonNode, type: string, value?: string) => void>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const editMenuProps = {
|
export const editMenuProps = {
|
||||||
sequenceEnable: {
|
sequenceEnable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
import type { MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
||||||
|
|
||||||
import type { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
import type { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
||||||
|
import { getGenerateId, mapTree } from '@/utils';
|
||||||
|
|
||||||
export function isDisableNode(minder: any) {
|
export function isDisableNode(minder: any) {
|
||||||
let node: MinderJsonNode;
|
let node: MinderJsonNode;
|
||||||
|
@ -120,20 +121,25 @@ export function setCustomPriorityView(valueMap: Record<any, string>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将节点及其子节点id置为null,changed 标记为true
|
* 重置节点为新节点
|
||||||
* @param node
|
* @param node
|
||||||
*/
|
*/
|
||||||
export function resetNodes(nodes: MinderJsonNode[]) {
|
export function resetNodes(nodes: MinderJsonNode[]) {
|
||||||
if (nodes) {
|
return mapTree(nodes, (node) => {
|
||||||
nodes.forEach((item: any) => {
|
if (node.data && node.data?.id !== 'fakeNode' && node.data?.type !== 'tmp') {
|
||||||
if (item.data) {
|
node.data = {
|
||||||
item.data.id = null;
|
...node.data,
|
||||||
item.data.contextChanged = true;
|
isNew: true,
|
||||||
item.data.changed = true;
|
id: getGenerateId(),
|
||||||
resetNodes(item.children);
|
count:
|
||||||
}
|
node.children?.filter((e: MinderJsonNode) => e.data?.id !== 'fakeNode' && e.data?.type !== 'tmp').length || 0,
|
||||||
});
|
type: 'ADD',
|
||||||
}
|
changed: false,
|
||||||
|
};
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDisableForNode(node: MinderJsonNode) {
|
export function isDisableForNode(node: MinderJsonNode) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ export enum MinderEventName {
|
||||||
'HOTBOX' = 'HOTBOX', // 热键菜单
|
'HOTBOX' = 'HOTBOX', // 热键菜单
|
||||||
'ENTER_NODE' = 'ENTER_NODE', // 进入节点
|
'ENTER_NODE' = 'ENTER_NODE', // 进入节点
|
||||||
'EXPAND' = 'EXPAND', // 展开节点
|
'EXPAND' = 'EXPAND', // 展开节点
|
||||||
|
'COLLAPSE' = 'COLLAPSE', // 折叠节点
|
||||||
'INSERT_CHILD' = 'INSERT_CHILD', // 插入子节点
|
'INSERT_CHILD' = 'INSERT_CHILD', // 插入子节点
|
||||||
'INSERT_SIBLING' = 'INSERT_SIBLING', // 插入同级节点
|
'INSERT_SIBLING' = 'INSERT_SIBLING', // 插入同级节点
|
||||||
'COPY_NODE' = 'COPY_NODE', // 复制节点
|
'COPY_NODE' = 'COPY_NODE', // 复制节点
|
||||||
|
|
|
@ -39,6 +39,7 @@ const useMinderStore = defineStore('minder', {
|
||||||
/**
|
/**
|
||||||
* 脑图组件派发事件
|
* 脑图组件派发事件
|
||||||
* @param name 事件名称
|
* @param name 事件名称
|
||||||
|
* @param params 携带参数
|
||||||
* @param position 触发事件的节点/鼠标位置
|
* @param position 触发事件的节点/鼠标位置
|
||||||
* @param nodeDom 节点 DOM
|
* @param nodeDom 节点 DOM
|
||||||
* @param nodes 节点集合
|
* @param nodes 节点集合
|
||||||
|
@ -90,7 +91,14 @@ const useMinderStore = defineStore('minder', {
|
||||||
setClipboard(nodes?: MinderJsonNode[]) {
|
setClipboard(nodes?: MinderJsonNode[]) {
|
||||||
this.clipboard = mapTree(nodes || [], (node) => {
|
this.clipboard = mapTree(nodes || [], (node) => {
|
||||||
if (node.id !== 'fakeNode' && node.type !== 'tmp') {
|
if (node.id !== 'fakeNode' && node.type !== 'tmp') {
|
||||||
return { ...node, id: getGenerateId(), type: 'ADD' };
|
return {
|
||||||
|
...node,
|
||||||
|
id: getGenerateId(),
|
||||||
|
type: 'ADD',
|
||||||
|
isNew: true,
|
||||||
|
changed: false,
|
||||||
|
count: node.children?.length || 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -135,7 +135,7 @@
|
||||||
{
|
{
|
||||||
key: 'belongModule',
|
key: 'belongModule',
|
||||||
locale: 'apiTestManagement.belongModule',
|
locale: 'apiTestManagement.belongModule',
|
||||||
value: previewDetail.value.path,
|
value: previewDetail.value.moduleName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'creator',
|
key: 'creator',
|
||||||
|
|
Loading…
Reference in New Issue