Authored by TaoHuang

Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	config/order-api-map.js
Showing 43 changed files with 1004 additions and 137 deletions
const config = {
development: {
axiosBaseUrl: 'http://m.yohobuy.com/xianyu',
axiosBaseUrl: 'http://m.yohobuy.com:6001/xianyu',
axiosResponseType: 'json',
reportUrl: '//badjs.yoho.cn/apm/yas2.gif'
reportUrl: '//badjs.yoho.cn/apm/yas2.gif',
},
production: {
axiosBaseUrl: 'http://m.yohobuy.com/xianyu',
axiosResponseType: 'json',
reportUrl: '//badjs.yoho.cn/apm/yas2.gif'
}
reportUrl: '//badjs.yoho.cn/apm/yas2.gif',
},
};
export default config[process.env.NODE_ENV];
... ...
<template>
<LayoutApp :show-back="true">
<div class="root-content">
<div class="left-content">
<Scroll>
<div >
<li
class="category-left-item"
:class="{'category-left-item-select' : item.isSelect }"
v-for="(item, index) in categoryParent"
:key="index"
:data-id="item"
@click="onClick(item)">{{item.name}}</li>
</div>
</Scroll>
</div>
<div class="left-right-split-line"></div>
<div class="right-content">
<Scroll>
<div v-for="(itemSub, index) in categorySubList" :key="index">
<p class="sub-title">————{{itemSub.name}}————</p>
<div class="category-sub-root">
<div class="item-imge-div"
v-for="(item, index) in itemSub.sub"
:key="index"
:data-id="item.id"
>
<ImgSize
class="item-imge"
:src="item.image"
:width="60"
:height="60"
/>
</div>
</div>
</div>
</Scroll>
</div>
</div>
</LayoutApp>
</template>
<script>
import { Scroll }from 'cube-ui'
import {createNamespacedHelpers} from 'vuex';
import Vue from 'vue';
import ImgSize from '../../components/img-size';
const {mapState, mapActions} = createNamespacedHelpers('category');
export default {
name: 'category',
components: {
Scroll,
ImgSize
},
data() {
return {
};
},
mounted() {
this.fetchCategoryParentList();
this.fetchBrandList({});
},
methods: {
...mapActions(['fetchCategoryParentList', 'selectCategoryParent', 'fetchBrandList', 'fetchCategorySubList']),
onClick(item){
if(!item.isSelect){
let id = item.id;
if(id === "-1"){
this.fetchBrandList({id});
}else {
this.fetchCategorySubList({id})
}
}
},
},
computed: {
...mapState(['categoryParent','categorySubList']),
},
};
</script>
<style>
.root-content{
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
background-color: #FFFFFF;
}
.left-right-split-line{
height: 100%;
width: 1px;
background-color: #999999;
}
.left-content{
width: 25%;
height: 100%;
}
.right-content{
display: flex;
flex-direction: column;
width: 75%;
height: 100%;
}
.category-left-item{
display: flex;
width: 100%;
height: 100px;
align-items: center;
justify-content: center;
font-size: 28px;
color: #EEEEEE;
}
.category-left-item-select{
font-size: 48px;
color: #000000;
}
.category-sub-root {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
}
.sub-title{
/* background-color: brown; */
font-size: 24px;
color: #000;
text-align: center;
}
.item-imge-div {
display: flex;
flex: 0 0 33%;
height: 150px;
align-items: center;
justify-content: center;
}
.item-imge {
object-fit: contain;
}
</style>
\ No newline at end of file
... ...
export default [
{
name: 'category',
path: '/xianyu/category',
component: () => import(/* webpackChunkName: "notice" */ './category')
}
];
\ No newline at end of file
... ...
<template>
<div class="body" ref="body">
<div v-for="(item, index) in channelData" :key="index">
<template v-if="item.template_name == 'focus'">
<Slider :list="list"></Slider>
</template>
<LayoutApp :show-back="true">
<div class="scroll-list-wrap">
<Scroll
ref="scroll"
:options="options"
@pulling-up="onPullingUp">
<div class="body" ref="body">
<div v-for="(item, index) in channelList.list" :key="index">
<template v-if="item.template_name == 'focus'">
<Slider :list="list"></Slider>
</template>
<template v-if="item.template_name == 'hotSeries'">
<Hot :list="item.data"></Hot>
</template>
<template v-if="item.template_name == 'hotSeries'">
<Hot :list="item.data"></Hot>
</template>
<template v-if="item.template_name == 'single_image'">
<Banner :linkUrl="linkUrl" :imgUrl="imgUrl"></Banner>
</template>
<template v-if="item.template_name == 'single_image'">
<Banner :linkUrl="linkUrl" :imgUrl="imgUrl"></Banner>
</template>
<template v-if="item.template_name == 'twoPicture'">
<TwoBanner :list="item.data"></TwoBanner>
</template>
</div>
<!-- <ScrollNav></ScrollNav> -->
<template v-if="item.template_name == 'twoPicture'">
<TwoBanner :list="item.data"></TwoBanner>
</template>
</div>
<ScrollNav></ScrollNav>
<ProductList :list="channelList.productlist"></ProductList>
</div>
</Scroll>
</div>
</LayoutApp>
</template>
<script>
import Slider from './components/slider'; // 轮播图
import Banner from './components/banner'; // 一张图广告位
import TwoBanner from './components/twoBanner'; // 两张图广告位
import Hot from './components/hot'; // 热门系列
import ScrollNav from './components/scrollNav'; // 滑动导航
import { Style, Scroll } from 'cube-ui'
import { createNamespacedHelpers } from 'vuex';
const {mapState, mapActions} = createNamespacedHelpers('home/channel');
import Slider from './components/slider';
import Banner from './components/banner';
import TwoBanner from './components/twoBanner';
import Hot from './components/hot';
import ScrollNav from './components/scrollNav';
import ProductList from '../../list/components/productList';
const { mapState, mapActions } = createNamespacedHelpers('home/channel');
export default {
data() {
return {
options: {
bounce: {
top: false
},
pullUpLoad: true
},
items: [1,2,3,4,5,6,7,8,9],
list: [
{
url: 'http://www.didichuxing.com/',
... ... @@ -195,28 +215,42 @@ export default {
}
},
computed: {
...mapState(['channelData']),
...mapState(['channelList']),
},
created() {
},
mounted() {
this.fetchChannelList();
this.fetchProductList();
},
methods: {
...mapActions(['fetchChannelList']),
...mapActions(['fetchChannelList','fetchProductList']),
async onPullingUp() {
await this.fetchProductList();
setTimeout(() => { this.$refs.scroll.forceUpdate() }, 1000)
}
},
components: {
Slider,
Banner,
TwoBanner,
Hot,
ScrollNav
ScrollNav,
Style,
Scroll,
ProductList
}
};
</script>
<style lang="scss" scoped>
.scroll-list-wrap {
height: 100%;
width: 100%;
}
.body {
height: 100%;
overflow-y: auto;
... ...
... ... @@ -3,7 +3,7 @@
<ul>
<li v-for="(item, index) in list" :key="index" @click="goProduct(item)">
<div class="hot-image">
<img :src="item.image_url" alt="" />
<ImgSize class="item-imge" :src="item.image_url" :width="100" :height="80"/>
</div>
<div class="hot-name">{{item.series_name}}</div>
</li>
... ... @@ -16,6 +16,8 @@
</template>
<script>
import ImgSize from '../../../../components/img-size';
export default {
name: 'hot',
props: {
... ... @@ -25,6 +27,9 @@ export default {
},
},
components: {
ImgSize,
},
methods: {
goProduct() {
alert('跳转列表!');
... ... @@ -45,6 +50,7 @@ export default {
<style lang="scss" scoped>
.hot {
margin: 40px 0;
ul {
overflow: hidden;
li {
... ...
<template>
<div class="ScrollNav">
<ScrollNav>
<ScrollNav-panel
v-for="item in [1,2,3,4,5]"
:key="item"
:label="item">
<div v-for="item in [1,2,3,4,5]" :key="item" :label="item">22222</div>
</ScrollNav-panel>
</ScrollNav>
<ScrollNavBar :current="current" :labels="labels">
<span slot-scope="props" @click="changeHandler(props.index)">
{{props.txt}}
</span>
</ScrollNavBar>
</div>
</template>
<script>
import Vue from 'vue'
import { Style, ScrollNav } from 'cube-ui';
import { Style, ScrollNavBar } from 'cube-ui';
import { createNamespacedHelpers } from 'vuex';
const { mapState, mapActions } = createNamespacedHelpers('home/channel');
export default {
name: 'slide',
... ... @@ -23,15 +22,36 @@ export default {
// default: true
// },
},
data() {
return {
index: 0,
current: '快车',
labels: [
'快车',
'小巴',
'专车',
'顺风车',
'代驾',
'公交',
'自驾租车',
'豪华车',
'二手车',
'出租车'
]
}
},
components: {
Style,
ScrollNav
ScrollNavBar
},
computed: {
// ...mapState(['resource'])
...mapState(['channelList','scrollnavidList']),
},
methods: {
changeHandler(index) {
console.log(this.channelList.scrollnavList[index]); // value
// console.log(this.channelList.scrollnavidList[index]); // id
}
}
};
</script>
... ...
<template>
<LayoutApp :show-back="true">
<Scroll :scrollEvents="['scroll']" :options="scrollOptions" @scroll="scroll"
@pulling-up="onPullingUp">
<ProductList :list="favoriteProductList"></ProductList>
</Scroll>
</LayoutApp>
</template>
<script>
import ProductList from '../../list/components/productList';
import {Scroll} from 'cube-ui';
import {createNamespacedHelpers} from 'vuex';
const {mapState, mapActions} = createNamespacedHelpers('home/favorite');
export default {
name: 'list',
components: {
ProductList,
Scroll
},
data() {
return {
scrollOptions: {
bounce: {
top: false
},
pullUpLoad: true
},
fixed: false
};
},
mounted() {
this.fetchFavoriteList();
},
methods: {
...mapActions(['fetchFavoriteList']),
async onPullingUp() {
await this.fetchFavoriteList();
},
scroll({ y }) {
const height = this.$refs.banner.$el.offsetHeight + this.$refs.header.offsetHeight;
if (-y >= height) {
this.fixed = true;
} else {
this.fixed = false;
}
}
},
computed: {
...mapState(['favoriteProductList']),
// getFa(){
// let length = this.favoriteProductList.product_list.lenght;
// console.log("length:"+length)
// },
},
};
</script>
<style scoped>
</style>
... ...
export default [{
name: 'favorite',
path: '/xianyu/home/favorite.html',
component: () => import(/* webpackChunkName: "mine" */ './favorite')
}];
\ No newline at end of file
... ...
import Mine from './mine';
import Trade from './tradeIncome';
import Favorite from './favorite';
export default [
{
name: 'channel',
... ... @@ -8,4 +10,5 @@ export default [
},
...Mine,
...Trade,
...Favorite,
];
... ...
... ... @@ -6,5 +6,7 @@ import Home from './home';
import Passport from './passport';
import Address from './address';
import Notice from './notice';
import Category from './category';
export default [...Order, ...Common, ...List, ...Product, ...Home, ...Passport, ...Address, ...Notice, ...Category];
export default [...Order, ...Common, ...List, ...Product, ...Home, ...Passport, ...Address, ...Notice];
... ...
... ... @@ -45,6 +45,7 @@ export default {
}
.item-price {
height: 32px;
margin-bottom: 38px;
font-size: 28px;
color: #000;
... ... @@ -64,5 +65,10 @@ export default {
line-height: 40px;
margin-top: 38px;
margin-bottom: 44px;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>
... ...
<template>
<LayoutApp :show-back="true">
<Scroll :scrollEvents="['scroll']" :options="scrollOptions" @scroll="scroll"
<div class="filter">
<div class="filter-tab">
<div class="tab-item" :class="selectedType === 2 && 'selected-tab'" @click="pressType(2)">人气</div>
<div class="tab-item middle" :class="selectedType === 1 && 'selected-tab'" @click="pressType(1)">
<span>价格</span>
<div :class="arrowImage"></div>
</div>
<div class="tab-item" :class="selectedType === 3 && 'selected-tab'" @click="pressType(3)">新品</div>
</div>
<div class="screen middle">
<div class="screen-img"></div>
筛选
</div>
</div>
<Scroll :options="scrollOptions"
:data="productList.list"
@pulling-up="onPullingUp">
<ProductList :list="productList.list"></ProductList>
</Scroll>
... ... @@ -27,33 +42,143 @@ export default {
},
pullUpLoad: true
},
fixed: false
fixed: false,
selectedType: 2,
priceDesc: true,
arrowImage: '',
searchKey: '',
listType: 1
};
},
mounted() {
this.fetchProductList();
this.changeArrow();
let params = this.$route.params;
if (Object.keys(params).length && params.listType) {
this.listType = params.listType;
}
this.fetchProductList({listType: this.listType, isReset: true});
},
methods: {
...mapActions(['fetchProductList']),
// 上拉加载
async onPullingUp() {
await this.fetchProductList();
await this.fetchProductList({listType: this.listType});
},
scroll({ y }) {
const height = this.$refs.banner.$el.offsetHeight + this.$refs.header.offsetHeight;
if (-y >= height) {
this.fixed = true;
} else {
this.fixed = false;
// 点击tab type, 0: 推荐, 1: 价格, 2: 人气, 3: 新品
pressType(type) {
if (type === this.selectedType && type !== 1) {
return;
}
}
let params = {
type: 6,
query: this.searchKey,
sort: this.filterParams.sort.join(','),
brand: this.filterParams.brand.join(','), // 品牌id
gender: this.filterParams.gender.join(','), // 性别
size: this.filterParams.size.join(','), // 尺码id
};
if (this.listType === 4) {
delete params.type;
}
this.selectedType = type;
if (type === 1) {
this.priceDesc = !this.priceDesc;
params.order = !this.priceDesc ? 'p_desc' : 'p_asc';
} else if (type === 2) {
this.priceDesc = true;
params.order = 'sale_desc';
} else if (type === 3) {
this.priceDesc = true;
params.order = 'st_desc';
}
params.listType = this.listType;
params.isReset = true;
this.changeArrow();
this.fetchProductList(params);
},
changeArrow() {
this.arrowImage = (this.selectedType === 3 || this.selectedType === 2) ? 'price-arrow' :
this.priceDesc ? 'desc-arrow' : 'asc-arrow';
},
},
computed: {
...mapState(['productList']),
...mapState(['productList', 'filterParams']),
},
};
</script>
<style scoped>
.filter {
display: flex;
height: 120px;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding-left: 42px;
padding-right: 38px;
}
.filter-tab {
display: flex;
flex-direction: row;
align-items: center;
font-size: 32px;
color: #999;
text-align: center;
}
.selected-tab {
font-size: 40px;
color: #000;
font-weight: bold;
}
.tab-item {
margin-right: 60px;
}
.screen {
font-size: 32px;
color: #000;
letter-spacing: 0;
}
.middle {
display: flex;
align-items: center;
}
.asc-arrow {
width: 40px;
height: 40px;
background: url(~statics/image/list/asc_arrow@3x.png) no-repeat;
background-size: cover;
}
.desc-arrow {
width: 40px;
height: 40px;
background: url(~statics/image/list/desc_arrow@3x.png) no-repeat;
background-size: cover;
}
.price-arrow {
width: 40px;
height: 40px;
background: url(~statics/image/list/price_arrow@3x.png) no-repeat;
background-size: cover;
}
.screen-img {
width: 40px;
height: 40px;
background: url(~statics/image/list/filter@3x.png) no-repeat;
background-size: cover;
}
</style>
... ...
... ... @@ -21,10 +21,18 @@ export default [
component: () => import(/* webpackChunkName: "order" */ './pay-ok'),
},
{
name: 'buyerAskOrder', //买家求购确认
name: 'buyerAskOrder', // 买家求购确认
path: '/xianyu/order/buyeraskorder.html',
component: () => import('./buyer-ask-order'),
},
// 物流信息
// code: 订单编码
{
name: 'orderLogisticsInfo',
path: '/xianyu/:owner/order/logistics/:code',
component: () => import('./order-logistics-info'),
},
...PriceChange,
...OrderList,
...OrderDetail,
... ...
<template>
<div class="address-wrapper">
<i class="address-icon"></i>
<div>
<p class="consignee">{{ userAddress.consignee }}</p>
<p class="area">{{ userAddress.area }}</p>
<p class="mobile">{{ userAddress.mobile }}</p>
</div>
</div>
</template>
<script>
import { createNamespacedHelpers } from "vuex";
const { mapGetters } = createNamespacedHelpers("order/orderDetail");
export default {
computed: {
...mapGetters(["userAddress"])
}
};
</script>
<style lang="scss" scoped>
.address-wrapper {
display: flex;
align-items: center;
.consignee {
font-size: 32px;
font-weight: bold;
}
.area {
color: #999;
margin: 12px 0;
}
.mobile {
font: 28px;
}
.address-icon {
width: 48px;
height: 48px;
display: block;
background-size: contain;
margin-right: 40px;
background-image: url("~statics/image/order/addr-icon@3x.png");
}
}
</style>
\ No newline at end of file
... ...
... ... @@ -7,43 +7,49 @@
<p class="status-desc">{{ statusDetail.detailDesc }}</p>
</div>
<!-- 物流信息 -->
<div class="logistics item-wrapper">
<div class="detail">
<p>{{ lastExpressInfo.acceptRemark }}</p>
<p>{{ lastExpressInfo.createTimeStr }}</p>
<router-link :to="{ name: 'orderLogisticsInfo', params: $route.params }">
<div class="logistics-info item-wrapper">
<div class="content">
<i class="logistics-icon"></i>
<div class="info">
<p>{{ lastExpressInfo.acceptRemark }}</p>
<p>{{ lastExpressInfo.createTimeStr }}</p>
</div>
</div>
<i class="right-icon"></i>
</div>
</div>
</router-link>
<!-- 地址信息 -->
<logistic-info class="item-wrapper" />
<address-info class="item-wrapper" />
<!-- 商品信息 -->
<order-item-info class="item-wrapper" />
<!-- 价格信息 -->
<div class="price-info item-wrapper">
<p>
<span>商品金额:</span>
<span>{{ priceInfo.goodPrice }}</span>
<span class="label">商品金额:</span>
<span>¥{{ priceInfo.goodPrice }}</span>
</p>
<p>
<span>运费:</span>
<span>{{ priceInfo.feePrice }}</span>
<p class="delivery-fee">
<span class="label">运费:</span>
<span>¥{{ priceInfo.feePrice }}</span>
</p>
<p>
<span>实际金额:</span>
<span>{{ priceInfo.realPayPrice }}</span>
<span class="label">实际金额:</span>
<span class="pay-price">¥{{ priceInfo.realPayPrice }}</span>
</p>
</div>
<!-- 交易信息 -->
<div class="trade-info item-wrapper">
<p>
<span>创建时间:</span>
<span class="label">创建时间:</span>
<span>{{ orderDetail.createTime }}</span>
</p>
<p>
<span>订单编号:</span>
<span class="label">订单编号:</span>
<span>{{ orderDetail.orderCode }}</span>
</p>
<p>
<span>支付方式:</span>
<span class="label">支付方式:</span>
<span>{{ orderDetail.paymentStr }}</span>
</p>
</div>
... ... @@ -59,7 +65,7 @@
<script>
import { createNamespacedHelpers } from "vuex";
import LogisticInfo from "./components/logistics-info";
import AddressInfo from "./components/address-info";
import OrderItemInfo from "./components/order-detail-item";
import { Button } from "cube-ui";
... ... @@ -68,12 +74,12 @@ const { mapActions, mapState, mapGetters } = createNamespacedHelpers(
);
export default {
components: {
LogisticInfo,
AddressInfo,
OrderItemInfo,
Button
},
asyncData({ store, router }) {
store.dispatch("order/orderDetail/fetchOrderDetail", router.params);
// store.dispatch("order/orderDetail/fetchOrderDetail", router.params);
},
mounted() {
this.fetchOrderDetail(this.$route.params);
... ... @@ -101,6 +107,7 @@ export default {
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
font-size: 24px;
.item-wrapper {
border-top: 1px solid #eee;
... ... @@ -117,15 +124,79 @@ export default {
}
.status-desc {
font-size: 24px;
color: #999;
letter-spacing: 0;
margin-top: 30px;
}
}
.logistics {
.logistics-info {
margin-top: 40px;
display: flex;
align-items: center;
justify-content: space-between;
.content {
display: flex;
align-items: center;
.info :last-child {
color: #999;
margin-top: 12px;
}
}
.logistics-icon,
.right-icon {
width: 48px;
height: 48px;
display: block;
background-size: contain;
}
.logistics-icon {
margin-right: 40px;
background-image: url("~statics/image/order/logistics-icon@3x.png");
}
.right-icon {
background-image: url("~statics/image/order/right-arrow-icon@3x.png");
}
}
.price-info {
font-size: 28px;
& > p {
display: flex;
justify-content: space-between;
}
& > p:first-child {
color: #999;
}
.delivery-fee {
margin: 12px 0;
color: #999;
}
.pay-price {
color: #d0021b;
}
}
.trade-info {
font-size: 28px;
& > :first-child + p {
margin: 20px 0;
}
}
.label {
font-size: 28px;
margin-right: 12px;
}
.actions {
... ...
<template>
<div class="logistics-wrapper">
<p>{{ userAddress.consignee }}</p>
<p>{{ userAddress.area }}</p>
<p>{{ userAddress.mobile }}</p>
物流信息
</div>
</template>
<script>
import { createNamespacedHelpers } from "vuex";
const { mapGetters } = createNamespacedHelpers("order/orderDetail");
const { mapActions } = createNamespacedHelpers("order/logisticsInfo");
export default {
computed: {
...mapGetters(["userAddress"])
computed: {},
mounted() {
this.fetchLogisticInfo(this.$route.params);
},
methods: {
...mapActions(["fetchLogisticInfo"])
}
};
</script>
<style lang="scss" scoped>
.logistics-wrapper {
height: 100vh;
-webkit-box-orient: vertical;
}
</style>
\ No newline at end of file
... ...
import {get} from 'lodash';
import Vue from 'vue';
export default function() {
return {
namespaced: true,
state: {
categoryParent: [],
categorySubList: [],
},
mutations: {
addCategoryParentList(state, {data}) {
let brand = {
id:'-1',
name: '品牌',
image: '',
linkType: '',
isSelect: true,
}
state.categoryParent.push(brand);
if (data && data.length) {
data.forEach(val => {
val.isSelect = false;
state.categoryParent.push(val);
});
}
},
addCategorySubList(state, {data}) {
if(data && data.category){
state.categorySubList = data.category;
}
},
addBrandList(state, {data}){
if(data && data.brand_list){
let sub = [];
data.brand_list.forEach(val => {
val.isSelect = false;
let subItem = {
id: val.id,
name: val.brand_name,
image: val.brand_logo,
type: 1,//表示 品牌
linkType: '',
link: '',
}
sub.push(subItem);
});
let category = [{
id:'',
image:'',
linkType:'',
name:'全部品牌',
sub: sub,
}];
state.categorySubList = category;
}
},
updateCategoryParentList(state, {id}) {
if (id) {
state.categoryParent.forEach((val, index) => {
if(id === val.id){
val.isSelect = true;
}else {
val.isSelect = false;
}
Vue.set(state.categoryParent, index, val);
});
}
}
},
actions: {
async fetchCategoryParentList({commit, state}) {
const result = await this.$api.get('/api/ufo/category/saleCategory');
if (result.code === 200) {
commit('addCategoryParentList', {data: result.data});
}
return result.data ? result.data.length : 0;
},
async fetchBrandList({commit, state}, {id}) {
if(id){
commit('updateCategoryParentList', {id: id});
}
const result = await this.$api.get('/api/ufo/category/search/brandList');
console.log(result);
if (result.code === 200) {
commit('addBrandList', {data: result.data});
}
return result.data ? result.data.length : 0;
},
async fetchCategorySubList({commit, state},{id}) {
commit('updateCategoryParentList', {id: id});
const result = await this.$api.get('/api/ufo/category/saleCategoryDetail',{ id });
console.log(result);
if (result.code === 200) {
commit('addCategorySubList', {data: result.data});
}
return result.data ? result.data.length : 0;
},
},
};
}
... ...
import Vue from 'vue';
import * as Types from './types';
import { get, set } from 'lodash';
import { getImgUrl } from '../../common/utils';
export default function() {
return {
namespaced: true,
state: {
channelData: [],
// channelData: [],
channelList: {
list: [], // 资源列表
productlist: [], // 资源列表
page: 0, // 当前页
page_size: 10, // 每页数量
page_total: 0, // 总共多少页
total: 0, // 总共多少条
scrollnavList: [], // 导航菜单
// scrollnavidList: [], // 导航菜单id
},
},
mutations: {
[Types.FETCH_CHANNEL](state, { list }) {
state.channelData = list;
state.channelList.list = list;
state.channelList.list.map(res => {
if (res.template_name === 'hotSeries') {
for (let i = 0; i < res.data.length; i++) {
state.channelList.scrollnavList.push(res.data[i].series_name);
// state.channelList.scrollnavidList.push(res.data[i].series_id);
}
}
});
},
[Types.FETCH_PRODUCT](state, { productlist }) {
// state.channelList.productlist = productlist;
Vue.set(state.channelList, 'productlist', state.channelList.productlist.concat(productlist.product_list));
Vue.set(state.channelList, 'page', productlist.page);
},
},
actions: {
async fetchProductList({ commit, state }) {
let page = state.channelList.page;
let size = state.channelList.page_size;
const result = await this.$api.get('/api/ufo/list/productList', {
page: page + 1,
size,
});
if (result.code === 200) {
commit(Types.FETCH_PRODUCT, {productlist: result.data});
}
},
async fetchChannelList({ commit }) {
const result = await this.$api.get('/api/ufo/channel/channelList', {
content_code: '9cb6138be8e60c96f48107da481816c3',
uid: '64668089',
});
if (result.code === 200) {
result.data.map(res => {
// 焦点图
if(res.template_name === 'focus') {
for (let i = 0; i < res.data.length; i++) {
let url = "https:" + getImgUrl(get(res.data[i], "src") || '', 750, 200);
set(res.data[i], "src", url);
}
}
// 热门系列
if(res.template_name === 'hotSeries') {
for (let i = 0; i < res.data.length; i++) {
let url = "https:" + getImgUrl(get(res.data[i], "image_url") || '', 100, 80);
set(res.data[i], "image_url", url);
}
}
})
console.log(result.data);
commit(Types.FETCH_CHANNEL, { list: result.data });
}
}
... ...
import { get, set } from 'lodash';
import { getImgUrl } from '../../common/utils';
import Vue from 'vue';
const uid = '500031170';
export default function() {
return {
namespaced: true,
state: {
page: 1,
pageTotal: 0,
recId: '',
favoriteProductList: [],
},
mutations: {
addList(state, { data }) {
if(data && data.product_list){
let list = state.favoriteProductList.list.concat(data.product_list);
Vue.set(state.favoriteProductList, "list", list);
}
},
},
actions: {
async fetchFavoriteList({ commit }) {
const result = await this.$api.get('/api/ufo/home/favoriteProduct', {uid});
if (result.code === 200) {
let data =result.data;
commit('addList', { data:data });
}
return result.data || [];
},
},
};
}
... ...
import mine from './mine';
import channel from './channel'
import favorite from './favorite'
export default function() {
return {
namespaced: true,
... ... @@ -16,7 +17,8 @@ export default function() {
},
modules: {
mine: mine(),
channel: channel()
channel: channel(),
favorite: favorite(),
}
};
}
\ No newline at end of file
... ...
... ... @@ -3,3 +3,9 @@ export const FETCH_NOTICE_LIST_FAILD = 'FETCH_NOTICE_LIST_FAILD';
export const FETCH_NOTICE_LIST_SUCCESS = 'FETCH_NOTICE_LIST_SUCCESS';
export const FETCH_CHANNEL = 'FETCH_CHANNEL';
export const FETCH_PRODUCT = 'FETCH_PRODUCT';
export const FETCH_FAVORITE_LIST_REQUEST = 'FETCH_FAVORITE_LIST_REQUEST';
export const FETCH_FAVORITE_LIST_FAILD = 'FETCH_FAVORITE_LIST_FAILD';
export const FETCH_FAVORITE_LIST_SUCCESS = 'FETCH_FAVORITE_LIST_SUCCESS';
... ...
... ... @@ -10,6 +10,7 @@ import storeHome from './home';
import storeAddress from './address';
import storeNotice from './notice';
import storeCategory from './category';
Vue.use(Vuex);
... ... @@ -27,6 +28,10 @@ export function createStore(context) {
// 买家订单列表
notice: storeNotice(),
category: storeCategory(),
// buyerOderList: buyerOderList(),
},
strict: process.env.NODE_ENV !== 'production',
... ...
import {get} from 'lodash';
import Vue from 'vue';
export default function() {
return {
... ... @@ -19,7 +18,7 @@ export default function() {
},
searchParams: {
type: 0, // type:0,推荐;1,热销;2,即将发售; 3,品类; 4,品牌;5,系列;6,搜索 7, 收藏
order: null, // 指定排序
order: 'sale_desc', // 指定排序
productPool: null, // 商品池id
sort: null, // 品类id
brand: null, // 品牌id
... ... @@ -43,25 +42,83 @@ export default function() {
},
mutations: {
addProductList(state, {data}) {
Vue.set(state.productList, 'list', state.productList.list.concat(data.product_list));
Vue.set(state.productList, 'page', data.page);
let {productList} = state;
if (typeof data === 'object' && Object.keys(data).length) {
for (let key in data) {
if (key === 'product_list') {
productList.list = data.page > 1 ? productList.list.concat(data.product_list) : data.product_list;
} else {
productList[key] = data[key];
}
}
state.productList = productList;
}
},
setSearchParams(state, {params}) {
state.searchParams = Object.assign(state.searchParams, params);
},
addFilterData(state, {filter}) {
state.filterData = filter;
}
},
actions: {
async fetchProductList({commit, state}) {
let page = state.productList.page;
let size = state.productList.page_size;
const result = await this.$api.get('/api/ufo/list/productList', {
page: page + 1,
size: size
fetchProductList: async function({commit, state}, params) {
let searchParams = state.searchParams;
let list = state.productList;
let pageSize = list.page_size;
let isReset = false;
if (params && params.isReset) {
isReset = true;
delete params.isReset;
}
if (params && Object.keys(params).length) {
searchParams = Object.assign(searchParams, params);
commit('setSearchParams', {params: searchParams});
}
if (!isReset && (list.endReached || (!list.endReached && list.page_total === 1))) {
return;
}
let page = isReset ? 1 : (list.page + 1);
for (let key in searchParams) {
if (!searchParams[key]) {
delete searchParams[key];
}
}
let result = await this.$api.get('/api/ufo/list/productList', {
...searchParams,
page,
pageSize
});
if (result.code === 200) {
commit('addProductList', {data: result.data});
let {data} = result;
data.endReached = (data.page === data.page_total) && (data.page_size !== 1);
commit('addProductList', {data});
}
return result.data ? result.data.length : 0;
},
},
fetchFilterData: async function({commit, state}) {
let searchParams = state.searchParams;
for (let key in searchParams) {
if (!searchParams[key]) {
delete searchParams[key];
}
}
let result = await this.$api.get('/api/ufo/list/filterData', {...searchParams});
if (result.code === 200) {
let {data} = result;
commit('addFilterData', {filter: data.filter});
}
}
};
}
... ...
... ... @@ -2,6 +2,7 @@ import priceChange from './price-change';
import orderList from './order-list';
import orderConfirm from './order-confirm';
import orderDetail from './order-detail';
import orderLogistics from './order-logistics';
export default function() {
return {
... ... @@ -11,6 +12,7 @@ export default function() {
orderList: orderList(),
orderConfirm: orderConfirm(),
orderDetail: orderDetail(),
logisticsInfo: orderLogistics(),
},
};
}
... ...
... ... @@ -27,7 +27,7 @@ export default function() {
async fetchOrderDetail({ commit }, { owner, code } = {}) {
const res = await this.$api.get('/api/order/detail', {
tabType: owner,
orderCode: code,
orderCode: +code,
// Todo 删除
uid: 600043484,
... ...
export default function() {
return {
namespaced: true,
state: {
logisticInfo: {},
},
mutations: {
initData: (state, data) => {
state.logisticInfo = data;
},
},
actions: {
// 获取物流信息
async fetchLogisticInfo({ commit }, { owner, code } = {}) {
const res = await this.$api.get('/api/order/express', {
tabType: owner,
orderCode: +code,
// Todo 删除
uid: 600043484,
});
if (res.code === 200) {
commit('initData', res.data);
}
},
},
};
}
... ...
... ... @@ -13,6 +13,7 @@ const webpackConfig = merge(baseConfig, {
entry: {
app: './apps/entry-client.js',
},
devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map',
optimization: {
runtimeChunk: true,
splitChunks: {
... ...
... ... @@ -3,51 +3,52 @@ const merge = require('webpack-merge');
const nodeExternals = require('webpack-node-externals');
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
let baseConfig = require('./webpack.base.conf');
const isProd = process.env.NODE_ENV === 'production';
let webpackConfig = merge(baseConfig, {
entry: {
app: './apps/entry-server.js'
app: './apps/entry-server.js',
},
devtool: isProd ? 'source-map' : 'cheap-module-source-map',
target: 'node',
resolve: {
alias: {
'create-api': 'common/create-api-server.js',
'report-error': 'common/report-error-server.js'
}
'report-error': 'common/report-error-server.js',
},
},
module: {
rules: [
{
test: /\.s?css$/,
use: 'ignore-loader'
}, {
use: 'ignore-loader',
},
{
test: /\.styl(us)?$/,
use: 'ignore-loader'
}, {
use: 'ignore-loader',
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: 'ignore-loader'
}, {
use: 'ignore-loader',
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: 'ignore-loader'
}
]
use: 'ignore-loader',
},
],
},
output: {
libraryTarget: 'commonjs2',
},
externals: nodeExternals({
whitelist: [/cube-ui/]
whitelist: [/cube-ui/],
}),
plugins: [
new VueSSRServerPlugin({
filename: '../../manifest.server.json'
filename: '../../manifest.server.json',
}),
new webpack.DefinePlugin({
'process.env.VUE_ENV': '"server"'
})
]
'process.env.VUE_ENV': '"server"',
}),
],
});
module.exports = webpackConfig;
... ...
... ... @@ -4,6 +4,8 @@ const listApi = require('./list-api-map');
const homeApi = require('./home-api-map');
const passportApi = require('./passport-api-map');
const addressApi = require('./address-api-map');
const orderListApi = require('./order-api-map');
const categoryApi = require('./category-api-map');
module.exports = {
...orderApi,
... ... @@ -12,4 +14,6 @@ module.exports = {
...homeApi,
...passportApi,
...addressApi,
...orderListApi,
...categoryApi,
};
... ...
module.exports = {
'/api/ufo/category/saleCategory': {
ufo: true,
api: 'ufo.product.saleCategory',
params: {},
},
'/api/ufo/category/search/brandList': {
ufo: true,
api: 'ufo.product.search.brandList',
params: {
},
},
'/api/ufo/category/saleCategoryDetail': {
ufo: true,
api: 'ufo.product.saleCategoryDetail',
params: {
id: { type: String }
},
},
};
\ No newline at end of file
... ...
... ... @@ -17,4 +17,11 @@ module.exports = {
coupon_token: {type: String}, // 优惠券token
},
},
'/api/ufo/list/filterData': {
ufo: true,
api: 'ufo.product.search.list.filter',
params: {
}
}
};
... ...
... ... @@ -31,7 +31,7 @@ module.exports = {
auth: true,
api: 'ufo.buyer.confirm',
params: {
order_code: { type: Number, require: true }, // 订单编号
orderCode: { type: Number, require: true }, // 订单编号
},
},
... ... @@ -69,4 +69,14 @@ module.exports = {
api: 'ufo.user.aliPayAccountQuery',
},
// 订单物流信息
'/api/order/express': {
ufo: true,
auth: true,
api: 'ufo.order.expressDetailInfo',
params: {
tabType: { type: String, require: true }, // 订单来源
orderCode: { type: Number, require: true }, // 订单编号
},
},
};
... ...