Files
vmall/apps/mall/components/ui/Modal.vue
T
Chengdong Zhang 21e99bb52b feat(mall): classic B2B2C PC storefront with fixed mock API layer
- Mock adapter implementing @vmall/shared ApiClient (localStorage-persisted
  cart/orders/invoices), runtime switch via mockApi flag (default on)
- Fixed bilingual mock catalog: 3-level categories, 24 products w/ SKUs,
  stores, brands, banners, floors, seckill/collective/integral, comments,
  coupons, addresses, seeded orders/shipments/invoices
- B2B2C mall shell: top bar, logo/search/cart header, dark nav + category
  mega-menu, value-prop footer, back-to-top; 1200px grid, #ca151e theme
- UI primitives replacing element-plus: carousel, pagination, breadcrumb,
  qty stepper, rating stars, modal, tabs, step bar, product card
- Pages: home floors, search (filters/sort/paging), goods detail (SKU
  picker, store rail, review tabs), cart -> checkout -> pay -> success,
  auth pages, user center (dashboard/orders/addresses/favorites/coupons/
  invoices), stores, seckill, collective, integral
- i18n split into per-domain locale modules (en+zh)
- OpenSpec change mall-pc-storefront-replica archived; all specs green
2026-09-17 19:13:29 +08:00

66 lines
1.3 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">
defineProps<{ open: boolean; title?: string }>();
const emit = defineEmits<{ close: [] }>();
</script>
<template>
<Teleport to="body">
<div v-if="open" class="mask" @click.self="emit('close')">
<div class="dialog">
<header v-if="title" class="head">
<span>{{ title }}</span>
<button type="button" class="x" :aria-label="$t('common.cancel')" @click="emit('close')">×</button>
</header>
<div class="body">
<slot />
</div>
<footer v-if="$slots.footer" class="foot">
<slot name="footer" />
</footer>
</div>
</div>
</Teleport>
</template>
<style scoped>
.mask {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 900;
display: flex;
align-items: center;
justify-content: center;
}
.dialog {
background: #fff;
min-width: 420px;
max-width: 720px;
border-radius: 4px;
box-shadow: var(--mall-shadow);
}
.head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
border-bottom: 1px solid var(--mall-line);
font-size: 15px;
}
.x {
border: 0;
background: none;
font-size: 20px;
cursor: pointer;
color: var(--mall-muted);
}
.body {
padding: 20px;
}
.foot {
padding: 12px 20px;
border-top: 1px solid var(--mall-line);
text-align: right;
}
</style>