This commit is contained in:
zpc 2025-06-23 01:52:56 +08:00
parent 30bbc09066
commit f4c6b693e0
5 changed files with 364 additions and 376 deletions

31
common/server/product.js Normal file
View File

@ -0,0 +1,31 @@
import HttpRequest from "../system/request";
/**
* 获取banner列表
* @returns {Promise} banner列表
*/
export const getBannerList = async () => {
const res = await HttpRequest.get('/get_banner_list');
if (res.status == 1) {
return res.data;
}
return [];
}
/**
* 获取商品列表
* @param {number} pageNo 页码
* @param {number} pageSize 每页条数
* @param {string} searchKeyword 搜索关键词
* @returns {Promise} 商品列表
*/
export const getProductList = async (pageNo, pageSize, searchKeyword) => {
const res = await HttpRequest.get('/get_product_list', {
page: pageNo,
limit: pageSize,
title: searchKeyword
});
if (res.status == 1) {
return res.data;
}
}

View File

@ -1,7 +1,8 @@
<template>
<view class="content">
<z-paging v-if="firstLoaded || isCurrentPage" ref="paging" show-refresher-update-time
loading-more-no-more-text="我也是有底线的!" v-model="dataList" @query="queryList" :fixed="false">
loading-more-no-more-text="我也是有底线的!" :show-loading-more-when-reload="true" v-model="dataList" @query="queryList" :fixed="false">
<slot name="search"></slot>
<template v-for="(item, index) in dataList">
<view v-if="item.cover_image !== ''" class="view-data" :key="index" @click="toDetails(item.id)">
<view class="title">

View File

