feat(产品)

This commit is contained in:
unknown 2024-05-27 00:51:03 +08:00
parent dbd3b1f839
commit 78d6d7df1f
3 changed files with 271 additions and 13 deletions

View File

@ -1,20 +1,69 @@
<template>
<pb-layout
title="分类"
navbar="normal"
tabbar="/pages/index/category"
:bgStyle="bgStyle"
opacityBgUi="bg-white"
color="black"
>
<p-empty icon="/static/soldout-empty.png" text="暂无内容" />
</pb-layout>
<pb-layout title="产品" navbar="normal" tabbar="/pages/index/product" :bgStyle="bgStyle" opacityBgUi="bg-white"
color="black">
<view v-if="StaticRange.pagination.total > 0" class="goods-list ss-m-t-20">
<view class="ss-p-l-20 ss-p-r-20" v-for="item in state.pagination.list" :key="item.id">
<p-goods-column size="lg" :data="item" :topRadius="10" bottomRadius="10"
@click="peach.$router.go('/pages/goods/index', { id: item.id })" />
</view>
</view>
<uni-load-more v-if="StaticRange.pagination.total > 0" :status="StaticRange.loadStatus" :content-text="{
contentdown: '上拉加载更多'
}" @click="loadMore" />
<p-empty v-if="StaticRange.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无产品" />
</pb-layout>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import peach from '@/peach'
import _ from 'lodash'
import { resetPagination } from '@/peach/util'
const bgStyle = {
backgroundImage: '',
backgroundColor: '',
description: '',
backgroundImage: '',
backgroundColor: '',
description: '',
}
const state = ref({
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 6
}
})
function emptyList() {
resetPagination(state.value.pagination)
}
function onSearch() {
emptyList()
getList()
}
function getList() {
}
function loadMore() {
if (state.value.loadStatus === 'noMore') {
return
}
state.value.pagination.pageNo++
getList()
}
onLoad(async (options) => {
getList()
})
onReachBottom(() => {
loadMore()
})
</script>

View File

@ -0,0 +1,176 @@
<template>
<view class="ss-goods-wrap">
<view v-if="size === 'lg'" class="lg-goods-card ss-flex ss-col-stretch" :style="[elStyles]" @click="onClick">
<image class="lg-img-box" :src="peach.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image>
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
<view>
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]">
{{ data.title || data.name }}
</view>
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]">
{{ data.subtitle || data.introduction }}
</view>
</view>
<view>
<view class="ss-flex ss-col-bottom ss-m-t-10">
<view v-if="goodsFields.price?.show" class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]">
<text class="ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="(goodsFields.original_price?.show || goodsFields.marketPrice?.show) && (data.original_price > 0 || data.marketPrice > 0)"
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS" :style="[{ color: originPriceColor }]">
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
</view>
<view>
<button>详情</button>
<button>编辑</button>
<button>删除</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { isArray } from 'lodash';
import { fen2yuan, formatSales, formatStock } from '@/peach/hooks/useGoods';
const props = defineProps({
goodsFields: {
type: [Array, Object],
default() {
return {
price: { show: true },
stock: { show: true },
name: { show: true },
introduction: { show: true },
marketPrice: { show: true },
salesCount: { show: true }
}
}
},
data: {
type: Object,
default: {}
},
size: {
type: String,
default: ''
},
topRadius: {
type: Number,
default: 0,
},
bottomRadius: {
type: Number,
default: 0,
},
priceUnit: {
type: String,
default: '¥',
},
titleColor: {
type: String,
default: '#333',
},
subTitleColor: {
type: String,
default: '#999999',
},
subTitleBackground: {
type: String,
default: '',
},
})
const emits = defineEmits(['click'])
function onClick() {
emits('click')
}
const elStyles = computed(() => {
return {
background: props.background,
'border-top-left-radius': props.topRadius + 'px',
'border-top-right-radius': props.topRadius + 'px',
'border-bottom-left-radius': props.bottomRadius + 'px',
'border-bottom-right-radius': props.bottomRadius + 'px',
}
})
//
const salesAndStock = computed(() => {
let text = [];
if (props.goodsFields.salesCount?.show) {
text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
}
if (props.goodsFields.stock?.show) {
text.push(formatStock(props.data.stock_show_type, props.data.stock));
}
return text.join(' | ');
});
</script>
<style lang="scss" scoped>
.lg-goods-card {
overflow: hidden;
position: relative;
z-index: 1;
background-color: $white;
height: 280rpx;
.lg-img-box {
width: 280rpx;
height: 280rpx;
margin-right: 20rpx;
}
.lg-goods-title {
font-size: 28rpx;
font-weight: 500;
color: #333333;
// line-height: 36rpx;
// width: 410rpx;
}
.lg-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
// line-height: 30rpx;
// width: 410rpx;
}
.lg-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.buy-box {
position: absolute;
bottom: 20rpx;
right: 20rpx;
z-index: 2;
width: 120rpx;
height: 50rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 25rpx;
font-size: 24rpx;
color: #ffffff;
}
}
</style>

33
peach/hooks/useGoods.js Normal file
View File

@ -0,0 +1,33 @@
import { ref } from "vue";
import dayjs from "dayjs";
/**
* 将分转成元
*
* @param price 例如说 100
* @returns {string} 例如说 1.00
*/
export function fen2yuan(price) {
return (price / 100.0).toFixed(2);
}
/**
* 格式化销量
* @param {'exact' | string} type 格式类型exact=精确值其它=大致数量
* @param {number} num 销量
* @return {string} 格式化后的销量字符串
*/
export function formatSales(type, num) {
let prefix = type !== "exact" && num < 10 ? "销量" : "已售";
return formatNum(prefix, type, num);
}
/**
* 格式化库存
* @param {'exact' | any} type 格式类型exact=精确值其它=大致数量
* @param {number} num 销量
* @return {string} 格式化后的销量字符串
*/
export function formatStock(type, num) {
return formatNum("库存", type, num);
}