首页示例数据调用
This commit is contained in:
+147
-47
@@ -2,25 +2,67 @@
|
||||
<view class="app-container">
|
||||
<!-- ========== 首页内容 ========== -->
|
||||
<view v-if="currentTab === 'home'" class="page-content home-page">
|
||||
<scroll-view
|
||||
class="product-area"
|
||||
<scroll-view
|
||||
class="product-area"
|
||||
scroll-y
|
||||
>
|
||||
<view class="section-title">热销商品</view>
|
||||
|
||||
<view class="product-grid" id="productGrid">
|
||||
<view
|
||||
v-for="(item, index) in productList"
|
||||
:key="index"
|
||||
class="product-card"
|
||||
>
|
||||
<image class="product-img" :src="item.image" mode="aspectFill" />
|
||||
<view class="product-name">{{ item.name }}</view>
|
||||
<view class="product-price">{{ item.price }}元</view>
|
||||
<!-- 热销商品标题 + 装饰 -->
|
||||
<view class="section-title-wrap">
|
||||
<view class="section-title">热销商品</view>
|
||||
<view class="title-decoration">
|
||||
<view class="deco-dot"></view>
|
||||
<view class="deco-line"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部占位,防止被tab-bar遮挡 -->
|
||||
<!-- 分类 Tab 横向滚动 -->
|
||||
<scroll-view class="category-tabs" scroll-x>
|
||||
<view class="tabs-inner">
|
||||
<view class="tab-item" :class="{ active: activeCategory === 'all' }" @click="switchCategory('all')">
|
||||
<text class="tab-text">全部商品</text>
|
||||
<view class="tab-underline"></view>
|
||||
</view>
|
||||
<view
|
||||
v-for="(cat, idx) in categoryList"
|
||||
:key="idx"
|
||||
class="tab-item"
|
||||
:class="{ active: activeCategory === cat.category }"
|
||||
@click="switchCategory(cat.category)"
|
||||
>
|
||||
<text class="tab-text">{{ cat.category }}</text>
|
||||
<view class="tab-underline"></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 商品网格 -->
|
||||
<view class="product-grid">
|
||||
<view
|
||||
v-for="(item, idx) in displayProducts"
|
||||
:key="idx"
|
||||
class="product-card"
|
||||
@click="goProductDetail(item)"
|
||||
>
|
||||
<image class="product-img" :src="item.image" mode="aspectFill" />
|
||||
<view class="product-name">{{ item.name }}</view>
|
||||
<view class="product-price">
|
||||
<text class="price-yen">¥</text>
|
||||
<text class="price-num">{{ getDisplayPrice(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无商品时 -->
|
||||
<view v-if="categoryList.length === 0 && !loading" class="empty-tip">
|
||||
<text>暂无商品</text>
|
||||
</view>
|
||||
|
||||
<!-- loading -->
|
||||
<view v-if="loading" class="loading-tip">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 底部占位 -->
|
||||
<view class="bottom-spacer"></view>
|
||||
</scroll-view>
|
||||
|
||||
@@ -89,34 +131,26 @@
|
||||
<script>
|
||||
import PageNavBar from '@/components/page-nav-bar/page-nav-bar.vue';
|
||||
|
||||
const API_BASE = 'http://localhost:4000';
|
||||
const DEVICE_ID = 'A1036';
|
||||
const BEARER_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRlZXB2ZW5kaW5nIiwic3ViIjoiMTY0MDI0MTEyNiIsImZyb20iOiJwb3MiLCJyb2xlIjoicG9zIiwibWFpbmJvYXJkX2lkIjoiVDEwMDIiLCJwb3Nfc24iOiIxNjQwMjQxMTI2IiwiaWF0IjoxNzc3NTI5MjYzLCJleHAiOjE3NzgxMzQwNjN9.I7eL2oL2rmkaJKH4R6aylUloyJh0dUS3vXLvKueX28I';
|
||||
|
||||
export default {
|
||||
components: { PageNavBar },
|
||||
data() {
|
||||
return {
|
||||
currentTab: 'home',
|
||||
showQrcodePopup: false,
|
||||
productList: [
|
||||
{ name: '君乐宝450ml悦鲜活', price: '0.01', image: '/static/c1.png' },
|
||||
{ name: '白红(0.0.0.0-9.9.9)', price: '0.06', image: '/static/c2.png' },
|
||||
{ name: '白桔(0.0.0.0-5.5.5)', price: '0.05', image: '/static/c3.png' },
|
||||
{ name: '可口可乐330ml', price: '3.00', image: '/static/c4.png' },
|
||||
{ name: '农夫山泉550ml', price: '2.00', image: '/static/c5.png' },
|
||||
{ name: '君乐宝450ml悦鲜活', price: '0.01', image: '/static/c1.png' },
|
||||
{ name: '白红(0.0.0.0-9.9.9)', price: '0.06', image: '/static/c2.png' },
|
||||
{ name: '白桔(0.0.0.0-5.5.5)', price: '0.05', image: '/static/c3.png' },
|
||||
{ name: '可口可乐330ml', price: '3.00', image: '/static/c4.png' },
|
||||
{ name: '农夫山泉550ml', price: '2.00', image: '/static/c5.png' },
|
||||
{ name: '乐事薯片原味75g', price: '7.50', image: '/static/c6.png' }
|
||||
],
|
||||
loading: false,
|
||||
categoryList: [],
|
||||
activeCategory: 'all',
|
||||
userInfo: { nickname: '张三', phone: '13812345678' },
|
||||
// 菜单:我的订单、常见问题、联系客服、公众号信息
|
||||
menuList: [
|
||||
{ title: '我的订单', action: 'order' },
|
||||
{ title: '常见问题', action: 'faq' },
|
||||
{ title: '联系客服', action: 'call' },
|
||||
{ title: '公众号信息', action: 'qrcode' }
|
||||
],
|
||||
// 客服电话
|
||||
servicePhone: '13264706088'
|
||||
};
|
||||
},
|
||||
@@ -124,40 +158,84 @@ export default {
|
||||
maskedPhone() {
|
||||
const p = this.userInfo.phone;
|
||||
return p ? p.substring(0,3) + '****' + p.substring(7) : '';
|
||||
},
|
||||
// 全部商品:合并所有分类下的商品
|
||||
allProducts() {
|
||||
let all = [];
|
||||
this.categoryList.forEach(cat => {
|
||||
if (cat.products) all = all.concat(cat.products);
|
||||
});
|
||||
return all;
|
||||
},
|
||||
// 当前显示的商品列表(根据选中的分类 tab)
|
||||
displayProducts() {
|
||||
if (this.activeCategory === 'all') return this.allProducts;
|
||||
const cat = this.categoryList.find(c => c.category === this.activeCategory);
|
||||
return cat ? cat.products || [] : [];
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.fetchProducts();
|
||||
},
|
||||
methods: {
|
||||
switchTab(tab) { this.currentTab = tab; },
|
||||
switchCategory(cat) { this.activeCategory = cat; },
|
||||
getDisplayPrice(item) {
|
||||
// 优先显示促销价,没有促销价则显示销售价
|
||||
if (item.promotion_price != null) return item.promotion_price;
|
||||
return item.sale_price;
|
||||
},
|
||||
goProductDetail(item) {
|
||||
uni.navigateTo({ url: '/pages/product/product?product_id=' + item.product_id });
|
||||
},
|
||||
async fetchProducts() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: API_BASE + '/device-product/getProductList',
|
||||
method: 'GET',
|
||||
data: { device_id: DEVICE_ID },
|
||||
header: {
|
||||
Authorization: 'Bearer ' + BEARER_TOKEN
|
||||
}
|
||||
});
|
||||
const ret = res.data || {};
|
||||
if (ret.code === 0 && Array.isArray(ret.data)) {
|
||||
this.categoryList = ret.data;
|
||||
} else {
|
||||
uni.showToast({ title: ret.message || '获取商品失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '网络请求失败', icon: 'none' });
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
handleOpenDoor() {
|
||||
uni.showModal({ title: '开门', content: '确认打开柜门?', success: r => r.confirm && uni.showToast({title:'柜门已打开', icon:'success'}) });
|
||||
uni.showModal({
|
||||
title: '开门',
|
||||
content: '确认打开柜门?',
|
||||
success: r => r.confirm && uni.showToast({ title: '柜门已打开', icon: 'success' })
|
||||
});
|
||||
},
|
||||
handleMenuClick(item) {
|
||||
switch (item.action) {
|
||||
case 'order':
|
||||
uni.showToast({ title: '订单功能开发中', icon: 'none' });
|
||||
uni.navigateTo({ url: '/pages/order/order' });
|
||||
break;
|
||||
case 'faq':
|
||||
uni.navigateTo({ url: '/pages/faq/faq' });
|
||||
break;
|
||||
case 'call':
|
||||
// 拨打电话
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.servicePhone,
|
||||
fail: () => {}
|
||||
});
|
||||
uni.makePhoneCall({ phoneNumber: this.servicePhone, fail: () => {} });
|
||||
break;
|
||||
case 'qrcode':
|
||||
// 显示公众号二维码弹窗
|
||||
this.showQrcodePopup = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
handleNavPrev() {
|
||||
this.currentTab = 'home';
|
||||
},
|
||||
handleNavNext() {
|
||||
uni.showToast({ title: '暂无下一页', icon: 'none' });
|
||||
}
|
||||
handleNavPrev() { this.currentTab = 'home'; },
|
||||
handleNavNext() { uni.showToast({ title: '暂无下一页', icon: 'none' }); }
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -170,24 +248,46 @@ page { height: 100%; background-color: #fff; }
|
||||
/* ====== 首页样式 ====== */
|
||||
.home-page { display: flex; flex-direction: column; height: 100%; }
|
||||
.product-area { flex: 1; overflow-y: auto; height: 0; }
|
||||
.section-title { font-size: 36rpx; font-weight: bold; color: #333; padding: 24rpx 28rpx 16rpx; }
|
||||
|
||||
/* 热销商品标题 + 装饰 */
|
||||
.section-title-wrap { display: flex; align-items: center; padding: 24rpx 28rpx 16rpx; }
|
||||
.section-title { font-size: 36rpx; font-weight: bold; color: #333; }
|
||||
.title-decoration { display: flex; align-items: center; margin-left: 16rpx; }
|
||||
.deco-dot { width: 12rpx; height: 12rpx; background: #ff6b6b; border-radius: 50%; }
|
||||
.deco-line { width: 40rpx; height: 6rpx; background: linear-gradient(90deg, #ff6b6b, transparent); margin-left: 6rpx; border-radius: 3rpx; }
|
||||
|
||||
/* 分类 Tab 横向滚动 */
|
||||
.category-tabs { white-space: nowrap; padding: 0 20rpx; border-bottom: 1rpx solid #f0f0f0; }
|
||||
.tabs-inner { display: inline-flex; padding: 0 8rpx; }
|
||||
.tab-item { display: inline-flex; flex-direction: column; align-items: center; padding: 20rpx 24rpx; position: relative; }
|
||||
.tab-text { font-size: 28rpx; color: #666; transition: color 0.2s; }
|
||||
.tab-item.active .tab-text { color: #2979ff; font-weight: bold; }
|
||||
.tab-underline { position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 0; height: 4rpx; background: #2979ff; border-radius: 2rpx; transition: width 0.2s; }
|
||||
.tab-item.active .tab-underline { width: 48rpx; }
|
||||
|
||||
/* 商品网格 */
|
||||
.product-grid { display: flex; flex-wrap: wrap; padding: 12rpx; gap: 12rpx; }
|
||||
.product-card { width: calc((100% - 24rpx) / 3); text-align: center; }
|
||||
.product-img { width: 100%; height: 220rpx; border-radius: 8rpx; background-color: #f0f0f0; }
|
||||
.product-name { font-size: 24rpx; color: #333; padding: 10rpx 8rpx 6rpx; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.product-price { font-size: 30rpx; font-weight: bold; color: #e4393c; padding: 0 8rpx 16rpx; }
|
||||
.price-yen { font-size: 22rpx; }
|
||||
.price-num { font-size: 32rpx; }
|
||||
|
||||
/* 底部占位 */
|
||||
.bottom-spacer { height: 160rpx; }
|
||||
|
||||
/* 底部导航栏 */
|
||||
.tab-bar { position: absolute; bottom: 0; left: 0; right: 0; height: 120rpx; background: #fff; display: flex; align-items: center; justify-content: space-around; box-shadow: 0 -2rpx 16rpx rgba(0,0,0,0.08); z-index: 999; padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); }
|
||||
.tab-item { flex: 1; display: flex; align-items: center; justify-content: center; height: 100%; }
|
||||
.tab-text { font-size: 28rpx; color: #999; font-weight: normal; }
|
||||
.tab-item.active .tab-text { color: #2979ff; }
|
||||
.tab-bar .tab-item { flex: 1; display: flex; align-items: center; justify-content: center; height: 100%; }
|
||||
.tab-bar .tab-text { font-size: 28rpx; color: #999; font-weight: normal; }
|
||||
.tab-bar .tab-item.active .tab-text { color: #2979ff; }
|
||||
.door-btn-wrapper { position: relative; display: flex; align-items: center; justify-content: center; margin-top: -80rpx; }
|
||||
.door-btn { width: 160rpx; height: 160rpx; border-radius: 50%; background: linear-gradient(135deg, #2979ff, #1e60e0); color: #fff; font-size: 38rpx; font-weight: bold; display: flex; align-items: center; justify-content: center; box-shadow: 0 10rpx 36rpx rgba(41,121,255,0.55); }
|
||||
|
||||
/* 空状态 / Loading */
|
||||
.empty-tip, .loading-tip { text-align: center; padding: 60rpx; color: #999; font-size: 28rpx; }
|
||||
|
||||
/* ====== 我的页面样式 ====== */
|
||||
.mine-page { background-color: #f5f5f5; position: relative; overflow-y: auto; }
|
||||
.user-header { background: linear-gradient(135deg, #2979ff, #1e60e0); padding: 60rpx 40rpx; }
|
||||
|
||||
Reference in New Issue
Block a user