Authored by zhangwenxue

商品详情: 使用列表数据初始化商品详情信息

@@ -41,6 +41,14 @@ export default { @@ -41,6 +41,14 @@ export default {
41 name: 'ProductDetail', 41 name: 'ProductDetail',
42 params: { 42 params: {
43 productId: product.id, 43 productId: product.id,
  44 +
  45 + /**
  46 + * 传递可用的初始化数据,避免白屏
  47 + */
  48 + productInfo: {
  49 + ...product,
  50 + price: product[this.priceKey], // 统一接收端使用的价格key
  51 + },
44 } 52 }
45 }); 53 });
46 }, 54 },
@@ -7,7 +7,8 @@ @@ -7,7 +7,8 @@
7 <cube-slide ref="slide" :data="imageList"> 7 <cube-slide ref="slide" :data="imageList">
8 <cube-slide-item v-for="(item, index) in imageList" :key="index"> 8 <cube-slide-item v-for="(item, index) in imageList" :key="index">
9 <a click="javascript:void 0" class="square-img-container"> 9 <a click="javascript:void 0" class="square-img-container">
10 - <square-img :src="item.image_url" :width="300" :height="300" /> 10 + <square-img v-if="!item.initial" :src="item.image_url" :width="600" :height="600" />
  11 + <square-img v-else :src="item.image_url" :width="274" :height="274" /> <!-- 利用缓存, productList使用的size -->
11 </a> 12 </a>
12 </cube-slide-item> 13 </cube-slide-item>
13 <template slot="dots" slot-scope="props"> 14 <template slot="dots" slot-scope="props">
@@ -26,8 +27,8 @@ @@ -26,8 +27,8 @@
26 </div> 27 </div>
27 <div class="info-name"><div>{{productDetail.product_name}}</div></div> 28 <div class="info-name"><div>{{productDetail.product_name}}</div></div>
28 </div> 29 </div>
29 - <a class="banner" v-if="resource" @click.prevent="gotoNewPage(resource.url)">  
30 - <img-size ref="resourceImg" :src="sizeImg(resource.src)"/> 30 + <a class="banner" @click.prevent="gotoNewPage">
  31 + <img-size v-if="resource" ref="resourceImg" :src="sizeImg(resource.src)"/>
31 </a> 32 </a>
32 <div class="info"> 33 <div class="info">
33 <transition-group name="info-list" tag="div" class="info-list"> 34 <transition-group name="info-list" tag="div" class="info-list">
@@ -202,6 +203,15 @@ export default { @@ -202,6 +203,15 @@ export default {
202 throw new Error('无效的商品ID'); 203 throw new Error('无效的商品ID');
203 } 204 }
204 205
  206 + /**
  207 + * 接收初始化数据
  208 + */
  209 + const initialProductInfo = router.params.productInfo;
  210 +
  211 + if (initialProductInfo) {
  212 + store.dispatch('product/setupInitialProductInfo', initialProductInfo);
  213 + }
  214 +
205 return store.dispatch('product/fetchProductInfo', {productId}); 215 return store.dispatch('product/fetchProductInfo', {productId});
206 }, 216 },
207 activated() { 217 activated() {
@@ -252,7 +262,8 @@ export default { @@ -252,7 +262,8 @@ export default {
252 next(); 262 next();
253 }, 263 },
254 methods: { 264 methods: {
255 - ...mapActions(['fetchProductInfo', 'fetchBrandTop', 'fetchFav', 'toggleFav', 'updateTradeInfo', 'getSelectedTradeProduct', 'payment', 'resetSelectedSize']), 265 + ...mapActions(['fetchProductInfo', 'fetchBrandTop', 'fetchFav', 'setupInitialProductInfo',
  266 + 'toggleFav', 'updateTradeInfo', 'getSelectedTradeProduct', 'payment', 'resetSelectedSize']),
256 historyBackGuard() { 267 historyBackGuard() {
257 for (let key of Object.keys(this.actionSheetCloseMap)) { 268 for (let key of Object.keys(this.actionSheetCloseMap)) {
258 if (this[key]) { 269 if (this[key]) {
@@ -347,6 +358,7 @@ export default { @@ -347,6 +358,7 @@ export default {
347 name: this.$route.name, 358 name: this.$route.name,
348 params: { 359 params: {
349 productId: product.id, 360 productId: product.id,
  361 + productInfo: product,
350 }, 362 },
351 }); 363 });
352 }, 364 },
@@ -507,7 +519,13 @@ export default { @@ -507,7 +519,13 @@ export default {
507 }, 519 },
508 520
509 // 资源位 521 // 资源位
510 - gotoNewPage(url) { 522 + gotoNewPage() {
  523 + if (!this.resource || !this.resource.url) {
  524 + return;
  525 + }
  526 +
  527 + const url = this.resource.url;
  528 +
511 /** 529 /**
512 * 商品详情页中的资源位点击 530 * 商品详情页中的资源位点击
513 * XY_UFO_GDS_DT_BANNER_C 531 * XY_UFO_GDS_DT_BANNER_C
@@ -600,10 +618,12 @@ export default { @@ -600,10 +618,12 @@ export default {
600 618
601 .banner { 619 .banner {
602 display: block; 620 display: block;
  621 + height: 132px;
603 622
604 img { 623 img {
  624 + display: block;
605 width: 100%; 625 width: 100%;
606 - height: 132px; 626 + height: 100%;
607 } 627 }
608 } 628 }
609 629
@@ -3,8 +3,9 @@ import { get } from 'lodash'; @@ -3,8 +3,9 @@ import { get } from 'lodash';
3 import Vue from 'vue'; 3 import Vue from 'vue';
4 4
5 export default { 5 export default {
6 - ensureProduct({ commit }, { productId }) { 6 + ensureProduct({ commit, state }, { productId }) {
7 commit(Types.ENSURE_PRODUCT_DETAIL, { productId }); 7 commit(Types.ENSURE_PRODUCT_DETAIL, { productId });
  8 + return state.products[productId];
8 }, 9 },
9 async fetchProductInfo({ commit, state }, { productId }) { 10 async fetchProductInfo({ commit, state }, { productId }) {
10 const queryTasks = ['', '/resource', '/activity', '/recommend'].map(path => { 11 const queryTasks = ['', '/resource', '/activity', '/recommend'].map(path => {
@@ -71,6 +72,18 @@ export default { @@ -71,6 +72,18 @@ export default {
71 commit(Types.UPDATE_BRAND_PRODUCT_TOP_LIST, { productId, topList: productList}); 72 commit(Types.UPDATE_BRAND_PRODUCT_TOP_LIST, { productId, topList: productList});
72 } 73 }
73 }, 74 },
  75 + async setupInitialProductInfo({ commit, state, dispatch }, payload) {
  76 + const { id: productId } = payload;
  77 + if (!productId) {
  78 + return;
  79 + }
  80 +
  81 + const productInfo = await dispatch('ensureProduct', {productId});
  82 +
  83 + if (productInfo.product_name === null) {
  84 + commit(Types.SETUP_INITIAL_PRODUCT_INFO, payload);
  85 + }
  86 + },
74 async toggleFav({ commit }, { productId, isFav }) { 87 async toggleFav({ commit }, { productId, isFav }) {
75 const result = await this.$api.post(`/api/ufo/product/favorite/${isFav ? 'add' : 'cancel'}`, { productId }); 88 const result = await this.$api.post(`/api/ufo/product/favorite/${isFav ? 'add' : 'cancel'}`, { productId });
76 89
1 import * as Types from './types'; 1 import * as Types from './types';
2 -import { find } from 'lodash'; 2 +import { find, set } from 'lodash';
3 3
4 import { defaultProduct, defaultSelectedSize } from './index'; 4 import { defaultProduct, defaultSelectedSize } from './index';
5 5
@@ -58,4 +58,21 @@ export default { @@ -58,4 +58,21 @@ export default {
58 [Types.RESET_SELECTED_PRODUCT_SIZE](state) { 58 [Types.RESET_SELECTED_PRODUCT_SIZE](state) {
59 Object.assign(state.selectedProductInfo, defaultSelectedSize()); 59 Object.assign(state.selectedProductInfo, defaultSelectedSize());
60 }, 60 },
  61 + [Types.SETUP_INITIAL_PRODUCT_INFO](state, payload) {
  62 + const { id: productId } = payload;
  63 +
  64 + const productInfo = state.products[productId];
  65 +
  66 + // 规格化数据
  67 + [['id', 'product_id'], ['price', 'least_price'], ['product_name'], ['default_images', 'goods_list[0].image_list[0].image_url']].forEach((keyMap) => {
  68 + const val = payload[keyMap[0]];
  69 +
  70 + if (val !== null) {
  71 + set(productInfo, keyMap[1] || keyMap[0], val);
  72 + if (keyMap[0] === 'default_images') {
  73 + set(productInfo, 'goods_list[0].image_list[0].initial', true); // 区分初始化数据,方便使用缓存
  74 + }
  75 + }
  76 + });
  77 + }
61 }; 78 };
1 export const UPDATE_PRODUCT_DETAIL = 'UPDATE_PRODUCT_DETAIL'; 1 export const UPDATE_PRODUCT_DETAIL = 'UPDATE_PRODUCT_DETAIL';
  2 +export const SETUP_INITIAL_PRODUCT_INFO = 'SETUP_INITIAL_PRODUCT_INFO';
2 export const ENSURE_PRODUCT_DETAIL = 'ENSURE_PRODUCT_DETAIL'; 3 export const ENSURE_PRODUCT_DETAIL = 'ENSURE_PRODUCT_DETAIL';
3 export const UPDATE_PRODUCT_FAV = 'UPDATE_PRODUCT_FAV'; 4 export const UPDATE_PRODUCT_FAV = 'UPDATE_PRODUCT_FAV';
4 export const UPDATE_SELECTED_PRODUCT_SIZE = 'UPDATE_SELECTED_PRODUCT_SIZE'; 5 export const UPDATE_SELECTED_PRODUCT_SIZE = 'UPDATE_SELECTED_PRODUCT_SIZE';