feat(home): 新增AWM子弹区间筛选,重排快速筛选为两列布局(租金移出高级区,登录方式固定右列)
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
import { Refresh } from '@element-plus/icons-vue'
|
import { Refresh } from '@element-plus/icons-vue'
|
||||||
import { ElButton, ElIcon } from 'element-plus'
|
import { ElButton } from 'element-plus'
|
||||||
import {
|
import {
|
||||||
|
awmRangeOptions,
|
||||||
coinRangeOptions,
|
coinRangeOptions,
|
||||||
ratioRangeOptions,
|
ratioRangeOptions,
|
||||||
moneyRangeOptions,
|
moneyRangeOptions,
|
||||||
@@ -60,8 +62,22 @@ function toggleSkin(name: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleRange(
|
function toggleRange(
|
||||||
minKey: 'minCoin' | 'minRatio' | 'minPrice' | 'minDeposit' | 'minTotal' | 'minFireLevel',
|
minKey:
|
||||||
maxKey: 'maxCoin' | 'maxRatio' | 'maxPrice' | 'maxDeposit' | 'maxTotal' | 'maxFireLevel',
|
| 'minCoin'
|
||||||
|
| 'minRatio'
|
||||||
|
| 'minPrice'
|
||||||
|
| 'minDeposit'
|
||||||
|
| 'minTotal'
|
||||||
|
| 'minFireLevel'
|
||||||
|
| 'minAwmAmmo',
|
||||||
|
maxKey:
|
||||||
|
| 'maxCoin'
|
||||||
|
| 'maxRatio'
|
||||||
|
| 'maxPrice'
|
||||||
|
| 'maxDeposit'
|
||||||
|
| 'maxTotal'
|
||||||
|
| 'maxFireLevel'
|
||||||
|
| 'maxAwmAmmo',
|
||||||
option: RangeOption
|
option: RangeOption
|
||||||
) {
|
) {
|
||||||
const currentMin = props.filters[minKey]
|
const currentMin = props.filters[minKey]
|
||||||
@@ -74,8 +90,22 @@ function toggleRange(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isRangeActive(
|
function isRangeActive(
|
||||||
minKey: 'minCoin' | 'minRatio' | 'minPrice' | 'minDeposit' | 'minTotal' | 'minFireLevel',
|
minKey:
|
||||||
maxKey: 'maxCoin' | 'maxRatio' | 'maxPrice' | 'maxDeposit' | 'maxTotal' | 'maxFireLevel',
|
| 'minCoin'
|
||||||
|
| 'minRatio'
|
||||||
|
| 'minPrice'
|
||||||
|
| 'minDeposit'
|
||||||
|
| 'minTotal'
|
||||||
|
| 'minFireLevel'
|
||||||
|
| 'minAwmAmmo',
|
||||||
|
maxKey:
|
||||||
|
| 'maxCoin'
|
||||||
|
| 'maxRatio'
|
||||||
|
| 'maxPrice'
|
||||||
|
| 'maxDeposit'
|
||||||
|
| 'maxTotal'
|
||||||
|
| 'maxFireLevel'
|
||||||
|
| 'maxAwmAmmo',
|
||||||
option: RangeOption
|
option: RangeOption
|
||||||
) {
|
) {
|
||||||
return isRangeSelected(props.filters[minKey], props.filters[maxKey], option.min, option.max)
|
return isRangeSelected(props.filters[minKey], props.filters[maxKey], option.min, option.max)
|
||||||
@@ -84,6 +114,14 @@ function isRangeActive(
|
|||||||
function toggleAdvanced() {
|
function toggleAdvanced() {
|
||||||
emit('update:advancedOpen', !props.advancedOpen)
|
emit('update:advancedOpen', !props.advancedOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 刀皮/红皮作为独立左列字段展示(与全宽皮肤区区分) */
|
||||||
|
const meleeSkinGroup = computed(() =>
|
||||||
|
props.skinFilterGroups.find(group => group.key === 'melee')
|
||||||
|
)
|
||||||
|
const redSkinGroup = computed(() =>
|
||||||
|
props.skinFilterGroups.find(group => group.key === 'operatorRed')
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -130,6 +168,22 @@ function toggleAdvanced() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="filter-field">
|
||||||
|
<label>AWM子弹</label>
|
||||||
|
<div class="pill-row">
|
||||||
|
<button
|
||||||
|
v-for="item in awmRangeOptions.filter(o => o.label !== '全部')"
|
||||||
|
:key="item.label"
|
||||||
|
type="button"
|
||||||
|
class="pill-chip"
|
||||||
|
:class="{ active: isRangeActive('minAwmAmmo', 'maxAwmAmmo', item) }"
|
||||||
|
@click="toggleRange('minAwmAmmo', 'maxAwmAmmo', item)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="filter-field">
|
<div class="filter-field">
|
||||||
<label>保险</label>
|
<label>保险</label>
|
||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
@@ -147,17 +201,17 @@ function toggleAdvanced() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-field">
|
<div class="filter-field">
|
||||||
<label>体力</label>
|
<label>租金</label>
|
||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
<button
|
<button
|
||||||
v-for="item in publishOptions.level_options"
|
v-for="item in moneyRangeOptions.filter(o => o.label !== '全部')"
|
||||||
:key="`stamina-${item}`"
|
:key="`price-${item.label}`"
|
||||||
type="button"
|
type="button"
|
||||||
class="pill-chip"
|
class="pill-chip"
|
||||||
:class="{ active: filters.stamina.includes(item) }"
|
:class="{ active: isRangeActive('minPrice', 'maxPrice', item) }"
|
||||||
@click="toggleChip('stamina', item)"
|
@click="toggleRange('minPrice', 'maxPrice', item)"
|
||||||
>
|
>
|
||||||
{{ item }}
|
{{ item.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -178,7 +232,55 @@ function toggleAdvanced() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="meleeSkinGroup" class="filter-field">
|
||||||
|
<label>{{ meleeSkinGroup.title }}</label>
|
||||||
|
<div class="pill-row">
|
||||||
|
<button
|
||||||
|
v-for="skin in meleeSkinGroup.options"
|
||||||
|
:key="`melee-${skin}`"
|
||||||
|
type="button"
|
||||||
|
class="pill-chip"
|
||||||
|
:class="{ active: filters.skinNames.includes(skin) }"
|
||||||
|
@click="toggleSkin(skin)"
|
||||||
|
>
|
||||||
|
{{ skin }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="filter-field">
|
<div class="filter-field">
|
||||||
|
<label>体力</label>
|
||||||
|
<div class="pill-row">
|
||||||
|
<button
|
||||||
|
v-for="item in publishOptions.level_options"
|
||||||
|
:key="`stamina-${item}`"
|
||||||
|
type="button"
|
||||||
|
class="pill-chip"
|
||||||
|
:class="{ active: filters.stamina.includes(item) }"
|
||||||
|
@click="toggleChip('stamina', item)"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="redSkinGroup" class="filter-field">
|
||||||
|
<label>{{ redSkinGroup.title }}</label>
|
||||||
|
<div class="pill-row">
|
||||||
|
<button
|
||||||
|
v-for="skin in redSkinGroup.options"
|
||||||
|
:key="`red-${skin}`"
|
||||||
|
type="button"
|
||||||
|
class="pill-chip"
|
||||||
|
:class="{ active: filters.skinNames.includes(skin) }"
|
||||||
|
@click="toggleSkin(skin)"
|
||||||
|
>
|
||||||
|
{{ skin }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter-field login-method-field">
|
||||||
<label>登录方式</label>
|
<label>登录方式</label>
|
||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
<button
|
<button
|
||||||
@@ -193,26 +295,6 @@ function toggleAdvanced() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
v-for="group in skinFilterGroups"
|
|
||||||
:key="group.key"
|
|
||||||
class="filter-field filter-field-full"
|
|
||||||
>
|
|
||||||
<label>{{ group.title }}</label>
|
|
||||||
<div class="pill-row">
|
|
||||||
<button
|
|
||||||
v-for="skin in group.options"
|
|
||||||
:key="`${group.key}-${skin}`"
|
|
||||||
type="button"
|
|
||||||
class="pill-chip"
|
|
||||||
:class="{ active: filters.skinNames.includes(skin) }"
|
|
||||||
@click="toggleSkin(skin)"
|
|
||||||
>
|
|
||||||
{{ skin }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="advanced-toggle-row">
|
<div class="advanced-toggle-row">
|
||||||
@@ -225,22 +307,6 @@ function toggleAdvanced() {
|
|||||||
|
|
||||||
<div v-show="advancedOpen" class="advanced-filter-panel">
|
<div v-show="advancedOpen" class="advanced-filter-panel">
|
||||||
<div class="quick-filter-grid">
|
<div class="quick-filter-grid">
|
||||||
<div class="filter-field">
|
|
||||||
<label>租金</label>
|
|
||||||
<div class="pill-row">
|
|
||||||
<button
|
|
||||||
v-for="item in moneyRangeOptions.filter(o => o.label !== '全部')"
|
|
||||||
:key="`price-${item.label}`"
|
|
||||||
type="button"
|
|
||||||
class="pill-chip"
|
|
||||||
:class="{ active: isRangeActive('minPrice', 'maxPrice', item) }"
|
|
||||||
@click="toggleRange('minPrice', 'maxPrice', item)"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="filter-field">
|
<div class="filter-field">
|
||||||
<label>押金</label>
|
<label>押金</label>
|
||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
|
|||||||
@@ -9,6 +9,16 @@ export const coinRangeOptions = [
|
|||||||
{ label: '300以上', min: 300, max: undefined },
|
{ label: '300以上', min: 300, max: undefined },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** AWM 子弹数量区间(与移动端档位保持一致) */
|
||||||
|
export const awmRangeOptions = [
|
||||||
|
{ label: '全部', min: undefined, max: undefined },
|
||||||
|
{ label: '0-20', min: 0, max: 20 },
|
||||||
|
{ label: '20-50', min: 20, max: 50 },
|
||||||
|
{ label: '50-100', min: 50, max: 100 },
|
||||||
|
{ label: '100-200', min: 100, max: 200 },
|
||||||
|
{ label: '200以上', min: 200, max: undefined },
|
||||||
|
]
|
||||||
|
|
||||||
export const ratioRangeOptions = [
|
export const ratioRangeOptions = [
|
||||||
{ label: '全部', min: undefined, max: undefined },
|
{ label: '全部', min: undefined, max: undefined },
|
||||||
{ label: '≤30', min: undefined, max: 30 },
|
{ label: '≤30', min: undefined, max: 30 },
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export const desktopHomeFilterQueryKeys = [
|
|||||||
'max_total',
|
'max_total',
|
||||||
'min_fire_level',
|
'min_fire_level',
|
||||||
'max_fire_level',
|
'max_fire_level',
|
||||||
|
'resource_awmAmmo_min',
|
||||||
|
'resource_awmAmmo_max',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const mobileHomeFilterQueryKeys = ['keyword', 'sort', 'zone', 'filters', 'ranges'] as const
|
export const mobileHomeFilterQueryKeys = ['keyword', 'sort', 'zone', 'filters', 'ranges'] as const
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ export interface HomeFilters {
|
|||||||
maxTotal: number | undefined
|
maxTotal: number | undefined
|
||||||
minFireLevel: number | undefined
|
minFireLevel: number | undefined
|
||||||
maxFireLevel: number | undefined
|
maxFireLevel: number | undefined
|
||||||
|
/** AWM 子弹数量区间 */
|
||||||
|
minAwmAmmo: number | undefined
|
||||||
|
maxAwmAmmo: number | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkinFilterGroup {
|
export interface SkinFilterGroup {
|
||||||
@@ -86,6 +89,8 @@ export function useHomeFilters(
|
|||||||
maxTotal: undefined,
|
maxTotal: undefined,
|
||||||
minFireLevel: undefined,
|
minFireLevel: undefined,
|
||||||
maxFireLevel: undefined,
|
maxFireLevel: undefined,
|
||||||
|
minAwmAmmo: undefined,
|
||||||
|
maxAwmAmmo: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeFilterPopover = ref<FilterPopoverKey | ''>('')
|
const activeFilterPopover = ref<FilterPopoverKey | ''>('')
|
||||||
@@ -145,7 +150,6 @@ export function useHomeFilters(
|
|||||||
let count = 0
|
let count = 0
|
||||||
if (filters.region.length) count += 1
|
if (filters.region.length) count += 1
|
||||||
if (filters.rank.length) count += 1
|
if (filters.rank.length) count += 1
|
||||||
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) count += 1
|
|
||||||
if (filters.minDeposit !== undefined || filters.maxDeposit !== undefined) count += 1
|
if (filters.minDeposit !== undefined || filters.maxDeposit !== undefined) count += 1
|
||||||
if (filters.minTotal !== undefined || filters.maxTotal !== undefined) count += 1
|
if (filters.minTotal !== undefined || filters.maxTotal !== undefined) count += 1
|
||||||
if (filters.minFireLevel !== undefined || filters.maxFireLevel !== undefined) count += 1
|
if (filters.minFireLevel !== undefined || filters.maxFireLevel !== undefined) count += 1
|
||||||
@@ -178,6 +182,8 @@ export function useHomeFilters(
|
|||||||
filters.maxTotal = undefined
|
filters.maxTotal = undefined
|
||||||
filters.minFireLevel = undefined
|
filters.minFireLevel = undefined
|
||||||
filters.maxFireLevel = undefined
|
filters.maxFireLevel = undefined
|
||||||
|
filters.minAwmAmmo = undefined
|
||||||
|
filters.maxAwmAmmo = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStringFilter(key: StringFilterKey, value: string | string[]) {
|
function setStringFilter(key: StringFilterKey, value: string | string[]) {
|
||||||
@@ -230,6 +236,11 @@ export function useHomeFilters(
|
|||||||
filters.maxFireLevel = max
|
filters.maxFireLevel = max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAwmAmmoRange(min: number | undefined, max: number | undefined) {
|
||||||
|
filters.minAwmAmmo = min
|
||||||
|
filters.maxAwmAmmo = max
|
||||||
|
}
|
||||||
|
|
||||||
/** 区间 chip:再点同一档则清空 */
|
/** 区间 chip:再点同一档则清空 */
|
||||||
function toggleRange(
|
function toggleRange(
|
||||||
currentMin: number | undefined,
|
currentMin: number | undefined,
|
||||||
@@ -277,6 +288,7 @@ export function useHomeFilters(
|
|||||||
setDepositRange,
|
setDepositRange,
|
||||||
setTotalRange,
|
setTotalRange,
|
||||||
setFireLevelRange,
|
setFireLevelRange,
|
||||||
|
setAwmAmmoRange,
|
||||||
toggleRange,
|
toggleRange,
|
||||||
setFilterPopover,
|
setFilterPopover,
|
||||||
closeFilterPopover,
|
closeFilterPopover,
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ export function useListingQuery(
|
|||||||
max_total: filters.maxTotal,
|
max_total: filters.maxTotal,
|
||||||
min_fire_level: filters.minFireLevel,
|
min_fire_level: filters.minFireLevel,
|
||||||
max_fire_level: filters.maxFireLevel,
|
max_fire_level: filters.maxFireLevel,
|
||||||
|
resource_awmAmmo_min: filters.minAwmAmmo,
|
||||||
|
resource_awmAmmo_max: filters.maxAwmAmmo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ function applyRouteQueryToHomeState() {
|
|||||||
filters.maxTotal = readQueryNumber(query, 'max_total')
|
filters.maxTotal = readQueryNumber(query, 'max_total')
|
||||||
filters.minFireLevel = readQueryNumber(query, 'min_fire_level')
|
filters.minFireLevel = readQueryNumber(query, 'min_fire_level')
|
||||||
filters.maxFireLevel = readQueryNumber(query, 'max_fire_level')
|
filters.maxFireLevel = readQueryNumber(query, 'max_fire_level')
|
||||||
|
filters.minAwmAmmo = readQueryNumber(query, 'resource_awmAmmo_min')
|
||||||
|
filters.maxAwmAmmo = readQueryNumber(query, 'resource_awmAmmo_max')
|
||||||
// 无 sort 参数即综合推荐(默认)
|
// 无 sort 参数即综合推荐(默认)
|
||||||
sortBy.value = readQueryString(query, 'sort') || 'recommended'
|
sortBy.value = readQueryString(query, 'sort') || 'recommended'
|
||||||
// zone 不从 query/storage 恢复,由用户实时点击决定,不参与筛选持久化
|
// zone 不从 query/storage 恢复,由用户实时点击决定,不参与筛选持久化
|
||||||
@@ -266,6 +268,8 @@ function buildDesktopHomeQueryValues(): Record<string, HomeQueryValue> {
|
|||||||
max_total: filters.maxTotal,
|
max_total: filters.maxTotal,
|
||||||
min_fire_level: filters.minFireLevel,
|
min_fire_level: filters.minFireLevel,
|
||||||
max_fire_level: filters.maxFireLevel,
|
max_fire_level: filters.maxFireLevel,
|
||||||
|
resource_awmAmmo_min: filters.minAwmAmmo,
|
||||||
|
resource_awmAmmo_max: filters.maxAwmAmmo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,11 @@
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 登录方式固定到右侧第二列(与「体力」同行的右列),避免左侧列过挤 */
|
||||||
|
.login-method-field {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-field label {
|
.filter-field label {
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -176,6 +181,10 @@
|
|||||||
.quick-filter-grid {
|
.quick-filter-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-method-field {
|
||||||
|
grid-column: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-chip-row {
|
.filter-chip-row {
|
||||||
|
|||||||
Reference in New Issue
Block a user