地形图列表
This commit is contained in:
parent
4ac36abfe3
commit
8f30b943a7
@ -76,6 +76,11 @@ const routes = [
|
|||||||
path: 'editors-maps',
|
path: 'editors-maps',
|
||||||
name: 'EditorsMaps',
|
name: 'EditorsMaps',
|
||||||
component: () => import('@/views/index/EditorsMaps.vue')
|
component: () => import('@/views/index/EditorsMaps.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'terrain',
|
||||||
|
name: 'Terrain',
|
||||||
|
component: () => import('@/views/index/TerrainList.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -82,6 +82,7 @@ onUnmounted(() => {
|
|||||||
<router-link to="/maps" class="nav-link">最近上传地图</router-link>
|
<router-link to="/maps" class="nav-link">最近上传地图</router-link>
|
||||||
<router-link to="/weekly" class="nav-link">热门下载地图</router-link>
|
<router-link to="/weekly" class="nav-link">热门下载地图</router-link>
|
||||||
<router-link to="/author" class="nav-link">活跃作者推荐</router-link>
|
<router-link to="/author" class="nav-link">活跃作者推荐</router-link>
|
||||||
|
<router-link to="/terrain" class="nav-link">地形图列表</router-link>
|
||||||
<router-link v-if="isLoggedIn" to="/weapon-match" class="nav-link">Weapon 匹配</router-link>
|
<router-link v-if="isLoggedIn" to="/weapon-match" class="nav-link">Weapon 匹配</router-link>
|
||||||
<router-link v-if="isLoggedIn" to="/competition" class="nav-link">赛程信息</router-link>
|
<router-link v-if="isLoggedIn" to="/competition" class="nav-link">赛程信息</router-link>
|
||||||
<router-link v-if="isLoggedIn" to="/demands" class="nav-link">办事大厅</router-link>
|
<router-link v-if="isLoggedIn" to="/demands" class="nav-link">办事大厅</router-link>
|
||||||
|
378
src/views/index/TerrainList.vue
Normal file
378
src/views/index/TerrainList.vue
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
<template>
|
||||||
|
<div class="map-detail">
|
||||||
|
<div class="map-header">
|
||||||
|
<h1>地形图列表</h1>
|
||||||
|
<div class="filter-controls">
|
||||||
|
<label for="category-select">分类:</label>
|
||||||
|
<select v-model="selectedCategory" id="category-select" @change="currentPage = 1">
|
||||||
|
<option v-for="category in categoryList" :key="category" :value="category">
|
||||||
|
{{ category }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<button class="pagination-btn" @click="prevPage" :disabled="currentPage === 1">
|
||||||
|
< 上一页
|
||||||
|
</button>
|
||||||
|
<span class="page-info">第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span>
|
||||||
|
<button class="pagination-btn" @click="nextPage" :disabled="currentPage === totalPages">
|
||||||
|
下一页 >
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="loading">加载中...</div>
|
||||||
|
|
||||||
|
<div v-if="error" class="error">
|
||||||
|
加载失败: {{ error }}
|
||||||
|
<button @click="fetchTerrainList" class="back-btn">重试</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="map-content">
|
||||||
|
<div v-if="filteredTerrainsByCategory.length > 0" class="terrain-grid">
|
||||||
|
<div v-for="terrain in paginatedTerrains" :key="terrain.key" class="terrain-item">
|
||||||
|
<div class="map-image">
|
||||||
|
<img :src="getImageUrl(terrain.key)" :alt="'地形图 ' + terrain.key" />
|
||||||
|
<div class="image-overlay">
|
||||||
|
<span class="image-name">{{ terrain.key }}</span>
|
||||||
|
<a :href="getImageUrl(terrain.key)" class="download-link" download title="下载">
|
||||||
|
<svg viewBox="0 0 24 24" width="20" height="20">
|
||||||
|
<path fill="white" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="!loading" class="no-data">
|
||||||
|
当前分类下没有可用的地形图数据
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination-controls bottom">
|
||||||
|
<button class="pagination-btn" @click="prevPage" :disabled="currentPage === 1">
|
||||||
|
< 上一页
|
||||||
|
</button>
|
||||||
|
<span class="page-info">第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span>
|
||||||
|
<button class="pagination-btn" @click="nextPage" :disabled="currentPage === totalPages">
|
||||||
|
下一页 >
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TerrainList',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
terrains: [],
|
||||||
|
filteredTerrains: [],
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
currentPage: 1,
|
||||||
|
itemsPerPage: 100,
|
||||||
|
apiBaseUrl: 'http://zybdatasupport.online:8000',
|
||||||
|
categoryList: [],
|
||||||
|
selectedCategory: '全部',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredTerrainsByCategory() {
|
||||||
|
if (this.selectedCategory === '全部') {
|
||||||
|
return this.filteredTerrains;
|
||||||
|
}
|
||||||
|
return this.filteredTerrains.filter(item =>
|
||||||
|
item.key.toLowerCase().startsWith(this.selectedCategory + '_')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
totalPages() {
|
||||||
|
return Math.ceil(this.filteredTerrainsByCategory.length / this.itemsPerPage);
|
||||||
|
},
|
||||||
|
paginatedTerrains() {
|
||||||
|
const start = (this.currentPage - 1) * this.itemsPerPage;
|
||||||
|
const end = start + this.itemsPerPage;
|
||||||
|
return this.filteredTerrainsByCategory.slice(start, end);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchTerrainList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchTerrainList() {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.apiBaseUrl}/terrain`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('获取地形图列表失败');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
this.terrains = data;
|
||||||
|
this.filteredTerrains = data.filter(item => this.isImageFile(item.key));
|
||||||
|
this.extractCategories();
|
||||||
|
this.currentPage = 1;
|
||||||
|
} catch (err) {
|
||||||
|
this.error = err.message;
|
||||||
|
console.error('Error fetching terrain list:', err);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
extractCategories() {
|
||||||
|
const categories = new Set();
|
||||||
|
this.filteredTerrains.forEach(item => {
|
||||||
|
const prefix = item.key.split('_')[0].toLowerCase();
|
||||||
|
categories.add(prefix);
|
||||||
|
});
|
||||||
|
this.categoryList = ['全部', ...Array.from(categories).sort()];
|
||||||
|
},
|
||||||
|
|
||||||
|
getImageUrl(key) {
|
||||||
|
return `http://dataimg-1307694021.cos.ap-beijing.myqcloud.com/Terrain/jpg/${key}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
isImageFile(key) {
|
||||||
|
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
|
||||||
|
const lowerKey = key.toLowerCase();
|
||||||
|
return imageExtensions.some(ext => lowerKey.endsWith(ext));
|
||||||
|
},
|
||||||
|
|
||||||
|
nextPage() {
|
||||||
|
if (this.currentPage < this.totalPages) {
|
||||||
|
this.currentPage++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
prevPage() {
|
||||||
|
if (this.currentPage > 1) {
|
||||||
|
this.currentPage--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.map-detail {
|
||||||
|
padding: 15px;
|
||||||
|
max-width: 1800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading, .error, .no-data {
|
||||||
|
padding: 15px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #d32f2f;
|
||||||
|
background-color: #ffebee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
color: #757575;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terrain-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(10, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terrain-item {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terrain-item:hover {
|
||||||
|
transform: scale(1.03);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-image {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-overlay {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: linear-gradient(transparent, rgba(0,0,0,0.7));
|
||||||
|
padding: 8px;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terrain-item:hover .image-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-name {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-link {
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-link:hover {
|
||||||
|
color: #4fc3f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls.bottom {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:hover:not(:disabled) {
|
||||||
|
background: #e9ecef;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-info {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn:hover {
|
||||||
|
background: #e9ecef;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1800px) {
|
||||||
|
.terrain-grid {
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1400px) {
|
||||||
|
.terrain-grid {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.terrain-grid {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.terrain-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.terrain-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user