代码提交

This commit is contained in:
黄少君
2023-11-14 17:21:03 +08:00
parent d0b337c596
commit dcab74274f
567 changed files with 22414 additions and 7375 deletions

View File

@ -0,0 +1,54 @@
<!--
@name: index
@author: kahu4
@date: 2023-11-02 16:10
@descriptionindex
@update: 2023-11-02 16:10
-->
<script setup>
</script>
<template>
<view class="banner-container">
<swiper
class="swiper"
circular
indicator-dots
autoplay
>
<swiper-item v-for="item in 10">
<view class="swiper-item">
<image
src="@/static/images/banner.png"
mode="aspectFit"
/>
</view>
</swiper-item>
</swiper>
</view>
</template>
<style
scoped
lang="scss"
>
.banner-container {
padding: 0 35rpx;
box-sizing: border-box;
border-radius: 15rpx;
.swiper {
height: 340rpx;
.swiper-item {
height: 340rpx;
image {
width: 100%;
height: 100%;
}
}
}
}
</style>

View File

@ -0,0 +1,44 @@
<!--
@name: 砍价
@author: kahu4
@date: 2023-10-27 14:42
@descriptionindex
@update: 2023-10-27 14:42
-->
<script setup>
import { useRouter } from "@/hooks/useRouter";
import TwoRowGoodRow from "@/pages/index/components/public/TwoRowGoodRow.vue"
const props = defineProps({
products: {
type: Array
}
})
const {push} = useRouter()
</script>
<template>
<blank size="15"></blank>
<activity
title="砍价专区"
more="查看更多"
@moreClick="push({ url: '/pages/newGoods/newGoods' })"
>
<TwoRowGoodRow :products="props.products"></TwoRowGoodRow>
</activity>
</template>
<style
scoped
lang="scss"
>
@import "@/style/main.scss";
.goods-row {
@include usePadding(30, 20);
border-radius: 15rpx;
}
</style>

View File

@ -0,0 +1,31 @@
import sp from "@/static/images/sp.png"
import pt from "@/static/images/pt.png"
import ms from "@/static/images/ms.png"
import kj from "@/static/images/kj.png"
export const menuList = [
{
id: 1,
label: '全部商品',
icon: sp,
path: '/pages/goodsList/goodsList'
},
{
id: 2,
label: '拼团专区',
icon: pt,
path: ''
},
{
id: 3,
label: '秒杀专区',
icon: ms,
path: ''
},
{
id: 4,
label: '砍价专区',
icon: kj,
path: ''
},
]

View File

@ -0,0 +1,93 @@
<!--
@name: 宫格菜单
@author: kahu4
@date: 2023-11-02 15:35
@descriptionindex
@update: 2023-11-02 15:35
-->
<script setup>
import { useRouter } from "@/hooks/useRouter";
import { menuList } from "@/pages/index/components/GridMenu/index.data";
import { useInterface } from "@/hooks/useInterface";
const {push} = useRouter()
const {toast} = useInterface()
function handleClickItem(menu) {
if (!menu.path) return toast({title:'😒敬请期待😒'})
// todo 这里可以通过判断menu.path去处理跳转参数
push({url: menu.path})
}
</script>
<template>
<blank size="15"></blank>
<view class="menu-container">
<view class="menu-inner">
<template
v-for="menu in menuList"
:key="menu.id"
>
<view
class="menu-inner-item"
@tap="handleClickItem(menu)"
>
<view class="menu-inner-item__icon">
<image
class="image"
:src="menu.icon"
mode="widthFix"
/>
</view>
<view class="menu-inner-item__name">
{{ menu.label }}
</view>
</view>
</template>
</view>
</view>
</template>
<style
scoped
lang="scss"
>
.menu-container {
width: 100%;
padding: 0 35rpx;
box-sizing: border-box;
.menu-inner {
display: flex;
align-items: center;
height: 144rpx;
background: #fff;
border-radius: 15rpx;
&-item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.image {
width: 50rpx;
height: 50rpx;
display: block;
}
&__name {
margin-top: 18rpx;
line-height: 32rpx;
font-size: 24rpx;
color: #333333;
}
}
}
}
</style>

View File

