index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <template>
  2. <app-layout>
  3. <view class="f-switch" :style="{'background-color': getTheme.background}">
  4. <template v-if="!is_no_now">
  5. <image v-if="is_switch" src="./../image/processing.png"></image>
  6. <image v-else src="./../image/start.png"></image>
  7. <button class="button left" @click="is_switch = true"></button>
  8. <button class="button right" @click="is_switch = false"></button>
  9. </template>
  10. <view v-else style="font-size: 36rpx;text-align: center;color: #fff;line-height:100rpx">
  11. 即将开始
  12. </view>
  13. </view>
  14. <view class="f-bulletin" :style="{'background-color': getTheme.background}" v-if="Object.keys(activity).length">
  15. <view>
  16. <view class="dir-left-nowrap main-between cross-center">
  17. <view class="f-title">
  18. {{activity.title}}
  19. </view>
  20. <view class="f-rule" @click="goRule">
  21. 活动规则
  22. <image src="/static/image/icon/arrow-right.png"></image>
  23. </view>
  24. </view>
  25. <view class="f-timing">
  26. 距离本场{{type === 1 ? '结束' : '开始'}}
  27. <text :style="{'color': getTheme.color}">{{time_str.day}}</text>天
  28. <text :style="{'color': getTheme.color}">{{time_str.hou}}</text>时
  29. <text :style="{'color': getTheme.color}">{{time_str.min}}</text>分
  30. <text :style="{'color': getTheme.color}">{{time_str.sec}}</text>秒
  31. </view>
  32. </view>
  33. </view>
  34. <view class="f-activity" :style="{'background-color': getTheme.background}"v-if="list.length > 0">
  35. <view class="f-item dir-left-nowrap"
  36. @click="routeDetail(item.id)"
  37. v-for="(item, index) in list" :key="index">
  38. <view class="f-image">
  39. <view class="out-dialog" v-if="item.goods_stock == 0 && appSetting.is_show_stock == '1'">
  40. <image :src="appSetting.is_use_stock == '1' ? appImg.plugins_out : appSetting.sell_out_pic"></image>
  41. </view>
  42. <image class='f-pic' :src="item.goodsWarehouse.cover_pic"></image>
  43. </view>
  44. <view class="cont">
  45. <view class="dir-left-nowrap cross-center" style="overflow: hidden">
  46. <view v-if="item.discount_type === 1" :style="{'background-color': getTheme.background}" class="f-discount box-grow-0">{{Number(item.min_discount)}}折</view>
  47. <view v-else :style="{'background-color': getTheme.background}" class="f-discount box-grow-0">减{{item.min_discount}}元</view>
  48. <view class="f-name t-omit">{{item.goodsWarehouse.name}}</view>
  49. </view>
  50. <view class="app-percentage" :style="{'background-color': getTheme.background_l}">
  51. <view :style="{'background-color': getTheme.background,width: `${item.percentage}%`}"></view>
  52. </view>
  53. <view class="f-num main-between">
  54. <text>{{item.sales}}</text>
  55. <text :style="{'color': getTheme.color}">仅剩{{item.goods_stock}}{{item.goodsWarehouse.unit}}</text>
  56. </view>
  57. <view class="f-content dir-top-nowrap main-right">
  58. <view v-if="item.is_level">
  59. <app-member-price :theme="getTheme" :price="item.level_price"></app-member-price>
  60. </view>
  61. <app-sup-vip
  62. :is_vip_card_user="item.vip_card_appoint.is_vip_card_user"
  63. margin="4rpx 0 0"
  64. v-if="item.vip_card_appoint.discount"
  65. :discount="item.vip_card_appoint.discount"
  66. ></app-sup-vip>
  67. <view class="dir-left-nowrap main-between cross-bottom">
  68. <view class="f-price dir-top-nowrap">
  69. <text :style="{'color': getTheme.color}">{{item.price_content}}</text>
  70. <text>¥{{item.original_price}}</text>
  71. </view>
  72. <button
  73. :style="{'background-color': item.goods_stock === 0 && type === 1 ? '#cdcdcd' : item.buy_goods_auth || type !== 1 ? getTheme.background : '#999999'}"
  74. class="f-button"
  75. @click.stop="grab(item)">
  76. {{type === 1 ? '马上抢' : '查看商品'}}
  77. </button>
  78. </view>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. <u-attr
  84. v-if="detail"
  85. :goods="detail"
  86. v-model="attrShow"
  87. :theme="getTheme"
  88. :checked="selectAttr"
  89. :right-func="true"
  90. :left-func="true"
  91. @leftFunc="leftFunc"
  92. @rightFunc="rightFunc"
  93. @check="onAttr"
  94. >
  95. </u-attr>
  96. <view
  97. v-if="!Object.keys(activity).length && loading"
  98. :style="{height: (windowHeight - switch_height) + 'px','background-color': getTheme.background}"
  99. class="f-empty">
  100. <view class="f-empty-con">
  101. <view class="f-no">
  102. <app-no-goods background="#efefef" :title="title"></app-no-goods>
  103. </view>
  104. </view>
  105. </view>
  106. </app-layout>
  107. </template>
  108. <script>
  109. import { mapGetters, mapState } from "vuex";
  110. import appNoGoods from "../../../components/page-component/app-no-goods/app-no-goods.vue";
  111. import uAttr from '../../../components/page-component/goods/u-attr.vue';
  112. export default {
  113. name: "index",
  114. data() {
  115. return {
  116. is_switch: true,
  117. page: 1,
  118. type: 1,
  119. activity: {},
  120. timing: null,
  121. time_str: {
  122. day: '00',
  123. hou: '00',
  124. min: '00',
  125. sec: '00'
  126. },
  127. list: [],
  128. page_count: 1,
  129. detail: null,
  130. attr_groups: [],
  131. attrShow: 0,
  132. selectAttr: {},
  133. switch_height: 0,
  134. title: `暂无进行中活动`,
  135. is_no_now: false,
  136. going: true,
  137. loading: true,
  138. disable: 'disable'
  139. }
  140. },
  141. methods: {
  142. async getList() {
  143. this.loading = false;
  144. const e = await this.$request({
  145. url: this.$api.flash_sale.list,
  146. data: {
  147. type: this.type,
  148. page: this.page
  149. }
  150. });
  151. if (e.code === 0) {
  152. let { activity, list, next_activity, pagination } = e.data;
  153. if (this.type === 1) {
  154. this.activity = activity;
  155. if (Object.keys(activity).length === 0) {
  156. this.is_no_now = true;
  157. this.type = 2;
  158. const w = await this.$request({
  159. url: this.$api.flash_sale.list,
  160. data: {
  161. type: this.type,
  162. page: this.page
  163. }
  164. });
  165. let { list, next_activity, pagination } = w.data;
  166. this.activity = next_activity;
  167. this.list.push(...list);
  168. this.page_count = pagination.page_count;
  169. } else {
  170. this.is_no_now = false;
  171. this.list.push(...list);
  172. this.page_count = pagination.page_count;
  173. }
  174. } else {
  175. this.activity = next_activity;
  176. this.list.push(...list);
  177. this.page_count = pagination.page_count;
  178. }
  179. }
  180. this.loading = true;
  181. },
  182. set_time(time_at) {
  183. clearInterval(this.timing);
  184. let time_str = new Date(time_at.replace(/-/g, '/'));
  185. this.now_time(time_str);
  186. this.timing = setInterval(() => {
  187. this.now_time(time_str);
  188. }, 1000);
  189. },
  190. now_time(time_str) {
  191. let time = time_str.getTime() - new Date().getTime();
  192. if (time < 0) {
  193. clearInterval(this.timing);
  194. }
  195. let day = parseInt(time/1000/60/60/24);
  196. let hou = parseInt((time/1000/60/60)%24);
  197. let min = parseInt((time/1000/60)%60);
  198. let sec = parseInt((time/1000)%60);
  199. this.time_str.day = day < 10 ? '0' + day : day;
  200. this.time_str.hou = hou < 10 ? '0' + hou : hou;
  201. this.time_str.min = min < 10 ? '0' + min : min;
  202. this.time_str.sec = sec < 10 ? '0' + sec : sec;
  203. },
  204. grab(item) {
  205. if (this.type === 1) {
  206. this.detail = null;
  207. if (item.goods_stock !== 0) {
  208. if (!item.buy_goods_auth) {
  209. this.$tips.showToast({
  210. title: '该商品您暂无权限购买',
  211. icon: 'none'
  212. });
  213. return ;
  214. }
  215. setTimeout(() => {
  216. this.selectAttr = {};
  217. this.detail = item;
  218. this.attrShow = true;
  219. })
  220. }
  221. } else {
  222. uni.navigateTo({
  223. url: `/plugins/flash_sale/goods/goods?id=${item.id}`
  224. })
  225. }
  226. },
  227. onAttr({item}) {
  228. this.selectAttr = item;
  229. },
  230. routeDetail(id) {
  231. uni.navigateTo({
  232. url: `/plugins/flash_sale/goods/goods?id=${id}`
  233. })
  234. },
  235. goRule() {
  236. uni.navigateTo({
  237. url: `/pages/rules/index?url=${encodeURIComponent(this.$api.flash_sale.list)}&key=content`
  238. });
  239. },
  240. rightFunc(data) {
  241. uni.navigateTo({
  242. url: `/pages/order-submit/order-submit?mch_list=${JSON.stringify([data])}`
  243. });
  244. },
  245. leftFunc(number) {
  246. this.$request({
  247. url: this.$api.flash_sale.add_cart,
  248. data: {
  249. flash_goods_id: this.selectAttr.goods_id,
  250. attr_id: this.selectAttr.id,
  251. num: number
  252. },
  253. method: 'post'
  254. }).then(e => {
  255. uni.showToast({
  256. title: e.msg,
  257. type: 'success'
  258. });
  259. });
  260. }
  261. },
  262. mounted() {
  263. let query = wx.createSelectorQuery();
  264. this.$nextTick().then(() => {
  265. query.select('.f-switch').boundingClientRect(rect=>{
  266. this.switch_height = rect.height;
  267. }).exec();
  268. });
  269. // #ifdef MP-WEIXIN
  270. wx.showShareMenu({
  271. menus: ['shareAppMessage', 'shareTimeline']
  272. })
  273. // #endif
  274. },
  275. onReachBottom() {
  276. if (this.page < this.page_count) {
  277. this.page++;
  278. this.getList();
  279. }
  280. },
  281. watch: {
  282. is_switch: {
  283. handler(boolean) {
  284. if (this.going) {
  285. this.going = false;
  286. this.list = [];
  287. this.page = 1;
  288. if (boolean) {
  289. this.type = 1;
  290. this.title = '暂无进行中活动';
  291. } else {
  292. this.type = 2;
  293. this.title = '暂无下一场活动';
  294. }
  295. this.getList().then(() => {
  296. if (this.type === 1) {
  297. let end_at = this.activity.end_at;
  298. end_at ? this.set_time(end_at) : null;
  299. } else {
  300. let start_at = this.activity.start_at;
  301. start_at ? this.set_time(start_at) : null;
  302. }
  303. this.going = true;
  304. });
  305. }
  306. },
  307. immediate: true
  308. }
  309. },
  310. computed: {
  311. ...mapGetters('mallConfig', {
  312. getTheme: 'getTheme'
  313. }),
  314. ...mapState('gConfig', {
  315. windowHeight: state => state.systemInfo.windowHeight
  316. }),
  317. ...mapState({
  318. appImg: state => state.mallConfig.__wxapp_img.mall,
  319. appSetting: state => state.mallConfig.mall.setting,
  320. })
  321. },
  322. components: {
  323. 'app-no-goods': appNoGoods,
  324. uAttr
  325. },
  326. // #ifdef MP
  327. onShareAppMessage() {
  328. return this.$shareAppMessage({
  329. path: '/plugins/flash_sale/index/index',
  330. title: this.$children[0].navigationBarTitle
  331. });
  332. },
  333. // #endif
  334. // #ifdef MP-WEIXIN
  335. onShareTimeline() {
  336. // 分享朋友圈beta
  337. return this.$shareTimeline({
  338. title:this.$children[0].navigationBarTitle
  339. });
  340. },
  341. // #endif
  342. }
  343. </script>
  344. <style scoped lang="scss">
  345. .f-switch {
  346. width: 750upx;
  347. height: 100upx;
  348. position: relative;
  349. }
  350. .f-switch image {
  351. width: 750upx;
  352. height: 100upx;
  353. position: absolute;
  354. top: -1upx;
  355. }
  356. .f-switch .button {
  357. width: 375upx;
  358. height: 100upx;
  359. position: absolute;
  360. background: transparent;
  361. padding: 0;
  362. margin: 0;
  363. border: none;
  364. }
  365. .f-switch .right {
  366. right: 0;
  367. }
  368. .f-switch .left {
  369. left: 0;
  370. }
  371. .f-bulletin {
  372. padding: 20upx 24upx;
  373. .f-title {
  374. font-size: 32upx;
  375. font-weight: bold;
  376. color: #353535;
  377. }
  378. .f-rule {
  379. font-size: 26upx;
  380. color: #666;
  381. vertical-align: middle;
  382. >image {
  383. width: 12upx;
  384. height: 22upx;
  385. margin-left: 14upx;
  386. }
  387. }
  388. .f-timing {
  389. margin-top: 18upx;
  390. font-size: 26upx;
  391. color: #353535;
  392. >text:first-child {
  393. margin-left: 18upx;
  394. }
  395. }
  396. }
  397. .f-bulletin>view {
  398. background-color: #fff;
  399. border-radius: 15upx;
  400. height: 147upx;
  401. padding: 32upx 24upx;
  402. }
  403. .f-activity {
  404. padding: 0 24upx;
  405. overflow: auto;
  406. position: absolute;
  407. width: 750upx;
  408. min-height: calc(100vh - 287rpx);
  409. .f-item {
  410. background-color: #fff;
  411. border-radius: 15upx;
  412. padding: 24upx;
  413. margin-bottom: 20upx;
  414. .f-pic {
  415. width: 240upx;
  416. height: 240upx;
  417. border-radius: 8upx;
  418. }
  419. >view.cont {
  420. width: 394upx;
  421. margin-left: 24upx;
  422. position: relative;
  423. }
  424. .f-name {
  425. font-size: 28upx;
  426. color: #353535;
  427. min-width: 304upx;
  428. }
  429. .f-discount {
  430. height: 26upx;
  431. color: #fff;
  432. font-size: 20upx;
  433. margin-right: 10upx;
  434. text-align: center;
  435. line-height: 26upx;
  436. border-radius: 7upx;
  437. padding: 0 5upx;
  438. }
  439. .f-num {
  440. font-size: 24upx;
  441. margin-top: 10upx;
  442. }
  443. .f-num>text:first-child {
  444. color: #666;
  445. }
  446. .f-button {
  447. height: 68upx;
  448. line-height: 68upx;
  449. width: 164upx;
  450. border-radius: 34upx;
  451. font-size: 26upx;
  452. color: #fff;
  453. margin: 0;
  454. padding: 0;
  455. text-align: center;
  456. border: none;
  457. }
  458. .f-content {
  459. position: absolute;
  460. bottom: 0;
  461. width: 394upx;
  462. }
  463. .f-price>text:first-child {
  464. font-size: 32upx;
  465. }
  466. .f-price>text:last-child {
  467. font-size: 25upx;
  468. color: #999;
  469. text-decoration: line-through;
  470. }
  471. .app-percentage {
  472. width: #{395rpx};
  473. height: #{20rpx};
  474. border-radius: #{12rpx};
  475. margin-top: #{10rpx};
  476. overflow: hidden;
  477. >view {
  478. height: #{20rpx};
  479. border-radius: #{12rpx};
  480. }
  481. }
  482. .f-sold-out {
  483. background-color: #cdcdcd;
  484. }
  485. }
  486. }
  487. .f-empty {
  488. width: 750upx;
  489. padding: 20upx 24upx;
  490. .f-empty-con {
  491. height: 100%;
  492. background: #efefef;
  493. border-radius: 15upx;
  494. position: relative;
  495. }
  496. .f-no {
  497. position: absolute;
  498. top: 30%;
  499. left: 50%;
  500. transform: translate(-50%, -50%);
  501. }
  502. }
  503. .out-dialog {
  504. border-top-left-radius: 15upx;
  505. border-top-right-radius: 15upx;
  506. width: 240upx;
  507. height: 240upx;
  508. position: absolute;
  509. top: 0;
  510. z-index: 10;
  511. left: 0;
  512. background-color: rgba(0,0,0,.5);
  513. image {
  514. width: 240upx;
  515. height: 240upx;
  516. }
  517. }
  518. .f-image {
  519. position: relative;
  520. }
  521. </style>