Browse Source

feat(game): add bag view and route

master
qinhan 1 month ago
parent
commit
90da13f8f0
  1. 5
      Build_God_Game/src/assets/images/bag.svg
  2. 6
      Build_God_Game/src/router/index.ts
  3. 292
      Build_God_Game/src/views/BagView.vue

5
Build_God_Game/src/assets/images/bag.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/>
<line x1="3" y1="6" x2="21" y2="6"/>
<path d="M16 10a4 4 0 0 1-8 0"/>
</svg>

After

Width:  |  Height:  |  Size: 304 B

6
Build_God_Game/src/router/index.ts

@ -51,6 +51,12 @@ const router = createRouter({
component: () => import('@/views/ScrapView.vue'),
meta: { requiresAuth: true }
},
{
path: '/bag',
name: 'bag',
component: () => import('@/views/BagView.vue'),
meta: { requiresAuth: true }
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',

292
Build_God_Game/src/views/BagView.vue

@ -0,0 +1,292 @@
<script setup lang="ts">
import { onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useBagStore } from '@/stores/bag'
import { useCharacterStore } from '@/stores/character'
import StarBorder from '@/components/StarBorder/StarBorder.vue'
import Particles from '@/components/Particles/Particles.vue'
import { ArrowLeft } from '@element-plus/icons-vue'
import bagIcon from '@/assets/images/bag.svg'
const router = useRouter()
const bagStore = useBagStore()
const characterStore = useCharacterStore()
const bagName = computed(() => bagStore.characterBag?.bagName || '背包')
const bagCapacity = computed(() => bagStore.characterBag?.bagCapacity || 0)
const usedCapacity = computed(() => bagStore.usedCapacity)
const itemTypeMap: Record<number, string> = {
1: '装备',
2: '丹药'
}
const rarityMap: Record<number, string> = {
1: '普通',
2: '稀有',
3: '史诗',
4: '传说'
}
const getItemTooltip = (item: { itemType: number; itemId: number; quantity: number; itemName: string | null; itemRarity: number | null }) => {
const type = itemTypeMap[item.itemType] || '未知'
const rarity = item.itemRarity ? rarityMap[item.itemRarity] || '' : ''
return `${item.itemName}\n类型: ${type}${rarity ? ` | 稀有度: ${rarity}` : ''}\n数量: ${item.quantity}`
}
const handleBack = () => {
router.push('/game')
}
onMounted(() => {
bagStore.loadBag()
})
</script>
<template>
<div class="bag-page">
<Particles :particle-count="30" :particle-colors="['#ffffff', '#cccccc']" class="particles-bg" />
<div class="bag-container">
<StarBorder as="div" color="#8b5cf6" speed="5s" :thickness="2" class="back-btn" @click="handleBack">
<div class="back-content">
<el-icon><ArrowLeft /></el-icon>
<span>返回</span>
</div>
</StarBorder>
<div class="bag-header">
<div class="header-left">
<img :src="bagIcon" class="header-icon" />
<h2>{{ bagName }}</h2>
</div>
<span class="capacity">{{ usedCapacity }} / {{ bagCapacity }}</span>
</div>
<div v-if="bagStore.loading" class="loading">
加载中...
</div>
<div v-else-if="bagStore.error" class="error">
{{ bagStore.error }}
</div>
<div v-else-if="bagStore.totalItems === 0" class="empty">
背包空空如也快去获取一些物品吧
</div>
<div v-else class="items-grid">
<el-tooltip
v-for="item in bagStore.paginatedItems"
:key="item.id"
:content="getItemTooltip(item)"
placement="top"
:show-after="300"
>
<div class="item-cell">
<div class="item-icon" :class="'rarity-' + (item.itemRarity || 1)">
{{ item.itemType === 1 ? '⚔️' : '💊' }}
</div>
<span class="item-name">{{ item.itemName }}</span>
<span v-if="item.quantity > 1" class="item-count">{{ item.quantity }}</span>
</div>
</el-tooltip>
</div>
<div v-if="bagStore.totalPages > 1" class="pagination">
<button
class="page-btn"
:disabled="bagStore.currentPage === 1"
@click="bagStore.prevPage()"
>
上一页
</button>
<span class="page-info">{{ bagStore.currentPage }} / {{ bagStore.totalPages }}</span>
<button
class="page-btn"
:disabled="bagStore.currentPage >= bagStore.totalPages"
@click="bagStore.nextPage()"
>
下一页
</button>
</div>
</div>
</div>
</template>
<style scoped>
.bag-page {
min-height: 100vh;
background: #000000;
padding: 20px;
position: relative;
overflow: hidden;
}
.particles-bg {
position: fixed !important;
top: 0;
left: 0;
width: 100% !important;
height: 100% !important;
}
.bag-container {
max-width: 480px;
margin: 0 auto;
position: relative;
z-index: 10;
}
.back-btn {
margin-bottom: 20px;
display: inline-block;
}
.back-content {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
cursor: pointer;
color: #cccccc;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 8px;
}
.bag-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
padding: 16px 20px;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
}
.header-left {
display: flex;
align-items: center;
gap: 12px;
}
.header-icon {
width: 28px;
height: 28px;
object-fit: contain;
}
.bag-header h2 {
margin: 0;
color: #ffffff;
font-size: 1.25rem;
font-weight: 500;
}
.capacity {
color: #888888;
font-size: 0.9rem;
}
.loading, .error, .empty {
text-align: center;
padding: 40px;
color: #888888;
}
.error {
color: #ff4444;
}
.items-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-bottom: 24px;
}
.item-cell {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 16px 8px;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.item-cell:hover {
background: rgba(255, 255, 255, 0.06);
border-color: rgba(255, 255, 255, 0.15);
}
.item-icon {
font-size: 2rem;
margin-bottom: 8px;
}
.item-name {
color: #cccccc;
font-size: 0.75rem;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
.item-count {
position: absolute;
top: 4px;
right: 4px;
background: rgba(139, 92, 246, 0.8);
color: #ffffff;
font-size: 0.65rem;
padding: 2px 6px;
border-radius: 8px;
min-width: 18px;
text-align: center;
}
.rarity-1 { filter: grayscale(0.3); }
.rarity-2 { filter: hue-rotate(80deg) saturate(1.5); }
.rarity-3 { filter: hue-rotate(200deg) saturate(2); }
.rarity-4 { filter: hue-rotate(-30deg) saturate(2) brightness(1.2); }
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
}
.page-btn {
padding: 10px 20px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: #cccccc;
cursor: pointer;
transition: all 0.2s ease;
}
.page-btn:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.1);
}
.page-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.page-info {
color: #888888;
font-size: 0.9rem;
}
</style>
Loading…
Cancel
Save