Files
inkreach-official-website/apps/website/app/components/product/ProductGrid.vue
T
yeuimu 6c61a4e871 feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma
  binaryTargets for openssl 3.0
- nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal
  cron, http->https redirect
- prisma: add origin_goods.delisted migration, sync missing schema
  (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz
- api: CORS wildcard reflection, helmet CORP cross-origin, price
  backfill in persistProductDetail, categoryIcon ancestor fallback,
  mediaByColor per-color gallery in public goods detail
- admin: /admin base path (vite + router)
- import-data.mjs: udt_name casting, serial sequence advance fix
2026-08-26 14:23:09 +08:00

25 lines
2.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import type { Product } from '~/composables/useProductCenter';
defineProps<{ products: Product[]; loading: boolean; showCountry?: boolean }>();
const emit = defineEmits<{ 'clear-filters': []; 'view-all': [] }>();
</script>
<template>
<div v-if="loading" class="product-grid"><ProductCardSkeleton v-for="index in 8" :key="index" /></div>
<div v-else-if="!products.length" class="empty">
<img src="/product-empty.svg" alt="" />
<h2>未找到相关商品</h2>
<p>当前筛选条件下暂无匹配产品可尝试调整关键词或减少筛选条件</p>
<div class="empty-actions"><button type="button" class="view-all" @click="emit('view-all')">查看全部商品</button><button type="button" class="clear" @click="emit('clear-filters')">清空筛选</button></div>
</div>
<div v-else class="product-grid"><ProductCard v-for="product in products" :key="product.id" :product="product" :show-country="showCountry" /></div>
</template>
<style scoped>
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px 24px; }
.empty { display: flex; flex-direction: column; align-items: center; min-height: 600px; padding-top: 86px; color: rgba(0,0,0,.6); text-align: center; }.empty img { width: 260px; height: 260px; object-fit: contain; }.empty h2 { margin: 12px 0 10px; color: #000; font-size: 22px; font-weight: 600; }.empty p { margin: 0; font-size: 14px; }.empty-actions { display: flex; gap: 24px; margin-top: 34px; }.empty-actions button { height: 38px; padding: 0 16px; border: 0; border-radius: 60px; font-size: 16px; cursor: pointer; }.empty-actions .view-all { color: #ff6800; background: rgba(255,104,0,.06); }.empty-actions .clear { min-width: 128px; color: #fff; background: #ff6800; }
@media (max-width: 1180px) { .product-grid { gap: 16px; } }
@media (max-width: 760px) { .product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 430px) { .product-grid { grid-template-columns: minmax(0, 1fr); } }
</style>