@ -1,415 +1,369 @@
<template>
<view class="content">
<view class="" style="width: 100%; height: 225.19rpx; background-color: white; position: relative;">
<view class="title">
商城
</view>
</view>
<!-- 顶部三个商品 -->
<view class="top">
<view v-for="(item, i) in topDataList" :key="i" class="item" @click="goToDetail(item)">
<view class="img">
<image v-if="item.imgUrl" :src="item.imgUrl" mode="aspectFill" class="product-image"></image>
<z-paging-swiper>
<template #top>
<view class="" style="width: 100%; height: 225.19rpx; background-color: white; position: relative;">
<view class="title">
商城
</view>
</view>
<view class="item-info">
<view class="item-name">
{{item.name}}
</view>
<view class="item-bottom">
<view class="item-price">
<text class="price-symbol-small"></text>
<text class="price-value-small">{{item.price}}</text>
</template>
<z-paging ref="paging" show-refresher-update-time loading-more-no-more-text="我也是有底线的" v-model="dataList"
@query="queryList" :fixed="false" :show-loading-more-when-reload="true">
<!-- 顶部三个商品 -->
<swiper :display-multiple-items="3" class="top" :duration="500">
<swiper-item v-for="(item, i) in topDataList" :key="i" @click="goToDetail(item)">
<view class="item">
<view class="img">
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
</image>
</view>
<view class="item-count">
<text class="count-text-small">{{item.num}}/1</text>
<image src="/static/ic_box.png" class="box-icon-small" mode="aspectFit"></image>
<view class="item-info">
<view class="item-name">
{{ item.title }}
</view>
<view class="item-bottom">
<view class="item-price">
<text class="price-symbol-small"></text>
<text class="price-value-small">{{ item.price }}</text>
</view>
<view class="item-count">
<text class="count-text-small">{{ item.sales }}/{{ item.stock }}</text>
<image src="/static/ic_box.png" class="box-icon-small" mode="aspectFit"></image>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="view-list">
<view class="product-item" v-for="(item, i) in dataList" :key="i" @click="goToDetail(item)">
<view class="product-image-container">
<image v-if="item.image" :src="item.image" mode="aspectFill" class="product-image">
</image>
</view>
<view class="product-name">
{{ item.title }}
</view>
<view class="product-count">
<text class="count-text">{{ item.sales }}/{{ item.stock }}</text>
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
</view>
<view class="product-price">
<text class="price-symbol"></text>
<text class="price-value">{{ item.price }}</text>
</view>
<view class="buy-button" @click.stop="buyProduct(item)">
<text class="buy-text">购买</text>
</view>
</view>
</view>
</view>
<scroll-view class="view-list" scroll-y="true">
<view class="product-item" v-for="(item, i) in dataList" :key="i" @click="goToDetail(item)">
<view class="product-image-container">
<image v-if="item.imgUrl" :src="item.imgUrl" mode="aspectFill" class="product-image"></image>
</view>
<view class="product-name">
{{item.name}}
</view>
<view class="product-count">
<text class="count-text">{{item.num}}/1</text>
<image src="/static/ic_box.png" class="box-icon" mode="aspectFit"></image>
</view>
<view class="product-price">
<text class="price-symbol"></text>
<text class="price-value">{{item.price}}</text>
</view>
<view class="buy-button" @click.stop="buyProduct(item)">
<text class="buy-text">购买</text>
</view>
</view>
</scroll-view>
</view>
<template #empty>
<no-data />
</template>
<template #loading>
<loading-data />
</template>
</z-paging>
</z-paging-swiper>
</template>
<script>
export default {
data() {
return {
topDataList: [{
id: '1',
imgUrl: "/static/product1.png",
name: "英雄联盟K/DA系列阿卡丽手办",
num: "1",
price: "69",
stock: 10
}, {
id: '2',
imgUrl: "/static/product2.png",
name: "英雄联盟K/DA系列阿狸手办",
num: "1",
price: "79",
stock: 5
}, {
id: '3',
imgUrl: "/static/product3.png",
name: "英雄联盟K/DA系列伊芙琳手办",
num: "1",
price: "89",
stock: 8
}, ],
dataList: [{
id: '4',
imgUrl: "/static/product4.png",
name: "英雄联盟K/DA系列阿卡丽手办豪华版",
num: "1",
price: "169",
stock: 3
}, {
id: '5',
imgUrl: "/static/product5.png",
name: "英雄联盟K/DA系列阿狸手办豪华版",
num: "1",
price: "179",
stock: 2
}, {
id: '6',
imgUrl: "/static/product6.png",
name: "英雄联盟K/DA系列伊芙琳手办豪华版",
num: "1",
price: "189",
stock: 6
}, {
id: '7',
imgUrl: "/static/product7.png",
name: "英雄联盟K/DA系列卡莎手办",
num: "1",
price: "99",
stock: 15
}, {
id: '8',
imgUrl: "/static/product8.png",
name: "英雄联盟K/DA系列莎拉手办",
num: "1",
price: "99",
stock: 12
}, {
id: '9',
imgUrl: "/static/product9.png",
name: "英雄联盟K/DA系列套装收藏版",
num: "1",
price: "599",
stock: 1
}, ]
}
},
methods: {
//
goToDetail(item) {
uni.navigateTo({
url: `/pages/mall/product-detail?id=${item.id}`
});
},
//
buyProduct(item) {
//
event.stopPropagation();
//
if (item.stock <= 0) {
uni.showToast({
title: '商品已售罄',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '已添加到购物车',
icon: 'success'
});
}
}
<script setup>
import { ref } from 'vue';
const paging = ref(null);
import { getProductList, getBannerList } from '@/common/server/product';
//
const topDataList = ref([
]);
const dataList = ref([]);
//
const goToDetail = (item) => {
uni.navigateTo({
url: `/pages/mall/product-detail?id=${item.id}`
});
};
//
const buyProduct = (item, event) => {
//
event.stopPropagation();
//
if (item.stock <= 0) {
uni.showToast({
title: '商品已售罄',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '已添加到购物车',
icon: 'success'
});
};
const queryList = (pageNo, pageSize) => {
getProductList(pageNo, pageSize, "").then(res => {
dataList.value.concat(res || []);
paging.value.complete(res || false);
});
};
onLoad(async () => {
const bannerList = await getBannerList();
topDataList.value = bannerList;
});
</script>
<style lang="scss">
.content {
width: 100%;
.content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #F7F7F7;
}
.title {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 32.44rpx;
font-weight: 600;
position: absolute;
bottom: 30rpx;
}
.top {
width: 688.94rpx;
height: 325.38rpx;
margin: 34rpx auto;
display: flex;
flex-direction: row;
justify-content: space-between;
.item {
width: 216.31rpx;
height: 100%;
background-color: #FFFFFF;
border-radius: 15.27rpx;
display: flex;
flex-direction: column;
background-color: #F7F7F7;
}
.title {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 32.44rpx;
font-weight: 600;
position: absolute;
bottom: 30rpx;
}
.top {
width: 688.94rpx;
height: 325.38rpx;
margin: 34rpx auto;
display: flex;
flex-direction: row;
justify-content: space-between;
.item {
width: 216.31rpx;
height: 100%;
background-color: #FFFFFF;
border-radius: 15.27rpx;
display: flex;
flex-direction: column;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
&:active {
transform: scale(0.98);
}
}
.img {
width: 100%;
height: 216.31rpx;
background-color: #F2F2F2;
border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;
overflow: hidden;
.product-image {
width: 100%;
height: 100%;
}
}
.item-info {
width: 100%;
height: 109.07rpx;
position: relative;
padding: 8rpx;
box-sizing: border-box;
}
.item-name {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 19.08rpx;
color: #333333;
text-align: center;
margin-top: 6rpx;
}
.item-bottom {
position: absolute;
width: 100%;
bottom: 12rpx;
left: 0;
padding: 0 13rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.item-price {
display: flex;
flex-direction: row;
align-items: center;
}
.price-symbol-small {
font-size: 15.27rpx;
margin-top: 6rpx;
color: #FF6A6A;
}
.price-value-small {
font-size: 22.9rpx;
font-weight: bold;
color: #FF6A6A;
}
.item-count {
display: flex;
flex-direction: row;
align-items: center;
}
.count-text-small {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon-small {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.view-list {
width: 688.93rpx;
height: 850rpx;
margin: 0 auto;
}
.product-item {
width: 100%;
height: 261.45rpx;
background-color: #FFFFFF;
margin-bottom: 21rpx;
border-radius: 15.27rpx;
position: relative;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
&:active {
transform: scale(0.98);
}
}
.product-image-container {
width: 216.31rpx;
.img {
width: 100%;
height: 216.31rpx;
background-color: #F2F2F2;
border-radius: 15.27rpx;
position: absolute;
left: 22rpx;
top: 22rpx;
border-radius: 15.27rpx 15.27rpx 0rpx 0rpx;
overflow: hidden;
.product-image {
width: 100%;
height: 100%;
}
}
.product-name {
width: 350rpx;
.item-info {
width: 100%;
height: 109.07rpx;
position: relative;
padding: 8rpx;
box-sizing: border-box;
}
.item-name {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
position: absolute;
left: 269rpx;
top: 44rpx;
font-size: 26.72rpx;
font-weight: 600;
font-size: 19.08rpx;
color: #333333;
text-align: center;
margin-top: 6rpx;
}
.product-count {
.item-bottom {
position: absolute;
width: 100%;
bottom: 12rpx;
left: 0;
padding: 0 13rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.item-price {
display: flex;
flex-direction: row;
left: 269rpx;
top: 95rpx;
align-items: center;
.count-text {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.product-price {
position: absolute;
.price-symbol-small {
font-size: 15.27rpx;
margin-top: 6rpx;
color: #FF6A6A;
}
.price-value-small {
font-size: 22.9rpx;
font-weight: bold;
color: #FF6A6A;
}
.item-count {
display: flex;
flex-direction: row;
left: 269rpx;
bottom: 44rpx;
align-items: center;
.price-symbol {
font-size: 19.08rpx;
margin-top: 15rpx;
color: #FF6A6A;
}
.price-value {
font-size: 34.35rpx;
font-weight: bold;
color: #FF6A6A;
}
}
.buy-button {
width: 89.22rpx;
height: 42rpx;
border-radius: 20.99rpx;
border: 1rpx solid #FF6A6A;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
right: 38rpx;
bottom: 38rpx;
transition: all 0.3s;
&:active {
background-color: #FF6A6A;
.buy-text {
color: white;
}
}
.count-text-small {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon-small {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.product-item {
width: 100%;
height: 261.45rpx;
background-color: #FFFFFF;
margin-bottom: 21rpx;
border-radius: 15.27rpx;
position: relative;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
&:active {
transform: scale(0.98);
}
}
.product-image-container {
width: 216.31rpx;
height: 216.31rpx;
background-color: #F2F2F2;
border-radius: 15.27rpx;
position: absolute;
left: 22rpx;
top: 22rpx;
overflow: hidden;
.product-image {
width: 100%;
height: 100%;
}
}
.product-name {
width: 350rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
position: absolute;
left: 269rpx;
top: 44rpx;
font-size: 26.72rpx;
font-weight: 600;
color: #333333;
}
.product-count {
position: absolute;
display: flex;
flex-direction: row;
left: 269rpx;
top: 95rpx;
align-items: center;
.count-text {
font-size: 15.27rpx;
color: #6C6C6C;
}
.box-icon {
width: 17.39rpx;
height: 17.39rpx;
margin-left: 7rpx;
}
}
.product-price {
position: absolute;
display: flex;
flex-direction: row;
left: 269rpx;
bottom: 44rpx;
align-items: center;
.price-symbol {
font-size: 19.08rpx;
margin-top: 15rpx;
color: #FF6A6A;
}
.price-value {
font-size: 34.35rpx;
font-weight: bold;
color: #FF6A6A;
}
}
.buy-button {
width: 89.22rpx;
height: 42rpx;
border-radius: 20.99rpx;
border: 1rpx solid #FF6A6A;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
right: 38rpx;
bottom: 38rpx;
transition: all 0.3s;
&:active {
background-color: #FF6A6A;
.buy-text {
font-size: 19.08rpx;
color: #FF6A6A;
font-weight: 500;
color: white;
}
}
.buy-text {
font-size: 19.08rpx;
color: #FF6A6A;
font-weight: 500;
}
}
</style>

View File

@ -1,6 +1,6 @@
<!-- 滑动切换选项卡演示(标准写法) -->
<template>
<page-no-container ref="pageContainer" title="我的订单" :showBack="true">
<PageNoContainer ref="pageContainer" title="我的订单" :showBack="true">
<!-- 使用z-paging-swiper为根节点可以免计算高度 -->
<z-paging-swiper :fixed="false">
<!-- 需要固定在顶部不滚动的view放在slot="top"的view中 -->
@ -19,7 +19,7 @@
</swiper>
</z-paging-swiper>
</page-no-container>
</PageNoContainer>
</template>
<script setup>
@ -33,7 +33,7 @@ const tabList = ref(['全部', '待发货', '待收货', '评价', '售后']);
onLoad((options) => {
console.log(options);
if (options.type) {
current.value = options.type;
current.value = Number(options.type);
}
});
// tabsswiper

View File

@ -13,17 +13,19 @@
</template>
<swiper class="swiper" :current="current" @animationfinish="swiperAnimationfinish">
<swiper-item class="swiper-item" v-for="(item, index) in tabList" :key="index">
<view class="search-container">
<view class="search">
<text class="iconfont icon-search" style="margin-right: 10rpx; color: #999;"></text>
<input type="text" v-model="searchKeywords[index]" placeholder="搜索" confirm-type="search"
@confirm="() => onSearch(index)" />
<text class="iconfont icon-close" v-if="searchKeywords[index]" @click="() => clearSearch(index)"
style="margin-left: 10rpx; color: #999;"></text>
</view>
</view>
<news-list-item @clickItem="onClickItem" :responseCallback="queryList" ref="listItem" :tabIndex="index"
:currentIndex="current">
<template #search>
<view class="search-container">
<view class="search">
<text class="iconfont icon-search" style="margin-right: 10rpx; color: #999;"></text>
<input type="text" v-model="searchKeywords[index]" placeholder="搜索"
confirm-type="search" @confirm="() => onSearch(index)" />
<text class="iconfont icon-close" v-if="searchKeywords[index]"
@click="() => clearSearch(index)" style="margin-left: 10rpx; color: #999;"></text>
</view>
</view>
</template>
</news-list-item>
</swiper-item>
</swiper>