移动端样式

This commit is contained in:
yiqiuyang
2026-08-10 14:07:05 +08:00
parent 22a48ceb9f
commit 387c5695e0
7 changed files with 454 additions and 209 deletions
+3 -3
View File
@@ -134,14 +134,14 @@ const {
top: 50%; top: 50%;
left: 0; left: 0;
right: 0; right: 0;
padding: 0 8px; /* no */ padding: 0 8px;
z-index: 10; z-index: 10;
pointer-events: none; pointer-events: none;
.nav-btn { .nav-btn {
pointer-events: auto; pointer-events: auto;
width: 32px; /* no */ width: 32px;
height: 32px; /* no */ height: 32px;
border: none; border: none;
border-radius: 50%; border-radius: 50%;
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
+75 -7
View File
@@ -15,22 +15,74 @@ const options = {
</script> </script>
<template> <template>
<el-dialog v-model="visible" title="扫码下载" width="500px" :close-on-click-modal="true"> <transition name="modal-fade">
<div class="dialog-body flex j-c a-c"> <div v-if="visible" class="modal-overlay" @click.self="visible = false">
<div class="modal-card">
<div class="modal-header">
<span class="modal-title">扫码下载</span>
<span class="modal-close" @click="visible = false">×</span>
</div>
<div class="modal-body">
<div class="download-option"> <div class="download-option">
<img :src="options[type]?.img" :alt="type" /> <img :src="options[type]?.img" :alt="type" />
<span class="label">{{ options[type]?.label }}</span> <span class="label">{{ options[type]?.label }}</span>
</div> </div>
</div> </div>
</el-dialog> </div>
</div>
</transition>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.dialog-body { .modal-overlay {
gap: 40px; position: fixed;
padding: 20px 0; top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2000;
display: flex;
align-items: center;
justify-content: center;
}
.download-option { .modal-card {
width: 280px;
background-color: #fff;
border-radius: 8px;
overflow: hidden;
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 1px solid #eee;
.modal-title {
font-size: 16px;
font-weight: 600;
color: #333;
}
.modal-close {
font-size: 22px;
color: #999;
cursor: pointer;
line-height: 1;
}
}
.modal-body {
padding: 20px 0;
display: flex;
justify-content: center;
align-items: center;
}
}
.download-option {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@@ -47,6 +99,22 @@ const options = {
font-size: 16px; font-size: 16px;
color: #333; color: #333;
} }
}
.modal-fade-enter-active,
.modal-fade-leave-active {
transition: opacity 0.25s ease;
.modal-card {
transition: transform 0.25s ease;
}
}
.modal-fade-enter-from,
.modal-fade-leave-to {
opacity: 0;
.modal-card {
transform: scale(0.9);
} }
} }
</style> </style>
+217 -133
View File
@@ -3,53 +3,58 @@ import {ref, onMounted, watch} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useNavStore} from '@/store/nav' import {useNavStore} from '@/store/nav'
import {storeToRefs} from 'pinia' import {storeToRefs} from 'pinia'
import {Menu, ArrowDown, ArrowRight} from '@element-plus/icons-vue' import {Menu, ArrowDown} from '@element-plus/icons-vue'
const navStore = useNavStore() const navStore = useNavStore()
const {navIndex} = storeToRefs(navStore) const {navIndex} = storeToRefs(navStore)
const router = useRouter() const router = useRouter()
const sidebarVisible = ref(false)
const navList = ref([]) const navList = ref([])
const activeIndex = ref('/') const activeIndex = ref('/')
const expandedSubMenus = ref([]) const expandedMenuId = ref(null)
const toggleSidebar = () => {
sidebarVisible.value = !sidebarVisible.value
}
const closeSidebar = () => {
sidebarVisible.value = false
}
const toggleSubMenu = (navId) => {
const idx = expandedSubMenus.value.indexOf(navId)
if (idx > -1) {
expandedSubMenus.value.splice(idx, 1)
} else {
expandedSubMenus.value.push(navId)
}
}
const getTargetUrl = (nav) => { const getTargetUrl = (nav) => {
return nav.mobileUrl || nav.url return nav.mobileUrl || nav.url
} }
const isNavActive = (nav) => {
if (activeIndex.value === getTargetUrl(nav)) return true
if (nav.children?.length > 0) {
return nav.children.some((child) => activeIndex.value === getTargetUrl(child))
}
return false
}
const handleNavClick = (nav) => { const handleNavClick = (nav) => {
if (nav.hasChildren || nav.children?.length > 0) { if (nav.hasChildren || nav.children?.length > 0) {
toggleSubMenu(nav.id) expandedMenuId.value = expandedMenuId.value === nav.id ? null : nav.id
return return
} }
expandedMenuId.value = null
if (nav.open) { if (nav.open) {
window.open(nav.url) window.open(nav.url)
sidebarVisible.value = false
return return
} }
const targetUrl = getTargetUrl(nav) const targetUrl = getTargetUrl(nav)
navStore.changeNavIndex(targetUrl) navStore.changeNavIndex(targetUrl)
activeIndex.value = targetUrl activeIndex.value = targetUrl
router.push(targetUrl) router.push(targetUrl)
sidebarVisible.value = false }
const handleChildClick = (child) => {
expandedMenuId.value = null
if (child.open) {
window.open(child.url)
return
}
const targetUrl = getTargetUrl(child)
navStore.changeNavIndex(targetUrl)
activeIndex.value = targetUrl
router.push(targetUrl)
}
const closeDropdown = () => {
expandedMenuId.value = null
} }
watch( watch(
@@ -73,54 +78,55 @@ const toMIIF = () => {
<div class="mobile-layout"> <div class="mobile-layout">
<!-- ==================== 顶部 Header ==================== --> <!-- ==================== 顶部 Header ==================== -->
<div class="mobile-header"> <div class="mobile-header">
<el-icon class="header-menu-icon" :size="22" @click="toggleSidebar">
<Menu />
</el-icon>
<div class="header-logo" @click="router.push('/')"></div> <div class="header-logo" @click="router.push('/')"></div>
</div> </div>
<!-- ==================== 侧边==================== --> <!-- ==================== 横向滚动菜单==================== -->
<transition name="sidebar-slide"> <div class="menu-bar">
<div v-show="sidebarVisible" class="sidebar"> <div class="menu-scroll">
<div class="sidebar-nav">
<template v-for="nav in navList" :key="nav.id">
<!-- 有子菜单 -->
<div v-if="nav.hasChildren || nav.children?.length > 0" class="nav-group">
<div <div
class="nav-item nav-item--parent" v-for="nav in navList"
:class="{'nav-item--expanded': expandedSubMenus.includes(nav.id)}" :key="nav.id"
class="menu-item"
:class="{
'menu-item--active': isNavActive(nav),
'menu-item--expanded': expandedMenuId === nav.id,
}"
@click="handleNavClick(nav)" @click="handleNavClick(nav)"
> >
<span class="nav-label">{{ nav.label }}</span> <span class="menu-label">{{ nav.label }}</span>
<el-icon class="nav-arrow" :size="12"> <el-icon
<ArrowDown v-if="expandedSubMenus.includes(nav.id)" /> v-if="nav.hasChildren || nav.children?.length > 0"
<ArrowRight v-else /> class="menu-arrow"
:size="10"
:class="{'menu-arrow--up': expandedMenuId === nav.id}"
>
<ArrowDown />
</el-icon> </el-icon>
</div> </div>
<div v-show="expandedSubMenus.includes(nav.id)" class="nav-sub"> </div>
</div>
<!-- ==================== 子菜单下拉遮罩 ==================== -->
<transition name="fade">
<div v-if="expandedMenuId" class="dropdown-mask" @click="closeDropdown"></div>
</transition>
<!-- ==================== 子菜单下拉面板 ==================== -->
<transition name="dropdown">
<div v-if="expandedMenuId" class="menu-dropdown">
<div class="dropdown-scroll">
<div <div
v-for="child in nav.children" v-for="child in navList.find((n) => n.id === expandedMenuId)?.children || []"
:key="child.id" :key="child.id"
class="nav-item nav-item--child" class="dropdown-item"
:class="{'nav-item--active': activeIndex === getTargetUrl(child)}" :class="{'dropdown-item--active': activeIndex === getTargetUrl(child)}"
@click="handleNavClick(child)" @click="handleChildClick(child)"
> >
{{ child.label }} {{ child.label }}
</div> </div>
</div> </div>
</div> </div>
<!-- 无子菜单 -->
<div
v-else
class="nav-item"
:class="{'nav-item--active': activeIndex === getTargetUrl(nav)}"
@click="handleNavClick(nav)"
>
<span class="nav-label">{{ nav.label }}</span>
</div>
</template>
</div>
</div>
</transition> </transition>
<!-- ==================== Content 内容区域 ==================== --> <!-- ==================== Content 内容区域 ==================== -->
@@ -134,6 +140,20 @@ const toMIIF = () => {
<!-- ==================== Footer 底部 ==================== --> <!-- ==================== Footer 底部 ==================== -->
<div class="mobile-footer"> <div class="mobile-footer">
<div class="footer-qr">
<div class="qr-item">
<img src="/static/images/footer/QR_code.png" />
<div class="qr-label">企业微信</div>
</div>
<div class="qr-item">
<img src="/static/images/footer/mark.png" />
<div class="qr-label">市场联系人</div>
</div>
<div class="qr-item">
<img src="/static/images/footer/sx.png" />
<div class="qr-label">陕西联系人</div>
</div>
</div>
<div class="footer-info"> <div class="footer-info">
<span>Copyright © 2023.Rangu Technology Co.,Ltd.</span> <span>Copyright © 2023.Rangu Technology Co.,Ltd.</span>
<span>燃谷科技南京有限公司</span> <span>燃谷科技南京有限公司</span>
@@ -160,14 +180,14 @@ const toMIIF = () => {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; /* no */ width: 100%;
max-width: 100vw; max-width: 100vw;
height: 44px; /* no */ height: 44px;
background-color: $bg_color; background-color: $bg_color;
z-index: 110; z-index: 110;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 10px; /* no */ padding: 0 10px;
box-sizing: border-box; box-sizing: border-box;
.header-menu-icon { .header-menu-icon {
@@ -177,78 +197,137 @@ const toMIIF = () => {
} }
.header-logo { .header-logo {
width: 128px;
height: 44px;
background-image: url('/static/images/header/logo.png'); background-image: url('/static/images/header/logo.png');
background-size: contain; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
width: 100px;
height: 32px; /* no */
cursor: pointer;
flex-shrink: 0;
} }
} }
// ==================== 侧边栏遮罩层 ==================== // ==================== 横向滚动菜单栏 ====================
.sidebar-mask { .menu-bar {
position: fixed; position: fixed;
top: 0; top: 44px;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; max-width: 100vw;
background-color: rgba(0, 0, 0, 0.5); height: 40px;
z-index: 100; background-color: $bg_color;
z-index: 109;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
} }
.mask-fade-enter-active, .menu-scroll {
.mask-fade-leave-active { display: flex;
transition: opacity 0.3s ease; align-items: center;
height: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
padding: 0 10px;
white-space: nowrap;
&::-webkit-scrollbar {
display: none;
}
} }
.mask-fade-enter-from,
.mask-fade-leave-to { .menu-item {
display: inline-flex;
align-items: center;
flex-shrink: 0;
padding: 0 12px;
height: 100%;
color: #999999;
font-size: 14px;
cursor: pointer;
user-select: none;
transition: color 0.2s ease;
&:active {
color: $white;
}
&--active {
color: $white;
}
&--expanded {
color: $white;
}
.menu-label {
line-height: 1;
}
.menu-arrow {
margin-left: 4px;
color: #999999;
transition: transform 0.3s ease;
&--up {
transform: rotate(180deg);
color: $white;
}
}
}
// ==================== 子菜单下拉遮罩 ====================
.dropdown-mask {
position: fixed;
top: 84px;
left: 0;
width: 100%;
max-width: 100vw;
height: calc(100vh - 84px);
background-color: rgba(0, 0, 0, 0.4);
z-index: 107;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.25s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0; opacity: 0;
} }
// ==================== 侧边栏(浮动层) ==================== // ==================== 子菜单下拉面板 ====================
.sidebar { .menu-dropdown {
position: fixed; position: fixed;
top: 0; top: 84px;
left: 0; left: 0;
width: 160px; /* no */ width: 100%;
height: 100%; max-width: 100vw;
max-height: 240px;
background-color: $bg_color; background-color: $bg_color;
z-index: 105; z-index: 108;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.dropdown-scroll {
max-height: 240px;
overflow-y: auto; overflow-y: auto;
padding-top: 56px; /* no */ -webkit-overflow-scrolling: touch;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3); /* no */ padding: 4px 0;
} }
.sidebar-slide-enter-active, .dropdown-item {
.sidebar-slide-leave-active { padding: 12px 20px;
transition: transform 0.3s ease;
}
.sidebar-slide-enter-from,
.sidebar-slide-leave-to {
transform: translateX(-100%);
}
.sidebar-nav {
padding: 0;
}
.nav-group {
border-bottom: 1px solid rgba(255, 255, 255, 0.08); /* no */
}
.nav-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px; /* no */
cursor: pointer;
color: #999999; color: #999999;
font-size: 14px; font-size: 14px;
transition: all 0.2s ease; cursor: pointer;
user-select: none; user-select: none;
transition: all 0.2s ease;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
&:last-child {
border-bottom: none;
}
&:active { &:active {
background-color: rgba(255, 255, 255, 0.05); background-color: rgba(255, 255, 255, 0.05);
@@ -257,37 +336,23 @@ const toMIIF = () => {
&--active { &--active {
color: $white; color: $white;
} }
&--parent {
font-weight: 500;
}
&--expanded {
color: $white;
}
&--child {
padding-left: 32px; /* no */
font-size: 13px;
}
.nav-label {
flex: 1;
}
.nav-arrow {
color: #999999;
flex-shrink: 0;
}
} }
.nav-sub { .dropdown-enter-active,
overflow: hidden; .dropdown-leave-active {
transition:
transform 0.25s ease,
opacity 0.25s ease;
}
.dropdown-enter-from,
.dropdown-leave-to {
transform: translateY(-10px);
opacity: 0;
} }
// ==================== Content 内容区域 ==================== // ==================== Content 内容区域 ====================
.mobile-content { .mobile-content {
margin-top: 44px; /* no */ margin-top: 84px;
flex: 1; flex: 1;
width: 100%; width: 100%;
max-width: 100vw; max-width: 100vw;
@@ -298,11 +363,30 @@ const toMIIF = () => {
.mobile-footer { .mobile-footer {
width: 100%; width: 100%;
max-width: 100vw; max-width: 100vw;
padding: 20px 16px; /* no */ padding: 20px 16px;
box-sizing: border-box; box-sizing: border-box;
text-align: center; text-align: center;
background-color: $bg_color; background-color: $bg_color;
.footer-qr {
display: flex;
justify-content: center;
gap: 16px;
margin-bottom: 20px;
.qr-item {
img {
width: 80px;
height: 80px;
}
.qr-label {
margin-top: 6px;
font-size: 12px;
color: $white;
}
}
}
.footer-info { .footer-info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
+16 -21
View File
@@ -1,21 +1,14 @@
<script setup> <script setup>
import {ref, onMounted, getCurrentInstance} from 'vue' import {ref} from 'vue'
import Swiper from '@/components/Swiper/mobile/index.vue'
import Banner from '@/components/Banner/index.vue' import Banner from '@/components/Banner/index.vue'
const instance = getCurrentInstance()
const $fontSize = instance.appContext.config.globalProperties.$fontSize
const introduction = '燃谷科技成立于2023年,位于南京鼓楼万谷硅巷,秉承创新、质量和合作精神的低空领域技术创新公司,专注于低空安全监管、城市飞行服务和空间数据应用的企业。公司依托低空大数据、低空物联网、智能算法引擎、空间计算模型四个核心组件,自主研发数智底座,致力于物联网、空间计算领域,助力低空经济蓬勃发展。' const introduction = '燃谷科技成立于2023年,位于南京鼓楼万谷硅巷,秉承创新、质量和合作精神的低空领域技术创新公司,专注于低空安全监管、城市飞行服务和空间数据应用的企业。公司依托低空大数据、低空物联网、智能算法引擎、空间计算模型四个核心组件,自主研发数智底座,致力于物联网、空间计算领域,助力低空经济蓬勃发展。'
const currentPage = ref(1) const currentPage = ref(1)
const imgList = [ const imgList = [
{id: 1, width: 140, height: 90, list: ['main/1.png','main/2.png','main/3.png','main/4.png']}, {id: 1, list: ['main/1.png','main/2.png','main/3.png','main/4.png']},
{id: 2, width: 100, height: 145, list: ['main/5.png','main/6.png','main/7.png','main/8.png','main/9.png']}, {id: 2, list: ['main/5.png','main/6.png','main/7.png','main/8.png','main/9.png','main/10.png','main/11.png','main/12.png','main/13.png','main/14.png','main/15.png','main/16.png','main/17.png','main/18.png','main/19.png','main/20.png','main/21.png','main/22.png','main/23.png','main/24.png']},
{id: 3, width: 100, height: 145, list: ['main/10.png','main/11.png','main/12.png','main/13.png','main/14.png']},
{id: 4, width: 100, height: 145, list: ['main/15.png','main/16.png','main/17.png','main/18.png','main/19.png']},
{id: 5, width: 100, height: 145, list: ['main/20.png','main/21.png']},
] ]
</script> </script>
@@ -36,12 +29,9 @@ const imgList = [
<div class="section"> <div class="section">
<h2 class="section-title">资质证书</h2> <h2 class="section-title">资质证书</h2>
<div class="cert-grid"> <div class="cert-grid">
<div v-for="listItem in imgList" :key="listItem.id" class="cert-row" :class="{'cert-row--few': listItem.list.length <= 4}"> <div v-for="listItem in imgList" :key="listItem.id" class="cert-row">
<div v-for="(img, idx) in listItem.list" :key="idx"> <div v-for="(img, idx) in listItem.list" :key="idx" class="cert-item">
<img <img :src="`./static/images/${img}`" />
:style="{width: $fontSize(listItem.width) + 'px', height: $fontSize(listItem.height) + 'px', margin: '3px'}"
:src="`./static/images/${img}`"
/>
</div> </div>
</div> </div>
</div> </div>
@@ -74,12 +64,17 @@ const imgList = [
.cert-grid { .cert-grid {
.cert-row { .cert-row {
display: flex; display: grid;
justify-content: center; grid-template-columns: repeat(2, 1fr);
flex-wrap: wrap; gap: 8px;
margin-bottom: 8px;
}
.cert-item {
img {
width: 100%;
height: auto;
border-radius: 4px;
} }
.cert-row--few {
justify-content: center;
} }
} }
</style> </style>
+102 -18
View File
@@ -27,14 +27,29 @@ const transform = (items) => {
items.forEach((item) => { items.forEach((item) => {
const parts = item.Key.split('/') const parts = item.Key.split('/')
if (parts.length === 1) { if (parts.length === 1) {
root.children.push({name: parts[0], type: 'file', etag: item.ETag, size: item.Size, lastModified: item.LastModifiedDateTime, fullPath: item.Key}) root.children.push({
name: parts[0],
type: 'file',
etag: item.ETag,
size: item.Size,
lastModified: item.LastModifiedDateTime,
fullPath: item.Key,
})
} else { } else {
let currentParent = root, currentPath = '' let currentParent = root,
currentPath = ''
for (let i = 0; i < parts.length - 1; i++) { for (let i = 0; i < parts.length - 1; i++) {
currentPath += (currentPath ? '/' : '') + parts[i] currentPath += (currentPath ? '/' : '') + parts[i]
currentParent = getOrCreateFolder(currentParent, parts[i], currentPath + '/') currentParent = getOrCreateFolder(currentParent, parts[i], currentPath + '/')
} }
currentParent.children.push({name: parts[parts.length - 1], type: 'file', etag: item.ETag, size: item.Size, lastModified: item.LastModifiedDateTime, fullPath: item.Key}) currentParent.children.push({
name: parts[parts.length - 1],
type: 'file',
etag: item.ETag,
size: item.Size,
lastModified: item.LastModifiedDateTime,
fullPath: item.Key,
})
} }
}) })
return root.children return root.children
@@ -45,25 +60,36 @@ const treeProps = {children: 'children', label: 'name'}
const formatSize = (bytes) => { const formatSize = (bytes) => {
if (!bytes) return '' if (!bytes) return ''
const units = ['B', 'KB', 'MB', 'GB'] const units = ['B', 'KB', 'MB', 'GB']
let i = 0, size = bytes let i = 0,
while (size >= 1024 && i < units.length - 1) { size /= 1024; i++ } size = bytes
while (size >= 1024 && i < units.length - 1) {
size /= 1024
i++
}
return size.toFixed(2) + ' ' + units[i] return size.toFixed(2) + ' ' + units[i]
} }
const getList = () => { const getList = () => {
downloadList({recursive: true, version: true, prefix: '', bucket: ''}) downloadList({recursive: true, version: true, prefix: '', bucket: ''})
.then((res) => { if (res.code == 0 && res?.data?.length > 0) list.value = transform(res.data) }) .then((res) => {
if (res.code == 0 && res?.data?.length > 0) list.value = transform(res.data)
})
.catch(() => {}) .catch(() => {})
} }
const downloadFileFN = (data) => { const downloadFileFN = (data) => {
downloadFile({bucket: '', objname: data.fullPath, expiresMinutes: 60, isDownload: true}) downloadFile({bucket: '', objname: data.fullPath, expiresMinutes: 60, isDownload: true})
.then((res) => { if (res.code === 0 && res.data) window.open(res.data) }) .then((res) => {
if (res.code === 0 && res.data) window.open(res.data)
})
.catch(() => {}) .catch(() => {})
} }
const showMsg = () => ElMessage.warning('敬请期待!') const showMsg = () => ElMessage.warning('敬请期待!')
const openImg = (type) => { imgType.value = type; showImgType.value = true } const openImg = (type) => {
imgType.value = type
showImgType.value = true
}
</script> </script>
<template> <template>
@@ -90,13 +116,34 @@ const openImg = (type) => { imgType.value = type; showImgType.value = true }
<div class="section"> <div class="section">
<h2 class="section-title">文件下载</h2> <h2 class="section-title">文件下载</h2>
<div class="file-list"> <div class="file-list">
<el-tree v-if="list && list.length" :data="list" :props="treeProps" accordion node-key="name" default-expand-all> <el-tree
v-if="list && list.length"
:data="list"
:props="treeProps"
accordion
node-key="name"
default-expand-all
>
<template #default="{data}"> <template #default="{data}">
<div class="tree-node"> <div class="tree-node">
<span class="node-label">{{ data.name }}</span> <span class="node-label">{{ data.name }}</span>
<template v-if="data.type === 'file'"> <template v-if="data.type === 'file'">
<span class="file-size">{{ formatSize(data.size) }}</span> <span class="file-size">{{ formatSize(data.size) }}</span>
<svg class="download-icon" @click.stop="downloadFileFN(data)" viewBox="0 0 24 24" fill="none"><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> <svg class="download-icon" @click.stop="downloadFileFN(data)" viewBox="0 0 24 24" fill="none">
<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> </template>
</div> </div>
</template> </template>
@@ -110,10 +157,13 @@ const openImg = (type) => { imgType.value = type; showImgType.value = true }
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.page { width: 100%; } .page {
width: 100%;
}
.section { .section {
padding: 0 12px; padding: 0 12px;
margin-bottom: 20px;
.section-title { .section-title {
text-align: center; text-align: center;
font-size: 18px; font-size: 18px;
@@ -130,7 +180,11 @@ const openImg = (type) => { imgType.value = type; showImgType.value = true }
.app-card { .app-card {
width: 100px; width: 100px;
height: 120px; height: 120px;
img { width: 100%; height: 100%; object-fit: contain; } img {
width: 100%;
height: 100%;
object-fit: contain;
}
} }
} }
@@ -141,18 +195,48 @@ const openImg = (type) => { imgType.value = type; showImgType.value = true }
padding: 12px; padding: 12px;
box-sizing: border-box; box-sizing: border-box;
overflow-y: auto; overflow-y: auto;
.empty-tip { text-align: center; color: #999; font-size: 14px; padding: 30px 0; } .empty-tip {
text-align: center;
color: #999;
font-size: 14px;
padding: 30px 0;
}
} }
.tree-node { .tree-node {
display: flex; align-items: center; width: 100%; padding: 4px 0; gap: 6px; display: flex;
.node-label { flex: 1; font-size: 13px; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } align-items: center;
.file-size { font-size: 11px; color: #999; white-space: nowrap; min-width: 60px; text-align: right; } width: 100%;
.download-icon { width: 18px; height: 18px; flex-shrink: 0; cursor: pointer; } padding: 4px 0;
gap: 6px;
.node-label {
flex: 1;
font-size: 13px;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-size {
font-size: 11px;
color: #999;
white-space: nowrap;
min-width: 60px;
text-align: right;
}
.download-icon {
width: 18px;
height: 18px;
flex-shrink: 0;
cursor: pointer;
}
} }
::v-deep(.el-tree) { ::v-deep(.el-tree) {
background: transparent; background: transparent;
.el-tree-node__content { height: auto; padding: 4px 0; } .el-tree-node__content {
height: auto;
padding: 4px 0;
}
} }
</style> </style>
+15 -2
View File
@@ -2,8 +2,12 @@
import {ref, onMounted} from 'vue' import {ref, onMounted} from 'vue'
import Banner from '@/components/Banner/index.vue' import Banner from '@/components/Banner/index.vue'
const toCompany = () => { const toCompany = (type) => {
if (type === 'nj') {
window.open('https://www.amap.com/search?query=%E7%87%83%E8%B0%B7%E7%A7%91%E6%8A%80(%E5%8D%97%E4%BA%AC)%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8') window.open('https://www.amap.com/search?query=%E7%87%83%E8%B0%B7%E7%A7%91%E6%8A%80(%E5%8D%97%E4%BA%AC)%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8')
} else {
window.open('https://ditu.amap.com/search?query=%E9%99%95%E8%A5%BF%E7%9C%81%E8%A5%BF%E5%AE%89%E5%B8%82%E9%9B%81%E5%A1%94%E5%8C%BA%E8%A5%BF%E6%B2%A3%E8%B7%AF56%E5%8F%B7%E4%B8%87%E7%A7%91%E6%B1%87%E6%99%BA%E4%B8%AD%E5%BF%83')
}
} }
</script> </script>
@@ -20,7 +24,15 @@ const toCompany = () => {
<div class="info-item">邮箱company@rangutech.com</div> <div class="info-item">邮箱company@rangutech.com</div>
<div class="info-item">地址江苏省南京市鼓楼区万谷硅巷5F</div> <div class="info-item">地址江苏省南京市鼓楼区万谷硅巷5F</div>
</div> </div>
<img class="map-img" src="/static/images/link/map.png" @click="toCompany" /> <img class="map-img" src="/static/images/link/map.png" @click="toCompany('nj')" />
</div>
<div class="link-box">
<div class="info-list">
<div class="info-item name">燃谷科技陕西有限公司</div>
<div class="info-item">电话15009261000</div>
<div class="info-item">地址陕西省西安市雁塔区西沣路56号万科汇智中心2506</div>
</div>
<img class="map-img" src="/static/images/link/shanxi.png" @click="toCompany('sx')" />
</div> </div>
</div> </div>
</div> </div>
@@ -44,6 +56,7 @@ const toCompany = () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
margin-bottom: 24px;
.info-list { .info-list {
.info-item { .info-item {
+2 -1
View File
@@ -84,7 +84,8 @@ function toBack() {
// ============== 硬件区域 ============== // ============== 硬件区域 ==============
.hardware-section { .hardware-section {
.hardware-img { .hardware-img {
width: 100%; margin-left: 10%;
width: 80%;
height: auto; height: auto;
border-radius: 8px; border-radius: 8px;
} }