Authored by 郭成尧

Merge branch 'develop' of git.yoho.cn:fe/yohoblk-wap into develop

... ... @@ -10,3 +10,6 @@
<hr>
Cookies:<br>
{{{cookies}}}
<hr>
<input type="date">
... ...
... ... @@ -39,6 +39,12 @@ const component = {
res.render('index', _.merge(result, data[1]));
}).catch(next);
},
mydetails: (req, res) => {
res.render('mydetails', {
module: 'home',
page: 'mydetails'
});
},
help: (req, res, next) => {
homeModel.getHelpInfo().then(helpList => {
res.render('help', {
... ... @@ -104,8 +110,6 @@ const component = {
}
}).catch(next);
},
// 关于我们
aboutUs: (req, res) => {
res.render('about-us', {
module: 'home',
... ...
... ... @@ -33,7 +33,7 @@ const refund = {
res.render('logistics', {
module: 'home',
page: 'logistics',
company_list: result ? JSON.stringify(result.data) : ""
company_list: result ? JSON.stringify(result.data) : ''
});
}).catch(next);
},
... ...
... ... @@ -50,6 +50,7 @@ router.get('/exchange', exchange.exchange);
router.get('/exchange/order', exchange.order); // AJAX 获取订单 商品
router.get('/exchange/delivery', exchange.delivery); // AJAX 获取 退货方式
router.get('/mydetails', home.mydetails); // 个人信息设置
router.get('/about-us', home.aboutUs); // 个人中心 - 关于我们
... ...
<div class="personal-details" id="details">
<mydetails gender="women" birthday="1990.07.17"></mydetails>
</div>
... ...
... ... @@ -52,7 +52,7 @@ exports.fetchFilters = (req, res, next) => {
.then(result => {
let filterConfig = {};
if (result.code === 200) {
if (result.code === 200 || !result.hasOwnProperty('code')) {
prettyFilter(result.data.filter);
filterConfig = camelCase(result.data.filter);
}
... ...
/**
* 产品搜索 controller
* @author 陈轩 <xuan.chen@yoho.cn>
*/
'use strict';
const newModel = require('../models/new');
/* 最新商品 页面 */
exports.index = (req, res) => {
const view = {
module: 'product',
page: 'new'
};
res.render('new', view);
};
/* 获取 筛选配置 */
exports.fetchFilters = (req, res, next) => {
const params = Object.assign({
uid: req.user.uid,
page: 1,
order: 1,
yh_channel: 'all',
channel: 'all',
}, req.query);
newModel.getNewData(params).then(result => {
res.json(result);
}).catch(next);
};
/* 查询 产品列表 */
exports.fetchProducts = (req, res, next) => {
const params = Object.assign({
uid: req.user.uid,
page: 1,
order: 1
}, req.query);
newModel.getNewData(params).catch(next);
};
... ...
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
const prettyFilter = require(`${global.utils}/beautify/filters`);
const processProductList = require(`${global.utils}/beautify/product`);
/* 查询最新产品列表 */
exports.getNewData = (params) => {
params = Object.assign({
method: 'app.search.newProduct',
}, params);
api.post('', params, {
cache: true,
code: 200
}).then(result => {
if (result.data) {
result.data.productList = processProductList(result.data.productList);
result = camelCase(result);
}
return result;
});
};
/* 查询最新产品筛选条件 */
exports.getNewFilterData = (params) => {
params = Object.assign({
method: 'app.search.newProduct',
}, params);
api.post('', params, {
cache: true,
code: 200
}).then(result => {
let filterConfig = {};
if (result.data) {
prettyFilter(result.data.filter);
filterConfig = camelCase(result.data.filter);
}
return {
code: result.code,
data: filterConfig
};
});
};
... ...
... ... @@ -17,12 +17,14 @@ const search = require(`${cRoot}/search`);
router.get('/search', search.index);
router.get('/search.json', search.fetchProducts); // ajax
router.get('/new', search.index);
router.get('/new.json', search.fetchProducts);
// 产品 列表页
const productList = require(`${cRoot}/list`);
router.get('/list', productList.index);
router.post('/list', productList.fetchProducts);
router.get('/list.json', productList.fetchProducts);
router.get('/filter', productList.subFilter);
router.get('/filters.json', productList.fetchFilters);
... ...
{{! 筛选的 二级菜单}}
<div id="filter-sub">
<filter-sub :data="data" :val="val" type="color"><filter-sub>
<filter-sub :data="data" :val="val" :type="type"><filter-sub>
</div>
\ No newline at end of file
... ...
<div id="product-new"></div>
... ...
... ... @@ -15,8 +15,8 @@ module.exports = {
port: 6004,
siteUrl: '//m.yohoblk.com',
domains: {
api: 'http://192.168.102.205:8080/gateway/',
service: 'http://192.168.102.205:8080/gateway/'
api: 'http://devapi.yoho.cn:58078/',
service: 'http://devservice.yoho.cn:58077/'
},
subDomains: {
host: '.m.yohoblk.com',
... ...
... ... @@ -7,9 +7,7 @@ require('common/vue-filter');
Vue.use(lazyload);
new Vue({
el: '#exchange',
components: {
exchange
}
});
new Vue(exchange);
// Global variable: 全局常量 只允许读, 不允许写!!!!!!! exchange created的时候设置
global.store = {};
... ...
const Vue = require('yoho-vue');
const Mydetails = require('home/mydetails.vue');
new Vue({
el: '#details',
components: {
Mydetails
}
});
... ...
... ... @@ -3,12 +3,291 @@ const filterSub = require('component/product/filter/filter-sub.vue');
// TODO: 该mock数据 应该有 上级页面传过来
const page = {
type: 'brand', // 二级筛选的 类型
data: [ // 二级筛选的 数据
{ id: 1, name: '红色' },
{ id: 2, name: '红色' },
{ id: 3, name: '红色' }
],
// 二级筛选的 类型
type: 'brand',
// data: [ // 二级筛选的 数据
// { id: 1, name: '红色' },
// { id: 2, name: '红色' },
// { id: 3, name: '红色' }
// ],
data: [{
domain: 'converse',
alif: 'C',
ico: 'http://img12.static.yhbimg.com/brandLogo/2015/12/09/14/02752d2839e7001a09ecf71dcc9a996387.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'converse',
keyword: 'converse,街头,摇滚,百搭,朋克,简约,个性,自然,潮流,环保',
id: 27,
hotKeyword: 'converse',
isHot: 'Y',
nameEn: 'converse',
nameCn: '匡威'
}, {
domain: 'eightguys',
alif: 'E',
ico: 'http://img11.static.yhbimg.com/brandLogo/2013/07/02/19/01959c3b33245e16e786bda6b1e91234be.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Eight Guys',
keyword: '8Guys,八个男人',
id: 396,
hotKeyword: '',
isHot: 'Y',
nameEn: 'eight guys',
nameCn: 'Eight Guys'
}, {
domain: 'soulandsole',
alif: 'S',
ico: 'http://img13.static.yhbimg.com/brandLogo/2014/01/27/11/02cfe4044dfb82230c1868211b814d6192.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'SOUL&SOLE',
keyword: '',
id: 335,
hotKeyword: '',
isHot: '',
nameEn: 'SOUL&SOLE ',
nameCn: 'SOUL&SOLE '
}, {
domain: 'thething',
alif: 'T',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/12/09/16/018d25bf4481ed2998bf33b294673a8535.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'THETHING',
keyword: 'thething,tee,polo,衬衫,裤类,包类,配件类',
id: 138,
hotKeyword: 'thething',
isHot: 'Y',
nameEn: 'THETHING',
nameCn: 'THETHING'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'roxy',
alif: 'R',
ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Roxy',
keyword: 'roxy',
id: 273,
hotKeyword: '',
isHot: '',
nameEn: 'Roxy',
nameCn: 'Roxy'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}, {
domain: 'natkiel',
alif: 'N',
ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
name: 'Natkiel',
keyword: '奈凯儿',
id: 393,
hotKeyword: '',
isHot: 'N',
nameEn: 'Natkiel',
nameCn: 'Natkiel'
}],
val: 3 // 二级筛选 的值
};
... ... @@ -25,5 +304,3 @@ new Vue({
filterSub
}
});
... ...
const Vue = require('yoho-vue');
const search = require('product/search/index.vue');
new Vue(search);
... ...
.personal-details {
width: 100%;
height: auto;
overflow: hidden;
margin-top: 20px;
background-color: #fff;
ul {
width: 95%;
height: auto;
overflow: hidden;
float: right;
li {
&:first-of-type {
height: 100px;
line-height: 100px;
}
height: 80px;
border-bottom: 1px solid #e0e0e0;
.details-icon {
float: right;
height: 90px;
margin-right: 15px;
.icon {
vertical-align: middle;
color: #b0b0b0;
}
}
.user-avatar {
display: inline-block;
width: 100%;
height: 100%;
background-image: resolve("home/user-icon.png");
background-size: 100%;
}
.head-portrait {
width: 90px;
height: 90px;
overflow: hidden;
border-radius: 50%;
border: 1px solid #eee;
vertical-align: middle;
}
> label {
width: 100%;
height: 100%;
line-height: 80px;
font-size: 32px;
margin-right: 8%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
display: inline-block;
.details-nickname,
.details-gender,
.details-birthday {
text-align: right;
float: right;
margin-right: 40px;
color: #b0b0b0;
}
}
}
}
}
... ...
... ... @@ -2,6 +2,7 @@
@import "help";
@import "feedback";
@import "fav";
@import "details";
@import "about-us";
@import "coin";
@import "logistics";
... ...
... ... @@ -36,7 +36,7 @@
$.ajax({
url: '/channel/channel.json'
}).then(res => {
if (res.data.length) {
if (res.data && res.data.length) {
const channel = [];
res.data.forEach(c => {
... ...
... ... @@ -22,7 +22,7 @@
<feature-options name="size" :options="sizes" :selection="selection.size"></feature-options>
</section>
<button @click="addToCart()"
class="button button-solid add-to-cart">加入购物袋
class="button button-solid add-to-cart">{{config.btnTxt || '加入购物袋'}}
</button>
</div>
</div>
... ... @@ -139,7 +139,9 @@
*
* @param result 后端返回的数据
*/
onAddToCart: Function
onAddToCart: Function,
config: Object
},
watch: {
isVisible() {
... ... @@ -283,7 +285,6 @@
*/
addToCart() {
// console.log(`${this.selection.color}:${this.selection.size}`);
const sku = this.selection.size;
if (!this.selection.color) {
tip('请选择颜色');
... ... @@ -295,12 +296,7 @@
return;
}
$.post('/product/cart.json', {
productSku: sku,
buyNumber: 1
}).then((result)=> {
this.onAddToCart(result);
});
this.onAddToCart(this.selection, this.entity.pid);
}
}
};
... ...
... ... @@ -9,6 +9,7 @@
<div class="item-inner">{{brand.name}}</div>
</dd>
</dl>
<index-list :index-list="indexList"></index-list>
</div>
</template>
<script>
... ... @@ -20,6 +21,7 @@
* }
*/
const $ = require('yoho-jquery');
const indexList = require('component/tool/index-list.vue');
module.exports = {
props: {
... ... @@ -29,7 +31,7 @@
// 以brand.alif 分组
const res = {};
$.each(data, brand => {
$.each(data, (index, brand) => {
let groupName = brand.alif;
if (!res.hasOwnProperty(groupName)) {
... ... @@ -38,6 +40,8 @@
res[groupName].push(brand);
});
return res;
}
}
},
... ... @@ -45,6 +49,22 @@
select: function(val) {
this.val = val;
}
},
computed: {
indexList() {
var arr = [];
$.each(this.data, (key, val) => {
arr.push({
index: key,
name: key
});
});
return arr;
}
},
components: {
indexList
}
};
... ...
... ... @@ -2,6 +2,7 @@
<div>
<brand-filter v-if="type === 'brand'" :data="data" :val.sync="val"></brand-filter>
<normal-filter v-else :data="data" :val.sync="val">
</normal-filter>
</div>
</template>
... ...
<template>
<div class="refund">
<div class="title">请选择换货商品</div>
<!--商品列表-->
<product-list v-bind:list="goods" v-bind:data="exchangeData"></product-list>
<div>
<exchange-item v-for="good in selectedGoods" :product="good"></exchange-item>
</div>
<div>
<product-list v-bind:list="goods" v-bind:data="exchangeData" type="exchange"></product-list>
</div>
<!--换货信息-->
<div class="list exchange-info">
<!--address-->
... ... @@ -23,19 +27,34 @@
</select>
</div>
</div>
<feature-selector
:is-visible="showFeatureSelector"
:entity="entity"
:on-add-to-cart="whenFeatureChange"
:config="{btnTxt:'确定'}">
</feature-selector>
</div>
</template>
<script>
const $ = require('yoho-jquery');
const qs = require('yoho-qs');
const bus = require('common/vue-bus');
const productList = require('home/refund/product-list.vue');
const productList = require('home/return/list.vue');
const exchangeItem = require('home/exchange/item.vue');
const featureSelector = require('component/product/feature-selector.vue');
module.exports = {
el: '#exchange',
data() {
return {
title: '请选择换货商品',
page: 'exchange',
showFeatureSelector: false,
entity: {},
exchangeData: {},
goods: [],
address: {},
delivery: [],
... ... @@ -57,7 +76,19 @@
});
}
},
events: {
'feature.close': function() {
this.showFeatureSelector = false;
}
},
created() {
// 打开 更换 颜色尺码
bus.$on('open.featureSelector', msg => {
this.showFeatureSelector = true;
this.queryProductFeature(msg.pid);
});
// 获取 换货商品
$.ajax({
url: '/home/exchange/order',
data: {
... ... @@ -68,7 +99,6 @@
if (res.data && res.data.goodsList) {
res.data.goodsList.forEach((product, index) => {
product.checked = false;
product.reason = {
id: 0
};
... ... @@ -78,15 +108,45 @@
});
this.goods = res.data.goodsList;
this.exchangeData = res.data;
this.$set('exchangeData', res.data);
this.$set('address', res.data.address);
// 全局只读变量 放入 全局对象
const arr = [];
res.data.specialExchangeReason.forEach(obj => arr.push(obj.id));
global.store.reasons = [{
id: 0,
name: '请选择'
}].concat(res.data.exchangeReason);
global.store.specialReasons = arr;
global.store.specialNotice = res.data.specialNoticeBo;
}
});
},
methods: {
changeAddress: function() {
changeAddress() {
alert('TODO:更换地址');
},
// 商品 feature改变
whenFeatureChange(selection, pid) {
const index = this.indexMap[pid];
this.showFeatureSelector = false;
this.goods[index]._change = {
};
},
// 查询 商品 feature
queryProductFeature(pid) {
$.get(`/product/product_${pid}.json`).then(result => {
this.entity = result;
this.entity.id = pid;
return result;
});
},
submit() {
if (!this.checkSubmitData()) {
alert('请填写完整退换货信息');
... ... @@ -108,23 +168,26 @@
// area code 改变,重新获取 换货方式
'address.areaCode': function(newVal, oldVal) {
const self = this;
$.get('/home/exchange/delivery', {
areaCode: newVal
})
.then(result => {
$.each(result.data, (index, obj) => {
if (obj.isDefault === 'Y') {
self.$set('deliveryType', obj.id);
return false;
}
});
self.$set('delivery', result.data);
areaCode: newVal
})
.then(result => {
$.each(result.data, (index, obj) => {
if (obj.isDefault === 'Y') {
self.$set('deliveryType', obj.id);
return false;
}
});
self.$set('delivery', result.data);
});
}
},
components: {
productList
productList,
exchangeItem,
featureSelector
}
};
... ...
<template>
<div class="return-form exchange-form">
<product :product="product"></product>
<div class="field" @click="openFeatureSelector(product.productId)">
换货的颜色尺码
<div class="right">
<span></span>
<i class="icon icon-right"></i>
</div>
</div>
<reason :product="product">
<span slot="type">换货原因</span>
</reason>
</div>
</template>
<script>
/**
* exchange form
* 1. 产品信息
* 2. 更换产品 款式
* 3. 换货 原因
*/
const product = require('home/return/item.vue');
const reason = require('home/return/reason.vue');
const bus = require('common/vue-bus');
module.exports = {
props: {
product: Object,
readyonly: Boolean,
reasons: Array,
specialReason: Array
},
components: {
product,
reason
},
methods: {
openFeatureSelector(pid) {
bus.$emit('open.featureSelector', {
pid,
uid: this._uid
});
}
}
};
</script>
<style>
.return-form {
.field {
position: relative;
height: 90px;
line-height: 90px;
padding: 0 30px;
background-color: #fff;
font-size: 32px;
&:after {
position: absolute;
z-index: 1;
content: "";
display: block;
right: 30px;
bottom: -1px;
left: 30px;
border-bottom: 1px solid #eee;
}
}
.field .right {
color: #b0b0b0;
}
}
</style>
... ...
... ... @@ -36,7 +36,7 @@
props: ['brandUrl'],
data() {
return {
nullbox : 'hide',
nullbox: 'hide',
busy: false,
editmodel: false,
page: 0,
... ... @@ -46,13 +46,13 @@
methods: {
loadMore: function() {
let _this = this;
this.busy = true;
this.busy = true;
$.ajax({
url: '/home/favorite/favpaging',
data: {
page : ++_this.page,
tab : "brand"
page: ++_this.page,
tab: 'brand'
}
}).then(result => {
if (result.isend) {
... ... @@ -62,12 +62,12 @@
}
if (result.list.length) {
result.list.forEach(function(o){
result.list.forEach(function(o) {
_this.brandData.push(o);
});
}
_this.nullbox = _this.brandData.length ? "hide" : "";
_this.nullbox = _this.brandData.length ? 'hide' : '';
}).fail(() => {
tip('网络错误');
});
... ... @@ -80,17 +80,19 @@
},
showDelBtn(index) {
this.hideDelBth();
var delBtn = $("#del-" + index);
var width = delBtn.width();
$("#li-" + index).css("transform","translateX(-" + width + "px)");
let delBtn = $('#del-' + index);
let width = delBtn.width();
$('#li-' + index).css('transform', 'translateX(-' + width + 'px)');
},
hideDelBth() {
this.brandData.forEach(function(d, index){
$("#li-" + index).css("transform","translateX(0px)");
})
this.brandData.forEach(function(d, index) {
$('#li-' + index).css('transform', 'translateX(0px)');
});
},
delItem(index, id) {
let _this = this;
$.ajax({
method: 'POST',
url: '/home/del-favdel',
... ...
... ... @@ -44,7 +44,7 @@
props: ['productUrl'],
data() {
return {
nullbox : 'hide',
nullbox: 'hide',
busy: false,
editmodel: false,
page: 0,
... ... @@ -54,12 +54,12 @@
methods: {
loadMore: function() {
let _this = this;
this.busy = true;
this.busy = true;
$.ajax({
url: '/home/favorite/favpaging',
data: {
page : ++_this.page
page: ++_this.page
}
}).then(result => {
if (result.isend) {
... ... @@ -69,12 +69,12 @@
}
if (result.list.length) {
result.list.forEach(function(o){
result.list.forEach(function(o) {
_this.productData.push(o);
});
}
_this.nullbox = _this.productData.length ? "hide" : "";
_this.nullbox = _this.productData.length ? 'hide' : '';
}).fail(() => {
tip('网络错误');
});
... ... @@ -87,17 +87,19 @@
},
showDelBtn(index) {
this.hideDelBth();
var delBtn = $("#del-" + index);
var width = delBtn.width();
$("#li-" + index).css("transform","translateX(-" + width + "px)");
let delBtn = $('#del-' + index);
let width = delBtn.width();
$('#li-' + index).css('transform', 'translateX(-' + width + 'px)');
},
hideDelBth() {
this.productData.forEach(function(d, index){
$("#li-" + index).css("transform","translateX(0px)");
})
this.productData.forEach(function(d, index) {
$('#li-' + index).css('transform', 'translateX(0px)');
});
},
delItem(index, id) {
let _this = this;
$.ajax({
method: 'POST',
url: '/home/del-favdel',
... ...
<template>
<ul>
<li>
<label>头像
<span class="details-icon">
<span class="head-portrait user-avatar" data-avatar="{{head_ico}}"></span>
<span class="icon icon-right"></span>
</span>
</label>
</li>
<li>
<label>昵称<input class="details-nickname" v-model='nickname'></label>
</li>
<li>
<label>性别<span class="details-gender">{{ gender }}</span></label>
</li>
<li>
<label>生日<span class="details-birthday">{{ birthday }}</span></label>
</li>
</ul>
</template>
<script>
module.exports = {
props: ['head_ico', 'nickname', 'gender', 'birthday'],
data() {
return {
};
}
};
</script>
... ...
<template>
<div class="refund">
<div class="title">请选择退货商品</div>
<product-list v-bind:list="list" v-bind:refund-data="refundData"></product-list>
<product-list v-bind:list="list" v-bind:data="refundData"></product-list>
<div class="return-amount">
<!-- TODO:退货信息优化为组件 -->
<div class="return-amount-item">
... ... @@ -110,7 +110,7 @@
}
});
this.list = res.data.goodsList;
this.refundData = res.data;
this.$set('refundData', res.data);
}
});
},
... ...
... ... @@ -14,7 +14,6 @@
</template>
<script>
const $ = require('yoho-jquery');
const indexList = require('component/tool/index-list.vue');
module.exports = {
... ... @@ -31,28 +30,32 @@
},
methods: {
search: function() {
var inputname = this.inputname;
let inputname = this.inputname;
if (!inputname) {
this.showData = this.company_list;
return;
}
var filter = {};
for (var k in this.company_list) {
this.company_list[k].forEach(function(d){
let filter = {};
for (let k in this.company_list) {
this.company_list[k].forEach(function(d) {
if (d.company_name.indexOf(inputname) > -1) {
if (!filter[k]) filter[k] = [];
if (!filter[k]) {
filter[k] = [];
}
filter[k].push(d);
}
})
});
}
this.showData = filter;
},
select: function(company_id, company_name) {
select: function(companyId, companyName) {
this.$dispatch('changeView', {
view: 'logistics',
company_id: company_id,
company_name: company_name
company_id: companyId,
company_name: companyName
});
// 重置列表
... ...
... ... @@ -26,19 +26,19 @@
};
},
methods: {
companylist: function(){
companylist: function() {
this.$dispatch('changeView', {
view: 'logisticsCompany'
});
},
submit: function(){
submit: function() {
if (!this.company_name) {
tip("请选择快递公司");
tip('请选择快递公司');
return false;
}
if (!this.num || !/^[0-9]*$/.test(this.num)) {
tip("请输入正确的快递单号");
return false;
tip('请输入正确的快递单号');
return false;
}
$.ajax({
... ... @@ -50,7 +50,7 @@
num: this.num
}
}).then(function(res) {
if ($.type(res) !== 'object') {
if ($.type(res) !== 'object') {
res = {};
}
if (res.code !== 200) {
... ... @@ -67,4 +67,4 @@
}
};
</script>
\ No newline at end of file
</script>
... ...
... ... @@ -139,7 +139,7 @@
border-bottom: 1px solid #eee;
}
span,
.icon,
select {
direction: rtl;
float: right;
... ...
<template>
<div>
<product></product>
</div>
</template>
\ No newline at end of file
... ...
# 退换货 业务组件的 公用组件
* item.vue
* list.vue 退换货 申请的中间部分
* reason.vue 退换货 原因
\ No newline at end of file
... ...
<template>
<div class="product clearfix">
<div class="checkbox">
<input type="checkbox" v-model="product.checked" id="checkbox-{{product.goodsId}}">
<label for="checkbox-{{product.goodsId}}"></label>
</div>
<img class="image" v-bind:src="product.goodsImage | resize 100 130">
<div class="info">
<div class="p-title">
{{product.productName}}{{product.productName}}{{product.productName}}{{product.productName}}
</div>
<div class="meta">
<span class="color">颜色: {{product.colorName}}</span>
<span class="size">尺码: {{product.sizeName}}</span>
</div>
</div>
<div class="price">
&yen;{{product.lastPrice}}
<p class="num">
x1
</p>
</div>
</div>
</template>
<script>
const reason = require('home/refund/reason.vue');
module.exports = {
props: {
product: Object
},
components: {
reason
},
created() {
// 经过该组件, 给product 添加 checked属性
if (!this.product.hasOwnProperty('checked')) {
this.$set('product.checked', false);
}
}
};
</script>
<style>
.product {
position: relative;
padding: 0 30px;
height: 170px;
font-size: 24px;
line-height: 1.5;
background: #fff;
&:after {
content: "";
position: absolute;
left: 30px;
bottom: -1px;
width: 690px;
height: 0;
border-bottom: 1px solid #eee;
z-index: 1;
}
.checkbox {
float: left;
margin-top: 67px;
label:before {
border-radius: 100%;
}
}
.image {
float: left;
margin: 20px;
width: 100px;
height: 130px;
}
.info {
padding: 15px 0;
width: 520px;
.p-title {
color: #000;
font-size: 24px;
height: 72px;
overflow: hidden;
}
.meta {
margin-top: 10px;
color: #b0b0b0;
}
.color {
margin-right: 30px;
}
}
.price {
position: absolute;
top: 15px;
right: 30px;
text-align: right;
.num {
color: #b0b0b0;
}
}
}
</style>
... ...
<template>
<div>
<div v-show="checkedList.length" class="product-list product-list-checked">
<div v-for="product in list" v-if="product.checked">
<component :is = 'selectView' v-for="product in list" v-if="product.checked" v-bind:product="product" v-bind:data="data"></component>
</div>
</div>
<div v-show="checkedList.length !== list.length" class="product-list">
<pruduct v-for="product in list" v-if="!product.checked" v-bind:product="product" v-bind:data="data"></pruduct>
</div>
</div>
</template>
<script>
const pruduct = require('home/return/item.vue');
const exchangeItem = require('home/exchange/item.vue');
const refundItem = require('home/refund/product-list.vue');
module.exports = {
props: ['list', 'data', 'type'],
data() {
return {};
},
computed: {
selectedView() {
return this.type === 'exchange' ? 'exchange-item' : 'refund-item';
},
checkedList() {
return this.list.filter(product => {
return product.checked;
});
}
},
components: {
pruduct,
exchangeItem,
refundItem
}
};
</script>
<style>
.title {
padding: 30px 30px 0;
color: #b0b0b0;
font-size: 28px;
line-height: 60px;
}
.product-list {
margin-top: -4px;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
}
</style>
... ...
<template>
<div v-if="product.checked" class="reason">
<div v-if="product.isLimitSkn === 'Y'" v-on:click="showTip" class="tip">
<span class="icon icon-love"></span>
{{specialNotice.title}}
</div>
<div class="select-reason">
<slot name="type">退货原因</slot>
<span class="icon icon-right"></span>
<select v-model="product.reason.id" name="reason">
<option v-for="reason in reasons" v-bind:value="reason.id" selected="{{reason.id === product.reason.id}}">{{reason.name}}</option>
</select>
</div>
<div class="remark">
<textarea v-model="product.remark" rows="3" max-length="100" placeholder="原因说明"></textarea>
</div>
<div v-show="specialReasons.indexOf(product.reason.id) !== -1" class="image-list clearfix">
<div class="image-item" v-for="image in imageListForShow">
<span v-on:click="deleteImage(image.index)" class="icon icon-close"></span>
<img v-bind:src="image.path">
</div>
<upload v-show="imageListForShow.length < 4" class="image-item" v-bind:image-list="product.imageList"></upload>
</div>
</div>
</template>
<script>
const upload = require('component/tool/upload.vue');
const getImgHost = function(url) {
let urlArr = url.split('/'),
num = urlArr[urlArr.length - 1].substr(1, 1),
domain = 'static.yhbimg.com/goodsimg';
url = domain + url;
if (num === '1') {
return '//img11.' + url;
} else {
return '//img12.' + url;
}
};
module.exports = {
props: ['product', 'data'],
data() {
return {
reasons: [],
specialReasons: [],
specialNoticeBo: {}
};
},
computed: {
imageListForShow() {
const list = [];
this.product.imageList.forEach((path, index) => {
list.push({
index: index,
path: getImgHost(path) + '?imageView2/2/w/160/h/160'
});
});
return list;
}
},
methods: {
showTip() {
alert(this.specialNotice.remark);
},
deleteImage(index) {
this.product.imageList.splice(index, 1);
}
},
components: {
upload
},
created() {
this.$set('reasons', global.store.reasons);
this.$set('specialReasons', global.store.specialReasons);
this.$set('specialNoticeBo', global.store.specialNoticeBo);
}
};
</script>
<style>
.reason {
font-size: 32px;
line-height: 90px;
background: #f6f6f6;
&:after {
content: "";
display: block;
width: 100%;
height: 30px;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
}
.tip {
position: relative;
padding: 0 30px;
font-size: 26px;
background: #fff;
.icon {
margin-right: 5px;
}
&:after {
content: "";
position: absolute;
left: 0;
bottom: -1px;
width: 690px;
height: 0;
border-bottom: 1px solid #eee;
}
}
.select-reason {
position: relative;
padding: 0 30px;
width: 100%;
height: 90px;
background: #fff;
&:after {
content: "";
position: absolute;
left: 0;
bottom: -1px;
width: 690px;
height: 0;
border-bottom: 1px solid #eee;
}
.icon,
select {
direction: rtl;
float: right;
height: 90px;
line-height: 90px;
color: #b0b0b0;
}
}
.remark {
margin-top: 20px;
padding: 0 30px;
background: #fff;
border-top: 1px solid #eee;
textarea {
margin-top: 30px;
width: 100%;
font-size: 24px;
line-height: 40px;
resize: none;
border: 0;
}
}
.image-list {
padding: 30px;
background: #fff;
.image-item {
position: relative;
float: left;
margin-right: 20px;
width: 150px;
height: 150px;
&:last-child {
margin-right: 0;
}
.icon-close {
position: absolute;
right: -20px;
top: -20px;
font-size: 40px;
color: #fff;
background: #b0b0b0;
border-radius: 100%;
z-index: 2;
}
img {
width: 100%;
height: 100%;
}
}
.label-input {
position: relative;
width: 150px;
height: 150px;
font-size: 150px;
&:before {
content: "\e604";
}
input {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 0;
opacity: 0;
}
}
}
}
</style>
... ...
... ... @@ -412,16 +412,21 @@
*
* @param result
*/
onAddToCart: (result)=> {
// TODO: 库存不足 后台暂未实现
// TODO: 商品已下架 后台暂未实现
if (result.code === 200) {
this.cartCount = result.data.goods_count;
this.showFeatureSelector = false;
} else {
this.showFeatureSelector = false;
tip('系统异常,请稍后重试');
}
onAddToCart: (selection)=> {
$.post('/product/cart.json', {
productSku: selection.size,
buyNumber: 1
}).then((result)=> {
// TODO: 库存不足 后台暂未实现
// TODO: 商品已下架 后台暂未实现
if (result.code === 200) {
this.cartCount = result.data.goods_count;
this.showFeatureSelector = false;
} else {
this.showFeatureSelector = false;
tip('系统异常,请稍后重试');
}
});
}
};
},
... ...
... ... @@ -32,7 +32,7 @@
filterConfig: global.filterConfig,
// query
url: 'search',
url: '/product/list.json',
sort: null,
filter: {},
page: 0, // 未搜索 page=0; 全部加载完 page = totalPage; 无数据: page !=0 && productList.length=0
... ... @@ -67,7 +67,7 @@
this.inSearching = true;
console.log(nextPage);
$.post(this.url, {
$.get(this.url, {
sort: this.sort,
filter: this.filter,
page: nextPage
... ... @@ -118,8 +118,11 @@
self.search();
});
bus.$on('sort.change', function({ val }) {
console.log(val); self.sort = val;
bus.$on('sort.change', function({
val
}) {
console.log(val);
self.sort = val;
});
/**
... ... @@ -140,7 +143,9 @@
* 1. 打开view
* 2. 监听 router.back ,重新设置 筛选值
*/
bus.$on('filter.sub.show', function({val}) {
bus.$on('filter.sub.show', function({
val
}) {
self.openFilterSub(val);
});
... ... @@ -150,4 +155,6 @@
</script>
<style>
</style>
... ...
<template>
<div>
<template v-if="productList.length">
<Sort :config="sortConfig" :val="sort">
</Sort>
<List :data="productList"></List>
</template>
<div class="empty-tip" v-if="empty">
<i class="icon icon-search"></i>
<p class="empty-tip-cn">未找到相关商品</p>
<p class="empty-tip-en">Did not find the relevant goods</p>
</div>
</div>
</template>
<script>
const Vue = require('yoho-vue');
const lazyload = require('yoho-vue-lazyload');
const infinitScroll = require('yoho-vue-infinite-scroll');
const qs = require('yoho-qs');
const bus = require('common/vue-bus');
const tip = require('common/tip');
const sort = require('component/product/sort.vue');
const list = require('component/product/list.vue');
Vue.use(lazyload);
Vue.use(infinitScroll);
require('common/vue-filter');
module.exports = {
el: '#product-new',
data: function() {
return {
sortConfig: global.sortConfig,
filterConfig: global.filterConfig,
// query
url: '/product/search.json',
sort: null,
query: qs.query,
page: 0, // 未搜索 page=0; 全部加载完 page = totalPage; 无数据: page !=0 && productList.length=0
totalPage: null,
// 产品列表
productList: [],
// state
inSearching: false // 请求中
};
},
computed: {
// 无数据
empty: function() {
return this.page !== 0 && !this.productList.length;
}
},
components: {
list,
sort
},
methods: {
search: function() {
const self = this;
const nextPage = this.page + 1;
if (this.inSearching) {
return;
}
// page = 0, 始终执行搜索
if (this.page && nextPage > this.totalPage) {
return;
}
this.inSearching = true;
console.log(nextPage);
$.get(this.url, {
order: this.sort, // 排序 信息
query: this.query,
page: nextPage
})
.done(res => {
if (res.code === 200) {
self.page = res.data.page;
self.totalPage = res.data.pageTotal;
self.$set('productList', self.productList.concat(res.data.productList));
}
})
.fail(() => {
tip('网络出错~');
})
.always(() => {
self.inSearching = false;
});
},
/**
* 清空数据(page=0) 重新搜索
*/
research: function() {
this.page = 0;
this.$set('productList', []);
this.search();
}
},
watch: {
/* sort 改变 都会触发 重新搜索 */
sort: function() {
this.research();
}
},
created: function() {
const self = this;
bus.$on('list.paging', function() {
self.search();
});
bus.$on('sort.change', function({
val
}) {
self.sort = val;
});
this.search();
}
};
</script>
<style>
.empty-tip {
margin-top: 380px;
color: #b0b0b0;
text-align: center;
.icon-search {
display: inline-block;
font-size: 200px;
margin-bottom: 56px;
}
}
.empty-tip-cn {
font-size: 34px;
margin-bottom: 30px;
}
.empty-tip-en {
font-size: 20px;
}
</style>
... ...