| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759 |
- <template>
- <view :style="{ paddingTop: statusBarHeight + 'px' }" class="bg-white">
- <view>
- <!-- 新的头部搜索栏 -->
- <view class="header-container">
- <view class="search-container">
- <view class="search-icon">
- <uni-icons type="search" size="18" color="#666"></uni-icons>
- </view>
- <input class="search-input" type="text" placeholder="Search ROMIDO" @input="onInput"
- @confirm="onSearch" />
- <view class="barcode-icon">
- <uni-icons type="scan" size="20" color="#666"></uni-icons>
- </view>
- </view>
- <view class="cart-container">
- <view class="message-icon" @tap="goChat">
- <uni-icons type="chat-filled" size="25" color="#1351D8"></uni-icons>
- <view class="unread-badge" v-if="unreadMessageCount > 0">{{unreadMessageCount}}</view>
- </view>
- <view class="cart-icon" @tap="goCart">
- <uni-icons type="cart-filled" size="25" color="#1351D8"></uni-icons>
- <view class="cart-badge" v-if="cartCount > 0">{{cartCount}}</view>
- </view>
- </view>
- </view>
- <view class="bg-index-image">
- <swiper class="swiper" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
- <!-- swiper-item组件,每个item代表一张轮播图 -->
- <swiper-item v-for="(item, index) in bannerList" :key="index">
- <image class="swiper-image" :src="item.image" mode="scaleToFill"></image>
- </swiper-item>
- </swiper>
- <!-- 新品上市 -->
- <view class="product-xinpin-bg">
- <view class="product">
- <view class="font-def pad-t-20 flex-sp-between flex-items">
- <view class="mar-l-20 font32 font-bold">
- New Arrivals
- </view>
- <view class="view-all" @click="goAll">
- <text>View All</text>
- <uni-icons type="right" size="14" color="#666"></uni-icons>
- </view>
- </view>
- <view class="xinpin">
- <view class="new-product-module">
- <!-- 商品列表 -->
- <view class="product-list">
- <view class="product-item" v-for="(product, index) in currentProductList"
- :key="index" @click="detail(product.id)">
- <!-- 商品图片 -->
- <image :src=" product.images" mode="aspectFill" class="product-image">
- </image>
- <!-- 商品名称 -->
- <view class="product-name">{{ product.name }}</view>
- <!-- 商品价格 -->
- <view class="product-price">¥{{ product.price }}</view>
- </view>
- </view>
- <!-- 换一批按钮 -->
- <view class="change-button" @click="changeProducts">
- <view class="pad-r-10">
- <uni-icons color="#007aff" type="refreshempty" size="18"></uni-icons>
- </view>
- <view>
- refresh
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- <!-- 限时秒杀 -->
- <!-- <view class="product-miaosha-bg">
- <view class="product">
- <view class="font-def pad-t-20 flex-sp-between flex-items">
- <view class="mar-l-20 font32 font-bold">
- 限时秒杀
- </view>
- <view class="mar-r-20 font26" @click="goAll">
- 查看全部>
- </view>
- </view>
- <view class="xinpin">
- <view class="new-product-module">
- <view class="product-list">
- <view class="product-item"
- v-for="(product, index) in indexProductList.killTimeProductList" :key="index"
- @click="detail(product.id)" v-if="index<3">
- <view class="product-image-container">
- <image :src="product.images" mode="aspectFill" class="product-image">
- </image>
- <view class="countdown">{{ getCountdown(product.killTime) }}</view>
- </view>
- <view class="product-name">{{ product.name }}</view>
- <view class="product-price">¥{{ product.price }}</view>
- <view class="product-stock">剩余{{ product.stock }}件</view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view> -->
- <!-- 更多商品 -->
- <view class="product-gengduo-bg">
- <view class="font-def pad-t-20 flex-sp-between flex-items">
- <view class="mar-l-20 font32 font-bold">
- More Products
- </view>
- <view class="view-all" @click="goAll">
- <text>View All</text>
- <uni-icons type="right" size="14" color="#666"></uni-icons>
- </view>
- </view>
- <view class="goods-list-container">
- <!-- 商品列表 -->
- <view class="goods-list">
- <view class="goods-item" v-for="(item, index) in goodsList" :key="index"
- @tap="detail(item.id)">
- <!-- 商品图片 -->
- <image :src="item.images" mode="aspectFill" class="gd-goods-image"></image>
- <!-- 商品详情 -->
- <view class="goods-info">
- <!-- 商品名称 -->
- <view class="goods-name">{{ item.name }}</view>
- <view class="flex-items">
- <text>
- {{item.productAvg}}
- </text>
- <uni-rate readonly allow-half :value="item.productAvg" />
- <text class="commentCount">
- ({{item.commentCount}})
- </text>
- </view>
- <!-- 商品价格 -->
- <view class="goods-price">
- ¥{{ item.price }}
- <text class="original-price"
- v-if="item.originalPrice">¥{{ item.originalPrice }}</text>
- </view>
- <!-- 商品销量 -->
- <view class="goods-sales">sales:{{ item.salesTotal }}</view>
- <!-- 加号图标 -->
- <!-- <view class="add-icon" @click.stop="handleAdd(item)">
- <uni-icons color="#1BA4F0" type="plus-filled" size="30"></uni-icons>
- </view> -->
- </view>
- </view>
- </view>
- <!-- 加载提示 -->
- <view v-if="isLoading" class="loading-tip">加载中...</view>
- <!-- 没有更多数据提示 -->
- <view v-if="!isLoading && noMoreData" class="no-more-tip">——没有更多商品了——</view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- import {
- carouselQueryAll,
- getShopIndexList,
- productList,
- productCartCount,
- unreadCount,
- markMessagesRead
- } from '@/config/api.js';
- export default {
- data() {
- return {
- statusBarHeight: 0, // 状态栏高度
- cartCount: 0, // 购物车数量
- goodsList: [], // 商品列表
- params: {
- current: 1,
- size: 10,
- categoriesId: "",
- name: "",
- sort: "",
- arrow: "",
- },
- isLoading: false, // 是否正在加载
- noMoreData: false, // 是否没有更多数据
- searchValue: "",
- bannerList: [],
- indexProductList: [],
- currentIndex: 0, // 当前显示的商品起始索引
- currentProductList: [], // 当前显示的商品列表
- newProductList: [],
- user: {},
- unreadMessageCount: 0, // Added for unread message count
- hasLoaded: false, // 标记页面是否已经加载过
- };
- },
- onLoad() {
- // 获取状态栏高度
- const systemInfo = uni.getSystemInfoSync();
- this.statusBarHeight = systemInfo.statusBarHeight;
- this.init();
- // 获取购物车数量
- this.getCartCount();
- // 获取未读消息数量
- this.getUnreadMessageCount();
- },
- onReachBottom() {
- if (!this.isLoading && !this.noMoreData) {
- this.loadGoods();
- }
- },
- onShow() {
- // 每次显示页面时获取最新的购物车数量
- // 只有不是首次加载时才更新未读消息数量(避免与onLoad重复调用)
- if (this.hasLoaded) {
- this.getCartCount();
- this.getUnreadMessageCount();
- } else {
- this.hasLoaded = true;
- }
- },
- methods: {
- goCart() {
- this.$route('/pages/shop/cart');
- },
- goChat() {
- // 先将所有消息标记为已读
- const userInfo = uni.getStorageSync("userInfo");
- if (userInfo && userInfo.user_id) {
- markMessagesRead({
- userId: userInfo.user_id
- }).then(res => {
- // 标记成功后,将未读消息数量清零
- if(res.success) {
- this.unreadMessageCount = 0;
- }
- }).catch(err => {
- console.error('标记消息已读失败:', err);
- });
- }
-
- // 然后跳转到聊天页面
- this.$route('/pages/chat/index');
- },
- // 获取购物车数量
- getCartCount() {
- productCartCount().then((res) => {
- this.cartCount = res.data;
- }).catch(err => {
- console.error('获取购物车数量失败:', err);
- });
- },
- // 获取未读消息数量
- getUnreadMessageCount() {
- // 确保用户信息已加载
- const userInfo = uni.getStorageSync("userInfo");
- if (userInfo && userInfo.user_id) {
- unreadCount({
- userId: userInfo.user_id
- }).then(res => {
- this.unreadMessageCount = res.data;
- }).catch(err => {
- console.error('获取未读消息数量失败:', err);
- });
- }
- },
- goBack() {
- uni.navigateBack()
- },
- detail(id) {
- this.$route('/packageShop/pages/detail/index?id=' + id)
- },
- onInput() {
- },
- onSearch() {
- this.$route('/pages/order/search?type=1&searchKey=' + this.params.name);
- },
- goAll() {
- this.$route('/pages/shop/product-type-list')
- },
- init() {
- this.user = uni.getStorageInfoSync("userInfo")
- this.getShufflingList();
- this.getIndexList();
- // 开启倒计时定时器
- this.startCountdown();
- this.loadGoods();
- },
- async loadGoods() {
- uni.showLoading({
- title: '加载中...',
- mask: true
- });
- this.isLoading = true;
- try {
- const response = await productList(this.params);
- const newGoods = response.data.records;
- if (newGoods.length === 0) {
- this.noMoreData = true;
- } else {
- this.goodsList = this.goodsList.concat(newGoods);
- this.params.current++;
- }
- } catch (error) {
- console.error('加载商品数据失败:', error);
- } finally {
- uni.hideLoading()
- this.isLoading = false;
- }
- },
- // 处理加号点击事件
- handleAdd(item) {
- console.log('点击了加号,商品信息:', item);
- // 这里可以添加你需要的业务逻辑,比如添加到购物车等
- },
- // 开启倒计时定时器
- startCountdown() {
- setInterval(() => {
- this.$forceUpdate(); // 强制更新组件,重新计算倒计时
- }, 1000);
- },
- // 计算倒计时
- getCountdown(endTime) {
- const now = new Date().getTime();
- const end = new Date(endTime).getTime();
- const diff = end - now;
- if (diff <= 0) {
- return '已结束';
- }
- const days = Math.floor(diff / (1000 * 60 * 60 * 24));
- const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
- const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
- const seconds = Math.floor((diff % (1000 * 60)) / 1000);
- if (days > 0) {
- return `${days} 天 ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
- } else {
- return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
- }
- },
- getIndexList() {
- getShopIndexList({
- type: 2
- }).then(res => {
- this.indexProductList = res.data;
- this.newProduct();
- });
- },
- newProduct() {
- this.currentProductList = this.indexProductList.newProductList.slice(this.currentIndex, this.currentIndex +
- 3);
- },
- // 换一批商品
- changeProducts() {
- if (this.currentIndex + 3 < this.indexProductList.newProductList.length) {
- this.currentIndex += 3;
- } else {
- this.currentIndex = 0;
- }
- this.newProduct();
- },
- getShufflingList() {
- carouselQueryAll().then(res => {
- this.bannerList = res.data;
- this.bannerList = this.bannerList.filter((item) => item.type == 2);
- });
- },
- }
- };
- </script>
- <style>
- .goods-list-container {
- padding: 20rpx;
- }
- .goods-list {
- display: flex;
- flex-direction: column;
- }
- .goods-item {
- width: 100%;
- background-color: #fff;
- border-radius: 16rpx;
- margin-bottom: 20rpx;
- padding: 20rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
- position: relative;
- box-sizing: border-box;
- display: flex;
- }
- .gd-goods-image {
- width: 240rpx;
- height: 240rpx;
- border-radius: 8rpx;
- margin-right: 20rpx;
- flex-shrink: 0;
- }
- .goods-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- padding-right: 40rpx;
- }
- .goods-name {
- font-size: 28rpx;
- color: #333;
- margin-bottom: 10rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- line-height: 1.4;
- }
- .goods-price {
- font-size: 36rpx;
- color: #FF4B4B;
- font-weight: bold;
- margin: 10rpx 0;
- }
- .original-price {
- font-size: 24rpx;
- color: #999;
- text-decoration: line-through;
- margin-left: 10rpx;
- }
- .goods-tag {
- display: inline-block;
- background-color: #FFF5F5;
- color: #FF4B4B;
- font-size: 20rpx;
- padding: 4rpx 12rpx;
- border-radius: 6rpx;
- margin-bottom: 10rpx;
- }
- .goods-sales {
- font-size: 24rpx;
- color: #999;
- margin-top: auto;
- }
- .add-icon {
- position: absolute;
- bottom: 20rpx;
- right: 20rpx;
- width: 40rpx;
- height: 40rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 32rpx;
- }
- .loading-tip {
- text-align: center;
- font-size: 24rpx;
- color: #999;
- margin: 20rpx 0;
- }
- .no-more-tip {
- text-align: center;
- font-size: 24rpx;
- color: #999;
- margin: 20rpx 0;
- }
- .product-image-container {
- position: relative;
- }
- .countdown {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: red;
- color: white;
- text-align: center;
- font-size: 24rpx;
- padding: 5rpx;
- }
- .new-product-module {
- background-color: #fff;
- padding: 40rpx 40rpx 20rpx 40rpx;
- }
- .product-list {
- display: flex;
- justify-content: flex-start;
- /* 修改为靠左对齐 */
- flex-wrap: wrap;
- }
- .product-item {
- width: calc((100% - 40rpx) / 3);
- margin-bottom: 20rpx;
- margin-right: 20rpx;
- /* 添加右边距,使商品之间有间隔 */
- }
- /* 去除最后一个商品的右边距 */
- .product-item:nth-child(3n) {
- margin-right: 0;
- }
- .product-image {
- width: 100%;
- height: 200rpx;
- border-radius: 8rpx;
- }
- .product-name {
- font-size: 30rpx;
- color: #333;
- line-height: 32rpx;
- height: 64rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- margin-top: 10rpx;
- }
- .product-price {
- padding-top: 20rpx;
- font-size: 30rpx;
- color: #f60;
- }
- .product-stock {
- color: #333333;
- padding-top: 10rpx;
- font-size: 26rpx;
- }
- .change-button {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 28rpx;
- color: #007aff;
- cursor: pointer;
- }
- .search-container {
- flex: 1;
- display: flex;
- align-items: center;
- background-color: #F6F7F9;
- border-radius: 40rpx;
- padding: 8rpx 20rpx;
- margin: 0 15rpx;
- }
- .header-container {
- display: flex;
- align-items: center;
- padding: 10rpx 20rpx 20rpx 20rpx;
- background-color: #fff;
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- z-index: 100;
- padding-top: v-bind('statusBarHeight + "px"');
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
- }
- .back-button {
- padding: 10rpx;
- margin-right: 10rpx;
- }
- .search-icon {
- margin-right: 10rpx;
- }
- .search-input {
- flex: 1;
- height: 60rpx;
- line-height: 60rpx;
- font-size: 28rpx;
- color: #333;
- padding: 0 10rpx;
- }
- .barcode-icon {
- margin-left: 10rpx;
- padding: 5rpx;
- }
- .cart-container {
- display: flex;
- align-items: center;
- }
- .message-icon {
- margin-right: 20rpx;
- position: relative; /* 添加相对定位,以便角标可以相对于图标定位 */
- }
- .cart-icon {
- position: relative;
- }
- .cart-badge {
- position: absolute;
- top: -10rpx;
- right: -10rpx;
- background-color: #FF4B4B;
- color: #fff;
- font-size: 20rpx;
- padding: 2rpx 8rpx;
- border-radius: 20rpx;
- min-width: 28rpx;
- height: 28rpx;
- text-align: center;
- line-height: 28rpx;
- }
- .unread-badge {
- position: absolute;
- top: -10rpx;
- right: -10rpx;
- background-color: #FF4B4B;
- color: #fff;
- font-size: 20rpx;
- padding: 2rpx 8rpx;
- border-radius: 20rpx;
- min-width: 28rpx;
- height: 28rpx;
- text-align: center;
- line-height: 28rpx;
- }
- .commentCount {
- font-size: 28rpx;
- color: #666;
- }
- .product-xinpin-bg {
- position: absolute;
- background: linear-gradient(to bottom, #f8f9fc, #ffffff);
- top: 650rpx;
- min-height: 100vh;
- width: 100%;
- }
- .product-miaosha-bg {
- position: absolute;
- top: 1180rpx;
- /* 调整位置:新品上市区域位置(650) + 预估高度(530) */
- min-height: 100vh;
- width: 100%;
- }
- .product-gengduo-bg {
- position: absolute;
- top: 1210rpx;
- background: linear-gradient(to bottom, #f8f9fc, #ffffff);
- min-height: 100vh;
- width: 100%;
- }
- .xinpin {
- margin: 20rpx;
- background-color: #FFF;
- border-radius: 16rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
- }
- .product {
- margin-top: 30rpx;
- min-height: 100vh;
- background: linear-gradient(to bottom, #f8f9fc, #ffffff);
- border-radius: 40rpx;
- }
- .product-bg {
- position: absolute;
- background-color: white;
- top: 500rpx;
- min-height: 100vh;
- width: 100%;
- }
- .bg-index-image {
- background: linear-gradient(to bottom, #f8f9fc, #ffffff);
- background-size: cover;
- height: 500rpx;
- position: relative;
- /* margin-top: v-bind('(statusBarHeight + 84) + "px"'); */
- }
- .swiper {
- width: 100%;
- height: 550rpx;
- position: absolute;
- /* 设置为绝对定位 */
- top: 106rpx;
- /* 调整顶部距离 */
- }
- .swiper-image {
- width: 100%;
- height: 100%;
- }
- .message-icon,
- .cart-icon {
- color: #5C6B8A;
- }
- .view-all {
- display: flex;
- align-items: center;
- margin-right: 20rpx;
- font-size: 26rpx;
- color: #666;
- }
- .view-all text {
- margin-right: 4rpx;
- }
- </style>
|