feat: minder-editor脑图组件功能补齐&样式

This commit is contained in:
baiqi 2023-06-07 17:41:45 +08:00 committed by rubylliu
parent b8a3ed8ed6
commit d8d94a0c20
13 changed files with 214 additions and 185 deletions

View File

@ -5,11 +5,57 @@
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core' import '@vue/runtime-core'
export {} export {};
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink'] AAffix: typeof import('@arco-design/web-vue')['Affix'];
RouterView: typeof import('vue-router')['RouterView'] AAlert: typeof import('@arco-design/web-vue')['Alert'];
AAvatar: typeof import('@arco-design/web-vue')['Avatar'];
ABadge: typeof import('@arco-design/web-vue')['Badge'];
ABreadcrumb: typeof import('@arco-design/web-vue')['Breadcrumb'];
ABreadcrumbItem: typeof import('@arco-design/web-vue')['BreadcrumbItem'];
AButton: typeof import('@arco-design/web-vue')['Button'];
ACard: typeof import('@arco-design/web-vue')['Card'];
ACardMeta: typeof import('@arco-design/web-vue')['CardMeta'];
ACol: typeof import('@arco-design/web-vue')['Col'];
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider'];
ADivider: typeof import('@arco-design/web-vue')['Divider'];
ADoption: typeof import('@arco-design/web-vue')['Doption'];
ADrawer: typeof import('@arco-design/web-vue')['Drawer'];
ADropdown: typeof import('@arco-design/web-vue')['Dropdown'];
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber'];
ALayout: typeof import('@arco-design/web-vue')['Layout'];
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent'];
ALayoutFooter: typeof import('@arco-design/web-vue')['LayoutFooter'];
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider'];
ALink: typeof import('@arco-design/web-vue')['Link'];
AList: typeof import('@arco-design/web-vue')['List'];
AListItem: typeof import('@arco-design/web-vue')['ListItem'];
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta'];
AMenu: typeof import('@arco-design/web-vue')['Menu'];
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem'];
AModal: typeof import('@arco-design/web-vue')['Modal'];
AOption: typeof import('@arco-design/web-vue')['Option'];
APagination: typeof import('@arco-design/web-vue')['Pagination'];
APopover: typeof import('@arco-design/web-vue')['Popover'];
AResult: typeof import('@arco-design/web-vue')['Result'];
ARow: typeof import('@arco-design/web-vue')['Row'];
ASelect: typeof import('@arco-design/web-vue')['Select'];
ASkeleton: typeof import('@arco-design/web-vue')['Skeleton'];
ASkeletonLine: typeof import('@arco-design/web-vue')['SkeletonLine'];
ASkeletonShape: typeof import('@arco-design/web-vue')['SkeletonShape'];
ASpace: typeof import('@arco-design/web-vue')['Space'];
ASpin: typeof import('@arco-design/web-vue')['Spin'];
ASubMenu: typeof import('@arco-design/web-vue')['SubMenu'];
ASwitch: typeof import('@arco-design/web-vue')['Switch'];
ATabPane: typeof import('@arco-design/web-vue')['TabPane'];
ATabs: typeof import('@arco-design/web-vue')['Tabs'];
ATag: typeof import('@arco-design/web-vue')['Tag'];
ATooltip: typeof import('@arco-design/web-vue')['Tooltip'];
ATypographyParagraph: typeof import('@arco-design/web-vue')['TypographyParagraph'];
ATypographyText: typeof import('@arco-design/web-vue')['TypographyText'];
RouterLink: typeof import('vue-router')['RouterLink'];
RouterView: typeof import('vue-router')['RouterView'];
} }
} }

View File