@ -0,0 +1,38 @@
<!--
@name: index
@author: kahu4
@date: 2023-11-01 15:38
@descriptionindex
@update: 2023-11-01 15:38
-->
<script setup>
import { useRouter } from "@/hooks/useRouter";
import ScrollGoodRow from "@/pages/index/components/public/ScrollGoodRow.vue"
const props = defineProps({
products: {
type: Array
}
})
const {push} = useRouter()
</script>
<template>
<blank size="15"></blank>
<activity
title="超值拼团"
subtitle="拼着买更划算"
more="查看更多"
@moreClick="push({ url: '/pages/newGoods/newGoods' })"
>
<ScrollGoodRow :products="props.products" />
</activity>
</template>
<style
scoped
lang="scss"
>
</style>

View File

@ -0,0 +1,30 @@
<!--
@name: index
@author: kahu4
@date: 2023-11-01 17:02
@descriptionindex
@update: 2023-11-01 17:02
-->
<script setup>
import LiveCards from "@/pages/index/components/public/LiveCards.vue"
</script>
<template>
<blank size="15"></blank>
<activity
title="热门直播"
more="查看更多"
@moreClick="push({ url: '/pages/newGoods/newGoods' })"
>
<LiveCards></LiveCards>
</activity>
<blank size="30"></blank>
</template>
<style
scoped
lang="scss"
>
</style>

View File

@ -0,0 +1,51 @@
<!--
@name: 新品首发
@author: kahu4
@date: 2023-10-27 14:42
@descriptionindex
@update: 2023-10-27 14:42
-->
<script setup>
import ThreeGoodRow from "@/pages/index/components/public/ThreeGoodRow.vue"
import { useRouter } from "@/hooks/useRouter";
import Card from "@/components/card/card.vue";
const props = defineProps({
products: {
type: Array
}
})
const {push} = useRouter()
</script>
<template>
<blank size="15"></blank>
<activity
title="新品首发"
subtitle="超多人想要"
more="更多新品"
@moreClick="push({ url: '/pages/newGoods/newGoods' })"
>
<view class="card goods-row">
<ThreeGoodRow :products="props.products"></ThreeGoodRow>
</view>
</activity>
</template>
<style
scoped
lang="scss"
>
@import "@/style/main.scss";
.goods-row {
@include usePadding(30, 20);
border-radius: 15rpx;
}
</style>

View File

@ -0,0 +1,88 @@
<!--
@name: 新品首发
@author: kahu4
@date: 2023-10-27 14:42
@descriptionindex
@update: 2023-10-27 14:42
-->
<script setup>
import { onLoad } from '@dcloudio/uni-app'
import { usePage } from "@/hooks";
import { getProductList } from "@/api/product";
import Empty from "@/components/Empty/index.vue"
import ListLoadOver from "@/components/ListLoadOver/index.vue"
import ListLoadLoading from "@/components/ListLoadLoading/index.vue"
import { useRouter } from "@/hooks/useRouter";
const {refresh, dataList, loadend, loading, listEmpty} = usePage(getProductList)
const {push} = useRouter()
onLoad(() => {
refresh()
})
</script>
<template>
<blank size="15"></blank>
<activity
title="商品推荐"
more="查看更多"
@moreClick="push({ url: '/pages/goodsList/goodsList' })"
>
<view class="card goods-row">
<template v-if="!listEmpty">
<uv-grid
:border="false"
:col="2"
:gutter="10"
>
<uv-grid-item
v-for="(item, index) in dataList"
:key="index"
>
<goods
class="item"
link
card
:data="item"
:storeName="item.storeName"
:price="item.price"
:stock="true"
>
</goods>
</uv-grid-item>
</uv-grid>
</template>
<Empty
v-else
:iconSrc="emptyIcon"
>
这里空空如也~
</Empty>
<!-- 加载中 -->
<ListLoadLoading v-if="loading" />
<!-- 加载完毕-->
<ListLoadOver v-if="loadend" />
</view>
</activity>
</template>
<style
scoped
lang="scss"
>
@import "@/style/main.scss";
.goods-row {
@include usePadding(20, 20);
border-radius: 15rpx;
.item {
width: 100%;
margin: 0 10rpx;
}
}
</style>

