detail.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <template>
  2. <Theme>
  3. <view class="wrap">
  4. <!-- 黑色导航栏 -->
  5. <Navbar fixed leftIconColor="var(--light)" :bgColor="'var(--black)'">
  6. <template #center>
  7. <view class="nav_search">
  8. <Search
  9. v-model="searchValue"
  10. border="none"
  11. @input="onSearchInput"
  12. @click="onSearchClick"
  13. :placeholder="t('请输入商品链接或关键字')"
  14. >
  15. <template #prefix>
  16. <i class="icon-font icon-search"></i>
  17. </template>
  18. </Search>
  19. </view>
  20. </template>
  21. </Navbar>
  22. <!-- 店铺信息区域 -->
  23. <view class="shop-info-section">
  24. <view class="shop-header">
  25. <view class="shop-avatar">
  26. <image :src="shopInfo.logo" mode="aspectFill" />
  27. </view>
  28. <view class="shop-details">
  29. <view class="shop-name">{{ shopInfo.name }}</view>
  30. <view class="shop-stats">
  31. <view
  32. >{{ shopInfo.fans }}
  33. <trans class="font" _t="粉丝"></trans>
  34. </view>
  35. <text class="divider">|</text>
  36. <view
  37. >{{ shopInfo.score }}%
  38. <trans class="font" _t="好评率"></trans>
  39. </view>
  40. </view>
  41. </view>
  42. <view class="follow-btn" @click="toggleFollow">
  43. <i class="icon-font icon-plus"></i>
  44. <text>{{ shopInfo.status ? "已关注" : "关注" }}</text>
  45. </view>
  46. </view>
  47. </view>
  48. <!-- 商品列表 -->
  49. <view class="content">
  50. <view v-for="(item, index) in shopGoods" :key="index" class="list">
  51. <productItem
  52. :item="item"
  53. @click="toProductDetail"
  54. @favorite="toggleProductFavorite"
  55. />
  56. </view>
  57. </view>
  58. </view>
  59. </Theme>
  60. </template>
  61. <script setup>
  62. import { ref, reactive, onMounted } from "vue";
  63. import Navbar from "@/components/navbar";
  64. import Search from "@/components/input";
  65. import List from "@/components/list";
  66. import productItem from "./components/product_item";
  67. import { t } from "@/locale";
  68. import { onLoad } from "@dcloudio/uni-app";
  69. import { SELLER_SELLER_INFO } from "@/api";
  70. // 搜索值
  71. const searchValue = ref("");
  72. // List组件引用
  73. const listRef = ref(null);
  74. // 默认参数
  75. const defaultParams = reactive({
  76. keyWord: "",
  77. id: "",
  78. });
  79. // 店铺信息
  80. const shopInfo = ref({});
  81. const shopGoods = ref([]);
  82. // 是否已关注
  83. const isFollowed = ref(false);
  84. // 商品数据
  85. const products = ref([
  86. {
  87. id: 1,
  88. image: "/static/products/product1.jpg",
  89. title: "种草这24cm不粘锅....",
  90. sales: "已售3000+",
  91. currentPrice: "80.20",
  92. originalPrice: "1380.00",
  93. isVideo: true,
  94. isFavorite: false,
  95. },
  96. {
  97. id: 2,
  98. image: "/static/products/product2.jpg",
  99. title: "#时尚锋芒计划",
  100. sales: "已售30万+",
  101. currentPrice: "210.99",
  102. originalPrice: "1380.00",
  103. isVideo: true,
  104. isFavorite: false,
  105. },
  106. {
  107. id: 3,
  108. image: "/static/products/product3.jpg",
  109. title: "种草这24cm不粘锅...",
  110. sales: "已售200+",
  111. currentPrice: "2100.00",
  112. originalPrice: "2380.00",
  113. isVideo: false,
  114. isFavorite: false,
  115. },
  116. {
  117. id: 4,
  118. image: "/static/products/product4.jpg",
  119. title: "种草这24cm不粘锅...",
  120. sales: "已售300+",
  121. currentPrice: "10.60",
  122. originalPrice: "13.00",
  123. isVideo: false,
  124. isFavorite: false,
  125. },
  126. {
  127. id: 5,
  128. image: "/static/products/product5.jpg",
  129. title: "种草这24cm不粘锅...",
  130. sales: "已售30",
  131. currentPrice: "2100.00",
  132. originalPrice: "2380.00",
  133. isVideo: false,
  134. isFavorite: false,
  135. },
  136. {
  137. id: 6,
  138. image: "/static/products/product6.jpg",
  139. title: "种草这24cm不粘锅...",
  140. sales: "已售100+",
  141. currentPrice: "10.60",
  142. originalPrice: "13.00",
  143. isVideo: false,
  144. isFavorite: false,
  145. },
  146. ]);
  147. // 过滤后的商品列表
  148. const filteredProducts = ref([]);
  149. // 搜索输入
  150. const onSearchInput = (value) => {
  151. searchValue.value = value;
  152. defaultParams.keyWord = value;
  153. // 触发列表刷新
  154. if (listRef.value) {
  155. listRef.value.handleRefresh();
  156. }
  157. };
  158. // 搜索点击
  159. const onSearchClick = () => {
  160. console.log("搜索:", searchValue.value);
  161. getList();
  162. };
  163. // Tab切换
  164. const onTabChange = (index) => {
  165. currentTab.value = index;
  166. // 根据Tab切换商品分类
  167. const category = tabList.value[index].name;
  168. defaultParams.category = category;
  169. // 刷新列表
  170. if (listRef.value) {
  171. listRef.value.handleRefresh();
  172. }
  173. };
  174. // 切换关注状态
  175. const toggleFollow = () => {
  176. isFollowed.value = !isFollowed.value;
  177. console.log("关注状态:", isFollowed.value);
  178. };
  179. // 获取列表数据
  180. const getList = (data) => {
  181. // 模拟搜索过滤
  182. if (searchValue.value.trim()) {
  183. const keyword = searchValue.value.toLowerCase();
  184. filteredProducts.value = products.value.filter((product) =>
  185. product.title.toLowerCase().includes(keyword)
  186. );
  187. } else {
  188. filteredProducts.value = products.value;
  189. }
  190. getDetail();
  191. };
  192. // 跳转到商品详情
  193. const toProductDetail = (product) => {
  194. uni.navigateTo({
  195. url: `/pagesBuyer/shop/detail?id=${product.id}`,
  196. });
  197. };
  198. // 切换商品收藏状态
  199. const toggleProductFavorite = (product) => {
  200. product.isFavorite = !product.isFavorite;
  201. console.log("商品收藏状态:", product.isFavorite);
  202. };
  203. const getDetail = async () => {
  204. try {
  205. const res = await SELLER_SELLER_INFO(defaultParams);
  206. shopInfo.value = res.data.seller;
  207. shopGoods.value = res.data.goods || [];
  208. } catch (error) {
  209. Toast(error.msg);
  210. }
  211. };
  212. onLoad((options) => {
  213. if (options.id) {
  214. defaultParams.id = options.id;
  215. getDetail();
  216. }
  217. });
  218. </script>
  219. <style lang="less" scoped>
  220. @import url("@/style.less");
  221. .wrap {
  222. min-height: 100vh;
  223. background: var(--bg);
  224. display: flex;
  225. flex-direction: column;
  226. .nav_search {
  227. flex: 1;
  228. padding: 0 40rpx 0 80rpx;
  229. :deep(.u-input) {
  230. padding: 0 26rpx !important;
  231. background: var(--light);
  232. backdrop-filter: blur(20rpx);
  233. color: var(--text-01);
  234. .u-input__content__field-wrapper__field {
  235. color: var(--text-01);
  236. }
  237. .u-input__content__field-wrapper__field::placeholder {
  238. color: rgba(255, 255, 255, 0.7);
  239. }
  240. }
  241. .icon-search {
  242. color: var(--text-01);
  243. font-size: 38rpx;
  244. }
  245. }
  246. .shop-info-section {
  247. padding: 30rpx;
  248. background: var(--black);
  249. border-bottom: 1rpx solid var(--border);
  250. color: var(--light);
  251. .shop-header {
  252. display: flex;
  253. align-items: center;
  254. .shop-avatar {
  255. width: 80rpx;
  256. height: 80rpx;
  257. border-radius: 50%;
  258. overflow: hidden;
  259. margin-right: 20rpx;
  260. background: var(--light);
  261. image {
  262. width: 100%;
  263. height: 100%;
  264. }
  265. }
  266. .shop-details {
  267. flex: 1;
  268. .shop-name {
  269. font-size: 32rpx;
  270. font-weight: bold;
  271. margin-bottom: 8rpx;
  272. }
  273. .shop-stats {
  274. display: flex;
  275. align-items: center;
  276. font-size: 24rpx;
  277. .font {
  278. color: rgba(255, 255, 255, 0.8);
  279. }
  280. .divider {
  281. margin: 0 20rpx;
  282. color: #cccccc;
  283. }
  284. }
  285. }
  286. .follow-btn {
  287. display: flex;
  288. align-items: center;
  289. padding: 0 24rpx;
  290. height: 44rpx;
  291. line-height: 44rpx;
  292. background: var(--light);
  293. border-radius: 20rpx;
  294. color: var(--text);
  295. font-size: 24rpx;
  296. .icon-plus {
  297. font-size: 20rpx;
  298. }
  299. }
  300. }
  301. }
  302. .content {
  303. .flex();
  304. flex-wrap: wrap;
  305. gap: 8rpx 16rpx;
  306. padding: 20rpx 30rpx;
  307. padding-bottom: calc(90rpx + constant(safe-area-inset-bottom));
  308. padding-bottom: calc(90rpx + env(safe-area-inset-bottom));
  309. .list {
  310. width: calc((100% - 16rpx) / 2);
  311. }
  312. }
  313. }
  314. </style>