143 lines
4.3 KiB
Vue
143 lines
4.3 KiB
Vue
<script setup lang="ts">
|
||
import { companies, regionOptions, routeOptions, serviceOptions } from '~/data/mock'
|
||
|
||
// USelect 的候选项不允许 value 为空字符串(Reka UI 会直接抛错导致页面水合失败),
|
||
// 因此「全部」使用 'all' 作为哨兵值,筛选时再转换为「不限制」。
|
||
const ANY = 'all'
|
||
|
||
const route = useRoute()
|
||
|
||
const keyword = ref(typeof route.query.q === 'string' ? route.query.q : '')
|
||
const region = ref<string>(ANY)
|
||
const routeFilter = ref<string>(ANY)
|
||
const serviceFilter = ref<string>(ANY)
|
||
const verifiedOnly = ref(false)
|
||
|
||
// 平台主导航的搜索框会带 q 跳转;目录页内再次搜索时组件复用,需同步 query
|
||
watch(() => route.query.q, (q) => {
|
||
if (typeof q === 'string') {
|
||
keyword.value = q
|
||
}
|
||
})
|
||
|
||
const toItems = (options: string[], label: string) => [
|
||
{ label: `全部${label}`, value: ANY },
|
||
...options.map(o => ({ label: o, value: o }))
|
||
]
|
||
|
||
const filtered = computed(() => {
|
||
const kw = keyword.value.trim().toLowerCase()
|
||
return companies.filter((c) => {
|
||
if (verifiedOnly.value && !c.verified) return false
|
||
if (region.value !== ANY && c.region !== region.value) return false
|
||
if (routeFilter.value !== ANY && !c.routes.includes(routeFilter.value)) return false
|
||
if (serviceFilter.value !== ANY && !c.services.includes(serviceFilter.value)) return false
|
||
if (kw && !(`${c.name}${c.slogan}${c.description}${c.city}`.toLowerCase().includes(kw))) return false
|
||
return true
|
||
})
|
||
})
|
||
|
||
function resetFilters() {
|
||
keyword.value = ''
|
||
region.value = ANY
|
||
routeFilter.value = ANY
|
||
serviceFilter.value = ANY
|
||
verifiedOnly.value = false
|
||
}
|
||
|
||
useSeoMeta({
|
||
title: '企业目录 - 链通物流',
|
||
description: '按航线、服务类型与地区筛选物流企业:海运整箱、拼箱、空运、铁路联运、报关报检、仓储与跨境电商物流服务商目录。'
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<UPage>
|
||
<UPageHeader
|
||
headline="企业目录"
|
||
title="查找物流服务商"
|
||
description="按航线、服务类型、地区筛选,或直接搜索企业名称与主营关键词。"
|
||
/>
|
||
|
||
<UPageBody>
|
||
<UContainer>
|
||
<!-- 筛选器 -->
|
||
<div class="flex flex-col lg:flex-row gap-3 lg:items-center mb-6">
|
||
<UInput
|
||
v-model="keyword"
|
||
icon="i-lucide-search"
|
||
placeholder="搜索企业名称、主营关键词…"
|
||
class="flex-1"
|
||
size="lg"
|
||
/>
|
||
|
||
<div class="flex flex-wrap gap-3 items-center">
|
||
<USelect
|
||
v-model="region"
|
||
:items="toItems(regionOptions, '地区')"
|
||
icon="i-lucide-map-pin"
|
||
class="w-32"
|
||
/>
|
||
<USelect
|
||
v-model="routeFilter"
|
||
:items="toItems(routeOptions, '航线')"
|
||
icon="i-lucide-globe"
|
||
class="w-36"
|
||
/>
|
||
<USelect
|
||
v-model="serviceFilter"
|
||
:items="toItems(serviceOptions, '服务')"
|
||
icon="i-lucide-ship"
|
||
class="w-40"
|
||
/>
|
||
<UCheckbox
|
||
v-model="verifiedOnly"
|
||
label="仅认证企业"
|
||
icon="i-lucide-badge-check"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 结果统计 -->
|
||
<p class="text-sm text-muted mb-4">
|
||
共找到 <span class="font-semibold text-default">{{ filtered.length }}</span> 家企业
|
||
</p>
|
||
|
||
<!-- 企业列表 -->
|
||
<div
|
||
v-if="filtered.length"
|
||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
||
>
|
||
<CompanyCard
|
||
v-for="company in filtered"
|
||
:key="company.slug"
|
||
:company="company"
|
||
/>
|
||
</div>
|
||
|
||
<div
|
||
v-else
|
||
class="flex flex-col items-center gap-3 py-20 text-center"
|
||
>
|
||
<UIcon
|
||
name="i-lucide-search-x"
|
||
class="size-10 text-dimmed"
|
||
/>
|
||
<p class="text-toned">
|
||
没有符合条件的企业,试试放宽筛选条件
|
||
</p>
|
||
<UButton
|
||
label="重置筛选"
|
||
color="neutral"
|
||
variant="outline"
|
||
icon="i-lucide-rotate-ccw"
|
||
@click="resetFilters"
|
||
/>
|
||
</div>
|
||
|
||
<div class="h-12" />
|
||
</UContainer>
|
||
</UPageBody>
|
||
</UPage>
|
||
</template>
|