新增模板相关功能

This commit is contained in:
Sh1yu
2023-08-24 09:28:16 +08:00
parent e393a71a93
commit ffbbe33a9f
24 changed files with 1442 additions and 518 deletions

View File

@@ -36,5 +36,9 @@ export default {
openPageList: (data) => request({url: '/zyplayer-doc-wiki/open-api/page/list', method: 'post', data: Qs.stringify(data)}),
openSpaceInfo: (data) => request({url: '/zyplayer-doc-wiki/open-api/space/info', method: 'post', data: Qs.stringify(data)}),
openPageNews: (data) => request({url: '/zyplayer-doc-wiki/open-api/page/news', method: 'post', data: Qs.stringify(data)}),
addTemplate: (data) => request({url: '/zyplayer-doc-wiki/template/add', method: 'post', data: Qs.stringify(data)}),
getTemplate: (data) => request({url: '/zyplayer-doc-wiki/template/filterAll', method: 'post', data: Qs.stringify(data,{arrayFormat:"indices",allowDots:true})}),
useTemplate: (data) => request({url: '/zyplayer-doc-wiki/template/use', method: 'post', data: Qs.stringify(data)}),
getTags: (data) => request({url: '/zyplayer-doc-wiki/template/allTags', method: 'post', data: Qs.stringify(data)}),
xxxxxxxxxxxx: (data) => request({url: 'update', method: 'post', data: Qs.stringify(data)}),
}

View File