View File

@ -0,0 +1,47 @@
<!--
@name: 新品首发
@author: kahu4
@date: 2023-10-27 14:42
@descriptionindex
@update: 2023-10-27 14:42
-->
<script setup>
import ThreeGoodRow from "@/pages/index/components/public/ThreeGoodRow.vue"
import { useRouter } from "@/hooks/useRouter";
const props = defineProps({
products: {
type: Array
}
})
const {push} = useRouter()
</script>
<template>
<blank size="15"></blank>
<activity
title="限时秒杀"
more="查看更多"
@moreClick="push({ url: '/pages/newGoods/newGoods' })"
>
<template #subTitle>限时秒杀</template>
<card class="goods-row">
<ThreeGoodRow :products="props.products"></ThreeGoodRow>
</card>
</activity>
</template>
<style
scoped
lang="scss"
>
@import "@/style/main.scss";
.goods-row {
@include usePadding(30, 20);
border-radius: 15rpx;
}
</style>

View File

@ -0,0 +1,27 @@
import Bargain from "./Bargain/index.vue"
import Banner from "./Banner/index.vue"
import GridMenu from "./GridMenu/index.vue"
import Group from "./Group/index.vue"
import Live from "./Live/index.vue"
import NewProduct from "./NewProduct/index.vue"
import Seckill from "./Seckill/index.vue"
import HomeGoodItem from "./public/HomeGoodItem.vue"
import LiveCards from "./public/LiveCards.vue"
import ScrollGoodRow from "./public/ScrollGoodRow.vue"
import ThreeGoodRow from "./public/ThreeGoodRow.vue"
import TwoRowGoodRow from "./public/TwoRowGoodRow.vue"
export {
Bargain,
Banner,
GridMenu,
Group,
Live,
NewProduct,
Seckill,
HomeGoodItem,
LiveCards,
ScrollGoodRow,
ThreeGoodRow,
TwoRowGoodRow
}

View File

@ -0,0 +1,130 @@
<!--
@name: HomeGoodItem
@author: kahu4
@date: 2023-10-27 14:47
@descriptionHomeGoodItem
@update: 2023-10-27 14:47
-->
<script setup>
import { useRouter } from "@/hooks/useRouter";
const {push} = useRouter()
const props = defineProps({
good: {
type: Object
},
size: {
type: String,
default: 'small'
},
mode: {
type: String,
default: 'col'
}
})
const toDetail = () => {
push({url: '/pages/goodsDetail/goodsDetail'}, {
data: {
id: props.good.id
}
})
}
</script>
<template>
<view
:class="{'good-item':true,row:props.mode==='row'}"
@tap="toDetail"
>
<view class="image">
<image
:src="props.good.image"
mode="aspectFill"
/>
</view>
<view
class="info-box"
:class="{'padding-box':props.size==='big'}"
>
<view class="title-row">
{{ props.good.storeName }}
</view>
<view class="price-row">
<slot
name="bottom"
:good="good"
>底部
</slot>
</view>
</view>
</view>
</template>
<style
scoped
lang="scss"
>
.good-item {
position: relative;
width: 100%;
.image {
width: 100%;
aspect-ratio: 1 / 1;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}
.info-box {
width: 100%;
.title-row {
margin: 14rpx 0;
max-width: 25vw;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-weight: 500;
font-size: 26rpx;
}
}
.padding-box {
box-sizing: border-box;
padding: 14rpx 20rpx;
}
}
.row {
display: flex;
align-items: center;
padding: 16rpx;
box-sizing: border-box;
background: #fff;
margin-bottom: 20rpx;
border-radius: 15rpx;
.image {
width: 220rpx;
}
.info-box {
padding: 20rpx 40rpx;
box-sizing: border-box;
height: 220rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title-row {
margin-bottom: 30rpx;
}
}
}
</style>

View File

