贯通商品编号全流程
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
assetRegions,
|
||||
formatEstimatedRentalDuration,
|
||||
formatHafCoinM,
|
||||
formatListingCode,
|
||||
formatRatio,
|
||||
getCoinWan,
|
||||
getDailyLoss,
|
||||
@@ -248,6 +249,16 @@ async function submitOrder() {
|
||||
}
|
||||
}
|
||||
|
||||
async function copyListingCode() {
|
||||
if (!listing.value) return
|
||||
try {
|
||||
await navigator.clipboard.writeText(formatListingCode(listing.value))
|
||||
ElMessage.success('商品编号已复制')
|
||||
} catch {
|
||||
ElMessage.error('复制失败')
|
||||
}
|
||||
}
|
||||
|
||||
function handleAgreementScroll(type: 'virtual' | 'renter') {
|
||||
updateAgreementReadState(type)
|
||||
}
|
||||
@@ -336,6 +347,9 @@ function listingPrice(item: Listing) {
|
||||
<span v-if="getLoginMethod(listing)">{{ getLoginMethod(listing) }}</span>
|
||||
<span v-if="listing.rank_level">{{ listing.rank_level }}</span>
|
||||
</div>
|
||||
<button class="detail-code-chip" type="button" @click="copyListingCode">
|
||||
编号 {{ formatListingCode(listing) }}
|
||||
</button>
|
||||
<h1>{{ getListingTitle(listing) }}</h1>
|
||||
<p>{{ getListingSubtitle(listing) }}</p>
|
||||
</div>
|
||||
@@ -606,6 +620,19 @@ function listingPrice(item: Listing) {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.detail-code-chip {
|
||||
width: fit-content;
|
||||
margin-top: 10px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid rgba(147, 197, 253, 0.6);
|
||||
border-radius: 999px;
|
||||
background: rgba(239, 246, 255, 0.92);
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.detail-hero-overlay h1 {
|
||||
margin: 0;
|
||||
color: #ffffff;
|
||||
|
||||
@@ -13,8 +13,6 @@ import {
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import {
|
||||
assetRegions,
|
||||
formatHafCoinM,
|
||||
getCoinM,
|
||||
getCoinWan,
|
||||
getListingChips,
|
||||
@@ -102,7 +100,6 @@ type RangePresets = Record<string, Array<{ label: string; min: string; max: stri
|
||||
|
||||
const selectedFilters = ref<SelectedFilters>({})
|
||||
const rangeFilters = ref<RangeFilters>({})
|
||||
const searchValue = ref('')
|
||||
const sortOpen = ref(false)
|
||||
const filterOpen = ref(false)
|
||||
|
||||
@@ -306,7 +303,6 @@ function toggleSortPanel() {
|
||||
function clearFilters() {
|
||||
selectedFilters.value = {}
|
||||
rangeFilters.value = {}
|
||||
searchValue.value = ''
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -324,12 +320,7 @@ const activeFilterCount = computed(() => {
|
||||
})
|
||||
|
||||
const filteredListings = computed(() => {
|
||||
const keyword = searchValue.value.trim().toLowerCase()
|
||||
const filtered = listings.value.filter(item => {
|
||||
if (!matchesFilters(item)) return false
|
||||
if (!keyword) return true
|
||||
return searchText(item).includes(keyword)
|
||||
})
|
||||
const filtered = listings.value.filter(item => matchesFilters(item))
|
||||
return sortListings(filtered)
|
||||
})
|
||||
|
||||
@@ -371,24 +362,6 @@ function inRange(value: number, range: { min: string; max: string }) {
|
||||
return true
|
||||
}
|
||||
|
||||
function searchText(item: Listing) {
|
||||
return [
|
||||
item.title,
|
||||
item.description,
|
||||
getServerRegion(item),
|
||||
getLoginMethod(item),
|
||||
item.rank_level,
|
||||
readAssetString(item, 'season_insurance'),
|
||||
readAssetString(item, 'stamina_level'),
|
||||
readAssetString(item, 'load_level'),
|
||||
formatHafCoinM(getCoinWan(item)),
|
||||
assetRegions(item).join(' '),
|
||||
...publishOptions.value.skin_groups.map(group => getSkinGroup(item, group.key).join(' ')),
|
||||
]
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
function sortListings(items: Listing[]) {
|
||||
const sorted = [...items]
|
||||
if (sortBy.value === 'comprehensive') return sorted
|
||||
@@ -438,19 +411,8 @@ function parseQuantityUnit(price: string) {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 搜索 + 排序 + 筛选入口 -->
|
||||
<!-- 排序 + 筛选入口,搜索统一保留在首页顶部 -->
|
||||
<div class="toolbar">
|
||||
<div class="search-box">
|
||||
<svg class="search-icon" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<input v-model="searchValue" placeholder="搜区服 / 段位 / 哈夫币数量" />
|
||||
</div>
|
||||
|
||||
<button type="button" class="toolbar-btn sort-btn" @click="toggleSortPanel">
|
||||
<span>{{ activeSortLabel }}</span>
|
||||
<svg
|
||||
@@ -748,7 +710,7 @@ function parseQuantityUnit(price: string) {
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* 工具栏:搜索 + 排序 + 筛选 */
|
||||
/* 工具栏:排序 + 筛选 */
|
||||
/* ================================================================== */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
@@ -757,47 +719,6 @@ function parseQuantityUnit(price: string) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 0 1 360px;
|
||||
height: 38px;
|
||||
padding: 0 12px;
|
||||
border-radius: 10px;
|
||||
background: #f4f6f8;
|
||||
border: 1px solid transparent;
|
||||
transition:
|
||||
border-color 0.15s,
|
||||
box-shadow 0.15s;
|
||||
}
|
||||
|
||||
.search-box:focus-within {
|
||||
border-color: #1477ff;
|
||||
box-shadow: 0 0 0 3px rgba(20, 119, 255, 0.1);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #a0aab6;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: #17233d;
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box input::placeholder {
|
||||
color: #a0aab6;
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -15,6 +15,7 @@ import { formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
assetRegions,
|
||||
formatHafCoinM,
|
||||
formatListingCode,
|
||||
formatRatio,
|
||||
getCoinWan,
|
||||
getDailyLoss,
|
||||
@@ -257,6 +258,16 @@ function readError(error: unknown, fallback: string) {
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
async function copyListingCode() {
|
||||
if (!listing.value) return
|
||||
try {
|
||||
await navigator.clipboard.writeText(formatListingCode(listing.value))
|
||||
showToast({ message: '商品编号已复制', icon: 'passed' })
|
||||
} catch {
|
||||
showToast({ message: '复制失败', icon: 'cross' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -309,6 +320,9 @@ function readError(error: unknown, fallback: string) {
|
||||
</van-tag>
|
||||
<van-tag v-if="listing.rank_level" plain size="medium">{{ listing.rank_level }}</van-tag>
|
||||
</div>
|
||||
<button class="mobile-code-chip" type="button" @click="copyListingCode">
|
||||
编号 {{ formatListingCode(listing) }}
|
||||
</button>
|
||||
<h2 class="detail-title">{{ getListingTitle(listing) }}</h2>
|
||||
<p class="detail-desc">{{ getListingSubtitle(listing) }}</p>
|
||||
</div>
|
||||
@@ -601,6 +615,17 @@ function readError(error: unknown, fallback: string) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mobile-code-chip {
|
||||
margin-bottom: 8px;
|
||||
padding: 4px 9px;
|
||||
border: 1px solid #dbeafe;
|
||||
border-radius: 999px;
|
||||
background: #eff6ff;
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
margin: 0 0 6px;
|
||||
font-size: 20px;
|
||||
|
||||
Reference in New Issue
Block a user