文档展示样式优化

This commit is contained in:
sswiki
2023-09-26 16:13:45 +08:00
parent 66904f0bb4
commit 75577350ba
16 changed files with 1779 additions and 10701 deletions

View File

@@ -19,9 +19,9 @@
<script setup>
import {useStoreDisplay} from '@/store/wikiDisplay.js'
import LeftSideBar from './LeftSideBar'
import RightHeader from './RightHeader'
import RightResize from './RightResize'
import LeftSideBar from './LeftSidebar.vue'
import RightHeader from './RightHeader.vue'
import RightResize from './RightResize.vue'
let storeDisplay = useStoreDisplay();
const rightAsideWidthChange = (width) =>{
storeDisplay.rightAsideWidth = width
@@ -63,16 +63,10 @@
.el-header {
color: #333;
line-height: 100px;
height: 60px !important;
border-bottom: 0.5px solid #eaeaea;
}
.fold-btn {
color: #ccc !important;
font-size: 18px;
}
.head-icon {
margin-right: 15px;
margin-top: 15px;
@@ -119,81 +113,74 @@
</style>
<style lang="scss">
.space-folder-box {
margin-left: 10px;
margin-bottom: 10px;
position: relative;
.space-folder-box {
margin-left: 10px;
margin-bottom: 10px;
position: relative;
}
.folder-action-dropdown-btn {
padding: 0 8px;
height: 25px;
position: absolute;
right: 0;
.wiki-page-tree-box {
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 30px;
.el-tree-node__content {
height: 35px;
position: relative;
.page-tree-node {
width: 100%;
.label {
.el-icon {
vertical-align: middle;
}
.text {
margin-left: 5px;
vertical-align: middle;
max-width: calc(100% - 40px);
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.rename-input {
width: 90%;
}
.page-action-box {
position: absolute;
right: 0;
top: 0;
height: 35px;
line-height: 35px;
background: #fff;
border-radius: 4px;
display: none;
.page-action-dropdown-btn {
padding: 0 8px;
height: 35px;
margin-top: -1px;
}
.el-button + .el-button {
margin-left: 0;
}
}
.page-action-box.renaming {
display: none !important;
}
}
.wiki-page-tree-box {
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 30px;
.el-tree-node__content {
height: 35px;
position: relative;
.page-tree-node {
width: 100%;
.label {
.el-icon {
vertical-align: middle;
}
.text {
margin-left: 5px;
vertical-align: middle;
max-width: calc(100% - 40px);
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.rename-input {
width: 90%;
}
.page-action-box {
position: absolute;
right: 0;
top: 0;
height: 35px;
line-height: 35px;
background: #fff;
border-radius: 4px;
display: none;
.page-action-dropdown-btn {
padding: 0 8px;
height: 35px;
margin-top: -1px;
}
.el-button+.el-button {
margin-left: 0;
}
}
.page-action-box.renaming {
display: none !important;
}
}
&:hover .page-action-box {
display: block;
}
}
&:hover .page-action-box {
display: block;
}
}
}
</style>

View File

@@ -21,43 +21,24 @@
</template>
<template v-slot:addMenuNode="{node,data}">
<div class="page-tree-node" @mouseover="changeNodeOptionStatus(data) ">
<div style="width: calc(100% - 30px);overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
<div class="node-content">
<!--图标-->
<el-icon v-if="data.editorType === 0" class="clickAddIcon"
style="margin-right: 5px;vertical-align: middle;">
<svg width="1em" height="1em" viewBox="0 0 48 48" fill="none">
<path d="M5 8C5 6.89543 5.89543 6 7 6H19L24 12H41C42.1046 12 43 12.8954 43 14V40C43 41.1046 42.1046 42 41 42H7C5.89543 42 5 41.1046 5 40V8Z"
fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></path>
<path d="M43 22H5" stroke="currentColor" stroke-width="4" stroke-linejoin="round"></path>
<path d="M5 16V28" stroke="currentColor" stroke-width="4" stroke-linecap="round"
stroke-linejoin="round"></path>
<path d="M43 16V28" stroke="currentColor" stroke-width="4" stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</el-icon>
<el-icon v-else-if="data.editorType === 1" class="clickAddIcon"
style="margin-right: 5px;vertical-align: middle;">
<svg width="1em" height="1em" viewBox="0 0 48 48" fill="none">
<rect x="6" y="6" width="36" height="36" rx="3" fill="none" stroke="currentColor"
stroke-width="4"></rect>
<path d="M14 16L18 32L24 19L30 32L34 16" stroke="currentColor" stroke-width="4"
stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</el-icon>
<el-icon v-else-if="data.editorType === 2" class="clickAddIcon"
style="margin-right: 5px;vertical-align: middle;">
<el-icon-document/>
</el-icon>
<span class="left-icon">
<template v-if="data.editorType === 0">
<FolderOpen v-if="node.expanded" class="el-icon"/>
<FolderClose v-else class="el-icon"/>
</template>
<template v-else-if="data.editorType === 1"><IconParkWord class="el-icon"/></template>
<template v-else-if="data.editorType === 2"><IconDocument class="el-icon"/></template>
</span>
<!--标题-->
<el-tooltip :content="data.tags" placement="top-start" :show-after="500"
v-if="data.shareStatus !== undefined">
<a-tag color="#f50">{{filterShareStatus(data.shareStatus)}}</a-tag>
<el-tooltip :content="data.tags" placement="top-start" :show-after="500" v-if="data.shareStatus !== undefined">
<a-tag color="warning" style="margin-inline-end: 4px;padding-inline: 4px;">{{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/>
<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;margin-right: 5px">
<el-tooltip :content="node.label" placement="top-start" :show-after="700">{{ node.label }}</el-tooltip>
</span>
<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
@@ -73,59 +54,23 @@
<el-button :icon="MoreFilled" text class="page-action-dropdown-btn"></el-button>
<template #overlay>
<a-menu>
<a-menu-item key="0" @click="rename(node,data)">
<el-icon class="clickAddIcon" style="margin-right: 5px">
<svg width="1em" height="1em" viewBox="0 0 48 48" fill="none">
<path d="M42 26V40C42 41.1046 41.1046 42 40 42H8C6.89543 42 6 41.1046 6 40V8C6 6.89543 6.89543 6 8 6L22 6"
stroke="currentColor" stroke-width="4" stroke-linecap="round"
stroke-linejoin="round"></path>
<path d="M14 26.7199V34H21.3172L42 13.3081L34.6951 6L14 26.7199Z"
fill="none" stroke="currentColor" stroke-width="4"
stroke-linejoin="round"></path>
</svg>
</el-icon>
重命名
<a-menu-item @click="rename(node,data)">
<IconParkEditTwo class="el-icon"/> 重命名
</a-menu-item>
<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 @click="deleteWikiPage(data.shareStatus)">
<IconParkDelete class="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/>
</el-icon>
复制文档
<a-sub-menu title="移动文档">
<template #icon><IconParkIntersection/></template>
<a-menu-item @click="openMoveMenu(false)">
<IconParkCopy/> 复制文档
</a-menu-item>
<a-menu-item key="4" @click="openMoveMenu(true)">
<el-icon class="clickAddIcon" style="margin-right: 5px">
<Scissor/>
</el-icon>
迁移文档
<a-menu-item @click="openMoveMenu(true)">
<IconParkCuttingOne/> 迁移文档
</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 v-if="data.editorType !== 0" @click="openTemplateCreate(data.shareStatus !== undefined)">
<IconParkPageTemplate/> 设为模板
</a-menu-item>
</a-menu>
</template>
@@ -135,268 +80,278 @@
</div>
</template>
</LeftSidebarCli>
<templateManage ref="templateManageRef" :pageId="storePage.optionPageId" :spaceId="storeSpace.chooseSpaceId"
@doGetPageList="doGetPageList"/>
<create-space ref="createSpaceRef" @success="loadSpaceList"></create-space>
<a-modal
v-model:open="visibleMoveMenu"
title="选择"
@ok="handleOk"
@cancel="handleCancel"
ok-text="确认"
cancel-text="取消"
:confirm-loading="aModalWaiting"
:destroyOnClose=true
:closable=false>
<LeftSidebarCli
:readOnly=true
:wikiPageList="moveToWikiPageList"
:spaceOptions="storeSpace.spaceOptions"
:nowPageId="moveToPageId"
:choiceSpace="moveToSpaceId"
@setNowPageId="setNowPageId"
@doGetPageList="doGetPageList"
@spaceChangeEvents="spaceChangeEvents"/>
<TemplateManage ref="templateManageRef" :pageId="storePage.optionPageId" :spaceId="storeSpace.chooseSpaceId" @doGetPageList="doGetPageList"/>
<create-space ref="createSpaceRef" @success="loadSpaceList"/>
<a-modal v-model:open="visibleMoveMenu"
title="选择"
@ok="handleOk"
@cancel="handleCancel"
ok-text="确认"
cancel-text="取消"
:confirm-loading="aModalWaiting"
:destroyOnClose="true"
:closable="false">
<LeftSidebarCli :readOnly="true"
:wikiPageList="moveToWikiPageList"
:spaceOptions="storeSpace.spaceOptions"
:nowPageId="moveToPageId"
:choiceSpace="moveToSpaceId"
@setNowPageId="setNowPageId"
@doGetPageList="doGetPageList"
@spaceChangeEvents="spaceChangeEvents"/>
</a-modal>
</template>
<script setup>
import {
Document as ElIconDocument,
Fold as ElIconFold,
Expand as ElIconExpand,
Upload as ElIconUpload,
Bell as ElIconBell,
Setting as ElIconSetting,
Plus as ElIconPlus,
Check as ElIconCheck,
Files,
Scissor,
DocumentCopy,
MoreFilled
} from '@element-plus/icons-vue'
import {
MoreFilled
} from '@element-plus/icons-vue'
import {
FolderClose,
FolderOpen,
Word as IconParkWord,
Copy as IconParkCopy,
CuttingOne as IconParkCuttingOne,
Intersection as IconParkIntersection,
Delete as IconParkDelete,
EditTwo as IconParkEditTwo,
PageTemplate as IconParkPageTemplate,
} from '@icon-park/vue-next'
import {ref, onMounted,} from 'vue';
import {useRouter, useRoute} from "vue-router";
import {ElMessageBox, ElMessage} from 'element-plus'
import pageApi from '../../assets/api/page'
import CreateSpace from '../space/CreateSpace.vue'
import TemplateManage from '../template/TemplateManage.vue'
import AddMenu from '../leftSideBar/AddMenu.vue'
import IconDocument from '@/components/base/IconDocument.vue'
import LeftSidebarCli from '../leftSideBar/LeftSidebarCli.vue'
import {useStoreDisplay} from '@/store/wikiDisplay.js'
import {useStorePageData} from "@/store/pageData";
import {DownOutlined, BuildOutlined, BlockOutlined} from '@ant-design/icons-vue';
import {useStoreSpaceData} from "@/store/spaceData";
import {ref, onMounted,} from 'vue';
import { useRouter, useRoute} from "vue-router";
import {ElMessageBox, ElMessage} from 'element-plus'
import pageApi from '../../assets/api/page'
import CreateSpace from '../space/CreateSpace'
import TemplateManage from '../template/TemplateManage'
import RightResize from './RightResize.vue'
import AddMenu from '../LeftSidebar/AddMenu.vue'
import LeftSidebarCli from '../LeftSidebar/LeftSidebarCli.vue'
import {useStoreDisplay} from '@/store/wikiDisplay.js'
import {useStorePageData} from "@/store/pageData";
import {DownOutlined, BuildOutlined, BlockOutlined} from '@ant-design/icons-vue';
import {useStoreSpaceData} from "@/store/spaceData";
let route = useRoute();
let router = useRouter();
let storePage = useStorePageData();
let storeDisplay = useStoreDisplay();
let storeSpace = useStoreSpaceData();
let route = useRoute();
let router = useRouter();
let storePage = useStorePageData();
let storeDisplay = useStoreDisplay();
let storeSpace = useStoreSpaceData();
// 空间搜索相关
let nowSpaceShow = ref({});
let moveToPageId = ref(0);
let moveToSpaceId = ref(0);
let moveToWikiPageList = ref([]);
// 空间搜索相关
let nowSpaceShow = ref({});
let moveToPageId = ref(0);
let moveToSpaceId = ref(0);
let moveToWikiPageList = ref([]);
// 页面展示相关
let wikiPage = ref({});
let wikiPageExpandedKeys = ref([]);
let rightAsideWidth = ref(300);
let optionPageId = ref('');
let visibleMoveMenu = ref(false);
let onlyMoveMode = ref(false);
let aModalWaiting = ref(false);
let templateManageRef = ref(null)
// 页面展示相关
let wikiPage = ref({});
let wikiPageExpandedKeys = ref([]);
let rightAsideWidth = ref(300);
let optionPageId = ref('');
let visibleMoveMenu = ref(false);
let onlyMoveMode = ref(false);
let aModalWaiting = ref(false);
let templateManageRef = ref(null)
onMounted(() => {
init()
})
const init = () => {
loadSpaceList()
}
onMounted(()=>{
init()
})
const init = () => {
loadSpaceList()
const openTemplateCreate = (exsit) => {
templateManageRef.value.showTemplateCreate(exsit)
}
const createWikiByTemplate = () => {
templateManageRef.value.showTemplateManage()
}
const filterShareStatus = (data) => {
if (data === 1) {
return '公共模板'
}
return '个人模板'
}
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
moveToPageId.value = storePage.choosePageId
moveToSpaceId.value = storeSpace.chooseSpaceId
moveToWikiPageList.value = storePage.wikiPageList
}
const handleOk = (onlyMove) => {
aModalWaiting.value = true
if (onlyMoveMode.value) {
pageApi.movePage({
const openMoveMenu = (onlyMove) => {
onlyMoveMode.value = onlyMove
visibleMoveMenu.value = true
moveToPageId.value = storePage.choosePageId
moveToSpaceId.value = storeSpace.chooseSpaceId
moveToWikiPageList.value = storePage.wikiPageList
}
const handleOk = (onlyMove) => {
aModalWaiting.value = true
if (onlyMoveMode.value) {
pageApi.movePage({
"id": storePage.optionPageId,
"spaceId": storeSpace.chooseSpaceId,
"moveToPageId": moveToPageId.value,
"moveToSpaceId": moveToSpaceId.value
})
.then((json) => {
doGetPageList(null)
ElMessage.success('迁移成功')
handleCancel()
aModalWaiting.value = false
}).catch((e) => {
.then((json) => {
doGetPageList(null)
ElMessage.success('迁移成功')
handleCancel()
aModalWaiting.value = false
})
return
}
pageApi.copyPage({
}).catch((e) => {
aModalWaiting.value = false
})
return
}
pageApi.copyPage({
"id": storePage.optionPageId,
"spaceId": storeSpace.chooseSpaceId,
"moveToPageId": moveToPageId.value,
"moveToSpaceId": moveToSpaceId.value
})
.then((json) => {
doGetPageList(null)
ElMessage.success('复制成功')
handleCancel()
aModalWaiting.value = false
}).catch((e) => {
.then((json) => {
doGetPageList(null)
ElMessage.success('复制成功')
handleCancel()
aModalWaiting.value = false
}).catch((e) => {
aModalWaiting.value = false
})
return
}
const handleCancel = () => {
visibleMoveMenu.value = false
moveToPageId.value = 0
moveToSpaceId.value = 0
moveToWikiPageList.value = []
}
const deleteWikiPage = (share) => {
let msg = '确定要删除此页面及其所有子页面吗?'
if (share !== undefined) {
msg = '选中的页面是:' + filterShareStatus(share) + '删除后无法使用此模板! 确定要删除此页面及其所有子页面吗?'
}
ElMessageBox.confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
let param = {pageId: optionPageId.value};
pageApi.pageDelete(param).then(() => {
ElMessage.success('已删除')
doGetPageList(null)
});
}).catch(() => {
});
}
const choosePageIdFunc = (id) => {
storePage.optionPageId = id
}
const setNowPageId = (id, readOnly) => {
if (readOnly) {
moveToPageId.value = id
return
}
storePage.choosePageId = id
}
const rename = (node, data) => {
data.renaming = true
}
const doRename = (node, data) => {
pageApi.renamePage({"id": data.id, "name": data.name})
.then((json) => {
doGetPageList(null)
ElMessage.success('重命名成功')
data.renaming = false
})
}
const changeNodeOptionStatus = (param) => {
optionPageId.value = param.id
}
let createSpaceRef = ref();
const spaceChangeEvents = (data, readonly) => {
storePage.pageInfo = {}
if (readonly) {
moveToSpaceId.value = data
setNowPageId(0, readonly)
let param = {spaceId: moveToSpaceId.value}
pageApi.pageList(param).then((json) => {
moveToWikiPageList.value = json.data || []
})
return
}
const handleCancel = () => {
visibleMoveMenu.value = false
moveToPageId.value = 0
moveToSpaceId.value = 0
moveToWikiPageList.value = []
if (data === 0) {
// 新建空间
createSpaceRef.value.show();
} else if (data === -1) {
// 管理空间
router.push({path: '/space/manage'});
} else {
storePage.choosePageId = 0;
storeSpace.chooseSpaceId = Number(data);
nowSpaceShow.value = storeSpace.spaceList.find((item) => item.id === data);
storeSpace.spaceInfo = nowSpaceShow.value;
doGetPageList(null);
router.push({path: '/home', query: {spaceId: data}});
}
const deleteWikiPage = (share) => {
let msg = '确定要删除此页面及其所有子页面吗?'
if (share !== undefined) {
msg = '选中的页面是:' + filterShareStatus(share) + '删除后无法使用此模板! 确定要删除此页面及其所有子页面吗?'
}
ElMessageBox.confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
let param = {pageId: optionPageId.value};
pageApi.pageDelete(param).then(() => {
ElMessage.success('已删除')
doGetPageList(null)
});
}).catch(() => {
});
}
const choosePageIdFunc = (id) => {
storePage.optionPageId = id
}
const setNowPageId = (id, readOnly) => {
if (readOnly) {
moveToPageId.value = id
return
}
storePage.choosePageId = id
}
const rename = (node, data) => {
data.renaming = true
}
const doRename = (node, data) => {
pageApi.renamePage({"id": data.id, "name": data.name})
.then((json) => {
doGetPageList(null)
ElMessage.success('重命名成功')
data.renaming = false
})
}
const changeNodeOptionStatus = (param) => {
optionPageId.value = param.id
}
let createSpaceRef = ref();
const spaceChangeEvents = (data, readonly) => {
storePage.pageInfo = {}
if (readonly) {
moveToSpaceId.value = data
setNowPageId(0, readonly)
let param = {spaceId: moveToSpaceId.value}
pageApi.pageList(param).then((json) => {
moveToWikiPageList.value = json.data || []
})
return
}
if (data === 0) {
// 新建空间
createSpaceRef.value.show();
} else if (data === -1) {
// 管理空间
router.push({path: '/space/manage'});
} else {
storePage.choosePageId = 0;
storeSpace.chooseSpaceId = Number(data);
nowSpaceShow.value = storeSpace.spaceList.find((item) => item.id === data);
storeSpace.spaceInfo = nowSpaceShow.value;
doGetPageList(null);
router.push({path: '/home', query: {spaceId: data}});
}
}
const loadSpaceList = (spaceId) => {
pageApi.spaceList({}).then((json) => {
storeSpace.spaceList = json.data || [];
let spaceOptionsNew = [];
storeSpace.spaceList.forEach((item) => spaceOptionsNew.push({label: item.name, value: item.id}));
storeSpace.spaceOptions = spaceOptionsNew;
if (storeSpace.spaceList.length > 0) {
let nowSpaceId = spaceId;
let nowSpaceShowTemp = storeSpace.spaceList.find((item) => item.id === spaceId);
if (!nowSpaceShowTemp) {
nowSpaceShowTemp = storeSpace.spaceList[0];
nowSpaceId = nowSpaceShowTemp.id;
}
nowSpaceShow.value = nowSpaceShowTemp;
storeSpace.spaceInfo = nowSpaceShowTemp;
storeSpace.chooseSpaceId = nowSpaceId;
storePage.choosePageId = 0;
doGetPageList(null);
// TODO 在首页时跳转
try {
if (route.path === '/home') {
router.push({path: '/home', query: {spaceId: nowSpaceId}});
}
} catch (e) {
console.log(e);
}
}
const loadSpaceList = (spaceId) => {
pageApi.spaceList({}).then((json) => {
storeSpace.spaceList = json.data || [];
let spaceOptionsNew = [];
storeSpace.spaceList.forEach((item) => spaceOptionsNew.push({label: item.name, value: item.id}));
storeSpace.spaceOptions = spaceOptionsNew;
if (storeSpace.spaceList.length > 0) {
let nowSpaceId = spaceId;
let nowSpaceShowTemp = storeSpace.spaceList.find((item) => item.id === spaceId);
if (!nowSpaceShowTemp) {
nowSpaceShowTemp = storeSpace.spaceList[0];
nowSpaceId = nowSpaceShowTemp.id;
}
})
}
nowSpaceShow.value = nowSpaceShowTemp;
storeSpace.spaceInfo = nowSpaceShowTemp;
storeSpace.chooseSpaceId = nowSpaceId;
storePage.choosePageId = 0;
doGetPageList(null);
// TODO 在首页时跳转
try {
if (route.path === '/home') {
router.push({path: '/home', query: {spaceId: nowSpaceId}});
}
} catch (e) {
console.log(e);
}
}
})
}
const doGetPageList = (parentId, node) => {
let param = {spaceId: storeSpace.chooseSpaceId}
pageApi.pageList(param).then((json) => {
storePage.wikiPageList = json.data || []
})
}
defineExpose({init})
const doGetPageList = (parentId, node) => {
let param = {spaceId: storeSpace.chooseSpaceId}
pageApi.pageList(param).then((json) => {
storePage.wikiPageList = json.data || []
})
}
defineExpose({init})
</script>
<style lang="scss">
.page-tree-node {
.node-content {
width: calc(100% - 30px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.left-icon {
margin-right: 6px;
}
}
}
</style>

View File

@@ -1,115 +1,57 @@
<template>
<el-row class="right-header-box">
<el-col :span="1">
<el-button @click="turnLeftCollapse" v-if="storeDisplay.showMenu" text :icon="ElIconFold" class="fold-btn"></el-button>
<el-button @click="turnLeftCollapse" v-else text :icon="ElIconExpand" class="fold-btn"></el-button>
</el-col>
<el-col :span="9" class="title-info-view">
<div class="wikititle" ref="wikiTitleRef" v-if="storePage.pageInfo.name">
<span class="create-user-time">
{{storePage.pageInfo.name}}
</span>
<br/>
<span v-if="storePage.pageInfo.updateUserName">
{{ storePage.pageInfo.updateUserName }}
<span class="split"></span>
{{ storePage.pageInfo.updateTime }}
<span class="split">修改</span>
</span>
<span v-else class="create-user-time">
{{ storePage.pageInfo.createUserName }}
<span class="split"></span>
{{ storePage.pageInfo.createTime }}
<span class="split">创建</span>
</span>
<el-row>
<el-col :span="12">
<div class="left-action-box">
<div class="collapse-box">
<el-button @click="turnLeftCollapse" v-if="storeDisplay.showMenu" text :icon="ElIconFold" class="fold-btn"></el-button>
<el-button @click="turnLeftCollapse" v-else text :icon="ElIconExpand" class="fold-btn"></el-button>
</div>
<div class="title-time-box">
<div class="title">
<span class="text">{{storePage.pageInfo.name || ''}}</span>
</div>
<div class="time">最近修改{{storePage.pageInfo.updateTime || ''}}</div>
</div>
</div>
</el-col>
<el-col :span="12" style="text-align: right" class = "dropdown-menu">
<el-tooltip v-if="storePage.pageAuth.canEdit === 1 && storePage.pageInfo.name && storePage.pageInfo.editorType !== 0" effect="dark" content="编辑文档"
placement="top">
<ElIconEdit @click="editWiki" type="primary" class="right-header-icon"></ElIconEdit>
</el-tooltip>
<el-tooltip v-if="storePage.pageAuth.canEdit === 1 && storePage.pageInfo.name && storePage.pageInfo.editorType !== 0" effect="dark" content="文档相关"
placement="top">
<ElIconChatLineRound @click="showCommentWiki" class="right-header-icon"></ElIconChatLineRound>
</el-tooltip>
<el-tooltip v-if="storePage.pageInfo.name" effect="dark" content="更多操作" placement="top">
<el-dropdown trigger="click" class="action-btn more-dropdown" >
<el-icon class="right-header-icon" style="margin-top: 18px;margin-left: 5px">
<el-icon-more/>
</el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="editWikiAuth" v-if="storePage.pageAuth.canConfigAuth === 1 && storePage.pageInfo.editorType !== 0"
:icon="ElIconSCheck">权限设置
</el-dropdown-item>
<el-dropdown-item @click="showOpenPage" v-if="storeSpace.spaceInfo.openDoc === 1 && storePage.pageInfo.editorType !== 0"
:icon="ElIconShare">查看开放文档
</el-dropdown-item>
<el-dropdown-item @click="showMobileView" v-if="storeSpace.spaceInfo.openDoc === 1 && storePage.pageInfo.editorType !== 0"
:icon="ElIconMobilePhone">手机端查看
</el-dropdown-item>
<el-dropdown-item @click="exportWord" :icon="ElIconDownload" v-if="storePage.pageInfo.editorType !== 0">导出为Word文档</el-dropdown-item>
<el-dropdown-item @click="deleteWikiPage" v-if="storePage.pageAuth.canDelete === 1"
:icon="ElIconDelete">删除
</el-dropdown-item>
</el-dropdown-menu>
<el-col :span="12" style="text-align: right;">
<div class="header-action-box">
<el-tooltip v-if="storePage.pageAuth.canEdit === 1" content="编辑文档">
<el-button class="hover-button" @click="editWiki" text><IconParkEdit size="18"/></el-button>
</el-tooltip>
<el-tooltip content="文档沟通">
<el-button class="hover-button" @click="showCommentWiki" text><IconParkCommunication size="18"/></el-button>
</el-tooltip>
<UserMessagePopover/>
<a-dropdown trigger="click" placement="bottom" overlayClassName="header-action-more-dropdown">
<span style="line-height: 60px;display:inline-block;margin: 0 12px;">
<el-button :icon="ElIconMoreFilled" class="hover-button" text></el-button>
</span>
<template #overlay>
<a-menu>
<a-menu-item @click="editWikiAuth" v-if="storePage.pageAuth.canConfigAuth === 1"><el-icon><ElIconSCheck/></el-icon> 权限设置</a-menu-item>
<a-menu-item @click="showOpenPage" v-if="storeSpace.spaceInfo.openDoc === 1"><el-icon><ElIconShare/></el-icon> 查看开放文档</a-menu-item>
<a-menu-item @click="showMobileView" v-if="storeSpace.spaceInfo.openDoc === 1"><el-icon><ElIconMobilePhone/></el-icon> 手机端查看</a-menu-item>
<a-menu-item @click="exportWord"><el-icon><ElIconDownload/></el-icon>导出为Word</a-menu-item>
<a-menu-divider />
<a-menu-item @click="deleteWikiPage" v-if="storePage.pageAuth.canDelete === 1" class="delete"><el-icon><ElIconDelete/></el-icon> 删除</a-menu-item>
</a-menu>
</template>
</el-dropdown>
</el-tooltip>
<span class="header-right-user-name">{{userSelfInfo.userName}}</span>
<el-popover v-model:visible="userMessagePopVisible" placement="bottom" trigger="click" width="600">
<template v-slot:reference>
<el-badge :is-dot="haveNotReadUserMessage" >
<el-icon class="right-header-icon" >
<el-icon-bell/>
</el-icon>
</el-badge>
</template>
<div style="margin-bottom: 10px">
<span style="font-size: 14px; font-weight: bold">通知</span>
<el-link v-if="haveNotReadUserMessage" :icon="ElIconCheck" style="float: right" type="primary"
@click="readAllUserMessage">本页标记已读
</el-link>
</div>
<div class="header-user-message">
<el-table :data="userMessageList" border max-height="500" size="small"
style="width: 100%; margin-bottom: 5px">
<el-table-column label="操作人" prop="operatorUserName" width="100px"></el-table-column>
<el-table-column label="操作时间" prop="creationTime" width="140px"></el-table-column>
<el-table-column label="内容">
<template v-slot="scope">
{{ scope.row.msgContent }}
<el-badge :is-dot="scope.row.msgStatus == 0"
style="line-height: 10px; padding-right: 5px">
<el-link type="primary" @click="showUserMessage(scope.row)">查看</el-link>
</el-badge>
</template>
</el-table-column>
</el-table>
<div class="page-info-box">
<el-pagination
:current-page="userMsgParam.pageNum"
:page-size="userMsgParam.pageSize"
:total="userMsgTotalCount"
layout="prev, pager, next, total"
@current-change="handleCurrentChange">
</el-pagination>
</div>
</div>
</el-popover>
<el-dropdown trigger="click" @command="userSettingDropdown" style="vertical-align: bottom;">
<el-icon class="right-header-icon">
<el-icon-setting/>
</el-icon>
<template v-slot:dropdown>
<el-dropdown-menu>
<el-dropdown-item command="console">控制台</el-dropdown-item>
<el-dropdown-item command="aboutDoc">关于</el-dropdown-item>
<el-dropdown-item command="userSignOut" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</a-dropdown>
<a-dropdown trigger="click" placement="bottom" overlayClassName="header-action-user-dropdown">
<span style="line-height: 60px;display:inline-block;">
<el-button :icon="ElIconUser" class="hover-button" text></el-button>
</span>
<template #overlay>
<a-menu>
<a-menu-item @click="showConsole">控制台</a-menu-item>
<a-menu-item @click="showAbout">关于</a-menu-item>
<a-menu-divider />
<a-menu-item @click="userSignOut">退出登录</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</el-col>
</el-row>
<MobileQrScanDialog v-model:visible="mobileScanDialogVisible"/>
@@ -121,315 +63,273 @@
</template>
<script setup>
import {
Setting as ElIconSetting,
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,
More as ElIconMore,
Stamp as ElIconSCheck,
Bell as ElIconBell,
Share as ElIconShare,
Iphone as ElIconMobilePhone,
Download as ElIconDownload,
Fold as ElIconFold,
Expand as ElIconExpand,
Check as ElIconCheck,
Back as ElIconBack,
} from '@element-plus/icons-vue'
import {toRefs, ref, reactive, onMounted, watch, computed} from 'vue';
import {onBeforeRouteUpdate, useRoute, useRouter} from "vue-router";
import {ElMessageBox, ElMessage, ElNotification} from 'element-plus';
import pageApi from '@/assets/api/page'
import PageAuthDialog from '../../views/page/show/PageAuthDialog.vue'
import MobileQrScanDialog from '../../views/page/show/MobileQrScanDialog.vue'
import {useStorePageData} from "@/store/pageData";
import {useStoreDisplay} from "@/store/wikiDisplay";
import {useStoreSpaceData} from "@/store/spaceData";
import {useStoreUserData} from "@/store/userData";
import userApi from "@/assets/api/user";
import AboutDialog from "../../views/common/AboutDialog"
import {
Fold as ElIconFold,
Expand as ElIconExpand,
Delete as ElIconDelete,
Stamp as ElIconSCheck,
Share as ElIconShare,
Iphone as ElIconMobilePhone,
Download as ElIconDownload,
MoreFilled as ElIconMoreFilled,
Setting as ElIconSetting,
User as ElIconUser,
} from '@element-plus/icons-vue'
import {
Star as IconParkStar,
Edit as IconParkEdit,
Communication as IconParkCommunication,
} from '@icon-park/vue-next'
import {toRefs, ref, reactive, onMounted, watch, defineEmits, computed} from 'vue';
import {useRouter, useRoute} from "vue-router";
import { ElMessageBox, ElMessage } from 'element-plus'
import { useStoreDisplay } from '@/store/wikiDisplay.js'
import { useStorePageData } from '@/store/pageData.js'
import { useStoreUserData } from '@/store/userData.js'
import pageApi from "@/assets/api/page";
import {useStoreSpaceData} from "@/store/spaceData";
import userApi from "@/assets/api/user";
import PageAuthDialog from '@/views/page/show/PageAuthDialog.vue'
import MobileQrScanDialog from '@/views/page/show/MobileQrScanDialog.vue'
import AboutDialog from "@/views/common/AboutDialog.vue"
import UserMessagePopover from "./UserMessagePopover.vue"
let storePage = useStorePageData();
let storeDisplay = useStoreDisplay();
let router = useRouter();
let storeSpace = useStoreSpaceData();
let storeUser = useStoreUserData();
let storePage = useStorePageData();
let storeDisplay = useStoreDisplay();
let storeUser = useStoreUserData();
let storeSpace = useStoreSpaceData();
let userSelfInfo = ref({});
let userMessageList = ref([]);
let haveNotReadUserMessage = ref(false);
let userMessagePopVisible = ref(false);
let userMsgTotalCount = ref(0);
let userMsgParam = ref({sysType: 2, pageNum: 1, pageSize: 20,});
let titleInput = ref('')
const emit = defineEmits(['collapse']);
onMounted(()=>{
init()
})
const init=()=>{
getSelfUserInfo()
loadUserMessageList();
}
let pageAuthDialogVisible = ref(false);
const editWikiAuth = () => {
pageAuthDialogVisible.value = true;
}
const showOpenPage = () => {
if (storeSpace.spaceInfo.openDoc !== 1) {
ElMessage.warning('该空间未开放,无法查看开放文档地址');
let turnLeftCollapse = () => {
storeDisplay.showMenu = !storeDisplay.showMenu;
setTimeout(() => {
if (storeDisplay.showMenu) {
storeDisplay.rightAsideWidth = 301;
} else {
let routeUrl = router.resolve({
path: '/page/share/view',
query: {pageId: storePage.pageInfo.id, space: storeSpace.spaceInfo.uuid}
});
window.open(routeUrl.href, '_blank');
storeDisplay.rightAsideWidth = 1;
}
}, 100);
};
// 清除控制台,和设置逻辑放远一点不容易被察觉
watch(() => storeUser.ts, () => {
console.clear();
});
watch(() => storePage.favoritePageChange, (newVal) => {
if (storePage.needVersion) {
ElMessage.warning("不支持在指定版本后收藏页面");
return;
}
const deleteWikiPage = () => {
ElMessageBox.confirm('确定要删除此页面及其所有子页面吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
pageApi.pageDelete({pageId: storePage.pageInfo.id}).then(() => {
pageApi.pageList({spaceId: storeSpace.chooseSpaceId}).then((json) => {
storePage.wikiPageList = json.data || []
}).then(()=>{
router.push({path: '/home', query: {spaceId: storePage.pageInfo.spaceId}});
})
});
}).catch((e) => {
console.log(e)
});
let favoritePage = (favorite) => {
storePage.favoritePageChange = {
id: storePage.pageInfo.id,
favorite: favorite,
};
};
const editWiki = () => {
// 锁定页面并进入编辑页面
storePage.pageIsUnlock = false;
let param = {pageId: storePage.pageInfo.id};
pageApi.pageLock(param).then(() => {
router.push({path: '/page/edit', query: {pageId: storePage.pageInfo.id}});
});
}
const showCommentWiki = () => {
storeDisplay.commentShow = !storeDisplay.commentShow;
}
let pageAuthDialogVisible = ref(false);
const editWikiAuth = () => {
pageAuthDialogVisible.value = true;
}
const showOpenPage = () => {
if (storeSpace.spaceInfo.openDoc !== 1) {
ElMessage.warning('该空间未开放,无法查看开放文档地址');
} else {
let routeUrl = router.resolve({
path: '/page/share/view',
query: {pageId: storePage.pageInfo.id, space: storeSpace.spaceInfo.uuid}
});
window.open(routeUrl.href, '_blank');
}
// 下载为Word
let downloadFormRef = ref();
let downloadFormParam = ref({url: 'zyplayer-doc-wiki/page/download', param: {}});
const exportWord = () => {
downloadFormParam.value.param = {pageId: storePage.pageInfo.id};
setTimeout(() => downloadFormRef.value.submit(), 0);
}
// 手机扫码
let mobileScanDialogVisible = ref(false);
const showMobileView = () => {
if (storeSpace.spaceInfo.openDoc !== 1) {
ElMessage.warning('该空间未开放,无法查看开放文档地址');
} else {
mobileScanDialogVisible.value = true;
}
}
const showCommentWiki = () => {
storePage.commentShow = true;
storePage.commentActiveTab = 'comment';
}
const editWiki = () => {
// 锁定页面并进入编辑页面
storePage.pageIsUnlock = false
titleInput.value = storePage.pageInfo.name
let param = {pageId: storePage.pageInfo.id};
pageApi.pageLock(param).then(() => {
router.push({path: '/page/edit', query: {pageId: storePage.pageInfo.id}});
});
}
const turnLeftCollapse = () => {
storeDisplay.showMenu = !storeDisplay.showMenu
setTimeout(() => {
if (storeDisplay.showMenu) {
storeDisplay.rightAsideWidth = 301
} else {
storeDisplay.rightAsideWidth = 1
}
}, 100)
}
const loadUserMessageIfPopVisible = () => {
if (!userMessagePopVisible.value) {
loadUserMessageList()
}
}
const loadUserMessageList = () => {
userApi.getUserMessageList(userMsgParam.value).then((res) => {
userMessageList.value = res.data || []
userMsgTotalCount.value = res.total || 0
haveNotReadUserMessage.value =
userMessageList.value.filter((item) => item.msgStatus == 0).length > 0
})
}
let aboutDialogRef = ref()
const userSettingDropdown = (command) => {
console.log('command:' + command)
if (command == 'userSignOut') {
userSignOut()
} else if (command == 'aboutDoc') {
aboutDialogRef.value.show()
} else if (command == 'myInfo') {
router.push({path: '/user/myInfo'})
} else if (command == 'console') {
window.open(import.meta.env.VITE_APP_BASE_API, '_blank')
} else {
ElMessage.warning('暂未开放')
}
}
const userSignOut = () => {
userApi.userLogout().then(() => {
location.reload()
})
}
const readAllUserMessage = () => {
let msgIds = []
userMessageList.value
.filter((item) => item.msgStatus == 0)
.forEach((item) => {
msgIds.push(item.id)
})
if (msgIds.length <= 0) return
userApi.readUserMessage({ids: msgIds.join(',')}).then(() => {
ElMessage.success('标记成功')
loadUserMessageList()
})
}
const showUserMessage = (row) => {
if (row.msgStatus == 0) {
userApi.readUserMessage({ids: row.id}).then(() => {
loadUserMessageList()
}
const deleteWikiPage = () => {
ElMessageBox.confirm('确定要删除此页面及其所有子页面吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
pageApi.pageDelete({pageId: storePage.pageInfo.id}).then(() => {
pageApi.pageList({spaceId: storeSpace.chooseSpaceId}).then((json) => {
storePage.wikiPageList = json.data || []
}).then(()=>{
router.push({path: '/home', query: {spaceId: storePage.pageInfo.spaceId}});
})
}
if (row.msgType >= 2 && row.msgType <= 14) {
router.push({path: '/page/show', query: {pageId: row.dataId}})
userMessagePopVisible.value = false
}
});
}).catch((e) => {
console.log(e)
});
}
// 下载为Word
let downloadFormRef = ref();
let downloadFormParam = ref({url: 'zyplayer-doc-wiki/page/download', param: {}});
const exportWord = () => {
downloadFormParam.value.param = {pageId: storePage.pageInfo.id};
setTimeout(() => downloadFormRef.value.submit(), 0);
}
// 手机扫码
let mobileScanDialogVisible = ref(false);
const showMobileView = () => {
if (storeSpace.spaceInfo.openDoc !== 1) {
ElMessage.warning('该空间未开放,无法查看开放文档地址');
} else {
mobileScanDialogVisible.value = true;
}
const handleCurrentChange = (val) => {
userMsgParam.value.pageNum = val
loadUserMessageList()
}
const getSelfUserInfo = () => {
userApi.getSelfUserInfo().then((json) => {
userSelfInfo.value = json.data
storeUser.userInfo = json.data
})
}
defineExpose({init})
}
const userSignOut = () => {
userApi.userLogout().then(() => {
location.reload();
});
}
let aboutDialogRef = ref();
const showAbout = () => {
aboutDialogRef.value.show();
}
const showConsole = () => {
window.open(import.meta.env.VITE_APP_BASE_API, '_blank')
}
</script>
<style scoped lang="scss">
.page-action-box {
padding: 30px 0;
<style lang="scss" scoped>
.left-action-box {
display: flex;
.page-create-info {
font-size: 14px;
color: #888;
.collapse-box {
line-height: 60px;
.split {
padding: 0 4px;
}
}
.page-action-list {
text-align: right;
}
.fold-btn {
font-size: 18px;
padding: 4px 10px;
color: #888 !important;
}
}
.title-time-box {
flex: 1;
padding: 5px 0 6px 10px;
overflow: hidden;
.title {
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
line-height: 28px;
.text {
vertical-align: middle;
}
}
.time {
font-size: 12px;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
}
}
.title-setting-box {
.setting-title {
font-size: 18px;
line-height: 60px;
padding-left: 10px;
.text {
display: inline-block;
}
}
}
}
</style>
<style lang="scss">
.right-header-box {
.page-action-list {
.header-right-user-name{
margin-left: 15px;
margin-right: 10px;
}
.dropdown-menu{
display: flex;
align-items: center;
position: absolute;
top: 10px;
right:0;
}
text-align: right;
.left-action-box {
.title-time-box {
.title {
.i-icon {
vertical-align: middle;
.el-icon {
margin-right: 4px;
}
.action-btn + .action-btn {
margin-left: 15px;
}
.upload-page-file {
display: inline;
vertical-align: middle;
}
.more-dropdown {
vertical-align: middle;
}
svg {
vertical-align: unset;
}
}
}
</style>
<style lang="scss">
.right-header-box{
padding: 5px 0;
overflow: hidden;;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
line-height: 28px;
.fold-btn{
margin-top: 7px;
padding: 10px 0;
color: #3d3a3a !important;
font-size: 18px;
}
.title-info-view{
font-size: 14px;
color: #454343;
.split{
padding: 0 4px;
}
}
.title-info-view-right{
text-align: right;
margin-left: 5px;
font-size: 14px;
color: #454343;
.split{
padding: 0 4px;
}
}
.page-title-input{
margin-top: 3px;
margin-left: 5px;
width: 100%;
height: 45px;
}
.page-info-news{
font-size: 14px;
line-height: 20px;
margin-top: 3px
}
.right-header-icon{
cursor: pointer;
width: 20px;
margin: 15px 10px;
vertical-align: bottom;
}
}
}
.title-setting-box {
.setting-title {
.tips-icon {
vertical-align: 0.1em;
margin-left: 6px;
}
}
}
.header-action-box {
display: inline-block;
line-height: 60px;
.disabled-btn-box {
margin-right: 10px;
}
.hover-button {
border: 0;
color: #888;
.i-icon svg {
vertical-align: middle;
}
}
.hover-button:focus {
color: #888;
background: #fff;
}
.hover-button:hover {
color: #888;
background: #eaeaea;
}
}
.header-action-user-dropdown {
width: 120px;
}
.header-action-more-dropdown {
width: 140px;
.delete {
color: #f00;
}
.delete.disabled {
cursor: not-allowed;
color: var(--el-text-color-disabled);
}
.cant-hover {
cursor: default;
}
.cant-hover:hover {
background: #fff;
}
}
</style>

View File

@@ -1,7 +1,5 @@
<template>
<div ref="rightResizeRef" class="right-resize">
<i ref="rightResizeBarRef">...</i>
</div>
<div ref="rightResizeRef" class="right-resize"></div>
</template>
<script setup>
@@ -13,16 +11,12 @@ onMounted(() => {
dragChangeRightAsideWidth();
});
let rightResizeRef = ref();
let rightResizeBarRef = ref();
const dragChangeRightAsideWidth = () => {
// 保留this引用
let resize = rightResizeRef.value
let resizeBar = rightResizeBarRef.value
resize.onmousedown = (e) => {
let startX = e.clientX
// 颜色改变提醒
resize.style.background = '#ccc'
resizeBar.style.background = '#aaa'
resize.left = resize.offsetLeft
document.onmousemove = (e2) => {
// 计算并应用位移量
@@ -39,9 +33,6 @@ const dragChangeRightAsideWidth = () => {
}
}
document.onmouseup = () => {
// 颜色恢复
resize.style.background = '#fafafa'
resizeBar.style.background = '#ccc'
document.onmousemove = null
document.onmouseup = null
}
@@ -50,24 +41,15 @@ const dragChangeRightAsideWidth = () => {
}
</script>
<style scoped>
<style scoped lang="scss">
.right-resize {
width: 5px;
height: 100%;
cursor: w-resize;
background: #fafafa;
}
width: 5px;
height: 100%;
cursor: w-resize;
background: #fafafa;
.right-resize i {
margin-top: 300px;
width: 5px;
height: 35px;
display: inline-block;
word-wrap: break-word;
word-break: break-all;
line-height: 8px;
border-radius: 5px;
&:hover {
background: #ccc;
color: #888;
}
}
</style>

View File

@@ -18,7 +18,7 @@ import {onBeforeUnmount, ref, onMounted, watch, defineProps, nextTick, defineEmi
import {onBeforeRouteUpdate, useRouter, useRoute} from "vue-router";
import {ElMessageBox, ElMessage} from 'element-plus'
import pageApi from '../../assets/api/page'
import PageTree from '../shareLayout/PageTree'
import PageTree from '../shareLayout/PageTree.vue'
import 'vant/es/icon/style/index';
import 'vant/es/popup/style/index';
import 'vant/es/cell/style/index';

View File

@@ -0,0 +1,156 @@
<template>
<span class="user-message-popover">
<el-tooltip content="文档通知">
<el-badge :value="notReadMessageNum" :max="99" :hidden="notReadMessageNum <= 0">
<el-button ref="remindButtonRef" class="hover-button" text><IconParkRemind size="18"/></el-button>
</el-badge>
</el-tooltip>
<el-popover v-model:visible="userMessagePopVisible" placement="bottom" :width="700" trigger="click"
popper-class="header-user-remind" ref="popoverRef"
:virtual-ref="remindButtonRef" virtual-triggering>
<div class="header">
<span class="title">文档通知</span>
<el-link v-if="notReadMessageNum > 0" :icon="ElIconCheck" type="primary" @click="readAllUserMessage">本页标记已读</el-link>
</div>
<div class="header-user-message">
<el-table :data="userMessageList" stripe max-height="400" style="width: 100%; margin-bottom: 5px">
<el-table-column label="操作时间" prop="creationTime" width="150px"></el-table-column>
<el-table-column label="内容" prop="msgContent" show-overflow-tooltip></el-table-column>
<el-table-column width="60px">
<template v-slot="scope">
<el-badge :is-dot="scope.row.msgStatus === 0" style="line-height: 10px; padding-right: 5px">
<el-link type="primary" @click="showUserMessage(scope.row)">查看</el-link>
</el-badge>
</template>
</el-table-column>
</el-table>
<div class="page-info-box">
<el-pagination background
:current-page="userMsgParam.pageNum"
:page-size="userMsgParam.pageSize"
:total="userMsgTotalCount"
layout="prev, pager, next, total"
@current-change="handleCurrentChange">
</el-pagination>
</div>
</div>
</el-popover>
</span>
</template>
<script setup>
import {
Document as ElIconDocument,
Fold as ElIconFold,
Expand as ElIconExpand,
Bell as ElIconBell,
Setting as ElIconSetting,
Plus as ElIconPlus,
Check as ElIconCheck,
} from '@element-plus/icons-vue'
import {
Remind as IconParkRemind,
} from '@icon-park/vue-next'
import {onBeforeUnmount, toRefs, ref, reactive, onMounted, watch, defineProps, nextTick, defineEmits, defineExpose, computed} from 'vue';
import {onBeforeRouteUpdate, useRouter, useRoute} from "vue-router";
import {ElMessageBox, ElMessage} from 'element-plus'
import pageApi from "@/assets/api/page";
import userApi from "@/assets/api/user";
import {useStoreDisplay} from '@/store/wikiDisplay.js'
let route = useRoute();
let router = useRouter();
const storeDisplay = useStoreDisplay();
let remindButtonRef = ref();
let userMessageList = ref([]);
let notReadMessageNum = ref(0);
let userMessagePopVisible = ref(false);
let userMsgTotalCount = ref(0);
let userMsgParam = ref({sysType: 2, pageNum: 1, pageSize: 20});
let messageInterval;
onMounted(() => {
loadUserMessageList();
messageInterval = setInterval(() => {
loadUserMessageList();
}, 10 * 1000);
});
onBeforeUnmount(() => {
if (messageInterval) {
clearInterval(messageInterval);
}
});
const loadUserMessageList = () => {
userApi.getUserMessageList(userMsgParam.value).then((res) => {
userMessageList.value = res.data || [];
userMsgTotalCount.value = res.total || 0;
notReadMessageNum.value = userMessageList.value.filter((item) => item.msgStatus === 0).length;
});
}
const showUserMessage = (row) => {
if (row.msgStatus === 0) {
userApi.readUserMessage({ids: row.id}).then(() => {
loadUserMessageList()
})
}
if (row.msgType >= 2 && row.msgType <= 14) {
router.push({path: '/page/show', query: {pageId: row.dataId}})
userMessagePopVisible.value = false
}
}
const readAllUserMessage = () => {
let msgIds = []
userMessageList.value.filter((item) => item.msgStatus === 0).forEach((item) => {
msgIds.push(item.id)
})
if (msgIds.length <= 0) return
userApi.readUserMessage({ids: msgIds.join(',')}).then(() => {
ElMessage.success('标记成功')
loadUserMessageList()
})
}
const handleCurrentChange = (val) => {
userMsgParam.value.pageNum = val
loadUserMessageList()
}
</script>
<style lang="scss">
.user-message-popover {
margin-left: 12px;
}
.header-user-remind {
.header {
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 14px;
font-weight: bold;
}
}
.header-user-message {
.el-table {
.cell {
padding: 0 6px;
}
/**覆盖箭头颜色*/
.el-popper__arrow::before {
border: 1px solid var(--el-text-color-primary);
background: var(--el-text-color-primary);
}
}
.page-info-box {
.el-pagination {
justify-content: end;
}
}
}
}
</style>