界面展示优化

This commit is contained in:
sswiki
2024-12-06 22:46:50 +08:00
parent 6cdcaf51ad
commit 858e7d6f21
12 changed files with 465 additions and 255 deletions

View File

@@ -7,6 +7,7 @@
"serve": "vite preview"
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@element-plus/icons-vue": "^2.0.10",
"@icon-park/vue-next": "^1.4.2",
"@soerenmartius/vue3-clipboard": "^0.1.2",

View File

@@ -23,17 +23,22 @@ body {
}
::-webkit-scrollbar {
width: 6px;
height: 9px;
-webkit-appearance: none;
height: 11px;
width: 11px !important;
background-color: unset !important;
}
::-webkit-scrollbar-thumb {
background: #ddd;
border-radius: 10px;
cursor: pointer;
border-radius: 11px;
border-style: dashed;
border-color: transparent;
border-width: 3px;
background-color: rgba(173, 180, 195, 0.4);
background-clip: padding-box;
}
::-webkit-scrollbar-track-piece {
background: #eee;
::-webkit-scrollbar-thumb:hover {
background: rgba(173, 180, 195, 0.5);
}
</style>

View File

@@ -0,0 +1,51 @@
<template>
<el-image-viewer
v-if="imagePreviewVisible"
:url-list="showImagePreviewList"
:initial-index="previewInitialIndex"
@close="closeImagePreview"
hide-on-click-modal
/>
</template>
<script setup>
import {onBeforeUnmount, ref, h, shallowRef, nextTick, onMounted, watch, defineProps, defineExpose} from 'vue'
import {showImagePreview} from 'vant';
import {useStoreDisplay} from "@/store/wikiDisplay";
let storeDisplay = useStoreDisplay();
onMounted(() => {
});
let imagePreviewVisible = ref(false);
let previewInitialIndex = ref(0);
let showImagePreviewList = ref([]);
const closeImagePreview = () => {
imagePreviewVisible.value = false;
}
const initViewer = (dom) => {
if (!dom) return;
const imgDomArr = [];
const imgSelector = dom.querySelectorAll('img');
imgSelector.forEach((item) => {
if (item.hasAttribute('not-allow-click')) return;
imgDomArr.push(item);
let index = imgDomArr.length - 1;
item.onclick = () => {
let imgArr = [];
// 点击后再去获取最新的url防止中途有修改比如plantuml的图
imgDomArr.forEach(dom => imgArr.push(dom.src));
if (storeDisplay.isMobile) {
showImagePreview({
images: imgArr,
startPosition: index,
});
} else {
previewInitialIndex.value = index;
showImagePreviewList.value = imgArr;
imagePreviewVisible.value = true;
}
}
});
}
defineExpose({initViewer});
</script>

View File

@@ -0,0 +1,24 @@
import {ref, onMounted, onUnmounted, watch} from 'vue'
import {useStoreDisplay} from "@/store/wikiDisplay";
import { useWindowSize, useWindowScroll } from '@vueuse/core'
export function useScroll(callback) {
const {x, y} = useWindowScroll();
watch([x, y], () => {
if (callback) {
callback();
}
});
}
export function useResizeEvent(callback) {
const {width, height} = useWindowSize();
watch([width, height], () => {
setTimeout(callback, 0);
});
let storeDisplay = useStoreDisplay();
watch(storeDisplay, () => {
setTimeout(callback, 0);
});
}

View File

@@ -7,7 +7,7 @@ import NoAuth from './views/common/NoAuth.vue'
import Home from './views/home/Home.vue'
import MyInfo from './views/user/MyInfo.vue'
import Show from './views/page/Show.vue'
import Show from './views/page/View.vue'
import Edit from './views/page/Edit.vue'
import spaceManage from './views/space/Manage.vue'

View File

@@ -13,6 +13,7 @@ export const useStoreDisplay = defineStore('wikiDisplay', {
showHeader:true,
// 当前页面 view、space
currentPage: '',
isMobile: false,
}
},
})

