Merge branch 'release/1.0' of http://git.yoho.cn/fe/yoho-app-web into feature/ufo
# Conflicts: # config/ssr-routes.js
Showing
23 changed files
with
504 additions
and
529 deletions
@@ -133,6 +133,10 @@ export default { | @@ -133,6 +133,10 @@ export default { | ||
133 | }, | 133 | }, |
134 | zoom: { | 134 | zoom: { |
135 | default: false | 135 | default: false |
136 | + }, | ||
137 | + observeDom: { | ||
138 | + type: Boolean, | ||
139 | + default: true | ||
136 | } | 140 | } |
137 | }, | 141 | }, |
138 | data() { | 142 | data() { |
@@ -185,7 +189,8 @@ export default { | @@ -185,7 +189,8 @@ export default { | ||
185 | freeScroll: this.freeScroll, | 189 | freeScroll: this.freeScroll, |
186 | mouseWheel: this.mouseWheel, | 190 | mouseWheel: this.mouseWheel, |
187 | bounce: this.bounce, | 191 | bounce: this.bounce, |
188 | - zoom: this.zoom | 192 | + zoom: this.zoom, |
193 | + observeDOM: this.observeDom, | ||
189 | }; | 194 | }; |
190 | 195 | ||
191 | this.scroll = new BetterScroll(this.$refs.wrapper, options); | 196 | this.scroll = new BetterScroll(this.$refs.wrapper, options); |
@@ -11,8 +11,6 @@ import 'statics/font/ufofont.css'; | @@ -11,8 +11,6 @@ import 'statics/font/ufofont.css'; | ||
11 | 11 | ||
12 | const {app, router, store} = createApp(); | 12 | const {app, router, store} = createApp(); |
13 | 13 | ||
14 | -window.newBlk = true; | ||
15 | - | ||
16 | if (window.__INITIAL_STATE__) { | 14 | if (window.__INITIAL_STATE__) { |
17 | store.replaceState(window.__INITIAL_STATE__); | 15 | store.replaceState(window.__INITIAL_STATE__); |
18 | } | 16 | } |
1 | <template> | 1 | <template> |
2 | - <Modal :value="value" @input="onInput" ref="modal" :transfer="true" @on-sure="onSure"> | 2 | + <Modal class="ufo-font" :value="value" @input="onInput" ref="modal" :transfer="true" @on-sure="onSure"> |
3 | <div class="change-price-modal"> | 3 | <div class="change-price-modal"> |
4 | <p class="modal-title">当前42码最低售价:¥1999.00</p> | 4 | <p class="modal-title">当前42码最低售价:¥1999.00</p> |
5 | <Inputx :maxlength="8" class="input-number"> | 5 | <Inputx :maxlength="8" class="input-number"> |
1 | <template> | 1 | <template> |
2 | - <Modal :value="value" @input="onInput" ref="modal" :transfer="true" @on-sure="onSure"> | 2 | + <Modal class="ufo-font" :value="value" @input="onInput" ref="modal" :transfer="true" @on-sure="onSure"> |
3 | <div class="change-price-modal"> | 3 | <div class="change-price-modal"> |
4 | <p class="modal-title">选择你要下架的数量</p> | 4 | <p class="modal-title">选择你要下架的数量</p> |
5 | <Inputx v-model="stockNum" :maxlength="8" :readonly="true" class="input-number"> | 5 | <Inputx v-model="stockNum" :maxlength="8" :readonly="true" class="input-number"> |
1 | +<template> | ||
2 | + <div class="product-item" :class="{['has-tip']: value.tip}"> | ||
3 | + <div class="item-content" :style="itemStyle" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"> | ||
4 | + <div class="tip" v-if="value.tip">超出建议售价将被限制超出建议售价将被限制展示</div> | ||
5 | + <div class="info"> | ||
6 | + <div class="left"> | ||
7 | + <span class="size">{{value.size}}</span> | ||
8 | + <span class="l-size">1/3</span> | ||
9 | + <span class="unit">码</span> | ||
10 | + </div> | ||
11 | + <div class="middle"> | ||
12 | + <p class="size-store">¥{{value.price}},12个库存</p> | ||
13 | + <p class="low-price">当前最低价¥{{value.price}}</p> | ||
14 | + </div> | ||
15 | + <div class="right"> | ||
16 | + <Button class="chg-price" @click="onChgPrice">调 价</Button> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + </div> | ||
20 | + <div ref="options" class="item-options"> | ||
21 | + <Button class="btn-no-sale" @click="onNoSale">不卖了</Button> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | +</template> | ||
25 | + | ||
26 | +<script> | ||
27 | +import {Button} from 'cube-ui'; | ||
28 | + | ||
29 | +export default { | ||
30 | + name: 'ProductItem', | ||
31 | + data() { | ||
32 | + return { | ||
33 | + distance: 0, | ||
34 | + startX: 0, | ||
35 | + startY: 0, | ||
36 | + move: false, | ||
37 | + transition: true | ||
38 | + }; | ||
39 | + }, | ||
40 | + computed: { | ||
41 | + itemStyle() { | ||
42 | + return { | ||
43 | + transition: this.transition ? void 0 : 'none 0s ease 0s', | ||
44 | + transform: this.move ? `translate3d(${this.distance}px, 0px, 0px)` : void 0 | ||
45 | + }; | ||
46 | + } | ||
47 | + }, | ||
48 | + props: { | ||
49 | + value: Object, | ||
50 | + slideValue: Object | ||
51 | + }, | ||
52 | + mounted() { | ||
53 | + | ||
54 | + }, | ||
55 | + watch: { | ||
56 | + slideValue(val) { | ||
57 | + if (this.distance !== 0 && this.value !== val) { | ||
58 | + this.distance = 0; | ||
59 | + this.timeout = setTimeout(() => { | ||
60 | + this.move = false; | ||
61 | + }, 500); | ||
62 | + } | ||
63 | + } | ||
64 | + }, | ||
65 | + methods: { | ||
66 | + onNoSale() { | ||
67 | + this.$emit('on-no-sale'); | ||
68 | + }, | ||
69 | + onChgPrice() { | ||
70 | + this.$emit('on-chg-price'); | ||
71 | + }, | ||
72 | + onTouchStart(evt) { | ||
73 | + const {clientX, clientY} = evt.touches[0]; | ||
74 | + | ||
75 | + this.startX = clientX - this.distance; | ||
76 | + this.startY = clientY; | ||
77 | + if (this.timeout) { | ||
78 | + clearTimeout(this.timeout); | ||
79 | + } | ||
80 | + }, | ||
81 | + onTouchMove(evt) { | ||
82 | + this.transition = false; | ||
83 | + const {clientX, clientY} = evt.touches[0]; | ||
84 | + let distance = clientX - this.startX; | ||
85 | + | ||
86 | + if (Math.abs(clientY - this.startY) > 20 && this.distance === 0) { | ||
87 | + this.startX = 0; | ||
88 | + return; | ||
89 | + } | ||
90 | + | ||
91 | + if (0 - distance > 20 && !this.move) { | ||
92 | + this.$emit('on-slide', this.value); | ||
93 | + this.move = true; | ||
94 | + } | ||
95 | + | ||
96 | + if (this.distance + distance > 0) { | ||
97 | + return; | ||
98 | + } | ||
99 | + if (this.move) { | ||
100 | + this.distance = distance; | ||
101 | + } | ||
102 | + }, | ||
103 | + onTouchEnd() { | ||
104 | + const optionsWidth = this.$refs.options.clientWidth; | ||
105 | + | ||
106 | + if (0 - this.distance > optionsWidth) { | ||
107 | + this.transition = true; | ||
108 | + this.distance = 0 - optionsWidth; | ||
109 | + } else if (0 - this.distance < optionsWidth) { | ||
110 | + this.transition = true; | ||
111 | + this.distance = 0; | ||
112 | + } | ||
113 | + if (this.distance === 0) { | ||
114 | + this.timeout = setTimeout(() => { | ||
115 | + this.move = false; | ||
116 | + }, 500); | ||
117 | + } | ||
118 | + } | ||
119 | + }, | ||
120 | + components: {Button} | ||
121 | +}; | ||
122 | +</script> | ||
123 | + | ||
124 | +<style lang="scss" scoped> | ||
125 | +.product-item { | ||
126 | + width: 100%; | ||
127 | + border-bottom: 1px solid #eee; | ||
128 | + position: relative; | ||
129 | +} | ||
130 | + | ||
131 | +.item-content { | ||
132 | + padding-left: 40px; | ||
133 | + padding-right: 40px; | ||
134 | + position: relative; | ||
135 | + z-index: 2; | ||
136 | + background-color: #fff; | ||
137 | + padding-top: 20px; | ||
138 | + padding-bottom: 40px; | ||
139 | + transition: transform 0.5s cubic-bezier(0.36, 0.66, 0.04, 1); | ||
140 | +} | ||
141 | + | ||
142 | +.item-options { | ||
143 | + position: absolute; | ||
144 | + top: 0; | ||
145 | + right: 0; | ||
146 | + bottom: 0; | ||
147 | + z-index: 1; | ||
148 | + | ||
149 | + .cube-btn { | ||
150 | + height: 100%; | ||
151 | + line-height: 1; | ||
152 | + background-color: #eee; | ||
153 | + width: 160px; | ||
154 | + font-size: 28px; | ||
155 | + color: #000; | ||
156 | + | ||
157 | + &:active { | ||
158 | + opacity: 0.7; | ||
159 | + } | ||
160 | + } | ||
161 | +} | ||
162 | + | ||
163 | +.tip { | ||
164 | + color: #d0021b; | ||
165 | +} | ||
166 | + | ||
167 | +.info { | ||
168 | + width: 100%; | ||
169 | + display: flex; | ||
170 | + padding-top: 20px; | ||
171 | +} | ||
172 | + | ||
173 | +.left { | ||
174 | + width: 160px; | ||
175 | + display: flex; | ||
176 | + height: 56px; | ||
177 | + align-items: flex-end; | ||
178 | + | ||
179 | + .size { | ||
180 | + font-size: 56px; | ||
181 | + line-height: 56px; | ||
182 | + margin-right: 6px; | ||
183 | + } | ||
184 | + | ||
185 | + .l-size { | ||
186 | + align-self: flex-end; | ||
187 | + margin-right: 6px; | ||
188 | + } | ||
189 | + | ||
190 | + .unit { | ||
191 | + align-self: flex-start; | ||
192 | + margin-right: 6px; | ||
193 | + } | ||
194 | +} | ||
195 | + | ||
196 | +.middle { | ||
197 | + flex: 1; | ||
198 | + | ||
199 | + .size-store { | ||
200 | + font-size: 28px; | ||
201 | + } | ||
202 | + | ||
203 | + .low-price { | ||
204 | + color: #999; | ||
205 | + margin-top: 6px; | ||
206 | + } | ||
207 | +} | ||
208 | + | ||
209 | +.right { | ||
210 | + width: 130px; | ||
211 | + text-align: right; | ||
212 | + display: flex; | ||
213 | + align-items: center; | ||
214 | + | ||
215 | + .chg-price { | ||
216 | + width: 130px; | ||
217 | + height: 60px; | ||
218 | + line-height: 60px; | ||
219 | + padding-top: 0; | ||
220 | + padding-bottom: 0; | ||
221 | + background-color: #08314d; | ||
222 | + font-size: 28px; | ||
223 | + | ||
224 | + &:active { | ||
225 | + opacity: 0.7; | ||
226 | + } | ||
227 | + } | ||
228 | +} | ||
229 | +</style> |
1 | +<template> | ||
2 | + <div class="product-group"> | ||
3 | + <ProductItem | ||
4 | + v-for="(skc, i) in skcs" | ||
5 | + :key="i" | ||
6 | + :value="skc" | ||
7 | + :slideValue="slideSkc" | ||
8 | + @on-chg-price="onChgPrice" | ||
9 | + @on-no-sale="onNoSale" | ||
10 | + @on-slide="onSlide"></ProductItem> | ||
11 | + <ModalPrice | ||
12 | + v-if="modalLoad" | ||
13 | + ref="modalPrice" | ||
14 | + v-model="showModalPrice" | ||
15 | + @on-sure="onPriceSure"> | ||
16 | + </ModalPrice> | ||
17 | + <ModalUnstock | ||
18 | + v-if="modalLoad" | ||
19 | + ref="modalUnstock" | ||
20 | + v-model="showModalUnstock" | ||
21 | + @on-sure="onUnstockSure"> | ||
22 | + </ModalUnstock> | ||
23 | + </div> | ||
24 | +</template> | ||
25 | + | ||
26 | +<script> | ||
27 | +import ModalPrice from './modal-price'; | ||
28 | +import ModalUnstock from './modal-unstock'; | ||
29 | +import ProductItem from './product-item'; | ||
30 | + | ||
31 | +export default { | ||
32 | + name: 'ProductList', | ||
33 | + props: { | ||
34 | + skcs: Array | ||
35 | + }, | ||
36 | + data() { | ||
37 | + return { | ||
38 | + modalLoad: false, | ||
39 | + showModalPrice: false, | ||
40 | + showTips: false, | ||
41 | + showModalUnstock: false, | ||
42 | + slideSkc: {} | ||
43 | + }; | ||
44 | + }, | ||
45 | + mounted() { | ||
46 | + this.modalLoad = true; | ||
47 | + }, | ||
48 | + methods: { | ||
49 | + onPriceSure() { | ||
50 | + this.showTips = !this.showTips; | ||
51 | + }, | ||
52 | + onUnstockSure() { | ||
53 | + this.showTips = !this.showTips; | ||
54 | + }, | ||
55 | + onChgPrice() { | ||
56 | + this.showModalPrice = true; | ||
57 | + }, | ||
58 | + onNoSale() { | ||
59 | + this.showModalUnstock = true; | ||
60 | + }, | ||
61 | + onSlide(val) { | ||
62 | + console.log('onSlide') | ||
63 | + this.slideSkc = val; | ||
64 | + } | ||
65 | + }, | ||
66 | + components: {ModalPrice, ModalUnstock, ProductItem} | ||
67 | +}; | ||
68 | +</script> |
1 | <template> | 1 | <template> |
2 | <LayoutApp class="ufo-font" :class="classes"> | 2 | <LayoutApp class="ufo-font" :class="classes"> |
3 | - <ScrollView ref="scroll" :pull-up-load="true" :pull-down-refresh="true" @pullingUp="onPullingUp" @pullingDown="onPullingDown"> | 3 | + <ScrollView ref="scroll" :observe-dom="false" :pull-up-load="true" :pull-down-refresh="true" @pullingUp="onPullingUp" @pullingDown="onPullingDown"> |
4 | <div class="order-page"> | 4 | <div class="order-page"> |
5 | <div class="title">出售中</div> | 5 | <div class="title">出售中</div> |
6 | <div class="product"> | 6 | <div class="product"> |
@@ -10,48 +10,19 @@ | @@ -10,48 +10,19 @@ | ||
10 | <p class="stock-info">5个尺码,39个商品库存</p> | 10 | <p class="stock-info">5个尺码,39个商品库存</p> |
11 | </div> | 11 | </div> |
12 | </div> | 12 | </div> |
13 | - <p class="arrival-time"><i class="iconfont icon-info"></i>最新上架时间:2018.10.27 00:16:41</p> | ||
14 | - <div class="product-group"> | ||
15 | - <div class="product-item" :class="{['has-tip']: skc.tip}" v-for="(skc, i) in orderDetail.skcs" :key="i" @click="onClick"> | ||
16 | - <div class="tip" v-if="skc.tip">超出建议售价将被限制超出建议售价将被限制展示</div> | ||
17 | - <div class="info"> | ||
18 | - <div class="left"> | ||
19 | - <span class="size">{{skc.size}}</span> | ||
20 | - <span class="l-size">1/3</span> | ||
21 | - <span class="unit">码</span> | ||
22 | - </div> | ||
23 | - <div class="middle"> | ||
24 | - <p class="size-store">¥{{skc.price}},12个库存</p> | ||
25 | - <p class="low-price">当前最低价¥{{skc.price}}</p> | ||
26 | - </div> | ||
27 | - <div class="right"> | ||
28 | - <Button class="chg-price" @click="onChgPrice">调价</Button> | ||
29 | - </div> | ||
30 | - </div> | ||
31 | - </div> | 13 | + <div class="arrival"> |
14 | + <p class="arrival-time"><i class="iconfont icon-info"></i><span>尺码列表左滑选择 不卖了 ,下架当前尺码商品</span></p> | ||
32 | </div> | 15 | </div> |
16 | + <ProductList :skcs="orderDetail.skcs"></ProductList> | ||
33 | </div> | 17 | </div> |
34 | </ScrollView> | 18 | </ScrollView> |
35 | - <ModalPrice | ||
36 | - v-if="modalLoad" | ||
37 | - ref="modalPrice" | ||
38 | - v-model="showModalPrice" | ||
39 | - @on-sure="onPriceSure"> | ||
40 | - </ModalPrice> | ||
41 | - <ModalUnstock | ||
42 | - v-if="modalLoad" | ||
43 | - ref="modalUnstock" | ||
44 | - v-model="showModalUnstock" | ||
45 | - @on-sure="onUnstockSure"> | ||
46 | - </ModalUnstock> | ||
47 | </LayoutApp> | 19 | </LayoutApp> |
48 | </template> | 20 | </template> |
49 | 21 | ||
50 | <script> | 22 | <script> |
51 | import {Button} from 'cube-ui'; | 23 | import {Button} from 'cube-ui'; |
52 | -import ModalPrice from './components/modal-price'; | ||
53 | -import ModalUnstock from './components/modal-unstock'; | ||
54 | -import ScrollView from 'components/scroll-view.vue'; | 24 | +import ScrollView from 'components/scroll-view'; |
25 | +import ProductList from './components/product-list'; | ||
55 | import {createNamespacedHelpers} from 'vuex'; | 26 | import {createNamespacedHelpers} from 'vuex'; |
56 | 27 | ||
57 | 28 | ||
@@ -74,11 +45,8 @@ export default { | @@ -74,11 +45,8 @@ export default { | ||
74 | asyncData({store, router}) { | 45 | asyncData({store, router}) { |
75 | return store.dispatch('ufo/order/fetchProduct', {orderId: router.params.orderId}); | 46 | return store.dispatch('ufo/order/fetchProduct', {orderId: router.params.orderId}); |
76 | }, | 47 | }, |
77 | - created() { | ||
78 | - }, | ||
79 | mounted() { | 48 | mounted() { |
80 | this.fetchOrderDetail({orderId: this.$route.params.orderId}); | 49 | this.fetchOrderDetail({orderId: this.$route.params.orderId}); |
81 | - this.modalLoad = true; | ||
82 | }, | 50 | }, |
83 | methods: { | 51 | methods: { |
84 | ...mapActions(['fetchOrderDetail']), | 52 | ...mapActions(['fetchOrderDetail']), |
@@ -95,34 +63,25 @@ export default { | @@ -95,34 +63,25 @@ export default { | ||
95 | onClick() { | 63 | onClick() { |
96 | this.showModalUnstock = true; | 64 | this.showModalUnstock = true; |
97 | }, | 65 | }, |
98 | - onPriceSure() { | ||
99 | - this.showTips = !this.showTips; | ||
100 | - }, | ||
101 | - onUnstockSure() { | ||
102 | - this.showTips = !this.showTips; | ||
103 | - }, | ||
104 | - onNoSale() { | ||
105 | - this.showModalUnstock = true; | ||
106 | - }, | ||
107 | - onChgPrice() { | ||
108 | - this.showModalPrice = true; | ||
109 | - } | ||
110 | }, | 66 | }, |
111 | - components: {ModalPrice, ModalUnstock, Button, ScrollView} | 67 | + components: {Button, ScrollView, ProductList} |
112 | }; | 68 | }; |
113 | </script> | 69 | </script> |
114 | 70 | ||
115 | <style lang="scss" scoped> | 71 | <style lang="scss" scoped> |
116 | .order-page { | 72 | .order-page { |
117 | - padding: 24px 40px; | ||
118 | - | ||
119 | & > .title { | 73 | & > .title { |
120 | font-size: 82px; | 74 | font-size: 82px; |
121 | font-weight: bold; | 75 | font-weight: bold; |
76 | + padding-top: 24px; | ||
77 | + padding-left: 40px; | ||
78 | + padding-right: 40px; | ||
122 | } | 79 | } |
123 | 80 | ||
124 | .product { | 81 | .product { |
125 | width: 100%; | 82 | width: 100%; |
83 | + padding-left: 40px; | ||
84 | + padding-right: 40px; | ||
126 | height: 192px; | 85 | height: 192px; |
127 | display: flex; | 86 | display: flex; |
128 | 87 | ||
@@ -152,95 +111,29 @@ export default { | @@ -152,95 +111,29 @@ export default { | ||
152 | } | 111 | } |
153 | } | 112 | } |
154 | 113 | ||
155 | - .arrival-time { | 114 | + .arrival { |
156 | margin-top: 20px; | 115 | margin-top: 20px; |
157 | margin-bottom: 20px; | 116 | margin-bottom: 20px; |
117 | + padding-left: 40px; | ||
118 | + padding-right: 40px; | ||
158 | width: 100%; | 119 | width: 100%; |
159 | - height: 56px; | ||
160 | - line-height: 56px; | ||
161 | - color: #999; | ||
162 | - font-size: 24px; | ||
163 | - padding-left: 14px; | ||
164 | - padding-right: 14px; | ||
165 | - background-color: #f0f0f0; | ||
166 | - display: flex; | ||
167 | - | ||
168 | - i { | ||
169 | - font-size: 30px; | ||
170 | - margin-right: 10px; | ||
171 | - align-items: center; | ||
172 | - } | ||
173 | - } | ||
174 | - | ||
175 | - .product-group { | ||
176 | - .product-item { | ||
177 | - width: 100%; | ||
178 | - border-bottom: 1px solid #eee; | ||
179 | - padding-top: 20px; | ||
180 | - padding-bottom: 40px; | ||
181 | - } | ||
182 | - | ||
183 | - .tip { | ||
184 | - color: #d0021b; | ||
185 | - } | ||
186 | 120 | ||
187 | - .info { | ||
188 | - width: 100%; | ||
189 | - display: flex; | ||
190 | - padding-top: 20px; | ||
191 | - } | ||
192 | - | ||
193 | - .left { | ||
194 | - width: 160px; | ||
195 | - display: flex; | 121 | + .arrival-time { |
196 | height: 56px; | 122 | height: 56px; |
197 | - align-items: flex-end; | ||
198 | - | ||
199 | - .size { | ||
200 | - font-size: 56px; | ||
201 | - line-height: 56px; | ||
202 | - margin-right: 6px; | ||
203 | - } | ||
204 | - | ||
205 | - .l-size { | ||
206 | - align-self: flex-end; | ||
207 | - margin-right: 6px; | ||
208 | - } | ||
209 | - | ||
210 | - .unit { | ||
211 | - align-self: flex-start; | ||
212 | - margin-right: 6px; | ||
213 | - } | ||
214 | - } | ||
215 | - | ||
216 | - .middle { | ||
217 | - flex: 1; | ||
218 | - | ||
219 | - .size-store { | ||
220 | - font-size: 28px; | ||
221 | - } | ||
222 | - | ||
223 | - .low-price { | ||
224 | - color: #999; | ||
225 | - margin-top: 6px; | ||
226 | - } | ||
227 | - } | ||
228 | - | ||
229 | - .right { | ||
230 | - width: 130px; | ||
231 | - text-align: right; | 123 | + color: #999; |
124 | + font-size: 24px; | ||
125 | + padding-left: 14px; | ||
126 | + padding-right: 14px; | ||
127 | + background-color: #f0f0f0; | ||
128 | + display: flex; | ||
129 | + align-items: center; | ||
232 | 130 | ||
233 | - .chg-price { | ||
234 | - width: 130px; | ||
235 | - height: 60px; | ||
236 | - line-height: 60px; | ||
237 | - padding-top: 0; | ||
238 | - padding-bottom: 0; | ||
239 | - background-color: #002b47; | ||
240 | - font-size: 28px; | 131 | + i { |
132 | + font-size: 30px; | ||
133 | + margin-right: 10px; | ||
134 | + align-items: center; | ||
241 | } | 135 | } |
242 | } | 136 | } |
243 | } | 137 | } |
244 | } | 138 | } |
245 | - | ||
246 | </style> | 139 | </style> |
1 | -const dispatchTap = (evt) => { | ||
2 | - const clickEvent = document.createEvent('MouseEvents'); | ||
3 | - const touch = evt.changedTouches[0] || {}; | ||
4 | - | ||
5 | - clickEvent.initMouseEvent('e-click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); | ||
6 | - clickEvent.forwardedTouchEvent = true; | ||
7 | - evt.target.dispatchEvent(clickEvent); | ||
8 | -}; | ||
9 | - | ||
10 | -const onTouchstart = function() { | ||
11 | - setTimeout(() => { // ios webview中scroll和touchmove事件在滚动时会被阻塞,判断滑动状态放入下一次Event loop | ||
12 | - if (this.state.yoho.touchStatus !== 'scrolling' || // 额外判断滚动状态中止100ms后可以触发tap事件 | ||
13 | - Date.now() - this.state.yoho.scrollTime > 100) { | ||
14 | - this.commit('SET_TOUCH_STATUS', {touchStatus: 'touchstart'}); | ||
15 | - } | ||
16 | - }, 0); | ||
17 | -}; | ||
18 | -const onTouchend = function(evt) { | ||
19 | - setTimeout(() => { // 同样放入下一次Event loop否则会导致touchend优先于touchstart事件触发 | ||
20 | - if (this.state.yoho.touchStatus === 'touchstart') { | ||
21 | - dispatchTap(evt); // 触发自定义e-click事件 | ||
22 | - this.commit('SET_TOUCH_STATUS', {touchStatus: ''}); | ||
23 | - } | ||
24 | - }, 0); | ||
25 | - | ||
26 | - if (evt.cancelable) { // ios webview中如果不阻止默认事件会导致:点击后迅速滑动不能及时响应 | ||
27 | - evt.preventDefault(); | ||
28 | - } | ||
29 | -}; | ||
30 | -const onTouchmove = function() { | ||
31 | - this.commit('SET_TOUCH_STATUS', {touchStatus: 'scrolling', time: Date.now()}); | ||
32 | -}; | ||
33 | -const onScroll = function() { | ||
34 | - console.log('onScroll') | ||
35 | - this.commit('SET_TOUCH_STATUS', {touchStatus: 'scrolling', time: Date.now()}); | ||
36 | -}; | ||
37 | - | ||
38 | - | ||
39 | export default store => { | 1 | export default store => { |
40 | - // if (process.env.VUE_ENV === 'client') { | ||
41 | - // // 自定义点击事件,解决ioswebview中点击延迟和滑动中误点击响应的问题。 | ||
42 | - // let supportsPassive = false; | ||
43 | - | ||
44 | - // try { | ||
45 | - // const opts = Object.defineProperty({}, 'passive', { | ||
46 | - // get: function() { | ||
47 | - // supportsPassive = true; | ||
48 | - // return false; | ||
49 | - // } | ||
50 | - // }); | ||
51 | - | ||
52 | - // window.addEventListener('test', null, opts); | ||
53 | - // } catch (e) {} //eslint-disable-line | ||
54 | - // store.commit('SET_SUPPORTS_PASSIVE', supportsPassive); | ||
55 | - | ||
56 | - // document.addEventListener('touchstart', onTouchstart.bind(store)); | ||
57 | - // document.addEventListener('touchend', onTouchend.bind(store)); | ||
58 | - // document.addEventListener('scroll', onScroll.bind(store), supportsPassive ? { passive: true } : false); | ||
59 | - // document.addEventListener('touchmove', onTouchmove.bind(store), supportsPassive ? { passive: true } : false); | ||
60 | - // } | 2 | + |
61 | }; | 3 | }; |
apps/utils/dom.js
0 → 100644
@@ -14,7 +14,6 @@ let webpackConfig = merge(baseConfig, { | @@ -14,7 +14,6 @@ let webpackConfig = merge(baseConfig, { | ||
14 | target: 'node', | 14 | target: 'node', |
15 | resolve: { | 15 | resolve: { |
16 | alias: { | 16 | alias: { |
17 | - hammerjs$: 'vue-touch/dist/hammer-ssr.js', | ||
18 | 'create-api': 'common/create-api-server.js' | 17 | 'create-api': 'common/create-api-server.js' |
19 | } | 18 | } |
20 | }, | 19 | }, |
@@ -22,7 +21,7 @@ let webpackConfig = merge(baseConfig, { | @@ -22,7 +21,7 @@ let webpackConfig = merge(baseConfig, { | ||
22 | libraryTarget: 'commonjs2', | 21 | libraryTarget: 'commonjs2', |
23 | }, | 22 | }, |
24 | externals: nodeExternals({ | 23 | externals: nodeExternals({ |
25 | - whitelist: [/cube-ui/] | 24 | + whitelist: [/\.css$/, /cube-ui/] |
26 | }), | 25 | }), |
27 | plugins: [ | 26 | plugins: [ |
28 | new VueSSRServerPlugin({ | 27 | new VueSSRServerPlugin({ |
@@ -57,7 +57,7 @@ module.exports = { | @@ -57,7 +57,7 @@ module.exports = { | ||
57 | activity: '//activity.yohobuy.com', | 57 | activity: '//activity.yohobuy.com', |
58 | index: '//m.yohobuy.com' | 58 | index: '//m.yohobuy.com' |
59 | }, | 59 | }, |
60 | - useCache: false, | 60 | + useCache: true, |
61 | loggers: { | 61 | loggers: { |
62 | infoFile: { | 62 | infoFile: { |
63 | close: true, | 63 | close: true, |
1 | module.exports = [ | 1 | module.exports = [ |
2 | { | 2 | { |
3 | route: /channel/, | 3 | route: /channel/, |
4 | - cache: true, | 4 | + cache: true |
5 | }, | 5 | }, |
6 | { | 6 | { |
7 | route: /ufo\/order/, | 7 | route: /ufo\/order/, |
8 | cache: true, | 8 | cache: true, |
9 | - }, | 9 | + cackeKey: '$url$params', |
10 | + cacheTime: 10 | ||
11 | + } | ||
10 | { | 12 | { |
11 | route: /coupon\/ufo/, | 13 | route: /coupon\/ufo/, |
12 | cache: true | 14 | cache: true |
1 | const fs = require('fs'); | 1 | const fs = require('fs'); |
2 | const path = require('path'); | 2 | const path = require('path'); |
3 | -const LRU = require('lru-cache'); | ||
4 | const url = require('url'); | 3 | const url = require('url'); |
4 | +const sourceMap = require('source-map'); | ||
5 | const _ = require('lodash'); | 5 | const _ = require('lodash'); |
6 | +const md5 = require('yoho-md5'); | ||
6 | const pkg = require('../../package.json'); | 7 | const pkg = require('../../package.json'); |
7 | const routes = require('../../config/ssr-routes'); | 8 | const routes = require('../../config/ssr-routes'); |
9 | +const redis = require('../../utils/redis'); | ||
8 | const {createBundleRenderer} = require('vue-server-renderer'); | 10 | const {createBundleRenderer} = require('vue-server-renderer'); |
11 | +const logger = global.yoho.logger; | ||
12 | +const config = global.yoho.config; | ||
9 | 13 | ||
10 | -const microCache = LRU({ // eslint-disable-line | ||
11 | - max: 1000, | ||
12 | - maxAge: 2000 | ||
13 | -}); | 14 | +const REG_STACK = /at ([^:]+):(\d+):(\d+)/; |
14 | 15 | ||
15 | const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV; | 16 | const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV; |
16 | 17 | ||
17 | let renderer; | 18 | let renderer; |
19 | +let serverBundle; | ||
18 | 20 | ||
19 | if (!isDev) { | 21 | if (!isDev) { |
20 | const template = fs.readFileSync(path.join(__dirname, '../../apps/index.html'), 'utf-8'); | 22 | const template = fs.readFileSync(path.join(__dirname, '../../apps/index.html'), 'utf-8'); |
21 | - const serverBundle = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-server-${pkg.version}.json`); | 23 | + |
24 | + serverBundle = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-server-${pkg.version}.json`); | ||
22 | const clientManifest = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-client-${pkg.version}.json`); | 25 | const clientManifest = require(`../../dist/yohoblk-wap/bundle/yoho-ssr-client-${pkg.version}.json`); |
23 | 26 | ||
24 | renderer = createBundleRenderer(serverBundle, { | 27 | renderer = createBundleRenderer(serverBundle, { |
@@ -43,32 +46,85 @@ const getContext = (req) => { | @@ -43,32 +46,85 @@ const getContext = (req) => { | ||
43 | }; | 46 | }; |
44 | }; | 47 | }; |
45 | 48 | ||
46 | -const render = ({cache, cacheRule}) => { | ||
47 | - return (req, res, next) => { | ||
48 | - const reqUrl = url.parse(req.url); | 49 | +const getCacheKey = (urlPath, cackeKey = '') => { |
50 | + const urlObj = url.parse(urlPath); | ||
51 | + | ||
52 | + return md5(cackeKey | ||
53 | + .replace('$url', urlObj.pathname) | ||
54 | + .replace('$params', urlObj.query)); | ||
55 | +}; | ||
56 | + | ||
57 | +const parseError = async({stack = ''}) => { | ||
58 | + try { | ||
59 | + const splits = stack.split('\n'); | ||
60 | + const lastError = splits.map(str => { | ||
61 | + const match = str.match(REG_STACK); | ||
49 | 62 | ||
50 | - if (cache && reqUrl[cacheRule]) { | ||
51 | - const html = microCache.get(reqUrl[cacheRule]); | 63 | + if (match) { |
64 | + return {file: match[1], line: parseInt(match[2], 10), column: parseInt(match[3], 10)}; | ||
65 | + } | ||
66 | + return false; | ||
67 | + }).find(match => match); | ||
68 | + | ||
69 | + if (lastError && lastError.file) { | ||
70 | + const consumer = await new sourceMap.SourceMapConsumer(serverBundle.maps[lastError.file]); | ||
71 | + | ||
72 | + const origin = consumer.originalPositionFor({ | ||
73 | + line: lastError.line, | ||
74 | + column: 342 | ||
75 | + }); | ||
76 | + | ||
77 | + console.log(origin); | ||
78 | + } | ||
79 | + } catch (error) { | ||
80 | + logger.error(error); | ||
81 | + } | ||
82 | +}; | ||
83 | + | ||
84 | +const render = (route) => { | ||
85 | + return async(req, res, next) => { | ||
86 | + res.setHeader('X-YOHO-Version', pkg.version); | ||
87 | + const ck = getCacheKey(req.url, route.cackeKey); | ||
88 | + | ||
89 | + if (config.useCache && route.cache && ck) { | ||
90 | + const html = await redis.getAsync(ck); | ||
52 | 91 | ||
53 | if (html) { | 92 | if (html) { |
93 | + logger.debug(`cached ${req.url}`); | ||
94 | + res.setHeader('X-YOHO-Cached', 'HIT'); | ||
54 | return res.send(html); | 95 | return res.send(html); |
55 | } | 96 | } |
97 | + res.setHeader('X-YOHO-Cached', 'MISS'); | ||
56 | } | 98 | } |
57 | let context = getContext(req); | 99 | let context = getContext(req); |
58 | 100 | ||
59 | renderer.renderToString(context, (err, html) => { | 101 | renderer.renderToString(context, (err, html) => { |
60 | if (err) { | 102 | if (err) { |
61 | - return next(err); | 103 | + parseError(err); |
104 | + return next(err.message); | ||
62 | } | 105 | } |
63 | - if (cache && reqUrl[cacheRule]) { | ||
64 | - microCache.set(reqUrl[cacheRule], html); | 106 | + if (config.useCache && route.cache && ck) { |
107 | + redis.setex(ck, route.cacheTime || 60, html); | ||
65 | } | 108 | } |
66 | return res.send(html); | 109 | return res.send(html); |
67 | }); | 110 | }); |
68 | }; | 111 | }; |
69 | }; | 112 | }; |
70 | -const devRender = () => { | ||
71 | - return (req, res, next) => { | 113 | +const devRender = (route) => { |
114 | + return async(req, res, next) => { | ||
115 | + res.setHeader('X-YOHO-Version', pkg.version); | ||
116 | + const ck = getCacheKey(req.url, route.cackeKey); | ||
117 | + | ||
118 | + if (config.useCache && route.cache && ck) { | ||
119 | + const html = await redis.getAsync(ck); | ||
120 | + | ||
121 | + if (html) { | ||
122 | + logger.debug(`cached ${req.url}`); | ||
123 | + res.setHeader('X-YOHO-Cached', 'HIT'); | ||
124 | + return res.send(html); | ||
125 | + } | ||
126 | + res.setHeader('X-YOHO-Cached', 'MISS'); | ||
127 | + } | ||
72 | let context = getContext(req); | 128 | let context = getContext(req); |
73 | 129 | ||
74 | process.send({action: 'ssr_request', context}); | 130 | process.send({action: 'ssr_request', context}); |
@@ -90,6 +146,9 @@ const devRender = () => { | @@ -90,6 +146,9 @@ const devRender = () => { | ||
90 | }); | 146 | }); |
91 | } | 147 | } |
92 | } | 148 | } |
149 | + if (config.useCache && route.cache && ck) { | ||
150 | + redis.setex(ck, route.cacheTime || 60, msg.html); | ||
151 | + } | ||
93 | return res.end(msg.html); | 152 | return res.end(msg.html); |
94 | } | 153 | } |
95 | }; | 154 | }; |
@@ -2,7 +2,21 @@ const _ = require('lodash'); | @@ -2,7 +2,21 @@ const _ = require('lodash'); | ||
2 | const config = global.yoho.config; | 2 | const config = global.yoho.config; |
3 | 3 | ||
4 | module.exports = (req, res, next) => { | 4 | module.exports = (req, res, next) => { |
5 | - if (!req.user.uid && | 5 | + if (!req.yoho.isApp) { |
6 | + if (req.session && _.isNumber(req.session.LOGIN_UID_)) { | ||
7 | + // 调用接口传参时切勿使用toString获得字符串 | ||
8 | + req.user.uid = { | ||
9 | + toString: () => { | ||
10 | + return _.parseInt(req.session.LOGIN_UID_); | ||
11 | + }, | ||
12 | + sessionKey: req.session.SESSION_KEY, | ||
13 | + appSessionType: req.session.SESSION_TYPE | ||
14 | + }; | ||
15 | + let userData = _.get(req.session, 'USER', {}); | ||
16 | + | ||
17 | + _.merge(req.user, userData); | ||
18 | + } | ||
19 | + } else if (!req.user.uid && | ||
6 | req.cookies.app_uid && | 20 | req.cookies.app_uid && |
7 | req.cookies.app_uid !== '0' && | 21 | req.cookies.app_uid !== '0' && |
8 | req.cookies.app_session_key && | 22 | req.cookies.app_session_key && |
@@ -9,6 +9,7 @@ | @@ -9,6 +9,7 @@ | ||
9 | }, | 9 | }, |
10 | "scripts": { | 10 | "scripts": { |
11 | "start": "NODE_ENV=production node app.js", | 11 | "start": "NODE_ENV=production node app.js", |
12 | + "test": "NODE_ENV=test3 node app.js", | ||
12 | "dev": "node app-dev.js", | 13 | "dev": "node app-dev.js", |
13 | "client": "NODE_ENV=production webpack --config ./build/webpack.client.conf.js", | 14 | "client": "NODE_ENV=production webpack --config ./build/webpack.client.conf.js", |
14 | "server": "NODE_ENV=production webpack --config ./build/webpack.server.conf.js", | 15 | "server": "NODE_ENV=production webpack --config ./build/webpack.server.conf.js", |
@@ -25,24 +26,21 @@ | @@ -25,24 +26,21 @@ | ||
25 | } | 26 | } |
26 | }, | 27 | }, |
27 | "dependencies": { | 28 | "dependencies": { |
29 | + "axios": "^0.18.0", | ||
28 | "body-parser": "^1.18.3", | 30 | "body-parser": "^1.18.3", |
29 | "client-sessions": "^0.8.0", | 31 | "client-sessions": "^0.8.0", |
30 | "connect-multiparty": "^2.2.0", | 32 | "connect-multiparty": "^2.2.0", |
31 | "connect-redis": "^3.4.0", | 33 | "connect-redis": "^3.4.0", |
32 | "cookie-parser": "^1.4.3", | 34 | "cookie-parser": "^1.4.3", |
35 | + "cube-ui": "^1.12.6", | ||
33 | "express": "^4.16.4", | 36 | "express": "^4.16.4", |
34 | "express-session": "^1.15.6", | 37 | "express-session": "^1.15.6", |
38 | + "fastclick": "^1.0.6", | ||
35 | "lodash": "^4.17.11", | 39 | "lodash": "^4.17.11", |
36 | "request-promise": "^4.2.2", | 40 | "request-promise": "^4.2.2", |
37 | "serve-favicon": "^2.5.0", | 41 | "serve-favicon": "^2.5.0", |
42 | + "source-map": "^0.7.3", | ||
38 | "uuid": "^3.3.2", | 43 | "uuid": "^3.3.2", |
39 | - "winston": "^3.1.0", | ||
40 | - "yoho-cookie": "^1.2.0", | ||
41 | - "yoho-express-session": "^2.0.0", | ||
42 | - "yoho-md5": "^2.1.0", | ||
43 | - "yoho-node-lib": "=0.6.41", | ||
44 | - "yoho-qs": "^1.0.1", | ||
45 | - "yoho-store": "^1.3.20", | ||
46 | "vue": "^2.5.20", | 44 | "vue": "^2.5.20", |
47 | "vue-awesome-swiper": "^3.1.3", | 45 | "vue-awesome-swiper": "^3.1.3", |
48 | "vue-infinite-scroll": "^2.0.2", | 46 | "vue-infinite-scroll": "^2.0.2", |
@@ -54,10 +52,14 @@ | @@ -54,10 +52,14 @@ | ||
54 | "vue-template-compiler": "^2.5.20", | 52 | "vue-template-compiler": "^2.5.20", |
55 | "vue-touch": "^1.1.0", | 53 | "vue-touch": "^1.1.0", |
56 | "vue-virtual-scroll-list": "^1.2.8", | 54 | "vue-virtual-scroll-list": "^1.2.8", |
57 | - "cube-ui": "^1.12.6", | ||
58 | - "axios": "^0.18.0", | ||
59 | - "fastclick": "^1.0.6", | ||
60 | - "vuex": "^3.0.1" | 55 | + "vuex": "^3.0.1", |
56 | + "winston": "^3.1.0", | ||
57 | + "yoho-cookie": "^1.2.0", | ||
58 | + "yoho-express-session": "^2.0.0", | ||
59 | + "yoho-md5": "^2.1.0", | ||
60 | + "yoho-node-lib": "=0.6.41", | ||
61 | + "yoho-qs": "^1.0.1", | ||
62 | + "yoho-store": "^1.3.20" | ||
61 | }, | 63 | }, |
62 | "devDependencies": { | 64 | "devDependencies": { |
63 | "@babel/core": "^7.2.0", | 65 | "@babel/core": "^7.2.0", |
utils/beautify/README.MD
deleted
100644 → 0
utils/beautify/filters.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 格式化 后台 返回的 filters 数据 | ||
3 | - * @author chenxuan <xuan.chen@yoho.cn> | ||
4 | - */ | ||
5 | -'use strict'; | ||
6 | - | ||
7 | -const _ = require('lodash'); | ||
8 | - | ||
9 | -/** | ||
10 | - * 处理 以风格的数据 | ||
11 | - * 风格1: | ||
12 | - * [ | ||
13 | - * {filter_attribute: value} | ||
14 | - * ] | ||
15 | - * 风格2: | ||
16 | - * {filter_attribute: value} | ||
17 | - * | ||
18 | - * 处理结果 | ||
19 | - * [ | ||
20 | - * {attribute:value,......} | ||
21 | - * ] | ||
22 | - * | ||
23 | - */ | ||
24 | -let verboseAttrHandler = (filterField, dataArr) => { | ||
25 | - let result = []; | ||
26 | - let re = new RegExp(`^${filterField}_`); | ||
27 | - | ||
28 | - // 处理 {filter_attribute: value} | ||
29 | - function handlerAttrObj(obj) { | ||
30 | - let item = {}; | ||
31 | - let keys = Object.keys(obj); | ||
32 | - | ||
33 | - keys.forEach(key => { | ||
34 | - let newKey = key.replace(re, ''); | ||
35 | - | ||
36 | - item[newKey] = obj[key]; | ||
37 | - }); | ||
38 | - return item; | ||
39 | - } | ||
40 | - | ||
41 | - if (_.isPlainObject(dataArr)) { | ||
42 | - // 风格2 | ||
43 | - let attr = handlerAttrObj(dataArr); | ||
44 | - | ||
45 | - result.push(attr); | ||
46 | - } else { | ||
47 | - // 风格1 | ||
48 | - dataArr.forEach(obj => { | ||
49 | - let attr = handlerAttrObj(obj); | ||
50 | - | ||
51 | - result.push(attr); | ||
52 | - }); | ||
53 | - } | ||
54 | - | ||
55 | - return result; | ||
56 | -}; | ||
57 | - | ||
58 | -/* | ||
59 | - * 处理 以下风格: | ||
60 | - * { | ||
61 | - "340,99999": "¥339以上", | ||
62 | - "0,149": "¥0-149", | ||
63 | - "150,179": "¥150-179", | ||
64 | - "180,339": "¥180-339" | ||
65 | - * }, | ||
66 | - * | ||
67 | - * 处理结果: | ||
68 | - * [ | ||
69 | - * {id: '0,149', value: '0,149', name: '¥0-149'}, | ||
70 | - * {id: '150, 179', value: '150,179', name: '¥150-179'} | ||
71 | - * ..... | ||
72 | - * ] | ||
73 | - * 按照字符串顺序 | ||
74 | - */ | ||
75 | -let keyIdHandler = (filterField, obj) => { | ||
76 | - const result = []; | ||
77 | - const keys = Object.keys(obj); | ||
78 | - | ||
79 | - keys.sort((a, b) => { | ||
80 | - let v1 = Number.parseFloat(a.split(',')[0]); | ||
81 | - let v2 = Number.parseFloat(b.split(',')[0]); | ||
82 | - | ||
83 | - return v1 - v2; | ||
84 | - }); | ||
85 | - | ||
86 | - keys.forEach(key => { | ||
87 | - let item = {}; | ||
88 | - | ||
89 | - item.id = key; | ||
90 | - | ||
91 | - let t = obj[key]; | ||
92 | - let isObject = Object.prototype.toString.apply(t) === '[object Object]'; | ||
93 | - | ||
94 | - if (isObject) { | ||
95 | - item = Object.assign(item, t); | ||
96 | - } else { | ||
97 | - item.name = t; | ||
98 | - } | ||
99 | - | ||
100 | - result.push(item); | ||
101 | - }); | ||
102 | - | ||
103 | - return result; | ||
104 | -}; | ||
105 | - | ||
106 | -function prettyFilter(filters) { | ||
107 | - // Warn!!! | ||
108 | - delete filters.ageLevel; | ||
109 | - | ||
110 | - let keys = _.keys(filters); | ||
111 | - | ||
112 | - _.forEach(keys, key => { | ||
113 | - let process; | ||
114 | - | ||
115 | - // 相同规律的 使用 相同的处理规则 | ||
116 | - switch (key) { | ||
117 | - case 'color': | ||
118 | - case 'size': | ||
119 | - case 'brand': | ||
120 | - case 'style': | ||
121 | - process = verboseAttrHandler; | ||
122 | - break; | ||
123 | - | ||
124 | - case 'gender': | ||
125 | - case 'priceRange': | ||
126 | - case 'discount': | ||
127 | - process = keyIdHandler; | ||
128 | - break; | ||
129 | - | ||
130 | - // 其他不做处理 | ||
131 | - default: | ||
132 | - process = _.noop; | ||
133 | - } | ||
134 | - filters[key] = process(key, filters[key]) || filters[key]; | ||
135 | - }); | ||
136 | -} | ||
137 | - | ||
138 | -module.exports = prettyFilter; | ||
139 | - | ||
140 | - | ||
141 | -/* | ||
142 | -filter Object经过 prettyFilter, camelCase 后的 数据格式: | ||
143 | -{ | ||
144 | - color: [{id,name,value, code}], | ||
145 | - gender: [{id,name}], | ||
146 | - size: [id,name], | ||
147 | - discount: [{id,name,count}], | ||
148 | - priceRange: [{id, name}], | ||
149 | - ageLevel: [{id,name, productCount}] | ||
150 | - brand: [{id, name,domain,alif,ico,keyword,hotKeyword,isHot, nameEn, nameCn}] | ||
151 | - groupSort, | ||
152 | -} | ||
153 | -*/ |
utils/beautify/product.js
deleted
100644 → 0
1 | -'use strict'; | ||
2 | -const path = require('path'); | ||
3 | -const _ = require('lodash'); | ||
4 | -const helpers = global.yoho.helpers; | ||
5 | -const utilsPath = path.join(global.utils, '/constant'); | ||
6 | -const genderMap = require(utilsPath).genderMap; | ||
7 | - | ||
8 | -/** | ||
9 | - * 根据性别来决定 默认图片获取字段 如果是 2、3 | ||
10 | - */ | ||
11 | -const _procProductImg = (product, genderVal) => { | ||
12 | - let defaultImages; | ||
13 | - | ||
14 | - switch (genderVal) { | ||
15 | - case genderMap.men: | ||
16 | - defaultImages = product.cover_1 || product.images_url; | ||
17 | - break; | ||
18 | - case genderMap.women: | ||
19 | - defaultImages = product.cover_2 || product.images_url; | ||
20 | - break; | ||
21 | - default: | ||
22 | - defaultImages = product.images_url || product.cover_1 || product.cover_2; | ||
23 | - break; | ||
24 | - } | ||
25 | - | ||
26 | - defaultImages || (defaultImages = ''); | ||
27 | - | ||
28 | - return defaultImages; | ||
29 | -}; | ||
30 | - | ||
31 | -/** | ||
32 | - * 商品搜索商品数据处理 | ||
33 | - */ | ||
34 | -module.exports = (list, options) => { | ||
35 | - options = options || {}; | ||
36 | - | ||
37 | - const pruductList = []; | ||
38 | - | ||
39 | - if (!options.gender) { | ||
40 | - options.gender = ''; | ||
41 | - } | ||
42 | - | ||
43 | - options = Object.assign({ | ||
44 | - showTags: true, | ||
45 | - showNew: true, | ||
46 | - showSale: true, | ||
47 | - width: 290, | ||
48 | - height: 388, | ||
49 | - isApp: false, | ||
50 | - showPoint: true, | ||
51 | - gender: '', | ||
52 | - yhChannel: '' | ||
53 | - }, options); | ||
54 | - | ||
55 | - if (Array.isArray(options.gender)) { | ||
56 | - options.gender = options.gender[0]; | ||
57 | - } | ||
58 | - | ||
59 | - let genderVal = options.gender.split(','); | ||
60 | - | ||
61 | - if (genderVal.indexOf(genderMap.men) && genderVal.indexOf(genderMap.women)) { // 男女 通吃 | ||
62 | - genderVal = ''; | ||
63 | - } else { | ||
64 | - genderVal = genderVal[0]; | ||
65 | - } | ||
66 | - | ||
67 | - _.forEach(list, (product) => { | ||
68 | - // 商品信息有问题,则不显示 | ||
69 | - if (!product || !product.product_id) { | ||
70 | - return; | ||
71 | - } | ||
72 | - | ||
73 | - // 如果库存为0,显示已抢完 | ||
74 | - if (product.storage_num === 0) { | ||
75 | - product.no_storage = true; | ||
76 | - } | ||
77 | - | ||
78 | - // 市场价和售价一样,则不显示市场价 | ||
79 | - if (product.market_price === product.sales_price) { | ||
80 | - product.market_price = false; | ||
81 | - } | ||
82 | - | ||
83 | - product.is_soon_sold_out = product.is_soon_sold_out === 'Y'; | ||
84 | - product.url = helpers.urlFormat(`/product/pro_${product.product_id}_${_.get(product, 'goods_list[0].goods_id', '')}/${product.cn_alphabet}.html`); // eslint-disable-line | ||
85 | - | ||
86 | - // APP访问需要加附加的参数 | ||
87 | - // 备注:如果以后APP的接口太多,可以把这边参数提取出来,变成一个公共的方法来生成,便于以后管理维护 | ||
88 | - if (options.isApp) { | ||
89 | - product.url += `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":'${product.product_id}'}}`; // eslint-disable-line | ||
90 | - } | ||
91 | - | ||
92 | - if (options.showTags) { | ||
93 | - product.tags = {}; | ||
94 | - | ||
95 | - product.tags.is_new = options.showNew && product.is_new === 'Y'; // 新品 | ||
96 | - product.tags.is_discount = options.showSale && product.is_discount === 'Y'; // 在售 | ||
97 | - product.tags.is_limited = product.is_limited === 'Y'; // 限量 | ||
98 | - product.tags.is_yohood = product.is_yohood === 'Y'; // YOHOOD | ||
99 | - product.tags.mid_year = product.mid_year === 'Y'; // 年中 | ||
100 | - product.tags.year_end = product.year_end === 'Y'; // 年末 | ||
101 | - product.tags.is_advance = product.is_advance === 'Y'; // 再到着 | ||
102 | - | ||
103 | - // 打折与即将售完组合显示打折 | ||
104 | - if (product.isSoonSoldOut && product.tags.is_discount) { | ||
105 | - product.tags.is_new = false; | ||
106 | - } else if (product.tags.is_discount && | ||
107 | - (product.tags.is_new || product.tags.is_limited || product.tags.is_yohood || product.tags.is_advance)) { | ||
108 | - // 打折与其它组合则隐藏打折 | ||
109 | - product.tags.is_discount = false; | ||
110 | - } else if (product.tags.is_yohood && product.tags.is_new) { | ||
111 | - // YOHOOD和新品组合显示YOHOOD | ||
112 | - product.tags.is_new = false; | ||
113 | - } | ||
114 | - } | ||
115 | - | ||
116 | - pruductList.push(product); | ||
117 | - }); | ||
118 | - | ||
119 | - return pruductList; | ||
120 | -}; |
utils/beautify/resources.js
deleted
100644 → 0
1 | -const _ = require('lodash'); | ||
2 | - | ||
3 | -/** | ||
4 | - * 处理楼层数据 | ||
5 | - * @param {[array]} list | ||
6 | - * @return {[array]} | ||
7 | - */ | ||
8 | -module.exports = (list) => { | ||
9 | - const formatData = []; | ||
10 | - | ||
11 | - list = list || []; | ||
12 | - | ||
13 | - _.forEach(list, (floor) => { | ||
14 | - floor[_.camelCase(floor.template_name)] = true; | ||
15 | - | ||
16 | - // 特殊资源位处理 | ||
17 | - | ||
18 | - formatData.push(floor); | ||
19 | - }); | ||
20 | - | ||
21 | - | ||
22 | - return formatData; | ||
23 | -}; |
utils/redis.js
0 → 100644
1 | + | ||
2 | +const _ = require('lodash'); | ||
3 | +const redis = require('redis'); | ||
4 | +const bluebird = require('bluebird'); | ||
5 | +const config = require('../config/common'); | ||
6 | +let client; | ||
7 | +const timeout = 200; // redis 操作超时时间 | ||
8 | + | ||
9 | +try { | ||
10 | + client = redis.createClient(config.redis.connect); | ||
11 | + | ||
12 | + bluebird.promisifyAll(redis.RedisClient.prototype); | ||
13 | + bluebird.promisifyAll(redis.Multi.prototype); | ||
14 | + | ||
15 | + | ||
16 | + client.all = args => { | ||
17 | + if (!client.ready) { | ||
18 | + if (Array.isArray(args)) { | ||
19 | + return Promise.resolve(_.fill(args, false)); | ||
20 | + } else { | ||
21 | + return Promise.resolve(false); | ||
22 | + } | ||
23 | + } | ||
24 | + | ||
25 | + return client.multi.call(client, args).execAsync().timeout(timeout).then(res => { | ||
26 | + return res; | ||
27 | + }).catch(() => { | ||
28 | + return false; | ||
29 | + }); | ||
30 | + }; | ||
31 | + | ||
32 | + client.on('error', function() { | ||
33 | + global.yoho.redis = ''; | ||
34 | + }); | ||
35 | + | ||
36 | + client.on('connect', function() { | ||
37 | + global.yoho.redis = client; | ||
38 | + }); | ||
39 | +} catch (e) { | ||
40 | + global.yoho.redis = ''; | ||
41 | +} | ||
42 | + | ||
43 | + | ||
44 | + | ||
45 | +module.exports = client; |
@@ -7162,6 +7162,10 @@ source-map@^0.6.1, source-map@~0.6.1: | @@ -7162,6 +7162,10 @@ source-map@^0.6.1, source-map@~0.6.1: | ||
7162 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" | 7162 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" |
7163 | integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= | 7163 | integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= |
7164 | 7164 | ||
7165 | +source-map@^0.7.3: | ||
7166 | + version "0.7.3" | ||
7167 | + resolved "http://npm.yohops.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" | ||
7168 | + | ||
7165 | spdx-correct@^3.0.0: | 7169 | spdx-correct@^3.0.0: |
7166 | version "3.1.0" | 7170 | version "3.1.0" |
7167 | resolved "http://npm.yohops.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" | 7171 | resolved "http://npm.yohops.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" |
-
Please register or login to post a comment