feat: P2阶段完成 - listings和auth模块迁移
## P2.1: 商品浏览模块(listings)✅ ### 完整迁移(23个文件) - API: listings.ts, listingOptions.ts, homeConfig.ts - Views: 5个页面(HomeView, ListingsView, ListingDetailView + 移动端2个) - Composables: 3个(useHomeFilters, useFilterOptions, useListingQuery) - Components: 9个(ListingCard, 各种过滤器组件) - Tests: 2个测试文件 **功能:** - 首页浏览、商品列表、详情查看 - 高级筛选(服务器、等级、哈夫币、皮肤等) - 排序和分区功能 - 横幅、公告、统计展示 **技术改进:** - 更新所有导入路径到 @/shared/ - 建立清晰的模块导出 --- ## P2.2: 用户认证模块(auth)✅ ### 完整迁移(12个文件) - API: auth.ts, realname.ts, notifications.ts - Views: 8个页面(登录、注册、个人资料、实名认证、通知 + 移动端) - 模块导出 **功能:** - 用户注册、登录、Token管理 - 实名认证、风险检查 - 个人资料编辑、头像上传 - 消息/通知中心 **技术改进:** - 统一 API 导入路径 - 类型安全增强 --- ## 里程碑 🎉 **P2 阶段完成!** **累计完成:** 6个模块 - ✅ P0: shared(基础设施)- 22个文件 - ✅ P1: wallet, chats, orders - 24个文件 - ✅ P2: listings, auth - 35个文件 **总计:** 81个文件已迁移 **剩余:** P3阶段(seller, disputes, admin)+ 清理工作 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
f415832c19
commit
405abfa4f7
@@ -0,0 +1,262 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { ElEmpty } from 'element-plus'
|
||||
import {
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/api/homeConfig'
|
||||
import {
|
||||
emptyListingPublishOptions,
|
||||
type ListingPublishOptions,
|
||||
} from '@/api/listingOptions'
|
||||
import { useHomeFilters } from '@/composables/home/useHomeFilters'
|
||||
import { useListingQuery } from '@/composables/home/useListingQuery'
|
||||
import HomeAnnouncement from './components/HomeAnnouncement.vue'
|
||||
import HomeBanner from './components/HomeBanner.vue'
|
||||
import HomeStats from './components/HomeStats.vue'
|
||||
import HomeFilters from './components/HomeFilters.vue'
|
||||
import HomeZonesAndSort from './components/HomeZonesAndSort.vue'
|
||||
import ListingCard from './components/ListingCard.vue'
|
||||
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const banners = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
|
||||
const sortBy = ref('recommended')
|
||||
const activeZone = ref('all')
|
||||
|
||||
const {
|
||||
filters,
|
||||
activeFilterPopover,
|
||||
regionOptions,
|
||||
loginMethodOptions,
|
||||
skinFilterGroups,
|
||||
skinChipLabel,
|
||||
resetFilters,
|
||||
setFilterPopover,
|
||||
closeFilterPopover,
|
||||
} = useHomeFilters(publishOptions, computed(() => listings.value))
|
||||
|
||||
const {
|
||||
loading,
|
||||
loadingMore,
|
||||
listings,
|
||||
totalListings,
|
||||
zoneCounts,
|
||||
hasMoreListings,
|
||||
loadListingsPage,
|
||||
zoneCount,
|
||||
} = useListingQuery(filters, sortBy, activeZone)
|
||||
|
||||
const statCards = computed(() => [
|
||||
{ label: '可租账号', value: `${totalListings.value}`, hint: '当前筛选结果' },
|
||||
{
|
||||
label: '高哈夫币',
|
||||
value: `${zoneCount('highCoin')}`,
|
||||
hint: '100M 以上',
|
||||
},
|
||||
{
|
||||
label: '账密登录',
|
||||
value: `${zoneCount('password')}`,
|
||||
hint: '交接更快',
|
||||
},
|
||||
])
|
||||
|
||||
const zoneOptions = computed(() => [
|
||||
{
|
||||
key: 'all',
|
||||
label: '全部专区',
|
||||
hint: '当前可租账号',
|
||||
count: zoneCount('all'),
|
||||
},
|
||||
{
|
||||
key: 'sale',
|
||||
label: '特惠专区',
|
||||
hint: '价格更划算',
|
||||
count: zoneCount('sale'),
|
||||
},
|
||||
{
|
||||
key: 'gift',
|
||||
label: '赠送专区',
|
||||
hint: '含赠送物品',
|
||||
count: zoneCount('gift'),
|
||||
},
|
||||
{
|
||||
key: 'night',
|
||||
label: '夜间专区',
|
||||
hint: '夜间也好上号',
|
||||
count: zoneCount('night'),
|
||||
},
|
||||
{
|
||||
key: 'password',
|
||||
label: '账密专区',
|
||||
hint: '交接更快',
|
||||
count: zoneCount('password'),
|
||||
},
|
||||
{
|
||||
key: 'highCoin',
|
||||
label: '高币专区',
|
||||
hint: '100M 以上',
|
||||
count: zoneCount('highCoin'),
|
||||
},
|
||||
])
|
||||
|
||||
async function loadHome() {
|
||||
loading.value = true
|
||||
try {
|
||||
const [, config] = await Promise.all([
|
||||
loadListingsPage(true),
|
||||
fetchMobileHomeConfig(),
|
||||
])
|
||||
announcements.value = config.announcements
|
||||
banners.value = config.banners
|
||||
publishOptions.value = config.publish_options
|
||||
} catch {
|
||||
announcements.value = defaultHomeAnnouncements
|
||||
banners.value = defaultHomeBanners
|
||||
publishOptions.value = emptyListingPublishOptions
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function updateFilters(partial: Partial<typeof filters>) {
|
||||
Object.assign(filters, partial)
|
||||
}
|
||||
|
||||
function handleResetFilters() {
|
||||
resetFilters()
|
||||
activeZone.value = 'all'
|
||||
sortBy.value = 'recommended'
|
||||
}
|
||||
|
||||
loadHome()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="pc-home-redesign">
|
||||
<HomeAnnouncement :announcements="announcements" />
|
||||
|
||||
<main class="home-content">
|
||||
<div class="hero-section">
|
||||
<HomeBanner :banners="banners" />
|
||||
<HomeStats :stats="statCards" />
|
||||
</div>
|
||||
|
||||
<HomeFilters
|
||||
:filters="filters"
|
||||
:total-listings="totalListings"
|
||||
:publish-options="publishOptions"
|
||||
:region-options="regionOptions"
|
||||
:login-method-options="loginMethodOptions"
|
||||
:skin-filter-groups="skinFilterGroups"
|
||||
:skin-chip-label="skinChipLabel"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
@update:filters="updateFilters"
|
||||
@reset="handleResetFilters"
|
||||
@set-filter-popover="setFilterPopover"
|
||||
@close-filter-popover="closeFilterPopover"
|
||||
/>
|
||||
|
||||
<div class="list-head">
|
||||
<div class="zone-head">
|
||||
<p class="eyebrow">Account Zone</p>
|
||||
<h2>账号专区</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HomeZonesAndSort
|
||||
:zones="zoneOptions"
|
||||
:active-zone="activeZone"
|
||||
:sort-by="sortBy"
|
||||
@update:active-zone="activeZone = $event"
|
||||
@update:sort-by="sortBy = $event"
|
||||
/>
|
||||
|
||||
<el-empty
|
||||
v-if="!loading && listings.length === 0"
|
||||
description="没有符合条件的账号"
|
||||
/>
|
||||
<div v-else v-loading="loading" class="enhanced-desktop-list">
|
||||
<ListingCard
|
||||
v-for="item in listings"
|
||||
:key="item.id"
|
||||
:listing="item"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && listings.length" class="infinite-load-state">
|
||||
<span v-if="loadingMore">正在加载更多账号...</span>
|
||||
<span v-else-if="!hasMoreListings">已经到底了</span>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pc-home-redesign {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
max-width: 1720px;
|
||||
min-width: 0;
|
||||
margin: 0 auto;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
.home-content {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.infinite-load-state {
|
||||
padding: 6px 0 18px;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-section {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 320px;
|
||||
gap: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.list-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.zone-head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: #ff6a00;
|
||||
}
|
||||
|
||||
.zone-head h2 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
color: #17233d;
|
||||
}
|
||||
|
||||
.enhanced-desktop-list {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user