mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-21 14:13:36 +08:00
Merge branch 'main' into pages
This commit is contained in:
@@ -112,7 +112,7 @@ function hoverDescription(event, description) {
|
||||
max-width: 238px;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.notice-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
@@ -17,14 +17,16 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以
|
||||
monitor = 14,
|
||||
tabs = 15,
|
||||
about = 16,
|
||||
editor = 17,
|
||||
flowchart = 18,
|
||||
formdesign = 19,
|
||||
board = 20,
|
||||
ppt = 21,
|
||||
mind = 22,
|
||||
guide = 23,
|
||||
menuoverflow = 24;
|
||||
codemirror = 17,
|
||||
markdown = 18,
|
||||
editor = 19,
|
||||
flowchart = 20,
|
||||
formdesign = 21,
|
||||
board = 22,
|
||||
ppt = 23,
|
||||
mind = 24,
|
||||
guide = 25,
|
||||
menuoverflow = 26;
|
||||
|
||||
export {
|
||||
home,
|
||||
@@ -44,6 +46,8 @@ export {
|
||||
monitor,
|
||||
tabs,
|
||||
about,
|
||||
codemirror,
|
||||
markdown,
|
||||
editor,
|
||||
flowchart,
|
||||
formdesign,
|
||||
|
||||
@@ -15,8 +15,7 @@ export default {
|
||||
name: "MqttClient",
|
||||
component: () => import("@/views/able/mqtt-client.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureMqtt"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: $t("menus.pureMqtt")
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
23
src/router/modules/codemirror.ts
Normal file
23
src/router/modules/codemirror.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { codemirror } from "@/router/enums";
|
||||
|
||||
export default {
|
||||
path: "/codemirror",
|
||||
redirect: "/codemirror/index",
|
||||
meta: {
|
||||
icon: "ri:code-box-line",
|
||||
title: $t("menus.pureCodeMirror"),
|
||||
rank: codemirror
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/codemirror/index",
|
||||
name: "CodeMirror",
|
||||
component: () => import("@/views/codemirror/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureCodeMirror"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies RouteConfigsTable;
|
||||
@@ -15,8 +15,7 @@ export default {
|
||||
name: "SchemaForm",
|
||||
component: () => import("@/views/schema-form/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureSchemaForm"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: $t("menus.pureSchemaForm")
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -15,8 +15,7 @@ export default {
|
||||
name: "Ganttastic",
|
||||
component: () => import("@/views/ganttastic/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureGanttastic"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: $t("menus.pureGanttastic")
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
23
src/router/modules/markdown.ts
Normal file
23
src/router/modules/markdown.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { markdown } from "@/router/enums";
|
||||
|
||||
export default {
|
||||
path: "/markdown",
|
||||
redirect: "/markdown/index",
|
||||
meta: {
|
||||
icon: "ri:markdown-line",
|
||||
title: $t("menus.pureMarkdown"),
|
||||
rank: markdown
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/markdown/index",
|
||||
name: "Markdown",
|
||||
component: () => import("@/views/markdown/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureMarkdown"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies RouteConfigsTable;
|
||||
@@ -31,8 +31,7 @@ export default {
|
||||
name: "PureTableEdit",
|
||||
component: () => import("@/views/table/edit.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureTableEdit"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: $t("menus.pureTableEdit")
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -40,8 +39,7 @@ export default {
|
||||
name: "VxeTable",
|
||||
component: () => import("@/views/table/virtual.vue"),
|
||||
meta: {
|
||||
title: $t("menus.pureVxeTable"),
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: $t("menus.pureVxeTable")
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -14,8 +14,7 @@ export default {
|
||||
name: "VueFlow",
|
||||
component: () => import("@/views/vue-flow/layouting/index.vue"),
|
||||
meta: {
|
||||
title: "vue-flow",
|
||||
extraIcon: "IF-pure-iconfont-new svg"
|
||||
title: "vue-flow"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -170,7 +170,7 @@ onBeforeUnmount(() => {
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
::v-deep(.el-upload-dragger) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
96
src/views/codemirror/index.vue
Normal file
96
src/views/codemirror/index.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
import "codemirror/theme/material-darker.css";
|
||||
import "codemirror/addon/hint/show-hint.css";
|
||||
import "codemirror/addon/hint/show-hint";
|
||||
import "codemirror/addon/hint/javascript-hint.js";
|
||||
import "codemirror/mode/javascript/javascript.js";
|
||||
|
||||
import { useDark } from "@pureadmin/utils";
|
||||
import Codemirror from "codemirror-editor-vue3";
|
||||
import { ref, reactive, watch, nextTick } from "vue";
|
||||
import type { Editor, EditorConfiguration } from "codemirror";
|
||||
|
||||
const { isDark } = useDark();
|
||||
const cminstance = ref<Editor | null>(null);
|
||||
const cmOptions: EditorConfiguration = reactive({
|
||||
mode: "javascript",
|
||||
theme: isDark.value ? "material-darker" : "default",
|
||||
tabSize: 4,
|
||||
readOnly: false,
|
||||
autofocus: true,
|
||||
autoRefresh: true,
|
||||
lineNumbers: true,
|
||||
lineWiseCopyCut: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
lint: true,
|
||||
extraKeys: {
|
||||
Ctrl: "autocomplete",
|
||||
Tab: "autocomplete"
|
||||
},
|
||||
hintOptions: {
|
||||
completeSingle: false
|
||||
}
|
||||
});
|
||||
|
||||
const code = ref(`function sayHello() {
|
||||
console.log("Hello, World!");
|
||||
}
|
||||
|
||||
sayHello();`);
|
||||
|
||||
const onReady = (cm: Editor) => {
|
||||
cminstance.value = cm;
|
||||
cm.on("keypress", () => cm.showHint());
|
||||
// console.log(cm.getValue());
|
||||
};
|
||||
|
||||
watch(
|
||||
() => isDark.value,
|
||||
async newVal => {
|
||||
await nextTick();
|
||||
newVal
|
||||
? cminstance.value.setOption("theme", "material-darker")
|
||||
: cminstance.value.setOption("theme", "default");
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="font-medium">
|
||||
代码编辑器组件,采用开源的
|
||||
<el-link
|
||||
href="https://rennzhang.github.io/codemirror-editor-vue3/zh-CN/guide/getting-started"
|
||||
target="_blank"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
codemirror-editor-vue3
|
||||
</el-link>
|
||||
</span>
|
||||
</div>
|
||||
<el-link
|
||||
class="mt-2"
|
||||
href="https://github.com/pure-admin/vue-pure-admin/blob/main/src/views/codemirror/index.vue"
|
||||
target="_blank"
|
||||
>
|
||||
代码位置 src/views/codemirror/index.vue
|
||||
</el-link>
|
||||
</template>
|
||||
<Codemirror
|
||||
v-model:value="code"
|
||||
width="100%"
|
||||
height="400px"
|
||||
:options="cmOptions"
|
||||
:border="true"
|
||||
@ready="onReady"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.codemirror-container.bordered {
|
||||
border: 1px solid var(--pure-border-color);
|
||||
}
|
||||
</style>
|
||||
@@ -84,17 +84,7 @@ watch(
|
||||
>
|
||||
vue-json-pretty
|
||||
</el-link>
|
||||
(支持大数据量)。
|
||||
</span>
|
||||
<span class="font-medium">
|
||||
当然还有一款代码编辑器推荐(这里就不做演示了),采用开源的
|
||||
<el-link
|
||||
href="https://github.com/surmon-china/vue-codemirror"
|
||||
target="_blank"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
codemirror6
|
||||
</el-link>
|
||||
(支持大数据量)
|
||||
</span>
|
||||
</div>
|
||||
<el-link
|
||||
|
||||
@@ -121,7 +121,7 @@ const swiperExample: any[] = [
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-card__body) {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ const cardLogoClass = computed(() => [
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.list-card-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -96,7 +96,7 @@ const immediateDebounce: any = debounce(
|
||||
true
|
||||
);
|
||||
|
||||
useEventListener(document, "keypress", ({ code }) => {
|
||||
useEventListener(document, "keydown", ({ code }) => {
|
||||
if (
|
||||
["Enter", "NumpadEnter"].includes(code) &&
|
||||
!disabled.value &&
|
||||
|
||||
105
src/views/markdown/components/Vditor.vue
Normal file
105
src/views/markdown/components/Vditor.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<script setup lang="ts">
|
||||
import "vditor/dist/index.css";
|
||||
import Vditor from "vditor";
|
||||
import { useDark } from "@pureadmin/utils";
|
||||
import { useIntervalFn } from "@vueuse/core";
|
||||
import { onMounted, ref, watch, toRaw, onUnmounted } from "vue";
|
||||
|
||||
const emit = defineEmits([
|
||||
"update:modelValue",
|
||||
"after",
|
||||
"focus",
|
||||
"blur",
|
||||
"esc",
|
||||
"ctrlEnter",
|
||||
"select"
|
||||
]);
|
||||
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
|
||||
const { isDark } = useDark();
|
||||
const editor = ref<Vditor | null>(null);
|
||||
const markdownRef = ref<HTMLElement | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
editor.value = new Vditor(markdownRef.value as HTMLElement, {
|
||||
...props.options,
|
||||
value: props.modelValue,
|
||||
cache: {
|
||||
enable: false
|
||||
},
|
||||
fullscreen: {
|
||||
index: 10000
|
||||
},
|
||||
after() {
|
||||
emit("after", toRaw(editor.value));
|
||||
},
|
||||
input(value: string) {
|
||||
emit("update:modelValue", value);
|
||||
},
|
||||
focus(value: string) {
|
||||
emit("focus", value);
|
||||
},
|
||||
blur(value: string) {
|
||||
emit("blur", value);
|
||||
},
|
||||
esc(value: string) {
|
||||
emit("esc", value);
|
||||
},
|
||||
ctrlEnter(value: string) {
|
||||
emit("ctrlEnter", value);
|
||||
},
|
||||
select(value: string) {
|
||||
emit("select", value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
newVal => {
|
||||
if (newVal !== editor.value?.getValue()) {
|
||||
editor.value?.setValue(newVal);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => isDark.value,
|
||||
newVal => {
|
||||
const { pause } = useIntervalFn(() => {
|
||||
if (editor.value.vditor) {
|
||||
newVal
|
||||
? editor.value.setTheme("dark", "dark", "rose-pine")
|
||||
: editor.value.setTheme("classic", "light", "github");
|
||||
pause();
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
const editorInstance = editor.value;
|
||||
if (!editorInstance) return;
|
||||
try {
|
||||
editorInstance?.destroy?.();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="markdownRef" />
|
||||
</template>
|
||||
59
src/views/markdown/index.vue
Normal file
59
src/views/markdown/index.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Vditor from "./components/Vditor.vue";
|
||||
|
||||
defineOptions({
|
||||
name: "Markdown"
|
||||
});
|
||||
|
||||
const text = ref(`
|
||||
\`\`\`ts
|
||||
function sayHello(): void {
|
||||
\tconsole.log("Hello, World!");
|
||||
}
|
||||
sayHello();
|
||||
\`\`\`
|
||||
# 一级标题
|
||||
## 二级标题
|
||||
### 三级标题
|
||||
#### 四级标题
|
||||
##### 五级标题
|
||||
###### 六级标题
|
||||
`);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="font-medium">
|
||||
Markdown组件,采用开源的
|
||||
<el-link
|
||||
href="https://b3log.org/vditor/"
|
||||
target="_blank"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
Vditor
|
||||
</el-link>
|
||||
</span>
|
||||
</div>
|
||||
<el-link
|
||||
class="mt-2"
|
||||
href="https://github.com/pure-admin/vue-pure-admin/blob/main/src/views/markdown"
|
||||
target="_blank"
|
||||
>
|
||||
代码位置 src/views/markdown
|
||||
</el-link>
|
||||
</template>
|
||||
<h1 class="mb-2">
|
||||
双向绑定:<span class="text-red-500">{{ text }}</span>
|
||||
</h1>
|
||||
<Vditor
|
||||
v-model="text"
|
||||
:options="{
|
||||
height: 560, // 高度
|
||||
outline: { enable: true, position: 'right' } // 大纲
|
||||
}"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -147,7 +147,7 @@ const {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ const {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ const {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ const {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ const {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user