1
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@ -10,9 +10,9 @@
|
||||
name="description"
|
||||
content="燃谷科技位于南京鼓楼万谷硅巷,秉承创新、质量和合作精神的低空领域技术创新公司,专注于低空安全监管、城市飞行服务和空间数据应用的企业。"
|
||||
/>
|
||||
<script src="/config.js"></script>
|
||||
<script src="/config/nav.js"></script>
|
||||
<script src="/config/product.js"></script>
|
||||
<script src="/config.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
window.config = {
|
||||
baseUrl: 'http://192.168.3.10:9121/',
|
||||
downloadUrl: 'https://work.rangutech.cn:1001/',
|
||||
featureUrl: 'https://sys.rangutech.com/#/',
|
||||
assetsUrl: 'https://insider.rangutech.com/app_static_data/images/',
|
||||
// downloadUrl: 'http://192.168.3.5:9193/',
|
||||
}
|
||||
|
||||
@ -25,7 +25,10 @@ window.nav = {
|
||||
{id: 4, label: '新闻中心', url: '/news', hasChildren: false},
|
||||
{id: 5, label: '关于我们', url: '/about', hasChildren: false},
|
||||
{id: 6, label: '联系我们', url: '/link', hasChildren: false},
|
||||
{id: 7, label: '资源下载', url: '/download', hasChildren: false},
|
||||
{id: 8, label: '演示系统', url: window.config.featureUrl, hasChildren: false, open: true},
|
||||
],
|
||||
|
||||
footer: [
|
||||
{
|
||||
id: 1,
|
||||
@ -43,13 +46,19 @@ window.nav = {
|
||||
// url: '/services',
|
||||
// hasChildren: false,
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// label: '软件下载',
|
||||
// url: '/download',
|
||||
// hasChildren: false,
|
||||
// },
|
||||
{id: 4, label: '新闻中心', url: '/news', hasChildren: false},
|
||||
{
|
||||
id: 3,
|
||||
label: '资源下载',
|
||||
url: '/download',
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{id: 3.1, label: '资源下载', url: '/download'},
|
||||
{id: 3.2, label: 'Android', url: '', downloadType: 'android'},
|
||||
{id: 3.3, label: 'iOS', url: '', downloadType: 'ios'},
|
||||
{id: 3.4, label: '客户端', url: '', downloadType: 'pc'},
|
||||
],
|
||||
},
|
||||
// {id: 4, label: '新闻中心', url: '/news', hasChildren: false},
|
||||
{
|
||||
id: 5,
|
||||
label: '关于燃谷',
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 5.8 MiB |
BIN
public/static/images/banner/download.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 690 KiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 679 KiB After Width: | Height: | Size: 6.0 MiB |
BIN
public/static/images/download/android.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
public/static/images/download/ios.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/static/images/download/windows.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
@ -44,3 +44,20 @@ export function saveDetail(data) {
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取下载资源
|
||||
export function downloadList(params) {
|
||||
return request({
|
||||
url: `${window.config.downloadUrl}api/minio/Object/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export function downloadFile(params) {
|
||||
return request({
|
||||
url: `${window.config.downloadUrl}api/minio/Object/url`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
52
src/components/downloadImg/index.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const visible = defineModel({default: false})
|
||||
|
||||
const options = {
|
||||
ios: {label: 'iOS', img: `${window.config.assetsUrl}app/ios.png`},
|
||||
android: {label: 'Android', img: `${window.config.assetsUrl}app/android.png`},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="扫码下载" width="500px" :close-on-click-modal="true">
|
||||
<div class="dialog-body flex j-c a-c">
|
||||
<div class="download-option">
|
||||
<img :src="options[type]?.img" :alt="type" />
|
||||
<span class="label">{{ options[type]?.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-body {
|
||||
gap: 40px;
|
||||
padding: 20px 0;
|
||||
|
||||
.download-option {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -28,6 +28,8 @@ export const useNavStore = defineStore(
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: true,
|
||||
persist: {
|
||||
storage: sessionStorage,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@ -1,55 +1,261 @@
|
||||
<script setup>
|
||||
import {ref, onMounted} from 'vue'
|
||||
import Swiper from '@/components/swiper/index.vue'
|
||||
import Swiper from '@/components/Swiper/index.vue'
|
||||
import {downloadFile, downloadList} from '@/api'
|
||||
import Banner from '@/components/Banner/index.vue'
|
||||
import DownloadImg from '@/components/downloadImg/index.vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
|
||||
const currentPage = ref(1)
|
||||
const currentFilePage = ref(1)
|
||||
|
||||
onMounted(() => {})
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const list = ref([
|
||||
{id: 1, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
{id: 2, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
{id: 3, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
{id: 4, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
{id: 5, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
{id: 6, imgUrl: 'main/1.png', label: 'XXX平台', subLabel: '具有XXX功能'},
|
||||
])
|
||||
const list = ref(null)
|
||||
|
||||
const downloadFile = (id) => {
|
||||
console.log('id===>', id)
|
||||
/**
|
||||
* 将带有 Key(路径)的扁平列表转换为树形结构
|
||||
* @param {Array} items - 原始数据,每个元素包含 Key, ETag, Size, LastModifiedDateTime 等
|
||||
* @returns {Array} 树形数组,每个元素为文件或文件夹节点
|
||||
*/
|
||||
const transform = (items) => {
|
||||
const root = {children: []}
|
||||
const getOrCreateFolder = (parent, name, fullPath) => {
|
||||
let folder = parent.children.find((child) => child.name === name && child.type === 'folder')
|
||||
if (!folder) {
|
||||
folder = {name, type: 'folder', children: [], fullPath}
|
||||
parent.children.push(folder)
|
||||
}
|
||||
return folder
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
const parts = item.Key.split('/')
|
||||
if (parts.length === 1) {
|
||||
root.children.push({
|
||||
name: parts[0],
|
||||
type: 'file',
|
||||
etag: item.ETag,
|
||||
size: item.Size,
|
||||
lastModified: item.LastModifiedDateTime,
|
||||
fullPath: item.Key,
|
||||
})
|
||||
} else {
|
||||
let currentParent = root
|
||||
let currentPath = ''
|
||||
for (let i = 0; i < parts.length - 1; i++) {
|
||||
const folderName = parts[i]
|
||||
currentPath += (currentPath ? '/' : '') + folderName
|
||||
currentParent = getOrCreateFolder(currentParent, folderName, currentPath + '/')
|
||||
}
|
||||
const fileName = parts[parts.length - 1]
|
||||
currentParent.children.push({
|
||||
name: fileName,
|
||||
type: 'file',
|
||||
etag: item.ETag,
|
||||
size: item.Size,
|
||||
lastModified: item.LastModifiedDateTime,
|
||||
fullPath: item.Key,
|
||||
})
|
||||
}
|
||||
})
|
||||
return root.children
|
||||
}
|
||||
|
||||
// el-tree 的 props 配置
|
||||
const treeProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*/
|
||||
const formatSize = (bytes) => {
|
||||
if (!bytes) return ''
|
||||
const units = ['B', 'KB', 'MB', 'GB']
|
||||
let i = 0
|
||||
let size = bytes
|
||||
while (size >= 1024 && i < units.length - 1) {
|
||||
size /= 1024
|
||||
i++
|
||||
}
|
||||
return size.toFixed(2) + ' ' + units[i]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载的文件列表
|
||||
*/
|
||||
const getList = () => {
|
||||
let params = {
|
||||
recursive: true,
|
||||
version: true,
|
||||
prefix: '',
|
||||
bucket: '',
|
||||
}
|
||||
downloadList(params)
|
||||
.then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 0 && res?.data?.length > 0) {
|
||||
list.value = transform(res.data)
|
||||
console.log('list.value===>', list.value)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
const downloadFileFN = (data) => {
|
||||
console.log('data===>', data)
|
||||
let query = {
|
||||
bucket: '',
|
||||
objname: data.fullPath,
|
||||
expiresMinutes: 60,
|
||||
isDownload: true,
|
||||
}
|
||||
downloadFile(query)
|
||||
.then((res) => {
|
||||
console.log('res===>', res)
|
||||
if (res.code === 0 && res.data) {
|
||||
window.open(res.data)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err===>', err)
|
||||
})
|
||||
}
|
||||
|
||||
// 提示用户敬请期待
|
||||
const showMsg = () => {
|
||||
ElMessage.warning('敬请期待!')
|
||||
}
|
||||
|
||||
const imgType = ref('ios')
|
||||
const showImgType = ref(false)
|
||||
|
||||
const openImg = (type) => {
|
||||
imgType.value = type
|
||||
showImgType.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="placeholder"></div>
|
||||
<Banner class="banner" img="banner/download.png" />
|
||||
<Swiper
|
||||
id="download"
|
||||
title="软件下载"
|
||||
id="one"
|
||||
title="资源下载"
|
||||
v-model="currentPage"
|
||||
:sourceWidth="1600"
|
||||
:sourceHeight="800"
|
||||
:sourceWidth="1200"
|
||||
:sourceHeight="400"
|
||||
:show-pagination="false"
|
||||
:auto-play="false"
|
||||
:showHover="false"
|
||||
>
|
||||
<template #default>
|
||||
<div class="my-card flex j-s wrap">
|
||||
<div class="card flex j-s" v-for="item in list" :key="item.id">
|
||||
<div class="img">
|
||||
<img :src="`./static/main/${item.imgUrl}`" alt="" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="label">{{ item.label }}</div>
|
||||
<div class="sub-label">{{ item.subLabel }}</div>
|
||||
<div class="download" @click="downloadFile(item.id)">
|
||||
点击下载
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-card flex j-s">
|
||||
<div class="img" @click="openImg('ios')">
|
||||
<img src="/static/images/download/ios.png" alt="" />
|
||||
</div>
|
||||
<div class="img" @click="openImg('android')">
|
||||
<img src="/static/images/download/android.png" alt="" />
|
||||
</div>
|
||||
<div class="img" @click="showMsg">
|
||||
<img src="/static/images/download/windows.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Swiper>
|
||||
|
||||
<Swiper
|
||||
id="file"
|
||||
title="文件下载"
|
||||
v-model="currentFilePage"
|
||||
:sourceWidth="1200"
|
||||
:sourceHeight="400"
|
||||
:show-pagination="false"
|
||||
:auto-play="false"
|
||||
:showHover="false"
|
||||
>
|
||||
<div class="file-list">
|
||||
<el-tree v-if="list && list.length" :data="list" :props="treeProps" accordion node-key="name">
|
||||
<template #default="{data}">
|
||||
<div class="tree-node">
|
||||
<!-- 文件夹图标 -->
|
||||
<svg
|
||||
v-if="data.type === 'folder'"
|
||||
class="node-icon folder-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2 6C2 4.89543 2.89543 4 4 4H9.17157C9.70199 4 10.2107 4.21071 10.5858 4.58579L12 6H20C21.1046 6 22 6.89543 22 8V18C22 19.1046 21.1046 20 20 20H4C2.89543 20 2 19.1046 2 18V6Z"
|
||||
fill="#F7C948"
|
||||
stroke="#E5A800"
|
||||
stroke-width="1.2"
|
||||
/>
|
||||
</svg>
|
||||
<!-- 文件图标 -->
|
||||
<svg
|
||||
v-else
|
||||
class="node-icon file-icon"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 2H14.1716C14.702 2 15.2107 2.21071 15.5858 2.58579L19.4142 6.41421C19.7893 6.78929 20 7.29799 20 7.82843V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2Z"
|
||||
fill="#A8C5E0"
|
||||
stroke="#7DA8CC"
|
||||
stroke-width="1.2"
|
||||
/>
|
||||
<path d="M14 2V6C14 7.10457 14.8954 8 16 8H20" stroke="#7DA8CC" stroke-width="1.2" fill="none" />
|
||||
</svg>
|
||||
|
||||
<span class="node-label">{{ data.name }}</span>
|
||||
|
||||
<!-- 文件信息(仅文件类型显示) -->
|
||||
<template v-if="data.type === 'file'">
|
||||
<span class="file-size">{{ formatSize(data.size) }}</span>
|
||||
<span class="file-date">{{ data.lastModified }}</span>
|
||||
<!-- 下载图标 -->
|
||||
<svg
|
||||
class="download-icon"
|
||||
@click.stop="downloadFileFN(data)"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 3V15M12 15L8 11M12 15L16 11"
|
||||
stroke="#4A90D9"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4 17V19C4 20.1046 4.89543 21 6 21H18C19.1046 21 20 20.1046 20 19V17"
|
||||
stroke="#4A90D9"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
<div v-else class="empty-tip">暂无下载资源</div>
|
||||
</div>
|
||||
</Swiper>
|
||||
|
||||
<DownloadImg :type="imgType" v-model="showImgType" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -57,40 +263,133 @@ const downloadFile = (id) => {
|
||||
.my-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.card {
|
||||
width: 48%;
|
||||
height: 170px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.img {
|
||||
width: 300px;
|
||||
height: 360px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
.img {
|
||||
width: 550px;
|
||||
|
||||
img {
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #d9d9d9;
|
||||
}
|
||||
.content {
|
||||
margin-top: 20px;
|
||||
text-align: left;
|
||||
.label {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 26px;
|
||||
color: $black;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.sub-label {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #999999;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.download {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #0389ff;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-title {
|
||||
text-align: center;
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 1.5rem;
|
||||
color: #333333;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 6px;
|
||||
background-color: #0389ff;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 20px;
|
||||
translate: -50%;
|
||||
}
|
||||
}
|
||||
|
||||
.file-list {
|
||||
width: 1200px;
|
||||
max-height: 500px;
|
||||
border: 1px solid #e5e5e5;
|
||||
margin: 0px auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
padding: 40px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* el-tree 节点自定义样式 */
|
||||
.tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 4px 0;
|
||||
gap: 8px;
|
||||
|
||||
.node-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.node-label {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
min-width: 80px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.file-date {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
min-width: 140px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 覆盖 el-tree 默认样式 */
|
||||
::v-deep(.el-tree) {
|
||||
background: transparent;
|
||||
|
||||
.el-tree-node__content {
|
||||
height: auto;
|
||||
padding: 6px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -23,6 +23,10 @@ function toUrl(item) {
|
||||
query: {type: cryptoEncrypt(JSON.stringify(item))},
|
||||
})
|
||||
}
|
||||
|
||||
function goToFeatural() {
|
||||
window.open(window.config.featureUrl)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -31,7 +35,7 @@ function toUrl(item) {
|
||||
<video autoplay muted loop @loadeddata="onVideoLoaded">
|
||||
<source src="/static/video/display.mp4" type="video/mp4" />
|
||||
</video>
|
||||
<div class="banner-link"><span>进入演示系统</span></div>
|
||||
<div class="banner-link" @click="goToFeatural"><span>进入演示系统</span></div>
|
||||
</div>
|
||||
<Swiper
|
||||
id="home_swiper"
|
||||
|
||||
@ -7,24 +7,26 @@ const navStore = useNavStore()
|
||||
const router = useRouter()
|
||||
const footerNav = ref([])
|
||||
|
||||
const emit = defineEmits(['downloadClick'])
|
||||
|
||||
onMounted(() => {
|
||||
footerNav.value = window.nav.footer
|
||||
})
|
||||
|
||||
const navClick = (url) => {
|
||||
navStore.changeNavIndex(url)
|
||||
router.push(url)
|
||||
const navClick = (node) => {
|
||||
if (node.downloadType) {
|
||||
emit('downloadClick', node.downloadType)
|
||||
return
|
||||
}
|
||||
if (!node.url) return
|
||||
navStore.changeNavIndex(node.url)
|
||||
router.push(node.url)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul class="footer-nav flex j-s">
|
||||
<NavNode
|
||||
v-for="node in footerNav"
|
||||
:key="node.id"
|
||||
:node="node"
|
||||
@nav-click="navClick"
|
||||
/>
|
||||
<NavNode v-for="node in footerNav" :key="node.id" :node="node" @nav-click="navClick" />
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@ defineProps({
|
||||
|
||||
const emits = defineEmits(['navClick'])
|
||||
|
||||
const onClick = (url) => emits('navClick', url)
|
||||
const onClick = (node) => emits('navClick', node)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="footer-nav__item">
|
||||
<div class="item-label" @click="onClick(node.url)">
|
||||
<div class="item-label" @click="onClick(node)">
|
||||
{{ node.label }}
|
||||
</div>
|
||||
|
||||
@ -41,8 +41,8 @@ const onClick = (url) => emits('navClick', url)
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
&:hover {
|
||||
-webkit-transform: translateY(-8px);
|
||||
transform: translateY(-8px);
|
||||
-webkit-transform: translateY(-2px);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,21 @@ import {ref, onMounted} from 'vue'
|
||||
import Logo from './components/logo.vue'
|
||||
import Nav from './components/nav.vue'
|
||||
import QRCode from './components/QRCode.vue'
|
||||
import DownloadImg from '@/components/downloadImg/index.vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
|
||||
const imgType = ref('ios')
|
||||
const showImgType = ref(false)
|
||||
|
||||
const handleDownloadClick = (type) => {
|
||||
if (type === 'pc') {
|
||||
ElMessage.warning('敬请期待!')
|
||||
return
|
||||
}
|
||||
imgType.value = type
|
||||
showImgType.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {})
|
||||
|
||||
const toMIIF = () => {
|
||||
@ -16,7 +31,7 @@ const toMIIF = () => {
|
||||
<Logo id="logo" />
|
||||
|
||||
<!-- 内容 -->
|
||||
<Nav id="nav" />
|
||||
<Nav id="nav" @download-click="handleDownloadClick" />
|
||||
|
||||
<!-- 二维码 -->
|
||||
<QRCode id="QR" />
|
||||
@ -29,6 +44,8 @@ const toMIIF = () => {
|
||||
<span class="url" @click="toMIIF">苏ICP备2023030548号-1</span>
|
||||
<span class="url" @click="toMIIF">苏ICP备2023030548号-5</span>
|
||||
</div>
|
||||
|
||||
<DownloadImg :type="imgType" v-model="showImgType" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,19 +1,39 @@
|
||||
<script setup>
|
||||
import {ref, onMounted, watch, onUnmounted} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useNavStore} from '@/store/nav'
|
||||
import {storeToRefs} from 'pinia'
|
||||
|
||||
// Store 相关
|
||||
const navStore = useNavStore()
|
||||
const {navIndex} = storeToRefs(navStore)
|
||||
const router = useRouter()
|
||||
|
||||
// 响应式数据
|
||||
const navList = ref([])
|
||||
const activeIndex = ref('/')
|
||||
|
||||
// 根据 url 查找导航项(含子级)
|
||||
const findNavItem = (url) => {
|
||||
for (const nav of navList.value) {
|
||||
if (nav.url === url && !nav.hasChildren) return nav
|
||||
if (nav.children) {
|
||||
const child = nav.children.find((c) => c.url === url)
|
||||
if (child) return child
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 处理导航选择
|
||||
const handleSelect = (key) => {
|
||||
const navItem = findNavItem(key)
|
||||
if (navItem?.open) {
|
||||
window.open(navItem.url)
|
||||
return
|
||||
}
|
||||
navStore.changeNavIndex(key)
|
||||
router.push(key)
|
||||
}
|
||||
|
||||
// 监听 store 中的 navIndex 变化
|
||||
@ -47,33 +67,20 @@ onUnmounted(() => {
|
||||
active-text-color="#FFFFFF"
|
||||
text-color="#999999"
|
||||
background-color="$bg_color"
|
||||
router
|
||||
>
|
||||
<template v-for="nav in navList" :key="nav.id">
|
||||
<!-- 有子菜单的情况 -->
|
||||
<el-sub-menu
|
||||
v-if="nav.hasChildren || nav?.children?.length > 0"
|
||||
:index="nav.url"
|
||||
popper-class="pepper"
|
||||
>
|
||||
<el-sub-menu v-if="nav.hasChildren || nav?.children?.length > 0" :index="nav.url" popper-class="pepper">
|
||||
<template #title>
|
||||
<span>{{ nav.label }}</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="child in nav.children"
|
||||
:key="child.id"
|
||||
:index="child.url"
|
||||
>
|
||||
<el-menu-item v-for="child in nav.children" :key="child.id" :index="child.url">
|
||||
{{ child.label }}
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<!-- 无子菜单的情况 -->
|
||||
<el-menu-item
|
||||
v-else
|
||||
:index="nav.url"
|
||||
:class="{'is-active': activeIndex === nav.url}"
|
||||
>
|
||||
<el-menu-item v-else :index="nav.url" :class="{'is-active': activeIndex === nav.url}">
|
||||
{{ nav.label }}
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||