add
This commit is contained in:
114
frontend/src/views/ProductDetail.vue
Normal file
114
frontend/src/views/ProductDetail.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card>
|
||||
<el-button type="text" @click="$router.push('/')">返回首页</el-button>
|
||||
</el-card>
|
||||
<el-card class="content">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<img :src="product.coverUrl || placeholder" class="cover" />
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<h2>{{ product.name }}</h2>
|
||||
<p>{{ product.description }}</p>
|
||||
<div class="price">¥{{ product.price }}</div>
|
||||
<el-input-number v-model="quantity" :min="1" :max="product.stock || 99" />
|
||||
<div class="section">
|
||||
<el-select v-model="addressId" placeholder="选择收货地址">
|
||||
<el-option
|
||||
v-for="addr in addresses"
|
||||
:key="addr.id"
|
||||
:label="formatAddress(addr)"
|
||||
:value="addr.id"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button type="primary" @click="submitOrder">立即购买</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getProduct } from '../api/product';
|
||||
import { listAddresses } from '../api/address';
|
||||
import { createOrder } from '../api/order';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
product: {},
|
||||
quantity: 1,
|
||||
addresses: [],
|
||||
addressId: null,
|
||||
placeholder: 'https://via.placeholder.com/400x300?text=Flower'
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.loadDetail();
|
||||
this.loadAddresses();
|
||||
},
|
||||
methods: {
|
||||
loadDetail() {
|
||||
getProduct(this.$route.params.id).then((res) => {
|
||||
this.product = res.data.data || {};
|
||||
});
|
||||
},
|
||||
loadAddresses() {
|
||||
listAddresses().then((res) => {
|
||||
this.addresses = res.data.data || [];
|
||||
const def = this.addresses.find((item) => item.isDefault);
|
||||
if (def) {
|
||||
this.addressId = def.id;
|
||||
}
|
||||
});
|
||||
},
|
||||
formatAddress(addr) {
|
||||
return `${addr.recipientName} ${addr.phone} ${addr.province || ''}${addr.city || ''}${addr.district || ''}${addr.detail || ''}`;
|
||||
},
|
||||
submitOrder() {
|
||||
if (!this.addressId) {
|
||||
this.$message.warning('请选择收货地址');
|
||||
return;
|
||||
}
|
||||
createOrder({
|
||||
addressId: this.addressId,
|
||||
items: [{ productId: this.product.id, quantity: this.quantity }]
|
||||
}).then((res) => {
|
||||
this.$message.success('下单成功');
|
||||
const order = res.data.data.order;
|
||||
this.$router.push(`/orders?highlight=${order.id}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
padding: 20px;
|
||||
}
|
||||
.content {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.cover {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.price {
|
||||
color: #f56c6c;
|
||||
font-size: 20px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
.section {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.section .el-select {
|
||||
margin-right: 12px;
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user