迁移UI框架至naive-ui,重构组件和样式,添加Gallery和Mask组件
This commit is contained in:
281
src/components/Gallery.vue
Normal file
281
src/components/Gallery.vue
Normal file
@ -0,0 +1,281 @@
|
||||
<template>
|
||||
<PerfectScrollbar ref="scrollbar" @ps-scroll-y="handleScroll">
|
||||
<div ref="myCon" class="gallery-page py-5 px-[10%]">
|
||||
<d-search class="mt-0 mb-8 w-2/3 mx-auto rounded-full" v-model="kw" is-keyup-search :delay="1000"
|
||||
@search="onSearch"></d-search>
|
||||
<div class="gallery-container w-full box-border">
|
||||
<!-- 瀑布流容器 -->
|
||||
<div ref="waterfallContainer" v-image-preview
|
||||
class="waterfall-container flex justify-between flex-nowrap w-full overflow-hidden">
|
||||
<!-- 动态生成的列 -->
|
||||
<div v-for="(column, index) in columns" :key="index" class="waterfall-column flex flex-col w-[240px]">
|
||||
<div v-for="item in column" :key="item.id"
|
||||
class="gallery-item group relative my-[10px] rounded-lg overflow-hidden transition-transform duration-300 box-border hover:-translate-y-1.5">
|
||||
<div
|
||||
class="absolute px-2 truncate hidden group-hover:block top-0 text-center w-full bg-[#00000070] text-white">
|
||||
{{ item.filename }}</div>
|
||||
<img :src="item.filepath" alt="" class="gallery-image block w-full h-auto object-cover rounded-md">
|
||||
<div class="px-2 absolute bottom-0 flex justify-between w-full bg-[#00000060]">
|
||||
<div class="text-white ">由 <span class="text-[#f1d9db] font-600">{{ item.nickname }}</span> 上传</div>
|
||||
<d-popover content="下载" trigger="hover" class="!bg-primary" style="color: #fff">
|
||||
<icon-download @click="downloadFile(item.filepath)"
|
||||
class="w-5 h-5 text-white hover-text-primary"></icon-download>
|
||||
</d-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 加载中指示器 -->
|
||||
<div v-if="loading" class="loading-indicator text-center p-5 text-gray-600">加载中...</div>
|
||||
<div v-else class="loading-indicator text-center p-5 text-gray-600">已全部加载完成</div>
|
||||
</div>
|
||||
</div>
|
||||
</PerfectScrollbar>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { throttle } from 'es-toolkit';
|
||||
|
||||
definePage({
|
||||
name: 'gallery',
|
||||
meta: {
|
||||
title: '画廊',
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// 画廊页逻辑
|
||||
const fileList = ref<any[]>([]);
|
||||
const pn = ref(1);
|
||||
const ps = ref(40);
|
||||
const loading = ref(false);
|
||||
const waterfallContainer = ref<HTMLDivElement | null>(null);
|
||||
const columns = ref<Array<Array<any>>>([]);
|
||||
const columnHeights = ref<number[]>([]);
|
||||
const columnCount = ref(4); // 默认列数
|
||||
const itemWidth = ref(240); // 图片宽度固定为240px
|
||||
const kw = ref<string>('');
|
||||
|
||||
// const uploadOptions = ref({
|
||||
// uri: 'https://www.hxyouzi.com/api/files/upload',
|
||||
// method: 'POST',
|
||||
// maximumSize: 5 * 1024 * 1024,
|
||||
// headers: {
|
||||
// 'Authorization': 'Bearer ' + $cookies.get('token'),
|
||||
// },
|
||||
// });
|
||||
|
||||
// 计算列数 based on 屏幕宽度
|
||||
function calculateColumnCount() {
|
||||
if (!waterfallContainer.value) return;
|
||||
const containerWidth = waterfallContainer.value.clientWidth;
|
||||
const newColumnCount = Math.max(1, Math.floor(containerWidth / itemWidth.value));
|
||||
if (newColumnCount !== columnCount.value) {
|
||||
columnCount.value = newColumnCount;
|
||||
resetWaterfall();
|
||||
}
|
||||
}
|
||||
|
||||
// 重置瀑布流
|
||||
function resetWaterfall() {
|
||||
columns.value = Array(columnCount.value).fill(0).map(() => []);
|
||||
columnHeights.value = Array(columnCount.value).fill(0);
|
||||
// 重新分配图片
|
||||
fileList.value.forEach(async (item:any) =>await addToWaterfall(item));
|
||||
console.log('>>> --> resetWaterfall --> fileList:', fileList.value)
|
||||
}
|
||||
|
||||
// 添加图片到瀑布流
|
||||
async function addToWaterfall(item: any) {
|
||||
if (columns.value.length === 0) return;
|
||||
const { height, width } =await getImageSizeByCheck(item.filepath)
|
||||
|
||||
// 找到高度最小的列
|
||||
let minHeight = Math.min(...columnHeights.value);
|
||||
let minIndex = columnHeights.value.indexOf(minHeight);
|
||||
console.log('>>> --> addToWaterfall --> item:', item)
|
||||
console.log('>>> --> addToWaterfall --> minIndex:', minIndex)
|
||||
// 添加到该列
|
||||
columns.value[minIndex].push(item);
|
||||
// 估算列高 - 实际高度会在图片加载后更新
|
||||
const estimatedHeight = itemWidth.value * height / width
|
||||
columnHeights.value[minIndex] += estimatedHeight + 20; // 加上padding和margin
|
||||
}
|
||||
|
||||
function getImageSizeByCheck(url: string): any {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let image = new Image();
|
||||
image.src = url;
|
||||
let height = 0
|
||||
let width = 0
|
||||
// let timer = setTimeout(() => {
|
||||
image.onload = () => {
|
||||
if (image.width > 0 && image.height > 0) {
|
||||
height = image.height
|
||||
width = image.width
|
||||
resolve({ height, width })
|
||||
// clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
// }, 100)
|
||||
});
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
async function getFileList() {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await $http.file.getFileList({
|
||||
keyword: kw.value,
|
||||
page_num: pn.value,
|
||||
page_size: ps.value,
|
||||
});
|
||||
// console.log('>>> --> getFileList --> res:', res);
|
||||
|
||||
if (pn.value === 1) {
|
||||
fileList.value = res.data;
|
||||
resetWaterfall();
|
||||
} else {
|
||||
// 追加新数据
|
||||
res.data.forEach((item: any) => {
|
||||
fileList.value.push(item);
|
||||
addToWaterfall(item);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取文件列表失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// // 获取我的文件列表
|
||||
// async function getMyList() {
|
||||
// if (loading.value) return;
|
||||
// loading.value = true;
|
||||
// try {
|
||||
// const res = await $http.file.getMyList({
|
||||
// page_num: pn.value,
|
||||
// page_size: ps.value,
|
||||
// });
|
||||
// // console.log('>>> --> getFileList --> res:', res);
|
||||
|
||||
// if (pn.value === 1) {
|
||||
// fileList.value = res.data;
|
||||
// resetWaterfall();
|
||||
// } else {
|
||||
// // 追加新数据
|
||||
// res.data.forEach((item: any) => {
|
||||
// fileList.value.push(item);
|
||||
// addToWaterfall(item);
|
||||
// });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('获取文件列表失败:', error);
|
||||
// } finally {
|
||||
// loading.value = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 监听滚动事件
|
||||
const handleScroll: any = throttle((e: any) => {
|
||||
console.log('>>> --> handleScroll --> loading:', e)
|
||||
if (loading.value) return;
|
||||
const scrollTop = e.target.scrollTop
|
||||
console.log('>>> --> handleScroll --> scrollTop:', scrollTop)
|
||||
const scrollHeight = e.target.scrollHeight
|
||||
// console.log('>>> --> handleScroll --> scrollHeight:', scrollHeight)
|
||||
const clientHeight = e.target.offsetHeight;
|
||||
|
||||
// 当滚动到距离底部20%时加载更多
|
||||
// console.log('>>> --> clientHeight --> clientHeight:', clientHeight)
|
||||
if (scrollTop + clientHeight >= scrollHeight * 0.8) {
|
||||
console.log('>>> --> handleScroll --> 加载更多')
|
||||
pn.value++;
|
||||
getFileList();
|
||||
}
|
||||
}, 1000)
|
||||
function onSearch() {
|
||||
pn.value = 1;
|
||||
getFileList();
|
||||
}
|
||||
|
||||
function downloadFile(url: string) {
|
||||
console.log('>>> --> downloadFile --> url:', url)
|
||||
// 创建临时a标签
|
||||
const link = document.createElement('a');
|
||||
// 设置下载链接
|
||||
link.href = url;
|
||||
// 提取文件名
|
||||
const fileName = url.split('/').pop() || 'downloaded-file';
|
||||
// 设置下载属性和文件名
|
||||
link.download = fileName;
|
||||
// 设置为隐藏元素
|
||||
link.style.display = 'none';
|
||||
// 添加到文档
|
||||
document.body.appendChild(link);
|
||||
// 触发点击事件
|
||||
link.click();
|
||||
// 移除临时元素
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getFileList();
|
||||
// 计算初始列数
|
||||
calculateColumnCount();
|
||||
// 添加窗口大小变化监听
|
||||
window.addEventListener('resize', calculateColumnCount);
|
||||
// 添加滚动监听
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
pn.value = 1;
|
||||
kw.value = '';
|
||||
fileList.value = [];
|
||||
resetWaterfall();
|
||||
|
||||
// 移除监听
|
||||
window.removeEventListener('resize', calculateColumnCount);
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
/* 画廊页样式 */
|
||||
:deep(.devui-tabs__nav) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100% !important;
|
||||
// padding: 0 10%;
|
||||
|
||||
li {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
li a span {
|
||||
font-size: 18px !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.ps {
|
||||
height: calc(100vh - 65px);
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.devui-upload) {
|
||||
width: 100%;
|
||||
|
||||
&>div {
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,44 +1,47 @@
|
||||
<template>
|
||||
<d-card class="mt-10 bg-[#ffffff60] rounded-[10px]" shadow="never">
|
||||
<d-tabs v-model="tid" type="pills">
|
||||
<d-tab id="tab1" title="登录">
|
||||
<d-form ref="formLogin" layout="vertical" :data="loginData" :rules="rules">
|
||||
<d-form-item field="username">
|
||||
<d-input v-model="loginData.username" placeholder="请输入用户名" />
|
||||
</d-form-item>
|
||||
<d-form-item field="password">
|
||||
<d-input v-model="loginData.password" show-password placeholder="请输入密码" />
|
||||
</d-form-item>
|
||||
<d-form-item class="form-operation-wrap">
|
||||
<d-button class="w-full" variant="solid" @click="login">登 录</d-button>
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
</d-tab>
|
||||
<d-tab id="tab2" title="注册">
|
||||
<d-form ref="formReg" layout="vertical" :data="regData" :rules="rrules">
|
||||
<d-form-item field="username">
|
||||
<d-input v-model="regData.username" placeholder="请输入用户名" />
|
||||
</d-form-item>
|
||||
<d-form-item field="password">
|
||||
<d-input v-model="regData.password" show-password placeholder="请输入用密码" />
|
||||
</d-form-item>
|
||||
<d-form-item field="nickname">
|
||||
<d-input v-model="regData.nickname" placeholder="请输入昵称" />
|
||||
</d-form-item>
|
||||
<d-form-item class="form-operation-wrap">
|
||||
<d-button class="w-full" variant="solid" @click="register">注册</d-button>
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
</d-tab>
|
||||
</d-tabs>
|
||||
</d-card>
|
||||
<n-card class="mt-10 rounden-[10px] w-[500px]" shadow="never">
|
||||
<n-tabs v-model:value="tid" justify-content="space-evenly" animated>
|
||||
<n-tab-pane name="tab1" tab="登录">
|
||||
<n-form ref="formLogin" layout="vertical" :data="loginData" :rules="rules">
|
||||
<n-form-item field="username">
|
||||
<n-input v-model:value="loginData.username" placeholder="请输入用户名" />
|
||||
</n-form-item>
|
||||
<n-form-item field="password">
|
||||
<n-input v-model:value="loginData.password" type="password" show-password-on="click" placeholder="请输入密码" />
|
||||
</n-form-item>
|
||||
<n-form-item class="form-operation-wrap">
|
||||
<n-button class="w-full" type="primary" @click="login">登 录</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="tab2" tab="注册">
|
||||
<n-form ref="formReg" layout="vertical" :data="regData" :rules="rrules">
|
||||
<n-form-item field="username">
|
||||
<n-input v-model:value="regData.username" placeholder="请输入用户名" />
|
||||
</n-form-item>
|
||||
<n-form-item field="password">
|
||||
<n-input v-model:value="regData.password" type="password" show-password-on="click" placeholder="请输入用密码" />
|
||||
</n-form-item>
|
||||
<n-form-item field="nickname">
|
||||
<n-input v-model:value="regData.nickname" placeholder="请输入昵称" />
|
||||
</n-form-item>
|
||||
<n-form-item class="form-operation-wrap">
|
||||
<n-button class="w-full" type="primary" @click="register">注册</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const router = useRouter()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void
|
||||
}>()
|
||||
const props = defineProps({
|
||||
setVisible: {
|
||||
type: Function,
|
||||
default: () => { },
|
||||
}
|
||||
})
|
||||
// 登录注册逻辑
|
||||
const tid = ref("tab1");
|
||||
const formLogin: any = ref(null);
|
||||
@ -77,8 +80,8 @@ const rrules: any = reactive({
|
||||
})
|
||||
function login() {
|
||||
console.log('>>> --> login --> formLogin.value:', usrLog.isLogin)
|
||||
formLogin.value.validate(async (is: boolean, b: any) => {
|
||||
if (!is) {
|
||||
formLogin.value?.validate(async (is: boolean) => {
|
||||
if (is) {
|
||||
$msg.error('信息填写不正确,请检查后再提交')
|
||||
} else {
|
||||
const res = await $http.user.login(loginData)
|
||||
@ -90,15 +93,14 @@ function login() {
|
||||
$cookies.set('userinfo', res.data.userinfo, '1d')
|
||||
$msg.success(res.msg)
|
||||
usrLog.setIsLogin(true)
|
||||
// router.push({ path: "/" })
|
||||
emit("update:visible",false)
|
||||
props.setVisible(false)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
function register() {
|
||||
formReg.value.validate(async (is: boolean, b: any) => {
|
||||
if (!is) {
|
||||
formReg.value.validate(async (is: boolean) => {
|
||||
if (is) {
|
||||
$msg.error('信息填写不正确,请检查后再提交')
|
||||
} else {
|
||||
const res = await $http.user.register(regData)
|
||||
@ -108,8 +110,10 @@ function register() {
|
||||
}
|
||||
$msg.success(res.msg)
|
||||
tid.value = 'tab1'
|
||||
formReg.value.resetForm()
|
||||
loginData.username = regData.username
|
||||
regData.username = ''
|
||||
regData.nickname = ''
|
||||
regData.password = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="pr-8">
|
||||
<d-card shadow="never" class="mt-4 bg-white">
|
||||
<n-card embedded class="mt-4 shadow">
|
||||
<!-- <div class="dt-card mt-10 bg-white"> -->
|
||||
<template #title>
|
||||
<template #header>
|
||||
<div class="flex items-center">
|
||||
<icon-time class="w-5 mr-2"></icon-time>
|
||||
时间日期
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<template #default>
|
||||
<div class="w-full pr-20 text-center text-[#ec66ab] font-500 text-4xl font-[yj]">{{ t }}</div>
|
||||
<div class="mt-3 flex justify-between">
|
||||
<span>今年已过了{{ jq.dayOfYear }}天</span>
|
||||
@ -18,19 +18,20 @@
|
||||
<img v-else class="absolute top-0 right-4" width="120" src="@/assets/images/onwork.png" alt="">
|
||||
</template>
|
||||
<!-- </div> -->
|
||||
</d-card>
|
||||
</n-card>
|
||||
|
||||
|
||||
<d-card shadow="never" class="mt-4 bg-white">
|
||||
<template #title>
|
||||
<n-card embedded class="mt-4 shadow">
|
||||
<template #header>
|
||||
<div class="flex items-center">
|
||||
<icon-news class="w-5 mr-2"></icon-news>
|
||||
百度新闻
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<template #default>
|
||||
<div class="py-1" v-for="i in bdNews" :key="i.id">
|
||||
<a class="devui-link flex justify-between truncate" :href="i.url" target="_blank">
|
||||
<!-- 淡蓝色 -->
|
||||
<a class="text-[#526ecc] no-underline hover:text-primary hover:underline flex justify-between truncate" :href="i.url" target="_blank">
|
||||
<span class="flex items-center">{{ i.index }}. {{ i.title }}
|
||||
<icon-hot v-show="i.index < 4" class="ml-2 w-4 text-[red] inline-block"></icon-hot>
|
||||
</span>
|
||||
@ -39,7 +40,7 @@
|
||||
</div>
|
||||
<div class="mt-2 justify-between flex items-center">
|
||||
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
||||
<a class="devui-link text-[#ec66ab] flex items-center" href="https://www.baidu.com/s?ie=utf-8&wd=百度新闻"
|
||||
<a class="text-[#526ecc] no-underline text-[#ec66ab] flex items-center" href="https://www.baidu.com/s?ie=utf-8&wd=百度新闻"
|
||||
target="_blank">
|
||||
更多
|
||||
<icon-right class="ml-1 w-4 text-primary inline-block"></icon-right>
|
||||
@ -47,18 +48,18 @@
|
||||
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
||||
</div>
|
||||
</template>
|
||||
</d-card>
|
||||
</n-card>
|
||||
|
||||
|
||||
<d-card shadow="never" class="mt-4 bg-white">
|
||||
<template #title>
|
||||
<n-card embedded class="mt-4 shadow">
|
||||
<template #header>
|
||||
<div class="flex items-center">
|
||||
<icon-date class="w-5 mr-2"></icon-date>
|
||||
农历节气
|
||||
<div class="ml-12 text-[#ec66ab] font-500">{{ jq.yearTips }}年 {{ jq.lunarCalendar }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<template #default>
|
||||
<div class="truncate text-sm mx-[5%]">
|
||||
宜:{{ jq.suit }}
|
||||
</div>
|
||||
@ -70,7 +71,7 @@
|
||||
</div>
|
||||
<div class="mt-2 text-center">{{ jq.solarTerms }}</div>
|
||||
</template>
|
||||
</d-card>
|
||||
</n-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@ -132,8 +133,14 @@ onUnmounted(() => {
|
||||
src: url('@/assets/font/LCDML.woff2');
|
||||
}
|
||||
|
||||
|
||||
:deep(.n-card > .n-card__content, .n-card > .n-card__footer){
|
||||
padding: 8px 25px !important;
|
||||
}
|
||||
|
||||
// .dt-card {
|
||||
// background-image: url('@/assets/images/中秋节中国风边框34.png');
|
||||
// background-size: 100% 100%;
|
||||
// padding: 20px 40px;
|
||||
// }</style>
|
||||
// }
|
||||
</style>
|
||||
35
src/components/mask.vue
Normal file
35
src/components/mask.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div v-if="visible"
|
||||
class="fixed top-0 left-0 z-[1000] w-[100vw] h-[100vh] flex items-center justify-center bg-[rgba(0,0,0,0.5)]">
|
||||
<slot></slot>
|
||||
<div @click.prevent="handdleClose" class="absolute w-8 h-8 top-4 right-4 rounded-full bg-white flex items-center justify-center text-[#ec66ab] cursor-pointer">X</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
//mark import
|
||||
|
||||
//mark data
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
setVisible: {
|
||||
type: Function,
|
||||
default: () => { },
|
||||
}
|
||||
});
|
||||
//mark method
|
||||
function handdleClose() {
|
||||
props.setVisible(false)
|
||||
}
|
||||
//mark 周期、内置函数等
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
@ -5,36 +5,15 @@
|
||||
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
||||
</div>
|
||||
<!-- 主导航菜单 -->
|
||||
<d-menu mode="horizontal" router class="ml-5 h-14 text-[16px] " :default-select-keys="[key]">
|
||||
<d-menu-item key="home">
|
||||
<d-icon :component="homeSvg" class="w-5 mr-1"></d-icon>
|
||||
首页
|
||||
</d-menu-item>
|
||||
<d-menu-item key="gallery">
|
||||
<d-icon :component="picSvg" class="w-5 mr-1"></d-icon>
|
||||
画廊
|
||||
</d-menu-item>
|
||||
<d-menu-item key="article">
|
||||
<d-icon :component="artiSvg" class="w-5 mr-1 "></d-icon>
|
||||
文章
|
||||
</d-menu-item>
|
||||
<d-menu-item key="widget">
|
||||
<d-icon :component="settingSvg" class="w-5 mr-1 "></d-icon>
|
||||
工具
|
||||
</d-menu-item>
|
||||
<d-menu-item key="appshare">
|
||||
<d-icon :component="downSvg" class="w-5 mr-1 "></d-icon>
|
||||
软件分享
|
||||
</d-menu-item>
|
||||
<d-menu-item key="plink">
|
||||
<d-icon :component="linkSvg" class="w-5 mr-1 "></d-icon>
|
||||
友链
|
||||
</d-menu-item>
|
||||
</d-menu>
|
||||
<div>
|
||||
<n-menu :icon-size="12" v-model:value="activeKey" class="" mode="horizontal" :options="menuOptions" />
|
||||
</div>
|
||||
<!-- 用户区域 -->
|
||||
<div class="!text-[#ec66ab] flex items-center" @click="gotoHf">
|
||||
<span class="flex items-center location-info truncate">
|
||||
<d-icon color="#ec66ab" class="mr-1" name="location-new"></d-icon>
|
||||
<n-icon class="mr-1">
|
||||
<icon-loc class="w-[26px] h-[26px]"></icon-loc>
|
||||
</n-icon>
|
||||
{{ locationInfo }}
|
||||
</span>
|
||||
<span class="mx-3 text-gray-300">|</span>
|
||||
@ -44,47 +23,35 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mr-8">
|
||||
<d-dropdown class="cursor-pointer w-[100px]" v-if="userinfo" trigger="hover">
|
||||
<n-dropdown class="cursor-pointer w-[100px]" v-if="userinfo" :options="oprOp" @select="handleSelect"
|
||||
trigger="hover">
|
||||
<div class="flex items-center">
|
||||
<d-avatar :img-src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
||||
<n-avatar round :src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
||||
</div>
|
||||
<template #menu>
|
||||
<ul class="list-menu">
|
||||
<!-- hover为淡粉色 -->
|
||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="logout">
|
||||
登出
|
||||
</li>
|
||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="">
|
||||
控制台
|
||||
</li>
|
||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="">
|
||||
设置
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</d-dropdown>
|
||||
<div v-else class="flex items-center">
|
||||
<d-avatar class="cursor-pointer" @click="toLogin"></d-avatar>
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm" @click="toLogin">登录</div>
|
||||
</n-dropdown>
|
||||
<div v-else class="flex items-center" @click="toLogin">
|
||||
<n-avatar round class="cursor-pointer"></n-avatar>
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm" >登录</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 登录弹窗 -->
|
||||
<d-modal class="!w-120" v-model="visible">
|
||||
<login-modal v-model:visible="visible"></login-modal>
|
||||
</d-modal>
|
||||
<masked :visible="visible" :setVisible="setVisible">
|
||||
<loginModal :setVisible="setVisible" />
|
||||
</masked>
|
||||
|
||||
</div>
|
||||
<div class="flex justify-between bg-white lg:hidden">
|
||||
<div class="pl-2 items-centerflex" slot="brand" @click="">
|
||||
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
||||
</div>
|
||||
<div class="flex items-center mr-2">
|
||||
<div v-if="userinfo" class="flex items-center">
|
||||
<d-avatar :img-src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
||||
</div>
|
||||
<div v-if="userinfo" class="flex items-center">
|
||||
<n-avatar :src="userinfo.ava_url" round class="cursor-pointer" alt="用户的头" />
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
||||
</div>
|
||||
<div v-else class="flex items-center">
|
||||
<d-avatar class="cursor-pointer" @click="toLogin"></d-avatar>
|
||||
<n-avatar round class="cursor-pointer" @click="toLogin"></n-avatar>
|
||||
<div class="cursor-pointer ml-2 text-gray text-sm" @click="toLogin">登录</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,16 +68,16 @@ import linkSvg from '@/icon/menu/link.svg';
|
||||
import picSvg from '@/icon/menu/pic.svg';
|
||||
import settingSvg from '@/icon/menu/setting.svg';
|
||||
import loginModal from '@/components/Login.vue'
|
||||
import masked from '@/components/mask.vue'
|
||||
|
||||
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { useRoute, useRouter, RouterLink } from 'vue-router';
|
||||
|
||||
const activeKey = ref('home')
|
||||
const route = useRoute();
|
||||
const visible = ref(false);
|
||||
const router = useRouter();
|
||||
const key = ref("home");
|
||||
const locationInfo = ref("获取位置中...");
|
||||
const latitude = ref<number | null>(null);
|
||||
const longitude = ref<number | null>(null);
|
||||
@ -122,7 +89,69 @@ const userinfo: any = ref(null)
|
||||
const nav: any = useTemplateRef('nav')
|
||||
const navx = $store.nav.useNavStore()
|
||||
const usrLog = $store.log.useLogStore()
|
||||
console.log('>>> --> route:', route)
|
||||
const menuOptions = ref([
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/home', class: 'flex items-center justify-center' }, { default: () => '首页' }),
|
||||
key: "home",
|
||||
icon: () => h(homeSvg)
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/gallery', class: 'flex items-center justify-center' }, { default: () => '画廊管理' }),
|
||||
key: "gallery",
|
||||
icon: () => h(picSvg)
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/blog', class: 'flex items-center justify-center' }, { default: () => '文章管理' }),
|
||||
key: "blog",
|
||||
icon: () => h(artiSvg)
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/widget', class: 'flex items-center justify-center' }, { default: () => '工具管理' }),
|
||||
key: "widget",
|
||||
icon: () => h(downSvg)
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/apps', class: 'flex items-center justify-center' }, { default: () => '软件管理' }),
|
||||
key: "apps",
|
||||
icon: () => h(settingSvg)
|
||||
},
|
||||
{
|
||||
label: () => h(RouterLink, { to: '/plink', class: 'flex items-center justify-center' }, { default: () => '友链管理' }),
|
||||
key: "plink",
|
||||
icon: () => h(linkSvg)
|
||||
},
|
||||
]);
|
||||
const oprOp = ref([
|
||||
{
|
||||
key: 'logout',
|
||||
label: '退出登录',
|
||||
},
|
||||
{
|
||||
key: 'console',
|
||||
label: '控制台',
|
||||
},
|
||||
{
|
||||
key: 'setting',
|
||||
label: '设置',
|
||||
}
|
||||
])
|
||||
|
||||
function setVisible(v: any) {
|
||||
visible.value = v
|
||||
}
|
||||
|
||||
function handleSelect(key: string) {
|
||||
console.log('>>> --> handleSelect --> key:', key)
|
||||
if (key == 'logout') {
|
||||
logout()
|
||||
return
|
||||
}
|
||||
if (key == 'console') {
|
||||
router.push('/console')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 获取地理位置
|
||||
const getLocation = () => {
|
||||
if (!navigator.geolocation) {
|
||||
@ -198,7 +227,7 @@ async function handdleJw(jw: string) {
|
||||
}
|
||||
|
||||
watch(() => route.name, (newVal) => {
|
||||
key.value = newVal as string
|
||||
activeKey.value = newVal as string
|
||||
})
|
||||
|
||||
function goHome() {
|
||||
@ -220,6 +249,9 @@ function logout() {
|
||||
usrLog.setIsLogin(false)
|
||||
userinfo.value = null;
|
||||
}
|
||||
function gotoConsole() {
|
||||
window.open("https://www.hxyouzi.com/console/home", "_BLACK")
|
||||
}
|
||||
|
||||
function gotoHf() {
|
||||
console.log('>>> --> gotoHf --> fxlink:', fxlink)
|
||||
@ -230,7 +262,10 @@ onMounted(() => {
|
||||
|
||||
userinfo.value = $cookies.get('userinfo');
|
||||
console.log('>>>>>>>>>>', userinfo.value);
|
||||
key.value = route.name as string;
|
||||
setTimeout(() => {
|
||||
console.log('>>>>>>>>>>', route)
|
||||
activeKey.value = route.name as string;
|
||||
}, 20);
|
||||
console.log('>>> --> route.name:', route.name)
|
||||
getLocation(); // 组件挂载时获取位置
|
||||
|
||||
@ -242,7 +277,7 @@ onMounted(() => {
|
||||
});
|
||||
onBeforeUpdate(() => {
|
||||
userinfo.value = $cookies.get('userinfo');
|
||||
key.value = route.name as string;
|
||||
activeKey.value = route.name as string;
|
||||
const h: number = nav.value.clientHeight
|
||||
// console.log('******>>> --> nav.value:', nav.value)
|
||||
// console.log('()()()()()>>> --> h:', h)
|
||||
@ -257,32 +292,10 @@ onBeforeUpdate(() => {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
:deep(.devui-menu-horizontal .devui-menu-item:hover span .icon) {
|
||||
color: var(--devui-brand, #5e7ce0) !important;
|
||||
fill: var(--devui-brand, #5e7ce0) !important;
|
||||
:deep(.n-menu-item-content__icon) {
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
}
|
||||
|
||||
:deep(.devui-menu-item-select span svg) {
|
||||
color: var(--devui-brand, #5e7ce0) !important;
|
||||
fill: var(--devui-brand, #5e7ce0) !important;
|
||||
line-height: 100% !important;
|
||||
}
|
||||
|
||||
:deep(.devui-menu-item-select span) {
|
||||
color: var(--devui-brand, #5e7ce0) !important;
|
||||
}
|
||||
|
||||
:deep(.devui-menu-horizontal) {
|
||||
padding: 14px 20px 6px;
|
||||
}
|
||||
|
||||
:deep(.devui-menu-item span) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.devui-icon__container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user