@@ -21,6 +21,10 @@
</el-icon>
创建文件夹
</a-menu-item>
<a-menu-item key="4" @click="createWikiByTemplate(props.funcId)">
<BuildOutlined/>
从模板创建
</a-menu-item>
<a-menu-item key="3">
<el-tooltip content="支持MDZIP格式图片和MD文件请放到同级目录并配置同级相对路径" placement="right-start" :show-after="300">
<a-upload
@@ -55,11 +59,13 @@
import {ElMessage} from 'element-plus'
import pageApi from '../../assets/api/page'
import axios from "axios";
import { BuildOutlined } from '@ant-design/icons-vue';
let router = useRouter();
let uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + '/zyplayer-doc-wiki/page/file/upload');
let fileList = ref([]);
let emit = defineEmits(['choosePageIdFunc', 'doGetPageList'])
let emit = defineEmits(['choosePageIdFunc', 'doGetPageList','createWikiByTemplate'])
let props = defineProps({
choiceSpace: Number,
choosePageId: Number,
@@ -105,6 +111,10 @@
emit('choosePageIdFunc', id)
}
const createWikiByTemplate = (id) => {
emit('createWikiByTemplate', id)
}
const createWiki = (editorType, parentId) => {
if (props.choiceSpace > 0) {
let name = "新建文档"

View File

@@ -18,6 +18,7 @@
:choosePageId="choosePageId"
:nowPageId = "nowPageId"
:funcId = "0"
@createWikiByTemplate="createWikiByTemplate"
@choosePageIdFunc="choosePageIdFunc"
@doGetPageList="doGetPageList"
/>
@@ -36,10 +37,13 @@
<el-icon-document/>
</el-icon>
<!--标题-->
<el-tooltip :content="data.tags" placement="top-start" :show-after="500">
<a-tag color="#f50" v-if="data.shareStatus !== undefined">{{filterShareStatus(data.shareStatus)}}</a-tag>
</el-tooltip>
<a-input v-if="data.renaming" v-model:value="data.name" class="rename-input" placeholder="请输入文档名称" @blur="doRename(node,data)" @click.stop/>
<span v-else style="vertical-align: middle;">
<el-tooltip :content="node.label" placement="top-start" :show-after="1000">{{ node.label }}</el-tooltip>
</span>
<span v-else style="vertical-align: middle;margin-right: 5px">
<el-tooltip :content="node.label" placement="top-start" :show-after="700">{{ node.label }}</el-tooltip>
</span>
<!--操作-->
<div class="page-action-box" :class="data.renaming?'renaming':''" @click.stop>
<AddMenu
@@ -47,6 +51,7 @@
:choosePageId="choosePageId"
:nowPageId = "nowPageId"
:funcId = "data.id"
@createWikiByTemplate="createWikiByTemplate"
@choosePageIdFunc="choosePageIdFunc"
@doGetPageList="doGetPageList"
/>
@@ -60,13 +65,17 @@
</el-icon>
重命名
</a-menu-item>
<a-menu-item key="1" @click="deleteWikiPage">
<a-menu-item key="1" @click="deleteWikiPage(data.shareStatus)">
<el-icon class="clickAddIcon" style="margin-right: 5px">
<svg width="1em" height="1em" viewBox="0 0 48 48" fill="none"><path d="M9 10V44H39V10H9Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></path><path d="M20 20V33" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M28 20V33" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M4 10H44" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M16 10L19.289 4H28.7771L32 10H16Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></path></svg>
</el-icon>
删除
</a-menu-item>
<a-sub-menu key="2" title="移动文档" >
<template #icon>
<BlockOutlined />
</template>
<a-menu-item key="3" @click="openMoveMenu(false)">
<el-icon class="clickAddIcon" style="margin-right: 5px">
<DocumentCopy/>
@@ -80,6 +89,10 @@
迁移文档
</a-menu-item>
</a-sub-menu>
<a-menu-item key="5" @click="openTemplateCreate(data.shareStatus !== undefined)" v-if="data.editorType !== 0">
<BuildOutlined />
设为模板
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
@@ -164,6 +177,7 @@
</el-main>
</el-container>
</el-container>
<templateManage ref="templateManageRef" :pageId="choosePageId" :spaceId="choiceSpace" @doGetPageList="doGetPageList" />
<create-space ref="createSpaceRef" @success="loadSpaceList"></create-space>
<a-modal
v-model:open="visibleMoveMenu"
@@ -211,6 +225,7 @@
import userApi from '../../assets/api/user'
import pageApi from '../../assets/api/page'
import CreateSpace from '../space/CreateSpace'
import TemplateManage from '../template/TemplateManage'
import RightResize from './RightResize.vue'
import AddMenu from './AddMenu.vue'
import LeftSidebar from './LeftSidebar.vue'
@@ -219,7 +234,7 @@
import {useStoreUserData} from "@/store/userData";
import {useStorePageData} from "@/store/pageData";
import { defineComponent } from 'vue';
import { DownOutlined } from '@ant-design/icons-vue';
import { DownOutlined,BuildOutlined,BlockOutlined } from '@ant-design/icons-vue';
let route = useRoute();
let router = useRouter();
@@ -257,6 +272,7 @@
let visibleMoveMenu = ref(false);
let onlyMoveMode = ref(false);
let aModalWaiting = ref(false);
let templateManageRef=ref(null)
watch(()=>nowPageId ,()=>{
leftSideBarDir.value.assisSetCurrentKey();
@@ -287,6 +303,22 @@
getSelfUserInfo()
});
const openTemplateCreate = (exsit) =>{
templateManageRef.value.showTemplateCreate(exsit)
}
const createWikiByTemplate = () =>{
templateManageRef.value.showTemplateManage()
}
const filterShareStatus = (data) =>{
if (data === 1){
return '公共模板'
}
return '个人模板'
}
const openMoveMenu = (onlyMove) =>{
onlyMoveMode.value = onlyMove
visibleMoveMenu.value =true
@@ -326,8 +358,13 @@
moveToWikiPageList.value = []
}
const deleteWikiPage = () => {
ElMessageBox.confirm('确定要删除此页面及其所有子页面吗?', '提示', {
const deleteWikiPage = (share) => {
let msg = '确定要删除此页面及其所有子页面吗?'
if (share !== undefined){
msg='选中的页面是:' +filterShareStatus(share)+'删除后无法使用此模板! 确定要删除此页面及其所有子页面吗?'
}
ElMessageBox.confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',

View File

@@ -0,0 +1,324 @@
<template>
<div class="template-manage">
<el-dialog title="设置为模板" v-model="newTemplateDialogVisible" width="600px" :close-on-click-modal="false">
<el-form label-width="100px" :model="templateNewForm">
<el-form-item label="模板标签">
<el-input v-model="templateNewForm.tagName"></el-input>
</el-form-item>
<el-form-item label="是否公开">
<el-switch v-model="templateNewForm.shareStatus" inactive-text="个人模板" :inactive-value="0"
active-text="公共模板" :active-value="1"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="exsit" @click="onNewTemplateSubmit">保存修改</el-button>
<el-button type="primary" v-else @click="onNewTemplateSubmit">立即创建</el-button>
<el-button @click="onNewTemplateCancel">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<a-modal
v-model:open="templateChooseDialogVisible"
title="模板库"
width="100%"
wrapClassName="full-modal"
:confirm-loading="aModalWaiting"
:destroyOnClose=true
:closable=true>
<div>
<el-switch v-model="open" inactive-text="个人模板" :inactive-value="0" active-text="公共模板" :active-value="1"
@change="filterByOpen"></el-switch>
<a-divider type="vertical"/>
<el-input v-model="name" style="width: 30%" @change="filterByName"></el-input>
</div>
<a-divider>模板标签</a-divider>
<a-checkable-tag v-for="tag in tags" @click="filterByTags(tag.tagName,tag.show)" v-model:checked="tag.show"
style="margin: 5px" size="big">{{tag.tagName}}
</a-checkable-tag>
<a-divider/>
<a-list :grid="{gutter:1,column:4,xs:1,sm:1,md:2,lg:2,xl:4,xxl:4}" :data-source="templateList">
<template #renderItem="{item}">
<a-list-item>
<a-card :title="item.name">
<a-tag color="#f50">{{filterShareStatus(item.shareStatus)}}</a-tag>
<a-tag color="#87d068">{{item.tags}}</a-tag>
<br/>
{{item.createUserName}}
<br/>
{{item.createTime}}
<template #actions>
<el-tooltip effect="dark" content="转到原文档" placement="top">
<AimOutlined @click="turnToSource(item)"/>
</el-tooltip>
<el-tooltip effect="dark" content="预览模板" placement="top">
<BorderOutlined @click="showPreview(item)"/>
</el-tooltip>`
<el-tooltip effect="dark" content="使用模板" placement="top">
<AlertOutlined @click="chooseTemplate(item)"/>
</el-tooltip>
</template>
</a-card>
</a-list-item>
</template>
</a-list>
<a-pagination simple v-model:current="nowTemplateNum" :total="totalTemplate" style="float: right"
:page-size="8" :hide-on-single-page=true @change="pageUpDown"></a-pagination>
<template #footer/>
</a-modal>
<a-modal
v-model:open="previewVisible"
title="模板预览"
width="100%"
wrapClassName="full-modal"
:destroyOnClose=true
:closable=true>
<el-row>
<div ref="pageContentRef" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="editorType.value === 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
</el-row>
<template #footer/>
</a-modal>
</div>
</template>
<script setup>
import {
onBeforeUnmount,
ref,
onMounted,
watch,
defineProps,
nextTick,
defineEmits,
defineExpose,
computed
} from 'vue';
import {AlertOutlined, AimOutlined, BorderOutlined} from '@ant-design/icons-vue';
import {onBeforeRouteUpdate, useRouter, useRoute} from "vue-router";
import {ElMessageBox, ElMessage} from 'element-plus'
import pageApi from '../../assets/api/page'
import {mavonEditor} from 'mavon-editor'
import 'mavon-editor/dist/markdown/github-markdown.min.css'
import 'mavon-editor/dist/css/index.css'
let emit = defineEmits('doGetPageList');
let router = useRouter()
let nowTemplateNum = ref(1)
let totalTemplate = ref(0)
let exsit = ref(false)
let props = defineProps({
pageId: Number,
spaceId: Number
})
let templateNewForm = ref({
pageId: 0,
spaceId: 0,
tagName: '',
shareStatus: false
})
let newTemplateDialogVisible = ref(false);
const showTemplateCreate = (exsited) => {
exsit.value = exsited
templateNewForm.value = {
pageId: props.pageId,
spaceId: props.spaceId,
tagName: '',
shareStatus: false
}
newTemplateDialogVisible.value = true
}
const filterShareStatus = (data) => {
if (data === 1) {
return '公共模板'
}
return '个人模板'
}
const onNewTemplateSubmit = () => {
pageApi.addTemplate(templateNewForm.value).then((json) => {
ElMessage.success('模板记录成功')
emit('doGetPageList', null)
})
newTemplateDialogVisible.value = false
}
const onNewTemplateCancel = () => {
newTemplateDialogVisible.value = false
}
let templateChooseDialogVisible = ref(false)
let previewVisible = ref(false)
let aModalWaiting = ref(false)
let tags = ref([])
let filterTags = ref([])
let open = ref(false)
let name = ref('')
let templateList = ref()
let editorType = ref(1)
const showTemplateManage = () => {
templateChooseDialogVisible.value = true
filterTags.value = [{show: true, tagName: ''}]
totalTemplate.value = 0
nowTemplateNum.value = 1
templateList.value = []
filterByOpen()
}
const chooseTemplate = (item) => {
pageApi.useTemplate({
spaceId: props.spaceId,
parentId: props.pageId,
templateId: item.templateId
}).then((json) => {
templateChooseDialogVisible.value = false
emit('doGetPageList', null)
ElMessage.success('创建成功')
router.push({
path: '/page/edit',
query: {parentId: props.pageId, pageId: json.data.id}
})
})
}
const turnToSource = (item) => {
templateChooseDialogVisible.value = false
router.push({
path: '/page/show',
query: {spaceId: item.spaceId, pageId: item.id}
})
}
const pageUpDown = () => {
templateList.value = []
pageApi.getTemplate({
name: name.value,
open: open.value,
tags: filterTags.value,
pageNum: nowTemplateNum.value
}).then((json) => {
totalTemplate.value = json.total || 0
templateList.value = json.data || []
})
}
const simpleQryTemplate = () => {
templateList.value = []
pageApi.getTemplate({
name: name.value,
open: open.value,
tags: filterTags.value,
}).then((json) => {
totalTemplate.value = json.total || 0
templateList.value = json.data || []
nowTemplateNum.value = 1
})
}
const filterByOpen = () => {
pageApi.getTags({open: open.value}).then((json) => {
tags.value = json.data || []
filterTags.value = json.data || []
simpleQryTemplate()
})
}
const filterByTags = () => {
filterTags.value = tags.value.filter((item) => {
return item.show
})
if (filterTags.value.length === 0) {
filterTags.value = ['']
}
setTimeout(simpleQryTemplate(), 200)
}
const filterByName = () => {
simpleQryTemplate()
}
let pageShowDetail = ref('')
let pageContentRef = ref(null)
const showPreview = (item) => {
editorType.value = item.editorType
if (item.editorType === 1) {
pageShowDetail.value = item.content
}
if (item.editorType === 2) {
pageShowDetail.value = mavonEditor.getMarkdownIt().render(item.content)
}
setTimeout(previewPageImage(), 500);
previewVisible.value = true
}
const previewPageImage = () => {
const imgArr = []
if (pageContentRef.value !== undefined || pageContentRef.value !== '') {
return
}
const imgSelector = pageContentRef.value.querySelectorAll('img')
imgSelector.forEach((item, index) => {
imgArr.push(item.src)
item.onclick = () => {
previewInitialIndex.value = index
showImagePreviewList.value = imgArr
showImagePreview.value = true
}
})
}
defineExpose({showTemplateCreate, showTemplateManage});
</script>
<style>
.template-manage .wiki-page-content {
margin-top: 5px;
height: calc(100vh);
overflow: hidden;
position: relative
}
.template-manage .markdown-body table {
display: table;
}
.template-manage .wiki-page-content img {
cursor: pointer;
max-width: 100%;
}
.template-manage .wiki-page-content img:hover {
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.3);
}
</style>
<style lang="less">
.full-modal {
.ant-modal {
max-width: 100%;
top: 0;
padding-bottom: 0;
margin: 0;
}
.ant-modal-content {
display: flex;
flex-direction: column;
height: calc(100vh);
overflow: auto;
position: relative
}
.ant-modal-body {
flex: 1;
}
}
</style>
<style lang="scss">
.template-manage {
height: 100%;
overflow: hidden;
.wiki-page-content {
ol {
list-style: decimal;
}
ul {
list-style: disc;
}
}
}
</style>