hookehuyr

feat(首页): 重构首页UI组件并优化交互体验

- 使用NutUI组件替换自定义搜索栏和轮播图
- 优化商品卡片布局和收藏按钮样式
- 移除与NutUI冲突的样式和导入
- 更新全局组件声明以支持新增NutUI组件
- 修复文件末尾缺少换行符的问题
......@@ -8,7 +8,9 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
NavBar: typeof import('./src/components/navBar.vue')['default']
NutInput: typeof import('@nutui/nutui-taro')['Input']
NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar']
NutSwiper: typeof import('@nutui/nutui-taro')['Swiper']
NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem']
Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
......
......@@ -69,7 +69,6 @@ export default defineConfig(async (merge) => {
pxtransform: {
enable: true,
config: {
}
},
// url: {
......@@ -134,7 +133,6 @@ export default defineConfig(async (merge) => {
}
},
webpackChain(chain) {
chain.plugin('unplugin-vue-components').use(Components({
resolvers: [NutUIResolver({taro: true})]
}))
......
......@@ -3,13 +3,13 @@
@tailwind utilities;
/* 修复 NutUI 图标字体样式 */
.nut-icon {
font-style: normal !important;
font-weight: normal !important;
}
// .nut-icon {
// font-style: normal !important;
// font-weight: normal !important;
// }
/* 修复所有可能的图标字体 */
[class*="nut-icon"] {
font-style: normal !important;
font-weight: normal !important;
}
// [class*="nut-icon"] {
// font-style: normal !important;
// font-weight: normal !important;
// }
......
......@@ -93,4 +93,4 @@ image {
.card-hover:active {
transform: scale(0.98);
}
\ No newline at end of file
}
......
<!--
* @Date: 2025-06-28 10:33:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-01 18:18:19
* @LastEditTime: 2025-07-01 19:43:08
* @FilePath: /jgdl/src/pages/index/index.vue
* @Description: 捡个电驴首页
-->
......@@ -11,33 +11,22 @@
<view class="bg-orange-400 p-4 pt-8 pb-6">
<view class="text-2xl font-bold text-white mb-3">捡个电驴</view>
<!-- Search Bar -->
<view class="relative">
<view class="absolute inset-y-0 left-3 flex items-center pointer-events-none">
<Search size="18" color="#9ca3af" />
</view>
<nut-input
v-model="searchValue"
placeholder="搜索品牌型号"
class="w-full py-2 pl-10 pr-4 rounded-full bg-white"
:border="false"
/>
</view>
<nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" shape="round" background="transparent"
input-background="#ffffff">
<template #leftin>
<Search2 />
</template>
</nut-searchbar>
</view>
<!-- Banner -->
<view class="px-4 mt-4">
<view class="relative rounded-lg overflow-hidden">
<image
:src="bannerImages[0]"
mode="aspectFill"
class="w-full h-40 object-cover rounded-lg"
/>
<view class="absolute bottom-2 right-2 flex space-x-1">
<view class="w-2 h-2 bg-white rounded-full opacity-100"></view>
<view class="w-2 h-2 bg-white rounded-full opacity-50"></view>
<view class="w-2 h-2 bg-white rounded-full opacity-50"></view>
</view>
</view>
<nut-swiper :init-page="0" :pagination-visible="true" pagination-color="#ffffff" auto-play="3000"
class="rounded-lg overflow-hidden" height="160">
<nut-swiper-item v-for="(image, index) in bannerImages" :key="index">
<image :src="image" mode="aspectFill" class="w-full h-40 object-cover" />
</nut-swiper-item>
</nut-swiper>
</view>
<!-- Category Icons -->
......@@ -74,33 +63,17 @@
</view>
</view>
<view class="grid grid-cols-2 gap-3">
<view
v-for="scooter in featuredScooters"
:key="scooter.id"
class="bg-white rounded-lg shadow-sm overflow-hidden"
@tap="() => onProductClick(scooter)"
>
<view v-for="scooter in featuredScooters" :key="scooter.id"
class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)">
<view class="relative p-2">
<image
:src="scooter.imageUrl"
:alt="scooter.name"
mode="aspectFill"
class="w-full h-36 object-cover rounded-lg"
/>
<view
class="absolute top-4 right-4 p-1"
@tap.stop="() => toggleFavorite(scooter.id)"
>
<Heart
size="24"
:color="favoriteIds.includes(scooter.id) ? '#f97316' : '#ffffff'"
:fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'"
/>
<image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill"
class="w-full h-36 object-cover rounded-lg" />
<view class="absolute top-4 right-4 p-1" @tap.stop="() => toggleFavorite(scooter.id)">
<Heart size="20" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#ffffff'"
:fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" />
</view>
<view
v-if="scooter.isVerified"
class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center"
>
<view v-if="scooter.isVerified"
class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center">
<Check size="12" color="#ffffff" class="mr-0.5" />
<text class="text-white">认证</text>
</view>
......@@ -116,10 +89,7 @@
<text class="text-orange-500 font-bold">
¥{{ scooter.price.toLocaleString() }}
</text>
<text
v-if="scooter.isVerified"
class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded"
>
<text v-if="scooter.isVerified" class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded">
低于市场价10%
</text>
<text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text>
......@@ -139,38 +109,22 @@
</view>
</view>
<view class="flex flex-col">
<view
v-for="scooter in latestScooters"
:key="scooter.id"
class="bg-white rounded-lg shadow-sm overflow-hidden mb-3"
@tap="() => onProductClick(scooter)"
>
<view v-for="scooter in latestScooters" :key="scooter.id"
class="bg-white rounded-lg shadow-sm overflow-hidden mb-3" @tap="() => onProductClick(scooter)">
<view class="flex">
<view class="w-32 h-24 relative p-2">
<image
:src="scooter.imageUrl"
:alt="scooter.name"
mode="aspectFill"
class="w-full h-full object-cover rounded-lg"
/>
<view
v-if="scooter.isVerified"
class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center"
>
<image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill"
class="w-full h-full object-cover rounded-lg" />
<view v-if="scooter.isVerified"
class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center">
<Check size="12" color="#ffffff" class="mr-0.5" />
<text class="text-white">认证</text>
</view>
</view>
<view class="flex-1 p-3 relative">
<view
class="absolute top-2 right-2"
@tap.stop="() => toggleFavorite(scooter.id)"
>
<Heart
size="20"
:color="favoriteIds.includes(scooter.id) ? '#f97316' : '#d1d5db'"
:fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'"
/>
<view class="absolute top-2 right-2" @tap.stop="() => toggleFavorite(scooter.id)">
<Heart size="16" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#d1d5db'"
:fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" />
</view>
<text class="font-medium text-sm block">{{ scooter.name }}</text>
<text class="text-xs text-gray-600 mt-1 block">
......@@ -194,10 +148,10 @@
<script setup>
import Taro from '@tarojs/taro'
import '@tarojs/taro/html.css'
// import '@tarojs/taro/html.css' 和 nutui组件居然有冲突?
import { ref, onMounted } from 'vue'
import { useDidShow, useReady } from '@tarojs/taro'
import { Search, Clock, Star, Service, Right, Heart, Check } from '@nutui/icons-vue-taro'
import { Clock, Star, Service, Right, Heart, Check, Search2 } from '@nutui/icons-vue-taro'
import "./index.less";
// 响应式数据
......@@ -206,7 +160,9 @@ const favoriteIds = ref([])
// Banner图片
const bannerImages = ref([
'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
])
// 精品推荐数据
......@@ -391,7 +347,7 @@ import { getCurrentPageParam } from "@/utils/weapp";
export default {
name: "indexPage",
onHide () {
onHide() {
console.warn('index onHide')
},
onShareAppMessage() {
......