View File

@@ -1,10 +1,10 @@
<template>
<div class="global-layout-vue">
<el-container>
<el-aside v-show="storeDisplay.showMenu" :style="leftAsideStyle">
<el-aside v-show="storeDisplay.showMenu" :style="leftAsideStyle" class="left-aside-outer-box">
<LeftAside/>
</el-aside>
<RightResize v-show="storeDisplay.showMenu" v-model:value="storeDisplay.rightAsideWidth" @change="rightAsideWidthChange"></RightResize>
<RightResize v-show="storeDisplay.showMenu" v-model="storeDisplay.rightAsideWidth" @change="rightAsideWidthChange"></RightResize>
<el-container>
<el-header v-if="storeDisplay.showHeader">
<RightHeader ref="rightHeaderRef"/>
@@ -23,8 +23,14 @@ import {useStoreDisplay} from '@/store/wikiDisplay.js'
import LeftAside from './aside/LeftAside.vue'
import RightHeader from './aside/RightHeader.vue'
import RightResize from './aside/RightResize.vue'
import userApi from "@/assets/api/user";
import {useStoreUserData} from "@/store/userData";
let storeUser = useStoreUserData();
let storeDisplay = useStoreDisplay();
onMounted(() => {
getSelfUserInfo();
});
const rightAsideWidthChange = (width) => {
storeDisplay.rightAsideWidth = width;
storeDisplay.commentShow = width;
@@ -32,8 +38,20 @@ const rightAsideWidthChange = (width) => {
let leftAsideStyle = computed(() => {
return {width: storeDisplay.rightAsideWidth + 'px'};
});
const getSelfUserInfo = () => {
userApi.getSelfUserInfo().then((json) => {
storeUser.userInfo = json.data || {};
});
}
</script>
<style lang="scss">
.left-aside-outer-box {
border-right: 1px solid #eee;
background: #fafafa;
}
</style>
<style>
html,
body {
@@ -66,7 +84,8 @@ body {
.el-header {
color: #333;
height: 60px !important;
border-bottom: 0.5px solid #eaeaea;
background-color: #fff !important;
border-bottom: 1px solid #eee;
}
.head-icon {
@@ -117,15 +136,10 @@ body {
<style lang="scss">
.space-folder-box {
margin-left: 10px;
margin-bottom: 10px;
position: relative;
}
.wiki-page-tree-box {
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 30px;
.el-tree-node__content {
height: 35px;
position: relative;
@@ -141,7 +155,6 @@ body {
.text {
margin-left: 5px;
vertical-align: middle;
max-width: calc(100% - 40px);
display: inline-block;
overflow: hidden;

View File

@@ -1,35 +1,26 @@
<template>
<div class="page-show-vue" v-if="storePage.pageInfo.editorType !== 0">
<el-row type="border-card" style="height: 100%">
<el-col :span="storeDisplay.commentShow ? 18 : 24" style="padding: 20px;border-right: 1px solid #f1f1f1;height: 100%;overflow: auto;">
<el-row>
<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">{{ storePage.pageInfo.name }}</div>
<div id="pageContentBox" 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>
<PageZan></PageZan>
</div>
</el-col>
<el-col :span="navigationList.length > 0 ? 6 : 0" v-if="navigationList.length > 0">
<Navigation :heading="navigationList"></Navigation>
</el-col>
</el-row>
</el-col>
<el-col :span="6" style="height: 100%" v-show="storeDisplay.commentShow">
<el-icon @click="closeActionTab" class="close-action-tab">
<el-icon-close/>
</el-icon>
<el-tabs v-model="storeDisplay.commentActiveTab">
<el-tab-pane label="评论" name="comment">
<Comment/>
</el-tab-pane>
<el-tab-pane label="附件" name="annex">
<a-row class="view-body-comment-box">
<a-col flex="auto" class="view-body-outer-box">
<div class="view-body-box">
<div class="wiki-title" ref="wikiTitleRef">{{ storePage.pageInfo.name }}</div>
<div id="pageContentBox" ref="pageContentRef" class="wiki-page-content">
<div v-if="wikiPage.editorType === 2" v-html="pageShowDetail" class="markdown-body" v-highlight></div>
<div v-else v-html="pageShowDetail" class="wang-editor-body"></div>
</div>
<PageZan></PageZan>
</div>
<Navigation :heading="navigationList"></Navigation>
</a-col>
<a-col v-if="storeDisplay.commentShow" flex="280px">
<a-tabs v-model:activeKey="actionTabActiveName" class="action-tabs-box">
<a-tab-pane tab="评论" key="comment">
<Comment></Comment>
</a-tab-pane>
<a-tab-pane tab="附件" key="files">
<Annex/>
</el-tab-pane>
<el-tab-pane label="修改历史" name="history">
</a-tab-pane>
<a-tab-pane tab="修改历史" key="history">
<PageHistory
:pageHistoryList="pageHistoryList"
:pageHistoryChoice="pageHistoryChoice"
@@ -37,39 +28,22 @@
@historyClickHandle="historyClickHandle"
@previewPageImage="previewPageImage"
@createNavigationHeading="createNavigationHeading"/>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
<el-image-viewer
v-if="showImagePreview"
:url-list="showImagePreviewList"
:initial-index="previewInitialIndex"
@close="closeImagePreview"
hide-on-click-modal
/>
</a-tab-pane>
<template #rightExtra>
<el-tooltip content="关闭" placement="top">
<a-button @click="closeActionTab" type="text" :icon="h(CloseOutlined)"></a-button>
</el-tooltip>
</template>
</a-tabs>
</a-col>
</a-row>
<ImageViewer ref="imageViewerRef"/>
</div>
</template>
<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 { CloseOutlined } from '@ant-design/icons-vue';
import {toRefs, ref, reactive, onMounted, watch, defineProps, h, nextTick, defineEmits, defineExpose, computed} from 'vue';
import {onBeforeRouteUpdate, useRoute, useRouter} from "vue-router";
import { ElMessageBox, ElMessage, ElNotification } from 'element-plus';
import QRCode from 'qrcode'
@@ -77,7 +51,7 @@ 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 Navigation from './show/Navigation.vue'
import Annex from './show/Annex.vue'
import PageHistory from './show/PageHistory.vue'
import Comment from './show/Comment.vue'
@@ -87,6 +61,7 @@ import 'mavon-editor/dist/markdown/github-markdown.min.css'
import 'mavon-editor/dist/css/index.css'
import {useStorePageData} from "@/store/pageData";
import {useStoreDisplay} from "@/store/wikiDisplay";
import ImageViewer from "@/components/base/ImageViewer.vue";
let page = {
colorArr: ['#67C23A', '#409EFF', '#E6A23C', '#F56C6C', '#909399', '#303133'],
@@ -142,6 +117,13 @@ onMounted(() => {
storeDisplay.currentPage = 'view';
initQueryParam(route);
});
let actionTabActiveName = ref('comment');
let imageViewerRef = ref();
const previewPageImage = () => {
if (imageViewerRef.value) {
imageViewerRef.value.initViewer(pageContentRef.value);
}
}
const getSearchUserList = (query) => {
if (query == '') return
@@ -250,7 +232,7 @@ const computeFileSize = (fileSize) => {
}
const loadPageDetail = (pageId) => {
clearHistory()
pageApi.pageDetail({id: pageId}).then((json) => {
pageApi.pageDetail({id: pageId}).then(async (json) => {
let result = json.data || {};
let wikiPageRes = result.wikiPage || {};
wikiPageRes.selfZan = result.selfZan || 0;
@@ -280,9 +262,7 @@ const loadPageDetail = (pageId) => {
//
emit('changeExpandedKeys', pageId);
setTimeout(() => {
if (storePage.pageInfo.editorType !== 0){
previewPageImage();
}
previewPageImage();
createNavigationHeading();
}, 500);
storePage.pageInfo = wikiPageRes;
@@ -308,18 +288,6 @@ 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 getUserHeadBgColor = (userId) => {
let color = page.userHeadColor[userId]
@@ -338,28 +306,35 @@ const initQueryParam = (to) => {
}
</script>
<style lang="scss" scoped>
.page-show-vue {
.wiki-page-content {
margin-top: 20px;
}
}
</style>
<style lang="scss">
.page-show-vue {
height: 100%;
overflow: hidden;
height: 100%;
overflow: hidden;
.wiki-page-content {
ol {
list-style: decimal;
}
.view-body-comment-box {
height: 100%;
ul {
list-style: disc;
.view-body-outer-box {
height: 100%;
overflow: auto;
padding: 30px 20px;
position: relative;
border-right: 1px solid #eee;
.view-body-box {
max-width: 840px;
margin: 0 auto;
.wiki-page-content {
margin-top: 30px;
}
}
}
.ant-tabs-nav {
padding: 0 15px;
}
}
}
}
</style>

View File

@@ -1,45 +1,45 @@
<template>
<div style="padding: 10px;height: 100%;box-sizing: border-box;background: #fafafa;">
<div style="margin-bottom: 5px">
<div class="left-aside-box">
<div class="left-aside-top-box">
<el-select :model-value="storeSpace.chooseSpaceId" @change="spaceChangeEvents" filterable
placeholder="选择空间" style="width: 100%">
placeholder="选择空间" style="width: 100%;margin-bottom: 5px;">
<el-option-group label="" v-if="!props.readOnly">
<el-option :key="-1" label="空间管理" :value="-1"></el-option>
</el-option-group>
<el-option-group label=""></el-option-group>
<el-option v-for="item in storeSpace.spaceOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
<el-autocomplete v-model="searchKeywords" v-if="!props.readOnly" :fetch-suggestions="doSearchByKeywords"
@select="handleSearchKeywordsSelect" popper-class="search-autocomplete"
placeholder="在当前空间搜索" style="width: 100%; margin: 10px 0">
<template v-slot="{ item }">
<div class="search-option-item">
<div class="title">
<span v-html="item.pageTitle || '-'"></span>
<el-autocomplete v-model="searchKeywords" v-if="!props.readOnly" :fetch-suggestions="doSearchByKeywords"
@select="handleSearchKeywordsSelect" popper-class="search-autocomplete"
placeholder="在当前空间搜索" style="width: 100%; margin: 10px 0">
<template v-slot="{ item }">
<div class="search-option-item">
<div class="title">
<span v-html="item.pageTitle || '-'"></span>
</div>
<span class="content" v-html="item.previewContent || '-'"></span>
</div>
<span class="content" v-html="item.previewContent || '-'"></span>
</div>
</template>
</el-autocomplete>
<div class="space-folder-box" v-if="!props.readOnly">
<el-row justify="space-between">
<el-col :span="12">
<el-tooltip style="margin: 4px" effect="dark" :content="descriptorForTree" placement="top">
<span style="color:#888;font-size: 12px;cursor: pointer;line-height: 32px;" @click="changeDropWownStatus">空间目录</span>
</el-tooltip>
</el-col>
<el-col :span="12" style="text-align: right;">
<AddMenu/>
</el-col>
</el-row>
</template>
</el-autocomplete>
<div class="space-folder-box" v-if="!props.readOnly">
<el-row justify="space-between">
<el-col :span="12">
<el-tooltip style="margin: 4px" effect="dark" :content="descriptorForTree" placement="top">
<span style="color:#888;font-size: 12px;cursor: pointer;line-height: 32px;" @click="changeDropWownStatus">空间目录</span>
</el-tooltip>
</el-col>
<el-col :span="12" style="text-align: right;">
<AddMenu/>
</el-col>
</el-row>
</div>
</div>
<div class="wiki-page-tree-box">
<el-tree ref="wikiPageTreeRef" :current-node-key="props.nowPageId" :data="storePage.wikiPageList"
:default-expanded-keys="wikiPageExpandedKeys" :expand-on-click-node="true" :class="explanClass"
:filter-node-method="filterPageNode" :props="defaultProps" :draggable="!props.readOnly"
@node-click="handleNodeClick" @node-drop="handlePageDrop" node-key="id" highlight-current
style="background-color: #fafafa">
style="background-color: #fafafa;">
<template v-slot="{ node, data }">
<div class="page-tree-node" @mouseover="changeNodeOptionStatus(data) ">
<div class="node-content">
@@ -58,7 +58,7 @@
</el-tooltip>
<a-input v-if="data.renaming" v-model:value="data.name" @blur="doRename(node,data)" @click.stop
class="rename-input" placeholder="请输入文档名称"/>
<span v-else style="vertical-align: middle;margin-right: 5px">
<span v-else style="vertical-align: middle;margin-left: 5px;">
<el-tooltip :content="node.label" placement="top-start" :show-after="700">{{ node.label }}</el-tooltip>
</span>
<!--操作-->
@@ -125,6 +125,8 @@ import AddMenu from "./AddMenu.vue";
import IconDocument from "@/components/base/IconDocument.vue";
import {ElMessageBox, ElMessage} from 'element-plus'
import {useStoreSpaceData} from "@/store/spaceData";
import Navigation from "@/views/page/show/Navigation.vue";
import PageZan from "@/views/page/show/PageZan.vue";
let route = useRoute();
let router = useRouter();
@@ -321,4 +323,22 @@ const handlePageDrop = (draggingNode, dropNode, dropType, ev) => {
defineExpose({searchByKeywords})
</script>
<style lang="scss">
.left-aside-box {
height: 100%;
box-sizing: border-box;
background: #fafafa;
display: flex;
flex-direction: column;
.left-aside-top-box {
padding: 10px;
}
.wiki-page-tree-box {
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 10px;
}
}
</style>

View File

@@ -1,55 +1,76 @@
<template>
<div ref="rightResizeRef" class="right-resize"></div>
<div ref="rightResizeRef" class="right-resize hide-on-mp" :style="{left: (modelValue-4)+'px'}">
<div class="line"></div>
</div>
</template>
<script setup>
import {onBeforeUnmount, ref, onMounted, watch, defineProps, nextTick, defineEmits, defineExpose, computed} from 'vue';
import {toRefs, ref, reactive, onMounted, onBeforeUnmount, watch, defineEmits, computed} from 'vue';
const props = defineProps({
modelValue: Number,
max: {
type: Number,
default: 600
},
min: {
type: Number,
default: 300
}
});
let emit = defineEmits(['update:modelValue', 'change']);
let rightAsideWidth = 300;
let emit = defineEmits(['update:value', 'change']);
onMounted(() => {
dragChangeRightAsideWidth();
});
let rightResizeRef = ref();
const dragChangeRightAsideWidth = () => {
// 保留this引用
let resize = rightResizeRef.value
resize.onmousedown = (e) => {
let startX = e.clientX
let resize = rightResizeRef.value;
resize.onmousedown = e => {
let startX = e.clientX;
let rightAsideWidth = props.modelValue;
// 颜色改变提醒
resize.left = resize.offsetLeft
document.onmousemove = (e2) => {
resize.classList.add('active');
document.onmousemove = e2 => {
// 计算并应用位移量
let endX = e2.clientX
let moveLen = startX - endX
if ((moveLen < 0 && rightAsideWidth < 600) || (moveLen > 0 && rightAsideWidth > 300)) {
startX = endX
rightAsideWidth -= moveLen
if (rightAsideWidth < 300) {
rightAsideWidth = 300
}
emit('update:value', rightAsideWidth)
emit('change', rightAsideWidth)
let endX = e2.clientX;
let moveLen = startX - endX;
if ((moveLen < 0 && rightAsideWidth < props.max) || (moveLen > 0 && rightAsideWidth > props.min)) {
startX = endX;
rightAsideWidth -= moveLen;
rightAsideWidth = Math.max(rightAsideWidth, props.min);
rightAsideWidth = Math.min(rightAsideWidth, props.max);
emit('update:modelValue', rightAsideWidth);
emit('change', rightAsideWidth);
}
}
};
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
return false
}
resize.classList.remove('active');
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
}
</script>
<style scoped lang="scss">
<style scoped>
.right-resize {
width: 3px;
height: 100%;
cursor: w-resize;
background: #fafafa;
height: 100%;
padding: 0 4px;
cursor: w-resize;
z-index: 200;
position: absolute;
}
&:hover {
background: #2a85f6;
}
.right-resize .line {
width: 2px;
height: 100%;
}
.right-resize:hover .line,
.right-resize.active .line {
background: #2876d7;
}
</style>

View File

@@ -1,38 +1,40 @@
<template>
<div class="comment-box" ref="actionTabCommentRef">
<div v-if="commentList.length <= 0" class="action-box-empty">
暂无评论
<div class="comment-outer-box">
<div class="comment-box" ref="actionTabCommentRef">
<div v-if="commentList.length <= 0" class="action-box-empty">暂无评论</div>
<div v-else class="comment-list">
<el-timeline>
<el-timeline-item :timestamp="comment.createTime" placement="top" v-for="comment in commentList">
<el-card class="box-card comment-card" :body-style="{ padding: '10px' }">
<div :style="'background-color: ' + comment.color" class="head">
{{ comment.createUserName.substr(0, 1) }}
</div>
<div class="comment-user-name">
{{ comment.createUserName }}
<el-popconfirm v-if="canDeleteComment(comment)"
placement="top" width="160" trigger="click"
confirm-button-text="删除"
cancel-button-text="取消"
@confirm="deleteComment(comment.id)"
title="确定要删除此评论吗?">
<template #reference>
<el-icon class="icon-delete"><ElIconDelete /></el-icon>
</template>
</el-popconfirm>
</div>
<pre class="comment-content">{{ comment.content }}</pre>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</div>
<div v-else class="comment-list">
<el-timeline>
<el-timeline-item :timestamp="comment.createTime" placement="top" v-for="comment in commentList">
<el-card class="box-card comment-card" :body-style="{ padding: '10px' }">
<div :style="'background-color: ' + comment.color" class="head">
{{ comment.createUserName.substr(0, 1) }}
</div>
<div class="comment-user-name">
{{ comment.createUserName }}
<el-popconfirm v-if="canDeleteComment(comment)"
placement="top" width="160" trigger="click"
confirm-button-text="删除"
cancel-button-text="取消"
@confirm="deleteComment(comment.id)"
title="确定要删除此评论吗?">
<template #reference>
<el-icon class="icon-delete"><ElIconDelete /></el-icon>
</template>
</el-popconfirm>
</div>
<pre class="comment-content">{{ comment.content }}</pre>
</el-card>
</el-timeline-item>
</el-timeline>
<div class="comment-input-box">
<textarea rows="5" placeholder="发表评论" v-model="commentTextInput" :maxlength="500"></textarea>
<div class="comment-btn-box">
<el-button type="primary" size="small" @click="submitPageComment">发送</el-button>
</div>
</div>
</div>
<div class="comment-input-box">
<textarea rows="5" placeholder="发表评论" v-model="commentTextInput" :maxlength="500"></textarea>
<el-button style="float: right; margin: 2px 5px" type="primary" size="small" @click="submitPageComment">发送</el-button>
</div>
</template>
<script setup>
@@ -97,17 +99,9 @@ const loadCommentList = () => {
scrollActionTabComment()
})
}
const recommentUser = (id, index) => {
recommentInfo.value = {
id: id,
index: index,
placeholder: '回复' + (index + 1) + '楼',
}
}
let canDeleteComment = (row) => {
return (
storeUser.userInfo.id === row.createUserId || storeUser.userInfo.id === storePage.pageInfo.createUserId
)
return storeUser.userInfo.id === row.createUserId
|| storeUser.userInfo.id === storePage.pageInfo.createUserId
}
const deleteComment = (id) => {
pageApi.deletePageComment({id: id}).then(() => {
@@ -147,58 +141,57 @@ const getUserHeadBgColor = (userId) => {
<style lang="scss">
.comment-box {
padding: 8px;
height: calc(100vh - 115px);
overflow: auto;
padding: 8px;
height: calc(100vh - 315px);
overflow: auto;
.comment-list {
padding-bottom: 130px;
}
.comment-card {
.comment-user-name {
margin-bottom: 10px;
.comment-card {
.comment-user-name {
margin-bottom: 10px;
.icon-delete {
color: #888;
font-size: 13px;
cursor: pointer;
float: right;
display: none;
}
}
.icon-delete {
color: #888;
font-size: 13px;
cursor: pointer;
float: right;
display: none;
}
.comment-content {
padding: 0;
color: #666;
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
line-height: 20px;
}
}
.comment-content {
padding: 0;
color: #666;
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
line-height: 20px;
.comment-card:hover {
.icon-delete {
display: inline-block;
}
}
}
.comment-card:hover {
.icon-delete {
display: inline-block;
}
}
}
.comment-input-box {
position: absolute;
bottom: 0;
width: 100%;
background: #fff;
border-top: 1px solid #f1f1f1;
textarea {
resize: none;
width: 100%;
box-sizing: border-box;
border: 0;
outline: none !important;
padding: 10px;
}
background: #fff;
border-top: 1px solid #f1f1f1;
textarea {
resize: none;
width: 100%;
box-sizing: border-box;
border: 0;
outline: none !important;
padding: 10px;
}
.comment-btn-box {
text-align: right;
padding: 4px 15px 6px 0;
}
}
</style>

View File

@@ -0,0 +1,106 @@
<template>
<div class="navigation-box">
<div class="navigation-content-box">
<div>dasdas</div>
<div class="nav-heading" :style="{ width: navigationWidth }">
<div v-for="item in heading" :class="'heading-item heading-' + item.level" @click="headingItemClick(item)">
{{ item.text }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import {toRefs, ref, reactive, onMounted, watch, defineEmits, defineProps, defineExpose,} from 'vue'
import {useStoreDisplay} from '@/store/wikiDisplay.js'
import {useStorePageData} from "@/store/pageData";
import {useResizeEvent} from "@/composable/windowsScroll";
let storePage = useStorePageData();
const storeDisplay = useStoreDisplay();
let navigationWidth = ref('100px');
const props = defineProps({
heading: {type: Array, default: []},
});
onMounted(() => {
setTimeout(() => computeNavigationWidth(), 100);
});
useResizeEvent(() => {
computeNavigationWidth();
});
const computeNavigationWidth = () => {
}
const headingItemClick = (item) => {
// 滚动到指定节点
item.node.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest',
});
// 距离顶部高度
//console.log(item.node.offsetTop - item.node.scrollHeight)
}
</script>
<style lang="scss">
.navigation-box {
width: 100px;
position: absolute;
top: 150px;
right: 10px;
z-index: 4;
.navigation-content-box {
position: fixed;
background: #fff;
border-radius: 8px;
padding: 16px;
margin-left: -40px;
box-shadow: var(--el-box-shadow-lighter);
}
.nav-heading {
max-height: calc(100vh - 250px);
overflow-y: auto;
.heading-item {
padding: 5px 0;
cursor: pointer;
color: #646a73;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: #3370ff;
}
}
.heading-1 {
padding-left: 0;
}
.heading-2 {
padding-left: 16px;
}
.heading-3 {
padding-left: 32px;
}
.heading-4 {
padding-left: 48px;
}
.heading-5 {
padding-left: 64px;
}
.heading-6 {
padding-left: 80px;
}
}
}
</style>