feat: 完善网址导航功能,支持跳转,支持查看链接详情
This commit is contained in:
18
src/App.vue
18
src/App.vue
@@ -189,6 +189,11 @@ html {
|
|||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-view-content {
|
.app-view-content {
|
||||||
@@ -209,4 +214,17 @@ html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- Naive UI --
|
||||||
|
|
||||||
|
.n-drawer--right-placement {
|
||||||
|
.n-drawer-body {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.n-drawer-body-content-wrapper {
|
||||||
|
padding: 20px !important;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,10 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nav-view flex-col">
|
<div class="nav-view flex-col">
|
||||||
|
|
||||||
<div class="app-view-header">
|
<div class="app-view-header">
|
||||||
<span>{{ NAV_MODULE_TITLE }}</span>
|
<div>{{ NAV_MODULE_TITLE }}</div>
|
||||||
|
<div class="placeholder"></div>
|
||||||
|
<n-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:circle="true"
|
||||||
|
:secondary="true"
|
||||||
|
@click="showHelp"
|
||||||
|
>
|
||||||
|
<span class="mdi mdi-help"></span>
|
||||||
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="app-view-content">
|
<div class="app-view-content">
|
||||||
<n-layout class="page-layout" :has-sider="true">
|
<n-layout
|
||||||
|
class="page-layout"
|
||||||
|
:has-sider="true"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- 左 -->
|
||||||
<n-layout-sider
|
<n-layout-sider
|
||||||
class="left-aside"
|
class="left-aside"
|
||||||
collapse-mode="width"
|
collapse-mode="width"
|
||||||
@@ -13,6 +30,7 @@
|
|||||||
:collapsed="isCollapsed"
|
:collapsed="isCollapsed"
|
||||||
:collapsed-width="64"
|
:collapsed-width="64"
|
||||||
:native-scrollbar="false"
|
:native-scrollbar="false"
|
||||||
|
:scrollbar-props="{ trigger: 'hover' }"
|
||||||
:width="240"
|
:width="240"
|
||||||
@collapse="isCollapsed = true"
|
@collapse="isCollapsed = true"
|
||||||
@expand="isCollapsed = false"
|
@expand="isCollapsed = false"
|
||||||
@@ -29,7 +47,13 @@
|
|||||||
:on-update:value="handleSelectCategory"
|
:on-update:value="handleSelectCategory"
|
||||||
/>
|
/>
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
<n-layout class="right-content">
|
|
||||||
|
<!-- 右 -->
|
||||||
|
<n-layout
|
||||||
|
class="right-content"
|
||||||
|
:native-scrollbar="false"
|
||||||
|
:scrollbar-props="{ trigger: 'none' }"
|
||||||
|
>
|
||||||
<div class="tree-data">
|
<div class="tree-data">
|
||||||
<n-tree
|
<n-tree
|
||||||
children-field="children"
|
children-field="children"
|
||||||
@@ -41,28 +65,82 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
|
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 链接详情 -->
|
||||||
|
<n-drawer
|
||||||
|
v-model:show="detailDrawer.show"
|
||||||
|
class="nav-url-detail-drawer"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<n-drawer-content
|
||||||
|
title="链接详情"
|
||||||
|
:closable="true"
|
||||||
|
>
|
||||||
|
<n-descriptions
|
||||||
|
label-placement="top"
|
||||||
|
:column="1"
|
||||||
|
>
|
||||||
|
<n-descriptions-item label="ID">
|
||||||
|
{{ detailDrawer.data._key }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="链接标题">
|
||||||
|
{{ detailDrawer.data.title }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="链接地址">
|
||||||
|
{{ detailDrawer.data.url }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="更新日期">
|
||||||
|
{{ detailDrawer.data.date }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="是否有效">
|
||||||
|
{{ detailDrawer.data.isInvalid ? '否' : '是' }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</n-drawer-content>
|
||||||
|
</n-drawer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx" setup>
|
<script lang="jsx" setup>
|
||||||
import {
|
import {
|
||||||
|
NButton,
|
||||||
|
NDescriptions, NDescriptionsItem,
|
||||||
|
NDrawer, NDrawerContent,
|
||||||
NLayout, NLayoutSider, NMenu, NTree,
|
NLayout, NLayoutSider, NMenu, NTree,
|
||||||
|
NLi, NUl,
|
||||||
} from 'naive-ui';
|
} from 'naive-ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
shallowRef, onBeforeMount,
|
reactive, shallowRef, onBeforeMount,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NAV_MODULE_TITLE,
|
NAV_MODULE_TITLE,
|
||||||
} from '@/config/modules';
|
} from '@/config/modules';
|
||||||
|
|
||||||
|
import {
|
||||||
|
$dialog, $message,
|
||||||
|
} from '@/assets/js/naive-ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
formatNavLinks,
|
formatNavLinks,
|
||||||
} from '@/assets/js/nav-links';
|
} from '@/assets/js/nav-links';
|
||||||
|
|
||||||
|
/** 链接详情 */
|
||||||
|
const detailDrawer = reactive({
|
||||||
|
|
||||||
|
/** @type {NavLinkItem | null} */
|
||||||
|
data: null,
|
||||||
|
|
||||||
|
/** @type {boolean} */
|
||||||
|
show: false,
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
/** 分类列表是否折叠 */
|
/** 分类列表是否折叠 */
|
||||||
const isCollapsed = shallowRef(false);
|
const isCollapsed = shallowRef(false);
|
||||||
|
|
||||||
@@ -113,13 +191,68 @@ function handleSelectCategory(key, item) {
|
|||||||
changeList(item._data);
|
changeList(item._data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 打开链接
|
||||||
|
* @param {string} url
|
||||||
|
* @param {boolean} showOnly
|
||||||
|
*/
|
||||||
|
function openURL(url = '', showOnly = false) {
|
||||||
|
if (showOnly) {
|
||||||
|
$message.warning('请在链接详情中复制后手动打开');
|
||||||
|
} else {
|
||||||
|
url && window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 树形数据节点内容渲染函数
|
* @description 树形数据节点内容渲染函数
|
||||||
* @param {object} info
|
* @param {object} info
|
||||||
* @param {NavLinkItem} info.option
|
* @param {NavLinkItem} info.option
|
||||||
*/
|
*/
|
||||||
function renderTreeLabel(info) {
|
function renderTreeLabel(info) {
|
||||||
return info.option.title;
|
|
||||||
|
let data = info.option;
|
||||||
|
let isURL = !data.children;
|
||||||
|
|
||||||
|
let open = () => {
|
||||||
|
isURL && openURL(data.url, data.showOnly);
|
||||||
|
};
|
||||||
|
|
||||||
|
let show = () => {
|
||||||
|
isURL && toggleDetailDrawer(true, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div class="item-wrapper" onContextmenu={show} onClick={open}>
|
||||||
|
<div class="item-title">{ data.title }</div>
|
||||||
|
<div class="item-url">{ data.url }</div>
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 显示说明 */
|
||||||
|
function showHelp() {
|
||||||
|
$dialog.create({
|
||||||
|
content: () => {
|
||||||
|
return <NUl>
|
||||||
|
<NLi>点击目录项左侧按钮以展开目录。</NLi>
|
||||||
|
<NLi>PC 端右键或移动端长按链接项以显示详情。</NLi>
|
||||||
|
</NUl>
|
||||||
|
},
|
||||||
|
title: '操作说明',
|
||||||
|
type: 'default',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 切换链接详情显示隐藏
|
||||||
|
* @param {boolean} show
|
||||||
|
* @param {NavLinkItem} data
|
||||||
|
*/
|
||||||
|
function toggleDetailDrawer(show = false, data = null) {
|
||||||
|
if (show) {
|
||||||
|
detailDrawer.data = data;
|
||||||
|
}
|
||||||
|
detailDrawer.show = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
@@ -162,10 +295,57 @@ onBeforeMount(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node-content__text) {
|
:deep(.n-tree-node-content) {
|
||||||
|
color: var(--color-text-2);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-tree-node-indent > div) {
|
||||||
|
width: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-tree-node--selected) {
|
||||||
|
.n-tree-node-content,
|
||||||
|
.n-tree-node-switcher__icon {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-tree-node-switcher__icon) {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.item-wrapper) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
height: 32px;
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.item-url) {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.nav-url-detail-drawer {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 320px;
|
||||||
|
|
||||||
|
.n-descriptions-table-content {
|
||||||
|
user-select: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Reference in New Issue
Block a user