mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
feat(projects): 添加富文本和markdown编辑器插件及示例页面
This commit is contained in:
18
src/components/custom/GithubLink/index.vue
Normal file
18
src/components/custom/GithubLink/index.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<p>
|
||||
<span>github地址:</span>
|
||||
<a class="text-blue-500" :href="link" target="_blank">
|
||||
{{ link }}
|
||||
</a>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
/** github链接 */
|
||||
link: string;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
<style scoped></style>
|
@ -3,5 +3,6 @@ import IconClose from './IconClose/index.vue';
|
||||
import ButtonTab from './ButtonTab/index.vue';
|
||||
import ChromeTab from './ChromeTab/index.vue';
|
||||
import BetterScroll from './BetterScroll/index.vue';
|
||||
import GithubLink from './GithubLink/index.vue';
|
||||
|
||||
export { CountTo, IconClose, ButtonTab, ChromeTab, BetterScroll };
|
||||
export { CountTo, IconClose, ButtonTab, ChromeTab, BetterScroll, GithubLink };
|
||||
|
@ -16,6 +16,9 @@ export enum EnumRoutePath {
|
||||
'component' = '/component',
|
||||
'component_map' = '/component/map',
|
||||
'component_video' = '/component/video',
|
||||
'component_editor' = '/component/editor',
|
||||
'component_editor_quill' = '/component/editor/quill',
|
||||
'component_editor_markdown' = '/component/editor/markdown',
|
||||
'multi-menu' = '/multi-menu',
|
||||
'multi-menu_first' = '/multi-menu/first',
|
||||
'multi-menu_first_second' = '/multi-menu/first/second',
|
||||
@ -44,6 +47,9 @@ export enum EnumRouteTitle {
|
||||
'component' = '组件插件',
|
||||
'component_map' = '地图插件',
|
||||
'component_video' = '视频插件',
|
||||
'component_editor' = '编辑器',
|
||||
'component_editor_quill' = '富文本编辑器',
|
||||
'component_editor_markdown' = 'markdown编辑器',
|
||||
'multi-menu' = '多级菜单',
|
||||
'multi-menu_first' = '一级菜单',
|
||||
'multi-menu_first_second' = '二级菜单',
|
||||
|
@ -20,6 +20,7 @@
|
||||
:collapsed-icon-size="22"
|
||||
:options="menus"
|
||||
:expanded-keys="expandedKeys"
|
||||
:indent="18"
|
||||
@update:value="handleUpdateMenu"
|
||||
@update:expanded-keys="handleUpdateExpandedKeys"
|
||||
/>
|
||||
|
@ -23,7 +23,7 @@
|
||||
</header>
|
||||
<div class="flex-1-hidden">
|
||||
<n-scrollbar>
|
||||
<n-menu :value="activeKey" :options="childMenus" @update:value="handleUpdateMenu" />
|
||||
<n-menu :value="activeKey" :options="childMenus" :indent="18" @update:value="handleUpdateMenu" />
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<hover-container class="w-40px h-full" placement="bottom-end" content="重新加载" @click="handleRefresh">
|
||||
<hover-container class="w-64px h-full" placement="bottom-end" content="重新加载" @click="handleRefresh">
|
||||
<icon-mdi-refresh class="text-16px" :class="{ 'reload-animation': loading }" />
|
||||
</hover-container>
|
||||
</template>
|
||||
|
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<n-menu
|
||||
:value="activeKey"
|
||||
:collapsed="app.menu.collapsed"
|
||||
:collapsed-width="theme.menuStyle.collapsedWidth"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menus"
|
||||
@update:value="handleUpdateMenu"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { NMenu } from 'naive-ui';
|
||||
import type { MenuOption } from 'naive-ui';
|
||||
import { useThemeStore, useAppStore } from '@/store';
|
||||
import { menus } from '@/router';
|
||||
import { GlobalMenuOption } from '@/interface';
|
||||
|
||||
const theme = useThemeStore();
|
||||
const app = useAppStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const activeKey = computed(() => getActiveKey());
|
||||
|
||||
function getActiveKey() {
|
||||
return route.name as string;
|
||||
}
|
||||
|
||||
function handleUpdateMenu(key: string, item: MenuOption) {
|
||||
const menuItem = item as GlobalMenuOption;
|
||||
router.push(menuItem.routePath);
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
@ -1,4 +1,3 @@
|
||||
import GlobalLogo from './GlobalLogo.vue';
|
||||
import GlobalMenu from './GlobalMenu.vue';
|
||||
|
||||
export { GlobalLogo, GlobalMenu };
|
||||
export { GlobalLogo };
|
||||
|
@ -1,12 +1,16 @@
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
import { BasicLayout, BasicChildLayout } from '@/layouts';
|
||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
|
||||
import ComponentMap from '@/views/component/map/index.vue';
|
||||
import ComponentVideo from '@/views/component/video/index.vue';
|
||||
import EditorQuill from '@/views/component/editor/quill/index.vue';
|
||||
import EditorMarkdown from '@/views/component/editor/markdown/index.vue';
|
||||
|
||||
setRouterCacheName(ComponentMap, ROUTE_NAME_MAP.get('component_map'));
|
||||
setRouterCacheName(ComponentVideo, ROUTE_NAME_MAP.get('component_video'));
|
||||
setRouterCacheName(EditorQuill, ROUTE_NAME_MAP.get('component_editor_quill'));
|
||||
setRouterCacheName(EditorMarkdown, ROUTE_NAME_MAP.get('component_editor_markdown'));
|
||||
|
||||
const COMPONENT: CustomRoute = {
|
||||
name: ROUTE_NAME_MAP.get('component'),
|
||||
@ -38,6 +42,39 @@ const COMPONENT: CustomRoute = {
|
||||
title: EnumRouteTitle.component_video,
|
||||
fullPage: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: ROUTE_NAME_MAP.get('component_editor'),
|
||||
path: EnumRoutePath.component_editor,
|
||||
component: BasicChildLayout,
|
||||
redirect: { name: ROUTE_NAME_MAP.get('component_editor_quill') },
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.component_editor,
|
||||
fullPage: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: ROUTE_NAME_MAP.get('component_editor_quill'),
|
||||
path: EnumRoutePath.component_editor_quill,
|
||||
component: EditorQuill,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.component_editor_quill,
|
||||
fullPage: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: ROUTE_NAME_MAP.get('component_editor_markdown'),
|
||||
path: EnumRoutePath.component_editor_markdown,
|
||||
component: EditorMarkdown,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.component_editor_markdown,
|
||||
fullPage: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
46
src/views/component/editor/markdown/index.vue
Normal file
46
src/views/component/editor/markdown/index.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card title="markdown插件" class="shadow-sm rounded-16px">
|
||||
<div ref="domRef"></div>
|
||||
<template #footer>
|
||||
<github-link link="https://github.com/Vanessa219/vditor" />
|
||||
</template>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { NCard } from 'naive-ui';
|
||||
import Vditor from 'vditor';
|
||||
import 'vditor/src/assets/scss/index.scss';
|
||||
import { useThemeStore } from '@/store';
|
||||
import { GithubLink } from '@/components';
|
||||
|
||||
const theme = useThemeStore();
|
||||
|
||||
const vditor = ref<Vditor | null>(null);
|
||||
const domRef = ref<HTMLElement | null>(null);
|
||||
|
||||
function renderVditor() {
|
||||
vditor.value = new Vditor(domRef.value!, {
|
||||
minHeight: 400,
|
||||
theme: theme.darkMode ? 'dark' : 'classic',
|
||||
icon: 'material',
|
||||
cache: { enable: false }
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => theme.darkMode,
|
||||
newValue => {
|
||||
const themeMode = newValue ? 'dark' : 'classic';
|
||||
vditor.value?.setTheme(themeMode);
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
renderVditor();
|
||||
});
|
||||
</script>
|
||||
<style scoped></style>
|
35
src/views/component/editor/quill/index.vue
Normal file
35
src/views/component/editor/quill/index.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card title="富文本插件" class="shadow-sm rounded-16px">
|
||||
<div ref="domRef"></div>
|
||||
<template #footer>
|
||||
<github-link link="https://github.com/wangeditor-team/wangEditor" />
|
||||
</template>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { NCard } from 'naive-ui';
|
||||
import WangEditor from 'wangeditor';
|
||||
import { GithubLink } from '@/components';
|
||||
|
||||
const editor = ref<WangEditor | null>(null);
|
||||
const domRef = ref<HTMLElement | null>(null);
|
||||
|
||||
function renderWangEditor() {
|
||||
editor.value = new WangEditor(domRef.value);
|
||||
setEditorConfig();
|
||||
editor.value.create();
|
||||
}
|
||||
|
||||
function setEditorConfig() {
|
||||
editor.value!.config.zIndex = 10;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
renderWangEditor();
|
||||
});
|
||||
</script>
|
||||
<style scoped></style>
|
@ -137,9 +137,9 @@ const shortcuts: Shortcuts[] = [
|
||||
{ id: 0, label: '主控台', icon: 'mdi:desktop-mac-dashboard', iconColor: '#409eff' },
|
||||
{ id: 1, label: '系统管理', icon: 'ic:outline-settings', iconColor: '#7238d1' },
|
||||
{ id: 2, label: '权限管理', icon: 'mdi:family-tree', iconColor: '#f56c6c' },
|
||||
{ id: 3, label: '组件', icon: 'ion:layers', iconColor: '#8aca6b' },
|
||||
{ id: 3, label: '组件', icon: 'fluent:app-store-24-filled', iconColor: '#19a2f1' },
|
||||
{ id: 4, label: '表格', icon: 'mdi:table-large', iconColor: '#fab251' },
|
||||
{ id: 5, label: '图表', icon: 'mdi:chart-areaspline', iconColor: '#1890ff' }
|
||||
{ id: 5, label: '图表', icon: 'mdi:chart-areaspline', iconColor: '#8aca6b' }
|
||||
];
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
Reference in New Issue
Block a user