Authored by TaoHuang

Merge branch 'develop' of http://git.yoho.cn/fe/xianyu-ufo-app-web into develop

... ... @@ -35,7 +35,7 @@
</template>
<script>
import { get, find } from 'lodash';
import { get, find, findIndex } from 'lodash';
import { Style, Scroll, Sticky } from 'cube-ui';
import { createNamespacedHelpers } from 'vuex';
import queryString from 'querystring';
... ... @@ -58,6 +58,7 @@ export default {
PAGE_URL: '',
listYasParams: {},
homeYasParams: [],
listScrollY: 0,
options: {
pullUpLoad: true,
},
... ... @@ -106,10 +107,19 @@ export default {
};
},
computed: {
...mapState(['channelList']),
...mapState(['channelList','contentCode']),
navList() {
return get(find(this.channelList.list, ['template_name', 'guessLike']), 'data') || [];
},
navInfo() {
let index = findIndex(this.channelList.list, ['template_name', 'guessLike'])
let id = get(find(this.channelList.list, ['template_name', 'guessLike']), 'template_id')
return {
F_ID: id,
F_NAME: 'guessLike',
F_INDEX: index + 1
}
},
noItemStyle() {
return {
height: this.total + 'px'
... ... @@ -270,16 +280,36 @@ export default {
// console.log(this.listYasParams)
}
},
guessLikeListParams(params) {
if (params && typeof params === 'object' && Object.keys(params).length) {
this.listYasParams = Object.assign({}, {
P_NAME: 'XY_UFOHome',
P_PARAM: this.contentCode,
PAGE_URL: this.PAGE_URL,
...this.navInfo,
I_INDEX: Number(params.index) + 1,
TAB_ID: Number(params.index) + 1,
TAB_NAME: params.title});
console.log(this.listYasParams)
}
},
getIndex({index, params}) {
this.selectedCategory = params;
this.active = Number(index);
this.isShow && this.$refs.scroll.scrollTo(this.navTop);
this.setYasParam({index, ...params});
// this.setYasParam({index, ...params});
this.guessLikeListParams({index, ...params});
// 商品列表曝光
this.listScrollY > 0 && this.$refs.product && this.$refs.product.yasShowEvent(this.listScrollY);
},
scrollEndHandler({y}) {
let scrollHeight = Math.abs(y);
this.$refs.product && this.$refs.product.yasShowEvent(scrollHeight + this.navTop);
let viewHeight = this.$refs.scroll.$el.offsetHeight;
let productListTop = this.$refs.product && this.$refs.product.$el.offsetTop || this.navTop + this.navHeight;
let listScrollY = scrollHeight + viewHeight - productListTop;
this.listScrollY = listScrollY
// 商品列表曝光
listScrollY > 0 && this.$refs.product && this.$refs.product.yasShowEvent(listScrollY);
if (scrollHeight >= this.navTop) {
return;
}
... ... @@ -307,7 +337,8 @@ export default {
await this.fetchList(this.searchParams);
// 列表上报数据
this.setYasParam({index: 0, ...this.searchParams});
// this.setYasParam({index: 0, ...this.searchParams});
this.guessLikeListParams({index: 0, ...this.searchParams});
},
async onPullingUp() {
... ... @@ -369,8 +400,12 @@ export default {
} else {
list[key] = data[key];
}
if (!data.product_list) {
this.productList.list = [];
}
}
this.productList = list;
}
} catch (e) {
// console.log(e);
... ...
... ... @@ -49,6 +49,8 @@ export default {
...product,
price: product[this.priceKey], // 统一接收端使用的价格key
},
yasParams: this.yasParams,
}
});
},
... ...
... ... @@ -377,9 +377,10 @@ export default {
reportType: 'qiugou_buy',
type: 'buy',
back: {
name: 'ProductDetail',
name: 'buyOrderDetail',
params: {
productId: get(this.originProductData, 'productId', '')
owner: 'buy',
code: get(this.publishresult, 'orderCode', ''),
}
},
forward: {
... ...
... ... @@ -224,9 +224,10 @@ export default {
type: UserType.buy,
reportType: 'buy',
back: {
name: 'ProductDetail',
name: 'buyOrderDetail',
params: {
productId: this.productId
owner: UserType.buy,
code: result.data.orderCode
}
},
forward: {
... ...
... ... @@ -2,15 +2,15 @@
<div class="fee-detail">
<div class="item">
<div>平台费用:<i class="iconfont iconquestion icon-class" @click="onClick"></i></div>
<div>{{data.platformFee.amount || '¥0'}}</div>
<div>{{feeInfo.platformFee.amount || '¥0'}}</div>
</div>
<div class="item">
<div>银行转账费(1%):</div>
<div>{{data.bankTransferFee || '¥0'}}</div>
<div>{{feeInfo.bankTransferFee || '¥0'}}</div>
</div>
<div class="item">
<div class="total-fee">实际收入:</div>
<div class="fee">{{data.income || '¥0'}}</div>
<div class="fee">{{feeInfo.income || '¥0'}}</div>
</div>
<Modal ref="dialog" v-model="showModal">
... ... @@ -20,17 +20,17 @@
<div class="item item2">
<span>商品鉴定费</span>
<span>{{data.platformFee.appraiseFee}}</span>
<span>{{feeInfo.platformFee.appraiseFee}}</span>
</div>
<div class="item item2">
<span>商品包装费</span>
<span>{{data.platformFee.packageFee}}</span>
<span>{{feeInfo.platformFee.packageFee}}</span>
</div>
<div class="item item2">
<span>平台服务费({{data.platformFee.goodsPaymentRatePercent}})</span>
<span>{{data.platformFee.serviceFee}}</span>
<span>平台服务费({{feeInfo.platformFee.goodsPaymentRatePercent}})</span>
<span>{{feeInfo.platformFee.serviceFee}}</span>
</div>
<template slot="footer">
... ... @@ -58,7 +58,8 @@ export default {
data() {
return {
confirmBtn: {},
showModal: false
showModal: false,
feeInfo: this.$props.data || {platformFee: {}}
};
},
components: {
... ... @@ -67,7 +68,7 @@ export default {
},
methods: {
onClick() {
if (!this.data.income) {
if (!this.feeInfo.income) {
return this.$createToast({
txt: '没有价格',
time: 1500,
... ...
<template>
<div>
<div class="tip" v-if="!superSell">需支付保证金:<span class="red">{{data.earnestMoneyStr || '¥0'}}</span><i v-if="!hiddenIcon"
class="iconfont iconquestion icon-class"
@click="onClick"></i></div>
<div class="tip2">所有商品必须为国内现货,且承诺36小时内发货,交易成功后将自动退还保证金</div>
<div class="tip" v-if="!superSell">
需支付保证金:<span class="red">{{ earnestInfo.earnestMoneyStr || "¥0" }}</span>
<i
v-if="!hiddenIcon"
class="iconfont iconquestion icon-class"
@click="onClick"
></i>
</div>
<div class="tip2">
所有商品必须为国内现货,且承诺36小时内发货,交易成功后将自动退还保证金
</div>
</div>
</template>
<script>
export default {
name: 'OrderFee',
name: "OrderFee",
props: {
data: {
type: Object,
... ... @@ -31,13 +38,18 @@ export default {
},
url: {
type: String,
default: ''
default: ""
}
},
data() {
return {
earnestInfo: this.$props.data || {}
}
},
methods: {
onClick() {
if (this.url) {
this.$xianyu.goXianyuNewPage({url: this.url});
this.$xianyu.goXianyuNewPage({ url: this.url });
}
}
}
... ...
... ... @@ -3,7 +3,6 @@
<layout-app
:title="'\u200E'"
class="buyer-order-detail-wrapper"
:backAction="onBack"
>
<div class="order-detail-wrapper">
<div class="content">
... ...
... ... @@ -3,7 +3,6 @@
<layout-app
:title="'\u200E'"
class="seller-order-detail-wrapper"
:backAction="onBack"
>
<div class="order-detail-wrapper">
<div class="content">
... ...
... ... @@ -48,7 +48,16 @@ export default {
border-color: #f5f5f5;
}
/deep/ input::-webkit-input-placeholder {
font-size: 0.9rem;
padding: 0.2rem;
bottom: 0.4rem;
}
/deep/ .cube-input-field {
font-family: "DINAlternate-Bold", "ufofont", "PingFang-SC-Regular", sans-serif;
padding: 0.25rem;
font-size: 1rem;
color: #000;
}
}
... ...
... ... @@ -193,9 +193,10 @@ export default {
type: 'sell',
reportType: 'bianxian',
back: {
name: 'ProductDetail',
name: 'sellOrderDetail',
params: {
productId: get(this.originProductData, 'productId', '')
owner: 'sell',
code: get(this.publishinfo, 'orderCode', '')
}
},
forward: {
... ...
... ... @@ -380,9 +380,10 @@ export default {
type: UserType.sell,
reportType: 'sell',
back: {
name: 'ProductDetail',
name: 'sellOrderDetail',
params: {
productId: this.productId
owner: UserType.sell,
code: orderResult.data.orderCode
}
},
forward: {
... ...
<template>
<layout-app title="商品列表" class="brand-product-list">
<div class="scroll-view" ref="scroll">
<LayoutScroll
class="scroll-view"
@scroll-end="scrollEndHandler">
<div class="list-wrapper" v-if="brandProductList != null">
<product-list :list="brandProductList" priceKey="price"/>
<product-list ref="productList" :list="brandProductList" priceKey="price" :yas-params="recommendYasParams"/>
</div>
</div>
</LayoutScroll>
</layout-app>
</template>
... ... @@ -14,7 +16,7 @@ import ScrollView from 'components/layout/scroll-view';
import ProductList from '../list/components/productList';
const STORE_PATH = 'product';
const { mapActions, mapState } = createNamespacedHelpers(STORE_PATH);
const { mapState } = createNamespacedHelpers(STORE_PATH);
export default {
name: 'BrandProductList',
... ... @@ -35,6 +37,18 @@ export default {
observeDOM: false,
pullUpLoad: false,
},
/**
* 商品详情页-推荐商品曝光时
* XY_UFO_SHOW_EVENT
* 1.P_NAME:页面名称,UFOProductDetail_LIST;
* 2.P_PARAM:页面参数;
* 3.I_INDEX:曝光顺序;
* 4.PRD_SKN:商品id;
*/
recommendYasParams: {
P_NAME: 'UFOProductDetail_LIST',
},
};
},
computed: {
... ... @@ -52,9 +66,10 @@ export default {
}
},
methods: {
...mapActions(['fetchBrandTop']),
onPullingDown() {
this.fetchBrandTop({productId: this.productId});
scrollEndHandler({y}) {
const scrollTop = Math.abs(y);
this.$refs.productList && this.$refs.productList.yasShowEvent(scrollTop);
},
},
};
... ...
... ... @@ -8,10 +8,10 @@
:emulateMask="true"
:full="true">
<div class="buy-sheet">
<a class="header" @click.prevent="gotoNewPage">求购<i class="cubeic-question question"></i></a>
<a class="header" @click.prevent="gotoNewPage">求购<i class="iconfont iconquestion"></i></a>
<div class="title">
<div class="title-thumbnail">
<square-img :src="imageUrl" :width="300" :height="300"/>
<square-img :src="imageUrl" :width="600" :height="600"/>
</div>
<div>选择尺码填写理想的价格发布求购</div>
<div>{{productDetail.product_name}} {{goodsName}}</div>
... ... @@ -19,9 +19,9 @@
<div class="size-list">
<cube-scroll ref="scroll" :data="sizeViewList">
<ul>
<li :class="['size-item', item.available ? '': 'disable']" v-for="(item, idx) in sizeViewList" :key="idx" @click="buy(item)">
<li class="size-item" v-for="(item, idx) in sizeViewList" :key="idx" @click="buy(item)">
<div class="size"><span>{{item.name}}</span><span v-if="item.subName">{{item.subName}}</span></div>
<div class="price">最高求购价 ¥{{item.price}} <i class="cubeic-arrow"></i></div>
<div class="price">最高求购价 <span>¥{{item.price}}</span> <i class="cubeic-arrow"></i></div>
</li>
</ul>
</cube-scroll>
... ... @@ -75,7 +75,6 @@ export default {
size_name: info.size_name,
price,
storage_id: info.storage_id,
available: info.storage_num > 0 && price !== '-',
skup: info.skup,
least_price: info.least_price,
bid_moster_price: info.bid_moster_price,
... ... @@ -185,11 +184,11 @@ export default {
color: #999;
letter-spacing: 0;
text-align: right;
}
.question {
color: #ccc;
font-size: 28px;
.iconfont {
margin-left: 5px;
font-size: inherit;
}
}
.title-thumbnail {
... ... @@ -220,6 +219,7 @@ export default {
align-items: baseline;
font-size: 40px;
letter-spacing: 0;
@include num;
span:nth-child(2) {
... ... @@ -236,6 +236,12 @@ export default {
letter-spacing: 0;
text-align: right;
span {
margin-left: 5px;
@include num;
}
i {
display: inline-block;
margin-left: 5px;
... ...
... ... @@ -224,9 +224,6 @@ export default {
.size-scroll {
width: 100%;
position: absolute;
top: 0;
bottom: 0;
}
li {
... ... @@ -242,7 +239,7 @@ export default {
}
.size-price {
font-family: "PingFang SC", "HiraginoSansGB-W3", "SanFranciscoText-Regular", Helvetica, Roboto, "Heiti SC", "黑体", Arial;
font-family: $size-font;
}
&.selected {
... ... @@ -278,6 +275,7 @@ export default {
height: 0;
padding-bottom: 100%;
position: relative;
box-sizing: border-box;
}
.size {
... ...
... ... @@ -5,11 +5,11 @@
<div class="title" @click="hide">{{config.title}}<i class="cubeic-close"></i></div>
<div class="selected-info">
<div class="title-thumbnail">
<square-img :src="imageList[0] && imageList[0].image_url" :width="70" :height="70"/>
<square-img :src="imageList[0] && imageList[0].image_url" :width="600" :height="600"/>
</div>
<div class="product">
<div>
<template v-if="product.least_price >= 0"> ¥{{product.least_price}}</template>
<template v-if="selectedPrice != null && selectedPrice >= 0"> ¥{{selectedPrice}}</template>
<template v-else>&nbsp;</template>
</div>
<div>
... ... @@ -89,6 +89,23 @@ export default {
return {};
},
selectedPrice() {
let price = this.product.least_price;
if (this.config.type === 'sell') {
return price;
}
if (this.selectedSize.size_id > 0) {
if (this.selectedSize.least_price > 0) {
price = this.selectedSize.least_price;
} else {
price = '-';
}
}
return price;
},
goods_name() {
return get(this.product, 'goods_list[0].goods_name', '');
},
... ... @@ -201,6 +218,23 @@ export default {
bid_moster_price: get(this.selectedSize, 'bid_moster_price', ''),
});
/**
* 数据埋点
* 商品详情页点击出售/购买/求购按钮
* event: XY_UFO_PRD_DT_SALE_C
* params: 1.TAB_ID:1-出售,2-购买,3-求购, 4-变现;
* 2.PRD_ID:商品ID;
*/
this.$store.dispatch('reportYas', {
params: {
appop: 'XY_UFO_PRD_DT_BUY_SEL_C',
param: {
TAB_ID: 4,
PRD_ID: this.product.product_id,
},
}
});
// 跳转变现
this.$router.push({
name: 'sellAskOrder',
... ... @@ -249,7 +283,7 @@ export default {
height: 60vh;
}
}
.selected-info {
display: flex;
padding-bottom: 20px;
... ... @@ -353,7 +387,7 @@ export default {
}
.footer {
padding: 16px 0;
padding: 16px 0 0;
display: flex;
justify-content: space-between;
... ...
... ... @@ -7,7 +7,7 @@
<div class="row">
<div class="col" v-for="(product, idx) in viewList" :key="idx" @click="onItemClick(product)">
<div class="product-item">
<square-img :src="product.default_images" :width="300" :height="300" />
<square-img :src="product.default_images" :width="600" :height="600" />
</div>
<div class="name"><span>{{product.product_name}}</span></div>
<div class="price"><i>¥</i>{{product.price}}</div>
... ...
$primary-color : #08304b;
$sub-color : #64ad88;
$size-font: "PingFang SC", "HiraginoSansGB-W3", "SanFranciscoText-Regular", Helvetica, Roboto, "Heiti SC", "黑体", Arial, serif;
@mixin cube-ufo-btn {
[type="button"] {
box-sizing: border-box;
... ...
... ... @@ -2,7 +2,10 @@
<div class="layout">
<LayoutHeader class="layout-header" :show-back="true" :title="'\u200E'"></LayoutHeader>
<div class="layout-context fixscroll">
<div class="cube-scroll-wrapper" ref="pageScroll">
<LayoutScroll
ref="pageScroll"
class="cube-scroll-wrapper"
@scroll-end="scrollEndHandler">
<div class="slide">
<cube-slide ref="slide" :data="imageList">
<cube-slide-item v-for="(item, index) in imageList" :key="index">
... ... @@ -27,8 +30,8 @@
</div>
<div class="info-name"><div>{{productDetail.product_name}}</div></div>
</div>
<a class="banner" @click.prevent="gotoNewPage">
<img-size v-if="resource" ref="resourceImg" :src="sizeImg(resource.src)"/>
<a class="banner" v-show="resource" @click.prevent="gotoNewPage">
<img-size ref="resourceImg" :src="sizeImg(resource.src)"/>
</a>
<div class="info">
<transition-group name="info-list" tag="div" class="info-list">
... ... @@ -44,7 +47,8 @@
<div class="info-list-value">{{desc.value}}</div>
</div>
</transition-group>
<top-list v-if="topList && topList.length !== 0" :list="topList" @itemClick="gotoProduct" @allClick="gotoBrand" />
<!-- 相关商品 -->
<top-list ref="topList" v-if="topList && topList.length !== 0" :list="topList" @itemClick="gotoProduct" @allClick="gotoBrand" />
<img class="ref-img" v-lazy="prdDetailTip"/>
</div>
... ... @@ -53,7 +57,7 @@
<div class="recommend" v-if="recommend"><h2>相关推荐</h2>
<product-list ref="recommendList" :list="recommend" priceKey="price" :yas-params="recommendYasParams"/>
</div>
</div>
</LayoutScroll>
<div class="footer">
<div class="fav">
<div class="icon-fav" @click="_toggleFav">
... ... @@ -240,6 +244,28 @@ export default {
immediate: true,
});
}
// yas
/**
* 商品详情页打开时
* XY_UFO_PRD_DT_INFO
* 1.FP_NAME:来源页面名称;eg:XY_UFOSearchList,XY_UFOSeriesList,XY_UFOBrandList、XY_UFOProductPoolList、UFOProductDetail_LIST等;
* 2.FP_PARAM:页面参数;搜索关键词,系列ID,品牌ID,商品池ID;
* 3.TAB_ID:tab切id,1-人气,2-价格,3-新品;
* 4.TAB_NAME:tab切名称,人气,价格,新品;
* 5.PRD_ID:商品id;
*/
this.$store.dispatch('reportYas', {
params: {
appop: 'XY_UFO_PRD_DT_INFO',
param: {
FP_NAME: `XY_${this.$route.name}`,
FP_PARAM: this.productId,
PRD_ID: this.productId,
...this.$route.params.yasParams
},
}
});
},
deactivated() {
if (this._resourceImgWatcher) {
... ... @@ -247,7 +273,7 @@ export default {
this._resourceImgWatcher = null;
}
},
beforeRouteUpdate(to, from ,next) {
beforeRouteUpdate(to, from, next) {
if (this.historyBackGuard() === false) {
return next(false);
}
... ... @@ -277,6 +303,49 @@ export default {
refresh() {
this.$refs.slide && this.$refs.slide.refresh && this.$refs.slide.refresh();
},
scrollEndHandler({y}) {
const scrollTop = Math.abs(y);
const pageScrollHeight = this.$refs.pageScroll.$el.offsetHeight;
// 相关商品
if (!this._topListYas && this.$refs.topList) {
if (this._topListTop === undefined) {
this._topListTop = this.$refs.topList.$el.offsetTop;
}
if (scrollTop < this._topListTop && (scrollTop + pageScrollHeight) > this._topListTop) {
const DATA = this.topList.slice(0, 3).map((value, i) => {
return {...this.recommendYasParams, I_INDEX: i, PRD_ID: value.id, PRD_SKN: value.id};
});
this.$store.dispatch('reportYas', {
params: {
param: {DATA},
appop: 'XY_UFO_SHOW_EVENT'
}
});
this._topListYas = true;
}
}
// 推荐商品
if (this._productItemHeight === undefined) {
let item = document.querySelector('.product-list-item');
if (item) {
this._productItemHeight = item.offsetHeight;
}
}
if (this.$refs.recommendList) {
const listTop = this.$refs.recommendList.$el.offsetTop;
const productListScrollTop = scrollTop + pageScrollHeight - listTop - this._productItemHeight;
if (productListScrollTop > 0) {
this.$refs.recommendList.yasShowEvent(productListScrollTop);
}
}
},
yasResourceVisible() {
/**
* 商品详情页中的资源位曝光
... ... @@ -675,7 +744,6 @@ export default {
i {
font-style: normal;
font-size: 36px;
vertical-align: text-bottom;
}
}
... ... @@ -781,11 +849,10 @@ export default {
width: 3em;
color: #888;
font-size: 22px;
line-height: 32px;
.icon-star-fill,
.icon-star-outline {
font-size: 48px;
font-size: 42px;
}
.icon-star-outline {
... ...
... ... @@ -18,6 +18,7 @@ export default function() {
// scrollnavidList: [], // 导航菜单
current: 0,
},
contentCode: contentCode,
showMsg: false,
},
mutations: {
... ... @@ -58,7 +59,7 @@ export default function() {
list && list.map((item) => {
if (item.unReadCount > 0) {
state.showMsg = true;
}
}
});
},
},
... ...
... ... @@ -65,7 +65,7 @@ module.exports = (app) => {
cookie: {
domain: 'yohobuy.com',
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24 * 7 // 7
maxAge: 1000 * 60 * 60 * 24 * 30 // 30
},
store: new RedisStore(Object.assign(config.redis.session, {
logErrors: (e) => {
... ...