Authored by yyq

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

import Vue from 'vue';
import { ROUTE_CHANGE } from 'store/yoho/types';
import { createApp } from './app';
import { createApi } from 'create-api';
import { Style, Toast, Dialog, DatePicker, ImagePreview } from 'cube-ui'; //eslint-disable-line
import { get } from 'lodash';
import {
ROUTE_CHANGE
} from 'store/yoho/types';
import {
createApp
} from './app';
import {
createApi
} from 'create-api';
import {
Style,
Toast,
Dialog,
DatePicker,
ImagePreview
} from 'cube-ui'; //eslint-disable-line
import {
get
} from 'lodash';
import Lazy from 'vue-lazyload';
import cookie from 'yoho-cookie';
import yoho from 'common/yoho';
... ... @@ -13,10 +27,13 @@ import OrderCouponList from 'components/order-coupon-list';
import OrderPromotionList from 'components/order-promotion-list';
import Bind from 'components/bind';
import ConfirmDialog from 'components/confirm-dialog';
import 'video.js/dist/video-js.css';
import sdk from 'yoho-activity-sdk';
import { initClient } from 'utils/init-client';
import {
initClient
} from 'utils/init-client';
import 'statics/scss/common.scss';
import 'statics/font/iconfont.css';
import 'statics/font/ufofont.css';
... ... @@ -25,7 +42,11 @@ const $app = document.getElementById('app');
const isDegrade = Boolean(!($app && $app.attributes['data-server-rendered']));
const context = get(window, '__INITIAL_STATE__.yoho.context');
const { app, router, store } = createApp(context);
const {
app,
router,
store
} = createApp(context);
const api = createApi();
if (window.__INITIAL_STATE__) {
... ... @@ -42,7 +63,9 @@ Vue.use(DatePicker);
Vue.use(Dialog);
Vue.use(ImagePreview);
Vue.prop('api', api);
Vue.use(Lazy, { error: '' });
Vue.use(Lazy, {
error: ''
});
Vue.use(OrderPayType);
Vue.use(OrderCouponList);
Vue.use(OrderPromotionList);
... ... @@ -53,7 +76,10 @@ initClient(store);
xianyu.$router = router;
yoho.auth = async (args) => {
let { refer, loginUrl } = args || {};
let {
refer,
loginUrl
} = args || {};
let user = await sdk.getUser(true);
if (user && user.uid) {
... ... @@ -96,7 +122,12 @@ yoho.authRealName = async () => {
const fetchAsycData = (matched, r) => {
const asyncDataPromises = matched
.map(({ asyncData }) => asyncData && asyncData({ store, router: r }))
.map(({
asyncData
}) => asyncData && asyncData({
store,
router: r
}))
.filter(p => p);
return Promise.all(asyncDataPromises);
... ... @@ -139,7 +170,10 @@ router.onReady(() => {
trackPage(to.fullPath);
const matched = router.getMatchedComponents(to);
store.commit(ROUTE_CHANGE, { to, from });
store.commit(ROUTE_CHANGE, {
to,
from
});
store.dispatch('reportYas', {
params: {
... ... @@ -155,12 +189,16 @@ router.onReady(() => {
fetchAsycData(matched, to)
.then(next)
.catch(e => {
store.dispatch('reportError', { error: e });
store.dispatch('reportError', {
error: e
});
console.error(e);
return next();
});
} catch (e) {
store.dispatch('reportError', { error: e });
store.dispatch('reportError', {
error: e
});
return next();
}
});
... ... @@ -168,6 +206,10 @@ router.onReady(() => {
});
router.onError(e => {
store.dispatch('reportError', { error: e });
router.push({ name: 'error.500' });
store.dispatch('reportError', {
error: e
});
router.push({
name: 'error.500'
});
});
... ...
... ... @@ -25,7 +25,7 @@
</div>
<div class="list-wrap" :style="{minHeight: total + 'px'}">
<ProductList :list="productList.list" v-if="productList.list.length > 0"></ProductList>
<UfoNoItem :tip="`暂无数据`" v-else style="margin-top: 60px;"></UfoNoItem>
<UfoNoItem :tip="`暂无数据`" v-else></UfoNoItem>
</div>
</div>
</Scroll>
... ... @@ -54,13 +54,12 @@ export default {
data() {
return {
options: {
scrollbar: true,
pullUpLoad: true,
// pullDownRefresh: true,
pullDownRefresh: {
txt: '刷新成功',
visible: true,
}
},
scrollEvents: ['scroll'],
scrollY: 0,
... ... @@ -157,11 +156,10 @@ export default {
},
async onPullingUp() {
if (this.productList.endReached) {
this.$refs.scroll.forceUpdate();
return;
}
console.log('111')
// if (this.productList.endReached) {
// this.$refs.scroll.forceUpdate();
// return;
// }
await this.fetchList();
this.$refs.scroll.forceUpdate();
... ... @@ -255,8 +253,8 @@ export default {
content: "";
position: absolute;
width: 100%;
height: 0;
box-shadow: 0 0 120px 100px #fefefe;
height: 100px;
box-shadow: 0 0 120px 100px #f2f2f2 !important;
}
&.fixed-nav {
... ... @@ -309,15 +307,16 @@ export default {
}
.list-wrap {
background: #fefefe;
overflow: hidden;
background: #f2f2f2;
/deep/ .item {
position: relative;
z-index: 1;
}
}
.cube-scroll-wrapper {
background: #fefefe;
.yohoufo-channel-page {
/deep/ .cube-pullup-wrapper {
background: #f2f2f2;
}
}
</style>
... ...
<template>
<div class="container" v-show="showType">
<div class="header">
<div class="back" @click="back()"></div>
<div class="title">筛选
<div class="cancel" @click="back()">取消</div>
</div>
<div class="title">筛选</div>
<div class="content-search">
<div class="item" v-if="filterData && filterData.length" v-for="(filter,row) in filterData">
<div class="item-title">{{filter.filterName}}</div>
... ... @@ -210,8 +209,15 @@ export default {
color: #000;
height: 82px;
line-height: 82px;
margin-bottom: 50px;
margin-left: 40px;
margin: 40px;
flex-direction: row;
display: flex;
justify-content: space-between;
.cancel {
font-size: 38px;
color: #888;
}
}
.content-search {
... ...
... ... @@ -36,7 +36,7 @@ import Filtrate from './filtrate';
import EmptyList from '../../components/ufo-no-item';
import {Scroll} from 'cube-ui';
import {createNamespacedHelpers} from 'vuex';
import {mapState, createNamespacedHelpers} from 'vuex';
const {mapActions} = createNamespacedHelpers('list');
... ... @@ -93,6 +93,10 @@ export default {
};
},
activated: function() {
if (this.yoho.direction === 'forword') {
this.$refs.filtrate.hide();
Object.assign(this.$data, this.$options.data());
}
this.changeArrow();
let params = this.$route.query;
... ... @@ -112,8 +116,13 @@ export default {
!params.order && (params.order = 'sale_desc');
this.fetchList({...params, isReset: true});
},
computed: {
...mapState(['yoho'])
},
methods: {
...mapActions(['fetchProductList']),
...mapActions(['fetchProductList', 'getDirection']),
// 上拉加载
async onPullingUp() {
... ... @@ -195,7 +204,7 @@ export default {
this.selectedType = type;
if (type === 1) {
this.priceDesc = !this.priceDesc;
params.order = !this.priceDesc ? 'p_desc' : 'p_asc';
params.order = this.priceDesc ? 'p_desc' : 'p_asc';
} else if (type === 2) {
this.priceDesc = true;
params.order = 'sale_desc';
... ...
... ... @@ -546,7 +546,7 @@ export default {
.feeTotalRight {
font-family: PingFangSC-Regular;
font-size: 14px;
font-size: 14*2px;
color: #D0021B;
letter-spacing: 0;
text-align: right;
... ...
... ... @@ -10,13 +10,6 @@
<i class="cubeic-arrow" ></i>
</div>
</div>
<!--<Select-->
<!--v-model="chooseday"-->
<!--:title="title"-->
<!--:options="options"-->
<!--@change="change"-->
<!--class="customSelect"-->
<!--/>-->
</div>
</template>
... ... @@ -88,20 +81,16 @@ export default {
</script>
<style lang="scss" scoped>
.customSelectWrapper {
position: relative;
height: 60px;
padding-top: 10px;
}
.customSelectTextWrapper {
position: absolute;
width: 100%;
height: 100%;
height: 60px;
display: flex;
flex-direction: row;
justify-content: space-between;
... ... @@ -110,7 +99,7 @@ export default {
.leftText {
font-family: PingFang-SC-Regular;
font-size: 14px;
font-size: 14*2px;
color: #000000;
letter-spacing: 0;
}
... ... @@ -121,7 +110,7 @@ export default {
.rightText {
font-family: PingFang-SC-Regular;
font-size: 14px;
font-size: 14*2px;
color: #000000;
letter-spacing: 0;
}
... ...
<template>
<div class="change-bid-price-wrapper"></div>
<div class="change-bid-price-wrapper">
<p class="price-item">
<span>我的求购价:</span>
<span>¥{{ goodsInfo.goodPrice }}</span>
</p>
<p class="price-item">
<span>当前最高求购价:</span>
<span>¥{{ goodsInfo.goodPrice }}</span>
</p>
<p class="price-item">
<span>最低现货价:</span>
<span>¥{{ goodsInfo.leastPrice }}</span>
</p>
<p v-for="(priceInfo, i) in computePriceList" :key="i">
<span>{{ priceInfo.promotion }}:</span>
<span>{{ priceInfo.promotionAmount }}</span>
</p>
<p class="a-tip">Tip: 调整求购价成功后,当前的求购将被关闭</p>
</div>
</template>
<script>
export default {};
import { createNamespacedHelpers } from "vuex";
const { mapActions } = createNamespacedHelpers("order/orderList");
export default {
props: {
computePriceInfo: {
type: Object,
default: () => ({})
},
goodsInfo: {
type: Object,
default: () => ({})
}
},
computed: {
computePriceList() {
return this.computePriceInfo.promotionFormulaList.filter(
({ promotion }) => promotion === "运费" || promotion === "实付金额"
);
}
},
methods: {
...mapActions(["computeChangePrice", "changePrice"])
}
};
</script>
<style scoped>
<style lang="scss" scoped>
.change-bid-price-wrapper {
font-size: 12px;
color: #000;
padding: 0 38px;
letter-spacing: 0;
.tip {
color: #999;
}
}
</style>
\ No newline at end of file
... ...
<template>
<div class="actions-wrapper">
<Button
v-for="action in actionList"
:key="action.code"
@click="() => onActionHandler(action)"
<div class="pane-body">
<div
class="video-wrapper"
v-if="appraiseVideoUrl"
@click="() => onVideoHandler({videoUrl:appraiseVideoUrl, orderCode: order.orderCode})"
>
{{ action.text }}
</Button>
<div class="play-btn"></div>
<div class="play-txt">鉴定视频</div>
</div>
<div class="after-video" v-else></div>
<div class="actions-wrapper">
<Button
v-for="action in actionList"
:key="action.code"
@click="() => onActionHandler(action)"
>{{ action.text }}</Button>
</div>
</div>
</template>
... ... @@ -27,6 +36,9 @@ export default {
computed: {
actionList: function() {
return this.order.buttons;
},
appraiseVideoUrl: function() {
return this.order.appraiseVideoUrl;
}
},
methods: {
... ... @@ -125,6 +137,9 @@ export default {
default:
this.$emit("on-action", action);
}
},
onVideoHandler(params) {
this.$emit("on-video", params);
}
}
};
... ... @@ -146,6 +161,33 @@ export default {
</style>
<style lang="scss" scoped>
.pane-body {
display: flex;
justify-content: space-between;
}
.video-wrapper {
display: flex;
align-items: center;
.play-btn {
width: 28.4px;
height: 28.4px;
background: url("~statics/image/order/play@3x.png");
background-size: cover;
}
.play-txt {
margin-left: 6.8px;
color: #000;
font-size: 24px;
line-height: 1.4;
}
}
.after-video {
background-color: transparent;
}
.actions-wrapper {
display: flex;
justify-content: flex-end;
... ...
<template>
<div class="video-player">
<video
v-if="showVideo"
ref="videoPlayer"
class="video-js vjs-matrix vjs-yoho"
controls
:poster="coverImg"
preload="auto"
muted="muted"
autoplay="none"
playsinline
x5-playsinline
webkit-playsinline="true"
>
<source :src="source" :type="sourceType" />
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser
</p>
<div class="vjs-yoho-voice"></div>
</video>
</div>
</template>
<script>
import { get } from "lodash";
import videojs from "video.js";
import { getArticleImageSize, processImage } from "utils/image-handler";
export default {
name: "VideoPlayer",
props: {
source: String,
cover: String,
width: [Number, String],
height: [Number, String],
options: {
type: Object,
default() {
return {
muted: true,
controls: true,
aspectRatio: "1:1"
};
}
}
},
data() {
return {
showVideo: false,
player: null
};
},
computed: {
coverImg() {
if (this.cover) {
if (this.width && this.height) {
let imgSize = getArticleImageSize({
width: this.width,
height: this.height,
minScale: 0,
maxWidth: 500
});
return processImage(
this.cover,
2,
imgSize.width,
imgSize.height,
get(this.yoho, "window.supportWebp")
);
} else {
return this.cover.split("?")[0];
}
} else {
return "";
}
},
sourceType() {
let type = "video/mp4";
if (this.source) {
let source = this.source.split("?")[0];
source = source.split(".");
switch (source[source.length - 1]) {
case "opus":
case "ogv":
type = "video/ogg";
break;
case "mkv":
type = "video/x-matroska";
break;
case "m3u8":
type = "application/x-mpegURL";
break;
case "m4a":
type = "audio/mp4";
break;
case "mp3":
type = "audio/mpeg";
break;
case "aac":
type = "audio/aac";
break;
case "oga":
type = "audio/ogg";
break;
default:
break;
}
}
return type;
}
},
watch: {
source() {
this.showPlayer();
}
},
mounted() {
this.showPlayer();
},
beforeDestroy() {
if (this.player) {
this.player.dispose();
}
},
methods: {
parentHandleclick() {
this.player.play();
const timeId = setTimeout(() => {
this.player.requestFullscreen();
clearTimeout(timeId);
});
},
showPlayer() {
if (this.showVideo || !this.source) {
return;
}
this.showVideo = true;
this.$nextTick(() => {
this.initPlayer();
});
},
initPlayer() {
const noVioceClass = "vjs-yoho-novoice";
this.player = videojs(this.$refs.videoPlayer, this.options);
this.voiceBtn = this.player.addChild("button");
this.voiceBtn.addClass("vjs-yoho-voice");
this.voiceBtn.addClass(noVioceClass);
this.backBtn = this.player.addChild("button");
this.backBtn.addClass("vjs-yoho-back");
this.voiceBtn.on("touchend", () => {
this.player.muted(!this.voiceBtn.hasClass(noVioceClass));
});
this.backBtn.on("touchend", () => {
this.player.exitFullscreen();
});
this.player.on("play", () => {
this.player._yohoPlayTime = this.getTime();
});
this.player.on("pause", () => {
this.player._yohoPauseTime = this.getTime();
});
this.player.on("ended", () => {
this.player._yohoEndedTime = this.getTime();
});
this.player.on("fullscreenchange", () => {
this.player._yohoPlayTime = this.getTime();
});
this.player.on("volumechange", () => {
const soundOff = this.player.muted() || this.player.volume() === 0;
if (soundOff) {
this.voiceBtn.addClass(noVioceClass);
} else {
this.voiceBtn.removeClass(noVioceClass);
}
});
// setTimeout(() => {
// this.$yoho.getNetStatus({}, res => {
// if (res && +res.wifi === 1) {
// this.player.autoplay("muted");
// }
// });
// }, 1000);
},
getTime() {
return new Date().getTime();
}
}
};
</script>
<style lang="scss" scoped>
.video-js {
width: 100%;
height: auto;
video {
width: 100%;
}
&.vjs-yoho /deep/ {
position: relative;
background-color: #222;
.vjs-resize-manager {
z-index: 0;
visibility: hidden;
}
.vjs-poster {
background-color: #222;
}
.vjs-yoho-voice {
width: 60px;
height: 60px;
position: absolute;
top: 20px;
right: 28px;
opacity: 0;
visibility: hidden;
background: url("~statics/image/components/video-voice-icon.png");
background-size: cover;
background-repeat: no-repeat;
&.vjs-yoho-novoice {
background-position: bottom left;
}
}
&.vjs-has-started .vjs-yoho-voice {
visibility: visible;
opacity: 1;
transition: visibility 1s, opacity 1s;
}
&.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-yoho-voice {
visibility: visible;
opacity: 0;
}
.vjs-big-play-button {
width: 126px;
height: 126px;
line-height: 126px;
font-size: 60px;
border: none;
left: 50%;
top: 50%;
margin: -63px auto auto -63px;
/*background: url("~statics/image/components/video-play-btn.png");*/
background: url("data:image/png;base64,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");
background-size: contain;
background-repeat: no-repeat;
> * {
display: none;
}
}
@keyframes roundframe {
0% {
-webkit-transform: rotate(0deg);
}
25% {
-webkit-transform: rotate(90deg);
}
50% {
-webkit-transform: rotate(180deg);
}
75% {
-webkit-transform: rotate(270deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
.vjs-loading-spinner {
width: 110px;
height: 110px;
margin-top: -55px;
margin-left: -55px;
border: none;
background: url("~statics/image/components/video-loading-icon.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
visibility: visible;
animation: roundframe 1.3s linear infinite;
&:before,
&:after,
> * {
display: none;
}
}
.vjs-control-bar {
height: 80px;
background: none;
padding-bottom: 20px;
.vjs-control {
width: 80px;
}
.vjs-play-control {
width: 60px;
height: 60px;
margin-left: 20px;
background: url("~statics/image/components/video-play-icon.png");
background-size: cover;
&.vjs-playing {
background-position: bottom left;
}
> * {
display: none;
}
}
.vjs-volume-panel {
display: none;
}
.vjs-duration,
.vjs-current-time {
display: block;
order: 3;
> span {
font-size: 22px;
font-weight: 300;
}
}
.vjs-time-control {
line-height: 60px;
}
.vjs-current-time {
order: 1;
}
.vjs-remaining-time {
display: none;
}
.vjs-progress-control {
order: 2;
.vjs-progress-holder {
margin: 0;
}
.vjs-progress-holder,
.vjs-load-progress,
.vjs-play-progress {
height: 1px;
}
.vjs-play-progress:before {
font-size: 10px;
top: 0;
transform: translateY(-44%);
}
}
.vjs-fullscreen-control {
order: 4;
width: 60px;
height: 60px;
margin-right: 20px;
background: url("~statics/image/components/video-fullscreen-icon.png");
background-size: cover;
> * {
display: none;
}
}
.vjs-icon-placeholder:before {
font-size: 38px;
line-height: 60px;
}
}
&.vjs-fullscreen .vjs-fullscreen-control {
background-position: bottom left;
}
&.vjs-fullscreen .vjs-yoho-back {
width: 40px;
height: 42px;
background: url("~statics/image/components/video-back-icon.png");
background-size: contain;
background-repeat: no-repeat;
position: absolute;
top: 20px;
left: 32px;
}
}
}
</style>
... ...
... ... @@ -3,6 +3,7 @@
import { orderActionsMap, ownType } from 'constants/order-constants';
import { createNamespacedHelpers } from 'vuex';
import DialogConfirmInfo from '../../components/dialog-confirm-info';
import DialogChangeBidPrice from '../../components/dialog-change-bid-price';
const { mapActions, mapMutations } = createNamespacedHelpers('order/orderList');
const { mapMutations: inSaleMapMutations } = createNamespacedHelpers(
... ... @@ -11,14 +12,25 @@ const { mapMutations: inSaleMapMutations } = createNamespacedHelpers(
export default {
methods: {
...mapActions(['cancelTradeConfirmInfo', 'cancelTrade', 'deleteOrder']),
...mapActions([
'cancelTradeConfirmInfo',
'cancelTrade',
'deleteOrder',
'computeChangePrice',
'changePrice',
]),
...mapMutations(['filterOrderList', 'resetData']),
...inSaleMapMutations(['filterInSaleOrderList']),
// 订单列表
async onAction({ action, order }) {
const { owner = ownType.SELL } = this.$route.params;
const { orderCode, realPrice = '', bidDepositInfo = {} } = order;
const {
orderCode,
realPrice = '',
bidDepositInfo = {},
goodsInfo = {},
} = order;
switch (action.name) {
case orderActionsMap.DEL_ORDER.name:
... ... @@ -140,7 +152,27 @@ export default {
}
case orderActionsMap.CHANGE_BID_PRICE.name: {
this.$createDialog({ type: 'prompt' }).show();
const { goodPrice } = goodsInfo;
const computePriceInfo = await this.computeChangePrice({
orderCode,
price: goodPrice,
});
this.$createDialog(
{
type: 'prompt',
confirmBtn: { text: '调整求购价' },
cancelBtn: { active: true },
},
createElement => {
return [
createElement(DialogChangeBidPrice, {
props: { computePriceInfo, goodsInfo },
slot: 'content',
}),
];
},
).show();
break;
}
case orderActionsMap.NOT_SOLD.name: {
... ...
... ... @@ -20,17 +20,21 @@
class="actions"
:order="order"
@on-action="action => onAction({ action, order })"
@on-video="params => onVideoHandle(params)"
/>
</div>
<div ref="videoWrapper">
<VideoPlayer
:ref="order.orderCode"
class="play-video"
:source="order.appraiseVideoUrl"
></VideoPlayer>
</div>
</li>
</ul>
</scroll>
<empty-list
class="empty-wrapper"
tip="这里什么都没有..."
v-show="isShowEmpty"
/>
<empty-list class="empty-wrapper" tip="这里什么都没有..." v-show="isShowEmpty" />
</div>
</layout-app>
</template>
... ... @@ -42,6 +46,7 @@ import { createNamespacedHelpers } from "vuex";
import OrderItem from "./components/order-item";
import StatusNav from "./components/status-nav";
import OrderItemHeader from "./components/order-item-header";
import VideoPlayer from "./components/video-player";
import EmptyList from "components//ufo-no-item";
... ... @@ -64,7 +69,8 @@ export default {
OrderItemHeader,
EmptyList,
OrderActions,
CountDown
CountDown,
VideoPlayer
},
computed: {
...mapState(["orderList", "pullUpLoad", "isShowEmpty"]),
... ... @@ -87,6 +93,24 @@ export default {
...mapActions(["fetchOrderList", "confirmReceipt"]),
fetchData() {
this.fetchOrderList(this.$route.params);
},
onVideoHandle({ videoUrl, orderCode }) {
if (!videoUrl) {
return;
}
const $video = this.$refs[`${orderCode}`][0];
if ($video) {
$video.parentHandleclick();
}
}
},
mounted() {
if (this.$yoho.isAndroid) {
this.$refs.videoWrapper.forEach($vnode => {
$vnode.style.position = "absolute";
$vnode.style.top = "-1000px";
});
}
}
};
... ... @@ -121,10 +145,16 @@ export default {
border-bottom: 1px solid #eee;
}
.play-video {
display: inline-block;
height: 10px;
opacity: 0;
}
& :last-child {
border-bottom: 0;
}
}
}
}
</style>
\ No newline at end of file
</style>
... ...
... ... @@ -28,7 +28,7 @@
<script>
import { Scroll } from 'cube-ui';
import { sortBy } from 'lodash';
import { orderBy } from 'lodash';
export default {
name: 'size-list',
... ... @@ -73,13 +73,40 @@ export default {
return this.list || [];
}
if (!this.simplePrice) {
const list = sortBy(this.list, 'order_by').reverse();
let list;
return list.map(this.priceMap);
if (!this.simplePrice) {
list = this.list.map(this.priceMap);
} else {
list = this.list.map(this.simplePriceMap);
}
return this.list.map(this.simplePriceMap);
/**
* 根据 name 及 subName 从小到大排列
* @type {Array}
*/
const sorted = orderBy(list, [o => parseFloat(o.name), o => {
if (o.subName == null) {
return 0;
}
let subName = o.subName.split('/');
if (subName.length === 2) {
if (subName[1] === '0') {
subName = subName[0];
} else {
subName = parseFloat(subName[0]) / parseFloat(subName[1]);
}
}
subName = parseFloat(subName);
if (isNaN(subName)) {
return 0;
}
return subName;
}]);
return sorted;
},
},
methods: {
... ... @@ -95,10 +122,10 @@ export default {
const name = info.size_name.split(/\s+/);
// 区分交易(buy|sell),变现
const isTradable = info.storage_num > 0 && price !== '-';
const isTradable = this.config.type === 'buy' && info.storage_num > 0 && price !== '-';
// 出售: 只要上架,都可出售
const isMarketable = this.config.type === 'sell' || info.bid_moster_price > 0;
const isMarketable = this.config.type === 'sell';
return {
size_id: info.size_id,
... ...
... ... @@ -29,7 +29,7 @@
<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>
<cube-button v-if="isQiugouEnabled && isMarketable" @click="convertToCash" :class="{active: isMarketable}">变现<span> <i>¥</i>{{cashPrice}}</span></cube-button>
<cube-button @click="select" :class="{active: isTradable}">{{config.title}}</cube-button>
</div>
</transition>
... ... @@ -41,7 +41,7 @@
<script>
import { Scroll, Button } from 'cube-ui';
import { get } from 'lodash';
import { createNamespacedHelpers, mapActions } from 'vuex';
import { createNamespacedHelpers, mapActions, mapGetters } from 'vuex';
import ActionSheet from './action-sheet';
import SizeList from './size-list';
... ... @@ -83,6 +83,7 @@ export default {
},
computed: {
...mapState(['selectedProductInfo']),
...mapGetters(['isQiugouEnabled']),
selectedSize() {
if (this.selectedProductInfo.productId === this.product.product_id) {
return this.selectedProductInfo.size;
... ... @@ -114,7 +115,8 @@ export default {
isTradable() {
return this.isAvailable && (
(this.config.type === 'buy' && this.selectedSize.storage_num > 0 && this.selectedSize.least_price !== '-') ||
(this.config.type === 'sell'));
this.isMarketable
);
},
/**
... ... @@ -133,7 +135,7 @@ export default {
* 通过bid_moster_price或bid_skup判断
*/
isMarketable() {
return this.cashPrice > 0;
return this.config.type === 'sell' && this.cashPrice > 0;
}
},
mounted() {
... ...
... ... @@ -183,12 +183,10 @@ export default {
}
},
activated() {
if (this.productId !== this.productDetail.product_id) {
this.loadData(this.productId);
}
this.loadData(this.productId);
},
methods: {
...mapActions(['fetchProductInfo', 'fetchTop3', 'fetchFav', 'toggleFav', 'updateTradeInfo', 'getSelectedTradeProduct', 'payment']),
...mapActions(['fetchProductInfo', 'fetchTop3', 'fetchFav', 'toggleFav', 'updateTradeInfo', 'getSelectedTradeProduct', 'payment', 'resetSelectedSize']),
refresh() {
this.$refs.slide.refresh();
},
... ... @@ -295,6 +293,7 @@ export default {
return;
}
this.resetSelectedSize();
this.selectSizeConfig = {
dest: 'OrderBuyConfirm',
type: 'buy',
... ... @@ -313,6 +312,7 @@ export default {
return;
}
this.resetSelectedSize();
this.selectSizeConfig = {
dest: 'OrderSellConfirm',
type: 'sell',
... ...
... ... @@ -61,12 +61,7 @@ export default function() {
let result = await this.$api.get('/api/ufo/list/searchSuggest', {query});
commit('setSearchSuggest', {searchSuggestList: result.data});
},
initData: function({commit}) {
commit('initData');
}
}
};
}
... ...
... ... @@ -157,6 +157,29 @@ export default function() {
return res.code === 200 ? res.data : null;
},
// 买家调价计算
async computeChangePrice(_, { orderCode, price }) {
const res = await this.$api.get(
'/api/order/buyerask/computechangeprice',
{
orderCode: `${orderCode}`,
price: +price,
},
);
return res.code === 200 ? res.data : null;
},
// 买家调价
async changePrice(_, { orderCode, price }) {
const res = await this.$api.post('/api/order/buyerask/changeprice', {
orderCode: `${orderCode}`,
price: +price,
});
return res.code === 200 ? res.data : null;
},
},
getters: {},
};
... ...
... ... @@ -100,6 +100,9 @@ export default {
return state.selectedProductInfo;
},
resetSelectedSize({commit}) {
commit(Types.RESET_SELECTED_PRODUCT_SIZE);
},
async requestSize({ state }, { sizeIds }) {
const selectedProduct = state.selectedProductInfo;
... ...
import actions from './actions';
import mutations from './mutations';
export function defaultSelectedSize() {
return {
productId: null,
product: {},
sizeId: null,
storageId: null,
size: {},
};
}
export function defaultProduct() {
return {
brand_name: '',
... ... @@ -51,13 +61,7 @@ export function defaultState() {
* storageId: 库存id
* size: 尺寸信息
*/
selectedProductInfo: {
productId: null,
product: {},
sizeId: null,
storageId: null,
size: {},
},
selectedProductInfo: defaultSelectedSize(),
};
}
... ...
import * as Types from './types';
import { find } from 'lodash';
import { defaultProduct } from './index';
import { defaultProduct, defaultSelectedSize } from './index';
function ensureProduct(state, productId) {
if (state.products[productId] === undefined) {
... ... @@ -55,4 +55,7 @@ export default {
}
state.selectedProductInfo.size = sizeInfo;
},
[Types.RESET_SELECTED_PRODUCT_SIZE](state) {
Object.assign(state.selectedProductInfo, defaultSelectedSize());
},
};
... ...
... ... @@ -2,4 +2,5 @@ export const UPDATE_PRODUCT_DETAIL = 'UPDATE_PRODUCT_DETAIL';
export const ENSURE_PRODUCT_DETAIL = 'ENSURE_PRODUCT_DETAIL';
export const UPDATE_PRODUCT_FAV = 'UPDATE_PRODUCT_FAV';
export const UPDATE_SELECTED_PRODUCT_SIZE = 'UPDATE_SELECTED_PRODUCT_SIZE';
export const RESET_SELECTED_PRODUCT_SIZE = 'RESET_SELECTED_PRODUCT_SIZE';
export const UPDATE_PRODUCT_TOP3 = 'UPDATE_PRODUCT_TOP3';
... ...
/* eslint-disable lines-around-comment */
/* eslint-disable spaced-comment */
// 查询订单数量
const ORDER_COUNT = 'ufo.order.getAllCnt';
... ... @@ -21,7 +23,6 @@ const SELLER_ASK_PRE_COMPUTE = 'ufo.seller.bid.compute';
//变现
const SELLER_ASK_PUBLISH = 'ufo.seller.bid.publish';
module.exports = {
ORDER_COUNT,
BUYER_ASK_CONFIG,
... ...
... ... @@ -13,7 +13,7 @@ module.exports = {
auth: true,
path: 'shopping/bid',
api: API.BUYER_ASK_CONFIG,
params: {}
params: {},
},
'/api/order/buyeraskcompute': {
ufo: true,
... ... @@ -21,9 +21,9 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_COMPUTE,
params: {
price: {type: Number, required: true},
storage_id: {type: Number, required: true},
}
price: { type: Number, required: true },
storage_id: { type: Number, required: true },
},
},
'/api/order/buyeraskprepublish': {
ufo: true,
... ... @@ -31,10 +31,10 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_TIPS,
params: {
price: {type: Number, required: true},
storage_id: {type: Number, required: true},
address_id: {type: String, required: true},
}
price: { type: Number, required: true },
storage_id: { type: Number, required: true },
address_id: { type: String, required: true },
},
},
'/api/order/buyeraskpublish': {
... ... @@ -43,11 +43,11 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_PUBLISH,
params: {
price: {type: Number, required: true},
storage_id: {type: Number, required: true},
address_id: {type: String, required: true},
time_limit_id: {type: Number, required: true}, // 有效期
}
price: { type: Number, required: true },
storage_id: { type: Number, required: true },
address_id: { type: String, required: true },
time_limit_id: { type: Number, required: true }, // 有效期
},
},
'/api/order/buyerask/computechangeprice': {
... ... @@ -56,9 +56,9 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_COMPUTE_CHANGE_PRICE,
params: {
price: {type: Number, required: true},
orderCode: {type: String, required: true},
}
price: { type: Number, required: true },
orderCode: { type: String, required: true },
},
},
'/api/order/buyerask/prechangeprice': {
ufo: true,
... ... @@ -66,9 +66,9 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_PRE_CHANGE_PRICE,
params: {
price: {type: Number, required: true},
orderCode: {type: String, required: true},
}
price: { type: Number, required: true },
orderCode: { type: String, required: true },
},
},
'/api/order/buyerask/changeprice': {
... ... @@ -77,9 +77,8 @@ module.exports = {
path: 'shopping/bid',
api: API.BUYER_ASK_CHANGE_PRICE,
params: {
price: {type: Number, required: true},
orderCode: {type: String, required: true},
}
}
price: { type: Number, required: true },
orderCode: { type: String, required: true },
},
},
};
... ...
... ... @@ -226,7 +226,6 @@ module.exports = {
auth: true,
ufo: true,
api: 'ufo.sellerOrder.computePublishPrd',
},
'/api/order/ordercount': {
... ... @@ -235,7 +234,7 @@ module.exports = {
api: API.ORDER_COUNT,
params: {
tabType: { type: String, require: true }, // 订单来源
}
},
},
// 判断用户状态
... ... @@ -310,7 +309,7 @@ module.exports = {
auth: true,
path: 'payment',
api: 'ufo.order.pay',
params: {}
params: {},
},
// 定单商品详情
... ... @@ -318,14 +317,14 @@ module.exports = {
ufo: true,
auth: true,
api: 'ufo.order.goodsDetail',
params: {}
params: {},
},
'/api/order/status': {
ufo: true,
auth: true,
api: 'ufo.order.payDetail',
params: {}
params: {},
},
// 订单物流信息
... ... @@ -372,22 +371,24 @@ module.exports = {
depotNum: { type: Number, require: true }, // 鉴定中心id
},
},
//瑕疵接受
// 瑕疵接受
'/api/order/flawaccept': {
ufo: true,
auth: true,
api: 'ufo.buyer.miniFaultAccept',
params: {
orderCode: { type: String, require: true }, // 订单编号
}
},
},
//瑕疵拒绝
// 瑕疵拒绝
'/api/order/flawreject': {
ufo: true,
auth: true,
api: 'ufo.buyer.miniFaultReject',
params: {
orderCode: { type: String, require: true }, // 订单编号
}
}
},
},
};
... ...
{
"name": "xianyu-ufo-app-web",
"version": "0.0.2-beta-19",
"version": "0.0.2-beta-20",
"private": true,
"description": "Xianyu Project With Express",
"repository": {
... ... @@ -85,7 +85,8 @@
"yoho-node-lib": "=0.6.41",
"yoho-qs": "^1.0.1",
"yoho-store": "^1.3.20",
"yoho-zookeeper": "^1.0.11"
"yoho-zookeeper": "^1.0.11",
"video.js": "^7.5.5"
},
"devDependencies": {
"@babel/core": "^7.2.0",
... ...