feat(脑图): 脑图批量操作&公共文案
This commit is contained in:
parent
658e78a098
commit
578fe9a157
|
@ -19,8 +19,14 @@
|
||||||
:can-show-paste-menu="!stopPaste()"
|
:can-show-paste-menu="!stopPaste()"
|
||||||
:can-show-more-menu="canShowMoreMenu()"
|
:can-show-more-menu="canShowMoreMenu()"
|
||||||
:can-show-priority-menu="canShowPriorityMenu()"
|
:can-show-priority-menu="canShowPriorityMenu()"
|
||||||
|
:custom-batch-expand="customBatchExpand"
|
||||||
|
:can-show-batch-expand="canShowBatchExpand()"
|
||||||
|
:can-show-batch-cut="true"
|
||||||
|
:can-show-batch-copy="true"
|
||||||
|
:can-show-batch-delete="true"
|
||||||
:priority-tooltip="t('caseManagement.caseReview.caseLevel')"
|
:priority-tooltip="t('caseManagement.caseReview.caseLevel')"
|
||||||
:disabled="!hasEditPermission"
|
:disabled="!hasEditPermission"
|
||||||
|
can-show-more-batch-menu
|
||||||
single-tag
|
single-tag
|
||||||
tag-enable
|
tag-enable
|
||||||
sequence-enable
|
sequence-enable
|
||||||
|
@ -697,6 +703,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量展开节点
|
||||||
|
*/
|
||||||
|
function customBatchExpand(node: MinderJsonNode) {
|
||||||
|
if (node.data?.resource?.includes(caseTag)) {
|
||||||
|
expendNodeAndChildren(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否显示批量展开按钮
|
||||||
|
*/
|
||||||
|
function canShowBatchExpand() {
|
||||||
|
if (window.minder) {
|
||||||
|
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
return nodes.some((node) => !!node.data?.resource?.includes(caseTag));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析用例节点信息
|
* 解析用例节点信息
|
||||||
* @param node 用例节点
|
* @param node 用例节点
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type {
|
import type {
|
||||||
InsertMenuItem,
|
|
||||||
MinderEvent,
|
MinderEvent,
|
||||||
MinderJsonNode,
|
MinderJsonNode,
|
||||||
MinderJsonNodeData,
|
MinderJsonNodeData,
|
||||||
|
MinderMenuItem,
|
||||||
} from '@/components/pure/ms-minder-editor/props';
|
} from '@/components/pure/ms-minder-editor/props';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -50,8 +50,8 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertSiblingMenus = ref<InsertMenuItem[]>([]);
|
const insertSiblingMenus = ref<MinderMenuItem[]>([]);
|
||||||
const insertSonMenus = ref<InsertMenuItem[]>([]);
|
const insertSonMenus = ref<MinderMenuItem[]>([]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测节点可展示的菜单项
|
* 检测节点可展示的菜单项
|
||||||
|
@ -236,9 +236,9 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (window.minder) {
|
if (window.minder) {
|
||||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
// 选中节点是用例节点时,可展示优先级菜单
|
// 选中节点是用例节点时,可展示优先级菜单
|
||||||
return !!node?.data?.resource?.includes(caseTag);
|
return nodes.every((node) => !!node.data?.resource?.includes(caseTag));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
:can-show-float-menu="canShowFloatMenu"
|
:can-show-float-menu="canShowFloatMenu"
|
||||||
:can-show-delete-menu="canShowDeleteMenu"
|
:can-show-delete-menu="canShowDeleteMenu"
|
||||||
:disabled="!hasEditPermission"
|
:disabled="!hasEditPermission"
|
||||||
|
:can-show-batch-delete="true"
|
||||||
|
can-show-more-batch-menu
|
||||||
custom-priority
|
custom-priority
|
||||||
single-tag
|
single-tag
|
||||||
tag-enable
|
tag-enable
|
||||||
|
@ -523,8 +525,13 @@
|
||||||
Message.warning(t('ms.minders.unsavedTip'));
|
Message.warning(t('ms.minders.unsavedTip'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
if (nodes.length > 1) {
|
||||||
|
extraVisible.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
extraVisible.value = !extraVisible.value;
|
extraVisible.value = !extraVisible.value;
|
||||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
const node = nodes[0];
|
||||||
switchingConfigFormData.value = true;
|
switchingConfigFormData.value = true;
|
||||||
if (extraVisible.value) {
|
if (extraVisible.value) {
|
||||||
activePlanSet.value = node as PlanMinderNode;
|
activePlanSet.value = node as PlanMinderNode;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import type { MinderEvent, MinderJsonNode } from '../props';
|
||||||
|
|
||||||
export interface UseEventListenerProps {
|
export interface UseEventListenerProps {
|
||||||
handleContentChange?: (node?: MinderJsonNode) => void;
|
handleContentChange?: (node?: MinderJsonNode) => void;
|
||||||
handleSelectionChange?: (node?: MinderJsonNode) => void;
|
handleSelectionChange?: (nodes: MinderJsonNode[]) => void;
|
||||||
handleMinderEvent?: (event: MinderCustomEvent) => void;
|
handleMinderEvent?: (event: MinderCustomEvent) => void;
|
||||||
handleBeforeExecCommand?: (event: MinderEvent) => void;
|
handleBeforeExecCommand?: (event: MinderEvent) => void;
|
||||||
handleViewChange?: (event: MinderEvent) => void;
|
handleViewChange?: (event: MinderEvent) => void;
|
||||||
|
@ -36,16 +36,16 @@ export default function useEventListener(listener: UseEventListenerProps) {
|
||||||
minder.on(
|
minder.on(
|
||||||
'selectionchange',
|
'selectionchange',
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
const node: MinderJsonNode = minder.getSelectedNode();
|
const nodes: MinderJsonNode[] = minder.getSelectedNodes();
|
||||||
// 如果节点选中后即刻进行拖拽,则等待拖拽结束后再触发选中事件
|
// 如果节点选中后即刻进行拖拽,则等待拖拽结束后再触发选中事件
|
||||||
if (isDragging.value) {
|
if (isDragging.value) {
|
||||||
selectionchangeEvent = () => {
|
selectionchangeEvent = () => {
|
||||||
if (listener.handleSelectionChange) {
|
if (listener.handleSelectionChange) {
|
||||||
listener.handleSelectionChange(node);
|
listener.handleSelectionChange(nodes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if (listener.handleSelectionChange) {
|
} else if (listener.handleSelectionChange) {
|
||||||
listener.handleSelectionChange(node);
|
listener.handleSelectionChange(nodes);
|
||||||
}
|
}
|
||||||
}, 300)
|
}, 300)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
|
import { useClipboard } from '@vueuse/core';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||||
import { getGenerateId } from '@/utils';
|
import { getGenerateId } from '@/utils';
|
||||||
|
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
import type { MinderJsonNode } from '../props';
|
import type { MinderJsonNode } from '../props';
|
||||||
import { markDeleteNode, resetNodes } from '../script/tool/utils';
|
import { markDeleteNode, resetNodes, setPriorityView } from '../script/tool/utils';
|
||||||
|
|
||||||
interface IData {
|
interface IData {
|
||||||
getRegisterProtocol(protocol: string): {
|
getRegisterProtocol(protocol: string): {
|
||||||
|
@ -15,16 +19,23 @@ interface IData {
|
||||||
|
|
||||||
export interface MinderOperationProps {
|
export interface MinderOperationProps {
|
||||||
insertNode?: (node: MinderJsonNode, command: string, value?: string) => void;
|
insertNode?: (node: MinderJsonNode, command: string, value?: string) => void;
|
||||||
|
customBatchExpand?: (node: MinderJsonNode) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
canShowMoreMenu?: boolean;
|
||||||
canShowMoreMenuNodeOperation?: boolean;
|
canShowMoreMenuNodeOperation?: boolean;
|
||||||
canShowPasteMenu?: boolean;
|
canShowPasteMenu?: boolean;
|
||||||
|
canShowDeleteMenu?: boolean;
|
||||||
|
customPriority?: boolean;
|
||||||
|
priorityStartWithZero?: boolean;
|
||||||
|
priorityPrefix?: string;
|
||||||
|
canShowBatchCut?: boolean;
|
||||||
|
canShowBatchCopy?: boolean;
|
||||||
|
canShowBatchDelete?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useMinderOperation({
|
export default function useMinderOperation(options: MinderOperationProps) {
|
||||||
insertNode,
|
|
||||||
canShowMoreMenuNodeOperation,
|
|
||||||
canShowPasteMenu,
|
|
||||||
}: MinderOperationProps) {
|
|
||||||
const minderStore = useMinderStore();
|
const minderStore = useMinderStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
function encode(nodes: Array<MinderJsonNode>): string {
|
function encode(nodes: Array<MinderJsonNode>): string {
|
||||||
const { editor } = window;
|
const { editor } = window;
|
||||||
|
@ -42,8 +53,8 @@ export default function useMinderOperation({
|
||||||
/**
|
/**
|
||||||
* 执行复制
|
* 执行复制
|
||||||
*/
|
*/
|
||||||
const minderCopy = (e?: ClipboardEvent) => {
|
const minderCopy = async (e?: ClipboardEvent) => {
|
||||||
if (!canShowMoreMenuNodeOperation) {
|
if ((!options.canShowMoreMenu || !options.canShowMoreMenuNodeOperation) && options.canShowBatchCopy === false) {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -57,8 +68,15 @@ export default function useMinderOperation({
|
||||||
case 'normal': {
|
case 'normal': {
|
||||||
const selectedNodes = minder.getSelectedNodes();
|
const selectedNodes = minder.getSelectedNodes();
|
||||||
minderStore.dispatchEvent(MinderEventName.COPY_NODE, undefined, undefined, undefined, selectedNodes);
|
minderStore.dispatchEvent(MinderEventName.COPY_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
if (e?.clipboardData) {
|
||||||
|
e.clipboardData.setData('text/plain', encode(selectedNodes));
|
||||||
|
} else {
|
||||||
|
const { copy } = useClipboard();
|
||||||
|
await copy(encode(selectedNodes));
|
||||||
|
}
|
||||||
minder.execCommand('Copy');
|
minder.execCommand('Copy');
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
|
Message.success(t('common.copySuccess'));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -68,8 +86,11 @@ export default function useMinderOperation({
|
||||||
/**
|
/**
|
||||||
* 执行剪切
|
* 执行剪切
|
||||||
*/
|
*/
|
||||||
const minderCut = (e?: ClipboardEvent) => {
|
const minderCut = async (e?: ClipboardEvent) => {
|
||||||
if (!canShowMoreMenuNodeOperation) {
|
if (
|
||||||
|
(options.disabled || !options.canShowMoreMenu || !options.canShowMoreMenuNodeOperation) &&
|
||||||
|
options.canShowBatchCut === false
|
||||||
|
) {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -79,9 +100,7 @@ export default function useMinderOperation({
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = fsm.state();
|
const state = fsm.state();
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'input': {
|
case 'input': {
|
||||||
break;
|
break;
|
||||||
|
@ -90,11 +109,17 @@ export default function useMinderOperation({
|
||||||
markDeleteNode(minder);
|
markDeleteNode(minder);
|
||||||
const selectedNodes = minder.getSelectedNodes();
|
const selectedNodes = minder.getSelectedNodes();
|
||||||
if (selectedNodes.length) {
|
if (selectedNodes.length) {
|
||||||
e?.clipboardData?.setData('text/plain', encode(selectedNodes));
|
if (e?.clipboardData) {
|
||||||
|
e.clipboardData.setData('text/plain', encode(selectedNodes));
|
||||||
|
} else {
|
||||||
|
const { copy } = useClipboard();
|
||||||
|
await copy(encode(selectedNodes));
|
||||||
|
}
|
||||||
minder.execCommand('Cut');
|
minder.execCommand('Cut');
|
||||||
}
|
}
|
||||||
e?.preventDefault();
|
|
||||||
minderStore.dispatchEvent(MinderEventName.CUT_NODE, undefined, undefined, undefined, selectedNodes);
|
minderStore.dispatchEvent(MinderEventName.CUT_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
e?.preventDefault();
|
||||||
|
Message.success(t('common.cutSuccess'));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -104,8 +129,8 @@ export default function useMinderOperation({
|
||||||
/**
|
/**
|
||||||
* 执行粘贴
|
* 执行粘贴
|
||||||
*/
|
*/
|
||||||
const minderPaste = (e?: ClipboardEvent) => {
|
const minderPaste = async (e?: ClipboardEvent) => {
|
||||||
if (!canShowMoreMenuNodeOperation && !canShowPasteMenu) {
|
if (options.disabled || !options.canShowPasteMenu) {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -117,10 +142,8 @@ export default function useMinderOperation({
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = fsm.state();
|
const state = fsm.state();
|
||||||
const textData = e?.clipboardData?.getData('text/plain');
|
const textData = e?.clipboardData ? e.clipboardData.getData('text/plain') : await navigator.clipboard.readText();
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'input': {
|
case 'input': {
|
||||||
// input状态下如果格式为application/km则不进行paste操作
|
// input状态下如果格式为application/km则不进行paste操作
|
||||||
|
@ -181,8 +204,8 @@ export default function useMinderOperation({
|
||||||
*/
|
*/
|
||||||
const execInsertCommand = (command: string, value?: string) => {
|
const execInsertCommand = (command: string, value?: string) => {
|
||||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
if (insertNode) {
|
if (options.insertNode) {
|
||||||
insertNode(node, command, value);
|
options.insertNode(node, command, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (window.minder.queryCommandState(command) !== -1) {
|
if (window.minder.queryCommandState(command) !== -1) {
|
||||||
|
@ -220,13 +243,57 @@ export default function useMinderOperation({
|
||||||
minderStore.dispatchEvent(MinderEventName.INSERT_SIBLING, value, undefined, undefined, selectedNodes);
|
minderStore.dispatchEvent(MinderEventName.INSERT_SIBLING, value, undefined, undefined, selectedNodes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脑图展开
|
||||||
|
* @param selectedNodes 当前选中的节点集合
|
||||||
|
*/
|
||||||
|
const minderExpand = (selectedNodes: MinderJsonNode[]) => {
|
||||||
|
if (selectedNodes.every((node) => node.isExpanded())) {
|
||||||
|
// 选中的节点集合全部展开,则全部收起
|
||||||
|
selectedNodes.forEach((node) => {
|
||||||
|
node.collapse();
|
||||||
|
node.renderTree();
|
||||||
|
});
|
||||||
|
if (!options.customPriority) {
|
||||||
|
// 展开后,需要设置一次优先级展示,避免展开后优先级显示成脑图内置文案;如果设置了自定义优先级,则不在此设置,由外部自行处理
|
||||||
|
setPriorityView(!!options.priorityStartWithZero, options.priorityPrefix || '');
|
||||||
|
window.minder.refresh();
|
||||||
|
}
|
||||||
|
minderStore.dispatchEvent(MinderEventName.COLLAPSE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
} else {
|
||||||
|
// 选中的节点集合中有一个节点未展开,则全部展开
|
||||||
|
selectedNodes.forEach((node) => {
|
||||||
|
if (selectedNodes.length > 1 && options.customBatchExpand) {
|
||||||
|
// 批量操作节点才执行customBatchExpand
|
||||||
|
options.customBatchExpand(node);
|
||||||
|
} else {
|
||||||
|
node.expand();
|
||||||
|
node.renderTree();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!options.customPriority) {
|
||||||
|
// 展开后,需要设置一次优先级展示,避免展开后优先级显示成脑图内置文案;如果设置了自定义优先级,则不在此设置,由外部自行处理
|
||||||
|
setPriorityView(!!options.priorityStartWithZero, options.priorityPrefix || '');
|
||||||
|
window.minder.refresh();
|
||||||
|
}
|
||||||
|
minderStore.dispatchEvent(MinderEventName.EXPAND, undefined, undefined, undefined, selectedNodes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除节点
|
* 删除节点
|
||||||
* @param selectedNodes 当前选中的节点集合
|
* @param selectedNodes 当前选中的节点集合
|
||||||
*/
|
*/
|
||||||
const minderDelete = (selectedNodes: MinderJsonNode[]) => {
|
const minderDelete = (selectedNodes: MinderJsonNode[]) => {
|
||||||
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, undefined, undefined, selectedNodes);
|
if (
|
||||||
window.minder.execCommand('RemoveNode');
|
(options.canShowDeleteMenu ||
|
||||||
|
(options.canShowMoreMenu && options.canShowMoreMenuNodeOperation) ||
|
||||||
|
options.canShowBatchDelete) &&
|
||||||
|
!options.disabled
|
||||||
|
) {
|
||||||
|
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, undefined, undefined, undefined, selectedNodes);
|
||||||
|
window.minder.execCommand('RemoveNode');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -236,5 +303,6 @@ export default function useMinderOperation({
|
||||||
appendChildNode,
|
appendChildNode,
|
||||||
appendSiblingNode,
|
appendSiblingNode,
|
||||||
minderDelete,
|
minderDelete,
|
||||||
|
minderExpand,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { isDisableNode, setPriorityView } from '../script/tool/utils';
|
||||||
|
|
||||||
|
export interface PriorityProps {
|
||||||
|
priorityStartWithZero: boolean;
|
||||||
|
priorityPrefix: string;
|
||||||
|
customPriority?: boolean;
|
||||||
|
priorityDisableCheck?: (node: any) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function usePriority(options: PriorityProps) {
|
||||||
|
const priorityDisabled = ref(true);
|
||||||
|
function isDisable(): boolean {
|
||||||
|
if (Object.keys(window.minder).length === 0) return true;
|
||||||
|
nextTick(() => {
|
||||||
|
setPriorityView(options.priorityStartWithZero, options.priorityPrefix);
|
||||||
|
});
|
||||||
|
const node = window.minder.getSelectedNode();
|
||||||
|
if (isDisableNode(window.minder) || !node || node.parent === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (options.priorityDisableCheck) {
|
||||||
|
return options.priorityDisableCheck(node);
|
||||||
|
}
|
||||||
|
return !!window.minder.queryCommandState && window.minder.queryCommandState('priority') === -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPriority(value?: string) {
|
||||||
|
if (value && !priorityDisabled.value) {
|
||||||
|
window.minder.execCommand('priority', value);
|
||||||
|
setPriorityView(options.priorityStartWithZero, options.priorityPrefix);
|
||||||
|
} else if (window.minder.execCommand && !priorityDisabled.value) {
|
||||||
|
window.minder.execCommand('priority');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
const freshFuc = setPriorityView;
|
||||||
|
if (window.minder && !options.customPriority) {
|
||||||
|
window.minder.on('contentchange', () => {
|
||||||
|
// 异步执行,否则执行完,还会被重置
|
||||||
|
setTimeout(() => {
|
||||||
|
freshFuc(options.priorityStartWithZero, options.priorityPrefix);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
window.minder.on('selectionchange', () => {
|
||||||
|
priorityDisabled.value = isDisable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
priorityDisabled,
|
||||||
|
setPriority,
|
||||||
|
};
|
||||||
|
}
|
|
@ -29,12 +29,14 @@
|
||||||
<slot name="extractMenu"></slot>
|
<slot name="extractMenu"></slot>
|
||||||
</template>
|
</template>
|
||||||
</nodeFloatMenu>
|
</nodeFloatMenu>
|
||||||
|
<batchMenu v-bind="props" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" name="minderContainer" setup>
|
<script lang="ts" name="minderContainer" setup>
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
import batchMenu from '../menu/batchMenu.vue';
|
||||||
import nodeFloatMenu from '../menu/nodeFloatMenu.vue';
|
import nodeFloatMenu from '../menu/nodeFloatMenu.vue';
|
||||||
import minderHeader from './header.vue';
|
import minderHeader from './header.vue';
|
||||||
import Navigator from './navigator.vue';
|
import Navigator from './navigator.vue';
|
||||||
|
@ -47,6 +49,7 @@
|
||||||
|
|
||||||
import useEventListener from '../hooks/useMinderEventListener';
|
import useEventListener from '../hooks/useMinderEventListener';
|
||||||
import {
|
import {
|
||||||
|
batchMenuProps,
|
||||||
editMenuProps,
|
editMenuProps,
|
||||||
floatMenuProps,
|
floatMenuProps,
|
||||||
headerProps,
|
headerProps,
|
||||||
|
@ -68,6 +71,7 @@
|
||||||
...mainEditorProps,
|
...mainEditorProps,
|
||||||
...tagProps,
|
...tagProps,
|
||||||
...priorityProps,
|
...priorityProps,
|
||||||
|
...batchMenuProps,
|
||||||
});
|
});
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'save', data: MinderJson, callback: () => void): void;
|
(e: 'save', data: MinderJson, callback: () => void): void;
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="batchMenuVisible" class="ms-minder-node-float-menu ms-minder-batch-menu">
|
||||||
|
<a-dropdown
|
||||||
|
v-if="props.priorityCount && props.canShowPriorityMenu"
|
||||||
|
v-model:popup-visible="priorityMenuVisible"
|
||||||
|
class="ms-minder-dropdown"
|
||||||
|
:popup-translate="[0, 4]"
|
||||||
|
position="bl"
|
||||||
|
trigger="click"
|
||||||
|
@select="(val) => handleMinderMenuSelect('priority', val as string)"
|
||||||
|
>
|
||||||
|
<a-tooltip :content="props.priorityTooltip" :disabled="!props.priorityTooltip">
|
||||||
|
<MsButton
|
||||||
|
type="icon"
|
||||||
|
class="ms-minder-node-float-menu-icon-button"
|
||||||
|
:class="[priorityMenuVisible ? 'ms-minder-node-float-menu-icon-button--focus' : '']"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-[16px] w-[16px] rounded-full bg-[rgb(var(--primary-5))] text-center text-[12px] font-medium text-white"
|
||||||
|
>
|
||||||
|
P
|
||||||
|
</div>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
<template #content>
|
||||||
|
<div v-if="props.priorityTooltip" class="mx-[6px] px-[8px] py-[3px] text-[var(--color-text-4)]">
|
||||||
|
{{ props.priorityTooltip }}
|
||||||
|
</div>
|
||||||
|
<template v-for="(item, pIndex) in priorityCount + 1" :key="item">
|
||||||
|
<a-doption v-if="pIndex != 0" :value="pIndex">
|
||||||
|
<div
|
||||||
|
class="flex h-[20px] w-[20px] items-center justify-center rounded-full text-[12px] font-medium text-white"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: priorityColorMap[pIndex],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ priorityPrefix }}{{ priorityStartWithZero ? pIndex - 1 : pIndex }}
|
||||||
|
</div>
|
||||||
|
</a-doption>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
<slot name="batchMenu"></slot>
|
||||||
|
<a-dropdown
|
||||||
|
v-if="props.canShowMoreBatchMenu"
|
||||||
|
v-model:popup-visible="moreMenuVisible"
|
||||||
|
class="ms-minder-dropdown"
|
||||||
|
:popup-translate="[0, -4]"
|
||||||
|
position="tl"
|
||||||
|
trigger="click"
|
||||||
|
@select="(val) => handleMinderMenuSelect(val)"
|
||||||
|
>
|
||||||
|
<a-tooltip :content="t('common.more')">
|
||||||
|
<MsButton
|
||||||
|
type="icon"
|
||||||
|
class="ms-minder-node-float-menu-icon-button"
|
||||||
|
:class="[moreMenuVisible ? 'ms-minder-node-float-menu-icon-button--focus' : '']"
|
||||||
|
>
|
||||||
|
<MsIcon type="icon-icon_more_outlined" class="text-[var(--color-text-4)]" />
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
<template #content>
|
||||||
|
<a-doption v-if="props.canShowBatchCopy" value="copy">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div>{{ t('minder.hotboxMenu.copy') }}</div>
|
||||||
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + C)</div>
|
||||||
|
</div>
|
||||||
|
</a-doption>
|
||||||
|
<a-doption v-if="props.canShowBatchCut" value="cut">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
||||||
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + X)</div>
|
||||||
|
</div>
|
||||||
|
</a-doption>
|
||||||
|
<a-doption v-if="props.canShowBatchDelete" value="delete">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div>{{ t('minder.hotboxMenu.delete') }}</div>
|
||||||
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Backspace)</div>
|
||||||
|
</div>
|
||||||
|
</a-doption>
|
||||||
|
<a-doption v-if="props.canShowBatchExpand" value="expand">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div>{{ t('minder.hotboxMenu.expand') }}</div>
|
||||||
|
<div class="ml-[4px] text-[var(--color-text-4)]">(/)</div>
|
||||||
|
</div>
|
||||||
|
</a-doption>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { useMinderStore } from '@/store';
|
||||||
|
|
||||||
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
|
import useMinderOperation from '../hooks/useMinderOperation';
|
||||||
|
import usePriority from '../hooks/useMinderPriority';
|
||||||
|
import {
|
||||||
|
batchMenuProps,
|
||||||
|
floatMenuProps,
|
||||||
|
mainEditorProps,
|
||||||
|
MinderJsonNode,
|
||||||
|
priorityColorMap,
|
||||||
|
priorityProps,
|
||||||
|
} from '../props';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
...mainEditorProps,
|
||||||
|
...floatMenuProps,
|
||||||
|
...priorityProps,
|
||||||
|
...batchMenuProps,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const minderStore = useMinderStore();
|
||||||
|
const { setPriority } = usePriority(props);
|
||||||
|
|
||||||
|
const batchMenuVisible = ref(false);
|
||||||
|
const priorityMenuVisible = ref(false);
|
||||||
|
const moreMenuVisible = ref(false);
|
||||||
|
|
||||||
|
const { minderCopy, minderCut, minderDelete, minderExpand } = useMinderOperation(props);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => minderStore.event.eventId,
|
||||||
|
async () => {
|
||||||
|
if (window.minder) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
if (
|
||||||
|
minderStore.event.name === MinderEventName.DRAG_FINISH ||
|
||||||
|
minderStore.event.name === MinderEventName.NODE_UNSELECT
|
||||||
|
) {
|
||||||
|
batchMenuVisible.value = selectedNodes.length > 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理快捷菜单选择
|
||||||
|
* @param type 选择的菜单项
|
||||||
|
*/
|
||||||
|
function handleMinderMenuSelect(type: string | number | Record<string, any> | undefined, value?: string) {
|
||||||
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
|
if (selectedNodes.length > 0) {
|
||||||
|
switch (type) {
|
||||||
|
case 'copy':
|
||||||
|
minderCopy();
|
||||||
|
break;
|
||||||
|
case 'cut':
|
||||||
|
minderCut();
|
||||||
|
break;
|
||||||
|
case 'expand':
|
||||||
|
minderExpand(selectedNodes);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
minderDelete(selectedNodes);
|
||||||
|
break;
|
||||||
|
case 'priority':
|
||||||
|
setPriority(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ms-minder-batch-menu {
|
||||||
|
@apply absolute flex w-auto flex-1 items-center bg-white;
|
||||||
|
|
||||||
|
bottom: 6px;
|
||||||
|
left: 50%;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
box-shadow: 0 4px 10px -1px rgb(100 100 102 / 15%);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -137,32 +137,32 @@
|
||||||
<a-doption v-if="props.canShowEnterNode" value="enterNode">
|
<a-doption v-if="props.canShowEnterNode" value="enterNode">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('minder.hotboxMenu.enterNode') }}</div>
|
<div>{{ t('minder.hotboxMenu.enterNode') }}</div>
|
||||||
<!-- <div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl+ Enter)</div> -->
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl+ Enter)</div>
|
||||||
</div>
|
</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<template v-if="props.canShowMoreMenuNodeOperation">
|
<template v-if="props.canShowMoreMenuNodeOperation">
|
||||||
<a-doption value="copy">
|
<a-doption value="copy">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('minder.hotboxMenu.copy') }}</div>
|
<div>{{ t('minder.hotboxMenu.copy') }}</div>
|
||||||
<!-- <div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + C)</div> -->
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + C)</div>
|
||||||
</div>
|
</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<a-doption value="cut">
|
<a-doption value="cut">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
||||||
<!-- <div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + X)</div> -->
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + X)</div>
|
||||||
</div>
|
</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<a-doption v-if="props.canShowPasteMenu && minderStore.clipboard.length > 0" value="paste">
|
<a-doption v-if="props.canShowPasteMenu && minderStore.clipboard.length > 0" value="paste">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('minder.hotboxMenu.paste') }}</div>
|
<div>{{ t('minder.hotboxMenu.paste') }}</div>
|
||||||
<!-- <div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + V)</div> -->
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + V)</div>
|
||||||
</div>
|
</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<a-doption value="delete">
|
<a-doption value="delete">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>{{ t('minder.hotboxMenu.delete') }}</div>
|
<div>{{ t('minder.hotboxMenu.delete') }}</div>
|
||||||
<!-- <div class="ml-[4px] text-[var(--color-text-4)]">(Backspace)</div> -->
|
<div class="ml-[4px] text-[var(--color-text-4)]">(Backspace)</div>
|
||||||
</div>
|
</div>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
</template>
|
</template>
|
||||||
|
@ -200,8 +200,9 @@
|
||||||
import { MinderEventName } from '@/enums/minderEnum';
|
import { MinderEventName } from '@/enums/minderEnum';
|
||||||
|
|
||||||
import useMinderOperation from '../hooks/useMinderOperation';
|
import useMinderOperation from '../hooks/useMinderOperation';
|
||||||
import { floatMenuProps, mainEditorProps, MinderJsonNode, priorityProps, tagProps } from '../props';
|
import usePriority from '../hooks/useMinderPriority';
|
||||||
import { isDisableNode, isNodeInMinderView, setPriorityView } from '../script/tool/utils';
|
import { floatMenuProps, mainEditorProps, MinderJsonNode, priorityColorMap, priorityProps, tagProps } from '../props';
|
||||||
|
import { isNodeInMinderView } from '../script/tool/utils';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
...mainEditorProps,
|
...mainEditorProps,
|
||||||
|
@ -215,6 +216,7 @@
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const minderStore = useMinderStore();
|
const minderStore = useMinderStore();
|
||||||
|
const { setPriority } = usePriority(props);
|
||||||
|
|
||||||
const currentNodeTags = ref<string[]>([]);
|
const currentNodeTags = ref<string[]>([]);
|
||||||
const tags = ref<string[]>([]);
|
const tags = ref<string[]>([]);
|
||||||
|
@ -240,7 +242,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selectedNodes.length > 1) {
|
if (selectedNodes.length > 1) {
|
||||||
// 多选时隐藏悬浮菜单 TODO:支持批量操作
|
// 多选时隐藏悬浮菜单
|
||||||
menuVisible.value = false;
|
menuVisible.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -304,31 +306,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const priorityColorMap: Record<number, string> = {
|
const { minderCopy, minderCut, minderPaste, appendChildNode, appendSiblingNode, minderDelete } =
|
||||||
1: 'rgb(var(--danger-6))',
|
useMinderOperation(props);
|
||||||
2: 'rgb(var(--link-6))',
|
|
||||||
3: 'rgb(var(--success-6))',
|
|
||||||
4: 'rgb(var(--warning-6))',
|
|
||||||
};
|
|
||||||
const priorityDisabled = ref(true);
|
|
||||||
function isDisable(): boolean {
|
|
||||||
if (Object.keys(window.minder).length === 0) return true;
|
|
||||||
nextTick(() => {
|
|
||||||
setPriorityView(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
});
|
|
||||||
const node = window.minder.getSelectedNode();
|
|
||||||
if (isDisableNode(window.minder) || !node || node.parent === null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (props.priorityDisableCheck) {
|
|
||||||
return props.priorityDisableCheck(node);
|
|
||||||
}
|
|
||||||
return !!window.minder.queryCommandState && window.minder.queryCommandState('priority') === -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { minderCopy, minderCut, minderPaste, appendChildNode, appendSiblingNode, minderDelete } = useMinderOperation({
|
|
||||||
insertNode: props.insertNode,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理快捷菜单选择
|
* 处理快捷菜单选择
|
||||||
|
@ -360,12 +339,7 @@
|
||||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
||||||
break;
|
break;
|
||||||
case 'priority':
|
case 'priority':
|
||||||
if (value && !priorityDisabled.value) {
|
setPriority(value);
|
||||||
window.minder.execCommand('priority', value);
|
|
||||||
setPriorityView(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
} else if (window.minder.execCommand && !priorityDisabled.value) {
|
|
||||||
window.minder.execCommand('priority');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -385,23 +359,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
const freshFuc = setPriorityView;
|
|
||||||
if (window.minder && !props.customPriority) {
|
|
||||||
window.minder.on('contentchange', () => {
|
|
||||||
// 异步执行,否则执行完,还会被重置
|
|
||||||
setTimeout(() => {
|
|
||||||
freshFuc(props.priorityStartWithZero, props.priorityPrefix);
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
window.minder.on('selectionchange', () => {
|
|
||||||
priorityDisabled.value = isDisable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="arrange-group">
|
|
||||||
<div class="arrange menu-btn" :disabled="disabled" @click="resetlayout">
|
|
||||||
<span class="tab-icons" />
|
|
||||||
<span class="label">
|
|
||||||
{{ t('minder.menu.arrange.arrange_layout') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="Arrange" setup>
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const disabled = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState && window.minder.queryCommandState('resetlayout') === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
function resetlayout() {
|
|
||||||
if (window.minder.queryCommandState('resetlayout') !== -1) {
|
|
||||||
window.minder.execCommand('resetlayout');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,261 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="font-group ml-[10px]">
|
|
||||||
<a-select
|
|
||||||
v-model="fontFamilyDefaultValue"
|
|
||||||
:placeholder="t('minder.menu.font.font')"
|
|
||||||
class="font-family-select"
|
|
||||||
:disabled="disabledFont"
|
|
||||||
size="mini"
|
|
||||||
@change="execCommandFontFamily"
|
|
||||||
>
|
|
||||||
<a-option
|
|
||||||
v-for="item in fontFamilys"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.name"
|
|
||||||
:value="item.value"
|
|
||||||
:style="{ 'font-family': item.value }"
|
|
||||||
/>
|
|
||||||
</a-select>
|
|
||||||
<a-select
|
|
||||||
v-model="fontSizeDefaultValue"
|
|
||||||
:placeholder="t('minder.menu.font.size')"
|
|
||||||
class="font-size-select"
|
|
||||||
:disabled="disabledFontSize"
|
|
||||||
size="mini"
|
|
||||||
@change="execCommandFontSize"
|
|
||||||
>
|
|
||||||
<a-option
|
|
||||||
v-for="item in fontSizes"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.label.toString()"
|
|
||||||
:value="item.value"
|
|
||||||
:style="{
|
|
||||||
'font-size': item.value + 'px',
|
|
||||||
'height': 2 * item.value + 'px',
|
|
||||||
'line-height': 2 * item.value + 'px',
|
|
||||||
'padding': 0,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</a-select>
|
|
||||||
<span class="font-btn mt-[2px]">
|
|
||||||
<span
|
|
||||||
class="menu-btn tab-icons font-bold"
|
|
||||||
:class="{ selected: boldSelected }"
|
|
||||||
:disabled="disabledBold"
|
|
||||||
@click="execCommandFontStyle('bold')"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="font-italic menu-btn tab-icons"
|
|
||||||
:class="{ selected: italicSelected }"
|
|
||||||
:disabled="disabledItalic"
|
|
||||||
@click="execCommandFontStyle('italic')"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="StyleOperation" setup>
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const fontFamilys = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: '宋体,SimSun',
|
|
||||||
name: '宋体',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
value: '微软雅黑,Microsoft YaHei',
|
|
||||||
name: '微软雅黑',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
value: '楷体,楷体_GB2312,SimKai',
|
|
||||||
name: '楷体',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
value: '黑体, SimHei',
|
|
||||||
name: '黑体',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
value: '隶书, SimLi',
|
|
||||||
name: '隶书',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
value: 'andale mono',
|
|
||||||
name: 'Andale Mono',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
value: 'arial,helvetica,sans-serif',
|
|
||||||
name: 'Arial',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
value: 'arial black,avant garde',
|
|
||||||
name: 'arialBlack',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
value: 'comic sans ms',
|
|
||||||
name: 'comic Sans Ms',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
value: 'impact,chicago',
|
|
||||||
name: 'Impact',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
value: 'times new roman',
|
|
||||||
name: 'times New Roman',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
value: 'sans-serif',
|
|
||||||
name: 'Sans-Serif',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const fontSizes = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
value: 10,
|
|
||||||
label: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
value: 12,
|
|
||||||
label: 12,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
value: 16,
|
|
||||||
label: 16,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
value: 18,
|
|
||||||
label: 18,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
value: 24,
|
|
||||||
label: 24,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
value: 32,
|
|
||||||
label: 32,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
value: 48,
|
|
||||||
label: 48,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const fontFamilyDefaultValue = ref('');
|
|
||||||
const fontSizeDefaultValue = ref('');
|
|
||||||
|
|
||||||
const disabledFont = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentFontFamily = window.minder.queryCommandValue('fontfamily');
|
|
||||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
||||||
fontFamilyDefaultValue.value = currentFontFamily || t('minder.menu.font.font');
|
|
||||||
return window.minder.queryCommandState('fontfamily') === -1;
|
|
||||||
});
|
|
||||||
const disabledFontSize = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
||||||
fontSizeDefaultValue.value = window.minder.queryCommandValue('fontsize') || t('minder.menu.font.size');
|
|
||||||
return window.minder.queryCommandState('fontsize') === -1;
|
|
||||||
});
|
|
||||||
const disabledBold = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState('bold') === -1;
|
|
||||||
});
|
|
||||||
const disabledItalic = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState('italic') === -1;
|
|
||||||
});
|
|
||||||
const boldSelected = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState('bold') === -1;
|
|
||||||
});
|
|
||||||
const italicSelected = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState('italic') === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
function execCommandFontFamily(
|
|
||||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
|
||||||
) {
|
|
||||||
if (value === t('minder.menu.font.font')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.minder.execCommand('fontfamily', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function execCommandFontSize(
|
|
||||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
|
||||||
) {
|
|
||||||
if (typeof value !== 'number') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.minder.execCommand('fontsize', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function execCommandFontStyle(style: string) {
|
|
||||||
switch (style) {
|
|
||||||
case 'bold':
|
|
||||||
if (window.minder.queryCommandState('bold') !== -1) {
|
|
||||||
window.minder.execCommand('bold');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'italic':
|
|
||||||
if (window.minder.queryCommandState('italic') !== -1) {
|
|
||||||
window.minder.execCommand('italic');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,93 +0,0 @@
|
||||||
<template>
|
|
||||||
<a-dropdown class="toggle" :disabled="disabled" @select="handleCommand">
|
|
||||||
<span class="dropdown-toggle mold-icons menu-btn cursor-pointer" :class="'mold-' + (moldIndex + 1)" />
|
|
||||||
<template #content>
|
|
||||||
<a-doption class="dropdown-item" :value="1">
|
|
||||||
<div class="mold-icons mold-1"></div>
|
|
||||||
</a-doption>
|
|
||||||
<a-doption class="dropdown-item" :value="2">
|
|
||||||
<div class="mold-icons mold-2"></div>
|
|
||||||
</a-doption>
|
|
||||||
<a-doption class="dropdown-item" :value="3">
|
|
||||||
<div class="mold-icons mold-3"></div>
|
|
||||||
</a-doption>
|
|
||||||
<a-doption class="dropdown-item" :value="4">
|
|
||||||
<div class="mold-icons mold-4"></div>
|
|
||||||
</a-doption>
|
|
||||||
<a-doption class="dropdown-item" :value="5">
|
|
||||||
<div class="mold-icons mold-5"></div>
|
|
||||||
</a-doption>
|
|
||||||
<a-doption class="dropdown-item" :value="6">
|
|
||||||
<div class="mold-icons mold-6"></div>
|
|
||||||
</a-doption>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="Mold" setup>
|
|
||||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
|
||||||
|
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
|
||||||
|
|
||||||
import { moleProps } from '../../props';
|
|
||||||
|
|
||||||
const props = defineProps(moleProps);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'moldChange', data: number): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const minderStore = useMinderStore();
|
|
||||||
const moldIndex = ref(0);
|
|
||||||
|
|
||||||
const disabled = computed(() => {
|
|
||||||
try {
|
|
||||||
if (!window.minder) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return window.minder.queryCommandState('template') === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
const templateList = computed(() => window.kityminder.Minder.getTemplateList());
|
|
||||||
|
|
||||||
function handleCommand(value: string | number | Record<string, any> | undefined) {
|
|
||||||
moldIndex.value = (value as number) - 1;
|
|
||||||
window.minder.execCommand('template', Object.keys(templateList.value)[(value as number) - 1]);
|
|
||||||
emit('moldChange', (value as number) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => handleCommand(props.defaultMold));
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
:deep(.arco-dropdown-list) {
|
|
||||||
@apply grid grid-cols-2;
|
|
||||||
}
|
|
||||||
.dropdown-toggle .mold-icons,
|
|
||||||
.mold-icons {
|
|
||||||
background-image: url('@/assets/images/minder/mold.png');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
.dropdown-item {
|
|
||||||
@apply flex items-center justify-center;
|
|
||||||
|
|
||||||
height: 50px !important;
|
|
||||||
}
|
|
||||||
.mold-loop(@i) when (@i > 0) {
|
|
||||||
.mold-@{i} {
|
|
||||||
@apply flex;
|
|
||||||
|
|
||||||
margin-top: 5px;
|
|
||||||
width: 50px;
|
|
||||||
height: 45px;
|
|
||||||
background-position: (1 - @i) * 50px 0;
|
|
||||||
}
|
|
||||||
.mold-loop(@i - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mold-loop(6);
|
|
||||||
</style>
|
|
|
@ -1,79 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="style-group">
|
|
||||||
<div class="clear-style-btn menu-btn" :disabled="disabled" @click="clearstyle">
|
|
||||||
<span class="tab-icons" />
|
|
||||||
<span class="label">
|
|
||||||
{{ t('minder.menu.style.clear') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="copy-paste-panel" @click="copystyle">
|
|
||||||
<div class="copy-style menu-btn" :disabled="disabled">
|
|
||||||
<span class="tab-icons" />
|
|
||||||
<span class="label">
|
|
||||||
{{ t('minder.menu.style.copy') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="paste-style menu-btn" :disabled="disabled" @click="pastestyle">
|
|
||||||
<span class="tab-icons" />
|
|
||||||
<span class="label">
|
|
||||||
{{ t('minder.menu.style.paste') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="StyleOperation" setup>
|
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
let minder = reactive<any>({});
|
|
||||||
const disabled = ref(true);
|
|
||||||
|
|
||||||
function checkDisabled() {
|
|
||||||
try {
|
|
||||||
if (Object.keys(minder).length === 0) return false;
|
|
||||||
} catch (e) {
|
|
||||||
// 如果window的还没挂载minder,先捕捉undefined异常
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const nodes = minder.getSelectedNodes && minder.getSelectedNodes();
|
|
||||||
disabled.value = nodes === null || nodes.length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
minder = window.minder;
|
|
||||||
minder.on('selectionchange', () => {
|
|
||||||
checkDisabled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function clearstyle() {
|
|
||||||
if (minder.queryCommandState && minder.execCommand && minder.queryCommandState('clearstyle') !== -1) {
|
|
||||||
minder.execCommand('clearstyle');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function copystyle() {
|
|
||||||
if (minder.queryCommandState && minder.execCommand && minder.queryCommandState('copystyle') !== -1) {
|
|
||||||
minder.execCommand('copystyle');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function pastestyle() {
|
|
||||||
if (minder.queryCommandState && minder.execCommand && minder.queryCommandState('pastestyle') !== -1) {
|
|
||||||
minder.execCommand('pastestyle');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.mold-dropdown-list .mold-icons,
|
|
||||||
.mold-icons {
|
|
||||||
background-image: url('@/assets/images/minder/mold.png');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="menu-container">
|
|
||||||
<mold v-if="moldEnable" :default-mold="props.defaultMold" @mold-change="handleMoldChange" />
|
|
||||||
<arrange v-if="arrangeEnable" />
|
|
||||||
<style-operation v-if="styleEnable" />
|
|
||||||
<font-operation v-if="fontEnable" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" name="viewMenu" setup>
|
|
||||||
import arrange from './arrange.vue';
|
|
||||||
import fontOperation from './fontOperation.vue';
|
|
||||||
import mold from './mold.vue';
|
|
||||||
import styleOperation from './styleOperation.vue';
|
|
||||||
|
|
||||||
import { moleProps, viewMenuProps } from '../../props';
|
|
||||||
|
|
||||||
const props = defineProps({ ...moleProps, ...viewMenuProps });
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'moldChange', data: number): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
function handleMoldChange(data: number) {
|
|
||||||
emit('moldChange', data);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.menu-container {
|
|
||||||
height: 60px;
|
|
||||||
i {
|
|
||||||
@apply inline-block;
|
|
||||||
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -37,6 +37,7 @@
|
||||||
import useMinderOperation from './hooks/useMinderOperation';
|
import useMinderOperation from './hooks/useMinderOperation';
|
||||||
import useShortCut from './hooks/useShortCut';
|
import useShortCut from './hooks/useShortCut';
|
||||||
import {
|
import {
|
||||||
|
batchMenuProps,
|
||||||
delProps,
|
delProps,
|
||||||
editMenuProps,
|
editMenuProps,
|
||||||
floatMenuProps,
|
floatMenuProps,
|
||||||
|
@ -50,13 +51,14 @@
|
||||||
tagProps,
|
tagProps,
|
||||||
viewMenuProps,
|
viewMenuProps,
|
||||||
} from './props';
|
} from './props';
|
||||||
import { isNodeInMinderView, setPriorityView } from './script/tool/utils';
|
import { isNodeInMinderView } from './script/tool/utils';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'moldChange', data: number): void;
|
(e: 'moldChange', data: number): void;
|
||||||
(e: 'save', data: MinderJson, callback: () => void): void;
|
(e: 'save', data: MinderJson, callback: () => void): void;
|
||||||
(e: 'afterMount'): void;
|
(e: 'afterMount'): void;
|
||||||
(e: 'nodeSelect', data: MinderJsonNode): void;
|
(e: 'nodeSelect', data: MinderJsonNode): void;
|
||||||
|
(e: 'nodeBatchSelect', data: MinderJsonNode[]): void;
|
||||||
(e: 'contentChange', data?: MinderJsonNode): void;
|
(e: 'contentChange', data?: MinderJsonNode): void;
|
||||||
(e: 'action', event: MinderCustomEvent): void;
|
(e: 'action', event: MinderCustomEvent): void;
|
||||||
(e: 'beforeExecCommand', event: MinderEvent): void;
|
(e: 'beforeExecCommand', event: MinderEvent): void;
|
||||||
|
@ -74,6 +76,7 @@
|
||||||
...tagProps,
|
...tagProps,
|
||||||
...delProps,
|
...delProps,
|
||||||
...viewMenuProps,
|
...viewMenuProps,
|
||||||
|
...batchMenuProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
const minderStore = useMinderStore();
|
const minderStore = useMinderStore();
|
||||||
|
@ -115,11 +118,7 @@
|
||||||
emit('save', data, callback);
|
emit('save', data, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { appendChildNode, appendSiblingNode, minderDelete } = useMinderOperation({
|
const { appendChildNode, appendSiblingNode, minderDelete, minderExpand } = useMinderOperation(props);
|
||||||
insertNode: props.insertNode,
|
|
||||||
canShowMoreMenuNodeOperation: props.canShowMoreMenuNodeOperation,
|
|
||||||
canShowPasteMenu: props.canShowPasteMenu,
|
|
||||||
});
|
|
||||||
const { unbindShortcuts } = useShortCut(
|
const { unbindShortcuts } = useShortCut(
|
||||||
{
|
{
|
||||||
undo: () => {
|
undo: () => {
|
||||||
|
@ -135,26 +134,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
delete: () => {
|
delete: () => {
|
||||||
if (props.canShowMoreMenuNodeOperation && !props.disabled) {
|
if (
|
||||||
|
(props.canShowDeleteMenu || (props.canShowMoreMenu && props.canShowMoreMenuNodeOperation)) &&
|
||||||
|
!props.disabled
|
||||||
|
) {
|
||||||
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
minderDelete(selectedNodes);
|
minderDelete(selectedNodes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expand: () => {
|
expand: () => {
|
||||||
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
if (selectedNodes.every((node) => node.isExpanded())) {
|
minderExpand(selectedNodes);
|
||||||
// 选中的节点集合全部展开,则全部收起
|
|
||||||
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: () => {
|
appendChildNode: () => {
|
||||||
if (props.insertSonMenus.length > 0 || props.insertNode) {
|
if (props.insertSonMenus.length > 0 || props.insertNode) {
|
||||||
|
@ -169,17 +159,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
props
|
||||||
insertNode: props.insertNode,
|
|
||||||
canShowMoreMenuNodeOperation: props.canShowMoreMenuNodeOperation,
|
|
||||||
canShowPasteMenu: props.canShowPasteMenu,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.minderProps = props;
|
window.minderProps = props;
|
||||||
useMinderEventListener({
|
useMinderEventListener({
|
||||||
handleSelectionChange: (node?: MinderJsonNode) => {
|
handleSelectionChange: (nodes: MinderJsonNode[]) => {
|
||||||
|
if (nodes && nodes.length > 1) {
|
||||||
|
emit('nodeBatchSelect', nodes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const node = nodes[0];
|
||||||
if (node) {
|
if (node) {
|
||||||
emit('nodeSelect', node);
|
emit('nodeSelect', node);
|
||||||
const box = node.getRenderBox();
|
const box = node.getRenderBox();
|
||||||
|
|
|
@ -102,6 +102,12 @@ export const priorityProps = {
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export const priorityColorMap: Record<number, string> = {
|
||||||
|
1: 'rgb(var(--danger-6))',
|
||||||
|
2: 'rgb(var(--link-6))',
|
||||||
|
3: 'rgb(var(--success-6))',
|
||||||
|
4: 'rgb(var(--warning-6))',
|
||||||
|
};
|
||||||
|
|
||||||
export interface MinderReplaceTag {
|
export interface MinderReplaceTag {
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
@ -133,7 +139,7 @@ export const tagProps = {
|
||||||
afterTagEdit: Function as PropType<(nodes: MinderJsonNode[], tag: string) => void>,
|
afterTagEdit: Function as PropType<(nodes: MinderJsonNode[], tag: string) => void>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface InsertMenuItem {
|
export interface MinderMenuItem {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
@ -146,14 +152,14 @@ export interface MoreMenuOtherOperationItem {
|
||||||
export const floatMenuProps = {
|
export const floatMenuProps = {
|
||||||
// 插入同级选项
|
// 插入同级选项
|
||||||
insertSiblingMenus: {
|
insertSiblingMenus: {
|
||||||
type: Array as PropType<InsertMenuItem[]>,
|
type: Array as PropType<MinderMenuItem[]>,
|
||||||
default() {
|
default() {
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 插入子级选项
|
// 插入子级选项
|
||||||
insertSonMenus: {
|
insertSonMenus: {
|
||||||
type: Array as PropType<InsertMenuItem[]>,
|
type: Array as PropType<MinderMenuItem[]>,
|
||||||
default() {
|
default() {
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
@ -210,6 +216,31 @@ export const floatMenuProps = {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export const batchMenuProps = {
|
||||||
|
canShowMoreBatchMenu: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
canShowBatchCopy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
canShowBatchCut: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
canShowBatchDelete: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
canShowBatchExpand: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
customBatchExpand: {
|
||||||
|
type: Function as PropType<(node: MinderJsonNode) => void>,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const editMenuProps = {
|
export const editMenuProps = {
|
||||||
sequenceEnable: {
|
sequenceEnable: {
|
||||||
|
|
|
@ -201,4 +201,5 @@ export default {
|
||||||
'common.jump': 'Jump',
|
'common.jump': 'Jump',
|
||||||
'common.gotIt': 'Got it',
|
'common.gotIt': 'Got it',
|
||||||
'common.inputPleaseEnterTags': 'Please enter the update tag enter add, not more than 64 characters',
|
'common.inputPleaseEnterTags': 'Please enter the update tag enter add, not more than 64 characters',
|
||||||
|
'common.cutSuccess': 'Cut successfully',
|
||||||
};
|
};
|
||||||
|
|
|
@ -200,4 +200,5 @@ export default {
|
||||||
'common.jump': '跳转',
|
'common.jump': '跳转',
|
||||||
'common.gotIt': '知道了',
|
'common.gotIt': '知道了',
|
||||||
'common.inputPleaseEnterTags': '请输入更新标签回车添加,不得超过64字符',
|
'common.inputPleaseEnterTags': '请输入更新标签回车添加,不得超过64字符',
|
||||||
|
'common.cutSuccess': '剪切成功',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
'login.form.title': 'Modern, open-source test management and interface testing tools',
|
'login.form.title': 'Open Source Continuous Testing Tools',
|
||||||
'login.form.userName.errMsg': 'Username cannot be empty',
|
'login.form.userName.errMsg': 'Username cannot be empty',
|
||||||
'login.form.password.errMsg': 'Password cannot be empty',
|
'login.form.password.errMsg': 'Password cannot be empty',
|
||||||
'login.form.login.errMsg': 'Login error, refresh and try again',
|
'login.form.login.errMsg': 'Login error, refresh and try again',
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
'login.form.title': '现代化、开源的测试管理和接口测试工具',
|
'login.form.title': '开源持续测试工具',
|
||||||
'login.form.userName.errMsg': '用户名不能为空',
|
'login.form.userName.errMsg': '用户名不能为空',
|
||||||
'login.form.password.errMsg': '密码不能为空',
|
'login.form.password.errMsg': '密码不能为空',
|
||||||
'login.form.login.errMsg': '登录出错,请刷新重试',
|
'login.form.login.errMsg': '登录出错,请刷新重试',
|
||||||
|
|
Loading…
Reference in New Issue