@ -23,7 +23,16 @@
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="viewMenu" :title="t('minder.main.header.style')"> <a-tab-pane key="viewMenu" :title="t('minder.main.header.style')">
<div class="mind-tab-panel"> <div class="mind-tab-panel">
<view-menu :minder="minder" :default-mold="props.defaultMold" @mold-change="handleMoldChange" /> <view-menu
v-if="props.viewMenuEnable"
:minder="minder"
:default-mold="props.defaultMold"
:arrange-enable="props.arrangeEnable"
:mold-enable="props.moldEnable"
:font-enable="props.fontEnable"
:style-enable="props.styleEnable"
@mold-change="handleMoldChange"
/>
</div> </div>
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
@ -35,7 +44,7 @@
import editMenu from '../menu/edit/editMenu.vue'; import editMenu from '../menu/edit/editMenu.vue';
import viewMenu from '../menu/view/viewMenu.vue'; import viewMenu from '../menu/view/viewMenu.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { editMenuProps, moleProps, priorityProps, tagProps, delProps } from '../props'; import { editMenuProps, moleProps, priorityProps, tagProps, delProps, viewMenuProps } from '../props';
const { t } = useI18n(); const { t } = useI18n();
@ -45,6 +54,7 @@
...priorityProps, ...priorityProps,
...tagProps, ...tagProps,
...delProps, ...delProps,
...viewMenuProps,
minder: null, minder: null,
}); });
@ -59,10 +69,11 @@
</script> </script>
<style lang="less"> <style lang="less">
@import '../style/header'; @import '../style/header.less';
.mind_tab-content { .mind_tab-content {
.tab-icons { .tab-icons {
@apply bg-[url('@/assets/images/minder/icons.png')] bg-no-repeat; background-image: url('@/assets/images/minder/icons.png');
background-repeat: no-repeat;
} }
} }
</style> </style>

View File

