index.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <template>
  2. <view>
  3. <uv-navbar title="店铺信息" placeholder autoBack></uv-navbar>
  4. <view class="top">
  5. <view class="shop">
  6. <view class="shop_l">
  7. <image :src="details.image" mode="" />
  8. <view>
  9. <view class="shop_l_title">{{ details.businessName }}</view>
  10. <view class="shop_l_rate u-flex-center-sb">
  11. <view class="u-flex-center">
  12. <rate :value="Math.round(details.average)" />
  13. <text class="u-font24 u-ml10">{{ details.average }}分</text>
  14. </view>
  15. <view class="shop_r" @click="goPhone()"> 售后电话 </view>
  16. </view>
  17. </view>
  18. </view>
  19. </view>
  20. <view class="searchBox">
  21. <image :src="$handleImageUrl('/common/search.png')" mode=""></image>
  22. <input
  23. @click="searchClick"
  24. v-model="value"
  25. type="text"
  26. placeholder-style="color:#B3B3B3;font-size:28rpx"
  27. placeholder="可搜索本店商品"
  28. />
  29. </view>
  30. </view>
  31. <!-- 限时秒杀 -->
  32. <SeckillGood />
  33. <!-- 拼团购 -->
  34. <GroupBuyingGood />
  35. <view class="tabsBox">
  36. <uv-tabs
  37. :list="tabList"
  38. keyName="categoryName"
  39. lineColor="#FA6138"
  40. activeStyle="color:#FA6138;"
  41. lineWidth="60rpx"
  42. @click="tabsClick"
  43. ></uv-tabs>
  44. </view>
  45. <view class="list">
  46. <view
  47. class="goodsListA_item"
  48. v-for="item in list"
  49. :key="item.id"
  50. @click="goDetails(item)"
  51. >
  52. <image :src="`${item.coverImage}`" mode=""></image>
  53. <view class="goodsListA_item_title">{{ item.title }}</view>
  54. <view class="goodsListA_item_pirce">
  55. <text v-if="item.productPaymentMode == 1" style="font-size: 22rpx"
  56. >{{ item.minPoints }}积分</text
  57. >
  58. <rich-text
  59. v-else
  60. :nodes="$mUtil.priceBigSmall(item.salePrice || item.minSalePrice)"
  61. ></rich-text>
  62. <view>¥ {{ item.marketPrice || item.minMarketPrice }}</view>
  63. </view>
  64. <view class="goodsListA_item_num">已售{{ item.showSales }}件</view>
  65. </view>
  66. </view>
  67. <view v-if="list.length <= 0" style="width: 100%">
  68. <noData :config="{ top: 20, content: '暂无商品~' }"></noData>
  69. </view>
  70. <uv-load-more v-else :status="status" />
  71. </view>
  72. </template>
  73. <script setup >
  74. import {
  75. getBusinessInfo,
  76. getProductCategoryList,
  77. productList,
  78. } from "@/api/shop.js";
  79. import { ref, getCurrentInstance } from "vue";
  80. import {
  81. onShow,
  82. onLoad,
  83. onPullDownRefresh,
  84. onReachBottom,
  85. } from "@dcloudio/uni-app";
  86. import SeckillGood from "./components/SeckillGood.vue"; // 限时秒杀组件
  87. import GroupBuyingGood from "./components/GroupBuyingGood.vue"; // 拼团购组件
  88. const details = ref({});
  89. const value = ref("");
  90. const status = ref("loadmore");
  91. const list = ref([]); // 添加缺失的商品列表数据
  92. const tabList = ref([
  93. {
  94. id: 1,
  95. categoryName: "全部",
  96. categoryId: "",
  97. },
  98. {
  99. id: 2,
  100. categoryName: "热销",
  101. categoryId: "hot",
  102. },
  103. {
  104. id: 3,
  105. categoryName: "新品",
  106. categoryId: "new",
  107. },
  108. ]);
  109. const params = ref({
  110. pageNum: 1,
  111. pageSize: 10,
  112. });
  113. onLoad((options) => {
  114. let id = options.businessId;
  115. if (id) {
  116. params.value.businessId = id;
  117. getDetails();
  118. getTabs();
  119. }
  120. });
  121. // 下拉刷新
  122. onPullDownRefresh(() => {
  123. params.value.pageNum = 1;
  124. getProductList();
  125. });
  126. // 上拉加载更多
  127. onReachBottom(() => {
  128. if (status.value == "loadmore") {
  129. params.value.pageNum++;
  130. getProductList();
  131. }
  132. });
  133. const goBack = () => {
  134. // uni.navigateBack()
  135. uni.navigateTo({ url: "/pages/index/index" });
  136. };
  137. const getTabs = () => {
  138. getProductCategoryList({ businessId: params.value.businessId }).then(
  139. (res) => {
  140. tabList.value = [...tabList.value, ...res.data];
  141. }
  142. );
  143. };
  144. // 商家电话
  145. const goPhone = () => {
  146. if (details.value.customerServicePhone) {
  147. uni.makePhoneCall({
  148. phoneNumber: details.value.customerServicePhone,
  149. });
  150. } else {
  151. uni.showToast({
  152. title: "暂无商家电话",
  153. icon: "none",
  154. });
  155. }
  156. };
  157. const getDetails = () => {
  158. getBusinessInfo({ businessId: params.value.businessId }).then((res) => {
  159. details.value = res.data;
  160. getProductList();
  161. });
  162. };
  163. // 获取商品分页列表
  164. const getProductList = () => {
  165. status.value = "loading";
  166. productList(params.value)
  167. .then((res) => {
  168. if (!res.rows) return;
  169. if (params.value.pageNum == 1) {
  170. list.value = res.rows;
  171. } else {
  172. list.value = [...list.value, ...res.rows];
  173. }
  174. if (list.value.length < res.total) {
  175. status.value = "loadmore";
  176. } else {
  177. status.value = "noMore";
  178. }
  179. uni.stopPullDownRefresh();
  180. })
  181. .catch((e) => {
  182. uni.stopPullDownRefresh();
  183. status.value = "loadmore";
  184. });
  185. };
  186. const goDetails = (item) => {
  187. uni.navigateTo({
  188. url: `/pages/shop/goodsDetails?id=${item.productId}`,
  189. });
  190. };
  191. const searchClick = () => {
  192. uni.navigateTo({
  193. url: "/pages/shop/goodSearch",
  194. });
  195. };
  196. const tabsClick = (e) => {
  197. // 重置分页参数
  198. params.value.pageNum = 1;
  199. // 根据选中的标签设置不同的查询参数
  200. if (e.index === 0) {
  201. // 全部
  202. delete params.value.productCategoryId;
  203. delete params.value.hot;
  204. delete params.value.newStatus;
  205. } else if (e.index === 1) {
  206. // 热销
  207. params.value.hot = true;
  208. delete params.value.productCategoryId;
  209. delete params.value.newStatus;
  210. } else if (e.index === 2) {
  211. // 新品
  212. params.value.newStatus = true;
  213. delete params.value.productCategoryId;
  214. delete params.value.hot;
  215. } else {
  216. // 具体分类
  217. params.value.productCategoryId = tabList.value[e.index].categoryId;
  218. delete params.value.hot;
  219. delete params.value.newStatus;
  220. }
  221. // 重新获取商品列表
  222. getProductList();
  223. };
  224. </script>
  225. <style lang="scss" scoped>
  226. .top {
  227. width: 720rpx;
  228. padding: 30rpx;
  229. box-shadow: 0rpx 4rpx 8rpx 0rpx #f1f1f1;
  230. background: #ffffff;
  231. border-radius: 20rpx;
  232. margin: auto;
  233. box-sizing: border-box;
  234. }
  235. .shop {
  236. display: flex;
  237. align-items: center;
  238. position: relative;
  239. .shop_l {
  240. width: 100%;
  241. display: flex;
  242. align-items: center;
  243. image {
  244. width: 124rpx;
  245. height: 124rpx;
  246. border-radius: 20rpx;
  247. }
  248. > view {
  249. flex: 1;
  250. margin-left: 20rpx;
  251. .shop_l_title {
  252. font-size: 32rpx;
  253. color: #333333;
  254. font-weight: 700;
  255. }
  256. .shop_l_rate {
  257. margin-top: 10rpx;
  258. }
  259. }
  260. }
  261. .shop_r {
  262. width: 150rpx;
  263. margin-left: auto;
  264. padding: 6rpx 0rpx;
  265. text-align: center;
  266. color: #666;
  267. border-radius: 25rpx;
  268. background-color: #fff;
  269. border: 1rpx solid #666;
  270. // position: absolute;
  271. // right: 30rpx;
  272. // bottom: 25rpx;
  273. // font-size: 28rpx;
  274. }
  275. }
  276. .searchBox {
  277. display: flex;
  278. padding: 10rpx 35rpx;
  279. border: 1rpx solid #cccccc;
  280. border-radius: 36rpx;
  281. margin: 30rpx 0 0;
  282. display: flex;
  283. align-items: center;
  284. margin-top: 10rpx;
  285. background: #fff;
  286. image {
  287. width: 35rpx;
  288. height: 35rpx;
  289. margin-right: 15rpx;
  290. flex-shrink: 0;
  291. }
  292. input {
  293. text-align: left;
  294. }
  295. }
  296. .tabsBox {
  297. margin-bottom: 20rpx;
  298. padding: 0 30rpx;
  299. }
  300. .list {
  301. padding: 0 30rpx;
  302. display: flex;
  303. flex-wrap: wrap;
  304. .goodsListA_item {
  305. width: 336rpx;
  306. box-shadow: 0rpx 4rpx 8rpx 0rpx #f1f1f1;
  307. border-radius: 18rpx;
  308. margin-left: 18rpx;
  309. margin-bottom: 30rpx;
  310. &:nth-child(2n-1) {
  311. margin-left: 0 !important;
  312. }
  313. image {
  314. width: 336rpx;
  315. height: 336rpx;
  316. border-radius: 18rpx 18rpx 0 0;
  317. }
  318. > view {
  319. padding: 0 20rpx;
  320. }
  321. .goodsListA_item_title {
  322. font-size: 28rpx;
  323. color: #181818;
  324. overflow: hidden;
  325. text-overflow: ellipsis;
  326. display: -webkit-box;
  327. -webkit-line-clamp: 2;
  328. -webkit-box-orient: vertical;
  329. }
  330. .goodsListA_item_pirce {
  331. display: flex;
  332. // align-items: flex-end;
  333. align-items: baseline;
  334. font-size: 20rpx;
  335. color: #ff6600;
  336. font-weight: 700;
  337. text {
  338. font-size: 36rpx;
  339. font-weight: 500;
  340. display: inline-block;
  341. // position: relative;
  342. // top: 4rpx;
  343. }
  344. > view {
  345. font-size: 24rpx;
  346. color: #cccccc;
  347. margin-left: 30rpx;
  348. text-decoration: line-through;
  349. font-weight: normal;
  350. }
  351. }
  352. .goodsListA_item_num {
  353. font-size: 22rpx;
  354. color: #999999;
  355. margin-top: 10rpx;
  356. padding-bottom: 20rpx;
  357. }
  358. }
  359. }
  360. </style>