377 lines
8.9 KiB
Vue
377 lines
8.9 KiB
Vue
<template>
|
||
<view class="u-relative u-flex item">
|
||
<up-image :src="data.coverImg" mode="aspectFill" :width="img.width" :height="img.height"></up-image>
|
||
<view class="info u-flex u-row-between u-col-top u-flex-col">
|
||
<view class="limit-discount" v-if="is_time_discount">限时折扣</view>
|
||
<view class="nowStockerNumber" v-if="nowStockerNumber<=10">
|
||
剩余库存:{{nowStockerNumber}}
|
||
</view>
|
||
<view>
|
||
<view>
|
||
<text class="up-line-1">{{ data.name }}</text>
|
||
</view>
|
||
<view>
|
||
<text class="u-font-32 font-bold u-m-t-16" v-if="is_time_discount"> ¥{{ limitPrice }} </text>
|
||
<text class="u-font-32 font-bold u-m-t-16" :class="[is_time_discount ? 'line-through' : '']">
|
||
¥{{ data.lowPrice }}
|
||
</text>
|
||
</view>
|
||
|
||
<template v-if="data.type == 'weight'">
|
||
<view class="btnweigh">称重</view>
|
||
</template>
|
||
</view>
|
||
<view class="u-flex" v-if="!isSellout">
|
||
<template v-if="data.type == 'sku' || data.groupType == 1">
|
||
<button class="btn" hover-class="btn-hover-class" @tap="emitEvent('chooseGuige')">
|
||
选规格
|
||
</button>
|
||
</template>
|
||
<template v-else>
|
||
<view class="u-flex icon-btn">
|
||
<template v-if="data.chooseNumber">
|
||
<view class="u-flex" @tap.stop="emitEvent('reduce')">
|
||
<image src="/pagesCreateOrder/static/images/icon-reduce.svg" class="icon" mode="">
|
||
</image>
|
||
</view>
|
||
<view class="u-font-32">
|
||
{{ data.chooseNumber.toFixed(2) }}
|
||
</view>
|
||
|
||
</template>
|
||
<view class="u-flex" @tap.stop="emitEvent(data.type == 'weight' ? 'tapweigh' : 'add')">
|
||
<image src="/pagesCreateOrder/static/images/icon-add.svg" class="icon" mode=""></image>
|
||
</view>
|
||
|
||
</view>
|
||
</template>
|
||
</view>
|
||
<template v-if="isSellout">
|
||
<view class="isSellout" v-if="data.isSale == 0">
|
||
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-toDown.svg" mode=""></image>
|
||
</view>
|
||
<view class="isSellout" v-else-if="
|
||
!isProductAvailable(data.days, data.startTime, data.endTime)
|
||
">
|
||
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-saleTime.svg" mode=""></image>
|
||
</view>
|
||
<view class="isSellout" v-else-if="data.isSoldStock == 1">
|
||
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-sold.svg" mode=""></image>
|
||
</view>
|
||
<view class="isSellout" v-else>
|
||
<image class="isSellout_icon" src="/pagesCreateOrder/static/images/no-stock.svg" mode=""></image>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
computed,
|
||
toRef,
|
||
inject
|
||
} from "vue";
|
||
import util from "../util.js";
|
||
import dayjs from "dayjs";
|
||
import isBetween from "dayjs/plugin/isBetween.js";
|
||
const yskUtils = inject("yskUtils");
|
||
const shopInfo = inject("shopInfo");
|
||
dayjs.extend(isBetween);
|
||
|
||
const props = defineProps({
|
||
img: {
|
||
type: Object,
|
||
default: {
|
||
width: "250rpx",
|
||
height: "272rpx",
|
||
},
|
||
},
|
||
index: {
|
||
type: [Number, String],
|
||
},
|
||
isSeatFee: {
|
||
//是否为餐位费
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
data: {
|
||
type: Object,
|
||
default: () => {
|
||
return {
|
||
chooseNumber: 0,
|
||
};
|
||
},
|
||
},
|
||
limitTimeDiscount: {
|
||
type: Object,
|
||
default: () => {
|
||
return {};
|
||
},
|
||
},
|
||
consStockList: {
|
||
type: Array,
|
||
default:[]
|
||
}
|
||
});
|
||
|
||
//判断是否是时间折扣商品
|
||
const is_time_discount = computed(() => {
|
||
if (!props.limitTimeDiscount || !props.limitTimeDiscount.id) {
|
||
return false;
|
||
}
|
||
|
||
const isCanuse = yskUtils.limitUtils.canUseLimitTimeDiscount(
|
||
props.data,
|
||
props.limitTimeDiscount,
|
||
shopInfo,
|
||
null,
|
||
"id"
|
||
);
|
||
return isCanuse;
|
||
});
|
||
|
||
const limitPrice = computed(() => {
|
||
if (!is_time_discount.value) {
|
||
return 0;
|
||
}
|
||
console.log("props.data", props.data);
|
||
const price = yskUtils.limitUtils.returnPrice({
|
||
goods: props.data,
|
||
shopInfo: shopInfo,
|
||
limitTimeDiscountRes: props.limitTimeDiscount,
|
||
shopUserInfo: null,
|
||
idKey: "id",
|
||
});
|
||
return price;
|
||
});
|
||
|
||
/**
|
||
* 判断是否是菜品
|
||
*/
|
||
function isGoods() {
|
||
return props.data.hasOwnProperty("id");
|
||
}
|
||
|
||
/**
|
||
* 判断商品是否售尽
|
||
*/
|
||
const isSellout = computed(() => {
|
||
const item = props.data;
|
||
if (!isGoods()) {
|
||
return false;
|
||
}
|
||
return (
|
||
!consStockisFull(item) ||
|
||
item.isSoldStock == 1 ||
|
||
item.isSale == 0 ||
|
||
!isProductAvailable(item.days, item.startTime, item.endTime)
|
||
);
|
||
});
|
||
const stockNumber=computed(()=>{
|
||
|
||
})
|
||
|
||
// 1. 筛选匹配的耗材列表
|
||
const conslist=computed(()=>{
|
||
if(props.consStockList.length<=0){
|
||
return []
|
||
}
|
||
return props.consStockList.filter(v => {
|
||
return props.data.consList.find(i =>{
|
||
return i.consInfoId == v.consId
|
||
});
|
||
});
|
||
})
|
||
// 2. 找到 stockNumber 最小的那一项
|
||
const minConsItem=computed(()=>{
|
||
if(conslist.value.length<=0){
|
||
return null
|
||
}
|
||
return conslist.value.reduce((prev, current) => {
|
||
return prev.stockNumber < current.stockNumber ? prev : current;
|
||
});
|
||
})
|
||
// 3. 找到和 minItem 的 consId 一样的那个消耗配置项
|
||
const targetCons=computed(()=>{
|
||
if(!minConsItem.value){
|
||
return null
|
||
}
|
||
return props.data.consList.find(i => i.consInfoId == minConsItem.value.consId);
|
||
})
|
||
const nowStockerNumber=computed(()=>{
|
||
if(!targetCons.value||!minConsItem.value){
|
||
return 9999
|
||
}
|
||
return Math.floor(minConsItem.value.stockNumber/targetCons.value.surplusStock)
|
||
})
|
||
function consStockisFull(item) {
|
||
// 无数据直接返回 true(或按你需求返回 false)
|
||
if (!conslist.value.length) return true;
|
||
|
||
if(!minConsItem.value)return true;
|
||
|
||
if(!targetCons.value) return true;
|
||
|
||
// 4. 判断:最小库存 > 每份消耗库存 → 返回 true,否则 false
|
||
if (nowStockerNumber.value>=1) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
// 判断商品是否在可售时间内
|
||
function isProductAvailable(sellDaysStr, startTimeStr, endTimeStr) {
|
||
// 将后端返回的字符串转换为数组
|
||
const sellDays = sellDaysStr.split(",");
|
||
const now = dayjs();
|
||
const days = [
|
||
"Sunday",
|
||
"Monday",
|
||
"Tuesday",
|
||
"Wednesday",
|
||
"Thursday",
|
||
"Friday",
|
||
"Saturday",
|
||
];
|
||
const currentDay = days[now.day()];
|
||
const currentTime = now.format("HH:mm:ss"); // 检查当前周几是否在可售周几列表中
|
||
|
||
// console.log('当前日期:', currentDay);
|
||
// console.log('可售日期列表:', sellDays);
|
||
if (!sellDays.includes(currentDay)) {
|
||
// console.log('当前日期不在可售日期列表中');
|
||
return false;
|
||
}
|
||
const startTime = dayjs(`${now.format("YYYY-MM-DD")} ${startTimeStr}`);
|
||
let endTime = dayjs(`${now.format("YYYY-MM-DD")} ${endTimeStr}`);
|
||
// 处理跨天情况
|
||
if (endTime.isBefore(startTime)) {
|
||
endTime = endTime.add(1, "day");
|
||
} // console.log('开始时间:', startTime.format('YYYY-MM-DD HH:mm:ss')); // console.log('结束时间:', endTime.format('YYYY-MM-DD HH:mm:ss'));
|
||
|
||
// console.log('当前时间:', now.format('YYYY-MM-DD HH:mm:ss'));
|
||
const isInRange = now.isBetween(startTime, endTime, null, "[)"); // console.log('当前时间是否在可售时间范围内:', isInRange);
|
||
return isInRange;
|
||
}
|
||
|
||
const emits = defineEmits(["add", "reduce", "chooseGuige", "tapweigh"]);
|
||
|
||
function emitEvent(emitName) {
|
||
if (isGoods()) {
|
||
emits(emitName, props.index);
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.icon {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
}
|
||
|
||
.icon-btn {
|
||
gap: 14rpx;
|
||
}
|
||
|
||
.btn {
|
||
background: #eb4f4f;
|
||
border-radius: 100rpx;
|
||
font-size: 28rpx;
|
||
height: 56rpx;
|
||
line-height: 56rpx;
|
||
color: #fff;
|
||
}
|
||
|
||
.btnweigh {
|
||
margin: 5rpx 0;
|
||
width: 100rpx;
|
||
background: linear-gradient(124deg, #73c969 6%, #27921b 93%);
|
||
border-radius: 10rpx;
|
||
font-size: 24rpx;
|
||
padding: 6rpx 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.btn-hover-class {
|
||
opacity: 0.6;
|
||
}
|
||
|
||
image {
|
||
will-change: transform;
|
||
}
|
||
|
||
.item {
|
||
// width: 250rpx;
|
||
// height: 272rpx;
|
||
background: #f9b798;
|
||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||
overflow: hidden;
|
||
|
||
.img {
|
||
width: 250rpx;
|
||
height: 272rpx;
|
||
}
|
||
|
||
.info {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
color: #fff;
|
||
padding: 52rpx 24rpx 24rpx 24rpx;
|
||
top: 0;
|
||
background: rgba(37, 22, 15, 0.5);
|
||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||
overflow: hidden;
|
||
}
|
||
}
|
||
|
||
.isSellout {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
.isSellout_icon {
|
||
height: 60%;
|
||
width: 60%;
|
||
}
|
||
}
|
||
|
||
.limit-discount {
|
||
background-color: #cc5617;
|
||
padding: 10rpx 20rpx;
|
||
white-space: nowrap;
|
||
text-align: center;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
font-weight: 400;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
border-radius: 0 0rpx 20rpx 0rpx;
|
||
color: #fff;
|
||
}
|
||
|
||
.line-through {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
text-decoration: line-through;
|
||
}
|
||
.nowStockerNumber{
|
||
position: absolute;
|
||
left: 24rpx;
|
||
bottom: 80rpx;
|
||
background-color: rgba(255, 255, 255, .8);
|
||
color: red;
|
||
padding: 4rpx 8rpx;
|
||
font-size: 24rpx;
|
||
border-radius: 4rpx ;
|
||
}
|
||
</style> |