@ -0,0 +1,234 @@
<!--
@name: LiveCards
@author: kahu4
@date: 2023-11-01 17:04
@descriptionLiveCards
@update: 2023-11-01 17:04
-->
<script setup>
import { computed, onMounted, ref, unref } from "vue";
import { useSystem } from "@/hooks/useSystem";
const liveCardList = [
{
id: 1,
isLive: true,
title: '买一送一',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 168
},
{
id: 2,
isLive: false,
title: '买一送二',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 16858
},
{
id: 3,
isLive: true,
title: '买一送三',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 22343
},
{
id: 4,
isLive: true,
title: '买一送三',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 22343
},
{
id: 4,
isLive: true,
title: '买一送三',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 22343
},
{
id: 4,
isLive: true,
title: '买一送三',
background: 'https://alipic.lanhuapp.com/XDSlicePNGMAXc18a81ef73fc74664ef83df1de77da21f12619ff86653931ed809710b31c2e82.png',
peopleNum: 22343
}
]
const {getSystemInfo} = useSystem();
// ============================== 设置card选中相关 ================================
const current = ref(1) // 当前选中的索引
const systemInfo = ref({windowWidth: 0}) // 系统信息
const scrollLeft = ref(0) // 当前滑动到的位置
const scrollWidth = ref(0) // 滑轨总大小
// 计算单张宽度
const cardWidth = computed(() => {
if (unref(systemInfo).windowWidth <= 0) return 0
return Math.floor((unref(systemInfo).windowWidth) / 3) - 25
})
/**
* 滑动
* @param e
*/
function handleScroll(e) {
scrollLeft.value = e.detail.scrollLeft
scrollWidth.value = e.detail.scrollWidth
setCurrent()
}
/**
* 设置选中card
* @returns {number}
*/
function setCurrent() {
// 小于单张宽度直接设置1选中第2张
if (scrollLeft.value <= cardWidth.value) return current.value = 1
// 否则 current = (当前位置 / 单张宽度)= 当前屏幕左侧顶到图片的索引
// +1选中后一张
current.value = Math.floor(scrollLeft.value / cardWidth.value) + 1
}
function clickCard() {
}
onMounted(async () => {
systemInfo.value = await getSystemInfo()
})
</script>
<template>
<view class="live-cards">
<scroll-view
class="live-cards__inner"
scroll-x
@scroll="handleScroll"
>
<view class="track">
<view
:class="{'card-item':true,'current':index===current}"
v-for="(item,index) in liveCardList"
:key="item.id"
@click="clickCard"
>
<image
class="live-img"
:src="item.background"
mode="aspectFill"
/>
<view class="mask">
<view :class="{'status-box':true}">
<view :class="{status:true,close:item.isLive===false}">
{{ item.isLive ? '直播中' : '暂未开始' }}
</view>
<view class="number">
{{ item.isLive ? item.peopleNum : 0 }}
</view>
</view>
<view class="title">
{{ item.title }}
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<style
scoped
lang="scss"
>
.live-cards {
width: 100%;
padding: 70rpx 0;
aspect-ratio: 750/480;
&__inner {
width: 100%;
height: 100%;
.track {
height: 100%;
display: flex;
align-items: center;
.card-item {
flex-shrink: 0;
width: calc(100% / 3);
height: 80%;
background: #fff;
border-radius: 15rpx;
overflow: hidden;
position: relative;
transition: all .3s;
scale: 1;
z-index: 1;
.live-img {
width: 100%;
height: 100%;
}
.mask {
position: absolute;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
padding: 35rpx 20rpx;
box-sizing: border-box;
color: #fff;
font-size: 18rpx;
.status-box {
position: absolute;
display: flex;
align-items: center;
top: 18rpx;
left: 20rpx;
height: 33rpx;
line-height: 33rpx;
border-radius: 33rpx;
background: rgba(0, 0, 0, 0.6);
.status {
background: #ee6d46;
border-radius: 33rpx;
padding: 0 10rpx;
}
.close {
background: grey;
}
.number {
padding: 0 1rpx;
}
}
.title {
font-size: 28rpx;
position: absolute;
width: 100%;
color: #fff;
left: 20rpx;
bottom: 20rpx;
}
}
}
.current {
scale: 1.2 1.2;
z-index: 11;
}
}
}
}
</style>

View File

