312 lines
8.0 KiB
Vue
312 lines
8.0 KiB
Vue
<template>
|
||
<a-row :wrap="false">
|
||
<a-col flex="auto">
|
||
<a-row>
|
||
<a-col flex="100px">
|
||
<a-row justify="start">
|
||
<a-col :span="8"
|
||
><a-tooltip title="返回顶层">
|
||
<a-button
|
||
type="text"
|
||
class="nav-btn"
|
||
:disabled="!canGoTop"
|
||
@click="$emit('go-top')"
|
||
>
|
||
<HomeOutlined />
|
||
</a-button> </a-tooltip
|
||
></a-col>
|
||
<a-col :span="8"
|
||
><a-tooltip title="返回上层">
|
||
<a-button
|
||
type="text"
|
||
class="nav-btn"
|
||
:disabled="!canGoBack"
|
||
@click="$emit('go-back')"
|
||
>
|
||
<ArrowLeftOutlined />
|
||
</a-button> </a-tooltip
|
||
></a-col>
|
||
<a-col :span="8"
|
||
><a-tooltip title="刷新">
|
||
<a-button
|
||
type="text"
|
||
class="nav-btn"
|
||
:loading="loading"
|
||
@click="onRefresh"
|
||
>
|
||
<ReloadOutlined />
|
||
</a-button> </a-tooltip
|
||
></a-col>
|
||
</a-row>
|
||
</a-col>
|
||
<a-col :xs="0" :sm="0" :lg="20" flex="auto">
|
||
<div
|
||
class="toolbar-center"
|
||
style="margin-top: 5px; margin-left: 10px"
|
||
>
|
||
<a-breadcrumb class="breadcrumb">
|
||
<a-breadcrumb-item
|
||
v-for="(item, index) in breadcrumbItems"
|
||
:key="index"
|
||
@click="onBreadcrumbClick(item, index)"
|
||
:class="{ clickable: index < breadcrumbItems.length - 1 }"
|
||
>
|
||
<template v-if="index === 0">
|
||
<LaptopOutlined style="margin-right: 4px" />
|
||
</template>
|
||
<template v-else>
|
||
<FolderOutlined style="margin-right: 4px" />
|
||
</template>
|
||
<span
|
||
:style="{
|
||
cursor:
|
||
index < breadcrumbItems.length - 1
|
||
? 'pointer'
|
||
: 'default',
|
||
color: index < breadcrumbItems.length - 1 ? '#1677ff' : '',
|
||
}"
|
||
>{{ item.displayName }}</span
|
||
>
|
||
</a-breadcrumb-item>
|
||
</a-breadcrumb>
|
||
</div>
|
||
</a-col>
|
||
<a-col :xs="10" :sm="10" :lg="0" flex="auto">
|
||
<div
|
||
v-if="viewMode == 'list'"
|
||
style="
|
||
margin-top: 8px;
|
||
margin-left: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
"
|
||
>
|
||
<FolderOutlined style="margin-right: 4px" />
|
||
<span class="breadcrumb-text">{{
|
||
breadcrumbItems.length > 0
|
||
? breadcrumbItems[breadcrumbItems.length - 1].displayName
|
||
: ""
|
||
}}</span>
|
||
</div>
|
||
<div
|
||
style="
|
||
max-width: 260px;
|
||
min-width: 220px;
|
||
margin-left: 20px;
|
||
margin-top: -2px;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
"
|
||
v-else
|
||
>
|
||
<a-input-search
|
||
v-model:value="searchKeyword"
|
||
placeholder="搜索文件名称"
|
||
allow-clear
|
||
@search="onSearch"
|
||
@pressEnter="onSearch"
|
||
>
|
||
</a-input-search>
|
||
<a-button size="small" type="default" @click="viewMode = 'list'" style="height: 32px;">
|
||
<cust-icon-font size="16" type="icon-gongcheng" />
|
||
</a-button>
|
||
</div>
|
||
</a-col> </a-row
|
||
></a-col>
|
||
<a-col :xs="0" :sm="0" :lg="10" flex="none">
|
||
<div style="margin-bottom: 8px; margin-right: 8px">
|
||
<a-input-search
|
||
v-model:value="searchKeyword"
|
||
placeholder="搜索文件名称"
|
||
allow-clear
|
||
@search="onSearch"
|
||
@pressEnter="onSearch"
|
||
>
|
||
</a-input-search>
|
||
</div>
|
||
</a-col>
|
||
<a-col :xs="4" :sm="4" :lg="0" flex="none">
|
||
<div
|
||
v-if="viewMode == 'list'"
|
||
style="
|
||
margin-right: 20px;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
"
|
||
>
|
||
<a-button size="small" type="default" @click="viewMode = 'search'">
|
||
<cust-icon-font size="14" type="icon-sousuo" />
|
||
</a-button>
|
||
<a-button
|
||
size="small"
|
||
type="default"
|
||
title="使用帮助"
|
||
@click="helpVisible = true"
|
||
>
|
||
<cust-icon-font size="14" type="icon-help" />
|
||
</a-button>
|
||
</div>
|
||
</a-col>
|
||
<a-col :xs="0" :sm="0" :lg="1" flex="none">
|
||
<div
|
||
v-if="viewMode == 'list'"
|
||
style="
|
||
margin-right: 20px;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
"
|
||
>
|
||
<a-button
|
||
style="height: 32px"
|
||
size="small"
|
||
type="default"
|
||
title="使用帮助"
|
||
@click="helpVisible = true"
|
||
>
|
||
<cust-icon-font size="16" type="icon-help" />
|
||
</a-button>
|
||
</div>
|
||
</a-col>
|
||
|
||
<!-- 使用帮助弹窗:内容默认取「我的云盘」页面说明,父组件可用 #help 插槽覆盖 -->
|
||
<!-- 宽度不写死:跟随 DragModal 的默认宽度(视口 90%) -->
|
||
<dragModal
|
||
v-model:open="helpVisible"
|
||
title="我的云盘 · 使用帮助"
|
||
:footer="null"
|
||
:fullscreen="width < 640"
|
||
>
|
||
<slot name="help">
|
||
<DmsFileEnquiryHelp />
|
||
</slot>
|
||
</dragModal>
|
||
</a-row>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, watch } from "vue";
|
||
import { useWindowSize } from "@vueuse/core";
|
||
import {
|
||
HomeOutlined,
|
||
ArrowLeftOutlined,
|
||
ReloadOutlined,
|
||
LaptopOutlined,
|
||
FolderOutlined,
|
||
SearchOutlined,
|
||
} from "@ant-design/icons-vue";
|
||
import dragModal from "@/components/basic/DragModal.vue";
|
||
import DmsFileEnquiryHelp from "@/components/basic/DmsFileEnquiryHelp.vue";
|
||
|
||
interface BreadcrumbItem {
|
||
value: string;
|
||
displayName: string;
|
||
}
|
||
|
||
const props = defineProps<{
|
||
pathStack: BreadcrumbItem[];
|
||
rootPath: string;
|
||
loading: boolean;
|
||
}>();
|
||
|
||
const emit = defineEmits([
|
||
"go-top",
|
||
"go-back",
|
||
"refresh",
|
||
"search",
|
||
"breadcrumb-click",
|
||
]);
|
||
|
||
const searchKeyword = ref("");
|
||
|
||
const viewMode = ref<"search" | "list">("list");
|
||
|
||
/** 使用帮助弹窗显示状态 */
|
||
const helpVisible = ref(false);
|
||
|
||
/** 小屏(手机)下帮助弹窗全屏显示 */
|
||
const { width } = useWindowSize();
|
||
|
||
const canGoTop = computed(() => {
|
||
return props.pathStack.length > 1;
|
||
});
|
||
|
||
const canGoBack = computed(() => {
|
||
return props.pathStack.length > 1;
|
||
});
|
||
|
||
const breadcrumbItems = computed(() => {
|
||
return props.pathStack;
|
||
});
|
||
|
||
const onSearch = () => {
|
||
emit("search", searchKeyword.value);
|
||
};
|
||
|
||
const onBreadcrumbClick = (item: BreadcrumbItem, index: number) => {
|
||
emit("breadcrumb-click", item, index);
|
||
};
|
||
|
||
/**
|
||
* 刷新:重新加载「当前所在目录」,也就是路径的最后一个节点。
|
||
* 不能取第一个节点,否则会把路径截回到根目录,变成跳转而不是刷新。
|
||
*/
|
||
const onRefresh = () => {
|
||
const lastIndex = breadcrumbItems.value.length - 1;
|
||
if (lastIndex < 0) return;
|
||
onBreadcrumbClick(breadcrumbItems.value[lastIndex], lastIndex);
|
||
};
|
||
</script>
|
||
|
||
<style lang="less">
|
||
.nav-btn {
|
||
width: 36px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.nav-btn:hover:not(:disabled) {
|
||
background: #e6f4ff;
|
||
color: #1677ff;
|
||
}
|
||
|
||
.nav-btn:disabled {
|
||
color: #bfbfbf;
|
||
}
|
||
|
||
.toolbar-center {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.breadcrumb {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.breadcrumb-item.clickable {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.breadcrumb-item.clickable:hover {
|
||
color: #1677ff;
|
||
}
|
||
|
||
.toolbar-right {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.breadcrumb-text {
|
||
display: inline-block;
|
||
max-width: 16ch; /* 6个字符宽度,ch 按字符计算 */
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
</style>
|