1
0

index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <template>
  2. <app-layout :overflow="false">
  3. <template v-if="hasActivity && activityLoading">
  4. <view class="search dir-left-nowrap main-between cross-center">
  5. <view class="input dir-left-nowrap main-center cross-center" @click="search">
  6. <view class="search-icon"></view>
  7. <view class="text">搜索</view>
  8. </view>
  9. <view class="icon" @click="setSwitch">
  10. <image class="icon-img" :src="style_switch ? '../image/list-2.png' : '../image/list-1.png' "></image>
  11. </view>
  12. </view>
  13. <view class="rule" id="rule" :class="[getTheme + '-m-gradient-l ' + getTheme, is_fixed ? 'rule-fixed' : 'rule-no-fixed']">
  14. <view class="rule-top dir-left-nowrap main-between cross-top">
  15. <view class="icon"></view>
  16. <view class="text">
  17. <template v-if="rule_type === 1">
  18. <block v-for="(item, index) in rule"
  19. :key="index">
  20. 满{{item.min_money}}{{item.discount_type === '1' ? '减' + item.cut : '打' + item.discount + '折'}}{{index !== rule.length - 1 ? ', ' : ''}}
  21. </block>
  22. </template>
  23. <template v-else-if="rule_type === 2">
  24. 每满{{rule.min_money}}减{{rule.cut}}
  25. </template>
  26. </view>
  27. </view>
  28. <view class="dir-left-nowrap main-between">
  29. <view class="time dir-left-nowrap cross-center">
  30. <view class="time-icon"></view>
  31. <view class="time-text">距离活动结束仅剩:{{time_str.day}}天{{time_str.hou}}时{{time_str.min}}分</view>
  32. </view>
  33. <view class="rule-text" @click="route">活动规则</view>
  34. </view>
  35. </view>
  36. <scroll-view scroll-x id="cats" class="cats dir-left-nowrap">
  37. <view class="cats-item"
  38. :class="item.active === true ? 'cats-item-active ' + getTheme + '-m-back ' + getTheme : 'cats-item-no'"
  39. v-for="(item, index) in cats"
  40. @click="active(item)"
  41. :key="index">
  42. {{item.name}}
  43. </view>
  44. </scroll-view>
  45. <view>
  46. <template v-if="style_switch">
  47. <u-water-fall v-model="flowList" ref="waterFall" :theme-object="themeObject" :theme="getTheme">
  48. </u-water-fall>
  49. </template>
  50. <template v-else>
  51. <view class="goods-item dir-left-nowrap " v-for="(item ,index) in flowList" @click="routeGood(item)" :key="index">
  52. <image class="goods-pic" :src="item.cover_pic"></image>
  53. <view class="goods-cont dir-top-nowrap main-between">
  54. <view>
  55. <view class="goods-name t-omit-two"> {{item.name}}</view>
  56. <view class="goods-vip" v-if="item.is_level == 1 && item.is_negotiable != 1">
  57. <app-member-price
  58. :price="item.level_price"
  59. :theme="themeObject"
  60. ></app-member-price>
  61. </view>
  62. <view class="goods-vip" v-if="item.vip_card_appoint.discount">
  63. <app-sup-vip
  64. :discount="item.vip_card_appoint.discount"
  65. :is_vip_card_user="item.vip_card_appoint.is_vip_card_user"
  66. ></app-sup-vip>
  67. </view>
  68. </view>
  69. <view class="dir-left-nowrap main-between">
  70. <view>
  71. <view :class="getTheme + '-m-text price ' + getTheme">{{item.price_content}}</view>
  72. <view class="sales">{{item.sales}}</view>
  73. </view>
  74. <view
  75. v-if="item.goods_stock !== 0"
  76. @click.stop="buyProduct(item)"
  77. :class="'app-button-icon-cart box-grow-0 app-button-icon ' + getTheme + '-m-back ' + getTheme"
  78. ></view>
  79. </view>
  80. </view>
  81. </view>
  82. </template>
  83. <view class="u-loading-list" v-if="bottomLoading">加载中...</view>
  84. </view>
  85. <view class="no-empty main-center" v-if="!loading && flowList.length === 0">
  86. <app-no-goods title="该分类下无相关内容哦~" background="#f7f7f7"></app-no-goods>
  87. </view>
  88. </template>
  89. <template v-else-if="!hasActivity && activityLoading">
  90. <view class="no-empty main-center" >
  91. <app-no-goods title="暂无满减商品" background="#f7f7f7"></app-no-goods>
  92. </view>
  93. </template>
  94. <app-attr :goods="goods" :attrGroupList="goods.attr_groups" :theme="getTheme" :show="attrShow"></app-attr>
  95. </app-layout>
  96. </template>
  97. <script>
  98. import { mapGetters, mapState } from 'vuex';
  99. import uWaterFall from '../u-waterfall.vue';
  100. import appSupVip from '../../../components/page-component/app-sup-vip/app-sup-vip.vue';
  101. import appMemberPrice from '../../../components/page-component/app-member-mark/app-member-price.vue';
  102. import appDiyGoodsList from "../../../components/page-component/app-diy-goods-list/app-diy-goods-list.vue";
  103. import appNoGoods from "../../../components/page-component/app-no-goods/app-no-goods.vue";
  104. import appAttr from '../../../components/page-component/app-attr/app-attr.vue';
  105. export default {
  106. name: "index",
  107. data() {
  108. return {
  109. flowList: [],
  110. page: 1,
  111. page_count: 1,
  112. rule_type: 1,
  113. rule: null,
  114. cats: [],
  115. cat_id: null,
  116. time_str: {
  117. day: '00',
  118. hou: '00',
  119. min: '00'
  120. },
  121. timing: null,
  122. is_fixed: false,
  123. style_switch: false,
  124. loading: false,
  125. hasActivity: true,
  126. activityLoading: false,
  127. is_no_scroll: true,
  128. goods: {},
  129. attrShow: 0,
  130. no_active: false,
  131. bottomLoading: false
  132. }
  133. },
  134. computed: {
  135. ...mapGetters('mallConfig', {
  136. getTheme: 'getTheme'
  137. }),
  138. ...mapState('gConfig', {
  139. windowWidth: state => state.systemInfo.windowWidth
  140. }),
  141. themeObject:function() {
  142. return {
  143. back: this.getTheme + '-m-back ' + this.getTheme,
  144. theme: this.getTheme,
  145. color: this.getTheme + '-m-text ' + this.getTheme,
  146. sBack: this.getTheme + '-s-back ' + this.getTheme
  147. }
  148. }
  149. },
  150. methods: {
  151. async getListData(status) {
  152. this.loading = true;
  153. const e = await this.$request({
  154. url: this.$api.full_reduce.list,
  155. data: {
  156. page: this.page,
  157. cat_id: this.cat_id
  158. }
  159. });
  160. this.loading = false;
  161. if (e.code === 0) {
  162. this.no_active = false;
  163. let list = e.data.list;
  164. if (status === true) {
  165. this.flowList.push(...list);
  166. } else {
  167. this.flowList = list;
  168. }
  169. this.page_count = e.data.pagination.page_count;
  170. let page = this.page;
  171. if (page++ === this.page_count) {
  172. this.bottomLoading = false;
  173. }
  174. }
  175. },
  176. async getIndex() {
  177. const e = await this.$request({
  178. url: this.$api.full_reduce.index
  179. });
  180. this.activityLoading = true;
  181. if (e.code === 0) {
  182. if (this.$validation.empty(e.data)) {
  183. this.hasActivity = false;
  184. } else {
  185. this.rule = e.data.rule;
  186. this.rule_type = e.data.rule_type;
  187. if (this.$validation.date(e.data.time)) {
  188. this.getTiming(e.data.time);
  189. }
  190. }
  191. }
  192. },
  193. async getCats() {
  194. const e = await this.$request({
  195. url: this.$api.default.cat_list
  196. });
  197. if (e.code === 0) {
  198. this.cats = e.data.list;
  199. this.cat_id = this.cats[0].id;
  200. }
  201. },
  202. active(item) {
  203. this.bottomLoading = false;
  204. if (!this.no_active) {
  205. this.no_active = true;
  206. this.cats.forEach((item) => {
  207. item.active = false;
  208. });
  209. item.active = true;
  210. this.page = 1;
  211. this.cat_id = item.id;
  212. this.flowList = [];
  213. if (this.style_switch) {
  214. this.$refs.waterFall.emptyList();
  215. }
  216. uni.pageScrollTo({
  217. scrollTop: 0,
  218. duration: 500
  219. });
  220. this.getListData();
  221. }
  222. },
  223. getTiming(data) {
  224. clearInterval(this.timing);
  225. let time_str = new Date(data.replace(/-/g, '/'));
  226. this.now_time(time_str);
  227. this.timing = setInterval(() => {
  228. this.now_time(time_str);
  229. }, 1000);
  230. },
  231. now_time(time_str) {
  232. let time = time_str.getTime() - new Date().getTime();
  233. if (time < 0) {
  234. clearInterval(this.timing);
  235. }
  236. let day = parseInt(time/1000/60/60/24);
  237. let hou = parseInt((time/1000/60/60)%24);
  238. let min = parseInt((time/1000/60)%60);
  239. this.time_str.day = day < 10 ? '0' + day : day;
  240. this.time_str.hou = hou < 10 ? '0' + hou : hou;
  241. this.time_str.min = min < 10 ? '0' + min : min;
  242. },
  243. route() {
  244. uni.navigateTo({
  245. url: `/pages/rules/index?url=${encodeURIComponent(this.$api.full_reduce.index)}&key=content`
  246. });
  247. },
  248. routeGood(item) {
  249. uni.navigateTo({
  250. url: item.page_url
  251. });
  252. },
  253. search() {
  254. uni.navigateTo({
  255. url: `/pages/full_reduce/search/search`
  256. })
  257. },
  258. setSwitch() {
  259. this.style_switch = !this.style_switch;
  260. },
  261. buyProduct(item) {
  262. this.goods = item;
  263. this.attrShow = Math.random();
  264. },
  265. },
  266. onReachBottom() {
  267. if (this.page < this.page_count) {
  268. this.page++;
  269. this.bottomLoading = true;
  270. this.getListData(true);
  271. }
  272. },
  273. mounted() {
  274. this.getIndex().then(() => {
  275. this.getCats().then(() => {
  276. this.getListData();
  277. });
  278. });
  279. },
  280. components: {
  281. uWaterFall,
  282. appDiyGoodsList,
  283. appNoGoods,
  284. appSupVip,
  285. appMemberPrice,
  286. appAttr
  287. },
  288. onHide() {
  289. clearInterval(this.timing);
  290. },
  291. onUnload() {
  292. clearInterval(this.timing);
  293. },
  294. }
  295. </script>
  296. <style scoped lang="scss">
  297. .search {
  298. height: 88upx;
  299. width: 750upx;
  300. border-bottom: 1upx solid #d6d6db;
  301. position: fixed;
  302. top: 0;
  303. background-color: #efeff4;
  304. z-index: 1000;
  305. padding: 0 24upx;
  306. .icon {
  307. width: 60upx;
  308. height: 60upx;
  309. padding: 15upx;
  310. }
  311. .icon-img {
  312. width: 100%;
  313. height: 100%
  314. }
  315. .input {
  316. width: 620upx;
  317. height: 56upx;
  318. border-radius: 28upx;
  319. background-color: #ffffff;
  320. border: 1upx solid #eaeaef;
  321. .search-icon {
  322. width: 25upx;
  323. height: 25upx;
  324. background-size: 100% 100%;
  325. background-image: url("../../../static/image/icon/search.png");
  326. background-repeat: no-repeat;
  327. margin-right: 5upx;
  328. }
  329. .text {
  330. font-size: 25upx;
  331. color: #b2b2b2;
  332. margin-left: 5upx;
  333. }
  334. }
  335. }
  336. .cats {
  337. height: 100upx;
  338. line-height: 100upx;
  339. width: 750upx;
  340. background-color: #ffffff;
  341. border-top:1upx solid #eaeaef;
  342. border-bottom: 1upx solid #eaeaef;
  343. white-space:nowrap;
  344. padding-left: 20upx;
  345. position: sticky;
  346. top: 88upx;
  347. z-index: 1000;
  348. .cats-item {
  349. display: inline-block;
  350. margin-right: 32upx;
  351. height: 58upx;
  352. line-height: 58upx;
  353. border-radius: 29upx;
  354. font-size: 26upx;
  355. padding: 0 28upx;
  356. }
  357. .cats-item-active {
  358. color: #ffffff;
  359. }
  360. .cats-item-no {
  361. color: #666666;
  362. }
  363. }
  364. .cats-fixed {
  365. position: fixed;
  366. top: 88upx;
  367. z-index: 1000;
  368. }
  369. .rule-fixed {
  370. margin-top: 188upx;
  371. }
  372. .rule-no-fixed {
  373. margin-top: 88upx;
  374. }
  375. .rule {
  376. padding: 36upx 24upx 30upx 24upx;
  377. .rule-top {
  378. margin-bottom: 30upx;
  379. }
  380. .icon {
  381. width: 54upx;
  382. height: 28upx;
  383. background-image: url("../image/icon.png");
  384. background-size: 100% 100%;
  385. background-repeat: no-repeat;
  386. margin-top: 7upx;
  387. }
  388. .text {
  389. width: 648upx;
  390. font-weight: bold;
  391. font-size: 28upx;
  392. color:#FFFFFF;
  393. margin-left: 8upx;
  394. }
  395. .rule-text {
  396. width: 120upx;
  397. height: 40upx;
  398. border-radius: 20upx;
  399. background-color: rgba(0,0,0,.4);
  400. color: #ffffff;
  401. font-size:22upx;
  402. line-height: 40upx;
  403. text-align: center;
  404. }
  405. .time-icon {
  406. width: 26upx;
  407. height: 26upx;
  408. background-image: url("../image/time.png");
  409. background-repeat: no-repeat;
  410. background-size: 100% 100%;
  411. margin-right: 8upx;
  412. }
  413. .time-text {
  414. font-size: 26upx;
  415. color: #ffffff;
  416. line-height: 1;
  417. }
  418. }
  419. .no-empty {
  420. width: 100%;
  421. margin-top: 150upx;
  422. }
  423. .goods-item {
  424. padding: 24upx;
  425. background-color: #ffffff;
  426. border-bottom: 1upx solid #e2e2e2;
  427. .goods-pic {
  428. width: 200upx;
  429. height: 200upx;
  430. border-radius: 13upx;
  431. margin-right: 24upx;
  432. }
  433. .goods-cont {
  434. width: 478upx;
  435. .goods-name {
  436. font-size: 26upx;
  437. color: #353535;
  438. }
  439. .goods-vip {
  440. margin-top: 8upx;
  441. }
  442. .app-button-icon-cart {
  443. background-image: url('../../../static/image/icon/cats.png');
  444. }
  445. .app-button-icon {
  446. width: #{56rpx};
  447. height: #{56rpx};
  448. display: block;
  449. background-repeat: no-repeat;
  450. background-size: cover;
  451. background-position: center;
  452. }
  453. .sales {
  454. font-size: 22upx;
  455. color: #b0b0b0;
  456. }
  457. .price {
  458. font-size: 24upx;
  459. }
  460. }
  461. }
  462. .u-loading-list {
  463. height: 64upx;
  464. line-height: 64upx;
  465. text-align: center;
  466. color: #b0b0b0;
  467. font-size: 24upx;
  468. }
  469. </style>