Authored by baoss

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

@@ -11,6 +11,7 @@ const serviceApi = global.yoho.ServiceAPI; @@ -11,6 +11,7 @@ const serviceApi = global.yoho.ServiceAPI;
11 const checkApiMap = url => { 11 const checkApiMap = url => {
12 return apiMaps[url] ? apiMaps[url] : void 0; 12 return apiMaps[url] ? apiMaps[url] : void 0;
13 }; 13 };
  14 +
14 // eslint-disable-next-line space-before-function-paren 15 // eslint-disable-next-line space-before-function-paren
15 const request = async ({ url, method, reqParams = {}, context }) => { 16 const request = async ({ url, method, reqParams = {}, context }) => {
16 const apiInfo = checkApiMap(url); 17 const apiInfo = checkApiMap(url);
@@ -18,6 +18,7 @@ const $app = document.getElementById('app'); @@ -18,6 +18,7 @@ const $app = document.getElementById('app');
18 const isDegrade = Boolean(!($app && $app.attributes['data-server-rendered'])); 18 const isDegrade = Boolean(!($app && $app.attributes['data-server-rendered']));
19 const context = get(window, '__INITIAL_STATE__.yoho.context'); 19 const context = get(window, '__INITIAL_STATE__.yoho.context');
20 const {app, router, store} = createApp(context); 20 const {app, router, store} = createApp(context);
  21 +const api = createApi();
21 22
22 if (window.__INITIAL_STATE__) { 23 if (window.__INITIAL_STATE__) {
23 store.replaceState(window.__INITIAL_STATE__); 24 store.replaceState(window.__INITIAL_STATE__);
@@ -31,9 +32,43 @@ Vue.use(Toast); @@ -31,9 +32,43 @@ Vue.use(Toast);
31 Vue.use(DatePicker); 32 Vue.use(DatePicker);
32 Vue.use(Dialog); 33 Vue.use(Dialog);
33 Vue.use(ImagePreview); 34 Vue.use(ImagePreview);
34 -Vue.prop('api', createApi()); 35 +Vue.prop('api', api);
35 Vue.use(Lazy, {error: ''}); 36 Vue.use(Lazy, {error: ''});
36 37
  38 +yoho.auth = async(loginUrl) => {
  39 + let user = await sdk.getUser();
  40 +
  41 + if (user && user.uid) {
  42 + return user;
  43 + } else {
  44 + location.href = loginUrl || `${location.origin}/xianyu/passport/login/taobao`;
  45 + return;
  46 + }
  47 +}
  48 +
  49 +yoho.authRealName = async() => {
  50 + if (await yoho.auth()) {
  51 + let res = await api.get('/api/ufo/sellerOrder/entryStatus');
  52 +
  53 + if (res.code === 200) {
  54 + store.commit('SET_USER_SELLER_INFO', res.data);
  55 +
  56 + if (!get(res.data, 'isZhiMaCertWithPhoto')) {
  57 + router.push({
  58 + name: 'passport.auth'
  59 + });
  60 + }
  61 + }
  62 +
  63 + return res;
  64 + }
  65 +
  66 + return {
  67 + code: 403,
  68 + message: '未登录'
  69 + };
  70 +}
  71 +
37 const fetchAsycData = (matched, r) => { 72 const fetchAsycData = (matched, r) => {
38 const asyncDataPromises = matched 73 const asyncDataPromises = matched
39 .map(({asyncData}) => asyncData && asyncData({store, router: r})). 74 .map(({asyncData}) => asyncData && asyncData({store, router: r})).
@@ -3,8 +3,8 @@ import Common from './common'; @@ -3,8 +3,8 @@ import Common from './common';
3 import List from './list'; 3 import List from './list';
4 import Product from './product'; 4 import Product from './product';
5 import Home from './home'; 5 import Home from './home';
  6 +import Passport from './passport';
6 import Address from './address'; 7 import Address from './address';
7 import Notice from './notice'; 8 import Notice from './notice';
8 9
9 -export default [...Order, ...Common, ...List, ...Product, ...Home, ...Address, ...Notice];  
10 - 10 +export default [...Order, ...Common, ...List, ...Product, ...Home, ...Passport, ...Address, ...Notice];
1 <template> 1 <template>
2 <LayoutApp :show-back="true"> 2 <LayoutApp :show-back="true">
3 - <div class="body" ref="body">  
4 - <List>  
5 - </List>  
6 - </div> 3 + <Scroll
  4 + ref="scroll"
  5 + :scroll-events="['scroll-end','scroll']"
  6 + @scroll-end="fetchList"
  7 + >
  8 + <NoticeItem v-for="(item, index) in noticeList" :key="index" :data="item"></NoticeItem>
  9 + </Scroll>
7 </LayoutApp> 10 </LayoutApp>
8 </template> 11 </template>
9 12
10 <script> 13 <script>
11 -import List from './components/list'; 14 +import { createNamespacedHelpers } from 'vuex';
12 15
  16 +const { mapState, mapActions} = createNamespacedHelpers('notice');
  17 +import NoticeItem from './components/noticeItem';
  18 +
  19 +import {
  20 + Style,
  21 + Scroll,
  22 + RecycleList
  23 +} from 'cube-ui';
13 export default { 24 export default {
14 components: { 25 components: {
15 - List 26 + NoticeItem,
  27 + Style,
  28 + Scroll,
  29 + RecycleList
  30 + },
  31 + data(){
  32 + return {
  33 + data: {},
  34 + scrolling: false,
  35 + scrollOption: {
  36 + pullUpLoad:true,
  37 + },
  38 + };
  39 + },
  40 + created(){
  41 + this.fetchList();
  42 + // this.fetchNoticeList();
  43 + },
  44 +
  45 + computed: {
  46 + ...mapState(['noticeList','fetchNoticePage','isMore']),
  47 + },
  48 + methods:{
  49 + ...mapActions(['fetchNoticeList']),
  50 + onScroll(){
  51 + console.log('onScroll')
  52 + this.scrolling = true;
  53 + this._scTimer && clearTimeout(this._scTimer);
  54 + this._scTimer = setTimeout(() => {
  55 + this.scrolling = false;
  56 + }, 400);
  57 + },
  58 + scroll({ y }) {
  59 + const height = this.$refs.banner.$el.offsetHeight + this.$refs.header.offsetHeight;
  60 +
  61 + if (-y >= height) {
  62 + this.fixed = true;
  63 + } else {
  64 + this.fixed = false;
  65 + }
  66 + },
  67 + fetchList(){
  68 + console.log('fetchList:'+this.isMore)
  69 + if (!this.isMore) {
  70 + return;
16 } 71 }
  72 + console.log('fetchList:'+this.noMore)
  73 + this.fetchNoticeList().then(res => {
  74 + this.$nextTick(() => {
  75 + this.$refs.scroll.forceUpdate(true);
  76 + });
  77 + });
  78 + },
  79 + async onPullingUp(){
  80 + console.log('onPullingUp:'+this.isMore)
  81 + await this.fetchList();
  82 + },
  83 +
  84 + },
  85 +
17 }; 86 };
18 87
19 </script> 88 </script>
20 89
21 -<style>  
22 - .body {  
23 - height: 100%;  
24 - overflow-y: auto;  
25 - } 90 +<style scoped>
  91 +
  92 +.scroll-content {
  93 + height: 500px;
  94 +}
26 </style> 95 </style>
@@ -8,12 +8,23 @@ export default [ @@ -8,12 +8,23 @@ export default [
8 component: () => import(/* webpackChunkName: "order" */ './detail'), 8 component: () => import(/* webpackChunkName: "order" */ './detail'),
9 }, 9 },
10 { 10 {
11 - name: 'OrderConfirm',  
12 - path: '/xianyu/order/confirm/:orderCode.html',  
13 - component: () => import(/* webpackChunkName: "order" */ './confirm'), 11 + name: 'OrderSellConfirm',
  12 + path: '/xianyu/order/sellerconfirm/:orderCode.html',
  13 + component: () => import(/* webpackChunkName: "order" */ './seller-confirm'),
14 props: true 14 props: true
15 }, 15 },
16 { 16 {
  17 + name: 'OrderBuyConfirm',
  18 + path: '/xianyu/order/buyerconfirm/:orderCode.html',
  19 + component: () => import(/* webpackChunkName: "order" */ './buyer-confirm'),
  20 + props: true
  21 + },
  22 + {
  23 + name: 'PayOk',
  24 + path: '/xianyu/order/ok.html',
  25 + component: () => import(/* webpackChunkName: "order" */ './pay-ok'),
  26 + },
  27 + {
17 name: 'buyerAskOrder', //买家求购确认 28 name: 'buyerAskOrder', //买家求购确认
18 path: '/xianyu/order/buyeraskorder.html', 29 path: '/xianyu/order/buyeraskorder.html',
19 component: () => import('./buyer-ask-order') 30 component: () => import('./buyer-ask-order')
@@ -9,20 +9,21 @@ @@ -9,20 +9,21 @@
9 /> 9 />
10 </div> 10 </div>
11 <div class="item-info"> 11 <div class="item-info">
  12 + <div>
12 <div class="price-status"> 13 <div class="price-status">
13 - <slot name="item-price">  
14 <span class="price">¥{{ goodsInfo.goodPrice }}</span> 14 <span class="price">¥{{ goodsInfo.goodPrice }}</span>
15 - </slot>  
16 - <slot name="orderStatus" :orderStatus="order.statuStr"></slot> 15 + <span class="status">
  16 + <slot name="orderStatus" :status="order.statuStr"></slot>
  17 + </span>
17 </div> 18 </div>
18 <p class="item-name"> 19 <p class="item-name">
19 {{ goodsInfo.productName }} 20 {{ goodsInfo.productName }}
20 </p> 21 </p>
21 - <slot name="item-spec"> 22 + </div>
22 <p class="item-spec"> 23 <p class="item-spec">
23 - {{ spec }} 24 + <span>{{ goodsInfo.colorName }},</span>
  25 + <span>{{ goodsInfo.sizeName }}码</span>
24 </p> 26 </p>
25 - </slot>  
26 </div> 27 </div>
27 </div> 28 </div>
28 </template> 29 </template>
@@ -50,7 +51,6 @@ export default { @@ -50,7 +51,6 @@ export default {
50 <style lang="scss" scoped> 51 <style lang="scss" scoped>
51 .order-item-wrapper { 52 .order-item-wrapper {
52 display: flex; 53 display: flex;
53 - margin: 40px 0;  
54 54
55 .item-img { 55 .item-img {
56 min-width: 180px; 56 min-width: 180px;
@@ -77,10 +77,40 @@ export default { @@ -77,10 +77,40 @@ export default {
77 flex: 1; 77 flex: 1;
78 flex-direction: column; 78 flex-direction: column;
79 margin-left: 20px; 79 margin-left: 20px;
  80 + font-size: 24px;
  81 + justify-content: space-between;
80 82
81 .price-status { 83 .price-status {
82 display: flex; 84 display: flex;
83 justify-content: space-between; 85 justify-content: space-between;
  86 + margin-bottom: 12px;
  87 +
  88 + .price {
  89 + font-size: 28px;
  90 + color: #d0021b;
  91 + letter-spacing: 0;
  92 + font-weight: bold;
  93 + }
  94 +
  95 + .status {
  96 + color: #000;
  97 + letter-spacing: 0;
  98 + font-weight: bold;
  99 + }
  100 + }
  101 +
  102 + .item-name {
  103 + color: #999;
  104 + letter-spacing: 0;
  105 + line-height: 36px;
  106 + }
  107 +
  108 + .item-spec {
  109 + font-weight: bold;
  110 +
  111 + & > :last-child {
  112 + padding-left: 10px;
  113 + }
84 } 114 }
85 } 115 }
86 } 116 }
1 <template> 1 <template>
2 - <scroll class="" direction="horizontal"></scroll> 2 + <div class="order-status-nav-scroll-wrap">
  3 + <scroll ref="statusScroll" :data="statusList" direction="horizontal">
  4 + <ul class="list-wrapper">
  5 + <li
  6 + :class="i === 1 ? 'list-item active' : 'list-item'"
  7 + v-for="(statusInfo, i) in statusList"
  8 + :key="i"
  9 + >
  10 + {{ statusInfo.text }}
  11 + </li>
  12 + </ul>
  13 + </scroll>
  14 + </div>
3 </template> 15 </template>
4 16
5 <script> 17 <script>
6 import { Scroll } from "cube-ui"; 18 import { Scroll } from "cube-ui";
  19 +
  20 +import {
  21 + buyerOrderStatusList,
  22 + sellerOrderStatusList,
  23 + ownType
  24 +} from "../../../../../constants/order-constants";
  25 +
7 export default { 26 export default {
8 components: { 27 components: {
9 Scroll 28 Scroll
  29 + },
  30 + computed: {
  31 + statusList: function() {
  32 + const { owner } = this.$route.params;
  33 + return owner === ownType.BUY
  34 + ? buyerOrderStatusList
  35 + : sellerOrderStatusList;
  36 + }
10 } 37 }
11 }; 38 };
12 </script> 39 </script>
13 40
  41 +<style>
  42 +.order-status-nav-scroll-wrap .cube-scroll-content {
  43 + display: inline-block;
  44 + min-width: 100%;
  45 +}
  46 +</style>
  47 +
14 <style lang="scss" scoped> 48 <style lang="scss" scoped>
  49 +.order-status-nav-scroll-wrap {
  50 + transform: rotate(0deg); // fix 子元素超出边框圆角部分不隐藏的问题
  51 + position: relative;
  52 +
  53 + .list-wrapper {
  54 + white-space: nowrap;
  55 + font-size: 28px;
  56 + color: #999;
  57 + background: #fff;
  58 + box-shadow: inset 0 -1px 0 0 #eee;
  59 + display: flex;
  60 + justify-content: space-between;
  61 + align-items: center;
  62 +
  63 + .list-item {
  64 + display: inline-block;
  65 + padding: 22px 0;
  66 + margin-left: 38px;
  67 +
  68 + &:last-child {
  69 + margin-right: 38px;
  70 + }
  71 + }
  72 +
  73 + .list-item.active {
  74 + font-size: 40px;
  75 + color: #000;
  76 + font-weight: bold;
  77 + border-bottom: 6px solid #000;
  78 + }
  79 + }
  80 +}
15 </style> 81 </style>
@@ -4,7 +4,7 @@ const routers = [ @@ -4,7 +4,7 @@ const routers = [
4 // status: 订单状态 4 // status: 订单状态
5 { 5 {
6 name: 'BuyerOrderList', 6 name: 'BuyerOrderList',
7 - path: '/xianyu/:owner/order/list/:status', 7 + path: '/xianyu/:owner/order/list/:status?',
8 component: () => import('./order-list'), 8 component: () => import('./order-list'),
9 }, 9 },
10 ]; 10 ];
1 <template> 1 <template>
2 - <scroll :data="orderList" class="order-list-wrapper">  
3 - <order-list-item  
4 - v-for="order in orderList"  
5 - :key="order.orderCode"  
6 - :order="order"  
7 - >  
8 - <template #orderStatus="{orderStatus}">{{ orderStatus }}</template> 2 + <div>
  3 + <status-nav />
  4 + <scroll :data="orderList" class="order-list-scroll-wrap">
  5 + <ul class="list-wrapper">
  6 + <li v-for="order in orderList" :key="order.orderCode">
  7 + <order-list-item :order="order">
  8 + <template #orderStatus="{status}">{{ status }}</template>
9 </order-list-item> 9 </order-list-item>
  10 + <div class="actions">
  11 + <Button v-for="action in order.buttons" :key="action.code">
  12 + {{ action.text }}
  13 + </Button>
  14 + </div>
  15 + </li>
  16 + </ul>
10 </scroll> 17 </scroll>
  18 + </div>
11 </template> 19 </template>
12 20
13 <script> 21 <script>
14 import { Button, Scroll } from "cube-ui"; 22 import { Button, Scroll } from "cube-ui";
15 import { createNamespacedHelpers } from "vuex"; 23 import { createNamespacedHelpers } from "vuex";
16 import OrderListItem from "./components/order-list-item"; 24 import OrderListItem from "./components/order-list-item";
  25 +import StatusNav from "./components/status-nav";
17 26
18 const { mapActions, mapState } = createNamespacedHelpers("order/orderList"); 27 const { mapActions, mapState } = createNamespacedHelpers("order/orderList");
19 28
@@ -21,7 +30,8 @@ export default { @@ -21,7 +30,8 @@ export default {
21 components: { 30 components: {
22 Button, 31 Button,
23 Scroll, 32 Scroll,
24 - OrderListItem 33 + OrderListItem,
  34 + StatusNav
25 }, 35 },
26 computed: { 36 computed: {
27 ...mapState(["orderList"]) 37 ...mapState(["orderList"])
@@ -45,7 +55,42 @@ export default { @@ -45,7 +55,42 @@ export default {
45 }; 55 };
46 </script> 56 </script>
47 <style lang="scss" scoped> 57 <style lang="scss" scoped>
48 -.order-list-wrapper {  
49 - margin: 40px 20px; 58 +.order-list-scroll-wrap {
  59 + .list-wrapper {
  60 + li {
  61 + padding: 40px 40px;
  62 + border-bottom: 1px solid #eee;
  63 + }
  64 +
  65 + & :last-child {
  66 + border-bottom: 0;
  67 + }
  68 + }
  69 +
  70 + .actions {
  71 + display: flex;
  72 + justify-content: flex-end;
  73 + margin-top: 40px;
  74 +
  75 + button {
  76 + font-size: 24px;
  77 + padding: 24px 64px 22px 64px;
  78 + color: #999;
  79 + letter-spacing: 0;
  80 + border-radius: 0;
  81 + background: #fff;
  82 + border: 1px solid #ccc;
  83 + line-height: 1.3;
  84 + width: 224px;
  85 + margin-right: 20px;
  86 + }
  87 +
  88 + & :last-child {
  89 + background: #002b47;
  90 + color: #fff;
  91 + border: 1px solid #002b47;
  92 + margin-right: 0;
  93 + }
  94 + }
50 } 95 }
51 </style> 96 </style>
  1 +<template>
  2 + <LayoutApp :show-back="true">
  3 + <div class="body">
  4 + <div class="header">
  5 + <i class="iconfont iconOk icon-class"></i>
  6 + </div>
  7 + <div class="title">支付成功</div>
  8 +
  9 + <OrderButton :txt="txt" class="btn-class" @on-click="onClick"></OrderButton>
  10 +
  11 + <div class="info">
  12 + <div class="item" @click="goPublish">继续发布</div>
  13 + <div class="item" @click="goHome">随便逛逛</div>
  14 + </div>
  15 + </div>
  16 + </LayoutApp>
  17 +</template>
  18 +
  19 +<script>
  20 +
  21 +import OrderButton from './components/confirm/button';
  22 +
  23 +export default {
  24 + name: 'PayOk',
  25 + data() {
  26 + return {
  27 + txt: '查看商品'
  28 + };
  29 + },
  30 + components: {
  31 + OrderButton
  32 + },
  33 + methods: {
  34 + onClick() {
  35 +
  36 + },
  37 + goPublish() {
  38 +
  39 + },
  40 + goHome() {
  41 +
  42 + }
  43 + }
  44 +};
  45 +</script>
  46 +
  47 +<style lang="scss" scoped>
  48 +.body {
  49 + height: 100%;
  50 + margin: 0 74px;
  51 + padding-bottom: 140px;
  52 + overflow-y: auto;
  53 +}
  54 +
  55 +.header {
  56 + margin-top: 170px;
  57 + text-align: center;
  58 +}
  59 +
  60 +.icon-class {
  61 + font-size: 120px;
  62 +}
  63 +
  64 +.btn-class {
  65 + height: 100px;
  66 + font-size: 32px;
  67 + line-height: 100px;
  68 +}
  69 +
  70 +.title {
  71 + font-size: 40px;
  72 + font-weight: bold;
  73 + text-align: center;
  74 + margin-bottom: 60px;
  75 +}
  76 +
  77 +.info {
  78 + font-size: 28px;
  79 + display: flex;
  80 + margin-top: 30px;
  81 +
  82 + .item {
  83 + width: 50%;
  84 + text-align: center;
  85 + }
  86 +
  87 + .item + .item {
  88 + border-left: 1px solid black;
  89 + }
  90 +}
  91 +
  92 +</style>
  1 +<template>
  2 + <LayoutApp :show-back="true">
  3 + <div class="body">
  4 + <TitleComp txt="出售"></TitleComp>
  5 + <ProductInfo :data="orderDetail.goodsInfo" class="product-info"></ProductInfo>
  6 + <InputPrice class="input-price"></InputPrice>
  7 + <OrderMargin class="order-item order-margin"></OrderMargin>
  8 + <OrderFee class="order-item"></OrderFee>
  9 + <AddressInfo :data="orderDetail.userAddress" class="order-item"></AddressInfo>
  10 + <OrderAgree v-model="agree" class="order-item"></OrderAgree>
  11 + </div>
  12 + <ConfirmButton :txt="txt" class="footer"></ConfirmButton>
  13 + </LayoutApp>
  14 +</template>
  15 +
  16 +<script>
  17 +
  18 +import ProductInfo from './components/confirm/product';
  19 +import InputPrice from './components/confirm/input-price';
  20 +import AddressInfo from './components/confirm/address';
  21 +import ConfirmButton from './components/confirm/button';
  22 +import TitleComp from './components/confirm/title';
  23 +import OrderMargin from './components/confirm/order-margin';
  24 +import OrderFee from './components/confirm/order-fee';
  25 +import OrderAgree from './components/confirm/agree';
  26 +
  27 +import { createNamespacedHelpers } from 'vuex';
  28 +const { mapState, mapActions, mapMutations } = createNamespacedHelpers('order/orderConfirm');
  29 +
  30 +export default {
  31 + name: 'OrderConfirm',
  32 + props: {
  33 + orderCode: {
  34 + type: String,
  35 + default: ''
  36 + }
  37 + },
  38 + components: {
  39 + ProductInfo,
  40 + AddressInfo,
  41 + ConfirmButton,
  42 + InputPrice,
  43 + TitleComp,
  44 + OrderMargin,
  45 + OrderFee,
  46 + OrderAgree
  47 + },
  48 + data() {
  49 + return {
  50 + txt: '提交',
  51 + agree: false
  52 + };
  53 + },
  54 + mounted() {
  55 + this.fetchOrderDetail({orderCode: this.orderCode})
  56 + },
  57 + computed: {
  58 + ...mapState(['orderDetail'])
  59 + },
  60 + methods: {
  61 + ...mapActions(['fetchOrderDetail'])
  62 + }
  63 +};
  64 +</script>
  65 +
  66 +<style lang="scss" scoped>
  67 +.footer {
  68 + position: absolute;
  69 + bottom: 0;
  70 + width: 100%;
  71 + z-index: 100;
  72 +}
  73 +
  74 +.body {
  75 + height: 100%;
  76 + margin: 0 40px;
  77 + padding-bottom: 140px;
  78 + overflow-y: auto;
  79 +}
  80 +
  81 +.order-item {
  82 + padding-top: 40px;
  83 + padding-bottom: 40px;
  84 +}
  85 +
  86 +.order-item + .order-item {
  87 + border-top: 1px solid #eee;
  88 +}
  89 +
  90 +</style>
  1 +<template>
  2 + <LayoutApp class="yohoufo-auth-page">
  3 + <div class="auth-content">
  4 + <div class="auth-title">实名认证</div>
  5 + <p class="auth-sub-title">信息仅用于身份验证,不对外展示,有货UFO平台将严保您的信息安全,请认证填写如下信息,确保上传的图片文字清晰可见。</p>
  6 + <div class="auth-form">
  7 + <p class="form-title">姓名</p>
  8 + <div class="form-input-block">
  9 + <CubeInput class="auth-input" v-model="name" :disabled="!!certName" placeholder="请输入真实姓名"></CubeInput>
  10 + </div>
  11 + <p class="form-title">身份证号</p>
  12 + <div class="form-input-block">
  13 + <CubeInput class="auth-input" v-model="idCode" :disabled="!!certIdCode" placeholder="请输入身份证号"></CubeInput>
  14 + </div>
  15 + <p class="form-title">上传身份证正面照片 <a :href="exampleLink" class="upload-intro">示例照片</a></p>
  16 + <div class="form-input-block">
  17 + <div class="upload-btn" @click="uploadFrontCard">
  18 + <div v-if="idCardFrontUrl" class="delete-img" @click.stop="clearInfo(['idCardFront', 'idCardFrontUrl'])">ㄨ</div>
  19 + <div v-if="idCardFrontUrl" class="up-img-block">
  20 + <img :src="idCardFrontUrl">
  21 + </div>
  22 + </div>
  23 + <div class="example-view">
  24 + <img src="//img12.static.yhbimg.com/goodsimg/2019/09/25/16/022553bde9fc6bafa0df244de694c551f2.png?imageView/1/w/160/h/100" alt="身份证正面(示例)">
  25 + <p>(示例)</p>
  26 + </div>
  27 + </div>
  28 + <p class="form-title">上传身份证反面照片</p>
  29 + <div class="form-input-block">
  30 + <div class="upload-btn" @click="uploadBackCard">
  31 + <div v-if="idCardBackUrl" class="delete-img" @click.stop="clearInfo(['idCardBack', 'idCardBackUrl'])">ㄨ</div>
  32 + <div v-if="idCardBackUrl" class="up-img-block">
  33 + <img :src="idCardBackUrl">
  34 + </div>
  35 + </div>
  36 + <div class="example-view">
  37 + <img src="//img11.static.yhbimg.com/goodsimg/2019/09/25/16/011df7d2637953bd6ce2c59500011d7fd7.png?imageView/1/w/160/h/100" alt="身份证反面(示例)">
  38 + <p>(示例)</p>
  39 + </div>
  40 + </div>
  41 + <div class="hide-upload-wrap">
  42 + <CubeUpload
  43 + ref="upload"
  44 + action="/xianyu/upload/idcard"
  45 + :simultaneous-uploads="1"
  46 + @files-added="addedHandler"
  47 + @file-success="successHandler"
  48 + @file-error="errorHandler"/>
  49 + </div>
  50 + </div>
  51 + </div>
  52 + <div class="auth-footer">
  53 + <CubeButton class="submit-btn" :disabled="canSubmit" @click="submitCert">确认提交</CubeButton>
  54 + </div>
  55 + </LayoutApp>
  56 +</template>
  57 +
  58 +<script>
  59 +import { get } from 'lodash';
  60 +import { Input, Button, Upload } from 'cube-ui';
  61 +import { mapActions, mapState } from 'vuex';
  62 +
  63 +export default {
  64 + name: 'auth',
  65 + data() {
  66 + return {
  67 + name: '',
  68 + idCode: '',
  69 + idCardFront: '',
  70 + idCardBack: '',
  71 + idCardFrontUrl: '',
  72 + idCardBackUrl: '',
  73 + exampleLink: '//activity.yoho.cn/feature/4899.html?share_id=7593&title=UFO-身份证示例'
  74 + }
  75 + },
  76 + computed: {
  77 + ...mapState(['yoho']),
  78 + certName() {
  79 + let name = get(this.yoho, 'user.sellerInfo.certName');
  80 +
  81 + name && (this.name = name);
  82 + return name;
  83 + },
  84 + certIdCode() {
  85 + let code = get(this.yoho, 'user.sellerInfo.certNo');
  86 +
  87 + code && (this.idCode = code);
  88 + return code;
  89 + },
  90 + canSubmit() {
  91 + return !(this.name && this.idCode && this.idCardFront && this.idCardBack);
  92 + }
  93 + },
  94 + methods: {
  95 + ...mapActions(['userRealCertification']),
  96 + clearInfo(arr) {
  97 + if (arr && arr.length) {
  98 + arr.forEach(val => {
  99 + this[val] && (this[val] = '');
  100 + });
  101 + }
  102 + },
  103 + chooseUploadFile() {
  104 + this.$refs.upload && this.$refs.upload.$el.querySelector('.cube-upload-input').click();
  105 + },
  106 + uploadFrontCard() {
  107 + if (!this.uploading && !this.idCardFront) {
  108 + this.uploadCallback = (path, img) => {
  109 + this.idCardFront = path;
  110 + this.idCardFrontUrl = img;
  111 + };
  112 + this.chooseUploadFile();
  113 + }
  114 + },
  115 + uploadBackCard() {
  116 + if (!this.uploading && !this.idCardBack) {
  117 + this.uploadCallback = (path, img) => {
  118 + this.idCardBack = path;
  119 + this.idCardBackUrl = img;
  120 + };
  121 + this.chooseUploadFile();
  122 + }
  123 + },
  124 + addedHandler() {
  125 + this.uploading = true;
  126 + },
  127 + successHandler(file) {
  128 + if (get(file, 'response.code') === 200 && this.uploadCallback) {
  129 + this.uploadCallback(get(file, 'response.data.imagesList[0]'), file.url);
  130 + }
  131 +
  132 + this.uploading = false;
  133 + setTimeout(() => {
  134 + this.$refs.upload.removeFile(file);
  135 + }, 1000);
  136 + },
  137 + errorHandler() {
  138 + this.uploading = false;
  139 + },
  140 + submitCert() {
  141 + this.userRealCertification({
  142 + certName: this.name,
  143 + certNo: this.idCode,
  144 + frontImageUrl: this.idCardFront,
  145 + backImageUrl: this.idCardBack
  146 + }).then(res => {
  147 + if (res.code === 200) {
  148 + if (this.$route.query.refer) {
  149 + this.$router.push({
  150 + name: this.$route.query.refer
  151 + });
  152 + } else {
  153 + this.$router.go(-1);
  154 + }
  155 + } else {
  156 + this.$createToast && this.$createToast({
  157 + txt: res.message || '认证失败',
  158 + type: 'txt',
  159 + time: 1000
  160 + }).show();
  161 + }
  162 + });
  163 + }
  164 + },
  165 + components: {
  166 + CubeInput: Input,
  167 + CubeButton: Button,
  168 + CubeUpload: Upload
  169 + }
  170 +};
  171 +</script>
  172 +
  173 +
  174 +<style lang="scss" scoped>
  175 + .auth-content {
  176 + height: calc(100% - 200px);
  177 + padding: 0 40px;
  178 + overflow-y: scroll;
  179 +
  180 + .auth-title {
  181 + font-size: 68px;
  182 + line-height: 96px;
  183 + font-weight: 900;
  184 + }
  185 +
  186 + .auth-sub-title {
  187 + font-size: 24px;
  188 + color: #999;
  189 + line-height: 1.5;
  190 + margin-top: 20px;
  191 + }
  192 +
  193 + .auth-form {
  194 + margin-top: 40px;
  195 + }
  196 +
  197 + .form-title {
  198 + font-size: 36px;
  199 + padding-top: 40px;
  200 + line-height: 1.6;
  201 + }
  202 +
  203 + .form-input-block {
  204 + padding-bottom: 16px;
  205 + border-bottom: 1px solid #f6f6f6;
  206 + position: relative;
  207 + }
  208 +
  209 + .auth-input {
  210 + &:after {
  211 + border: 0;
  212 + }
  213 +
  214 + /deep/ .cube-input-field {
  215 + font-size: 14px;
  216 + height: 40px;
  217 + border: none;
  218 + padding: 0;
  219 + }
  220 + }
  221 +
  222 + .upload-intro {
  223 + font-size: 28px;
  224 + line-height: 58px;
  225 + color: #999;
  226 + float: right;
  227 + }
  228 +
  229 + .upload-btn {
  230 + width: 220px;
  231 + height: 140px;
  232 + background-color: #eee;
  233 + margin: 30px 0 14px;
  234 + position: relative;
  235 +
  236 + &:before {
  237 + content: "";
  238 + width: 40px;
  239 + height: 4px;
  240 + background-color: #999;
  241 + position: absolute;
  242 + left: 50%;
  243 + top: 50%;
  244 + margin-top: -2px;
  245 + margin-left: -20px;
  246 + }
  247 +
  248 + &:after {
  249 + content: "";
  250 + width: 4px;
  251 + height: 40px;
  252 + background-color: #999;
  253 + position: absolute;
  254 + left: 50%;
  255 + top: 50%;
  256 + margin-top: -20px;
  257 + margin-left: -2px;
  258 + }
  259 + }
  260 +
  261 + .delete-img {
  262 + width: 40px;
  263 + height: 40px;
  264 + line-height: 40px;
  265 + border-radius: 20px;
  266 + background-color: #676767;
  267 + color: #fff;
  268 + text-align: center;
  269 + position: absolute;
  270 + top: -20px;
  271 + right: -20px;
  272 + z-index: 2;
  273 + }
  274 +
  275 + .up-img-block {
  276 + position: absolute;
  277 + top: 0;
  278 + bottom: 0;
  279 + left: 0;
  280 + right: 0;
  281 + z-index: 1;
  282 + background-color: #fff;
  283 + display: flex;
  284 + justify-content: center;
  285 + align-items: center;
  286 +
  287 + > img {
  288 + display: block;
  289 + max-width: 100%;
  290 + max-height: 100%;
  291 + }
  292 + }
  293 +
  294 + .example-view {
  295 + width: 160px;
  296 + font-size: 20px;
  297 + color: #999;
  298 + text-align: center;
  299 + position: absolute;
  300 + right: 0;
  301 + top: 16px;
  302 +
  303 + > img {
  304 + width: 100%;
  305 + }
  306 +
  307 + > p {
  308 + font-weight: 300;
  309 + }
  310 + }
  311 +
  312 + .hide-upload-wrap {
  313 + height: 0;
  314 + overflow: hidden;
  315 + }
  316 + }
  317 +
  318 + .auth-footer {
  319 + padding: 40px;
  320 +
  321 + .submit-btn {
  322 + height: 120px;
  323 + background: #022c46;
  324 +
  325 + &.cube-btn_disabled {
  326 + background: #ccc;
  327 + }
  328 + }
  329 + }
  330 +</style>
  1 +<template>
  2 + <div>bind page</div>
  3 +</template>
  4 +
  5 +<script>
  6 +export default {
  7 + name: 'bind',
  8 + activated() {
  9 + },
  10 + beforeRouteUpdate(to, from, next) {
  11 + },
  12 + mounted() {
  13 + this.$yoho.authRealName();
  14 + },
  15 + methods: {
  16 + }
  17 +};
  18 +</script>
  1 +export default [{
  2 + name: 'passport.bind',
  3 + path: '/xianyu/passport/bind',
  4 + component: () => import(/* webpackChunkName: "passport.bind" */ './bind')
  5 +}, {
  6 + name: 'passport.auth',
  7 + path: '/xianyu/passport/real/auth',
  8 + component: () => import(/* webpackChunkName: "passport.auth" */ './auth')
  9 +}];
1 @font-face {font-family: "iconfont"; 1 @font-face {font-family: "iconfont";
2 - src: url('iconfont.eot?t=1569404435657'); /* IE9 */  
3 - src: url('iconfont.eot?t=1569404435657#iefix') format('embedded-opentype'), /* IE6-IE8 */  
4 - url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),  
5 - url('iconfont.woff?t=1569404435657') format('woff'),  
6 - url('iconfont.ttf?t=1569404435657') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */  
7 - url('iconfont.svg?t=1569404435657#iconfont') format('svg'); /* iOS 4.1- */ 2 + src: url('iconfont.eot?t=1569468612498'); /* IE9 */
  3 + src: url('iconfont.eot?t=1569468612498#iefix') format('embedded-opentype'), /* IE6-IE8 */
  4 + url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAdwAAsAAAAADywAAAchAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCFGgqOKItIATYCJANECyQABCAFhG0HgTkb3QwjEVacMrK/SLCNHR86OkSlyPGNjgoBL+u+kgn9I+majMKZ7ukkEz0wB9D/IbI/wOB0Krfsb9kQQHQAyBCyy1KRH8RD/u3d7xYlUORx4HmQYB5RohEkra2/5iFsAxmdry3qtO2QjkfHEzz7jk6gdw7Iic2T5UIBBAzd7+X/Vw2WtyzhAU7w7kXd3Y9eZeq3NfAGEtmAA920eUIT5JlIVzvp4d8F1zkIZwMBqCQrRMaGvhYosKRC0GKZPnU8FBUjdogfodDImD1zJfkIHEV5l7kL4MPw9uRGeSgABtdAnmvglPpJ6CIoxPuUl3iMonbw80sH0FsOoIBCANujJ5t5FTTJhQGruI6sVYB4hsavu5RCrFAqVAq1wgRhr/CNmCtOFK+K9yUJQSHE8Oq7Q5GLI+IlSlb/xAMYlAxLQU1Oj0MoqRhoaOmAtADWCKeHVQYQFCYKGBCUUUBBiIkCGQixUcCCUKpgGlIJPdQgtdBDDjIBeuhB9kIPDuQbRAEBMTcKlCBOjAIViFejwADi3SjQgHhPDy3IfXSCDgAYXft0QCYwAVOF9JyFdA6jMDlPswnWZTKoaUM6DVFqdTq/RaKGTYmIUGo0mQaZxpDlGwxGg9xaozHR8QEDgcZgcKjfb/X5VmjZElF56UDAolq7t2k3v8uxZzilE2r/0YGh8DbidEQ3uutEWV38LJLSY4Z6ximPtDgdNkP3VOU5Q+iusV6cTUPdboczktE4nbwrSsu4XE2eGKr1eOzu8QGhMSgO9X9j9X09QU1UI++rHD6LeuuD+p3Ho3aD3+crXLUJ6jUbY9YGg8Q+25E9JXr+rlN3Lrs+ctJkF3/K1pQ1OWrh+ZO2Obyt72TKGvuZiat3N+2173Hssm7YjqPcewjZeKVg78GYDY8dDxM3kZCR6q+7mLvrbCz+L2xwuwmxe2KMLhcI75w9Zap10uTxe4S5qb6GMq7V/03WTnFoMIAty8CW5R3B2nTP73voC1xO3hpcrrseSOfC2Xvor/nT2E2+FdvOxrKrz2Xpd15I4Nacz564j+rtjLJO9WzfIjvOySOnAsv/pE131ZfKbvbX628EM7gtgWGTnJP326H9NznDqSIjOa7d4vj6SNuyFVLHs2xzM3tWQYesWLRRP6nZTINBCmmzQOgjKneX0j25qk7xGZ0xbEo1ONEtjXa9iJfZPzbXUObtrup/Ww8trBRK9X7M9mbea6YCtBuelQtvZ4aaGR1bFrLuZXpHhf5UqK1u23L5XtNe+fLl87wm77zltoq7zdYG0qvP2NRU1krPughi8VfgwjSw//G/xw4bMnOcbNCgd5oMH21q+6U0btbYwRH2N3IGaLhRpyY3Zjbk9cbVDjH6dxwmFP5vv64vljRSN3ryVKkwEbF3Y931RW5Tfk1/MJfdUiVva+tcOce2tLBWOtdFEIs26q/ab6FPn1JIWwRCH7F90kOjtloWPt39G72icbBFod1TdbSk+/Bh3cmXDB/Rju7abYmj1dp9t848pe+mn9RQP5vC8ri3vLW5tbVbt9Pe06c2fImPZnwae5Ye/O67g0KiXQhYgY2jkK07zFhZMXZ8xSswR67NH9S3r4FBB3NVN3Y8t4T5o8HM7NlkEBnsYGL7foPJoCs1ZJ9MrNc2WBq05kQbx5jNqH6nh9PMZlPYZLVptF5ZhHtThSqsqtgUDg/BnYBm6ckTy2Iw7p2tmym9/c/qjYtd+mnnUNn4kNTdle5TpjhUkRBOqDgUslv9LaJs65z42KVKc2qWvhz1Dn6wXbmn09B+6j0K1/t83rs6aLcdO5bLjbzngw8Zxd3a185iHOVLWejvga0NAOkSvUA7AwA9mJwQTgrRrTQj7WWmjXbXXaSqrAsAYBmyBpDepCZqzwJ4upHyQR76HZ3uJDBV7m1mLdTPvD19rL7DXwr1S8+8Z0cGXRUFEi/DfJpAgYGxuTeVLHkSHlPCryBNxvxWMJQxQnVEQGXL6AKjenDwlNRDpXIBiXJNwsulUWNz72U0qgAMuSRAKWSqWKdCwFGrBDIKnYFKgR77q0VYAIqkEkC+NzNAGBwEDJ0LgDK4p2KdQoAT7ScgYwgKVPY0fjiiGtnV+SNhxzhCvwc1BC+1hc9jy0+csu2oLAT/X6SkSqAp63rNK3qkeWyTNlPLLEFScPCSnQ+tDRApaBy4nJnjuqokt205BLc4R3cEddiFH4HePrEyCDw5OTtvvP4nNMmsDg0Z8CfxL0QStXDQKNVjqF6xH2vAdWmfbExaTOkSmO4kcMALpSOrKgMQ+dU0NGCleYryaK2iieS4uFw+dac9xsk3qHwm45WiarphWrbjekL67947nH48jrfK8WgMW++PVNGN4+l/xsRHbMNDi5KPSE0znzWXaM6jzalwyrt6h303mJOxT0OY0tUw42D+RpRdtnxUIediJ5mtXb2Zo44obBcLAAA=') format('woff2'),
  5 + url('iconfont.woff?t=1569468612498') format('woff'),
  6 + url('iconfont.ttf?t=1569468612498') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  7 + url('iconfont.svg?t=1569468612498#iconfont') format('svg'); /* iOS 4.1- */
8 } 8 }
9 9
10 .iconfont { 10 .iconfont {
@@ -71,6 +71,10 @@ @@ -71,6 +71,10 @@
71 content: "\e7ce"; 71 content: "\e7ce";
72 } 72 }
73 73
  74 +.iconOk:before {
  75 + content: "\e662";
  76 +}
  77 +
74 .iconarrow:before { 78 .iconarrow:before {
75 content: "\e7c4"; 79 content: "\e7c4";
76 } 80 }
@@ -62,6 +62,9 @@ Created by iconfont @@ -62,6 +62,9 @@ Created by iconfont
62 <glyph glyph-name="check_full" unicode="&#59342;" d="M878.545455 872.727273h-733.09091A122.298182 122.298182 0 0 1 23.272727 750.545455v-733.09091A122.298182 122.298182 0 0 1 145.454545-104.727273h733.09091A122.298182 122.298182 0 0 1 1000.727273 17.454545v733.09091A122.298182 122.298182 0 0 1 878.545455 872.727273z m-112.872728-369.105455l-282.181818-280.436363a29.090909 29.090909 0 0 0-40.96 0L258.327273 406.109091a29.090909 29.090909 0 0 0 40.96 41.309091l163.607272-162.909091 261.701819 260.305454a29.090909 29.090909 0 1 0 40.96-41.30909z" horiz-adv-x="1024" /> 62 <glyph glyph-name="check_full" unicode="&#59342;" d="M878.545455 872.727273h-733.09091A122.298182 122.298182 0 0 1 23.272727 750.545455v-733.09091A122.298182 122.298182 0 0 1 145.454545-104.727273h733.09091A122.298182 122.298182 0 0 1 1000.727273 17.454545v733.09091A122.298182 122.298182 0 0 1 878.545455 872.727273z m-112.872728-369.105455l-282.181818-280.436363a29.090909 29.090909 0 0 0-40.96 0L258.327273 406.109091a29.090909 29.090909 0 0 0 40.96 41.309091l163.607272-162.909091 261.701819 260.305454a29.090909 29.090909 0 1 0 40.96-41.30909z" horiz-adv-x="1024" />
63 63
64 64
  65 + <glyph glyph-name="Ok" unicode="&#58978;" d="M512-128a512 512 0 1 0 512 512 512.576 512.576 0 0 0-512-512z m0 960a448 448 0 1 1 448-448A448.512 448.512 0 0 1 512 832z m-34.848-630.4a32 32 0 0 0-22.688-9.6H454.4a32 32 0 0 0-22.624 9.376l-166.4 166.4A32 32 0 0 0 310.624 412.8l143.424-143.36 259.2 264.864a32 32 0 1 0 45.76-44.8z" horiz-adv-x="1024" />
  66 +
  67 +
65 <glyph glyph-name="arrow" unicode="&#59332;" d="M1536 896L768-128 0 896z" horiz-adv-x="1536" /> 68 <glyph glyph-name="arrow" unicode="&#59332;" d="M1536 896L768-128 0 896z" horiz-adv-x="1536" />
66 69
67 70
@@ -3,21 +3,18 @@ import { get } from 'lodash'; @@ -3,21 +3,18 @@ import { get } from 'lodash';
3 3
4 export default { 4 export default {
5 async fetchNoticeList({ commit, state }) { 5 async fetchNoticeList({ commit, state }) {
6 - console.log("==="+state.fetchNoticeList)  
7 if (state.fetchNoticeList) { 6 if (state.fetchNoticeList) {
8 return {}; 7 return {};
9 } 8 }
10 9
11 let page = state.fetchNoticePage || 1; 10 let page = state.fetchNoticePage || 1;
12 - console.log("page:"+page)  
13 commit(Types.FETCH_NOTICE_LIST_REQUEST, { page }); 11 commit(Types.FETCH_NOTICE_LIST_REQUEST, { page });
14 12
15 const result = await this.$api.post('/api/ufo/home/noticelist', { 13 const result = await this.$api.post('/api/ufo/home/noticelist', {
16 page, 14 page,
17 - size: 10, 15 + size: 8,
18 lastedTime: state.fetchNoticeLastedTime || void 0 16 lastedTime: state.fetchNoticeLastedTime || void 0
19 }); 17 });
20 - console.log(result)  
21 if (result && result.code === 200) { 18 if (result && result.code === 200) {
22 commit(Types.FETCH_NOTICE_LIST_SUCCESS, { 19 commit(Types.FETCH_NOTICE_LIST_SUCCESS, {
23 data: result.data, 20 data: result.data,
@@ -8,6 +8,7 @@ export default function() { @@ -8,6 +8,7 @@ export default function() {
8 noticeList:[], 8 noticeList:[],
9 fetchNoticePage: 1, 9 fetchNoticePage: 1,
10 fetchNoticeLastedTime: 0, 10 fetchNoticeLastedTime: 0,
  11 + isMore: true,
11 }, 12 },
12 actions, 13 actions,
13 mutations, 14 mutations,
@@ -2,7 +2,7 @@ import * as Types from './types'; @@ -2,7 +2,7 @@ import * as Types from './types';
2 2
3 export default { 3 export default {
4 [Types.FETCH_NOTICE_LIST_REQUEST](state, { page }) { 4 [Types.FETCH_NOTICE_LIST_REQUEST](state, { page }) {
5 - console.log("page:"+page+"==="+state.fetchNoticeList) 5 +
6 state.fetchNoticeList = false; 6 state.fetchNoticeList = false;
7 if (page === 1) { 7 if (page === 1) {
8 state.fetchNoticeLastedTime = 0; 8 state.fetchNoticeLastedTime = 0;
@@ -11,10 +11,17 @@ export default { @@ -11,10 +11,17 @@ export default {
11 }, 11 },
12 [Types.FETCH_NOTICE_LIST_SUCCESS](state, { data }) { 12 [Types.FETCH_NOTICE_LIST_SUCCESS](state, { data }) {
13 state.fetchNoticeList = false; 13 state.fetchNoticeList = false;
14 - state.fetchNoticePage += 1; 14 + state.fetchNoticePage = data.page +1;
15 state.fetchNoticeLastedTime = data.lastedTime; 15 state.fetchNoticeLastedTime = data.lastedTime;
16 16
  17 + if(data.page < data.totalPage){
  18 + state.isMore = true;
  19 + }else {
  20 + state.isMore = false;
  21 + }
  22 +
17 const noticeList = data.list || []; 23 const noticeList = data.list || [];
  24 +
18 if (noticeList.length) { 25 if (noticeList.length) {
19 noticeList.forEach(val => { 26 noticeList.forEach(val => {
20 state.noticeList.push(val); 27 state.noticeList.push(val);
@@ -117,6 +117,9 @@ export default function(mergeState = {}) { @@ -117,6 +117,9 @@ export default function(mergeState = {}) {
117 [Types.FETCH_USER_INFO_FAILD](state) { 117 [Types.FETCH_USER_INFO_FAILD](state) {
118 state.context.userHeadIco = ''; 118 state.context.userHeadIco = '';
119 }, 119 },
  120 + [Types.SET_USER_SELLER_INFO](state, sellerInfo) {
  121 + state.user.sellerInfo = sellerInfo || {};
  122 + }
120 }, 123 },
121 getters: { 124 getters: {
122 getLogin(state) { 125 getLogin(state) {
@@ -138,6 +141,14 @@ export default function(mergeState = {}) { @@ -138,6 +141,14 @@ export default function(mergeState = {}) {
138 return {}; 141 return {};
139 } 142 }
140 }, 143 },
  144 + userRealCertification({ commit }, { certName, certNo, frontImageUrl, backImageUrl }) {
  145 + return this.$api.post('/api/ufo/user/certification', {
  146 + certName,
  147 + certNo,
  148 + frontImageUrl,
  149 + backImageUrl
  150 + });
  151 + },
141 reportError(params, {error}) { 152 reportError(params, {error}) {
142 this.$reportError(error); 153 this.$reportError(error);
143 }, 154 },
@@ -2,6 +2,7 @@ export const SET_SERVER_INFO = 'SET_SERVER_INFO'; @@ -2,6 +2,7 @@ export const SET_SERVER_INFO = 'SET_SERVER_INFO';
2 export const SET_ENV = 'SET_ENV'; 2 export const SET_ENV = 'SET_ENV';
3 export const SET_TITLE = 'SET_TITLE'; 3 export const SET_TITLE = 'SET_TITLE';
4 export const SET_USER = 'SET_USER'; 4 export const SET_USER = 'SET_USER';
  5 +export const SET_USER_SELLER_INFO = 'SET_USER_SELLER_INFO';
5 export const ROUTE_CHANGE = 'ROUTE_CHANGE'; 6 export const ROUTE_CHANGE = 'ROUTE_CHANGE';
6 export const REPORT_YAS = 'REPORT_YAS'; 7 export const REPORT_YAS = 'REPORT_YAS';
7 export const SET_NEED_LOGIN = 'SET_NEED_LOGIN'; 8 export const SET_NEED_LOGIN = 'SET_NEED_LOGIN';
@@ -2,6 +2,7 @@ const orderApi = require('./order-api-map'); @@ -2,6 +2,7 @@ const orderApi = require('./order-api-map');
2 const productApi = require('./product-api-map'); 2 const productApi = require('./product-api-map');
3 const listApi = require('./list-api-map'); 3 const listApi = require('./list-api-map');
4 const homeApi = require('./home-api-map'); 4 const homeApi = require('./home-api-map');
  5 +const passportApi = require('./passport-api-map');
5 const addressApi = require('./address-api-map'); 6 const addressApi = require('./address-api-map');
6 const orderListApi = require('./order-list-api-map'); 7 const orderListApi = require('./order-list-api-map');
7 8
@@ -10,6 +11,7 @@ module.exports = { @@ -10,6 +11,7 @@ module.exports = {
10 ...productApi, 11 ...productApi,
11 ...listApi, 12 ...listApi,
12 ...homeApi, 13 ...homeApi,
  14 + ...passportApi,
13 ...addressApi, 15 ...addressApi,
14 ...orderListApi, 16 ...orderListApi,
15 }; 17 };
@@ -2,45 +2,45 @@ module.exports = { @@ -2,45 +2,45 @@ module.exports = {
2 '/api/ufo/mine/rollBoardList': { 2 '/api/ufo/mine/rollBoardList': {
3 ufo: true, 3 ufo: true,
4 api: 'ufo.users.rollNoticeList', 4 api: 'ufo.users.rollNoticeList',
5 - params: {} 5 + params: {},
6 }, 6 },
7 '/api/ufo/mine/seller/orderSummary': { 7 '/api/ufo/mine/seller/orderSummary': {
8 ufo: true, 8 ufo: true,
9 api: 'ufo.seller.orderSummary', 9 api: 'ufo.seller.orderSummary',
10 params: { 10 params: {
11 - uid: {type: Number}  
12 - } 11 + uid: { type: Number },
  12 + },
13 }, 13 },
14 '/api/ufo/mine/favoriteNum': { 14 '/api/ufo/mine/favoriteNum': {
15 ufo: true, 15 ufo: true,
16 api: 'ufo.user.favoriteNum', 16 api: 'ufo.user.favoriteNum',
17 params: { 17 params: {
18 - uid: {type: Number}  
19 - } 18 + uid: { type: Number },
  19 + },
20 }, 20 },
21 '/api/ufo/mine/depositNum': { 21 '/api/ufo/mine/depositNum': {
22 ufo: true, 22 ufo: true,
23 api: 'ufo.deposit.queryUserStorageCount', 23 api: 'ufo.deposit.queryUserStorageCount',
24 params: { 24 params: {
25 - uid: {type: Number}  
26 - } 25 + uid: { type: Number },
  26 + },
27 }, 27 },
28 '/api/ufo/mine/assets': { 28 '/api/ufo/mine/assets': {
29 ufo: true, 29 ufo: true,
30 api: 'ufo.asssets.details', 30 api: 'ufo.asssets.details',
31 params: { 31 params: {
32 - uid: {type: Number},  
33 - limit: {type: Number},  
34 - page: {type: Number}  
35 - } 32 + uid: { type: Number },
  33 + limit: { type: Number },
  34 + page: { type: Number },
  35 + },
36 }, 36 },
37 '/api/ufo/mine/order/summary': { 37 '/api/ufo/mine/order/summary': {
38 ufo: true, 38 ufo: true,
39 path: '/shopping', 39 path: '/shopping',
40 api: 'ufo.order.summary', 40 api: 'ufo.order.summary',
41 params: { 41 params: {
42 - uid: {type: Number}  
43 - } 42 + uid: { type: Number },
  43 + },
44 }, 44 },
45 '/api/ufo/mine/resource': { 45 '/api/ufo/mine/resource': {
46 ufo: true, 46 ufo: true,
@@ -48,17 +48,17 @@ module.exports = { @@ -48,17 +48,17 @@ module.exports = {
48 params: { 48 params: {
49 content_code: { type: String }, 49 content_code: { type: String },
50 uid: { type: Number }, 50 uid: { type: Number },
51 - }  
52 }, 51 },
53 - '/api/ufo/home/noticelist':{ 52 + },
  53 + '/api/ufo/home/noticelist': {
54 ufo: true, 54 ufo: true,
55 api: 'ufo.users.noticeList', 55 api: 'ufo.users.noticeList',
56 - params:{} 56 + params: {},
57 }, 57 },
58 - '/api/ufo/home/favoriteProduct':{ 58 + '/api/ufo/home/favoriteProduct': {
59 ufo: true, 59 ufo: true,
60 api: 'ufo.user.favoriteList', 60 api: 'ufo.user.favoriteList',
61 - params:{} 61 + params: {},
62 }, 62 },
63 '/api/ufo/channel/channelList': { 63 '/api/ufo/channel/channelList': {
64 ufo: true, 64 ufo: true,
@@ -66,6 +66,6 @@ module.exports = { @@ -66,6 +66,6 @@ module.exports = {
66 params: { 66 params: {
67 content_code: { type: String }, 67 content_code: { type: String },
68 uid: { type: Number, require: true }, 68 uid: { type: Number, require: true },
69 - } 69 + },
70 }, 70 },
71 }; 71 };
  1 +module.exports = {
  2 + '/api/ufo/sellerOrder/entryStatus': {
  3 + ufo: true,
  4 + auth: true,
  5 + api: 'ufo.sellerOrder.entryStatus',
  6 + params: {}
  7 + },
  8 + '/api/ufo/user/certification': {
  9 + ufo: true,
  10 + auth: true,
  11 + api: 'ufo.user.alipayCertification',
  12 + params: {
  13 + certName: { type: String, require: true },
  14 + certNo: { type: String, require: true },
  15 + frontImageUrl: { type: String, require: true },
  16 + backImageUrl: { type: String, require: true }
  17 + }
  18 + },
  19 +};
@@ -21,3 +21,47 @@ export const buyerOrderStatus = { @@ -21,3 +21,47 @@ export const buyerOrderStatus = {
21 DONE: 5, // 交易成功 21 DONE: 5, // 交易成功
22 FAILED: 6, // 交易失败 22 FAILED: 6, // 交易失败
23 }; 23 };
  24 +
  25 +// 卖家订单状态, 接口对应查询参数: type
  26 +export const sellerOrderStatusList = [
  27 + {
  28 + value: 1,
  29 + text: '出售中',
  30 + },
  31 + {
  32 + value: 2,
  33 + text: '待发货',
  34 + },
  35 + {
  36 + value: 3,
  37 + text: '已发货',
  38 + },
  39 + {
  40 + value: 5,
  41 + text: '交易完成',
  42 + },
  43 + {
  44 + value: 6,
  45 + text: '交易失败',
  46 + },
  47 +];
  48 +
  49 +// 买家订单状态,接口对应查询参数: type
  50 +export const buyerOrderStatusList = [
  51 + {
  52 + value: 1,
  53 + text: '全部',
  54 + },
  55 + {
  56 + value: 2,
  57 + text: '待付款',
  58 + },
  59 + {
  60 + value: 3,
  61 + text: '待发货',
  62 + },
  63 + {
  64 + value: 4,
  65 + text: '待收货',
  66 + },
  67 +];
@@ -88,6 +88,33 @@ exports.createApp = async(app) => { @@ -88,6 +88,33 @@ exports.createApp = async(app) => {
88 app.use(userMiddleware); 88 app.use(userMiddleware);
89 app.use(serverMiddleware); 89 app.use(serverMiddleware);
90 90
  91 + if (!app.locals.proEnv) {
  92 + app.use((req, res, next) => {
  93 + if (/cordova/.test(req.url)) {
  94 + return res.status(404).end();
  95 + }
  96 + return next();
  97 + });
  98 + app.use('/favicon.ico', (req, res) => {
  99 + res.send('');
  100 + });
  101 + app.use('/passport/login/user', (req, res) => {
  102 + let result = {
  103 + code: 403,
  104 + message: '未登录',
  105 + data: ''
  106 + };
  107 +
  108 + if (req.user.uid) {
  109 + result.code = 200;
  110 + result.message = '已登录';
  111 + result.data = req.user.uid.toString();
  112 + console.log(req.user);
  113 + }
  114 + res.jsonp(result);
  115 + });
  116 + }
  117 +
91 app.use('/xianyu', ssrApiMiddleware); 118 app.use('/xianyu', ssrApiMiddleware);
92 119
93 app.use(ssrRouteMiddleware.routers); 120 app.use(ssrRouteMiddleware.routers);
1 const express = require('express'); 1 const express = require('express');
  2 +const multipart = require('connect-multiparty');
2 3
3 const passport = require('../models/passport'); 4 const passport = require('../models/passport');
  5 +const upload = require('../models/upload');
4 6
5 const app = express(); 7 const app = express();
6 const router = express.Router(); // eslint-disable-line 8 const router = express.Router(); // eslint-disable-line
  9 +const multipartMiddleware = multipart();
7 10
8 -router.get('/xianyu/passport/login/taobao', passport.login.taobaoLogin)  
9 -router.get('/xianyu/passport/callback/taobao', passport.login.taobaoCallback) 11 +router.post('/xianyu/upload/idcard', multipartMiddleware, upload.uploadIdCard);
  12 +
  13 +router.get('/xianyu/passport/login/taobao', passport.login.taobaoLogin);
  14 +router.get('/xianyu/passport/callback/taobao', passport.login.taobaoCallback);
10 15
11 app.use(router); 16 app.use(router);
12 17
@@ -67,66 +67,12 @@ util.inherits(Strategy, OAuth2Strategy); @@ -67,66 +67,12 @@ util.inherits(Strategy, OAuth2Strategy);
67 * @api protected 67 * @api protected
68 */ 68 */
69 Strategy.prototype.userProfile = function (accessToken, done) { 69 Strategy.prototype.userProfile = function (accessToken, done) {
70 - console.log(client)  
71 - client.execute('taobao.user.buyer.get', {  
72 - session: accessToken,  
73 - fields: 'nick,sex' 70 + client.execute('taobao.openuid.get', {
  71 + session: accessToken
74 }).then(res => { 72 }).then(res => {
75 - console.log(res);  
76 - });  
77 -return;  
78 -  
79 -  
80 - console.log(arguments)  
81 - let oauth2 = this._oauth2;  
82 - let url = 'https://eco.taobao.com/router/rest';  
83 - let params = {  
84 - method: 'taobao.user.buyer.get',  
85 - app_key: oauth2._clientId,  
86 - session: accessToken,  
87 - format: 'json',  
88 - v: '2.0',  
89 - fields: 'uid,nick,avatar'  
90 - };  
91 -  
92 -  
93 - // _clientSecret  
94 - // ?format=json&v=2.0&fields=uid,nick,avatar&method=taobao.user.buyer.get';  
95 - // url = url + '&app_key=' + oauth2._clientId;  
96 - // url = url + '&timestamp=' + Date.parse(new Date());  
97 - // url = url + '&access_token=' + accessToken;  
98 - if (!accessToken) {  
99 - return done(new Error('accessToken is empty'));  
100 - }  
101 -  
102 - Object.keys(signMD5(params, oauth2._clientSecret)).forEach((k, i) => {  
103 - url += `${i ? '&' : '?'}${k}=${params[k]}`;  
104 - });  
105 - console.log(url)  
106 - oauth2.get(url, accessToken, function (err, result, res) {  
107 - if (err) {  
108 - return done(new InternalOAuthError('failed to fetch user profile', err));  
109 - }  
110 - try {  
111 - if (result) {  
112 - console.log(result)  
113 - let json = JSON.parse(result);  
114 - if (json.error_response)  
115 - return done(new InternalOAuthError(json.error_response.code + '-' + json.error_response.msg, new Error(json.error_response.msg)));  
116 - else {  
117 - let json = JSON.parse(result);  
118 - let profile = { provider: 'taobao' };  
119 - profile.id = json.uid;  
120 - profile.nickname = json.nick;  
121 - profile.avatar = json.avatar;  
122 - profile._raw = result;  
123 - profile._json = json;  
124 - done(null, profile);  
125 - }  
126 - }  
127 - } catch (e) {  
128 - done('ERROR:' + e + result);  
129 - } 73 + done(null, res);
  74 + }).catch(e => {
  75 + done(new InternalOAuthError('failed to fetch open uid', e));
130 }); 76 });
131 } 77 }
132 78
@@ -4,7 +4,9 @@ const TaobaoStrategy = require('./passport-taobao'); @@ -4,7 +4,9 @@ const TaobaoStrategy = require('./passport-taobao');
4 4
5 const uuid = require('uuid'); 5 const uuid = require('uuid');
6 6
  7 +const log = global.yoho.logger;
7 const config = global.yoho.config; 8 const config = global.yoho.config;
  9 +const loginPage = `${config.siteUrl}/signin.html`;
8 10
9 // taobao 登录 11 // taobao 登录
10 passport.use('taobao', new TaobaoStrategy({ 12 passport.use('taobao', new TaobaoStrategy({
@@ -26,17 +28,14 @@ const login = { @@ -26,17 +28,14 @@ const login = {
26 })(req, res, next); 28 })(req, res, next);
27 }, 29 },
28 taobaoCallback: (req, res, next) => { 30 taobaoCallback: (req, res, next) => {
29 - console.log(req.session)  
30 - // return res.send(req.query);  
31 passport.authenticate('taobao', (err, user) => { 31 passport.authenticate('taobao', (err, user) => {
32 - console.log('21312312')  
33 - console.log(user)  
34 - console.log(err) 32 + if (err || !user) {
  33 + log.error(`taobao authenticate error : ${JSON.stringify(err)}`);
  34 + return res.redirect(loginPage);
  35 + }
  36 +
  37 + res.json(user);
35 })(req, res, next); 38 })(req, res, next);
36 - // if (req.session.authState === req.query.state) {  
37 - // } else {  
38 - // res.send('error');  
39 - // }  
40 } 39 }
41 } 40 }
42 41
  1 +
  2 +const fs = require('fs');
  3 +const _ = require('lodash');
  4 +const request = require('request-promise');
  5 +const log = global.yoho.logger;
  6 +
  7 +const upload = ({ files, type, size, bucket }) => {
  8 + let reqFiles = [];
  9 + let errTip = '';
  10 +
  11 + if (!_.isArray(files)) {
  12 + files = [files];
  13 + }
  14 +
  15 + size = size || 10 * 1024 * 1024;
  16 +
  17 + files.forEach(file => {
  18 + let fileType = file.type.split('/');
  19 +
  20 + if (!fileType || (type && fileType[0] !== type)) {
  21 + errTip = '上传文件格式不正确!';
  22 + }
  23 +
  24 + if (file.size > size) {
  25 + errTip = '上传文件尺寸太大!';
  26 + }
  27 +
  28 + reqFiles.push(fs.createReadStream(file.path));
  29 + reqFiles.push(file.name);
  30 + });
  31 +
  32 + if (errTip) {
  33 + return Promise.resolve({
  34 + code: 403,
  35 + message: errTip
  36 + });
  37 + }
  38 +
  39 + return request({
  40 + method: 'post',
  41 + url: 'http://upload.static.yohobuy.com',
  42 + formData: {
  43 + fileData: reqFiles,
  44 + project: bucket
  45 + },
  46 + json: true
  47 + }).catch(err => {
  48 + let message = 'file upload error';
  49 +
  50 + log.error(message, JSON.stringify(err));
  51 + return {
  52 + code: 403,
  53 + message
  54 + };
  55 + });
  56 +}
  57 +
  58 +const uploadIdCard = (req, res, next) => {
  59 + upload({
  60 + files: req.files && req.files.file || [],
  61 + type: 'image',
  62 + bucket: 'yohocard'
  63 + }).then(res.json).catch(next);
  64 +}
  65 +
  66 +module.exports = {
  67 + uploadIdCard
  68 +};
  1 +declare module 'yohoApi' {
  2 + type PlainObject<T = any> = { [key: string]: T };
  3 +
  4 + type ApiMap = { [key: string]: UrlParam };
  5 +
  6 + interface UrlParam {
  7 + api: string; // 接口方法名
  8 + ufo: boolean; // 是否是ufo接口
  9 + service: boolean; // service接口
  10 + path: string; // 接口路由
  11 + auth?: boolean; // 接口是否需要登陆,ture时请求参数会自动添加uid
  12 + params?: PlainObject; // 仅用于参数校验,不会合并到请求参数中
  13 + }
  14 +}
  1 +declare module 'yoho' {
  2 + interface OrderOwner {}
  3 +}