category.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <!-- 商品分类列表 -->
  2. <template>
  3. <s-layout title="分类" tabbar="/pages/index/category" class='ss-w-100 box-sizing' navbar="haha">
  4. <view class="s-category">
  5. <view class="three-level-wrap ss-flex ss-col-top" :style="[{ height: pageHeight + 'px' }]">
  6. <!-- 商品分类(左) -->
  7. <scroll-view class="side-menu-wrap" scroll-y :style="[{ height: pageHeight + 'px' }]">
  8. <view
  9. class="menu-item ss-flex"
  10. v-for="(item, index) in state.categoryList"
  11. :key="item.id"
  12. :class="[{ 'menu-item-active': index === state.activeMenu }]"
  13. >
  14. <view class="menu-title ss-line-1" @tap="onMenu(index)">
  15. {{ item.name }}333
  16. </view>
  17. </view>
  18. </scroll-view>
  19. <!-- 商品分类(右) -->
  20. <scroll-view
  21. class="goods-list-box"
  22. scroll-y
  23. :style="[{ height: pageHeight + 'px' }]"
  24. v-if="state.categoryList?.length"
  25. >
  26. <image
  27. v-if="state.categoryList[state.activeMenu].picUrl"
  28. class="banner-img"
  29. :src="sheep.$url.cdn(state.categoryList[state.activeMenu].picUrl)"
  30. mode="widthFix"
  31. />
  32. <first-one v-if="state.style === 'first_one'" :pagination="state.pagination" />
  33. <first-two v-if="state.style === 'first_two'" :pagination="state.pagination" />
  34. <second-one
  35. v-if="state.style === 'second_one'"
  36. :data="state.categoryList"
  37. :activeMenu="state.activeMenu"
  38. />
  39. <uni-load-more
  40. v-if="
  41. (state.style === 'first_one' || state.style === 'first_two') &&
  42. state.pagination.total > 0
  43. "
  44. :status="state.loadStatus"
  45. :content-text="{
  46. contentdown: '点击查看更多',
  47. }"
  48. @tap="loadMore"
  49. />
  50. </scroll-view>
  51. </view>
  52. </view>
  53. </s-layout>
  54. </template>
  55. <script setup>
  56. import secondOne from './components/second-one.vue';
  57. import firstOne from './components/first-one.vue';
  58. import firstTwo from './components/first-two.vue';
  59. import sheep from '@/sheep';
  60. import CategoryApi from '@/sheep/api/product/category';
  61. import SpuApi from '@/sheep/api/product/spu';
  62. import { onLoad, onReachBottom } from '@dcloudio/uni-app';
  63. import { computed, reactive } from 'vue';
  64. import _ from 'lodash-es';
  65. import { handleTree } from '@/sheep/util';
  66. const state = reactive({
  67. style: 'second_one', // first_one(一级 - 样式一), first_two(二级 - 样式二), second_one(二级)
  68. categoryList: [], // 商品分类树
  69. activeMenu: 0, // 选中的一级菜单,在 categoryList 的下标
  70. pagination: {
  71. // 商品分页
  72. list: [], // 商品列表
  73. total: [], // 商品总数
  74. pageNo: 1,
  75. pageSize: 6,
  76. },
  77. loadStatus: '',
  78. });
  79. const { safeArea } = sheep.$platform.device;
  80. const pageHeight = computed(() => safeArea.height - 44 - 50);
  81. // 加载商品分类
  82. async function getList() {
  83. const { code, data } = await CategoryApi.getCategoryList();
  84. if (code !== 0) {
  85. return;
  86. }
  87. state.categoryList = handleTree(data);
  88. }
  89. // 选中菜单
  90. const onMenu = (val) => {
  91. state.activeMenu = val;
  92. console.log(val,'yyyyyyyyyyyyy')
  93. if (state.style === 'first_one' || state.style === 'first_two') {
  94. state.pagination.pageNo = 1;
  95. state.pagination.list = [];
  96. state.pagination.total = 0;
  97. getGoodsList();
  98. }
  99. };
  100. // 加载商品列表
  101. async function getGoodsList() {
  102. // 加载列表
  103. state.loadStatus = 'loading';
  104. const res = await SpuApi.getSpuPage({
  105. categoryId: state.categoryList[state.activeMenu].id,
  106. pageNo: state.pagination.pageNo,
  107. pageSize: state.pagination.pageSize,
  108. });
  109. if (res.code !== 0) {
  110. return;
  111. }
  112. // 合并列表
  113. state.pagination.list = _.concat(state.pagination.list, res.data.list);
  114. state.pagination.total = res.data.total;
  115. state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
  116. }
  117. // 加载更多商品
  118. function loadMore() {
  119. if (state.loadStatus === 'noMore') {
  120. return;
  121. }
  122. state.pagination.pageNo++;
  123. getGoodsList();
  124. }
  125. onLoad(async () => {
  126. await getList();
  127. // 如果是 first 风格,需要加载商品分页
  128. if (state.style === 'first_one' || state.style === 'first_two') {
  129. onMenu(0);
  130. }
  131. });
  132. onReachBottom(() => {
  133. loadMore();
  134. });
  135. </script>
  136. <style lang="scss" scoped>
  137. .s-category {
  138. :deep() {
  139. .side-menu-wrap {
  140. width: 200rpx;
  141. height: 100%;
  142. padding-left: 12rpx;
  143. background-color: #f6f6f6;
  144. .menu-item {
  145. width: 100%;
  146. height: 88rpx;
  147. position: relative;
  148. transition: all linear 0.2s;
  149. .menu-title {
  150. line-height: 32rpx;
  151. font-size: 30rpx;
  152. font-weight: 400;
  153. color: #333;
  154. margin-left: 28rpx;
  155. position: relative;
  156. z-index: 0;
  157. &::before {
  158. content: '';
  159. width: 64rpx;
  160. height: 12rpx;
  161. background: linear-gradient(
  162. 90deg,
  163. var(--ui-BG-Main-gradient),
  164. var(--ui-BG-Main-light)
  165. ) !important;
  166. position: absolute;
  167. left: -64rpx;
  168. bottom: 0;
  169. z-index: -1;
  170. transition: all linear 0.2s;
  171. }
  172. }
  173. &.menu-item-active {
  174. background-color: #fff;
  175. border-radius: 20rpx 0 0 20rpx;
  176. &::before {
  177. content: '';
  178. position: absolute;
  179. right: 0;
  180. bottom: -20rpx;
  181. width: 20rpx;
  182. height: 20rpx;
  183. background: radial-gradient(circle at 0 100%, transparent 20rpx, #fff 0);
  184. }
  185. &::after {
  186. content: '';
  187. position: absolute;
  188. top: -20rpx;
  189. right: 0;
  190. width: 20rpx;
  191. height: 20rpx;
  192. background: radial-gradient(circle at 0% 0%, transparent 20rpx, #fff 0);
  193. }
  194. .menu-title {
  195. font-weight: 600;
  196. &::before {
  197. left: 0;
  198. }
  199. }
  200. }
  201. }
  202. }
  203. .goods-list-box {
  204. background-color: #fff;
  205. width: calc(100vw - 100px);
  206. padding: 10px;
  207. }
  208. .banner-img {
  209. width: calc(100vw - 130px);
  210. border-radius: 5px;
  211. margin-bottom: 20rpx;
  212. }
  213. }
  214. }
  215. </style>