Files
zyplayer-doc/zyplayer-doc-ui/wiki-ui/src/views/page/Show.vue

611 lines
18 KiB
Vue
Raw Normal View History

2019-05-30 22:45:22 +08:00
<template>
<div class="page-show-vue">
2023-01-11 20:33:42 +08:00
<el-row type="border-card" style="height: 100%">
2023-07-04 20:15:32 +08:00
<el-col :span="storePage.commentShow ? 18 : 24" style="padding: 20px;border-right: 1px solid #f1f1f1;height: 100%;overflow: auto;">
<el-row>
2023-01-11 20:33:42 +08:00
<el-col :span="navigationList.length > 0 ? 18 : 24">
<div style="max-width: 1000px; margin: 0 auto; padding-left: 10px">
<div class="wiki-title" ref="wikiTitleRef">{{ wikiPage.name }}</div>
<PageAction/>
<div class="wiki-files">
2023-07-04 20:15:32 +08:00
<el-table v-show="storePage.fileList.length > 0" :data="storePage.fileList" border style="width: 100%; margin-bottom: 5px">
2023-01-11 20:33:42 +08:00
<el-table-column label="文件名" show-overflow-tooltip>
<template v-slot="scope">
2023-01-11 23:28:20 +08:00
<el-link target="_blank" :href="scope.row.fileUrl" type="primary">{{scope.row.fileName }}</el-link>
</template>
</el-table-column>
2023-01-11 23:28:20 +08:00
<el-table-column prop="createUserName" label="创建人" width="110px" show-overflow-tooltip></el-table-column>
2023-01-11 20:33:42 +08:00
<el-table-column label="文件大小" width="120px">
<template v-slot="scope">{{computeFileSize(scope.row.fileSize) }}</template>
</el-table-column>
2023-01-11 20:33:42 +08:00
<el-table-column prop="createTime" label="创建时间" width="160px"></el-table-column>
2023-01-11 23:28:20 +08:00
<el-table-column prop="downloadNum" label="下载次数" width="90px">
2023-01-11 20:33:42 +08:00
<template v-slot="scope">{{scope.row.downloadNum || 0}}</template>
</el-table-column>
2023-01-11 23:28:20 +08:00
<el-table-column label="操作" width="90px" v-if="wikiPageAuth.canDeleteFile == 1">
2023-01-11 20:33:42 +08:00
<template v-slot="scope">
2023-07-04 20:15:32 +08:00
<el-button @click="deletePageFile(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
2023-01-11 20:33:42 +08:00
<div ref="pageContentRef" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="wikiPage.editorType == 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
2023-01-11 20:33:42 +08:00
<div style="margin-top: 40px; font-size: 14px">
<span style="vertical-align: top" class="is-link">
2023-07-04 20:15:32 +08:00
<span v-show="wikiPage.selfZan == 0" @click="zanPage(1)"><img src="../../assets/img/zan.png" style="vertical-align: middle"/> </span>
<span v-show="wikiPage.selfZan == 1" @click="zanPage(0)"><img src="../../assets/img/zan.png" style="vertical-align: middle; transform: rotateX(180deg)"/> </span>
2023-01-11 20:33:42 +08:00
</span>
<span style="margin-left: 10px; vertical-align: top">
<span v-if="wikiPage.selfZan == 0 && wikiPage.zanNum <= 0">成为第一个赞同者</span>
<span v-else-if="wikiPage.selfZan == 0 && wikiPage.zanNum > 0">
2023-07-04 20:15:32 +08:00
<span class="is-link" @click="showZanPageUser">{{ wikiPage.zanNum }}</span>赞了它
2023-01-11 20:33:42 +08:00
</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum <= 1">我赞了它</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum > 1">
2023-07-04 20:15:32 +08:00
<span class="is-link" @click="showZanPageUser">我和{{ wikiPage.zanNum - 1 }}个其他人</span>赞了它
2023-01-11 20:33:42 +08:00
</span>
</span>
<span style="margin-left: 10px">
<el-icon style="font-size: 16px; color: #666;vertical-align: middle;"><el-icon-view/></el-icon> {{ wikiPage.viewNum }}次阅读
</span>
</div>
</div>
</el-col>
2023-01-11 20:33:42 +08:00
<el-col :span="navigationList.length > 0 ? 6 : 0" v-if="navigationList.length > 0">
2023-07-04 20:15:32 +08:00
<Navigation :heading="navigationList"></Navigation>
</el-col>
</el-row>
</el-col>
2023-07-04 20:15:32 +08:00
<el-col :span="6" style="height: 100%" v-show="storePage.commentShow">
2023-01-11 20:33:42 +08:00
<el-icon @click="closeActionTab" class="close-action-tab">
<el-icon-close/>
</el-icon>
2023-07-04 20:15:32 +08:00
<el-tabs v-model="storePage.commentActiveTab">
<el-tab-pane label="评论" name="comment">
2023-01-11 20:33:42 +08:00
<Comment/>
</el-tab-pane>
<el-tab-pane label="修改历史" name="history">
2023-01-11 20:33:42 +08:00
<div class="action-tab-box">
<div v-if="pageHistoryList.length <= 0" class="action-box-empty">
暂无修改历史记录
</div>
<el-timeline v-else>
<el-timeline-item v-for="history in pageHistoryList">
2023-01-11 20:33:42 +08:00
<el-tag :type="pageHistoryChoice.id === history.id ? history.loading === 3 ? 'danger' : 'success' : 'info'" class="history-item" @click="historyClick(history)">
<div>{{ history.createUserName }}</div>
<div>{{ history.createTime }}</div>
</el-tag>
2023-01-11 20:33:42 +08:00
<el-icon class="history-loading-status" v-show="history.loading===1"><el-icon-loading/></el-icon>
<el-icon class="history-loading-status" v-show="history.loading===2"><el-icon-circle-check/></el-icon>
<el-icon class="history-loading-status" v-show="history.loading===3"><el-icon-circle-close/></el-icon>
</el-timeline-item>
</el-timeline>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
2019-05-30 22:45:22 +08:00
</el-row>
<!--点赞人员弹窗-->
2023-01-11 20:33:42 +08:00
<el-dialog title="赞了它的人" v-model="zanUserDialogVisible" width="600px">
<el-table :data="zanUserList" border :show-header="false" style="width: 100%; margin-bottom: 5px">
2019-05-30 22:45:22 +08:00
<el-table-column prop="createUserName" label="用户"></el-table-column>
<el-table-column prop="createTime" label="时间"></el-table-column>
</el-table>
</el-dialog>
2023-04-01 17:49:53 +08:00
<el-image-viewer
v-if="showImagePreview"
:url-list="showImagePreviewList"
:initial-index="previewInitialIndex"
@close="closeImagePreview"
hide-on-click-modal
/>
2019-05-30 22:45:22 +08:00
</div>
</template>
2023-01-11 20:33:42 +08:00
<script setup>
import {
ArrowDown as ElIconArrowDown,
View as ElIconView,
Close as ElIconClose,
Delete as ElIconDelete,
Loading as ElIconLoading,
CircleCheck as ElIconCircleCheck,
CircleClose as ElIconCircleClose,
ChatLineRound as ElIconChatLineRound,
Upload as ElIconUpload,
Edit as ElIconEdit,
Timer as ElIconTime,
Stamp as ElIconSCheck,
Share as ElIconShare,
Iphone as ElIconMobilePhone,
Download as ElIconDownload,
} from '@element-plus/icons-vue'
import {toRefs, ref, reactive, onMounted, watch, defineProps, defineEmits, defineExpose, computed} from 'vue';
import {onBeforeRouteUpdate, useRoute, useRouter} from "vue-router";
import { ElMessageBox, ElMessage, ElNotification } from 'element-plus';
import QRCode from 'qrcode'
import unitUtil from '../../assets/lib/UnitUtil.js'
import htmlUtil from '../../assets/lib/HtmlUtil.js'
import pageApi from '../../assets/api/page'
import userApi from '../../assets/api/user'
import Navigation from './components/Navigation.vue'
import PageAction from './show/PageAction.vue'
2023-01-11 20:33:42 +08:00
import Comment from './show/Comment.vue'
import {mavonEditor} from 'mavon-editor'
import 'mavon-editor/dist/markdown/github-markdown.min.css'
import 'mavon-editor/dist/css/index.css'
2023-01-11 20:33:42 +08:00
import {useStorePageData} from "@/store/pageData";
2023-01-11 20:33:42 +08:00
let page = {
colorArr: ['#67C23A', '#409EFF', '#E6A23C', '#F56C6C', '#909399', '#303133'],
userHeadColor: {},
}
// 页面展示相关
let wikiPage = ref({});
let wikiPageAuth = ref({});
let pageContent = ref({});
let selfUserId = ref(0);
let uploadFileList = ref([]);
let uploadFormData = ref({pageId: 0});
let zanUserDialogVisible = ref(false);
let zanUserList = ref([]);
let parentPath = ref({});
// 手机扫码
let qrCodeUrl = ref('');
let mobileScanDialogVisible = ref(false);
let uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + '/zyplayer-doc-wiki/page/file/upload');
// 页面权限
let pageAuthDialogVisible = ref(false);
let pageAuthUserList = ref([]);
let searchUserList = ref([]);
let pageAuthNewUser = ref('');
let pageAuthUserLoading = ref(false);
// 右侧标签页
let pageHistoryDetail = ref('');
let pageShowDetail = ref('');
let pageHistoryChoice = ref({});
let pageHistoryList = ref([]);
let pageHistoryPageNum = ref(1);
// 左侧导航菜单
let navigationList = ref([]);
// 大图预览
let previewInitialIndex = ref(0);
let showImagePreview = ref(false);
let showImagePreviewList = ref([]);
let markdownToolbars = ref({fullscreen: true, readmodel: true,});
// 下载为Word
let downloadFormParam = ref({url: 'zyplayer-doc-wiki/page/download', param: {},});
let route = useRoute();
let router = useRouter();
2019-05-30 22:45:22 +08:00
2023-01-11 20:33:42 +08:00
let storePage = useStorePageData();
const props = defineProps({
spaceInfo: Object,
});
let emit = defineEmits(['switchSpace', 'changeExpandedKeys', 'loadPageList']);
onBeforeRouteUpdate((to) => {
initQueryParam(to);
2023-01-11 20:33:42 +08:00
});
onMounted(() => {
initQueryParam(route);
});
const editWiki = () => {
let param = {pageId: parentPath.value.pageId}
pageApi.pageLock(param).then(() => {
router.push({
path: '/page/edit',
query: {pageId: parentPath.value.pageId}
})
})
}
const getSearchUserList = (query) => {
if (query == '') return
pageAuthUserLoading.value = true
userApi.getUserBaseInfo({search: query}).then((json) => {
searchUserList.value = json.data || []
pageAuthUserLoading.value = false
})
}
const addPageAuthUser = () => {
if (pageAuthNewUser.value.length <= 0) {
ElMessage.warning('请先选择用户')
return
}
2023-01-11 20:33:42 +08:00
if (
!!searchUserList.value.find(
(item) => item.userId == pageAuthNewUser.value
)
) {
pageAuthNewUser.value = ''
return
}
2023-01-11 20:33:42 +08:00
let userName = ''
for (let i = 0; i < searchUserList.value.length; i++) {
if (pageAuthNewUser.value == searchUserList.value[i].id) {
userName = searchUserList.value[i].userName
break
}
}
2023-01-11 20:33:42 +08:00
pageAuthUserList.value.push({
userName: userName,
userId: pageAuthNewUser.value,
editPage: 0,
commentPage: 0,
deletePage: 0,
pageFileUpload: 0,
pageFileDelete: 0,
pageAuthManage: 0,
})
pageAuthNewUser.value = ''
}
const saveUserPageAuth = () => {
let param = {
pageId: wikiPage.value.id,
authList: JSON.stringify(pageAuthUserList.value),
}
2023-01-11 20:33:42 +08:00
pageApi.assignPageUserAuth(param).then(() => {
ElMessage.success('保存成功!')
})
}
const notOpen = () => {
ElMessage.warning('暂未开放')
}
const deleteUserPageAuth = (row) => {
2023-07-04 20:15:32 +08:00
let pageAuthUserList = [];
2023-01-11 20:33:42 +08:00
for (let i = 0; i < pageAuthUserList.value.length; i++) {
2023-07-04 20:15:32 +08:00
let item = pageAuthUserList.value[i];
if (item.userId !== row.userId) {
pageAuthUserList.push(pageAuthUserList.value[i]);
2023-01-11 20:33:42 +08:00
}
}
2023-07-04 20:15:32 +08:00
pageAuthUserList.value = pageAuthUserList;
2023-01-11 20:33:42 +08:00
}
const closeActionTab = () => {
2023-07-04 20:15:32 +08:00
storePage.commentShow = false;
clearHistory();
2023-01-11 20:33:42 +08:00
}
const getPageHistoryByScroll = () => {
if (pageHistoryPageNum.value <= 0) {
2023-07-04 20:15:32 +08:00
return;
}
2023-07-04 20:15:32 +08:00
pageHistoryPageNum.value++;
getPageHistory(wikiPage.value.id, pageHistoryPageNum.value);
2023-01-11 20:33:42 +08:00
}
const getPageHistory = (pageId, pageNum) => {
2023-07-04 20:15:32 +08:00
if (pageNum === 1) {
pageHistoryList.value = [];
pageHistoryPageNum.value = 1;
}
2023-07-04 20:15:32 +08:00
let param = {pageId: pageId, pageNum: pageNum};
2023-01-11 20:33:42 +08:00
pageApi.pageHistoryList(param).then((json) => {
2023-07-04 20:15:32 +08:00
let historyList = json.data || [];
2023-01-11 20:33:42 +08:00
if (historyList.length <= 0) {
2023-07-04 20:15:32 +08:00
pageHistoryPageNum.value = 0;
2023-01-11 20:33:42 +08:00
} else {
2023-07-04 20:15:32 +08:00
historyList.forEach((item) => (item.loading = 0));
pageHistoryList.value = pageHistoryList.value.concat(historyList);
2023-01-11 20:33:42 +08:00
}
})
}
const historyClick = (history) => {
if (pageHistoryChoice.value.id === history.id && !!pageHistoryDetail.value) {
2023-07-04 20:15:32 +08:00
return;
}
2023-07-04 20:15:32 +08:00
pageHistoryChoice.value.loading = 0;
pageHistoryChoice.value = history;
2023-01-11 20:33:42 +08:00
// 缓存一下,但如果历史页面多了而且很大就占内存,也可以每次去拉取,先这样吧
if (history.content) {
2023-07-04 20:15:32 +08:00
history.loading = 2;
pageHistoryDetail.value = history.content;
pageShowDetail.value = history.content;
2023-01-11 20:33:42 +08:00
setTimeout(() => {
2023-07-04 20:15:32 +08:00
previewPageImage();
createNavigationHeading();
2023-01-11 20:33:42 +08:00
}, 500)
} else {
history.loading = 1
2023-07-04 20:15:32 +08:00
pageApi.pageHistoryDetail({id: history.id}).then((json) => {
history.loading = 2;
history.content = json.data || '--';
if (wikiPage.value.editorType === 2) {
history.content = mavonEditor.getMarkdownIt().render(history.content);
}
pageHistoryDetail.value = history.content;
pageShowDetail.value = history.content;
setTimeout(() => {
previewPageImage();
createNavigationHeading();
}, 500);
}).catch(() => {
history.loading = 3;
});
}
2023-01-11 20:33:42 +08:00
}
const clearHistory = () => {
2023-07-04 20:15:32 +08:00
pageHistoryChoice.value.loading = 0;
pageHistoryDetail.value = '';
pageHistoryChoice.value = {};
pageHistoryList.value.forEach((item) => (item.loading = 0));
pageShowDetail.value = pageContent.value.content;
2023-01-11 20:33:42 +08:00
}
const computeFileSize = (fileSize) => {
return unitUtil.computeFileSize(fileSize)
}
const loadPageDetail = (pageId) => {
clearHistory()
pageApi.pageDetail({id: pageId}).then((json) => {
2023-07-04 20:15:32 +08:00
let result = json.data || {};
let wikiPageRes = result.wikiPage || {};
wikiPageRes.selfZan = result.selfZan || 0;
wikiPage.value = wikiPageRes;
pageContent.value = result.pageContent || {};
storePage.fileList = result.fileList || [];
selfUserId.value = result.selfUserId || 0;
uploadFormData.value = {pageId: wikiPage.value.id};
2023-01-11 20:33:42 +08:00
wikiPageAuth.value = {
canEdit: result.canEdit,
canDelete: result.canDelete,
canUploadFile: result.canUploadFile,
canDeleteFile: result.canDeleteFile,
canConfigAuth: result.canConfigAuth,
}
if (wikiPage.value.editorType === 2) {
pageContent.value.content = mavonEditor.getMarkdownIt().render(pageContent.value.content);
2023-01-11 20:33:42 +08:00
}
pageShowDetail.value = pageContent.value.content;
2023-01-11 20:33:42 +08:00
// 修改标题
document.title = wikiPageRes.name || 'WIKI-内容展示';
2023-01-11 20:33:42 +08:00
// 修改最后点击的项,保证刷新后点击编辑能展示编辑的项
// if (!lastClickNode.value.id) {
// lastClickNode.value = {id: wikiPage.id, nodePath: wikiPage.name};
// }
// 调用父方法切换选择的空间
emit('switchSpace', wikiPage.value.spaceId);
// 调用父方法展开目录树
emit('changeExpandedKeys', pageId);
setTimeout(() => {
previewPageImage();
createNavigationHeading();
2023-01-11 20:33:42 +08:00
}, 500);
storePage.pageInfo = wikiPageRes;
storePage.pageAuth = wikiPageAuth.value;
2023-01-11 20:33:42 +08:00
})
getPageHistory(pageId, 1)
}
let wikiTitleRef = ref();
const createNavigationHeading = () => {
2023-03-02 23:04:50 +08:00
let navigationListVal = htmlUtil.createNavigationHeading()
2023-01-11 20:33:42 +08:00
// 标题加到导航里面去
2023-03-02 23:04:50 +08:00
if (navigationListVal.length > 0) {
2023-01-11 20:33:42 +08:00
let wikiTile = wikiPage.value.name || 'WIKI-内容展示'
2023-03-02 23:04:50 +08:00
navigationListVal.unshift({
2023-01-11 20:33:42 +08:00
level: 1,
node: wikiTitleRef.value,
text: wikiTile,
})
}
2023-03-02 23:04:50 +08:00
navigationList.value = navigationListVal;
2023-01-11 20:33:42 +08:00
}
const closeImagePreview = () => {
showImagePreview.value = false
}
let pageContentRef = ref();
const previewPageImage = () => {
const imgArr = []
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
}
})
}
const zanPage = (yn) => {
let param = {yn: yn, pageId: wikiPage.value.id}
pageApi.updatePageZan(param).then(() => {
wikiPage.value.selfZan = yn
wikiPage.value.zanNum = wikiPage.value.zanNum + (yn == 1 ? 1 : -1)
})
}
const showZanPageUser = () => {
zanUserDialogVisible.value = true
zanUserList.value = []
let param = {pageId: wikiPage.value.id}
pageApi.pageZanList(param).then((json) => {
zanUserList.value = json.data
})
}
const deletePageFile = (row) => {
ElMessageBox.confirm('确定要删除此文件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
let param = {id: row.id};
2023-01-11 20:33:42 +08:00
pageApi.deletePageFile(param).then(() => {
2023-07-04 20:15:32 +08:00
storePage.fileList = storePage.fileList.filter(item => item.id !== row.id);
});
2023-01-11 20:33:42 +08:00
})
}
const getUserHeadBgColor = (userId) => {
let color = page.userHeadColor[userId]
if (!color) {
color =
page.colorArr[Math.ceil(Math.random() * page.colorArr.length) - 1]
page.userHeadColor[userId] = color
}
2023-01-11 20:33:42 +08:00
return color
}
const initQueryParam = (to) => {
parentPath.value = {pageId: to.query.pageId}
if (!!parentPath.value.pageId) {
loadPageDetail(parentPath.value.pageId)
}
2023-01-11 20:33:42 +08:00
}
</script>
2023-01-11 23:28:20 +08:00
<style lang="scss" scoped>
.page-show-vue {
.wiki-page-content {
margin-top: 20px;
2023-01-11 23:28:20 +08:00
}
}
</style>
<style lang="scss">
2023-01-11 20:33:42 +08:00
.page-show-vue {
height: 100%;
overflow: hidden;
.wiki-page-content {
ol {
list-style: decimal;
}
ul {
list-style: disc;
}
}
2023-01-11 20:33:42 +08:00
}
</style>
<style>
@import '../../assets/lib/wangEditor.css';
2023-01-11 20:33:42 +08:00
.page-show-vue .icon-collapse {
float: left;
font-size: 25px;
color: #aaa;
margin-top: 8px;
cursor: pointer;
}
.page-show-vue .icon-collapse:hover {
color: #eee;
}
.page-show-vue .wiki-title {
font-size: 2em;
2023-01-11 20:33:42 +08:00
text-align: center;
font-weight: bold;
}
2019-05-30 22:45:22 +08:00
2023-01-11 20:33:42 +08:00
.page-show-vue .create-user-time {
margin-right: 20px;
}
.page-show-vue .wiki-author {
font-size: 14px;
color: #888;
padding: 20px 0;
height: 40px;
line-height: 40px;
}
.page-show-vue .wiki-page-content img {
cursor: pointer;
max-width: 100%;
}
.page-show-vue .wiki-page-content img:hover {
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.3);
}
.page-show-vue .upload-page-file .el-upload-list {
display: none;
}
.page-show-vue .is-link {
color: #1e88e5;
cursor: pointer;
}
.page-show-vue #newPageContentDiv .w-e-text-container {
height: 600px !important;
}
.page-show-vue .head {
float: left;
background-color: #ccc;
border-radius: 50%;
margin-right: 10px;
width: 45px;
height: 45px;
line-height: 45px;
text-align: center;
color: #fff;
}
.page-show-vue .el-tabs__header {
margin: 0;
}
.page-show-vue .el-tabs__nav-wrap {
padding: 0 20px;
}
.page-show-vue .close-action-tab {
position: absolute;
right: 15px;
top: 12px;
cursor: pointer;
z-index: 1;
}
.page-show-vue .action-tab-box {
height: calc(100vh - 120px);
overflow: auto;
padding: 20px 10px;
}
.page-show-vue .action-box-empty {
text-align: center;
padding-top: 30px;
color: #888;
font-size: 14px;
}
.page-show-vue .history-item {
height: 55px;
line-height: 25px;
cursor: pointer;
vertical-align: middle;
}
.page-show-vue .history-loading-status {
margin-left: 5px;
color: #67c23a;
}
.page-show-vue .history-loading-status.el-icon-circle-close {
color: #f56c6c;
}
.page-show-vue .el-timeline {
padding-inline-start: 0;
}
2023-05-04 19:57:35 +08:00
.page-show-vue .markdown-body table {
display: table;
}
2023-01-11 20:33:42 +08:00
.mobile-qr {
width: 250px;
height: 250px;
border: 1px solid #ccc;
display: inline-block;
border-radius: 4px;
margin-bottom: 10px;
padding: 5px;
}
</style>