205 lines
7.9 KiB
Vue
205 lines
7.9 KiB
Vue
<template>
|
||
<main class="shop" :class="`shop--${shop.layout}`" :style="{ '--theme': shop.theme }">
|
||
<van-nav-bar :title="shop.name" left-arrow @click-left="$router.push('/')" />
|
||
|
||
<section class="hero" :style="{ background: shop.gradient }">
|
||
<div>
|
||
<span class="hero__eyebrow">官方品质供应商</span>
|
||
<h1>{{ shop.slogan }}</h1>
|
||
<p>满 {{ shop.freeShipping }} 元免配送费</p>
|
||
</div>
|
||
<van-icon :name="shop.icon" size="64" />
|
||
</section>
|
||
|
||
<van-notice-bar class="notice" left-icon="volume-o" :text="shop.notice" />
|
||
<van-search v-model="keyword" placeholder="搜索商品" shape="round" />
|
||
|
||
<van-tabs v-model:active="activeCategory" sticky :color="shop.theme" title-active-color="var(--theme)">
|
||
<van-tab v-for="category in categories" :key="category" :title="category" />
|
||
</van-tabs>
|
||
|
||
<van-empty v-if="filteredProducts.length === 0" description="暂无相关商品" />
|
||
<section v-else class="goods-list">
|
||
<van-card
|
||
v-for="item in filteredProducts"
|
||
:key="item.id"
|
||
:price="item.price.toFixed(2)"
|
||
:desc="item.desc"
|
||
:title="item.name"
|
||
:thumb="item.image"
|
||
:origin-price="item.originPrice.toFixed(2)"
|
||
>
|
||
<template #tags>
|
||
<van-tag round plain :color="shop.theme">{{ item.tag }}</van-tag>
|
||
</template>
|
||
<template #footer>
|
||
<van-stepper v-model="cart[item.id]" theme="round" :button-size="25" :disable-input="true" />
|
||
</template>
|
||
</van-card>
|
||
</section>
|
||
|
||
<div class="bottom-space" />
|
||
<van-submit-bar :price="totalPrice" :button-text="submitText" :disabled="totalCount === 0" @submit="openCheckout">
|
||
<van-icon name="shopping-cart-o" size="26" :badge="totalCount || ''" class="cart-icon" />
|
||
<span class="selected">已选 {{ totalCount }} 件</span>
|
||
</van-submit-bar>
|
||
|
||
<van-popup v-model:show="checkoutVisible" round position="bottom" :style="{ minHeight: '68%' }" closeable>
|
||
<section class="checkout">
|
||
<h2>确认订单</h2>
|
||
<van-contact-card type="add" name="商城收货人" tel="138****8888" @click="Toast('当前使用默认收货地址')" />
|
||
<van-cell-group inset title="商品清单">
|
||
<van-cell
|
||
v-for="item in selectedProducts"
|
||
:key="item.id"
|
||
:title="item.name"
|
||
:label="`¥ ${item.price.toFixed(2)} × ${cart[item.id]}`"
|
||
:value="`¥ ${(item.price * cart[item.id]).toFixed(2)}`"
|
||
/>
|
||
</van-cell-group>
|
||
<van-cell-group inset>
|
||
<van-cell title="配送方式" value="供应商配送" />
|
||
<van-cell title="配送费" :value="freight ? `¥ ${freight.toFixed(2)}` : '免配送费'" />
|
||
</van-cell-group>
|
||
<div class="checkout__total">合计 <b>¥ {{ (totalPrice / 100).toFixed(2) }}</b></div>
|
||
<van-button block round :color="shop.gradient" :loading="submitting" @click="submitOrder">提交订单</van-button>
|
||
</section>
|
||
</van-popup>
|
||
|
||
<van-popup v-model:show="successVisible" round closeable class="result-popup">
|
||
<van-icon name="checked" color="#23b65d" size="62" />
|
||
<h2>订单提交成功</h2>
|
||
<p>订单号:{{ submittedOrderId }}</p>
|
||
<van-button round block type="primary" @click="successVisible = false">继续选购</van-button>
|
||
</van-popup>
|
||
</main>
|
||
</template>
|
||
|
||
<script>
|
||
import { Toast } from 'vant'
|
||
|
||
const apiBase = process.env.VUE_APP_API_BASE || 'http://localhost:8050'
|
||
const formatTime = date => date.toISOString().slice(0, 19).replace('T', ' ')
|
||
|
||
export default {
|
||
props: {
|
||
shop: { type: Object, required: true }
|
||
},
|
||
data() {
|
||
return {
|
||
keyword: '',
|
||
activeCategory: 0,
|
||
cart: this.shop.products.reduce((result, item) => ({ ...result, [item.id]: 0 }), {}),
|
||
checkoutVisible: false,
|
||
successVisible: false,
|
||
submitting: false,
|
||
submittedOrderId: ''
|
||
}
|
||
},
|
||
computed: {
|
||
categories() {
|
||
return ['全部', ...this.shop.categories]
|
||
},
|
||
filteredProducts() {
|
||
const category = this.categories[this.activeCategory]
|
||
const keyword = this.keyword.trim()
|
||
return this.shop.products.filter(item => (category === '全部' || item.category === category) && (!keyword || item.name.includes(keyword)))
|
||
},
|
||
selectedProducts() {
|
||
return this.shop.products.filter(item => this.cart[item.id] > 0)
|
||
},
|
||
totalCount() {
|
||
return this.selectedProducts.reduce((sum, item) => sum + this.cart[item.id], 0)
|
||
},
|
||
goodsAmount() {
|
||
return this.selectedProducts.reduce((sum, item) => sum + item.price * this.cart[item.id], 0)
|
||
},
|
||
freight() {
|
||
return this.goodsAmount > 0 && this.goodsAmount < this.shop.freeShipping ? 12 : 0
|
||
},
|
||
totalPrice() {
|
||
return Math.round((this.goodsAmount + this.freight) * 100)
|
||
},
|
||
submitText() {
|
||
return this.totalCount ? `提交订单(${this.totalCount} 件)` : '提交订单'
|
||
}
|
||
},
|
||
methods: {
|
||
openCheckout() {
|
||
this.checkoutVisible = true
|
||
},
|
||
createOrderId() {
|
||
return `SUP${new Date().toISOString().replace(/\D/g, '').slice(0, 14)}${Math.floor(Math.random() * 9000 + 1000)}`
|
||
},
|
||
async submitOrder() {
|
||
const orderId = this.createOrderId()
|
||
const now = formatTime(new Date())
|
||
const orderInfo = {
|
||
orderId,
|
||
orderNumberId: `TRADE${Date.now()}`,
|
||
supplierId: this.shop.id,
|
||
aplName: this.shop.name,
|
||
createTime: now,
|
||
updateTime: now,
|
||
deliveryStatus: '0',
|
||
orderState: '0',
|
||
totalPrice: +(this.totalPrice / 100).toFixed(2),
|
||
pointsPrice: +(this.totalPrice / 100).toFixed(2),
|
||
wPayOrAPay: 0,
|
||
freightCost: this.freight,
|
||
orderProInfos: this.selectedProducts.map(item => ({
|
||
sku: item.sku,
|
||
number: this.cart[item.id],
|
||
price: +(item.price * this.cart[item.id]).toFixed(2),
|
||
name: item.name,
|
||
taxRate: 0.13,
|
||
picInfo: [item.image]
|
||
}))
|
||
}
|
||
|
||
this.submitting = true
|
||
try {
|
||
const response = await fetch(`${apiBase}/general/receive/pending`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ supplierId: this.shop.id, userId: 'h5-demo-user', token: 'h5-demo-token', orderInfo })
|
||
})
|
||
const result = await response.json()
|
||
if (!response.ok || result.resultCode !== 0) throw new Error(result.message || '订单提交失败')
|
||
|
||
this.submittedOrderId = result.data && result.data.orderId ? result.data.orderId : orderId
|
||
this.checkoutVisible = false
|
||
this.successVisible = true
|
||
this.selectedProducts.forEach(item => { this.cart[item.id] = 0 })
|
||
} catch (error) {
|
||
Toast.fail(error.message || '无法连接订单服务,请确认服务已启动')
|
||
} finally {
|
||
this.submitting = false
|
||
}
|
||
},
|
||
Toast
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.shop { min-height: 100vh; background: #f6f7f9; }
|
||
.hero { display: flex; align-items: center; justify-content: space-between; margin: 12px; padding: 22px; border-radius: 18px; color: #fff; box-shadow: 0 10px 22px rgba(30, 80, 90, .14); }
|
||
.hero h1 { margin: 7px 0; font-size: 23px; }
|
||
.hero p, .hero__eyebrow { margin: 0; font-size: 13px; opacity: .9; }
|
||
.notice { margin: 0 12px 8px; overflow: hidden; border-radius: 9px; }
|
||
.goods-list { padding: 0 12px; }
|
||
.van-card { margin: 10px 0; padding: 12px; border-radius: 12px; background: #fff; }
|
||
.van-card__thumb { overflow: hidden; border-radius: 8px; }
|
||
.bottom-space { height: 72px; }
|
||
.cart-icon { margin: 0 10px 0 4px; }
|
||
.selected { color: #646566; font-size: 13px; }
|
||
.checkout { padding: 22px 16px 28px; }
|
||
.checkout h2 { margin: 2px 0 18px; }
|
||
.checkout__total { padding: 18px 8px; text-align: right; }
|
||
.checkout__total b { color: #ee0a24; font-size: 22px; }
|
||
.result-popup { width: 78%; padding: 32px 22px 24px; text-align: center; }
|
||
.result-popup h2 { margin: 14px 0 8px; }
|
||
.result-popup p { margin: 0 0 22px; color: #969799; font-size: 12px; }
|
||
</style>
|