feat:完成商品详情

merge-requests/8/head
张征 3 years ago
parent 966d13922f
commit 7049ca6890

@ -15,7 +15,7 @@
<script> <script>
import UiMoney from "@/components/UiMoney.vue"; import UiMoney from "@/components/UiMoney.vue";
export default { export default {
name: "GoodsItem", name: "UiGoodsItem",
componetns: { UiMoney }, componetns: { UiMoney },
props: { props: {
item: { item: {

@ -8,7 +8,7 @@
<template> <template>
<div class="layout"> <div class="layout">
<BsLogin :visible.sync="loginVisible" /> <BsLogin :visible.sync="loginVisible" />
<Header /> <!-- <Header /> -->
<Nuxt /> <Nuxt />
<Footer /> <Footer />
</div> </div>

@ -13,18 +13,52 @@
</nav> </nav>
<main class="main flex"> <main class="main flex">
<aside class="main__preview"> <aside class="main__preview">
<img class="main__preview" src="~/static/images/goods/more.png" alt="商品大图" /> <img
class="main__preview-big"
:src="detailData.pictureList[activeImg]"
alt="商品大图"
/>
<div class="main__preview-control">
<img
class="main__preview-control--left"
src="~/static/images/goods/left.png"
alt="左侧切换"
@click="onImgLeft"
/>
<div
class="main__preview-control--imgs"
:style="
activeImg > 4
? 'transform: translateX(-' + (activeImg - 4) * 78 + 'px);'
: ''
"
>
<img
:class="index == activeImg ? 'img-active' : ''"
:src="item"
alt=""
v-for="(item, index) in detailData.pictureList"
:key="index"
@click="onActiveImg(index)"
/>
</div>
<img
class="main__preview-control--right"
src="~/static/images/goods/right.png"
alt="右侧切换"
@click="onImgRight"
/>
</div>
</aside> </aside>
<article class="main__details"> <article class="main__details">
<p class="main__details-title"> <p class="main__details-title">
<span class="main__details-title--label">新品</span> <span class="main__details-title--label">新品</span>
Java从入门到项目实战全程视频版 {{ detailData.name }}
编程入门it计算机书籍算法java编程思想java从入门到精通java核心技术javascript
</p> </p>
<div class="main__details-msg"> <div class="main__details-msg">
<div class="main__details-msg--price flex"> <div class="main__details-msg--price flex">
<span class="msg-txt">售价</span> <span class="msg-txt">售价</span>
<UiMoney :money="123"></UiMoney> <UiMoney :money="detailData.startingPrice"></UiMoney>
</div> </div>
<div class="hr"></div> <div class="hr"></div>
<div class="main__details-msg--service flex flex-middle"> <div class="main__details-msg--service flex flex-middle">
@ -40,41 +74,219 @@
</div> </div>
</div> </div>
<div class="main__details-option"> <div class="main__details-option">
<div class="main__details-option--line flex flex-middle"> <div
<span class="line-txt">规格</span> class="main__details-option--line flex flex-middle"
v-for="(item, index) in detailData.attributeGroupList"
:key="item.id"
>
<span class="line-txt">{{ item.name }}</span>
<div class="line-btns"> <div class="line-btns">
<UiButton <UiButton
type="yellow_line" type="yellow_line"
v-for="(item, index) in 11" v-for="val in item.attributes"
:key="index" :key="val.symbol"
>123</UiButton @click="handleAttrItem(val, index)"
:class="{
'attr-item__active': val.active,
'attr-item__disabled': val.disabled,
}"
>{{ val.name }}</UiButton
> >
</div> </div>
</div> </div>
</div> </div>
<div class="main__details-pay"> <div class="main__details-pay">
<UiButton type="yellow_line">加入购物车</UiButton> <UiButton type="yellow_line">加入购物车</UiButton>
<UiButton type="yellow_panel">立即购</UiButton> <UiButton type="yellow_panel" @click="buyNow"></UiButton>
</div> </div>
</article> </article>
</main> </main>
<section class="section flex">
<div class="section-recommend">
<p class="section-title">看了又看</p>
<UiGoodsItem
v-for="item in recommendedData"
:item="item"
:key="item.id"
></UiGoodsItem>
</div>
<div class="section-details">
<p class="section-title">商品详情</p>
<div class="rich" v-html="detailData.detail"></div>
</div>
</section>
</div> </div>
</template> </template>
<script> <script>
import UiMoney from "@/components/UiMoney.vue"; import UiMoney from "@/components/UiMoney.vue";
import UiButton from "@/components/UiButton.vue"; import UiButton from "@/components/UiButton.vue";
import { ApiGetGoodsDetail, ApiGetGoodsSkus } from "@/plugins/api/goods"; import {
ApiGetGoodsDetail,
ApiGetGoodsSkus,
ApiGetRecommendedGoodsList,
} from "@/plugins/api/goods";
import UiGoodsItem from "@/components/UiGoodsItem.vue";
export default { export default {
componetns: { UiMoney, UiButton }, componetns: { UiMoney, UiButton, UiGoodsItem },
data() { data() {
return {}; return {
curBuyNum: 1,
activeImg: 0,
recommendedData: [],
skuData: {},
detailData: {
pictureList: [],
},
};
}, },
async created() { async created() {
let vm = this;
let id = this.$route.params.id; let id = this.$route.params.id;
let res1 = await ApiGetGoodsDetail({ id }); let res1 = await ApiGetGoodsDetail({ id });
let res2 = await ApiGetGoodsSkus({ productId: id }); let res2 = await ApiGetGoodsSkus({ productId: id });
let res3 = await ApiGetRecommendedGoodsList();
vm.detailData = res1.result;
vm.skuData = res2.result;
vm.recommendedData = res3.result;
console.log(`res1`, res1.result); console.log(`res1`, res1.result);
console.log(`res2`, res2.result); console.log(`res2`, res2.result);
console.log(`res3`, res3.result);
},
computed: {
/**
* 当前选中SKU根据选中规格计算
*/
curSku() {
return (
this.skuData.find(
(i) => i.attributeSymbolList === this.selectedSymbol.join(",")
) || {}
);
},
// [1,.,3]
selectedSymbol() {
return this.detailData.attributeGroupList
.map((item) => {
const activeAttr = item.attributes.find((i) => i.active);
return activeAttr ? activeAttr.symbol : ".";
})
.filter((i) => i); //.sort();
},
/**
* 最大可购买数量
* 1有限购则对比限购跟库存取最小值
* 2没限购取库存
*/
maxBuyNum() {
const singleBuyLimit = this.detailData.singleBuyLimit;
const stock = this.curSku.stock;
return singleBuyLimit ? Math.min(singleBuyLimit, stock || 1) : stock;
},
},
methods: {
onActiveImg(i) {
this.activeImg = i;
},
onImgLeft() {
let vm = this;
if (vm.activeImg > 0) {
vm.activeImg--;
}
},
onImgRight() {
let vm = this;
if (vm.activeImg < vm.detailData.pictureList.length - 1) {
vm.activeImg++;
}
},
/**
* 设置默认选中规格
*/
setDefaultAttr() {
let vm = this;
const curSku = vm.skuData.find((i) => i.stock > 0);
if (!curSku) {
return false;
}
vm.detailData.attributeGroupList.forEach((item, index) => {
for (let i of item.attributes) {
if (curSku.attributeSymbolList.includes(i.symbol)) {
this.$set(i, "active", true);
this.setDisabledItem(i, index, true);
break;
}
}
});
this.$emit("input", this.curSku);
},
/**
* 点击属性项设置选中和禁用项
*/
handleAttrItem(item, groupIndex) {
let vm = this;
//
if (item.disabled) {
return false;
}
// 1
vm.curBuyNum = 1;
const active = item.active;
//
vm.detailData.attributeGroupList[groupIndex].attributes.forEach(
(item) => {
this.$set(item, "active", false);
}
);
//
this.$set(item, "active", !active);
this.setDisabledItem(item, groupIndex);
},
/**
* 每次点击选项属性时计算不可选属性
*/
setDisabledItem(item, groupIndex) {
let vm = this;
vm.detailData.attributeGroupList.forEach((group, idx) => {
//
let symbolCache = Object.assign([], this.selectedSymbol);
//
if (groupIndex === idx) return false;
//
group.attributes.forEach((item) => {
//
symbolCache[idx] = item.symbol;
const reg = new RegExp(symbolCache.join(","));
// SKU
const res = vm.skuData
.filter((i) => reg.test(i.attributeSymbolList))
.find((i) => i.stock > 0);
if (res) {
item.disabled = false;
} else {
item.disabled = true;
}
});
});
},
buyNow() {
if (!this.curSku.skuId) {
this.$message.error("请选择规格~");
return false;
}
let query = {
mode: "buyNow",
skuId: this.curSku.skuId,
num: this.curBuyNum,
activityType: 1,
};
console.log(query);
this.$router.push({
path: "/order/submit",
query,
});
},
}, },
}; };
</script> </script>
@ -94,6 +306,64 @@ export default {
&__preview { &__preview {
width: 456px; width: 456px;
margin-right: 30px; margin-right: 30px;
&-big {
width: 456px;
height: 456px;
margin-bottom: 24px;
}
&-control {
width: 100%;
height: 58px;
position: relative;
overflow: hidden;
padding-left: 43px;
&::before {
content: "";
width: 43px;
height: 58px;
background: #fff;
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
&::after {
content: "";
width: 43px;
height: 58px;
background: #fff;
position: absolute;
right: 0;
top: 0;
}
&--left,
&--right {
width: 20px;
height: 34px;
position: absolute;
top: 12px;
z-index: 1;
cursor: pointer;
}
&--left {
left: 0;
}
&--right {
right: 0;
}
&--imgs {
width: 1500px;
img {
width: 58px;
height: 58px;
margin-right: 20px;
cursor: pointer;
}
.img-active {
border: 1px solid #ff512b;
}
}
}
} }
&__details { &__details {
width: 714px; width: 714px;
@ -195,4 +465,37 @@ export default {
} }
} }
} }
.section {
width: 1200px;
margin: 64px auto 0;
&-recommend {
width: 210px;
margin-right: 30px;
/deep/.goods-item {
border: 1px solid #f2f2f2;
}
}
&-details {
width: 960px;
}
&-title {
width: 100%;
height: 40px;
line-height: 40px;
background: #f7f7f7;
border: 1px solid #f2f2f2;
padding-left: 16px;
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
font-weight: 400;
color: #666666;
}
}
.attr-item__active {
background: red !important;
}
.attr-item__disabled {
background: cyan !important;
}
</style> </style>

@ -36,11 +36,11 @@
</div> </div>
</nav> </nav>
<div class="main__content"> <div class="main__content">
<GoodsItem <UiGoodsItem
:item="item" :item="item"
v-for="item in listData" v-for="item in listData"
:key="item.id" :key="item.id"
></GoodsItem> ></UiGoodsItem>
</div> </div>
<el-pagination <el-pagination
class="main__pagination flex flex-right" class="main__pagination flex flex-right"
@ -57,9 +57,9 @@
<script> <script>
import { ApiGetGoodsList } from "@/plugins/api/goods"; import { ApiGetGoodsList } from "@/plugins/api/goods";
import Sort from "./module/SortItem.vue"; import Sort from "./module/SortItem.vue";
import GoodsItem from "./module/Item.vue"; import UiGoodsItem from "@/components/UiGoodsItem.vue";
export default { export default {
components: { Sort, GoodsItem }, components: { Sort, UiGoodsItem },
data() { data() {
return { return {
navActive: 0, navActive: 0,

Loading…
Cancel
Save