Authored by baoss

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

Showing 55 changed files with 1564 additions and 213 deletions
... ... @@ -21,12 +21,6 @@ const request = (options, store) => {
sign(options);
return axios(options).then((res) => {
if (res.data.code === 401) {
store && store.commit('needLogin', {
needLogin: true
});
return Promise.reject(res.data);
}
return res.data;
}, errHandle);
};
... ...
... ... @@ -26,9 +26,15 @@ export default {
},
methods: {
onTouchstart() {
if (this.disable) {
return;
}
this.active = true;
},
onTouchend() {
if (this.disable) {
return;
}
this.clearActive();
this.$emit('click');
},
... ...
<template>
<button class="btn" :class="classes" type="button" @touchstart="onTouchstart" @touchend.prevent.stop="onTouchend">
<span>
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'Button',
data() {
return {
classes: {}
};
},
methods: {
onTouchstart() {
this.classes = {
active: true
};
},
onTouchend() {
this.clearActive();
this.$emit('click');
},
clearActive() {
this.classes = {};
}
}
};
</script>
<style lang="scss">
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: none;
background: none;
white-space: nowrap;
line-height: 1.5;
user-select: none;
font-size: 30px;
outline: 0;
border: none;
color: #000;
background-color: #eee;
height: 60px;
padding-left: 40px;
padding-right: 40px;
&:active,
&.active {
opacity: 0.5;
// color: #eee !important;
}
}
</style>
... ...
... ... @@ -35,11 +35,7 @@ export default {
},
methods: {
onBack() {
if (this.yoho.homePage) {
this.$yoho.finishPage({});
} else {
this.$router.go(-1);
}
this.$router.go(-1);
}
}
};
... ...
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>
... ...
<template>
<div class="agree">
<span @click="onClick"><i :class="getClass"></i> 我已阅读并同意</span> <span class="link" @click="onLinkClick">有货卖家协议</span>
<span @click="onClick"><Check v-model="val"></Check> 我已阅读并同意</span> <span class="link"
@click="onLinkClick">有货卖家协议</span>
</div>
</template>
<script>
import Check from './check';
export default {
name: 'OrderCheck',
props: {
... ... @@ -13,21 +17,14 @@ export default {
default: true
}
},
components: {
Check
},
data() {
return {
val: this.value
};
},
computed: {
getClass() {
return {
iconfont: true,
iconcheck_default: !this.val,
iconcheck_full: this.val,
icon_color: this.val
};
}
},
watch: {
value(newVal) {
this.val = newVal;
... ... @@ -43,7 +40,6 @@ export default {
}
}
};
</script>
... ... @@ -59,7 +55,4 @@ export default {
text-decoration-color: #65ab85;
}
.icon_color {
color: #002b47;
}
</style>
... ...
<template>
<i :class="getClass"></i>
</template>
<script>
export default {
name: 'YohoCheck',
props: {
value: {
type: Boolean,
default: true
}
},
data() {
return {
val: this.value
};
},
computed: {
getClass() {
return {
iconfont: true,
icon_size: true,
iconcheck_default: !this.val,
iconcheck_full: this.val,
icon_color: this.val
};
}
},
watch: {
value(newVal) {
this.val = newVal;
}
},
methods: {
onClick() {
this.val = !this.val;
this.$emit('input', this.val);
},
}
};
</script>
<style lang="scss" scoped>
.icon_size {
font-size: 24px;
}
.icon_color {
color: #002b47;
}
</style>
... ...
<template>
<div class="input-wrapper" @click="onClick">
<div class="input-wrapper">
<div class="price-symbol">¥</div>
<input class="tip" type="text" placeholder="定价需以9结尾,例如¥1299"></input>
<input ref="input" :value="value" class="tip" type="text" placeholder="定价需以9结尾,例如¥1299" @blur="onBlur"
@change="onChange"></input>
</div>
</template>
<script>
export default {
name: 'InputPrice',
props: {
value: {
type: [Number, String],
default: ''
}
},
data() {
return {
show: false,
val: this.value
};
},
methods: {
onClick() {
onBlur() {
this.$emit('on-blur');
},
onChange() {
this.$emit('input', this.$refs.input.value);
}
},
watch: {
value(newVal) {
this.val = newVal;
}
}
};
</script>
... ...
<template>
<div class="modal-box" v-show="value" v-transfer-dom :data-transfer="transfer">
<div class="modal-mask"></div>
<div class="modal-wrap" @touchmove.prevent.stop="onTouchmove">
<div class="modal modal-content">
<div class="modal-body">
<slot>
<div class="text">{{title}}</div>
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<Button class="btn" :class="{active: loading}" type="button" @click="onSure">{{sureText}}</Button>
<Button class="btn" type="button" @click="onCancel">{{cancelText}}</Button>
</slot>
</div>
</div>
</div>
</div>
</template>
<script>
import Button from 'components/button2.vue';
export default {
name: 'Modal',
props: {
transfer: [Boolean],
title: String,
value: Boolean,
loading: Boolean,
sureText: {
type: String,
default: '确认'
},
cancelText: {
type: String,
default: '取消'
}
},
methods: {
onTouchmove() {},
onCancel() {
this.$emit('on-cancel');
this.$emit('input', false);
},
onSure() {
if (!this.loading) {
this.$emit('on-sure');
}
}
},
components: {Button}
};
</script>
<style lang="scss">
.modal-box {
font-size: 24px;
}
.modal-mask {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.4);
height: 100%;
z-index: 99;
&-hidden {
display: none;
}
}
.modal {
width: auto;
margin: 0 auto;
position: relative;
outline: none;
&-hidden {
display: none !important;
}
&-wrap {
position: fixed;
overflow: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 99;
-webkit-overflow-scrolling: touch;
outline: 0;
}
&-content {
position: relative;
background-color: #fff;
top: 314px;
border: 0;
width: 600px;
background-clip: padding-box;
& .text {
text-align: center;
padding-top: 30px;
padding-bottom: 30px;
}
}
&-body {
padding: 38px;
}
&-footer {
width: 100%;
border-top: 1px solid #eee;
display: flex;
button {
width: 50%;
overflow: hidden;
height: 100px;
background: none;
&:first-child {
color: #999;
}
}
button + button {
margin-left: 8px;
margin-bottom: 0;
border-left: 1px solid #eee;
}
}
}
</style>
... ...
<template>
<div class="fee-detail">
<div class="item">
<div>平台用费:<i class="iconfont iconquestion icon-class"></i></div>
<div>-¥10.00</div>
<div>平台用费:<i class="iconfont iconquestion icon-class" @click="onClick"></i></div>
<div>{{data.platformFee.amount || '¥0'}}</div>
</div>
<div class="item">
<div>银行转账费(0.6%):</div>
<div>-¥10.00</div>
<div>银行转账费(1%):</div>
<div>{{data.bankTransferFee || '¥0'}}</div>
</div>
<div class="item">
<div class="total-fee">实际收入:</div>
<div class="fee">¥0.00</div>
<div class="fee">{{data.income || '¥0'}}</div>
</div>
<Modal ref="dialog" v-model="showModal">
<div class="title">
平台费用
</div>
<div class="item item2">
<span>商品鉴定费</span>
<span>{{data.platformFee.appraiseFee}}</span>
</div>
<div class="item item2">
<span>商品包装费</span>
<span>{{data.platformFee.appraiseFee}}</span>
</div>
<div class="item item2">
<span>平台服务费{{data.goodsPaymentRatePercent}}</span>
<span>{{data.platformFee.serviceFee}}</span>
</div>
<template slot="footer">
<Button class="btn" @click="hide">我知道了</Button>
</template>
</Modal>
</div>
</template>
<script>
import Modal from './modal';
import Button from 'components/button2.vue';
export default {
name: 'OrderFee'
name: 'OrderFee',
props: {
data: {
type: Object,
default() {
return {};
}
}
},
data() {
return {
confirmBtn: {},
showModal: false
};
},
components: {
Modal,
Button
},
methods: {
onClick() {
if (!this.data.income) {
return this.$createToast({
txt: '没有价格',
time: 1500,
type: 'txt'
}).show();
}
this.showModal = true;
},
hide() {
this.showModal = false;
}
}
};
</script>
... ... @@ -30,6 +92,22 @@ export default {
margin: 12px 0;
}
.item2 {
color: black;
margin-bottom: 43px;
font-size: 28px;
&:last-child {
margin-bottom: 0;
}
}
.title {
font-size: 32px !important;
margin-bottom: 50px;
text-align: center;
}
.total-fee {
font-size: 28px;
color: black;
... ... @@ -45,4 +123,15 @@ export default {
font-size: 26px;
margin-left: 10px;
}
.fee-content {
padding: 0 40px;
}
.btn {
width: 100% !important;
font-size: 30px;
color: black !important;
font-weight: bold;
}
</style>
... ...
<template>
<div>
<div class="tip">需支付保证金:<span class="red">¥0</span><i class="iconfont iconquestion icon-class"></i></div>
<div class="tip">需支付保证金:<span class="red">{{data.earnestMoneyStr || '¥0'}}</span><i 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,
default() {
return {};
}
}
},
methods: {
onClick() {
}
}
};
</script>
... ...
... ... @@ -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
... ...
... ... @@ -2,14 +2,16 @@
<LayoutApp :show-back="true">
<div class="body">
<TitleComp txt="出售"></TitleComp>
<ProductInfo :data="orderDetail.goodsInfo" class="product-info"></ProductInfo>
<InputPrice class="input-price"></InputPrice>
<OrderMargin class="order-item order-margin"></OrderMargin>
<OrderFee class="order-item"></OrderFee>
<AddressInfo :data="orderDetail.userAddress" class="order-item"></AddressInfo>
<OrderAgree v-model="agree" class="order-item"></OrderAgree>
<ProductInfo :data="{}" class="product-info"></ProductInfo>
<InputPrice @input="changePrice" :value="price" class="input-price" @on-blur="compute"></InputPrice>
<OrderMargin class="order-item order-margin" :data="fee"></OrderMargin>
<OrderFee class="order-item" :data="fee"></OrderFee>
<AddressInfo :data="address" class="order-item"></AddressInfo>
</div>
<div class="footer">
<OrderAgree :value="agree" @input="changeAgree" class="agree-wrapper"></OrderAgree>
<YohoButton :txt="txt" @click="onClick" :disable="!agree"></YohoButton>
</div>
<YohoButton :txt="txt" class="footer" @click="onClick"></YohoButton>
</LayoutApp>
</template>
... ... @@ -22,17 +24,24 @@ import TitleComp from './components/confirm/title';
import OrderMargin from './components/confirm/order-margin';
import OrderFee from './components/confirm/order-fee';
import OrderAgree from './components/confirm/agree';
import { Types } from 'store/order/order-confirm';
import { createNamespacedHelpers } from 'vuex';
const { mapState, mapActions } = createNamespacedHelpers('order/orderConfirm');
const { mapState, mapActions, mapMutations } = createNamespacedHelpers('order/orderConfirm');
const UserType = {
sell: 'sell',
buy: 'buy'
};
export default {
name: 'OrderConfirm',
props: {
orderCode: {
code: {
type: String,
default: ''
}
},
},
components: {
ProductInfo,
... ... @@ -46,18 +55,52 @@ export default {
data() {
return {
txt: '提交',
agree: false
error: false
};
},
mounted() {
this.fetchOrderDetail({orderCode: this.orderCode})
this.fetchUserStatus();
this.fetchOrderAddress({ tabType: UserType.sell });
},
computed: {
...mapState(['orderDetail'])
...mapState(['productDetail', 'address', 'fee', 'price', 'agree'])
},
methods: {
...mapActions(['fetchOrderDetail']),
...mapActions(['fetchOrderAddress', 'fetchUserStatus', 'fetchOrderPrice']),
...mapMutations([Types.CHANGE_PRICE, Types.CHANGE_AGREE]),
onClick() {
if (!this.error) {
this.$createOrderPayType().show();
}
},
compute() {
this.fetchOrderPrice({
address_id: this.address.address_id,
num: 1,
price: this.price,
storage_id: 10000128,
}).then(result => {
if (result.error) {
this.error = result.error;
this.$createToast({
time: 1500,
txt: result.error,
type: 'txt'
}).show();
}
});
},
changePrice(val) {
this[Types.CHANGE_PRICE](val);
},
changeAgree(val) {
this[Types.CHANGE_AGREE](val);
},
submit() {
this.compute().then(result => {
});
}
}
};
... ... @@ -74,7 +117,7 @@ export default {
.body {
height: 100%;
margin: 0 40px;
padding-bottom: 140px;
padding-bottom: 200px;
overflow-y: auto;
}
... ... @@ -87,4 +130,11 @@ export default {
border-top: 1px solid #eee;
}
.agree-wrapper {
height: 60px;
background-color: white;
border-top: 1px solid #eee;
padding: 0 40px;
line-height: 60px;
}
</style>
... ...
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(),
},
};
}
... ...
import { get, find } from 'lodash';
export const Types = {
FETCH_ORDER_DETAIL_REQUEST: 'FETCH_ORDER_DETAIL_REQUEST',
FETCH_ORDER_DETAIL_FAIL: 'FETCH_ORDER_DETAIL_FAIL',
FETCH_ORDER_DETAIL_SUCCESS: 'FETCH_ORDER_DETAIL_SUCCESS'
FETCH_ORDER_ADDRESS: 'FETCH_ORDER_ADDRESS',
FETCH_ORDER_USER_STATUS: 'FETCH_ORDER_USER_STATUS',
FETCH_ORDER_FEE: 'FETCH_ORDER_FEE',
CHANGE_PRICE: 'CHANGE_PRICE',
CHANGE_AGREE: 'CHANGE_AGREE'
};
export default function() {
return {
namespaced: true,
state: {
orderDetail: {},
fetchOrderDetail: false
productDetail: {},
fetchProductDetail: false,
address: {},
fee: {
income: '',
bankTransferFee: '',
platformFee: {
amount: '',
appraiseFee: '',
goodsPaymentRatePercent: '',
packageFee: '',
payChannelPercentage: '',
serviceFee: ''
}
},
alipayStatus: false,
userStatus: false,
price: '',
agree: false
},
mutations: {
[Types.FETCH_ORDER_DETAIL_REQUEST](state) {
state.fetchOrderDetail = true;
[Types.FETCH_ORDER_ADDRESS](state, data) {
state.address = data;
},
[Types.FETCH_ORDER_DETAIL_SUCCESS](state, data) {
state.fetchOrderDetail = false;
state.orderDetail = data;
[Types.FETCH_ORDER_FEE](state, data) {
state.fee = data;
},
[Types.FETCH_ORDER_DETAIL_FAIL](state) {
state.fetchOrderDetail = false;
[Types.CHANGE_PRICE](state, data) {
state.price = data;
},
[Types.CHANGE_AGREE](state, data) {
state.agree = data;
}
},
actions: {
async fetchOrderDetail({ commit }, { tabType = 'sell', orderCode } = {}) {
commit(Types.FETCH_ORDER_DETAIL_REQUEST);
async fetchOrderAddress({ commit }, payload) {
const orderCount = await this.$api.get('/api/order/confirm/count', payload);
if (get(orderCount, 'data.cnt', 0)) {
const addressInfo = await this.$api.get('/api/order/confirm/address');
const result = await this.$api.post('/api/order/detail', {
tabType,
orderCode: orderCode
});
const address = find(get(addressInfo, 'data', []), { is_default: 'Y' });
if (result.code !== 200) {
commit(Types.FETCH_ORDER_DETAIL_FAIL);
return;
commit(Types.FETCH_ORDER_ADDRESS, address);
}
},
async fetchOrderPrice({ commit }, payload) {
const order = await this.$api.post('/api/order/confirm/compute', payload);
if (order.code !== 200) {
return {
error: order.message
};
}
commit(Types.FETCH_ORDER_FEE, order.data);
return {};
},
commit(Types.FETCH_ORDER_DETAIL_SUCCESS, result.data);
async fetchUserStatus() {
const alipayStatus = await this.$api.get('/api/order/alipay/status');
const userStatus = await this.$api.get('/api/order/user/status');
}
},
getters: {},
... ...
... ... @@ -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,52 @@ module.exports = {
auth: true,
api: 'ufo.buyer.confirm',
params: {
order_code: { type: Number, require: true }, // 订单编号
orderCode: { type: Number, require: true }, // 订单编号
},
},
// 订单数量
'/api/order/confirm/count': {
ufo: true,
auth: true,
api: 'ufo.order.getAllCnt',
},
// 地址列表
'/api/order/confirm/address': {
auth: true,
api: 'app.address.gethidden',
},
// 计算订单价格
'/api/order/confirm/compute': {
auth: true,
ufo: true,
api: 'ufo.sellerOrder.computePublishPrd',
},
// 判断用户状态
'/api/order/user/status': {
auth: true,
ufo: true,
api: 'ufo.sellerOrder.entryStatus',
},
// 是绑定支付宝
'/api/order/alipay/status': {
auth: true,
ufo: true,
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 }, // 订单编号
},
},
};
... ...