mall.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <template>
  2. <view class="mall-container">
  3. <!-- 顶部搜索框 -->
  4. <view class="search-header">
  5. <view class="search-box">
  6. <view class="search-input">
  7. <image class="search-icon" src="/static/icons/search.png" mode="aspectFit"></image>
  8. <input
  9. class="input"
  10. placeholder="搜索农资商品(如:化肥、除草剂)"
  11. placeholder-style="color: #999;"
  12. v-model="searchKeyword"
  13. @confirm="handleSearch"
  14. />
  15. </view>
  16. </view>
  17. </view>
  18. <!-- 分类导航 -->
  19. <view class="category-nav">
  20. <scroll-view
  21. class="nav-scroll"
  22. scroll-x="true"
  23. :show-scrollbar="false"
  24. :enhanced="true"
  25. :bounces="false"
  26. :scroll-with-animation="true"
  27. :scroll-left="scrollLeft"
  28. >
  29. <view class="nav-list">
  30. <view
  31. class="nav-item"
  32. :class="{ active: activeCategory === item.id }"
  33. v-for="item in categoryList"
  34. :key="item.id"
  35. @click="switchCategory(item.id)"
  36. >
  37. {{ item.name }}
  38. </view>
  39. </view>
  40. </scroll-view>
  41. </view>
  42. <!-- 商品展示区 -->
  43. <view class="goods-container">
  44. <view class="goods-grid">
  45. <view
  46. class="goods-card"
  47. v-for="item in filteredGoods"
  48. :key="item.id"
  49. @click="navigateToDetail(item)"
  50. >
  51. <view class="goods-image">
  52. <image :src="item.image" mode="aspectFill"></image>
  53. </view>
  54. <view class="goods-info">
  55. <text class="goods-title">{{ item.title }}</text>
  56. <text class="goods-desc">{{ item.description }}</text>
  57. <view class="goods-price">
  58. <text class="price">¥{{ item.price }}</text>
  59. <text class="unit">/{{ item.unit }}</text>
  60. </view>
  61. <view class="action-btn">了解更多</view>
  62. </view>
  63. </view>
  64. </view>
  65. </view>
  66. </view>
  67. </template>
  68. <script>
  69. export default {
  70. data() {
  71. return {
  72. searchKeyword: '',
  73. activeCategory: 'recommend',
  74. scrollLeft: 0,
  75. // 分类列表
  76. categoryList: [
  77. { id: 'recommend', name: '推荐' },
  78. { id: 'seeds', name: '种子' },
  79. { id: 'fertilizer', name: '肥料' },
  80. { id: 'pesticide', name: '农药' },
  81. { id: 'film', name: '农膜' },
  82. { id: 'parts', name: '农机配件' }
  83. ],
  84. // 商品列表
  85. goodsList: [
  86. {
  87. id: 1,
  88. title: '高产玉米种子',
  89. description: '优质杂交种,抗病性强,适应性广',
  90. price: '68',
  91. unit: '袋',
  92. image: '/static/images/products/corn-seeds-new.jpg',
  93. category: 'seeds'
  94. },
  95. {
  96. id: 2,
  97. title: '复合肥料NPK',
  98. description: '15-15-15配比,全营养均衡',
  99. price: '120',
  100. unit: '袋',
  101. image: '/static/images/products/fertilizer.jpg',
  102. category: 'fertilizer'
  103. },
  104. {
  105. id: 3,
  106. title: '植物保护剂',
  107. description: '广谱除草,效果持久',
  108. price: '45',
  109. unit: '瓶',
  110. image: '/static/images/products/plant-protection.jpg',
  111. category: 'pesticide'
  112. },
  113. {
  114. id: 4,
  115. title: '优质水稻种子',
  116. description: '高产稳产,米质优良',
  117. price: '85',
  118. unit: '袋',
  119. image: '/static/images/products/seeds-packets.jpg',
  120. category: 'seeds'
  121. },
  122. {
  123. id: 5,
  124. title: '有机肥料',
  125. description: '纯天然有机,改良土壤',
  126. price: '95',
  127. unit: '袋',
  128. image: '/static/images/products/organic-fertilizer-new.jpg',
  129. category: 'fertilizer'
  130. },
  131. {
  132. id: 6,
  133. title: '农用工具套装',
  134. description: '多功能农具,提高作业效率',
  135. price: '285',
  136. unit: '套',
  137. image: '/static/images/products/agriculture-tools.jpg',
  138. category: 'pesticide'
  139. },
  140. {
  141. id: 7,
  142. title: '温室农膜',
  143. description: '保温保湿,延长生长期',
  144. price: '125',
  145. unit: '卷',
  146. image: '/static/images/products/greenhouse-film.jpg',
  147. category: 'film'
  148. },
  149. {
  150. id: 8,
  151. title: '农业机械配件',
  152. description: '耐用配件,维护设备正常运行',
  153. price: '350',
  154. unit: '套',
  155. image: '/static/images/products/farming-equipment.jpg',
  156. category: 'parts'
  157. }
  158. ]
  159. }
  160. },
  161. computed: {
  162. filteredGoods() {
  163. let goods = this.goodsList;
  164. // 按分类筛选
  165. if (this.activeCategory !== 'recommend') {
  166. goods = goods.filter(item => item.category === this.activeCategory);
  167. }
  168. // 按搜索关键词筛选
  169. if (this.searchKeyword.trim()) {
  170. const keyword = this.searchKeyword.trim().toLowerCase();
  171. goods = goods.filter(item =>
  172. item.title.toLowerCase().includes(keyword) ||
  173. item.description.toLowerCase().includes(keyword)
  174. );
  175. }
  176. return goods;
  177. }
  178. },
  179. methods: {
  180. // 切换分类
  181. switchCategory(categoryId) {
  182. this.activeCategory = categoryId;
  183. // 滚动到当前分类位置
  184. this.$nextTick(() => {
  185. this.scrollToActiveCategory(categoryId);
  186. });
  187. },
  188. // 滚动到激活的分类
  189. scrollToActiveCategory(categoryId) {
  190. const index = this.categoryList.findIndex(item => item.id === categoryId);
  191. if (index > -1) {
  192. // 计算滚动位置,让当前分类居中显示
  193. const itemWidth = 120; // 每个分类项大约120rpx宽度
  194. const containerWidth = 750; // 屏幕宽度
  195. const scrollLeft = Math.max(0, index * itemWidth - containerWidth / 2 + itemWidth / 2);
  196. // 设置scroll-view的scrollLeft
  197. this.scrollLeft = scrollLeft;
  198. }
  199. },
  200. // 搜索处理
  201. handleSearch() {
  202. if (!this.searchKeyword.trim()) {
  203. uni.showToast({
  204. title: '请输入搜索关键词',
  205. icon: 'none'
  206. });
  207. return;
  208. }
  209. // 搜索逻辑已在computed中处理
  210. },
  211. // 导航到商品详情
  212. navigateToDetail(goods) {
  213. uni.navigateTo({
  214. url: `/pages/service/mall-detail?id=${goods.id}&title=${encodeURIComponent(goods.title)}`
  215. });
  216. }
  217. },
  218. onNavigationBarTitleText() {
  219. return '农资商城';
  220. }
  221. }
  222. </script>
  223. <style lang="scss">
  224. .mall-container {
  225. min-height: 100vh;
  226. background-color: #f5f5f5;
  227. }
  228. .search-header {
  229. background-color: #fff;
  230. padding: 20rpx;
  231. border-bottom: 1rpx solid #f0f0f0;
  232. }
  233. .search-box {
  234. position: relative;
  235. }
  236. .search-input {
  237. display: flex;
  238. align-items: center;
  239. background-color: #f8f8f8;
  240. border-radius: 32rpx;
  241. padding: 16rpx 24rpx;
  242. .search-icon {
  243. width: 32rpx;
  244. height: 32rpx;
  245. margin-right: 16rpx;
  246. }
  247. .input {
  248. flex: 1;
  249. font-size: 28rpx;
  250. line-height: 1.5;
  251. }
  252. }
  253. .category-nav {
  254. background-color: #fff;
  255. border-bottom: 1rpx solid #f0f0f0;
  256. position: sticky;
  257. top: 0;
  258. z-index: 100;
  259. }
  260. .nav-scroll {
  261. white-space: nowrap;
  262. height: 88rpx;
  263. width: 100%;
  264. overflow: hidden;
  265. -webkit-overflow-scrolling: touch; /* iOS滑动优化 */
  266. scroll-behavior: smooth; /* 平滑滚动 */
  267. }
  268. .nav-list {
  269. display: inline-flex;
  270. padding: 0 20rpx;
  271. height: 100%;
  272. align-items: center;
  273. min-width: 100%;
  274. }
  275. .nav-item {
  276. flex-shrink: 0;
  277. padding: 24rpx 32rpx;
  278. margin-right: 8rpx;
  279. font-size: 28rpx;
  280. color: #666;
  281. font-weight: 500;
  282. position: relative;
  283. white-space: nowrap;
  284. transition: all 0.2s ease;
  285. border-radius: 8rpx;
  286. &:active {
  287. background-color: #f0f0f0;
  288. transform: scale(0.95);
  289. }
  290. &.active {
  291. color: #4CAF50;
  292. font-weight: bold;
  293. background-color: #f8fdf8;
  294. }
  295. &.active::after {
  296. content: '';
  297. position: absolute;
  298. bottom: 8rpx;
  299. left: 50%;
  300. transform: translateX(-50%);
  301. width: 40rpx;
  302. height: 4rpx;
  303. background-color: #4CAF50;
  304. border-radius: 2rpx;
  305. }
  306. }
  307. .goods-container {
  308. padding: 20rpx;
  309. }
  310. .goods-grid {
  311. display: grid;
  312. grid-template-columns: 1fr 1fr;
  313. gap: 20rpx;
  314. }
  315. .goods-card {
  316. background-color: #fff;
  317. border-radius: 16rpx;
  318. overflow: hidden;
  319. box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
  320. transition: transform 0.2s ease;
  321. &:active {
  322. transform: scale(0.98);
  323. }
  324. }
  325. .goods-image {
  326. width: 100%;
  327. height: 240rpx;
  328. image {
  329. width: 100%;
  330. height: 100%;
  331. }
  332. }
  333. .goods-info {
  334. padding: 24rpx;
  335. }
  336. .goods-title {
  337. font-size: 28rpx;
  338. font-weight: bold;
  339. color: #333;
  340. line-height: 1.4;
  341. display: block;
  342. margin-bottom: 8rpx;
  343. }
  344. .goods-desc {
  345. font-size: 24rpx;
  346. color: #666;
  347. line-height: 1.4;
  348. display: block;
  349. margin-bottom: 16rpx;
  350. overflow: hidden;
  351. text-overflow: ellipsis;
  352. white-space: nowrap;
  353. }
  354. .goods-price {
  355. display: flex;
  356. align-items: baseline;
  357. margin-bottom: 20rpx;
  358. .price {
  359. font-size: 32rpx;
  360. font-weight: bold;
  361. color: #4CAF50;
  362. }
  363. .unit {
  364. font-size: 24rpx;
  365. color: #999;
  366. margin-left: 4rpx;
  367. }
  368. }
  369. .action-btn {
  370. background-color: #4CAF50;
  371. color: #fff;
  372. text-align: center;
  373. padding: 16rpx 0;
  374. border-radius: 8rpx;
  375. font-size: 28rpx;
  376. font-weight: 500;
  377. }
  378. </style>