@ -0,0 +1,107 @@
<!--
@name: ScrollGoodRow
@author: kahu4
@date: 2023-11-01 15:56
@descriptionScrollGoodRow
@update: 2023-11-01 15:56
-->
<script setup>
import Goods from "@/components/goodsComponents/Goods.vue";
import Options from "@/components/goodsComponents/components/Options.vue";
const props = defineProps({
products: {
type: Array
}
})
</script>
<template>
<scroll-view
scroll-x
class="scroll-view"
>
<view
class="scroll-inner"
>
<template
v-for="good in props.products"
:key="good.id"
>
<Goods
class="scroll-item"
info-padding="15rpx 20rpx"
:goods="good"
>
<template #options>
<Options
:goods="good"
show-btn
></Options>
</template>
</Goods>
</template>
</view>
</scroll-view>
</template>
<style
scoped
lang="scss"
>
.scroll-view {
width: 100%;
overflow: hidden;
.scroll-inner {
display: flex;
flex-wrap: nowrap;
gap: 20rpx;
.scroll-item {
flex-shrink: 0;
max-width: 290rpx;
background: #fff;
border-radius: 15rpx;
overflow: hidden;
.good-bottom {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20rpx;
.price {
color: #EE6D46;
font-size: 30rpx;
.tip {
color: #999999;
font-size: 24rpx;
}
}
.sale {
color: #999999;
}
.btn {
background: #ee6d46;
color: #fff;
font-size: 24rpx;
padding: 10rpx 24rpx;
transition: all .3s;
&:active {
transform-origin: right bottom;
scale: .9;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,87 @@
<!--
@name: 一行三个
@author: kahu4
@date: 2023-10-27 14:47
@descriptionTreeGoodRow
@update: 2023-10-27 14:47
-->
<script setup>
import Goods from "@/components/goodsComponents/Goods.vue";
import Options from "@/components/goodsComponents/components/Options.vue";
import { useRouter } from "@/hooks/useRouter";
const props = defineProps({
products: {
type: Array
}
})
const {push} = useRouter()
const toDetail = (id) => {
push({url: '/pages/goodsDetail/goodsDetail'}, {
data: {
id
}
})
}
</script>
<template>
<view class="three-row">
<template v-for="item in props.products">
<view class="good-item">
<Goods
:goods="item"
@click="toDetail(item.id)"
>
<template #options>
<Options :goods="item"></Options>
</template>
</Goods>
</view>
</template>
</view>
</template>
<style
scoped
lang="scss"
>
.three-row {
width: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10rpx;
.good-item {
position: relative;
width: 31%;
}
.good-bottom {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20rpx;
.price {
color: #EE6D46;
font-size: 30rpx;
.tip {
color: #999999;
font-size: 24rpx;
}
}
.sale {
color: #999999;
}
}
}
</style>

View File

@ -0,0 +1,96 @@
<!--
@name: 两行商品
@author: kahu4
@date: 2023-11-01 16:49
@descriptionTwoRowGoodROw
@update: 2023-11-01 16:49
-->
<script setup>
import Goods from "@/components/goodsComponents/Goods.vue";
import Options from "@/components/goodsComponents/components/Options.vue";
const props = defineProps({
products: {
type: Array
}
})
</script>
<template>
<view
class="two-row"
v-if=" props.products"
>
<template v-for="item in props.products.slice(0,2)">
<view class="row-item">
<Goods
row
:goods="item"
img-width="220rpx"
info-padding="20rpx 20rpx"
>
<template #options>
<Options
style="width: 100%;"
:goods="item"
btn-text="立即抢购"
show-btn
></Options>
</template>
</Goods>
</view>
</template>
</view>
</template>
<style
scoped
lang="scss"
>
.two-row {
width: 100%;
.row-item {
@include usePadding(15, 14);
background: #fff;
margin: 20rpx 0;
border-radius: 15rpx;
}
.good-bottom {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20rpx;
.price {
display: flex;
align-items: center;
color: #EE6D46;
font-size: 30rpx;
.tip {
color: #999999;
font-size: 24rpx;
}
}
.sale {
color: #999999;
}
.btn {
background: #ee6d46;
color: #fff;
font-size: 24rpx;
padding: 10rpx 24rpx;
transition: all .3s;
&:active {
transform-origin: right bottom;
scale: .9;
}
}
}
}
</style>