feat(组件): 脑图支持新功能&部分组件调整
This commit is contained in:
parent
17215a686e
commit
bff4a60c58
|
@ -90,5 +90,16 @@ export default {
|
|||
priority: 'Priority',
|
||||
tag: 'Tag',
|
||||
},
|
||||
hotboxMenu: {
|
||||
expand: 'Expand/Collapse',
|
||||
insetParent: 'Insert one level up',
|
||||
insetSon: 'Insert next level',
|
||||
insetBrother: 'Insert sibling',
|
||||
copy: 'Copy',
|
||||
cut: 'Cut',
|
||||
paste: 'Paste',
|
||||
delete: 'Delete',
|
||||
enterNode: 'Enter the current node',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -84,5 +84,16 @@ export default {
|
|||
priority: '优先级',
|
||||
tag: '标签',
|
||||
},
|
||||
hotboxMenu: {
|
||||
expand: '展开/收起',
|
||||
insetParent: '插入上一级',
|
||||
insetSon: '插入下一级',
|
||||
insetBrother: '插入同级',
|
||||
copy: '复制',
|
||||
cut: '剪切',
|
||||
paste: '粘贴',
|
||||
delete: '删除',
|
||||
enterNode: '进入当前节点',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<edit-menu
|
||||
:minder="minder"
|
||||
:move-enable="props.moveEnable"
|
||||
:move-confirm="props.moveConfirm"
|
||||
:sequence-enable="props.sequenceEnable"
|
||||
:tag-enable="props.tagEnable"
|
||||
:progress-enable="props.progressEnable"
|
||||
|
|
|
@ -1,18 +1,96 @@
|
|||
<template>
|
||||
<div ref="mec" class="minder-container" :style="{ height: `${props.height}px` }">
|
||||
<a-button type="primary" :disabled="props.disabled" class="save-btn bottom-[30px] right-[30px]" @click="save">{{
|
||||
t('minder.main.main.save')
|
||||
}}</a-button>
|
||||
<a-button type="primary" :disabled="props.disabled" class="save-btn bottom-[30px] right-[30px]" @click="save">
|
||||
{{ t('minder.main.main.save') }}
|
||||
</a-button>
|
||||
<navigator />
|
||||
<a-dropdown
|
||||
v-model:popup-visible="menuVisible"
|
||||
class="minder-dropdown"
|
||||
position="bl"
|
||||
:popup-translate="menuPopupOffset"
|
||||
@select="handleMinderMenuSelect"
|
||||
>
|
||||
<span></span>
|
||||
<template #content>
|
||||
<a-doption 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>
|
||||
<a-doption value="insetParent">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.insetParent') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Shift + Tab)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption value="insetSon">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Tab)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption value="insetBrother">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.insetBrother') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Enter)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption 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 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 value="paste">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.paste') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl + V)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
<a-doption 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 value="enterNode">
|
||||
<div class="flex items-center">
|
||||
<div>{{ t('minder.hotboxMenu.enterNode') }}</div>
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">(Ctrl+ Enter)</div>
|
||||
</div>
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<div
|
||||
v-if="innerImportJson.treePath?.length > 1"
|
||||
class="absolute left-[50%] top-[24px] z-50 translate-x-[-50%] bg-white p-[8px]"
|
||||
>
|
||||
<a-breadcrumb>
|
||||
<a-breadcrumb-item v-for="crumb of innerImportJson.treePath" :key="crumb.name" @click="switchNode(crumb)">
|
||||
{{ crumb.text }}
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="minderContainer" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import Navigator from './navigator.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
import { findNodePathByKey } from '@/utils';
|
||||
|
||||
import { editMenuProps, mainEditorProps, priorityProps, tagProps } from '../props';
|
||||
import Editor from '../script/editor';
|
||||
|
@ -25,9 +103,12 @@
|
|||
const emit = defineEmits({
|
||||
afterMount: () => ({}),
|
||||
save: (json) => json,
|
||||
enterNode: (data) => data,
|
||||
});
|
||||
|
||||
const minderStore = useMinderStore();
|
||||
const mec: Ref<HTMLDivElement | null> = ref(null);
|
||||
const innerImportJson = ref<any>({});
|
||||
|
||||
function save() {
|
||||
emit('save', window.minder.exportJson());
|
||||
|
@ -129,6 +210,80 @@
|
|||
onMounted(async () => {
|
||||
init();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.importJson,
|
||||
(val) => {
|
||||
innerImportJson.value = val;
|
||||
window.minder.importJson(val);
|
||||
}
|
||||
);
|
||||
|
||||
const menuVisible = ref(false);
|
||||
const menuPopupOffset = ref([0, 0]);
|
||||
|
||||
function switchNode(node: any) {
|
||||
innerImportJson.value = cloneDeep(findNodePathByKey([props.importJson.root], node.id, 'data', 'id'));
|
||||
innerImportJson.value.data.expandState = 'expand';
|
||||
window.minder.importJson(innerImportJson.value);
|
||||
window.minder.execCommand('template', Object.keys(window.kityminder.Minder.getTemplateList())[minderStore.mold]);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => minderStore.event.timestamp,
|
||||
() => {
|
||||
if (minderStore.event.name === 'hotbox') {
|
||||
const nodeDomWidth = minderStore.event.nodeDom?.getBoundingClientRect().width || 0;
|
||||
menuPopupOffset.value = [
|
||||
minderStore.event.nodePosition.x + nodeDomWidth / 2,
|
||||
minderStore.event.nodePosition.y - nodeDomWidth / 4,
|
||||
];
|
||||
menuVisible.value = true;
|
||||
}
|
||||
if (minderStore.event.name === 'enterNode') {
|
||||
switchNode(minderStore.event.nodeData);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function handleMinderMenuSelect(val: string | number | Record<string, any> | undefined) {
|
||||
const selectedNode = window.minder.getSelectedNode();
|
||||
switch (val) {
|
||||
case 'expand':
|
||||
if (selectedNode.data.expandState === 'collapse') {
|
||||
window.minder.execCommand('Expand');
|
||||
} else {
|
||||
window.minder.execCommand('Collapse');
|
||||
}
|
||||
break;
|
||||
case 'insetParent':
|
||||
window.minder.execCommand('AppendParentNode');
|
||||
break;
|
||||
case 'insetSon':
|
||||
window.minder.execCommand('AppendChildNode');
|
||||
break;
|
||||
case 'insetBrother':
|
||||
window.minder.execCommand('AppendSiblingNode');
|
||||
break;
|
||||
case 'copy':
|
||||
window.minder.execCommand('Copy');
|
||||
break;
|
||||
case 'cut':
|
||||
window.minder.execCommand('Cut');
|
||||
break;
|
||||
case 'paste':
|
||||
window.minder.execCommand('Paste');
|
||||
break;
|
||||
case 'delete':
|
||||
window.minder.execCommand('RemoveNode');
|
||||
break;
|
||||
case 'enterNode':
|
||||
switchNode(selectedNode.data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
@ -139,4 +294,9 @@
|
|||
.minder-container {
|
||||
@apply relative;
|
||||
}
|
||||
.minder-dropdown {
|
||||
.arco-dropdown-list-wrapper {
|
||||
max-height: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</a-button>
|
||||
{{ t('minder.menu.expand.folding') }}
|
||||
</div>
|
||||
<move-box :move-enable="props.moveEnable" />
|
||||
<move-box :move-enable="props.moveEnable" :move-confirm="props.moveConfirm" />
|
||||
<insert-box />
|
||||
<edit-del :del-confirm="props.delConfirm" />
|
||||
</div>
|
||||
|
@ -39,10 +39,14 @@
|
|||
: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';
|
||||
|
@ -51,9 +55,19 @@
|
|||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { delProps, editMenuProps, priorityProps, tagProps } from '../../props';
|
||||
import { delProps, editMenuProps, moleProps, priorityProps, tagProps, viewMenuProps } from '../../props';
|
||||
|
||||
const props = defineProps({ ...editMenuProps, ...priorityProps, ...tagProps, ...delProps });
|
||||
const props = defineProps({
|
||||
...editMenuProps,
|
||||
...priorityProps,
|
||||
...tagProps,
|
||||
...delProps,
|
||||
...viewMenuProps,
|
||||
...moleProps,
|
||||
});
|
||||
const emit = defineEmits<{
|
||||
(e: 'moldChange', data: number): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -94,4 +108,8 @@
|
|||
window.minder?.execCommand('ExpandToLevel', 1);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMoldChange(data: number) {
|
||||
emit('moldChange', data);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
const props = defineProps<{
|
||||
moveEnable: boolean;
|
||||
moveConfirm: any;
|
||||
}>();
|
||||
|
||||
let minder = reactive<any>({});
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
<template>
|
||||
<div class="mold-group" :disabled="disabled">
|
||||
<a-dropdown class="toggle" @select="handleCommand">
|
||||
<div>
|
||||
<span class="dropdown-toggle mold-icons menu-btn" :class="'mold-' + (moldIndex + 1)" />
|
||||
<span class="dropdown-link">
|
||||
<icon-caret-down />
|
||||
</span>
|
||||
</div>
|
||||
<template #content>
|
||||
<a-doption class="dropdown-item mold-icons mold-1" :value="1" />
|
||||
<a-doption class="dropdown-item mold-icons mold-2" :value="2" />
|
||||
<a-doption class="dropdown-item mold-icons mold-3" :value="3" />
|
||||
<a-doption class="dropdown-item mold-icons mold-4" :value="4" />
|
||||
<a-doption class="dropdown-item mold-icons mold-5" :value="5" />
|
||||
<a-doption class="dropdown-item mold-icons mold-6" :value="6" />
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<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);
|
||||
|
@ -30,6 +37,7 @@
|
|||
(e: 'moldChange', data: number): void;
|
||||
}>();
|
||||
|
||||
const minderStore = useMinderStore();
|
||||
const moldIndex = ref(0);
|
||||
|
||||
const disabled = computed(() => {
|
||||
|
@ -45,9 +53,10 @@
|
|||
const templateList = computed(() => window.kityminder.Minder.getTemplateList());
|
||||
|
||||
function handleCommand(value: string | number | Record<string, any> | undefined) {
|
||||
moldIndex.value = value as number;
|
||||
window.minder.execCommand('template', Object.keys(templateList.value)[value as number]);
|
||||
emit('moldChange', value as number);
|
||||
moldIndex.value = (value as number) - 1;
|
||||
window.minder.execCommand('template', Object.keys(templateList.value)[(value as number) - 1]);
|
||||
minderStore.setMold((value as number) - 1);
|
||||
emit('moldChange', (value as number) - 1);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -55,40 +64,19 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.toggle {
|
||||
.arco-dropdown-list {
|
||||
@apply grid grid-cols-2;
|
||||
|
||||
padding: 5px;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<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;
|
||||
}
|
||||
.mold-group {
|
||||
@apply relative flex items-center justify-center;
|
||||
.dropdown-item {
|
||||
@apply flex items-center justify-center;
|
||||
|
||||
width: 80px;
|
||||
.dropdown-toggle {
|
||||
@apply flex;
|
||||
|
||||
margin-top: 5px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
.dropdown-link {
|
||||
@apply absolute cursor-pointer;
|
||||
|
||||
right: 3px;
|
||||
bottom: 2px;
|
||||
height: 50px !important;
|
||||
}
|
||||
.mold-loop(@i) when (@i > 0) {
|
||||
.mold-@{i} {
|
||||
|
@ -96,7 +84,7 @@
|
|||
|
||||
margin-top: 5px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
height: 45px;
|
||||
background-position: (1 - @i) * 50px 0;
|
||||
}
|
||||
.mold-loop(@i - 1);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
:priority-start-with-zero="props.priorityStartWithZero"
|
||||
:tags="props.tags"
|
||||
:move-enable="props.moveEnable"
|
||||
:move-confirm="props.moveConfirm"
|
||||
:tag-edit-check="props.tagEditCheck"
|
||||
:tag-disable-check="props.tagDisableCheck"
|
||||
:priority-disable-check="props.priorityDisableCheck"
|
||||
|
@ -26,6 +27,7 @@
|
|||
:sequence-enable="props.sequenceEnable"
|
||||
:tag-enable="props.tagEnable"
|
||||
:move-enable="props.moveEnable"
|
||||
:move-confirm="props.moveConfirm"
|
||||
:progress-enable="props.progressEnable"
|
||||
:import-json="props.importJson"
|
||||
:height="props.height"
|
||||
|
@ -38,6 +40,7 @@
|
|||
:priority-start-with-zero="props.priorityStartWithZero"
|
||||
@after-mount="emit('afterMount')"
|
||||
@save="save"
|
||||
@enter-node="handleEnterNode"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -54,6 +57,8 @@
|
|||
(e: 'moldChange', data: number): void;
|
||||
(e: 'save', data: Record<string, any>): void;
|
||||
(e: 'afterMount'): void;
|
||||
(e: 'enterNode', data: any): void;
|
||||
(e: 'nodeClick', data: any): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -73,7 +78,28 @@
|
|||
function handleMoldChange(data: number) {
|
||||
emit('moldChange', data);
|
||||
}
|
||||
|
||||
function save(data: Record<string, any>) {
|
||||
emit('save', data);
|
||||
}
|
||||
|
||||
function handleEnterNode(data: any) {
|
||||
emit('enterNode', data);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (window.minder.on) {
|
||||
window.minder.on('mousedown', (e: any) => {
|
||||
if (e.originEvent.button === 0) {
|
||||
// 鼠标左键点击
|
||||
const selectedNode = window.minder.getSelectedNode();
|
||||
if (Object.keys(window.minder).length > 0 && selectedNode) {
|
||||
emit('nodeClick', selectedNode.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,25 +7,9 @@ export const mainEditorProps = {
|
|||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
root: {
|
||||
data: {
|
||||
text: 'test111',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
text: '地图',
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
text: '百科',
|
||||
expandState: 'collapse',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
root: {},
|
||||
template: 'default',
|
||||
treePath: [] as any[],
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -95,6 +79,10 @@ export const editMenuProps = {
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
moveConfirm: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
||||
export const moleProps = {
|
||||
|
|
|
@ -16,20 +16,20 @@ const MimeType = () => {
|
|||
'\uFFFF': 'application/km',
|
||||
};
|
||||
|
||||
function getSpitor(): string {
|
||||
function getSplitor(): string {
|
||||
return SPLITOR;
|
||||
}
|
||||
|
||||
function isPureText(text: string): boolean {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return !~text.indexOf(getSpitor());
|
||||
return !~text.indexOf(getSplitor());
|
||||
}
|
||||
|
||||
function getPureText(text: string): string {
|
||||
if (isPureText(text)) {
|
||||
return text;
|
||||
}
|
||||
return text.split(getSpitor())[1];
|
||||
return text.split(getSplitor())[1];
|
||||
}
|
||||
|
||||
function getMimeType(sign?: string): MimeTypes | string | null {
|
||||
|
@ -43,7 +43,7 @@ const MimeType = () => {
|
|||
if (isPureText(text)) {
|
||||
return null;
|
||||
}
|
||||
return getMimeType(text.split(getSpitor())[0]);
|
||||
return getMimeType(text.split(getSplitor())[0]);
|
||||
}
|
||||
|
||||
function process(mimetype: string | false, text: string): string {
|
||||
|
@ -84,8 +84,12 @@ const MimeType = () => {
|
|||
return {
|
||||
registerMimeTypeProtocol,
|
||||
getMimeTypeProtocol,
|
||||
getSpitor,
|
||||
getSplitor,
|
||||
getMimeType,
|
||||
whichMimeType,
|
||||
process,
|
||||
getPureText,
|
||||
isPureText,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -13,10 +13,6 @@ interface IData {
|
|||
};
|
||||
}
|
||||
|
||||
interface ICliboardEvent extends ClipboardEvent {
|
||||
clipboardData: DataTransfer;
|
||||
}
|
||||
|
||||
export default function ClipboardRuntime(this: any) {
|
||||
const { minder } = this;
|
||||
const { receiver } = this;
|
||||
|
@ -38,11 +34,10 @@ export default function ClipboardRuntime(this: any) {
|
|||
return kmencode(Data.getRegisterProtocol('json').encode(_nodes));
|
||||
}
|
||||
|
||||
const beforeCopy = (e: ICliboardEvent) => {
|
||||
const beforeCopy = (e: ClipboardEvent) => {
|
||||
if (document.activeElement === receiver.element) {
|
||||
const clipBoardEvent = e;
|
||||
const state = this.fsm.state();
|
||||
|
||||
switch (state) {
|
||||
case 'input': {
|
||||
break;
|
||||
|
@ -80,7 +75,7 @@ export default function ClipboardRuntime(this: any) {
|
|||
}
|
||||
}
|
||||
const str = encode(nodes);
|
||||
clipBoardEvent.clipboardData.setData('text/plain', str);
|
||||
clipBoardEvent.clipboardData?.setData('text/plain', str);
|
||||
}
|
||||
e.preventDefault();
|
||||
break;
|
||||
|
@ -193,7 +188,7 @@ export default function ClipboardRuntime(this: any) {
|
|||
* @Editor: Naixor
|
||||
* @Date: 2015.9.24
|
||||
*/
|
||||
document.addEventListener('copy', () => beforeCopy);
|
||||
document.addEventListener('cut', () => beforeCut);
|
||||
document.addEventListener('paste', () => beforePaste);
|
||||
document.addEventListener('copy', (e) => beforeCopy(e));
|
||||
document.addEventListener('cut', (e) => beforeCut(e));
|
||||
document.addEventListener('paste', (e) => beforePaste(e));
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class FSM {
|
|||
}
|
||||
|
||||
const oldState = this.currentState;
|
||||
const notify = [oldState, newState].concat([].slice.call(args, 1));
|
||||
const notify = [oldState, newState].concat([reason, args[0]]);
|
||||
let i;
|
||||
let handler;
|
||||
|
||||
|
@ -67,7 +67,6 @@ class FSM {
|
|||
|
||||
this.currentState = newState;
|
||||
this.debug.log('[{0}] {1} -> {2}', reason, oldState, newState);
|
||||
|
||||
// 跳转后
|
||||
for (i = 0; i < this.handlers.length; i++) {
|
||||
handler = this.handlers[i];
|
||||
|
@ -99,8 +98,9 @@ class FSM {
|
|||
* * to - 跳转后的状态
|
||||
* * reason - 跳转的原因
|
||||
*/
|
||||
public when(condition: string, handler: Handler | string): void {
|
||||
if (arguments.length === 1) {
|
||||
public when(...args: any[]): void {
|
||||
let [condition, handler] = args;
|
||||
if (args.length === 1) {
|
||||
handler = condition;
|
||||
condition = '* -> *';
|
||||
}
|
||||
|
@ -138,8 +138,8 @@ class FSM {
|
|||
}
|
||||
}
|
||||
|
||||
function FSMRumtime(this: any) {
|
||||
function FSMRuntime(this: any) {
|
||||
this.fsm = new FSM('normal');
|
||||
}
|
||||
|
||||
export default FSMRumtime;
|
||||
export default FSMRuntime;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
|
||||
interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -10,10 +12,11 @@ function HotboxRuntime(this: any) {
|
|||
const { container } = this;
|
||||
const { HotBox } = window;
|
||||
const hotbox = new HotBox(container);
|
||||
const minderStore = useMinderStore();
|
||||
|
||||
hotbox.setParentFSM(fsm);
|
||||
|
||||
fsm.when('normal -> hotbox', () => {
|
||||
function handleHotBoxShow() {
|
||||
const node = minder.getSelectedNode();
|
||||
let position: Position | undefined;
|
||||
if (node) {
|
||||
|
@ -22,18 +25,46 @@ function HotboxRuntime(this: any) {
|
|||
x: box.cx,
|
||||
y: box.cy,
|
||||
};
|
||||
minderStore.dispatchEvent('hotbox', position, node.rc.node);
|
||||
}
|
||||
hotbox.active('main', position);
|
||||
}
|
||||
|
||||
fsm.when('normal -> hotbox', () => {
|
||||
handleHotBoxShow();
|
||||
});
|
||||
|
||||
fsm.when('hotbox -> hotbox', () => {
|
||||
handleHotBoxShow();
|
||||
});
|
||||
|
||||
function handleShortcut(e: any) {
|
||||
// 检查是否按下Ctrl键(Windows和Linux)或Command键(Mac)
|
||||
const isCtrlKey = e.ctrlKey || e.metaKey;
|
||||
// 检查是否按下Enter键
|
||||
const isEnterKey = e.key === 'Enter';
|
||||
// 检查是否同时按下Ctrl(或Command)和Enter键
|
||||
if (isCtrlKey && isEnterKey) {
|
||||
// 处理Ctrl+Enter组合键事件
|
||||
e.preventDefault(); // 阻止默认行为
|
||||
// 执行进入模块方法
|
||||
const node = minder.getSelectedNode();
|
||||
let position: Position | undefined;
|
||||
if (node) {
|
||||
const box = node.getRenderBox();
|
||||
position = {
|
||||
x: box.cx,
|
||||
y: box.cy,
|
||||
};
|
||||
minderStore.dispatchEvent('enterNode', position, node.rc.node, node.data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
minder.dispatchKeyEvent(e);
|
||||
}
|
||||
|
||||
fsm.when('normal -> normal', (exit: any, enter: any, reason: any, e: any) => {
|
||||
if (reason === 'shortcut-handle') {
|
||||
const handleResult = hotbox.dispatch(e);
|
||||
if (handleResult) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
minder.dispatchKeyEvent(e);
|
||||
}
|
||||
handleShortcut(e);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ function isIntendToInput(e: KeyboardEvent): boolean {
|
|||
function JumpingRuntime(this: IJumpingRuntime): void {
|
||||
const { fsm, minder, receiver, container, hotbox } = this;
|
||||
const receiverElement = receiver.element;
|
||||
|
||||
// normal -> *
|
||||
receiver.listen('normal', (e: KeyboardEvent) => {
|
||||
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
|
||||
|
@ -141,6 +140,7 @@ function JumpingRuntime(this: IJumpingRuntime): void {
|
|||
/// ///////////////////////////////////////////
|
||||
let downX: number;
|
||||
let downY: number;
|
||||
const MOUSE_LB = 1; // 左键
|
||||
const MOUSE_RB = 2; // 右键
|
||||
|
||||
container.addEventListener(
|
||||
|
@ -149,10 +149,10 @@ function JumpingRuntime(this: IJumpingRuntime): void {
|
|||
if (e.button === MOUSE_RB) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (fsm.state() === 'hotbox') {
|
||||
hotbox.active(HotBox.STATE_IDLE);
|
||||
|
||||
if (fsm.state() === 'hotbox' && e.button === MOUSE_LB) {
|
||||
fsm.jump('normal', 'blur');
|
||||
} else if (fsm.state() === 'normal' && e.button === MOUSE_RB) {
|
||||
} else if (e.button === MOUSE_RB) {
|
||||
downX = e.clientX;
|
||||
downY = e.clientY;
|
||||
}
|
||||
|
@ -164,7 +164,6 @@ function JumpingRuntime(this: IJumpingRuntime): void {
|
|||
'mousewheel',
|
||||
() => {
|
||||
if (fsm.state() === 'hotbox') {
|
||||
hotbox.active(HotBox.STATE_IDLE);
|
||||
fsm.jump('normal', 'mousemove-blur');
|
||||
}
|
||||
},
|
||||
|
@ -178,14 +177,14 @@ function JumpingRuntime(this: IJumpingRuntime): void {
|
|||
container.addEventListener(
|
||||
'mouseup',
|
||||
(e) => {
|
||||
if (fsm.state() !== 'normal') {
|
||||
if (fsm.state() !== 'normal' && e.button === MOUSE_LB) {
|
||||
return;
|
||||
}
|
||||
if (e.button !== MOUSE_RB || e.clientX !== downX || e.clientY !== downY) {
|
||||
return;
|
||||
}
|
||||
if (!minder.getSelectedNode()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
fsm.jump('hotbox', 'content-menu');
|
||||
},
|
||||
|
|
|
@ -50,6 +50,13 @@ export default function NodeRuntime(this: { minder: any; hotbox: any; editText:
|
|||
return;
|
||||
}
|
||||
markDeleteNode(minder);
|
||||
} else if (command.indexOf('ArrangeUp') > -1 || command.indexOf('ArrangeDown') > -1) {
|
||||
if (
|
||||
!window.minderProps.moveEnable ||
|
||||
(window.minderProps.moveConfirm && !window.minderProps.moveConfirm())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
minder.execCommand(command);
|
||||
}
|
||||
|
|
|
@ -11,33 +11,7 @@ function ReceiverRuntime(this: any) {
|
|||
|
||||
// 侦听器,接收到的事件会派发给所有侦听器
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const listeners: ((event: KeyboardEvent) => boolean)[] = [];
|
||||
|
||||
const dispatchKeyEvent = (e: KeyboardEvent) => {
|
||||
(e as any).is = (keyExpression: string) => {
|
||||
const subs = keyExpression.split('|');
|
||||
for (let i = 0; i < subs.length; i++) {
|
||||
if (key.is(this, subs[i])) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
let listener;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
listener = listeners[i];
|
||||
// 忽略不在侦听状态的侦听器
|
||||
if ((listener as any).notifyState !== '*' && (listener as any).notifyState !== this.fsm.state()) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listener.call(null, e)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
element.onkeydown = element.onkeypress = element.onkeyup = dispatchKeyEvent;
|
||||
this.container.appendChild(element);
|
||||
const listeners: (((event: KeyboardEvent) => boolean) | string)[] = [];
|
||||
|
||||
interface Receiver {
|
||||
element: HTMLDivElement;
|
||||
|
@ -48,7 +22,7 @@ function ReceiverRuntime(this: any) {
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
onblur(handler: (event: FocusEvent) => void): void;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
listen?(state: string, listener: (event: KeyboardEvent) => boolean): void;
|
||||
listen?(state: string, listener: ((event: KeyboardEvent) => boolean) | string): void;
|
||||
}
|
||||
|
||||
// receiver 对象
|
||||
|
@ -76,11 +50,47 @@ function ReceiverRuntime(this: any) {
|
|||
element.blur();
|
||||
element.focus();
|
||||
},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
onblur(handler: (event: FocusEvent) => void) {
|
||||
element.onblur = handler;
|
||||
},
|
||||
};
|
||||
|
||||
// 侦听指定状态下的事件,如果不传 state,侦听所有状态
|
||||
receiver.listen = (...args) => {
|
||||
let [state, listener] = args;
|
||||
if (args.length <= 1) {
|
||||
listener = state;
|
||||
state = '*';
|
||||
}
|
||||
(listener as any).notifyState = state;
|
||||
listeners.push(listener as any);
|
||||
};
|
||||
|
||||
const dispatchKeyEvent = (e: KeyboardEvent) => {
|
||||
(e as any).is = (keyExpression: string) => {
|
||||
const subs = keyExpression.split('|');
|
||||
for (let i = 0; i < subs.length; i++) {
|
||||
if (key.is(this, subs[i])) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
const listener = listeners[i];
|
||||
// 忽略不在侦听状态的侦听器
|
||||
if ((listener as any).notifyState !== '*' && (listener as any).notifyState !== this.fsm.state()) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof listener === 'function' && listener.call(null, e)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
element.onkeydown = element.onkeypress = element.onkeyup = dispatchKeyEvent;
|
||||
this.container.appendChild(element);
|
||||
|
||||
receiver.selectAll();
|
||||
this.minder.on('beforemousedown', receiver.selectAll);
|
||||
this.minder.on('receiverfocus', receiver.selectAll);
|
||||
|
@ -91,22 +101,6 @@ function ReceiverRuntime(this: any) {
|
|||
window.editor.hotbox.$container.removeChild(window.editor.hotbox.$element);
|
||||
});
|
||||
|
||||
// 侦听指定状态下的事件,如果不传 state,侦听所有状态
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
receiver.listen = (state: string, listener: ((event: KeyboardEvent) => boolean) | string) => {
|
||||
if (arguments.length === 1) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
listener = state;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
state = '*';
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
if (typeof listener === 'function') {
|
||||
(listener as any).notifyState = state;
|
||||
}
|
||||
listeners.push(listener as any);
|
||||
};
|
||||
|
||||
this.receiver = receiver as any;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useTableStore } from '@/store';
|
||||
import { TableOpenDetailMode } from '@/store/modules/ms-table/types';
|
||||
import { TableOpenDetailMode } from '@/store/modules/components/ms-table/types';
|
||||
|
||||
import { MsTableColumn } from './type';
|
||||
import Draggable from 'vuedraggable';
|
||||
|
@ -219,3 +219,4 @@
|
|||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@/store/modules/components/ms-table/types
|
||||
|
|
|
@ -4,7 +4,7 @@ import localforage from 'localforage';
|
|||
import { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type';
|
||||
|
||||
import { useAppStore } from '@/store';
|
||||
import { PageSizeMap, SelectorColumnMap, TableOpenDetailMode } from '@/store/modules/ms-table/types';
|
||||
import { PageSizeMap, SelectorColumnMap, TableOpenDetailMode } from '@/store/modules/components/ms-table/types';
|
||||
import { isArraysEqualWithOrder } from '@/utils/equal';
|
||||
|
||||
import { SpecialColumnEnum } from '@/enums/tableEnum';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export default {
|
||||
'common.pleaseSelectMember': 'Please select member',
|
||||
'common.pleaseSelectMember': 'Please select a member',
|
||||
'common.add': 'Add',
|
||||
'common.saveAndContinue': 'Save & Continue',
|
||||
'common.saveAndContinue': 'Save & continue',
|
||||
'common.edit': 'Edit',
|
||||
'common.delete': 'Delete',
|
||||
'common.save': 'Save',
|
||||
|
@ -17,6 +17,23 @@ export default {
|
|||
'common.close': 'Close',
|
||||
'common.create': 'Create',
|
||||
'common.update': 'Update',
|
||||
'common.all': 'All',
|
||||
'common.operation': 'Operation',
|
||||
'common.remove': 'Remove',
|
||||
'common.revoked': 'Revoked',
|
||||
'common.createSuccess': 'Create success',
|
||||
'common.createFailed': 'Create failed',
|
||||
'common.updateSuccess': 'Update success',
|
||||
'common.updateFailed': 'Update failed',
|
||||
'common.deleteConfirm': 'Delete confirm',
|
||||
'common.deleteSuccess': 'Delete success',
|
||||
'common.deleteFailed': 'Delete failed',
|
||||
'common.addSuccess': 'Added successfully',
|
||||
'common.addFailed': 'Add failed',
|
||||
'common.editSuccess': 'Edit success',
|
||||
'common.editFailed': 'Edit failed',
|
||||
'common.saveSuccess': 'Save success',
|
||||
'common.saveFailed': 'Save failed',
|
||||
'common.confirmEnable': 'Confirm enable',
|
||||
'common.confirmDisable': 'Confirm disable',
|
||||
'common.confirmClose': 'Confirm close',
|
||||
|
@ -25,21 +42,6 @@ export default {
|
|||
'common.enableFailed': 'Enable failed',
|
||||
'common.closeSuccess': 'Close success',
|
||||
'common.closeFailed': 'Close failed',
|
||||
'common.updateSuccess': 'Update success',
|
||||
'common.updateFailed': 'Update failed',
|
||||
'common.all': 'All',
|
||||
'common.operation': 'Operation',
|
||||
'common.remove': 'Remove',
|
||||
'common.revoked': 'Revoked',
|
||||
'common.deleteConfirm': 'Confirm delete?',
|
||||
'common.deleteSuccess': 'Delete success',
|
||||
'common.deleteFailed': 'Delete failed',
|
||||
'common.addSuccess': 'Add success',
|
||||
'common.addFailed': 'Add failed',
|
||||
'common.editSuccess': 'Edit success',
|
||||
'common.editFailed': 'Edit failed',
|
||||
'common.saveSuccess': 'Save success',
|
||||
'common.saveFailed': 'Save failed',
|
||||
'common.operationSuccess': 'Operation success',
|
||||
'common.operationFailed': 'Operation failed',
|
||||
'common.removeSuccess': 'Remove success',
|
||||
|
@ -48,18 +50,20 @@ export default {
|
|||
'common.revokeDelete': 'Revoke delete',
|
||||
'common.revokeDeleteSuccess': 'Revoke delete success',
|
||||
'common.unSaveLeaveTitle': 'Leave this page?',
|
||||
'common.unSaveLeaveContent': 'The system may not save your changes',
|
||||
'common.unSaveLeaveContent': 'Your changes may not be saved',
|
||||
'common.leave': 'Leave',
|
||||
'common.rename': 'Rename',
|
||||
'common.noData': 'No data',
|
||||
'common.internal': 'Internal',
|
||||
'common.custom': 'Custom',
|
||||
'common.preview': 'Preview',
|
||||
'common.fullScreen': 'Full Screen',
|
||||
'common.offFullScreen': 'Exit',
|
||||
'common.allSelect': 'Select All',
|
||||
'common.fullScreen': 'Full screen',
|
||||
'common.offFullScreen': 'Off full screen',
|
||||
'common.allSelect': 'All select',
|
||||
'common.setting': 'Setting',
|
||||
'common.resetDefault': 'Restore default',
|
||||
'common.pleaseSelect': 'Please Select',
|
||||
'common.quickAddMember': 'Quick Add Member',
|
||||
'common.resetDefault': 'Reset default',
|
||||
'common.tagPlaceholder': 'Add tag and press Enter to end',
|
||||
'common.batchModify': 'Batch Edit',
|
||||
'common.pleaseSelect': 'please choose',
|
||||
'common.quickAddMember': 'Quickly add members',
|
||||
};
|
||||
|
|
|
@ -35,10 +35,10 @@ function setI18nLanguage(locale: LocaleType) {
|
|||
async function changeLocale(locale: LocaleType) {
|
||||
const globalI18n = i18n.global;
|
||||
const currentLocale = unref(globalI18n.locale);
|
||||
Message.loading(currentLocale === 'zh-CN' ? '语言切换中...' : 'Language switching...');
|
||||
if (currentLocale === locale) {
|
||||
return locale;
|
||||
}
|
||||
Message.loading(currentLocale === 'zh-CN' ? '语言切换中...' : 'Language switching...');
|
||||
|
||||
if (loadLocalePool.includes(locale)) {
|
||||
setI18nLanguage(locale);
|
||||
|
|
|
@ -4,11 +4,12 @@ import useTableStore from '@/hooks/useTableStore';
|
|||
|
||||
import useAppStore from './modules/app';
|
||||
import useVisitStore from './modules/app/visit';
|
||||
import useMinderStore from './modules/components/minder-editor';
|
||||
import useUserStore from './modules/user';
|
||||
import { debouncePlugin } from './plugins';
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
|
||||
const pinia = createPinia().use(debouncePlugin).use(piniaPluginPersistedstate);
|
||||
|
||||
export { useAppStore, useTableStore, useUserStore, useVisitStore };
|
||||
export { useAppStore, useMinderStore, useTableStore, useUserStore, useVisitStore };
|
||||
export default pinia;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import { MinderNodePosition, MinderState } from './types';
|
||||
|
||||
// 脑图组件的 store
|
||||
const useMinderStore = defineStore('minder', {
|
||||
state: (): MinderState => ({
|
||||
event: {
|
||||
name: '',
|
||||
timestamp: 0,
|
||||
nodePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
nodeDom: undefined,
|
||||
nodeData: undefined,
|
||||
},
|
||||
mold: 0,
|
||||
}),
|
||||
actions: {
|
||||
dispatchEvent(name: string, position: MinderNodePosition, nodeDom?: HTMLElement, nodeData?: Record<string, any>) {
|
||||
this.event = {
|
||||
name,
|
||||
timestamp: Date.now(),
|
||||
nodePosition: position,
|
||||
nodeDom,
|
||||
nodeData,
|
||||
};
|
||||
},
|
||||
setMold(val: number) {
|
||||
this.mold = val;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useMinderStore;
|
|
@ -0,0 +1,17 @@
|
|||
export interface MinderNodePosition {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface MinderEvent {
|
||||
name: string;
|
||||
timestamp: number;
|
||||
nodePosition: MinderNodePosition;
|
||||
nodeDom?: HTMLElement;
|
||||
nodeData?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface MinderState {
|
||||
event: MinderEvent;
|
||||
mold: number;
|
||||
}
|
|
@ -234,6 +234,32 @@ export function findNodeByKey<T>(trees: TreeNode<T>[], targetKey: string, custom
|
|||
return null; // 如果在整个树形数组中都没有找到匹配的节点,则返回 null
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 key 遍历树,并返回找到的节点路径和节点
|
||||
*/
|
||||
export function findNodePathByKey<T>(
|
||||
tree: TreeNode<T>[],
|
||||
targetKey: string,
|
||||
dataKey?: string,
|
||||
customKey = 'key'
|
||||
): TreeNode<T> | null {
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const node = tree[i];
|
||||
if (dataKey ? node[dataKey]?.[customKey] === targetKey : node[customKey] === targetKey) {
|
||||
return { ...node, treePath: [dataKey ? node[dataKey] : node] }; // 如果当前节点的 key 与目标 key 匹配,则返回当前节点
|
||||
}
|
||||
|
||||
if (Array.isArray(node.children) && node.children.length > 0) {
|
||||
const result = findNodePathByKey(node.children, targetKey, dataKey, customKey); // 递归在子节点中查找
|
||||
if (result) {
|
||||
result.treePath.unshift(dataKey ? node[dataKey] : node);
|
||||
return result; // 如果在子节点中找到了匹配的节点,则返回该节点
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 找出俩数组之间的差异项并返回
|
||||
* @param targetMap 目标项
|
||||
|
|
|
@ -33,13 +33,23 @@
|
|||
</div>
|
||||
</div>
|
||||
<FilterPanel v-show="isExpandFilter"></FilterPanel>
|
||||
<MinderEditor :tags="['模块', '用例', '前置条件', '备注', '步骤', '预期结果']" tag-enable sequence-enable />
|
||||
<MinderEditor
|
||||
:import-json="importJson"
|
||||
:tags="['模块', '用例', '前置条件', '备注', '步骤', '预期结果']"
|
||||
tag-enable
|
||||
sequence-enable
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
<MsDrawer v-model:visible="visible" :width="480" :mask="false">
|
||||
{{ nodeData.text }}
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MinderEditor from '@/components/pure/minder-editor/minderEditor.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import FilterPanel from '@/components/business/ms-filter-panel/searchForm.vue';
|
||||
|
||||
|
@ -65,6 +75,62 @@
|
|||
const isExpandFilterHandler = () => {
|
||||
isExpandFilter.value = !isExpandFilter.value;
|
||||
};
|
||||
|
||||
const visible = ref<boolean>(false);
|
||||
const nodeData = ref<any>({});
|
||||
|
||||
const importJson = ref<any>({});
|
||||
|
||||
function handleNodeClick(data: any) {
|
||||
if (data.resource && data.resource.includes('用例')) {
|
||||
visible.value = true;
|
||||
nodeData.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
importJson.value = {
|
||||
root: {
|
||||
data: {
|
||||
text: '测试用例',
|
||||
id: 'xxxx',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'sdasdas',
|
||||
text: '模块 1',
|
||||
resource: ['模块'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'dasdasda',
|
||||
text: '模块 2',
|
||||
expandState: 'collapse',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
id: 'frihofiuho3f',
|
||||
text: '用例 1',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
id: 'df09348f034f',
|
||||
text: ' 用例 2',
|
||||
resource: ['用例'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
template: 'default',
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<a-spin v-if="!projectVersionStatus" :loading="loading" class="h-full w-full">
|
||||
<a-spin v-if="!projectVersionStatus" :loading="loading" class="h-full w-full min-w-[930px]">
|
||||
<div class="flex h-full flex-col items-center p-[24px]">
|
||||
<div class="mt-[200px] text-[16px] font-medium text-[var(--color-text-1)]">
|
||||
{{ t('project.projectVersion.version') }}
|
||||
</div>
|
||||
<div class="mt-[16px] text-[var(--color-text-4)]">{{ t('project.projectVersion.tip') }}</div>
|
||||
<div class="mt-[24px] flex justify-between gap-[16px]">
|
||||
<div class="mt-[24px] grid grid-cols-3 gap-[16px]">
|
||||
<div class="tip-card">
|
||||
<img src="@/assets/images/project_assign.png" width="78" height="60" class="tip-icon" />
|
||||
<div>
|
||||
|
@ -61,8 +61,11 @@
|
|||
<template #statusTitle>
|
||||
<div class="flex items-center">
|
||||
{{ t('project.projectVersion.status') }}
|
||||
<a-popover :title="t('project.projectVersion.statusTip')" position="right">
|
||||
<a-popover position="rt">
|
||||
<icon-info-circle class="ml-[4px] hover:text-[rgb(var(--primary-5))]" size="16" />
|
||||
<template #title>
|
||||
<div class="w-[256px]"> {{ t('project.projectVersion.statusTip') }} </div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="mt-[12px] w-[256px] rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]">
|
||||
<div class="statusTipContent">
|
||||
|
@ -172,7 +175,7 @@
|
|||
:on-before-ok="handleBeforeLatestModalOk"
|
||||
class="p-[4px]"
|
||||
title-align="start"
|
||||
body-class="px-0 py-[8px]"
|
||||
body-class="p-0"
|
||||
:ok-text="t('common.confirmClose')"
|
||||
:ok-button-props="{ status: 'danger' }"
|
||||
@cancel="handleLatestModalCancel"
|
||||
|
@ -515,11 +518,11 @@
|
|||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
} else {
|
||||
await toggleVersionStatus(record.id);
|
||||
Message.success(t('project.projectVersion.open', { name: record.name }));
|
||||
loadList();
|
||||
return false;
|
||||
}
|
||||
await toggleVersionStatus(record.id);
|
||||
Message.success(t('project.projectVersion.open', { name: record.name }));
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
|
|
@ -14,7 +14,7 @@ export default {
|
|||
'project.projectVersion.openVersionSuccess': 'Activated successfully',
|
||||
'project.projectVersion.versionName': 'Version name',
|
||||
'project.projectVersion.status': 'Status',
|
||||
'project.projectVersion.latest': 'Latest version',
|
||||
'project.projectVersion.latest': 'Latest',
|
||||
'project.projectVersion.publishTime': 'Release time',
|
||||
'project.projectVersion.createTime': 'Creation time',
|
||||
'project.projectVersion.creator': 'Creator',
|
||||
|
@ -34,4 +34,7 @@ export default {
|
|||
'project.projectVersion.confirmCloseTipContent2': 'You can switch other versions to the latest version',
|
||||
'project.projectVersion.replaceVersionPlaceholder': 'Please select an alternative version',
|
||||
'project.projectVersion.latestVersionDeleteTip': 'The latest version cannot be deleted',
|
||||
'project.projectVersion.statusTip': 'After closing, the version information drop-down box will not be displayed.',
|
||||
'project.projectVersion.versionInfo': 'Version information example',
|
||||
'project.projectVersion.versionLatest': 'Latest',
|
||||
};
|
||||
|
|
|
@ -275,7 +275,10 @@
|
|||
const type = ref(''); // 操作类型
|
||||
const _module = ref(''); // 操作对象
|
||||
const content = ref(''); // 名称
|
||||
const time = ref<(Date | string | number)[]>([dayjs().subtract(1, 'M').valueOf(), dayjs().valueOf()]); // 操作时间
|
||||
const time = ref<(Date | string | number)[]>([
|
||||
dayjs().subtract(1, 'M').hour(0).minute(0).second(1).valueOf(),
|
||||
dayjs().valueOf(),
|
||||
]); // 操作时间
|
||||
const selectedTime = ref<Date | string | number | undefined>(''); // 日期选择器选中但未确认的时间
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue