Authored by zhangwenxue

商品详情:调整state

... ... @@ -3,18 +3,18 @@
<LayoutHeader class="layout-header" :show-back="true">
<template>
<transition name="fade">
<img-size v-show="headThumbnailVisible" class="title-thumbnail" :src="imageList[0] && imageList[0].image_url" :width="300" :height="300"/>
<img-size v-show="headThumbnailVisible" class="title-thumbnail" :src="imageList && imageList[0] && imageList[0].image_url" :width="300" :height="300"/>
</transition>
</template>
<template #opts>
<cube-button class="icon-fav" :light="true" v-if="productDetail.isFav" @click="_toggleFav(true)">
<cube-button class="icon-fav" :light="true" v-if="productDetail.isFav" @click="_toggleFav(false)">
<svg id="icon-heart" style="width: 1rem; height: 1rem;" viewBox="0 0 28 28">
<title>heart</title>
<path d="M14 26c-0.25 0-0.5-0.094-0.688-0.281l-9.75-9.406c-0.125-0.109-3.563-3.25-3.563-7 0-4.578 2.797-7.313 7.469-7.313 2.734 0 5.297 2.156 6.531 3.375 1.234-1.219 3.797-3.375 6.531-3.375 4.672 0 7.469 2.734 7.469 7.313 0 3.75-3.437 6.891-3.578 7.031l-9.734 9.375c-0.187 0.187-0.438 0.281-0.688 0.281z"></path>
</svg>
</cube-button>
<cube-button class="icon-fav" :light="true" v-else @click="_toggleFav(false)">
<cube-button class="icon-fav" :light="true" v-else @click="_toggleFav(true)">
<svg id="icon-heart-o" style="width: 1rem; height: 1rem;" viewBox="0 0 28 28">
<title>heart-o</title>
<path d="M26 9.312c0-4.391-2.969-5.313-5.469-5.313-2.328 0-4.953 2.516-5.766 3.484-0.375 0.453-1.156 0.453-1.531 0-0.812-0.969-3.437-3.484-5.766-3.484-2.5 0-5.469 0.922-5.469 5.313 0 2.859 2.891 5.516 2.922 5.547l9.078 8.75 9.063-8.734c0.047-0.047 2.938-2.703 2.938-5.563zM28 9.312c0 3.75-3.437 6.891-3.578 7.031l-9.734 9.375c-0.187 0.187-0.438 0.281-0.688 0.281s-0.5-0.094-0.688-0.281l-9.75-9.406c-0.125-0.109-3.563-3.25-3.563-7 0-4.578 2.797-7.313 7.469-7.313 2.734 0 5.297 2.156 6.531 3.375 1.234-1.219 3.797-3.375 6.531-3.375 4.672 0 7.469 2.734 7.469 7.313z"></path>
... ... @@ -46,10 +46,9 @@
<img-size :src="sizeImg(resource.src)" :width="300" :height="60"/>
</a>
<div class="info-list">
<div class="info-list-item" v-if="activity && activity.length !== 0">
<div class="info-list-item" v-if="activity && activity.length !== 0" @click="showActivity">
<div class="info-list-name">促销</div>
<div class="info-list-value info-promote" @click="showActivity"
>
<div class="info-list-value info-promote">
<span>{{activity[0].promotionTypeStr}}</span>
<i class="cubeic-arrow"></i>
</div>
... ... @@ -166,16 +165,23 @@ export default {
},
},
beforeRouteUpdate(to, from, next) {
const loading = this.createLoading();
// const loading = this.createLoading();
this.loadData(to.params.productId, loading).then(next);
this.loadData(to.params.productId).then(next);
},
mounted() {
this.loadData(this.productId);
this.imageHideThreadhold = -window.innerWidth * 0.8;
},
activated() {
this.refresh();
},
methods: {
...mapActions(['fetchProductInfo', 'toggleFav', 'updateTradeInfo', 'getSelectedTradeProduct']),
refresh() {
this.$refs.slide.refresh();
this.headThumbnailVisible = false;
},
handleScroll(e) {
this.headThumbnailVisible = e.y < this.imageHideThreadhold;
},
... ... @@ -194,6 +200,9 @@ export default {
return this.fetchProductInfo({productId}).then(() => {
loading && loading.hide();
setTimeout(() => {
this.refresh();
}, 200);
}).catch(() => {
loading && loading.hide();
});
... ... @@ -217,9 +226,6 @@ export default {
onSizeSelectSheetHidden() {
this.showSizeSelectSheet = false;
},
gotoProduction(productId) {
this.$router.push({name: this.$route.name, params: {productId}});
},
buy() {
this.showBuySheet = true;
},
... ... @@ -234,6 +240,7 @@ export default {
name: 'OrderSellConfirm',
query: tradeProduct
});
this.showSizeSelectSheet = false;
},
onRequestSize() {
this.showSizeSelectSheet = false;
... ... @@ -283,6 +290,11 @@ export default {
}
}
.cube-slide-item {
img {
margin: 0 auto;
}
}
.banner {
padding: 20px 0 0;
display: block;
... ...
... ... @@ -3,26 +3,27 @@ import { get } from 'lodash';
export default {
async fetchProductInfo({commit}, {productId}) {
const queryTasks = ['', '/resource', '/activity', '/recommend'].map(path => {
const queryTasks = ['', '/fav', '/resource', '/activity', '/recommend'].map(path => {
return this.$api.get(`/api/ufo/product${path}`, {product_id: productId}).then(result => {
if (result.code === 200) {
return result.data;
} else {
throw new Error(result.message);
return null;
}
});
});
let [detail,resource, activity, recommend] = await Promise.all(queryTasks);
resource = [];
const [detail, isFav, resource, activity, recommend] = await Promise.all(queryTasks);
commit(Types.UPDATE_PRODUCT_DETAIL, Object.assign(detail.product_info, {
resource: get(resource, '[0].data[0]', null),
activity,
isFav,
activity: activity || [],
recommend: recommend && recommend.product_list || [],
}));
},
async toggleFav({commit}, {productId, isFav}) {
const result = await this.$api.get(`/api/ufo/product/${isFav ? 'add' : 'cancel'}`, {product_id: productId});
const result = await this.$api.get(`/api/ufo/product/${isFav ? 'add' : 'cancel'}`, {productId});
if (result && result.code === 200) {
commit(Types.UPDATE_PRODUCT_FAV, {productId, isFav});
... ... @@ -48,8 +49,7 @@ export default {
productId = parseInt(productId, 10);
storageId = parseInt(storageId, 10);
tradeTypeId = parseInt(tradeTypeId, 10);
if (!(state.selectedProductInfo && state.selectedProductInfo.productId === productId ||
state.products.byId[productId])) {
if (state.selectedProductInfo.productId !== productId && state.product.product_id !== productId) {
await dispatch('fetchProductInfo', {productId});
}
... ...
import actions from './actions';
import mutations from './mutations';
import { get } from 'lodash';
export default function() {
export function defaultState() {
return {
namespaced: true,
state: {
products: {
byId: {},
product: {
brand_name: '',
canPublishSecondHand: false,
gender: '通用',
goods_list: [
{
canAddSize: false,
color_name: '',
goods_id: null,
goods_name: '-',
image_list: [
],
size_list: [
]
}
],
least_price: null,
max_price: null,
max_sort_id: null,
min_price: null,
offer_price: null,
product_code: null,
product_id: null,
product_name: null,
sale_time: null,
sellerCanPublish: true,
series_name: null,
shelve_status: null,
resource: null,
activity: [],
recommend: [],
},
currentId: null,
/**
* 用户在商品详情页选择的交易信息
* productId: 商品id
* product: 商品详情
* sizeId: 尺寸id
* storageId: 库存id
* size: 尺寸信息
* tradeTypeId: 交易类型id
* tradeType: 交易类型
... ... @@ -29,30 +55,30 @@ export default function() {
tradeTypeId: null,
tradeType: {},
},
},
};
}
export default function() {
return {
namespaced: true,
state: defaultState(),
mutations,
actions,
getters: {
productDetail(state) {
return state.products.byId[state.currentId] || {};
return state.product;
},
imageList(state, getters) {
return get(getters.productDetail, 'goods_list[0].image_list', []);
imageList(state) {
return state.product.goods_list[0].image_list;
},
resource(state, getters) {
return get(getters.productDetail, 'resource', {});
resource(state) {
return state.product.resource;
},
activity(state, getters) {
return get(getters.productDetail, 'activity', []);
activity(state) {
return state.product.activity;
},
recommend(state, getters) {
const list = get(getters.productDetail, 'recommend', []);
if (list && list.length !== 0) {
return list;
}
return null;
recommend(state) {
return state.product.recommend;
},
selectedSize(state) {
return state.selectedProductInfo.size;
... ...
import * as Types from './types';
import {get, find } from 'lodash';
import { find } from 'lodash';
function ensureSelectedProduct(state, productId) {
if (!state.selectedProductInfo || state.selectedProductInfo.productId !== productId) {
state.selectedProductInfo = {
productId,
product: state.products.byId[productId],
product: state.product,
sizeId: null,
storageId: null,
size: {},
... ... @@ -17,31 +17,31 @@ function ensureSelectedProduct(state, productId) {
export default {
[Types.UPDATE_PRODUCT_DETAIL](state, payload) {
state.products.byId[state.currentId] = null;
state.currentId = payload.product_id;
state.products.byId[state.currentId] = payload;
ensureSelectedProduct(state, state.currentId);
state.product = payload;
ensureSelectedProduct(state, state.product.product_id);
},
[Types.UPDATE_PRODUCT_FAV](state, { productId, isFav}) {
if (state.products.byId[productId]) {
state.products.byId[productId].isFav = isFav;
if (state.product.product_id === productId) {
state.product.isFav = isFav;
}
},
[Types.UPDATE_SELECTED_RPODUCT_SIZE](state, { productId, sizeId, storageId}) {
ensureSelectedProduct(state, productId);
const sizeList = get(state.selectedProductInfo.product, 'goods_list[0].size_list', []);
const sizeList = state.selectedProductInfo.product.goods_list[0].size_list;
let sizeInfo;
if (storageId) {
sizeInfo = find(sizeList, (size) => size.storage_id === storageId) || {};
sizeInfo = find(sizeList, (size) => size.storage_id === storageId);
} else {
sizeInfo = find(sizeList, (size) => size.size_id === sizeId) || {};
sizeInfo = find(sizeList, (size) => size.size_id === sizeId);
}
if (sizeInfo) {
state.selectedProductInfo.sizeId = sizeInfo.size_id;
state.selectedProductInfo.storageId = sizeInfo.storage_id;
}
state.selectedProductInfo.size = sizeInfo;
},
[Types.UPDATE_SELECTED_TRADE_TYPE](state, { productId, tradeTypeId}) {
... ...
... ... @@ -2,5 +2,4 @@ export const UPDATE_PRODUCT_DETAIL = 'UPDATE_PRODUCT_DETAIL';
export const UPDATE_PRODUCT_FAV = 'UPDATE_PRODUCT_FAV';
export const UPDATE_SELECTED_RPODUCT_SIZE = 'UPDATE_SELECTED_RPODUCT_SIZE';
export const UPDATE_SELECTED_TRADE_TYPE = 'UPDATE_SELECTED_TRADE_TYPE';
export const PRODUCT_REQUEST_SIZE = 'PRODUCT_REQUEST_SIZE';
... ...
... ... @@ -25,7 +25,7 @@ module.exports = {
auth: true,
api: 'ufo.user.favoriteAdd',
params: {
product_id: {type: Number}, // 商品id
productId: {type: Number}, // 商品id
},
},
... ... @@ -33,9 +33,9 @@ module.exports = {
'/api/ufo/product/favorite/cancel': {
ufo: true,
auth: true,
api: 'ufo.user.ufo.user.favoriteCancel',
api: 'ufo.user.favoriteCancel',
params: {
product_id: {type: Number}, // 商品id
productId: {type: Number}, // 商品id
},
},
... ...