后台教程
This commit is contained in:
@@ -25,7 +25,7 @@ watch(authed, (v) => {
|
|||||||
<template>
|
<template>
|
||||||
<n-config-provider class="myContainer" :locale="zhCN" :date-locale="dateZhCN">
|
<n-config-provider class="myContainer" :locale="zhCN" :date-locale="dateZhCN">
|
||||||
<n-modal-provider>
|
<n-modal-provider>
|
||||||
<n-message-provider max="1">
|
<n-message-provider :max="1">
|
||||||
<n-dialog-provider>
|
<n-dialog-provider>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
<Login />
|
<Login />
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export class Account {
|
|||||||
|
|
||||||
export class Tutorial {
|
export class Tutorial {
|
||||||
static async list() {
|
static async list() {
|
||||||
const res = await http.get("/tutorial/")
|
const res = await http.get("/tutorial/list")
|
||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { useMessage } from "naive-ui"
|
|||||||
import { Icon } from "@iconify/vue"
|
import { Icon } from "@iconify/vue"
|
||||||
import { user, authed, roleNormal, roleSuper } from "../store/user"
|
import { user, authed, roleNormal, roleSuper } from "../store/user"
|
||||||
import { loginModal } from "../store/modal"
|
import { loginModal } from "../store/modal"
|
||||||
|
import { step } from "../store/tutorial"
|
||||||
import { Account } from "../api"
|
import { Account } from "../api"
|
||||||
import { Role } from "../utils/type"
|
import { Role } from "../utils/type"
|
||||||
import { router } from "../router"
|
import { router } from "../router"
|
||||||
@@ -61,7 +62,7 @@ const menu = computed(() => [
|
|||||||
function clickMenu(name: string) {
|
function clickMenu(name: string) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "dashboard":
|
case "dashboard":
|
||||||
router.push({ name: "tutorial" })
|
router.push({ name: "tutorial", params: { display: step.value } })
|
||||||
break
|
break
|
||||||
case "admin":
|
case "admin":
|
||||||
window.open(ADMIN_URL)
|
window.open(ADMIN_URL)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<n-flex align="center" class="title">
|
<n-flex align="center" justify="space-between" class="title">
|
||||||
<n-flex align="center">
|
<n-flex align="center">
|
||||||
<Icon icon="twemoji:open-book" :width="20"></Icon>
|
<Icon icon="twemoji:open-book" :width="20"></Icon>
|
||||||
<n-text class="preview">教程(测试版)</n-text>
|
<n-text class="preview">教程(测试版)</n-text>
|
||||||
@@ -11,6 +11,13 @@
|
|||||||
<Icon :width="24" icon="pepicons-pencil:arrow-right"></Icon>
|
<Icon :width="24" icon="pepicons-pencil:arrow-right"></Icon>
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
<n-button
|
||||||
|
v-if="authed && roleSuper"
|
||||||
|
quaternary
|
||||||
|
@click="$router.push({ name: 'tutorial', params: { display: step } })"
|
||||||
|
>
|
||||||
|
修改
|
||||||
|
</n-button>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<div class="markdown-body" v-html="content" ref="$content"></div>
|
<div class="markdown-body" v-html="content" ref="$content"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,11 +27,10 @@ import { Icon } from "@iconify/vue"
|
|||||||
import { html, css, js, tab } from "../store/editors"
|
import { html, css, js, tab } from "../store/editors"
|
||||||
import { computed, onMounted, ref, useTemplateRef, watch } from "vue"
|
import { computed, onMounted, ref, useTemplateRef, watch } from "vue"
|
||||||
import { marked } from "marked"
|
import { marked } from "marked"
|
||||||
import { useStorage } from "@vueuse/core"
|
|
||||||
import { Tutorial } from "../api"
|
import { Tutorial } from "../api"
|
||||||
import { STORAGE_KEY } from "../utils/const"
|
import { step } from "../store/tutorial"
|
||||||
|
import { authed, roleSuper } from "../store/user"
|
||||||
|
|
||||||
const step = useStorage(STORAGE_KEY.STEP, 1)
|
|
||||||
const displays = ref<number[]>([])
|
const displays = ref<number[]>([])
|
||||||
const content = ref("")
|
const content = ref("")
|
||||||
const $content = useTemplateRef("$content")
|
const $content = useTemplateRef("$content")
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
</n-button>
|
</n-button>
|
||||||
<n-button
|
<n-button
|
||||||
v-for="item in menu"
|
v-for="item in menu"
|
||||||
:type="$route.name === item.name ? 'primary' : 'default'"
|
:type="$route.name === item.route.name ? 'primary' : 'default'"
|
||||||
@click="$router.push({ name: item.name })"
|
@click="$router.push(item.route)"
|
||||||
>
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</n-button>
|
</n-button>
|
||||||
@@ -18,9 +18,14 @@
|
|||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { step } from "../store/tutorial"
|
||||||
|
|
||||||
const menu = [
|
const menu = [
|
||||||
{ label: "教程", name: "tutorial" },
|
{
|
||||||
{ label: "用户", name: "user-manage" },
|
label: "教程",
|
||||||
|
route: { name: "tutorial", params: { display: step.value } },
|
||||||
|
},
|
||||||
|
{ label: "用户", route: { name: "user-manage" } },
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
v-for="item in list"
|
v-for="item in list"
|
||||||
:key="item.display"
|
:key="item.display"
|
||||||
@click="show(item.display)"
|
@click="show(item.display)"
|
||||||
style="cursor: pointer"
|
class="card"
|
||||||
|
:header-style="{
|
||||||
|
backgroundColor:
|
||||||
|
item.display === tutorial.display ? 'rgba(24, 160, 80, 0.1)' : '',
|
||||||
|
}"
|
||||||
:embedded="!item.is_public"
|
:embedded="!item.is_public"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
@@ -72,11 +76,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { marked } from "marked"
|
import { marked } from "marked"
|
||||||
import { computed, onMounted, reactive, ref, watch } from "vue"
|
import { computed, onMounted, reactive, ref, watch } from "vue"
|
||||||
|
import { useRoute, useRouter } from "vue-router"
|
||||||
import { Icon } from "@iconify/vue"
|
import { Icon } from "@iconify/vue"
|
||||||
import { Tutorial } from "../api"
|
import { Tutorial } from "../api"
|
||||||
import type { TutorialSlim } from "../utils/type"
|
import type { TutorialSlim } from "../utils/type"
|
||||||
import { useDialog, useMessage } from "naive-ui"
|
import { useDialog, useMessage } from "naive-ui"
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const confirm = useDialog()
|
const confirm = useDialog()
|
||||||
|
|
||||||
@@ -90,14 +97,11 @@ const tutorial = reactive({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const canSubmit = computed(
|
const canSubmit = computed(
|
||||||
() =>
|
() => tutorial.display && tutorial.title && tutorial.content,
|
||||||
tutorial.display && tutorial.title && tutorial.content,
|
|
||||||
)
|
)
|
||||||
async function getContent() {
|
async function getContent() {
|
||||||
const res = await Tutorial.list()
|
list.value = await Tutorial.list()
|
||||||
list.value = res.list
|
show(Number(route.params.display))
|
||||||
const data = tutorial.content || res.first?.content
|
|
||||||
content.value = await marked.parse(data ?? "", { async: true })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNew() {
|
function createNew() {
|
||||||
@@ -137,6 +141,7 @@ async function remove(display: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function show(display: number) {
|
async function show(display: number) {
|
||||||
|
router.push({ name: "tutorial", params: { display } })
|
||||||
const item = await Tutorial.get(display)
|
const item = await Tutorial.get(display)
|
||||||
tutorial.display = item.display
|
tutorial.display = item.display
|
||||||
tutorial.title = item.title
|
tutorial.title = item.title
|
||||||
@@ -173,6 +178,10 @@ onMounted(getContent)
|
|||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.editor {
|
.editor {
|
||||||
height: calc(100vh - 200px);
|
height: calc(100vh - 200px);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const routes = [
|
|||||||
meta: { auth: true },
|
meta: { auth: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "tutorial",
|
path: "tutorial/:display",
|
||||||
name: "tutorial",
|
name: "tutorial",
|
||||||
component: () => import("./pages/Markdown.vue"),
|
component: () => import("./pages/Markdown.vue"),
|
||||||
},
|
},
|
||||||
|
|||||||
4
src/store/tutorial.ts
Normal file
4
src/store/tutorial.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { useStorage } from "@vueuse/core"
|
||||||
|
import { STORAGE_KEY } from "../utils/const"
|
||||||
|
|
||||||
|
export const step = useStorage(STORAGE_KEY.STEP, 1)
|
||||||
@@ -18,6 +18,10 @@ export interface TutorialSlim {
|
|||||||
is_public: boolean
|
is_public: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TutorialReturn extends TutorialSlim {
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface TutorialIn {
|
export interface TutorialIn {
|
||||||
display: number
|
display: number
|
||||||
title: string
|
title: string
|
||||||
|
|||||||
Reference in New Issue
Block a user