Authored by lea guo

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

... ... @@ -59,6 +59,7 @@ const xianyu = {
},
goXianyuNewPage(args) {
console.log(args);
if (!args.url) {
return;
}
... ...
<template>
<div class="canvas-container" ref="canvasContainer">
<canvas ref="countCanvas"
id="countCircleCanvas"
:width="canvasWidth"
:height="canvasHeight"
:time="time"
:totalTime="totalTime"
:lineWidth="lineWidth"
></canvas>
</div>
</template>
<script>
/**
* 使用方法, 在对应页面引入CountCircle
* <CountCircle :line-width="6" :time="time" :total-time="totalTime" @on-end="onTimeEnd" style="width: 70px; height: 70px; display: block;"></CountCircle>
* 在自己的页面做定时器,修改time,
*/
export default { // 环形倒计时
name: 'CountCircle',
props: {
time: {
type: Number,
default: 60000
},
totalTime: {
type: Number,
default: 60000
},
lineWidth: {
type: Number,
default: 8
},
},
data() {
return {
canvas: null,
context: null,
interval: 100,
circle: {
x: 0,
y: 0,
radius: 0
},
canvasWidth: 200,
canvasHeight: 200,
pixelRatio: 2,
};
},
mounted() {
this.resetCanvas();
this.draw();
},
computed: {
canvasLineWidth() {
return this.lineWidth * this.pixelRatio;
}
},
methods: {
resetCanvas() {
this.canvas = this.$refs.countCanvas;
if (window.devicePixelRatio) {
this.pixelRatio = window.devicePixelRatio;
}
this.canvasWidth = this.$refs.canvasContainer.getBoundingClientRect().width * this.pixelRatio || 200;
this.canvasHeight = this.$refs.canvasContainer.getBoundingClientRect().height * this.pixelRatio || 200;
this.context = this.canvas.getContext('2d');
this.circle = {
x: this.canvasWidth / 2,
y: this.canvasHeight / 2,
radius: this.canvasWidth / 2
};
},
drawCircle() {
if (this.canvas && this.context) {
let ctx = this.context;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
ctx.save();
ctx.beginPath();
ctx.strokeStyle = 'rgba(2, 42, 71, 1)';
ctx.lineCap = 'round';
ctx.lineWidth = this.canvasLineWidth - 2;
ctx.arc(this.circle.x, this.circle.y, (this.circle.radius - this.canvasLineWidth / 2), -Math.PI / 2, (Math.PI + Math.PI / 2), false);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
},
strokeCircle(percent) {
if (this.canvas && this.context) {
this.drawCircle();
let ctx = this.context;
if (percent > 0) {
ctx.save();
ctx.strokeStyle = '#f0f0f0';
ctx.lineCap = 'square';
ctx.lineWidth = this.canvasLineWidth;
ctx.beginPath();
ctx.arc(this.circle.x, this.circle.y, (this.circle.radius - this.canvasLineWidth / 2), -Math.PI / 2, Math.PI * ( 2 * percent - 0.5), false);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
ctx.save();
ctx.font = 'bold ' + 20 * this.pixelRatio + 'px "ufofont"';
ctx.fillStyle = '#022A47';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(Math.round(this.time / 1000) + 's', this.circle.x, this.circle.y);
ctx.restore();
setTimeout(this.draw.bind(this), this.interval);
}
},
draw() {
if (this.time > 0) {
let percent = 1 - this.time / this.totalTime;
this.strokeCircle(percent);
} else {
this.$emit('on-end');
}
}
}
};
</script>
<style lang="scss" scoped>
.canvas-container {
display: block;
width: 100%;
margin: 44px auto;
canvas {
position: relative;
width: 100%;
height: 100%;
}
p {
text-align: center;
font-weight: 600;
font-size: 28px;
white-space: nowrap;
}
}
</style>
... ...
import CountCircle from './count-circle';
export default [
CountCircle
];
... ...
... ... @@ -3,11 +3,13 @@ import LayoutHeader from './layout/layout-header';
import LayoutLink from './layout/layout-link';
import Images from './images';
import YohoButton from './button';
import CountCircle from './count-circle';
export default [
LayoutApp,
LayoutHeader,
LayoutLink,
...Images,
YohoButton
YohoButton,
...CountCircle
];
... ...
... ... @@ -52,7 +52,7 @@ Vue.use(ConfirmDialog);
initClient(store);
yoho.auth = async loginUrl => {
let user = await sdk.getUser();
let user = await sdk.getUser(true);
if (user && user.uid) {
return user;
... ...
... ... @@ -2,7 +2,7 @@
<LayoutApp :show-back="true" :hide-header="hideHeader">
<div class="scroll-list-wrap">
<template v-if="isShow">
<div v-for="(item, index) in channelList.list" v-if="item.template_name == 'guessLike'">
<div v-for="(item, index) in channelList.list" :key="index" v-if="item.template_name == 'guessLike'">
<ScrollNav :list="item.data" :current="active"></ScrollNav>
</div>
</template>
... ... @@ -16,6 +16,9 @@
<div class="body" ref="body">
<div class="channel-top"></div>
<div class="marginTop">
<div class="channel-html">
<img src="../../../statics/image/channel/server.png" alt="" />
</div>
<div v-for="(item, index) in channelList.list" :key="index" class="space-between">
<Swiper :list="item.data" v-if="item.template_name == 'threePicture'"/>
<Hot :list="item.data" v-if="item.template_name == 'image_list'"/>
... ... @@ -146,7 +149,7 @@ export default {
}
.marginTop {
margin-top: -150px;
margin-top: -260px;
}
.scroll-app {
... ... @@ -199,7 +202,14 @@ export default {
left: 0;
z-index: 999;
}
.marginTop {
// margin-top: 64px;
.channel-html {
padding: 0 80px;
margin-bottom: 20px;
img {
width: 100%;
display: block;
}
}
</style>
... ...
... ... @@ -2,19 +2,19 @@
<LayoutApp>
<div class="tab">
<div class="item right-line" :class="type ==='unused' ? 'item-selected' : 'item-default'"
@click="onChangeList('unused')">未使用{{unused.length && '('+ unused.length + ')'}}
@click="onChangeList('unused')">未使用{{unused.total && '('+ unused.total + ')'}}
</div>
<div class="item right-line" :class="type ==='used' ? 'item-selected' : 'item-default'"
@click="onChangeList('used')">已使用{{used.length && '('+ used.length + ')'}}
@click="onChangeList('used')">已使用{{used.total && '('+ used.total + ')'}}
</div>
<div class="item" :class="type ==='overtime' ? 'item-selected' : 'item-default'"
@click="onChangeList('overtime')">已失效{{overtime.length && '('+ overtime.length + ')'}}
@click="onChangeList('overtime')">已失效{{overtime.total && '('+ overtime.total + ')'}}
</div>
</div>
<Scroll class="coupon-list"
:options="scrollOptions"
:data="list"
@pulling-up="onPullingUp">
@pulling-up="onPullingUp" v-show="!showEmpty">
<div class="item" v-for="(item,index) in list">
<div :class="type === 'unused' ? 'item-bg' : 'item-gray-bg'">
<div class="item-left">
... ... @@ -27,14 +27,32 @@
{{item.coupon_name}}
</div>
<div class="item-time" :class="type !== 'unused' && 'gray'">{{item.coupon_validity}}</div>
<div class="item-desc-btn" :class="type !== 'unused' && 'gray'">使用说明</div>
<div class="item-desc-btn" v-show="type === 'unused'" @click="handleShowNotice(item,index)">
使用说明
<div class="down" :class="item.showNotice && 'up'"></div>
</div>
<div class="time-up" v-if="item.is_expired_soon === 'Y'"></div>
<div class="item-used-flag" v-if="type === 'used'"></div>
<div class="item-overtime-flag" v-if="type === 'overtime'"></div>
</div>
</div>
<div class="notice" v-show="item.showNotice">
<div class="shadow"></div>
<div v-for="no in item.notes" class="row">
<div class="mr10">•</div>
<div class="no-text">{{no}}</div>
</div>
</div>
</div>
</Scroll>
<div
class="empty-wrapper"
v-show="showEmpty"
>
<div class="couponErrorPageImage"></div>
暂无优惠券
</div>
</LayoutApp>
</template>
... ... @@ -42,15 +60,18 @@
import {Scroll} from 'cube-ui';
import {createNamespacedHelpers} from 'vuex';
import EmptyList from "../../../components/ufo-no-item";
const {mapState, mapActions} = createNamespacedHelpers('home/coupon');
export default {
name: 'Coupon',
components: {Scroll},
components: {Scroll,EmptyList},
activated: function() {
this.fetchCouponList({type: 'unused', isReset: true}).then(r => {
this.type = 'unused';
this.fetchCouponList({type: 'unused', isReset: true}).then(r=>{
this.list = r;
this.showEmpty = !(r && r.length);
});
this.fetchCouponList({type: 'used', isReset: true});
this.fetchCouponList({type: 'overtime', isReset: true});
... ... @@ -64,7 +85,8 @@ export default {
pullUpLoad: true
},
type: 'unused',
list: []
list: [],
showEmpty: false,
};
},
methods: {
... ... @@ -76,10 +98,21 @@ export default {
// 切换list
this.list = this[type].list;
this.showEmpty = this[type].isEmpty;
},
handleShowNotice(item, index) {
if (item.showNotice !== void(0)) {
item.showNotice = !item.showNotice;
} else {
item.showNotice = true;
}
this.$set(this.list, index, item);
},
async onPullingUp() {
this.list = await this.fetchCouponList({type: this.type});
this.showEmpty = this[this.type].isEmpty;
},
},
... ... @@ -91,11 +124,14 @@ export default {
<style lang="scss" scoped>
.tab {
position: relative;
display: flex;
width: 100%;
height: 88px;
padding: 14px 0;
align-items: center;
z-index: 9999;
background: #fff;
.item {
font-size: 28px;
... ... @@ -106,7 +142,7 @@ export default {
}
.right-line {
border-left: 1px solid #E0E0E0;
border-right: 1px solid #E0E0E0;
}
.item-default {
... ... @@ -134,6 +170,33 @@ export default {
margin: 0 auto;
display: flex;
position: relative;
z-index: 10;
}
.down {
transform: rotate(0deg);
background: url(~statics/image/coupon/down@3x.png) no-repeat;
background-size: contain;
width: 20px;
height: 20px;
margin-left: 10px;
margin-top: 4px;
}
.up {
margin-top: -8px !important;
transform: rotate(180deg);
}
.shadow {
opacity: 0.7;
background: #fff;
position: absolute;
top: 0;
left: 0;
height: 2px;
width: 702px;
box-shadow: #ddd 0 1px 10px 10px;
}
.item-left {
... ... @@ -162,6 +225,11 @@ export default {
font-size: 24px;
color: #222;
margin-top: 22px;
width: 320px;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
overflow: hidden;
}
.item-type {
... ... @@ -174,10 +242,12 @@ export default {
color: #999;
}
.item-desc-btn{
.item-desc-btn {
margin-top: 26px;
font-size: 22px;
color: #999;
display: flex;
align-items: center;
}
.time-up {
... ... @@ -212,7 +282,7 @@ export default {
}
.gray {
color: #ccc;
color: #ccc !important;
}
.item-gray-bg {
... ... @@ -223,6 +293,52 @@ export default {
margin: 0 auto;
display: flex;
position: relative;
z-index: 10;
}
.notice {
opacity: 0.7;
background: #fff;
margin: -10px 20px 0 20px;
padding: 36px 26px 26px 26px;
position: relative;
.mr10 {
margin-right: 10px;
}
.row {
display: flex;
margin-bottom: 8px;
}
.no-text {
font-size: 22px;
color: #444;
}
}
}
.empty-wrapper {
width: 100%;
margin: auto 0;
position: absolute;
top: 0;
bottom: 0;
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 28px;
color: #b0b0b0;
}
.couponErrorPageImage {
background: url(~statics/image/coupon/no_coupon.png) no-repeat;
background-size: cover;
width: 208px;
height: 130px;
margin-bottom: 30px;
}
</style>
... ...
<template>
<LayoutApp :show-back="true" :title="title">
<Scroll :scrollEvents="['scroll']" :options="scrollOptions" @scroll="scroll"
<Scroll :scroll-events="['scroll-end','scroll']"
@scroll-end="fetchList"
v-if="favoriteProductList.list.length"
@pulling-up="onPullingUp">
>
<ProductList :list="favoriteProductList.list"></ProductList>
</Scroll>
<!-- <empty-list v-show="!isShowEmpty" /> -->
... ... @@ -42,20 +43,23 @@ export default {
this.fetchFavoriteList();
},
methods: {
...mapActions(['fetchFavoriteList','isShowEmpty']),
...mapActions(['fetchFavoriteList','isMore']),
async onPullingUp() {
async fetchList() {
if(isMore){
await this.fetchFavoriteList();
}
},
scroll({ y }) {
const height = this.$refs.banner.$el.offsetHeight + this.$refs.header.offsetHeight;
// scroll({ y }) {
// const height = this.$refs.banner.$el.offsetHeight + this.$refs.header.offsetHeight;
if (-y >= height) {
this.fixed = true;
} else {
this.fixed = false;
}
}
// if (-y >= height) {
// this.fixed = true;
// } else {
// this.fixed = false;
// }
// }
},
computed: {
... ...
... ... @@ -24,7 +24,7 @@ export default {
...mapState(
{
amountPart1: (state) => {
return (''+state.userWalletInfo.walletAmount).split('.')[0]
return (''+state.userWalletInfo.walletAmount).split('.')[0].split('¥')[1]
},
amountPart2: (state) => {
return (''+state.userWalletInfo.walletAmount).split('.')[1]
... ...
... ... @@ -7,6 +7,75 @@ import Coupon from './coupon';
export default [
{
name: 'IndexPage',
path: '/xianyu/index',
component: () => import(/* webpackChunkName: "index" */ './indexPage/index-page'),
redirect: { name: 'ChannelPage' },
props: (route) => {
switch (route.name) {
case 'ChannelPage': {
return {
tabIndex: 0
};
}
case 'CategoryPage': {
return {
tabIndex: 1
};
}
case 'NewsPage': {
return {
tabIndex: 2
};
}
case 'MinePage': {
return {
tabIndex: 3
};
}
default: {
return {
tabIndex: 0
};
}
}
},
children: [
{
name: 'ChannelPage',
path: 'channel',
component: () => import(/* webpackChunkName: "index" */ './channel/channel'),
props: () => ({
hideHeader: true,
}),
},
{
name: 'CategoryPage',
path: 'category',
component: () => import(/* webpackChunkName: "index" */ '../category/category'),
props: () => ({
hideHeader: true,
}),
},
{
name: 'NewsPage',
path: 'news',
component: () => import(/* webpackChunkName: "index" */ './news/news'),
props: () => ({
hideHeader: true,
}),
},
{
name: 'MinePage',
path: 'mine',
component: () => import(/* webpackChunkName: "index" */ './mine/mine'),
props: () => ({
hideHeader: true,
}),
},
]
},
{
name: 'channel',
path: '/xianyu/channel',
component: () => import(/* webpackChunkName: "channel" */ './channel/channel')
... ...
... ... @@ -7,6 +7,6 @@ export default [
{
name: 'newsDetail',
path: '/xianyu/newsDetail',
component: () => import(/* webpackChunkName: "newsDetail" */ './newsDetail')
component: () => import(/* webpackChunkName: "newsDetail" */ './newsDetail'),
}
];
\ No newline at end of file
... ...
... ... @@ -5,10 +5,10 @@
ref="scroll"
:options="options"
@pulling-up="onPullingUp"
:data="newsList.list">
:data="newsDeatilList.list">
<div class="news-content">
<Title :title="title"></Title>
<List :list="newsList && newsList.list || []" :isTitle="false"></List>
<List :list="newsDeatilList && newsDeatilList.list || []" :isTitle="false"></List>
</div>
</Scroll>
</div>
... ... @@ -36,7 +36,7 @@ export default {
}
},
computed: {
...mapState(['newsList']),
...mapState(['newsList','newsDeatilList']),
},
mounted() {
let params = {
... ...
... ... @@ -9,6 +9,10 @@ import Notice from './notice';
import Category from './category';
export default [
{
path: '/xianyu',
redirect: { name: 'ChannelPage' },
},
...Order,
...Common,
...List,
... ...
... ... @@ -8,31 +8,56 @@
<div class="desc">如卖家原因导致交易失败,您可获赔付200元保证金,建议您设置支付宝账号作为赔偿收款账户,如未绑定银行卡则视为放弃赔偿</div>
<div class="btn-wrap">
<YohoButton :txt="txt" class="btn-class" @click="onClick"></YohoButton>
</div>
<div class="info">
<div class="item" @click="goHome">随便逛逛</div>
</div>
<div class="recommend" v-if="productList.length">
<div class="recommend-title">为您推荐</div>
<ProductList :list="productList"></ProductList>
</div>
</div>
</LayoutApp>
</template>
<script>
import ProductList from '../list/components/productList';
import { createNamespacedHelpers } from 'vuex';
const { mapActions: mapProductAction } = createNamespacedHelpers('product');
export default {
name: 'BuyPayOk',
props: ['productId', 'orderCode'],
components: {
ProductList
},
data() {
return {
txt: '返回首页'
txt: '返回首页',
productList: []
};
},
mounted() {
if (this.productId) {
this.fetchRecommendProduct({ productId: this.productId }).then(result => {
this.productList = result;
});
}
},
methods: {
...mapProductAction(['fetchRecommendProduct']),
onClick() {
this.goHome();
},
goHome() {
this.$router.replace({
name: 'channel'
name: 'ChannelPage'
});
}
}
... ... @@ -42,7 +67,6 @@ export default {
<style lang="scss" scoped>
.body {
height: 100%;
margin: 0 32px;
padding-bottom: 140px;
overflow-y: auto;
}
... ... @@ -56,8 +80,12 @@ export default {
font-size: 120px;
}
.btn-wrap {
margin: 0 32px;
}
.btn-class {
height: 100px;
height: 88px;
font-size: 32px;
line-height: 100px;
}
... ... @@ -82,6 +110,7 @@ export default {
font-size: 28px;
display: flex;
margin-top: 30px;
margin-bottom: 66px;
.item {
width: 100%;
... ... @@ -89,4 +118,16 @@ export default {
}
}
.recommend {
background: #f5f5f5;
.recommend-title {
font-weight: bold;
font-size: 36px;
line-height: 50px;
padding: 20px 0 0;
margin: 0 40px;
}
}
</style>
... ...
... ... @@ -191,6 +191,10 @@ export default {
},
forward: {
name: 'BuyPayOk',
query: {
productId: this.productId,
orderCode: result.data.orderCode
}
}
}),
onCloseAction() {
... ...
... ... @@ -46,7 +46,7 @@ export default {
},
onLinkClick() {
if (this.url) {
this.$xianyu.goXianyuNewPage({url: this.url});
}
}
}
... ...
... ... @@ -45,6 +45,7 @@ export default [
component: () => import(/* webpackChunkName: "order" */ './buy-pay-ok'),
props: route => ({
orderCode: route.query.orderCode,
productId: route.query.productId
})
},
{
... ...
<template>
<LayoutApp :show-back="true" title="支付中">
<div class="timer-wrapper">
<div class="timer">{{count}}s</div>
</div>
<CountCircle :line-width="6" :time="count * 1000" style="width: 70px; height: 70px; display: block;"></CountCircle>
<div class="tip">正在支付中…</div>
<div class="tip2">支付成功跳转成功页面,支付失败返回上一层</div>
... ... @@ -18,17 +16,18 @@
import config from 'config';
import { UserType } from 'store/order/order-confirm';
import YohoButton from '../../components/button';
import { createNamespacedHelpers } from 'vuex';
const { mapActions: mapOrderAction } = createNamespacedHelpers('order/orderConfirm');
export default {
name: 'PayPage',
components: { YohoButton },
props: ['orderCode', 'payParams', 'extra'],
data() {
return {
count: 60,
page: null,
timer: null
timer: null,
};
},
mounted() {
... ... @@ -41,6 +40,12 @@ export default {
if (this.extra) {
this.page = JSON.parse(this.extra || '{}');
}
this.check().catch((result) => {
if (result?.data?.statusDetail?.leftTime < 60) {
this.count = result?.data?.statusDetail?.leftTime;
}
});
},
beforeRouteLeave(to, from, next) {
if (this.timer) {
... ... @@ -50,6 +55,7 @@ export default {
next();
},
methods: {
...mapOrderAction(['fetchOrderStatus']),
openPay() {
const url = config.alipayUrl + '?' + this.payParams;
... ... @@ -63,15 +69,29 @@ export default {
this.count = this.count - 1;
this.setCount();
}, 1000);
if (this.count % 5 === 0) {
this.check().catch(() => {});
}
} else {
this.goOk();
}
},
check() {
},
goOk() {
return this.fetchOrderStatus({
orderCode: this.orderCode
}).then((result) => {
if (result?.data?.statusDetail?.status === 1) {
this.$router.replace(this.page?.forward);
} else {
return Promise.reject(result);
}
});
},
async goOk() {
this.check().catch(() => {
this.goDetail();
});
},
goDetail() {
switch (this.page.type) {
... ...
... ... @@ -121,7 +121,8 @@ export default {
isAgree: false,
labelOption: {
label: '我已阅读并同意'
}
},
time: 15000
};
},
asyncData({store, router}) {
... ... @@ -241,9 +242,9 @@ export default {
this.platformFeeModalVisible = true;
},
showEarnestQuestion() { // 跳转保证金页面
showEarnestQuestion() { // 跳转保证金说明页
console.log('showEarnest');
this.$xianyu.goXianyuNewPage({url: this.agreementURL});
},
/**
... ... @@ -280,8 +281,9 @@ export default {
onCloseAction() {
that.clearData();
that.$router.replace({
name: 'InSaleOrderList',
name: 'sellOrderDetail',
params: {
owner: 'sell',
code: result.data.orderCode
}
});
... ... @@ -595,6 +597,7 @@ export default {
position: relative;
width: 100%;
height: 100px;
background-color: #fff;
button {
display: block;
... ...
... ... @@ -8,7 +8,7 @@
<ProductInfo class="product-info" :data="product"></ProductInfo>
<YohoButton :txt="txt" class="btn-class" @on-click="onClick"></YohoButton>
<YohoButton :txt="txt" class="btn-class" @click="onClick"></YohoButton>
<div class="info">
<div class="item" @click="goPublish">继续发布</div>
... ... @@ -60,7 +60,7 @@ export default {
},
goHome() {
this.$router.replace({
name: 'channel'
name: 'ChannelPage'
});
}
}
... ...
... ... @@ -18,8 +18,7 @@
@select="onSelectSize"
@add="onAdd" />
<transition name="slide-up">
<div class="footer" v-if="isAvailable">
<cube-button v-if="config.type === 'sell'" @click="convertToCash" :class="{active: isMarketable}">变现<span> <i>¥</i>{{cashPrice}}</span></cube-button>
<div class="footer">
<cube-button @click="select" :class="{active: isTradable}">{{config.title}}</cube-button>
</div>
</transition>
... ... @@ -97,25 +96,6 @@ export default {
isTradable() {
return this.isAvailable && this.selectedSize.storage_num > 0 && this.selectedSize.least_price !== '-';
},
/**
* 变现价格,使用bid_moster_price
*/
cashPrice() {
if (this.selectedSize && this.selectedSize.hasOwnProperty('bid_moster_price')) {
return this.selectedSize.bid_moster_price;
}
return '-';
},
/**
* 可变现
* 通过bid_moster_price或bid_skup判断
*/
isMarketable() {
return this.cashPrice > 0;
}
},
mounted() {
this.$refs.popup.show();
... ... @@ -148,14 +128,6 @@ export default {
bid_skup: this.selectedSize.bid_skup,
});
},
convertToCash() {
if (!this.isMarketable) {
return;
}
this.hide();
// TODO: TBD
},
},
};
</script>
... ...
... ... @@ -52,8 +52,6 @@ export default function() {
async fetchChannelList({ commit }) {
const result = await this.$api.get('/api/ufo/channel/channelList', {
content_code: 'f788335b57b67c1711f255648c744dab',
// uid: '64668089',
uid: '500031170',
});
if (result.code === 200) {
commit(Types.FETCH_CHANNEL, { list: result.data });
... ...
const uid = '500031170';
export default function() {
return {
namespaced: true,
... ... @@ -8,6 +6,7 @@ export default function() {
type: 'unused',
isFetching: false,
reachedEnd: false,
isEmpty: false,
list: [],
filter: 0,
page: 0,
... ... @@ -18,6 +17,7 @@ export default function() {
type: 'used',
isFetching: false,
reachedEnd: false,
isEmpty: false,
list: [],
filter: 0,
page: 0,
... ... @@ -28,6 +28,7 @@ export default function() {
type: 'overtime',
isFetching: false,
reachedEnd: false,
isEmpty: false,
list: [],
filter: 0,
page: 0,
... ... @@ -62,7 +63,7 @@ export default function() {
} else {
params.page += 1;
}
params.uid = uid;
let result = await this.$api.get('/api/ufo/coupon/list', {...params});
if (result.code === 200) {
... ... @@ -79,8 +80,13 @@ export default function() {
if (couponData.list.length === couponData.total) {
couponData.reachedEnd = true;
}
couponData.list.length ? couponData.isEmpty = false : couponData.isEmpty = true;
commit('addList', { data: couponData });
}
} else {
couponData.isEmpty = true;
commit('addList', { data: couponData });
}
return couponData.list || [];
},
... ...
import { get, set } from 'lodash';
import { getImgUrl } from '../../common/utils';
import Vue from 'vue';
const uid = '500031170';
// const uid = '500031170';
export default function() {
return {
... ... @@ -13,17 +13,23 @@ export default function() {
favoriteProductList: {
list:[]
},
isShowEmpty: false,
isMore: true,
},
mutations: {
addList(state, { data }) {
console.log(data)
if(data && data.product_list){
// data.product_list.
let { page, product_list = [] } = data;
let { page, product_list = [], pageTotal } = data;
let isShowEmpty = page === 1 && product_list === 0;
// console.log("isShowEmpty:"+isShowEmpty)
// state.isShowEmpty = isShowEmpty
if(pageTotal > page){
state.isMore = true;
}
state.pageTotal = pageTotal;
state.page = page + 1;
let list = state.favoriteProductList.list.concat(product_list);
Vue.set(state.favoriteProductList, "list", list);
}else {
... ... @@ -38,8 +44,10 @@ export default function() {
},
actions: {
async fetchFavoriteList({ commit }) {
const result = await this.$api.get('/api/ufo/home/favoriteProduct', {uid});
async fetchFavoriteList({ commit, state }) {
let page = state.page;
let limit = 20;
const result = await this.$api.get('/api/ufo/home/favoriteProduct', {page, limit});
if (result.code === 200) {
let data =result.data;
commit('addList', { data:data });
... ... @@ -48,6 +56,9 @@ export default function() {
commit('errorData');
}
return result.data || [];
// }else {
// return [];
// }
},
},
};
... ...
... ... @@ -46,11 +46,11 @@ export default function() {
endTime: 0,
},
userWalletInfo: {
totalAmount: 0.0,
totalAmount: 0.00,
withdrawLimit: 0,
withdrawAmount: 0,
shareSettlementAmount: 0,
walletAmount: 0.0,
walletAmount: '¥0.00',
},
filterData: {
tradeTypes: [],
... ... @@ -102,7 +102,7 @@ export default function() {
resource1: { name: 'resource1', data: state.resource1 },
income: {
title: '我的收入',
num: '¥' + state.userWalletInfo.walletAmount,
num: state.userWalletInfo.walletAmount,
page: 'income',
}, // 原交易收入 tradeIncome
buyOrder: {
... ... @@ -127,7 +127,7 @@ export default function() {
name: 'coupon',
title: '我的优惠券',
num: state.couponNum,
page: ''
page: 'Coupon'
},
service: {
name: 'service',
... ... @@ -249,6 +249,8 @@ export default function() {
state.walletData.endTime = endTime;
},
addUserWalletInfo(state, data) {
// data.totalAmount = formatNumber(data.totalAmount);
data.walletAmount = formatNumber(data.walletAmount);
state.userWalletInfo = data;
},
addfilterData(state, data) {
... ...
... ... @@ -13,6 +13,14 @@ export default function() {
totalPage: 0,
uid: '500031170',
},
newsDeatilList: {
list: [],
tabList: [],
page: 0,
limit: 10,
totalPage: 0,
uid: '500031170',
}
},
mutations: {
[Types.FETCH_NEWS_LIST](state, { list }) {
... ... @@ -21,12 +29,19 @@ export default function() {
state.newsList.totalPage = list.totalPage;
},
[Types.FETCH_NEWSDETAIL_LIST](state, { list }) {
state.newsDeatilList.list = list.page > 1 ? state.newsDeatilList.list.concat(list.list) : list.list;
state.newsDeatilList.page = list.page;
state.newsDeatilList.totalPage = list.totalPage;
},
[Types.FETCH_NEWS_TAB_LIST](state, { list }) {
state.newsList.tabList = list;
},
},
actions: {
async fetchNewsList({ commit, state }, obj) {
console.log(obj);
let page = state.newsList.page + 1;
let uid = state.newsList.uid;
let limit = state.newsList.limit;
... ... @@ -40,21 +55,23 @@ export default function() {
if (page === totalPage) {
return false;
}
const result = await this.$api.post('/api/ufo/home/newsList', {
page, uid, type, limit
page, type, limit
});
if (result.code === 200) {
// 时间戳转换 moment
result.data.list.map((res) => {
res.createTime = moment(new Date(res.createTime * 1000)).format('YYYY.MM.DD HH:mm');
});
commit(Types.FETCH_NEWS_LIST, {list: result.data});
if (obj.type == 1 || obj.type == 2 || obj.type == 3) {
commit(Types.FETCH_NEWSDETAIL_LIST, {list: result.data});
}
}
},
async fetchNewsTabList({ commit, state }) {
let uid = '500031170';
const result = await this.$api.post('/api/ufo/home/newsListTab', { uid });
async fetchNewsTabList({ commit }) {
const result = await this.$api.post('/api/ufo/home/newsListTab', {});
if (result.code === 200) {
commit(Types.FETCH_NEWS_TAB_LIST, {list: result.data});
}
... ...
... ... @@ -6,6 +6,7 @@ export const FETCH_CHANNEL = 'FETCH_CHANNEL';
export const FETCH_PRODUCT = 'FETCH_PRODUCT';
export const FETCH_NEWS_LIST = 'FETCH_NEWS_LIST';
export const FETCH_NEWS_TAB_LIST = 'FETCH_NEWS_TAB_LIST';
export const FETCH_NEWSDETAIL_LIST = 'FETCH_NEWSDETAIL_LIST';
export const FETCH_FAVORITE_LIST_REQUEST = 'FETCH_FAVORITE_LIST_REQUEST';
export const FETCH_FAVORITE_LIST_FAILD = 'FETCH_FAVORITE_LIST_FAILD';
... ...
... ... @@ -222,6 +222,12 @@ export default function() {
return this.$api.get('/api/order/goods', {
orderCode
});
},
async fetchOrderStatus(ctx, { orderCode }) {
return this.$api.get('/api/order/status', {
orderCode
});
}
},
getters: {},
... ...
... ... @@ -37,7 +37,7 @@ export default {
});
}
console.log(result);
// console.log(result);
if (result && result.code === 200) {
commit(Types.FETCH_ORDER_PRODUCT_SUCCESS, {
... ... @@ -64,7 +64,8 @@ export default {
orderCode,
tabType: 'sell'
});
console.log('fetchOrder= ', result.data);
// console.log('fetchOrder= ', result.data);
if (result && result.code === 200) {
commit(Types.FETCH_NOENTRY_ORDER_PRODUCT_SUCCESS, {
... ... @@ -89,7 +90,7 @@ export default {
commit(Types.POST_NOSALE_REQUEST);
const result = await this.$api.get('/api/ufo/sellerOrder/batchDownShelf', payload);
console.log('下架=', result);
// console.log('下架=', result);
if (result && result.code === 200) {
commit(Types.POST_NOSALE_SUCCESS, {
order: result.data
... ...
... ... @@ -3,9 +3,9 @@ import { get } from 'lodash';
import Vue from 'vue';
export default {
async fetchProductInfo({commit}, {productId}) {
async fetchProductInfo({ commit }, { productId }) {
const queryTasks = ['', '/resource', '/activity', '/recommend'].map(path => {
let params = {product_id: productId};
let params = { product_id: productId };
if (path === '/resource') {
params = {
... ... @@ -31,7 +31,12 @@ export default {
recommend: recommend && recommend.product_list || [],
}));
},
async fetchFav({commit, rootGetters}, {productId}) {
async fetchRecommendProduct({ commit }, { productId }) {
const result = await this.$api.get('/api/ufo/product/recommend', { product_id: productId })
return result?.data?.product_list ?? []
},
async fetchFav({ commit, rootGetters }, { productId }) {
let isLogin = rootGetters.getLogin;
if (!isLogin) {
... ... @@ -44,7 +49,7 @@ export default {
return false;
}
const isFav = await this.$api.get('/api/ufo/product/fav', {productId}).then(result => {
const isFav = await this.$api.get('/api/ufo/product/fav', { productId }).then(result => {
if (result.code === 200) {
return result.data;
} else {
... ... @@ -52,27 +57,27 @@ export default {
}
});
commit(Types.UPDATE_PRODUCT_FAV, {productId, isFav});
commit(Types.UPDATE_PRODUCT_FAV, { productId, isFav });
},
async fetchTop3({commit}, {productId}) {
const result = await this.$api.get('/api/ufo/product/top', {product_id: productId});
async fetchTop3({ commit }, { productId }) {
const result = await this.$api.get('/api/ufo/product/top', { product_id: productId });
if (result.code === 200) {
const productList = result.data.product_list || [];
commit(Types.UPDATE_PRODUCT_TOP3, {productId, topList: productList.slice(0, 3)});
commit(Types.UPDATE_PRODUCT_TOP3, { productId, topList: productList.slice(0, 3) });
}
},
async toggleFav({commit}, {productId, isFav}) {
const result = await this.$api.get(`/api/ufo/product/favorite/${isFav ? 'add' : 'cancel'}`, {productId});
async toggleFav({ commit }, { productId, isFav }) {
const result = await this.$api.get(`/api/ufo/product/favorite/${isFav ? 'add' : 'cancel'}`, { productId });
if (result && result.code === 200) {
commit(Types.UPDATE_PRODUCT_FAV, {productId, isFav});
commit(Types.UPDATE_PRODUCT_FAV, { productId, isFav });
}
},
async updateTradeInfo({commit, state}, {productId, sizeInfo}) {
async updateTradeInfo({ commit, state }, { productId, sizeInfo }) {
if (sizeInfo) {
commit(Types.UPDATE_SELECTED_PRODUCT_SIZE, {productId, sizeId: sizeInfo.size_id});
commit(Types.UPDATE_SELECTED_PRODUCT_SIZE, { productId, sizeId: sizeInfo.size_id });
}
return {
... ... @@ -81,18 +86,18 @@ export default {
storageId: state.selectedProductInfo.storageId,
};
},
async getSelectedTradeProduct({state, commit, dispatch}, {productId, storageId}) {
async getSelectedTradeProduct({ state, commit, dispatch }, { productId, storageId }) {
productId = parseInt(productId, 10);
storageId = parseInt(storageId, 10);
if (state.selectedProductInfo.productId !== productId && state.product.product_id !== productId) {
await dispatch('fetchProductInfo', {productId});
await dispatch('fetchProductInfo', { productId });
}
commit(Types.UPDATE_SELECTED_PRODUCT_SIZE, {productId, storageId});
commit(Types.UPDATE_SELECTED_PRODUCT_SIZE, { productId, storageId });
return state.selectedProductInfo;
},
async requestSize({state}, { sizeIds }) {
async requestSize({ state }, { sizeIds }) {
const selectedProduct = state.selectedProductInfo;
await this.$api.get('/api/ufo/product/addsize', {
... ... @@ -103,7 +108,7 @@ export default {
// 忽略错误
},
async payment(context, {skup}) {
return this.$api.post('/api/ufo/product/order/payment', {skup, api_version: 1});
async payment(context, { skup }) {
return this.$api.post('/api/ufo/product/order/payment', { skup, api_version: 1 });
},
};
... ...
... ... @@ -58,14 +58,14 @@ module.exports = {
'/api/ufo/mine/order/summary': {
ufo: true,
auth: true,
path: '/ufo-gateway/shopping',
path: 'shopping',
api: 'ufo.order.summary',
params: {},
},
'/api/ufo/mine/coupon': {
ufo: true,
auth: true,
path: '/ufo-gateway/coupon',
path: 'coupon',
api: 'ufo.coupons.cnt',
params: {},
},
... ... @@ -82,34 +82,37 @@ module.exports = {
},
'/api/ufo/home/favoriteProduct': {
ufo: true,
auth: true,
api: 'ufo.user.favoriteList',
params: {},
auth: true,
},
'/api/ufo/channel/channelList': {
ufo: true,
api: 'ufo.resource.get',
params: {
content_code: { type: String },
uid: { type: Number, require: true },
},
auth: true,
},
'/api/ufo/home/newsList': {
ufo: true,
auth: true,
api: 'ufo.users.listInboxs',
params: {
uid: { type: Number },
},
params: {},
auth: true,
},
'/api/ufo/home/newsListTab': {
ufo: true,
auth: true,
api: 'ufo.users.listInboxTypeInfo',
params: {
uid: { type: Number },
},
params: {},
auth: true,
},
'/api/ufo/coupon/list': {
ufo: true,
path: '/ufo-gateway/coupon',
auth: true,
path: 'coupon',
api: 'ufo.coupons.list',
param: {
page: {type: Number},
... ...
... ... @@ -306,7 +306,14 @@ module.exports = {
'/api/order/goods': {
ufo: true,
auth: true,
api: 'ufo.buyerOrder.goodsDetail',
api: 'ufo.order.goodsDetail',
params: {}
},
'/api/order/status': {
ufo: true,
auth: true,
api: 'ufo.order.payDetail',
params: {}
},
... ...
... ... @@ -59,20 +59,9 @@ module.exports = {
},
},
// 限制出售
'/api/ufo/product/limit': {
ufo: true,
auth: false,
api: 'ufo.product.limitInfo',
params: {
product_id: {type: Number}, // 商品id
},
},
// TOP3
'/api/ufo/product/top': {
ufo: true,
auth: false,
api: 'ufo.product.data.search.recommendBySeriesBrand',
params: {
product_id: {type: Number}, // 商品id
... ... @@ -82,26 +71,12 @@ module.exports = {
// 推荐
'/api/ufo/product/recommend': {
ufo: true,
auth: false,
api: 'ufo.product.data.search.recommend',
params: {
product_id: {type: Number}, // 商品id
},
},
// 建议尺码
'/api/ufo/product/addsize': {
ufo: true,
auth: true,
path: '/ufoLive',
api: 'ufo.product.addSize',
params: {
product_id: {type: Number}, // 商品id
goods_id: {type: Number}, // 商品id
size_ids: {type: String}, // 建议尺码id
},
},
// 入驻状态 用户入驻状态,这里放入product命名下,防止冲突
'/api/ufo/product/user/entrystatus': {
ufo: true,
... ...
const _ = require('lodash');
const url = require('url');
const uuid = require('uuid');
const passport = require('passport');
const TaobaoStrategy = require('./passport-taobao');
... ... @@ -13,6 +14,8 @@ const config = global.yoho.config;
const loginPage = '//m.yohobuy.com/signin.html';
const homePage = `${config.siteUrl}/xianyu/channel`;
const URL_BIND_KEY = 'bind_code';
// taobao 登录
passport.use('taobao', new TaobaoStrategy({
clientID: '27930297',
... ... @@ -23,6 +26,19 @@ passport.use('taobao', new TaobaoStrategy({
done(null, profile);
}));
function handleReferUrl(refer) {
let referParse = url.parse(refer, true);
let query = [];
_.forEach(referParse.query, (val, key) => {
if (key !== URL_BIND_KEY) {
query.push(`${key}=${val}`);
}
});
return `${refer.split('?')[0]}${query.length ? '?' : ''}${query.join(',')}`;
}
class passportModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
... ... @@ -147,11 +163,15 @@ const login = {
}).then(result => {
let redirectUrl = loginPage;
if (req.cookies.third_backurl) {
redirectUrl += '?refer=' + encodeURIComponent(handleReferUrl(req.cookies.third_backurl));
}
if (result.code === 200) {
if (_.get(result, 'data.is_bind') === 'N') {
redirectUrl = req.cookies.third_backurl ? req.cookies.third_backurl : homePage;
redirectUrl += redirectUrl.indexOf('?') > 0 ? '&' : '?';
redirectUrl += 'bind_code=' + encodeURIComponent(aes.dynamicEncryption(`taobao::${user.open_uid}`));
redirectUrl += URL_BIND_KEY + '=' + encodeURIComponent(aes.dynamicEncryption(`taobao::${user.open_uid}`));
} else if (+_.get(result, 'data.uid') > 0) {
return model.syncUserSession({
uid: result.data.uid,
... ... @@ -159,9 +179,10 @@ const login = {
req,
res
}).finally(() => {
let refer = req.cookies.third_backurl ? req.cookies.third_backurl : homePage;
return res.redirect(refer);
res.cookie('third_backurl', '', {
domain: 'yohobuy.com'
});
return res.redirect(handleReferUrl(req.cookies.third_backurl ? req.cookies.third_backurl : homePage));
});
}
} else {
... ...