1
@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@ -10,9 +10,9 @@
|
|||||||
name="description"
|
name="description"
|
||||||
content="燃谷科技位于南京鼓楼万谷硅巷,秉承创新、质量和合作精神的低空领域技术创新公司,专注于低空安全监管、城市飞行服务和空间数据应用的企业。"
|
content="燃谷科技位于南京鼓楼万谷硅巷,秉承创新、质量和合作精神的低空领域技术创新公司,专注于低空安全监管、城市飞行服务和空间数据应用的企业。"
|
||||||
/>
|
/>
|
||||||
|
<script src="/config.js"></script>
|
||||||
<script src="/config/nav.js"></script>
|
<script src="/config/nav.js"></script>
|
||||||
<script src="/config/product.js"></script>
|
<script src="/config/product.js"></script>
|
||||||
<script src="/config.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
window.config = {
|
window.config = {
|
||||||
baseUrl: 'http://192.168.3.10:9121/',
|
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: 4, label: '新闻中心', url: '/news', hasChildren: false},
|
||||||
{id: 5, label: '关于我们', url: '/about', hasChildren: false},
|
{id: 5, label: '关于我们', url: '/about', hasChildren: false},
|
||||||
{id: 6, label: '联系我们', url: '/link', 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: [
|
footer: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -43,13 +46,19 @@ window.nav = {
|
|||||||
// url: '/services',
|
// url: '/services',
|
||||||
// hasChildren: false,
|
// hasChildren: false,
|
||||||
// },
|
// },
|
||||||
// {
|
{
|
||||||
// id: 3,
|
id: 3,
|
||||||
// label: '软件下载',
|
label: '资源下载',
|
||||||
// url: '/download',
|
url: '/download',
|
||||||
// hasChildren: false,
|
hasChildren: true,
|
||||||
// },
|
children: [
|
||||||
{id: 4, label: '新闻中心', url: '/news', hasChildren: false},
|
{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,
|
id: 5,
|
||||||
label: '关于燃谷',
|
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,
|
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>
|
<script setup>
|
||||||
import {ref, onMounted} from 'vue'
|
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 currentPage = ref(1)
|
||||||
|
const currentFilePage = ref(1)
|
||||||
|
|
||||||
onMounted(() => {})
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
|
||||||
const list = ref([
|
const list = ref(null)
|
||||||
{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 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="placeholder"></div>
|
<Banner class="banner" img="banner/download.png" />
|
||||||
<Swiper
|
<Swiper
|
||||||
id="download"
|
id="one"
|
||||||
title="软件下载"
|
title="资源下载"
|
||||||
v-model="currentPage"
|
v-model="currentPage"
|
||||||
:sourceWidth="1600"
|
:sourceWidth="1200"
|
||||||
:sourceHeight="800"
|
:sourceHeight="400"
|
||||||
:show-pagination="false"
|
:show-pagination="false"
|
||||||
:auto-play="false"
|
:auto-play="false"
|
||||||
:showHover="false"
|
:showHover="false"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="my-card flex j-s wrap">
|
<div class="my-card flex j-s">
|
||||||
<div class="card flex j-s" v-for="item in list" :key="item.id">
|
<div class="img" @click="openImg('ios')">
|
||||||
<div class="img">
|
<img src="/static/images/download/ios.png" alt="" />
|
||||||
<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="img" @click="openImg('android')">
|
||||||
|
<img src="/static/images/download/android.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="img" @click="showMsg">
|
||||||
|
<img src="/static/images/download/windows.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Swiper>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -57,40 +263,133 @@ const downloadFile = (id) => {
|
|||||||
.my-card {
|
.my-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.card {
|
|
||||||
width: 48%;
|
|
||||||
height: 170px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
width: 550px;
|
width: 300px;
|
||||||
|
height: 360px;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
img {
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #d9d9d9;
|
|
||||||
}
|
&:hover {
|
||||||
.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;
|
|
||||||
cursor: pointer;
|
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>
|
</style>
|
||||||
|
|||||||
@ -23,6 +23,10 @@ function toUrl(item) {
|
|||||||
query: {type: cryptoEncrypt(JSON.stringify(item))},
|
query: {type: cryptoEncrypt(JSON.stringify(item))},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToFeatural() {
|
||||||
|
window.open(window.config.featureUrl)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -31,7 +35,7 @@ function toUrl(item) {
|
|||||||
<video autoplay muted loop @loadeddata="onVideoLoaded">
|
<video autoplay muted loop @loadeddata="onVideoLoaded">
|
||||||
<source src="/static/video/display.mp4" type="video/mp4" />
|
<source src="/static/video/display.mp4" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
<div class="banner-link"><span>进入演示系统</span></div>
|
<div class="banner-link" @click="goToFeatural"><span>进入演示系统</span></div>
|
||||||
</div>
|
</div>
|
||||||
<Swiper
|
<Swiper
|
||||||
id="home_swiper"
|
id="home_swiper"
|
||||||
|
|||||||
@ -7,24 +7,26 @@ const navStore = useNavStore()
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const footerNav = ref([])
|
const footerNav = ref([])
|
||||||
|
|
||||||
|
const emit = defineEmits(['downloadClick'])
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
footerNav.value = window.nav.footer
|
footerNav.value = window.nav.footer
|
||||||
})
|
})
|
||||||
|
|
||||||
const navClick = (url) => {
|
const navClick = (node) => {
|
||||||
navStore.changeNavIndex(url)
|
if (node.downloadType) {
|
||||||
router.push(url)
|
emit('downloadClick', node.downloadType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!node.url) return
|
||||||
|
navStore.changeNavIndex(node.url)
|
||||||
|
router.push(node.url)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ul class="footer-nav flex j-s">
|
<ul class="footer-nav flex j-s">
|
||||||
<NavNode
|
<NavNode v-for="node in footerNav" :key="node.id" :node="node" @nav-click="navClick" />
|
||||||
v-for="node in footerNav"
|
|
||||||
:key="node.id"
|
|
||||||
:node="node"
|
|
||||||
@nav-click="navClick"
|
|
||||||
/>
|
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -8,12 +8,12 @@ defineProps({
|
|||||||
|
|
||||||
const emits = defineEmits(['navClick'])
|
const emits = defineEmits(['navClick'])
|
||||||
|
|
||||||
const onClick = (url) => emits('navClick', url)
|
const onClick = (node) => emits('navClick', node)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<li class="footer-nav__item">
|
<li class="footer-nav__item">
|
||||||
<div class="item-label" @click="onClick(node.url)">
|
<div class="item-label" @click="onClick(node)">
|
||||||
{{ node.label }}
|
{{ node.label }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -41,8 +41,8 @@ const onClick = (url) => emits('navClick', url)
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
&:hover {
|
&:hover {
|
||||||
-webkit-transform: translateY(-8px);
|
-webkit-transform: translateY(-2px);
|
||||||
transform: translateY(-8px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,21 @@ import {ref, onMounted} from 'vue'
|
|||||||
import Logo from './components/logo.vue'
|
import Logo from './components/logo.vue'
|
||||||
import Nav from './components/nav.vue'
|
import Nav from './components/nav.vue'
|
||||||
import QRCode from './components/QRCode.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(() => {})
|
onMounted(() => {})
|
||||||
|
|
||||||
const toMIIF = () => {
|
const toMIIF = () => {
|
||||||
@ -16,7 +31,7 @@ const toMIIF = () => {
|
|||||||
<Logo id="logo" />
|
<Logo id="logo" />
|
||||||
|
|
||||||
<!-- 内容 -->
|
<!-- 内容 -->
|
||||||
<Nav id="nav" />
|
<Nav id="nav" @download-click="handleDownloadClick" />
|
||||||
|
|
||||||
<!-- 二维码 -->
|
<!-- 二维码 -->
|
||||||
<QRCode id="QR" />
|
<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号-1</span>
|
||||||
<span class="url" @click="toMIIF">苏ICP备2023030548号-5</span>
|
<span class="url" @click="toMIIF">苏ICP备2023030548号-5</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<DownloadImg :type="imgType" v-model="showImgType" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,39 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref, onMounted, watch, onUnmounted} from 'vue'
|
import {ref, onMounted, watch, onUnmounted} from 'vue'
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
import {useNavStore} from '@/store/nav'
|
import {useNavStore} from '@/store/nav'
|
||||||
import {storeToRefs} from 'pinia'
|
import {storeToRefs} from 'pinia'
|
||||||
|
|
||||||
// Store 相关
|
// Store 相关
|
||||||
const navStore = useNavStore()
|
const navStore = useNavStore()
|
||||||
const {navIndex} = storeToRefs(navStore)
|
const {navIndex} = storeToRefs(navStore)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const navList = ref([])
|
const navList = ref([])
|
||||||
const activeIndex = 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 handleSelect = (key) => {
|
||||||
|
const navItem = findNavItem(key)
|
||||||
|
if (navItem?.open) {
|
||||||
|
window.open(navItem.url)
|
||||||
|
return
|
||||||
|
}
|
||||||
navStore.changeNavIndex(key)
|
navStore.changeNavIndex(key)
|
||||||
|
router.push(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听 store 中的 navIndex 变化
|
// 监听 store 中的 navIndex 变化
|
||||||
@ -47,33 +67,20 @@ onUnmounted(() => {
|
|||||||
active-text-color="#FFFFFF"
|
active-text-color="#FFFFFF"
|
||||||
text-color="#999999"
|
text-color="#999999"
|
||||||
background-color="$bg_color"
|
background-color="$bg_color"
|
||||||
router
|
|
||||||
>
|
>
|
||||||
<template v-for="nav in navList" :key="nav.id">
|
<template v-for="nav in navList" :key="nav.id">
|
||||||
<!-- 有子菜单的情况 -->
|
<!-- 有子菜单的情况 -->
|
||||||
<el-sub-menu
|
<el-sub-menu v-if="nav.hasChildren || nav?.children?.length > 0" :index="nav.url" popper-class="pepper">
|
||||||
v-if="nav.hasChildren || nav?.children?.length > 0"
|
|
||||||
:index="nav.url"
|
|
||||||
popper-class="pepper"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>{{ nav.label }}</span>
|
<span>{{ nav.label }}</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item
|
<el-menu-item v-for="child in nav.children" :key="child.id" :index="child.url">
|
||||||
v-for="child in nav.children"
|
|
||||||
:key="child.id"
|
|
||||||
:index="child.url"
|
|
||||||
>
|
|
||||||
{{ child.label }}
|
{{ child.label }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
|
||||||
<!-- 无子菜单的情况 -->
|
<!-- 无子菜单的情况 -->
|
||||||
<el-menu-item
|
<el-menu-item v-else :index="nav.url" :class="{'is-active': activeIndex === nav.url}">
|
||||||
v-else
|
|
||||||
:index="nav.url"
|
|
||||||
:class="{'is-active': activeIndex === nav.url}"
|
|
||||||
>
|
|
||||||
{{ nav.label }}
|
{{ nav.label }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||