advance.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <template>
  2. <app-layout>
  3. <view class="ms">
  4. <template v-if="(time_list.length > 0 || is_estimate === 1 ) && loading">
  5. <view class="time-list" >
  6. <scroll-view
  7. class="scroll "
  8. :scroll-x="true"
  9. scroll-with-animation
  10. :scroll-into-view="`${scroll_id}`"
  11. >
  12. <view class="content">
  13. <view
  14. class="item"
  15. :id="`ms_${i}`"
  16. v-for="(t, i) in time_list"
  17. :key="i"
  18. :style="{'background-color': active_index === i ? getTheme.background : ''}"
  19. :class="active_index === i ? 'active-item' : 'no-active-item'"
  20. @click="activeTime({open_time: t.open_time, type: 1, date_time: t.date_time}, i)"
  21. >
  22. <view class="open-time">{{t.new_open_time}}</view>
  23. <view class="label">{{t.label}}</view>
  24. <view class="icon" :style="{'color': getTheme.color}"></view>
  25. </view>
  26. <view
  27. class="item teaser"
  28. :style="{'background-color': active_index === time_list.length ? getTheme.background : ''}"
  29. :class="active_index === time_list.length ? 'active-item' : 'no-active-item'"
  30. :id="`ms_${time_list.length}`"
  31. v-if="is_estimate === 1"
  32. @click="activeTime({open_time: 0, type: 2}, time_list.length)"
  33. >
  34. 预告
  35. <view class="icon" :style="{'color': getTheme.color}"></view>
  36. </view>
  37. </view>
  38. </scroll-view>
  39. <view class="time dir-left-nowrap main-between" v-if="!is_booking">
  40. <view class="left"></view>
  41. <view class="text">限时限量 先到先得</view>
  42. <view class="timing">
  43. <text v-if="time_list[active_index] && time_list[active_index].status === 1">距离本场结束</text>
  44. <text v-if="time_list[active_index] && time_list[active_index].status === 2">本场秒杀已结束</text>
  45. <text v-if="time_list[active_index] && time_list[active_index].status === 0">距离本场开始</text>
  46. <text class="time-html" v-if="time_list[active_index] && (time_list[active_index].status === 1 || time_list[active_index].status === 0)">{{html}}</text>
  47. </view>
  48. </view>
  49. <view class="empty-goods dir-left-nowrap main-center cross-center" v-if="is_booking">
  50. <image src="/static/image/icon/empty.png"></image>
  51. <view>
  52. <view style="color: #353535;">今日已无更多场次</view>
  53. <view style="color: #999999;">
  54. 下场将于
  55. <text style="color: #ff4544;">{{next_time}}</text>
  56. 开始
  57. </view>
  58. </view>
  59. </view>
  60. </view>
  61. <scroll-view :class="is_booking ? 'is_book_list' : 'goods-list'" :scroll-y="true" @scrolltolower="scrollLower">
  62. <product-list
  63. :empty="nav_bool"
  64. :botHeight="BotHeight"
  65. :list="goods_list"
  66. :theme="getTheme"
  67. :status="time_list[active_index] && time_list[active_index].status"
  68. ></product-list>
  69. </scroll-view>
  70. </template>
  71. <template v-else-if="time_list.length === 0 && is_estimate !== 1 && loading">
  72. <view>
  73. <view class="empty dir-top-nowrap cross-center" >
  74. <image src="../image/empty.png"></image>
  75. <text>暂无秒杀商品</text>
  76. <button :style="{'background-color': getTheme.background}" @click="router_go">返回首页</button>
  77. </view>
  78. </view>
  79. </template>
  80. </view>
  81. </app-layout>
  82. </template>
  83. <script>
  84. import { mapState, mapGetters } from 'vuex';
  85. import appProductList from '../components/app-product-list.vue';
  86. export default {
  87. name: 'advance',
  88. data() {
  89. return {
  90. time_list: [],
  91. goods_list: [],
  92. next_time: '',
  93. page: 1,
  94. active_index: null,
  95. scroll_id: '',
  96. is_estimate: 0,
  97. open_time: 0,
  98. type: 0,
  99. page_count: 1,
  100. nav_bool: false,
  101. // #ifdef MP
  102. currentRoute: this.$platDiff.route(),
  103. // #endif
  104. time: -1,
  105. html: '',
  106. is_booking: false,
  107. loading: false
  108. }
  109. },
  110. computed: {
  111. ...mapState({
  112. tabBarNavs: state => state.mallConfig.navbar.navs,
  113. }),
  114. ...mapGetters('iPhoneX', {
  115. BotHeight: 'getBotHeight',
  116. }),
  117. ...mapGetters('mallConfig', {
  118. getTheme: 'getTheme',
  119. }),
  120. },
  121. onLoad() { this.$commonLoad.onload();
  122. this.getTimeList().then(() => {
  123. let active_status = false;
  124. this.time_list.map((item, index) => {
  125. if (item.status === 1) {
  126. active_status = true;
  127. this.active_index = index;
  128. this.scroll_id = `ms_${index}`;
  129. item.type = 1;
  130. this.getGoodsList(item);
  131. }
  132. });
  133. this.$nextTick(() => {
  134. this.loading = true;
  135. });
  136. if (active_status === false) {
  137. this.active_index = 0;
  138. if (this.time_list.length > 0) {
  139. this.type = 1;
  140. this.open_time = this.time_list[0].open_time;
  141. this.getGoodsList({
  142. open_time: this.open_time,
  143. type: this.type
  144. });
  145. } else {
  146. if (this.is_estimate === 1) {
  147. this.type = 2;
  148. this.open_time = 0;
  149. this.is_booking = true;
  150. this.getGoodsList({
  151. open_time: this.open_time,
  152. type: this.type,
  153. });
  154. }
  155. }
  156. }
  157. });
  158. // #ifdef MP-WEIXIN
  159. wx.showShareMenu({
  160. menus: ['shareAppMessage', 'shareTimeline']
  161. })
  162. // #endif
  163. },
  164. onShow() {
  165. if (this.type === 1) {
  166. this.set_time(this.time_list[this.active_index].date_time);
  167. }
  168. },
  169. onHide() {
  170. clearInterval(this.time);
  171. },
  172. onUnload() {
  173. clearInterval(this.time);
  174. },
  175. methods: {
  176. async getTimeList() {
  177. uni.showLoading({
  178. title:'加载中...'
  179. });
  180. try {
  181. const res = await this.$request({
  182. url: this.$api.miaosha.time_list,
  183. method: 'get'
  184. });
  185. if (res.code === 0) {
  186. let {is_estimate, list, next_miaosha_date_time} = res.data;
  187. this.time_list = list;
  188. this.is_estimate = is_estimate;
  189. this.next_time = next_miaosha_date_time;
  190. }
  191. } catch (e) {
  192. throw new Error(e);
  193. }
  194. uni.hideLoading();
  195. },
  196. async getGoodsList(item) {
  197. try {
  198. this.open_time = item.open_time;
  199. this.type = item.type;
  200. if (this.type === 1) {
  201. this.set_time(item.date_time);
  202. } else {
  203. clearInterval(this.time);
  204. }
  205. const res = await this.$request({
  206. url: this.$api.miaosha.goods,
  207. data: {
  208. open_time: item.open_time,
  209. type: item.type,
  210. page: this.page ? this.page : 1,
  211. }
  212. });
  213. if (res.code === 0) {
  214. this.goods_list = res.data.list;
  215. this.page_count = res.data.pagination.page_count;
  216. }
  217. } catch(e) {
  218. throw new Error(e);
  219. }
  220. },
  221. activeTime(item, index) {
  222. this.active_index = index;
  223. this.scroll_id = `ms_${index}`;
  224. this.page = 1;
  225. this.getGoodsList(item);
  226. this.getTimeList();
  227. if (item.type === 2) {
  228. this.is_booking = true;
  229. } else {
  230. this.is_booking = false;
  231. }
  232. },
  233. async scrollLower() {
  234. try {
  235. if (this.page >= this.page_count) return;
  236. this.page++;
  237. const res = await this.$request({
  238. url: this.$api.miaosha.goods,
  239. data: {
  240. open_time: this.open_time,
  241. type: this.type,
  242. page: this.page,
  243. }
  244. });
  245. if (res.code === 0) {
  246. this.goods_list = [...this.goods_list, ...res.data.list];
  247. }
  248. } catch(e) {
  249. throw new Error(e);
  250. }
  251. },
  252. set_nav() {
  253. let currentRoute = null;
  254. // #ifdef MP
  255. currentRoute = this.currentRoute;
  256. // #endif
  257. // #ifdef H5
  258. currentRoute = this.$route.fullPath;
  259. // #endif
  260. for (let i = 0; i < this.tabBarNavs.length; i++) {
  261. if(currentRoute.includes(this.tabBarNavs[i].url.split('?')[0])) {
  262. return this.nav_bool = true;
  263. }
  264. }
  265. return this.nav_bool = false;
  266. },
  267. set_time(data) {
  268. clearInterval(this.time);
  269. if (!data) return;
  270. let time_str = new Date(data.replace(/-/g, '/'));
  271. let time = time_str.getTime() - new Date().getTime();
  272. let day = parseInt((time/1000/60/60/24)%30);
  273. let hou = parseInt((time/1000/60/60)%24);
  274. let min = parseInt((time/1000/60)%60);
  275. let sec = parseInt((time/1000)%60);
  276. if (day > 0) {
  277. this.html = day+"天"+hou+":"+(min<10?"0"+min:min) + ":"+(sec<10?"0"+sec:sec);
  278. } else {
  279. this.html = hou+":"+(min<10?"0"+min:min) + ":"+(sec<10?"0"+sec:sec);
  280. }
  281. this.time = setInterval(() =>{
  282. let time = time_str.getTime() - new Date().getTime();
  283. if (time < 0) {
  284. clearInterval(this.time);
  285. this.time_list[this.active_index].status = 2;
  286. }
  287. let day = parseInt((time/1000/60/60/24)%30);
  288. let hou = parseInt((time/1000/60/60)%24);
  289. let min = parseInt((time/1000/60)%60);
  290. let sec = parseInt((time/1000)%60);
  291. if (day > 0) {
  292. this.html = day+"天"+hou+":"+(min<10?"0"+min:min) + ":"+(sec<10?"0"+sec:sec);
  293. } else {
  294. this.html = hou+":"+(min<10?"0"+min:min) + ":"+(sec<10?"0"+sec:sec);
  295. }
  296. },1000);
  297. },
  298. router_go() {
  299. uni.reLaunch({
  300. url: '/pages/index/index'
  301. });
  302. }
  303. },
  304. // #ifdef MP-WEIXIN
  305. onShareAppMessage() {
  306. return this.$shareAppMessage({
  307. path: '/plugins/miaosha/advance/advance',
  308. title: this.$children[0].navigationBarTitle,
  309. });
  310. },
  311. onShareTimeline() {
  312. // 分享朋友圈beta
  313. return this.$shareTimeline({
  314. title: this.$children[0].navigationBarTitle,
  315. query: {
  316. } // 此处填写页面的参数
  317. });
  318. },
  319. // #endif
  320. components: {
  321. 'product-list': appProductList,
  322. },
  323. watch: {
  324. tabBarNavs: {
  325. handler: function() {
  326. this.set_nav();
  327. },
  328. immediate: true,
  329. }
  330. }
  331. }
  332. </script>
  333. <style scoped lang="scss">
  334. .ms {
  335. height: 100vh;
  336. width: 100%;
  337. background: white;
  338. }
  339. .time-list {
  340. width: #{750upx};
  341. height: #{176upx};
  342. position: fixed;
  343. top: 0;
  344. left: 0;
  345. }
  346. .goods-list {
  347. margin-top: #{176upx};
  348. width: #{750upx};
  349. height: calc(100% - #{176upx});
  350. }
  351. .is_book_list {
  352. margin-top: #{350upx};
  353. width: #{750upx};
  354. height: calc(100% - #{350upx});
  355. }
  356. .scroll {
  357. width: #{750upx};
  358. height: #{111upx};
  359. position: relative;
  360. z-index: 1500;
  361. background: #ffffff;
  362. .content {
  363. white-space: nowrap;
  364. /*z-index: 1500;*/
  365. height: #{96upx};
  366. background-color: #30353c;
  367. }
  368. .item {
  369. display: inline-block;
  370. width: #{150upx};
  371. height: #{96upx};
  372. position: relative;
  373. vertical-align:top;
  374. color: #bbbbbb;
  375. > view {
  376. text-align: center;
  377. line-height: 1;
  378. }
  379. }
  380. .teaser {
  381. line-height: #{96upx};
  382. text-align: center;
  383. }
  384. .open-time {
  385. margin-top: #{20upx};
  386. font-size: #{32upx};
  387. }
  388. .label {
  389. margin-top: #{5upx};
  390. font-size: #{22upx};
  391. }
  392. .no-active-item {
  393. background-color: #30353c;
  394. }
  395. .active-item {
  396. color: #ffffff;
  397. .icon {
  398. border: #{20rpx} solid;
  399. border-bottom-color: transparent;
  400. border-left-color: transparent;
  401. border-right-color: transparent;
  402. position: absolute;
  403. bottom: #{-36rpx};
  404. left: 50%;
  405. transform: translateX(-50%);
  406. }
  407. }
  408. }
  409. .time {
  410. background-color: #ffffff;
  411. height: #{80upx};
  412. line-height: #{80rpx};
  413. position: relative;
  414. top: #{-18upx};
  415. .left {
  416. width: #{6upx};
  417. height: 100%;
  418. background-color: #ff4544;
  419. position: absolute;
  420. top: 0;
  421. z-index: 1600;
  422. }
  423. .text {
  424. margin-left: #{20rpx};
  425. font-size: #{28rpx};
  426. color: #ff4544;
  427. }
  428. .timing {
  429. font-size: #{28rpx};
  430. margin-right: #{24rpx};
  431. color: #999999;
  432. }
  433. .time-html {
  434. margin-left: #{12rpx};
  435. color: #353535;
  436. }
  437. }
  438. .empty {
  439. background-color: #ffffff;
  440. width: 100%;
  441. font-size: #{26upx};
  442. >image {
  443. width: #{350upx};
  444. height: #{350upx};
  445. margin-top: #{150upx};
  446. }
  447. >text {
  448. font-size: #{32upx};
  449. color: #353535;
  450. line-height: 1;
  451. margin-top: #{80upx};
  452. }
  453. >button {
  454. padding: 0;
  455. border: 0;
  456. border-radius: #{34upx};
  457. height: #{68upx};
  458. font-size: #{26upx};
  459. text-align: center;
  460. color: #ffffff;
  461. line-height: #{68upx};
  462. width: #{240upx};
  463. margin-top: #{96upx};
  464. }
  465. }
  466. .empty-goods {
  467. margin-top: 45upx;
  468. >image {
  469. width: #{150upx};
  470. height: #{150upx};
  471. }
  472. }
  473. </style>