新增商品编号搜索

This commit is contained in:
yml
2026-06-08 19:44:07 +08:00
parent c4420dc753
commit 38d7469965
15 changed files with 191 additions and 6 deletions
@@ -4,6 +4,7 @@ import type { ListingReviewStatus, ListingStatus } from '@/shared/types/status'
export interface Listing {
id: number
listing_no: string
account_id: number
owner_id: number
owner_phone?: string
@@ -7,6 +7,7 @@ import {
getCoinWan,
getDailyLoss,
getListingDisplayPrice,
formatListingCode,
getListingResources,
getListingTitle,
getLoginMethod,
@@ -100,7 +101,10 @@ function formatStatNumber(value: number) {
<div class="card-details">
<div class="card-title-row">
<h3>{{ getListingTitle(listing) }}</h3>
<span v-if="dailyLoss" class="daily-loss">日耗 {{ dailyLoss }}</span>
<div class="card-title-meta">
<span class="listing-no">编号 {{ formatListingCode(listing) }}</span>
<span v-if="dailyLoss" class="daily-loss">日耗 {{ dailyLoss }}</span>
</div>
</div>
<div class="info-panel">
@@ -252,6 +256,23 @@ function formatStatNumber(value: number) {
white-space: nowrap;
}
.card-title-meta {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
gap: 8px;
}
.listing-no {
padding: 4px 10px;
border: 1px solid #dbeafe;
border-radius: 6px;
background: #eff6ff;
font-size: 12px;
font-weight: 800;
color: #2563eb;
}
.daily-loss {
flex: 0 0 auto;
padding: 4px 10px;
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
defaultHomeAnnouncements,
defaultHomeBanners,
@@ -24,6 +25,8 @@ const banners = ref<HomeBannerSlide[]>(defaultHomeBanners)
const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
const sortBy = ref('recommended')
const activeZone = ref('all')
const route = useRoute()
const router = useRouter()
const {
filters,
@@ -40,6 +43,8 @@ const {
computed(() => listings.value)
)
filters.keyword = routeKeyword()
const {
loading,
loadingMore,
@@ -50,6 +55,13 @@ const {
zoneCount,
} = useListingQuery(filters, sortBy, activeZone)
watch(
() => route.query.keyword,
() => {
filters.keyword = routeKeyword()
}
)
const statCards = computed(() => [
{ label: '可租账号', value: `${totalListings.value}`, hint: '当前筛选结果' },
{
@@ -127,6 +139,19 @@ function handleResetFilters() {
resetFilters()
activeZone.value = 'all'
sortBy.value = 'recommended'
router.replace({
path: '/',
query: {
...route.query,
keyword: undefined,
},
})
}
function routeKeyword() {
const keyword = route.query.keyword
if (Array.isArray(keyword)) return String(keyword[0] || '')
return typeof keyword === 'string' ? keyword : ''
}
loadHome()
@@ -323,6 +323,18 @@
white-space: nowrap;
}
.mobile-listing-no {
display: inline-flex;
width: fit-content;
margin-top: 6px;
padding: 3px 7px;
border-radius: 999px;
background: #eff6ff;
color: #2563eb;
font-size: 11px;
font-weight: 800;
}
.card-subtitle {
margin: 6px 0 10px;
color: #64748b;
@@ -26,6 +26,7 @@ import {
getListingDisplayPrice,
getListingSubtitle,
getListingTitle,
formatListingCode,
getLoginMethod,
getServerRegion,
hasAcceleratedSaleRatio,
@@ -377,7 +378,7 @@ function uniqueOptions(values: string[]) {
<van-search
v-model="searchValue"
shape="round"
placeholder="搜区服 / 段位"
placeholder="搜编号 / 区服 / 段位"
class="home-search"
/>
<button
@@ -510,6 +511,7 @@ function uniqueOptions(values: string[]) {
<div class="card-title-row">
<h2>{{ getListingTitle(item) }}</h2>
</div>
<div class="mobile-listing-no">编号 {{ formatListingCode(item) }}</div>
<p class="card-subtitle">{{ getListingSubtitle(item) }}</p>
<div class="card-badges-row">
<span class="server-badge">{{ getServerRegion(item) }}</span>
+36 -3
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
ArrowDown,
@@ -28,6 +28,7 @@ import { useSessionStore } from '@/stores/session'
const session = useSessionStore()
const router = useRouter()
const route = useRoute()
const navItems = [
{ label: '首页', to: '/', icon: House },
@@ -50,6 +51,7 @@ const sellerServiceItems = [
const showUserDropdown = ref(false)
const supportLoading = ref(false)
const topSearchKeyword = ref('')
const realnameBadge = computed(() => {
switch (session.realnameStatus) {
@@ -64,6 +66,33 @@ const realnameBadge = computed(() => {
}
})
watch(
() => [route.path, route.query.keyword],
() => {
if (route.path !== '/') return
topSearchKeyword.value = normalizeRouteKeyword(route.query.keyword)
},
{ immediate: true }
)
function normalizeRouteKeyword(value: unknown) {
if (Array.isArray(value)) return String(value[0] || '')
return typeof value === 'string' ? value : ''
}
function handleTopSearchInput(event: Event) {
const value = (event.target as HTMLInputElement).value
topSearchKeyword.value = value
const keyword = value.trim()
router.replace({
path: '/',
query: {
...route.query,
keyword: keyword || undefined,
},
})
}
function handleLogout() {
session.logout()
showUserDropdown.value = false
@@ -108,7 +137,11 @@ async function handleSupportClick() {
<div class="pc-search">
<el-icon><Search /></el-icon>
<input placeholder="搜索区服 / 段位 / 哈夫币数量 / 皮肤" />
<input
:value="topSearchKeyword"
placeholder="搜索编号 / 区服 / 段位 / 哈夫币数量 / 皮肤"
@input="handleTopSearchInput"
/>
</div>
<div class="pc-user-actions">
@@ -23,6 +23,7 @@ export function getCoinM(item: Listing) {
}
export function formatListingCode(item: Listing) {
if (item.listing_no) return item.listing_no
return `SP${String(item.id).padStart(6, '0')}`
}
+1
View File
@@ -9,6 +9,7 @@
.filter-header {
display: flex;
gap: 16px;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
+1
View File
@@ -23,6 +23,7 @@ export function getCoinM(item: Listing) {
}
export function formatListingCode(item: Listing) {
if (item.listing_no) return item.listing_no
return `SP${String(item.id).padStart(6, '0')}`
}
+1
View File
@@ -2,6 +2,7 @@
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": true,
"types": ["vite/client"],
"paths": {
"@/*": ["./src/*"]