@ -131,7 +131,7 @@
<style lang="less"> <style lang="less">
@import '../style/editor.less'; @import '../style/editor.less';
.save-btn { .save-btn {
@apply absolute; @apply !absolute;
} }
.minder-container { .minder-container {
@apply relative; @apply relative;

View File

@ -36,3 +36,15 @@
const props = defineProps({ ...editMenuProps, ...priorityProps, ...tagProps, ...delProps }); const props = defineProps({ ...editMenuProps, ...priorityProps, ...tagProps, ...delProps });
</script> </script>
<style lang="less" scoped>
.menu-container {
height: 60px;
i {
@apply inline-block;
width: 20px;
height: 20px;
}
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div :disabled="commandDisabled"> <div :disabled="commandDisabled">
<a-button class="delete-btn mx-[4px] my-0 h-[23px] w-[23px] !p-[2px]" shape="circle" @click="execCommand()"> <a-button class="delete-btn !mx-[4px] !my-0 !h-[23px] !w-[23px] !p-[2px]" shape="circle" @click="execCommand()">
<template #icon> <template #icon>
<icon-delete /> <icon-delete />
</template> </template>
@ -83,6 +83,8 @@
<style lang="less" scoped> <style lang="less" scoped>
.delete-btn { .delete-btn {
border-color: #909399;
background-color: #909399;
i { i {
width: 1em !important; width: 1em !important;
height: 1em !important; height: 1em !important;

View File

@ -57,7 +57,7 @@
<style lang="less"> <style lang="less">
.toggle { .toggle {
.arco-dropdown-list { .arco-dropdown-list {
@apply col-span-2 grid; @apply grid grid-cols-2;
padding: 5px; padding: 5px;
gap: 5px; gap: 5px;

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="menu-container"> <div class="menu-container">
<mold :default-mold="props.defaultMold" @mold-change="handleMoldChange" /> <mold v-if="moldEnable" :default-mold="props.defaultMold" @mold-change="handleMoldChange" />
<arrange /> <arrange v-if="arrangeEnable" />
<style-operation /> <style-operation v-if="styleEnable" />
<font-operation /> <font-operation v-if="fontEnable" />
</div> </div>
</template> </template>
@ -12,9 +12,9 @@
import arrange from './arrange.vue'; import arrange from './arrange.vue';
import styleOperation from './styleOperation.vue'; import styleOperation from './styleOperation.vue';
import fontOperation from './fontOperation.vue'; import fontOperation from './fontOperation.vue';
import { moleProps } from '../../props'; import { moleProps, viewMenuProps } from '../../props';
const props = defineProps(moleProps); const props = defineProps({ ...moleProps, ...viewMenuProps });
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'moldChange', data: number): void; (e: 'moldChange', data: number): void;

View File

@ -15,6 +15,10 @@
:distinct-tags="props.distinctTags" :distinct-tags="props.distinctTags"
:default-mold="props.defaultMold" :default-mold="props.defaultMold"
:del-confirm="props.delConfirm" :del-confirm="props.delConfirm"
:arrange-enable="props.arrangeEnable"
:mold-enable="props.moldEnable"
:font-enable="props.fontEnable"
:style-enable="props.styleEnable"
@mold-change="handleMoldChange" @mold-change="handleMoldChange"
/> />
<main-editor <main-editor
@ -42,7 +46,7 @@
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import headerMenu from './main/header.vue'; import headerMenu from './main/header.vue';
import mainEditor from './main/mainEditor.vue'; import mainEditor from './main/mainEditor.vue';
import { editMenuProps, mainEditorProps, moleProps, priorityProps, tagProps, delProps } from './props'; import { editMenuProps, mainEditorProps, moleProps, priorityProps, tagProps, delProps, viewMenuProps } from './props';
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'moldChange', data: number): void; (e: 'moldChange', data: number): void;
@ -57,6 +61,7 @@
...priorityProps, ...priorityProps,
...tagProps, ...tagProps,
...delProps, ...delProps,
...viewMenuProps,
}); });
onMounted(async () => { onMounted(async () => {

View File

@ -111,3 +111,26 @@ export const delProps = {
default: null, default: null,
}, },
}; };
export const viewMenuProps = {
viewMenuEnable: {
type: Boolean,
default: true,
},
moldEnable: {
type: Boolean,
default: true,
},
arrangeEnable: {
type: Boolean,
default: true,
},
styleEnable: {
type: Boolean,
default: true,
},
fontEnable: {
type: Boolean,
default: true,
},
};

View File

@ -1,4 +1,3 @@
@import 'mixin.less';
@import 'dropdown-list.less'; @import 'dropdown-list.less';
.mind-tab-panel { .mind-tab-panel {
@apply h-full w-full; @apply h-full w-full;
@ -14,11 +13,13 @@
} }
} }
.menu-btn { .menu-btn {
@apply inline-flex cursor-pointer; @apply flex cursor-pointer items-center justify-center;
@include flexcenter;
} }
.menu-btn:not([disabled='true']):hover { .menu-btn:not([disabled='true']):hover {
background-color: @btn-hover-color; background-color: var(--color-fill-2);
}
.menu-btn[disabled='true'] {
opacity: 0.7;
} }
.tab-icons { .tab-icons {
@apply inline-flex; @apply inline-flex;
@ -27,15 +28,14 @@
height: 20px; height: 20px;
} }
.do-group { .do-group {
@apply h-full w-[40px]; @apply h-full;
padding: 0 5px; padding: 0 5px;
width: 40px; width: 40px;
p { p {
@apply m-0; @apply m-0 flex items-center justify-center;
height: 50%; height: 50%;
@include flexcenter;
} }
.undo i { .undo i {
background-position: 0 -1240px; background-position: 0 -1240px;
@ -47,7 +47,7 @@
.insert-group { .insert-group {
width: 110px; width: 110px;
& > div { & > div {
margin: 5px 0; margin: 0 5px;
} }
.insert-sibling-box { .insert-sibling-box {
i { i {
@ -62,8 +62,9 @@
} }
.edit-del-group, .edit-del-group,
.move-group { .move-group {
@apply flex items-center justify-center;
width: 70px; width: 70px;
@include flexcenter;
} }
.move-group { .move-group {
.move-up { .move-up {
@ -90,28 +91,26 @@
} }
} }
.attachment-group { .attachment-group {
@apply flex items-center justify-center;
width: 185px; width: 185px;
@include flexcenter;
button { button {
@apply bg-no-repeat p-0; @apply flex items-center justify-center border-none bg-transparent bg-no-repeat p-0 outline-none;
width: 45px; width: 45px;
height: 20px; height: 20px;
background-position: right; background-position: right;
@include button;
@include flexcenter;
span { span {
margin-left: 15px; margin-left: 15px;
} }
} }
button:hover { button:hover {
background-color: @btn-hover-color; background-color: var(--color-fill-2);
} }
& > div { & > div {
@apply h-full flex-wrap; @apply flex h-full flex-wrap items-center justify-center;
width: 60px; width: 60px;
@include flexcenter;
} }
.insert { .insert {
@apply bg-no-repeat; @apply bg-no-repeat;
@ -136,8 +135,9 @@
} }
.progress-group, .progress-group,
.sequence-group { .sequence-group {
@apply flex items-center justify-center;
width: 135px; width: 135px;
@include flexcenter;
ul { ul {
@apply m-0 list-none p-0; @apply m-0 list-none p-0;
@ -172,8 +172,7 @@
.arrange-group { .arrange-group {
width: 65px; width: 65px;
.arrange { .arrange {
@apply flex-wrap; @apply flex flex-wrap items-center justify-center;
@include flexcenter;
} }
.tab-icons { .tab-icons {
@apply m-0 inline-block bg-no-repeat; @apply m-0 inline-block bg-no-repeat;
@ -184,10 +183,11 @@
} }
} }
.style-group { .style-group {
@apply w-[150px]; width: 150px;
.clear-style-btn { .clear-style-btn {
@apply w-[65px] flex-wrap; @apply flex flex-wrap items-center justify-center;
@include flexcenter;
width: 65px;
.tab-icons { .tab-icons {
@apply m-0 inline-block bg-no-repeat; @apply m-0 inline-block bg-no-repeat;
@ -197,7 +197,7 @@
} }
} }
.copy-paste-panel { .copy-paste-panel {
@apply w-[70px]; width: 70px;
.tab-icons { .tab-icons {
@apply inline-block; @apply inline-block;
@ -245,12 +245,13 @@
} }
.expand-group, .expand-group,
.selection-group { .selection-group {
@apply flex items-center justify-center;
margin: 0 5px; margin: 0 5px;
width: 60px; width: 60px;
button { button {
@apply border-none outline-none; @apply border-none outline-none;
} }
@include flexcenter;
span { span {
font-size: 12px; font-size: 12px;
} }

View File

@ -1,16 +0,0 @@
@btn-hover-color: #eee;
*[disabled='true'] {
@apply opacity-50;
}
.block() {
@apply h-full w-full;
}
.button() {
@apply border-none bg-transparent outline-none;
}
.flexcenter() {
@apply flex items-center justify-center;
}

View File

@ -175,10 +175,10 @@
}; };
onMounted(() => { onMounted(() => {
const _theme = getLocalStorage<ThemeData>('vue-custom-theme', true) as ThemeData; // const _theme = getLocalStorage<ThemeData>('vue-custom-theme', true) as ThemeData;
if (_theme) { // if (_theme) {
useTheme(_theme, false); // useTheme(_theme, false);
} // }
}); });
const fetchThemeList = async (current: number, search: string) => { const fetchThemeList = async (current: number, search: string) => {

View File

@ -1,5 +1,5 @@
<template> <template>
<!-- <minder-editor <minder-editor
class="minder-container" class="minder-container"
:import-json="importJson" :import-json="importJson"
:progress-enable="false" :progress-enable="false"
@ -7,136 +7,81 @@
:tags="tags" :tags="tags"
:default-mold="defaultMode" :default-mold="defaultMode"
:del-confirm="delConfirm" :del-confirm="delConfirm"
:style-enable="true"
:arrange-enable="true"
:mold-enable="true"
:font-enable="true"
@save="save" @save="save"
/> --> />
<!-- <JsonPicker /> --> <!-- <JsonPicker /> -->
<div class="bg-white">
<a-tabs>
<a-tab-pane key="1">
<template #title> <icon-calendar /> Tab 1 </template>
Content of Tab Panel 1
</a-tab-pane>
<a-tab-pane key="2">
<template #title> <icon-clock-circle /> Tab 2 </template>
Content of Tab Panel 2
</a-tab-pane>
<a-tab-pane key="3">
<template #title> <icon-user /> Tab 3 </template>
Content of Tab Panel 3
</a-tab-pane>
</a-tabs>
<a-tabs class="w-[500px]" :editable="true" show-add-button auto-switch @add="handleAdd" @delete="handleDelete">
<a-tab-pane v-for="(item, index) of data" :key="item.key" :title="item.title" :closable="index !== 2">
{{ item?.content }}
</a-tab-pane>
</a-tabs>
</div>
</template> </template>
<script setup lang="ts" name="minderIndex"> <script setup lang="ts" name="minderIndex">
import { ref } from 'vue'; import MinderEditor from '@/components/minder-editor/minderEditor.vue';
let count = 5;
const data = ref([
{
key: '1',
title: 'Tab 1',
content: 'Content of Tab Panel 1',
},
{
key: '2',
title: 'Tab 2',
content: 'Content of Tab Panel 2',
},
{
key: '3',
title: 'Tab 3',
content: 'Content of Tab Panel 3',
},
{
key: '4',
title: 'Tab 4',
content: 'Content of Tab Panel 4',
},
]);
const handleAdd = () => {
const number = count++;
data.value = data.value.concat({
key: `${number}`,
title: `New Tab ${number}`,
content: `Content of New Tab Panel ${number}`,
});
};
const handleDelete = (key: string | number) => {
data.value = data.value.filter((item) => item.key !== key);
};
// import MinderEditor from '@/components/minder-editor/minderEditor.vue';
// import JsonPicker from '@/components/jsonpath-picker/index.vue'; // import JsonPicker from '@/components/jsonpath-picker/index.vue';
// const importJson = { const importJson = {
// root: { root: {
// data: { data: {
// // //
// text: 'vue3-minder-editor', text: 'vue3-minder-editor',
// // //
// resource: ['1'], resource: ['模块1'],
// // //
// // disable: true,
// // collapse
// // expandState: 'collapse',
// // disable true
// // tagEnable: true,
// // disable true
// // allowDelete: true,
// // disable true tagEnable
// // allowDisabledTag: true,
// },
// //
// children: [
// {
// data: {
// text: 'child1',
// // disable: true,
// expandState: 'collapse',
// resource: ['2'],
// },
// children: [
// {
// data: {
// text: 'axxaaaa',
// disable: true, // disable: true,
// collapse
// expandState: 'collapse',
// disable true
// tagEnable: true,
// disable true
// allowDelete: true, // allowDelete: true,
// // tagEnable: true, // disable true tagEnable
// allowDisabledTag: true, // allowDisabledTag: true,
// resource: ['12'], },
// priority: 3, //
// loaded: true, children: [
// }, {
// }, data: {
// ], text: 'child1',
// }, // disable: true,
// { expandState: 'collapse',
// data: { resource: ['模块2'],
// text: 'child2', },
// }, children: [
// }, {
// ], data: {
// }, text: '地图axxaaaa',
// template: 'default', disable: true,
// }; allowDelete: true,
// const height = 500; // tagEnable: true,
// const defaultMode = 3; allowDisabledTag: true,
// const tags = ['1', '', '', '', '', '']; resource: ['模块12'],
priority: 3,
loaded: true,
},
},
],
},
{
data: {
text: 'child2',
},
},
],
},
template: 'default',
};
const height = 500;
const defaultMode = 3;
const tags = ['模块1', '用例', '前置条件', '测试步骤', '预期结果', '备注'];
// function save(data: any) { function save(data: any) {
// // eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log(data); console.log(data);
// } }
// function delConfirm() { function delConfirm() {
// // eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('-=-=-=-=-=-=-=='); console.log('-=-=-=-=-=-=-==');
// } }
</script> </script>