This commit is contained in:
2025-04-02 10:35:17 +08:00
commit 89db955ec1
701 changed files with 91082 additions and 0 deletions

View File

@@ -0,0 +1,536 @@
<template>
<view class="mask" @tap="hideGoods" v-if="switchGoods">
</view>
<view class="fixed goods-box u-flex u-flex-col" :class="{active:switchGoods}" @tap.stop="nullFun">
<view class="u-row-between top u-flex">
<view class="u-flex">
<view>
<up-icon name="shopping-cart-fill" size="20" color="rgb(102,102,102)"></up-icon>
</view>
<view class="u-m-l-10">
已选菜品({{goodsNumber}})
</view>
</view>
<view class="u-flex" @click="setModalShow('clear',true)">
<view>
<up-icon name="trash-fill" size="20" color="rgb(102,102,102)"></up-icon>
</view>
<view class="u-m-l-10">
清空点餐
</view>
</view>
<view class="u-flex">
<view>合计:</view>
<view class="u-m-l-10 color-red font-bold allPrice">{{allPrice}}</view>
<view class=""></view>
</view>
</view>
<scroll-view scroll-y="true" class=" u-flex-1 ">
<view class=" ">
<view class="color-333item border-bottom u-p-l-20 u-p-r-20 u-p-b-10 u-p-t-20 u-flex u-row-center u-row-between"
v-for="(item,index) in data" :key="index">
<view class="u-flex u-col-top">
<view class="u-p-r-20">
{{index+1}}
</view>
<view class="">
<view>{{item.name}}</view>
<view class="u-m-t-10 u-font-24 color-666">{{item.specSnap||''}}</view>
<view class="u-flex u-m-t-14">
<up-icon name="edit-pen" @click="showModel('remark',index)" color="#333" size="16"></up-icon>
<view class="color-666 u-font-24">
{{item.note}}
</view>
</view>
</view>
</view>
<view class="u-flex">
<view class="font-bold red u-m-r-32">{{formatPrice(item.salePrice*item.number) }}</view>
<view class="u-flex" @tap="updateNumber(false,index,item)">
<image src="/pagesCreateOrder/static/images/icon-reduce-black.svg" class="icon" mode="">
</image>
</view>
<view class="u-p-l-30 u-p-r-30 color-333" style="">
{{item.number}}
</view>
<view class="u-flex" @tap="updateNumber(true,index,item)">
<image src="/pagesCreateOrder/static/images/icon-add-black.svg" class="icon" mode="">
</image>
</view>
</view>
</view>
<my-empty v-if="!data.length" text="暂未有添加商品"></my-empty>
</view>
</scroll-view>
<view class="u-row-between bottom u-flex">
<view class="u-flex" @click="hideGoods">
<view>
<up-icon name="arrow-left" size="14" color="#333"></up-icon>
</view>
<view class="u-m-l-10">
返回
</view>
</view>
<view class="u-flex luodan" @click="toConfimOrder">
<view>落单</view>
</view>
</view>
</view>
<view class="car u-flex u-row-between u-col-bottom u-relative" @touchmove.stop.prevent="moveHandle"
:style="{transform: 'translateY(' + offset.y + 'px)'}" @touchstart="touchstart"
@touchmove="touchmove" @touchend="touchend">
<view class="u-absolute goods bg-fff">
<view
class="u-p-t-32 color-666 border-bottom bg-fff u-absolute total u-p-r-28 u-p-b-32 u-p-l-28 u-flex u-row-between">
<view>已添加{{goodsNumber}}件商品</view>
<view class="color-666" @tap="setModalShow('clear',true)">
<uni-icons color="#666" type="trash"></uni-icons>
<text class="u-m-l-10">清空</text>
</view>
</view>
</view>
<view class="icon-car-box" @tap="toggleGoods">
<image src="/pagesCreateOrder/static/images/icon-car.svg" class="icon-car" />
<view class="dot">{{goodsNumber}}</view>
</view>
<!-- <view class="price font-bold u-flex">
<view></view>
<view>{{allPrice}}</view>
</view> -->
<!-- <my-button shape="circle" height="80" width="220" @tap="toConfimOrder">
<text class="u-font-32 font-bold">{{table.type=='add'?'确认加菜':'去下单'}} </text>
</my-button> -->
</view>
<up-modal title="提示" content="是否清空全部已添加的商品?" :show="modal.clear" showCancelButton closeOnClickOverlay
@confirm="confirmModelConfirm" @cancel="setModalShow('clear',false)" @close="setModalShow('clear',false)"
width="300px"></up-modal>
<one-remark width="400px" @confirm="goodsOneRemarkConfirm" title="单品备注" :ref="setModel" name="remark"></one-remark>
</template>
<script setup>
import go from '@/commons/utils/go.js';
import infoBox from '@/commons/utils/infoBox.js';
import oneRemark from '/pagesCreateOrder/confirm-order/components/remark'
import {
formatPrice
} from '@/commons/utils/format.js';
import {
getElRect
} from '@/commons/utils/safe-bottom.js'
import * as Api from '@/http/yskApi/Instead.js'
import {
computed,
ref,
onMounted,
reactive,
watch
} from 'vue';
const props = defineProps({
sysInfo:{
type: Object,
default:()=>{
return {
windowWidth: 0,
windowHeight: 0,
statusBarHeight:0
}
}
},
instance: {
type: Object,
default: {
}
},
data: {
type: Array,
default: () => {
return []
}
},
isCreateOrderToDetail: {
type: Boolean,
default: false
},
user: {
type: Object,
default: () => {
return {
id: ""
}
}
},
table: {
type: Object,
default: () => {
return {
tableId: ''
}
}
},
masterId: {
type: [String, Number],
default: ''
}
})
const edmits = defineEmits(['clear', 'updateNumber', 'updateSafeBottom','updateCart'])
const modal = reactive({
key: '',
clear: false
})
const models = new Map();
const modelData = reactive({
data: {},
selIndex: -1
})
//备注
let note = ref('')
function setModel(el) {
if (el && el.$attrs['name']) {
models.set(el.$attrs['name'], el);
}
}
function showModel(key, index) {
modelData.data = props.data[index]
modelData.selIndex = index
const model = models.get(key)
model && model.open({
remark: modelData.data.note||''
})
}
function confirmModelConfirm() {
if (modal.key == 'clear') {
clear()
}
}
//单品备注确认
async function goodsOneRemarkConfirm(e) {
const cart = props.data[modelData.selIndex]
await Api.$updateCart({
cartId: cart.id,
productId: cart.productId,
skuId: cart.skuId,
tableId: props.table.tableId,
note: e.remark,
num: cart.number // 0会删除此商品
})
edmits('updateCart')
}
function setModalShow(key = 'show', show = true) {
if (key == 'clear' && show && props.data.length <= 0) {
return infoBox.showToast('购物车是空的!')
}
modal.key = key
modal[key] = show
console.log(modal);
}
function nullFun() {
}
// mask
let switchGoods = ref(false)
function hideGoods() {
switchGoods.value = false
}
function showGoods() {
switchGoods.value = true
}
function toggleGoods() {
switchGoods.value = !switchGoods.value
}
function toConfimOrder() {
console.log(props.user);
if (props.data.length <= 0) {
return infoBox.showToast('还没有选择商品')
}
const {
tableId,
name,
maxCapacity,
status,
type
} = props.table
if (props.table.tableId == '') {
go.to('PAGES_CONFIRM_ORDER', {
masterId: props.masterId,
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0
})
}else{
go.to('PAGES_CONFIRM_ORDER', {
masterId: props.masterId,
type,
tableId,
name,
maxCapacity,
status,
isCreateOrderToDetail: props.isCreateOrderToDetail ? 1 : 0
})
}
hideGoods()
}
const allPrice = computed(() => {
return props.data.reduce((prve, cur) => {
return prve + cur.salePrice * cur.number
}, 0).toFixed(2)
})
const goodsNumber = computed(() => {
let result = 0
result = props.data.reduce((prve, cur) => {
return prve + cur.number
}, 0)
return result >= 99 ? 99 : result
})
function updateNumber(isAdd, index, goods) {
const step = isAdd ? 1 : -1
const newval = goods.number + step
const par = {
num: newval,
index: index,
goods: goods
}
edmits('updateNumber', par)
}
const offset = ref({
x: 0,
y: (props.sysInfo.windowHeight-70-40)/2
})
const startPoint = ref({
x: 0,
y: 0
})
watch(()=>props.sysInfo.windowHeight,(newval)=>{
console.log('---------');
console.log(newval);
offset.value.y=(newval-70-40)/2
})
function touchstart(event) {
startPoint.value = {
x: event.touches[0].clientX,
y: event.touches[0].clientY
};
}
function touchmove(event) {
const currentPoint = {
x: event.touches[0].clientX,
y: event.touches[0].clientY
};
const delta = {
x: currentPoint.x - startPoint.value.x,
y: currentPoint.y - startPoint.value.y
};
const minY=props.sysInfo.statusBarHeight||0 ,maxY=props.sysInfo.windowHeight-70-40;
let newY=offset.value.y + delta.y
if(newY>maxY){
newY=maxY
}
if(newY<minY){
newY=minY
}
offset.value = {
// x: offset.value.x + delta.x,
y: newY
};
startPoint.value = currentPoint;
}
function moveHandle() {
return false
}
function touchend(e) {
// 触摸结束时重置起始坐标
}
function clear() {
setModalShow('clear', false)
edmits('clear')
hideGoods()
}
onMounted(() => {
getElRect('car', props.instance).then(res => {
console.log(res);
edmits('updateSafeBottom', res)
}).catch(err=>{
console.log(err);
})
})
</script>
<style lang="scss" scoped>
$car-size: 70px;
$car-top: -16rpx;
.luodan {
background-color: $my-main-color;
padding: 10px 30px;
border-radius: 4px;
color: #fff;
font-size: 16px;
font-weight: bold;
}
.allPrice {
font-size: 24px;
}
.goods-box {
position: fixed;
right: 0;
top: 80px;
bottom: 80px;
left: 30%;
right: 0;
background-color: #fff;
border-radius: 12px 0 0 12px;
overflow: hidden;
transition: all .2s ease-in-out;
transform: translateX(100%);
z-index: 10;
&.active {
transform: translateX(0);
}
.top {
width: 100%;
color: rgb(102, 102, 102);
font-size: 16px;
background-color: rgb(233, 233, 238);
padding: 14px 20px;
}
.bottom {
padding: 14px 20px;
border-top: 1px solid #eee;
width: 100%;
font-size: 16px;
}
}
@mixin fixedAll {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.total {
left: 0;
right: 0;
top: 0;
z-index: 1;
}
.icon {
width: 40rpx;
height: 40rpx
}
.mask {
@include fixedAll;
background: rgba(51, 51, 51, 0.5);
}
.goods {
position: fixed;
width: 50vh;
bottom: 0;
right: 0;
transition: all .2s ease-in-out;
overflow: hidden;
z-index: 3;
.item {
padding: 32rpx 28rpx;
}
}
.border-bottom {
// border-bottom: 1px solid #E5E5E5;
}
.border-top {
// border-top: 1px solid #E5E5E5;
}
.red {
color: #EB4F4F;
}
.car {
position: fixed;
right: 20px;
top: 40px;
// top: 50%;
// transform: translateY(-50%);
.icon-car-box {
position: relative;
display: flex;
width: $car-size;
height: $car-size;
justify-content: center;
align-items: center;
z-index: 2;
.dot {
position: absolute;
right: 0;
top: 0;
width: 28rpx;
height: 28rpx;
background: #EB4F4F;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 20rpx;
font-weight: bold;
color: #FFFFFF;
}
}
.price {
color: #EB4F4F;
margin-left: calc(38rpx + $car-size);
transform: translateY(calc($car-top / 2));
}
.icon-car {
width: $car-size;
height: $car-size;
}
}
</style>

View File

@@ -0,0 +1,230 @@
<template>
<view class="u-relative u-flex item box-shadow " @tap="emitEvent('showDetail')">
<view class="img">
<image lazy-load :src="data.coverImg" mode="aspectFill"></image>
</view>
<!-- <image lazy-load class="img" :src="data.coverImg" mode="" ></image> -->
<view class="info u-flex u-flex-col u-row-right " >
<view class="u-flex w-full u-row-right u-p-r-20 u-p-b-16 u-flex-1 u-flex-col">
<template v-if="!isSellout">
<template v-if="data.typeEnum=='sku'">
<view class="u-flex u-row-right w-full">
<view class="u-flex">
<button class="btn" hover-class="btn-hover-class" @tap.stop="emitEvent('chooseGuige')">选规格</button>
</view>
</view>
</template>
<template v-else>
<view class="u-flex w-full u-row-right ">
<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}}
</view>
</template>
<view class="u-flex" @tap.stop="emitEvent('add')">
<image src="/pagesCreateOrder/static/images/icon-add.svg" class="icon" mode="">
</image>
</view>
</view>
</view>
</template>
</template>
<template v-else>
<view class=" u-m-t-16 u-row-center u-col-center">
已售罄
</view>
</template>
</view>
<view class="bg-fff u-p-20 w-full">
<view class="u-flex u-row-between u-font-16">
<view>{{data.name}}</view>
<view class=" font-bold u-m-t-16">
{{data.lowPrice}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
computed,
toRef,
toRefs,
watch
} from 'vue';
const props = defineProps({
img: {
type: Object,
default: {
width: '250rpx',
height: '272rpx'
}
},
windowWidth: {
//px
type: Number,
default: 0
},
windowHeight: {
//px
type: Number,
default: 0
},
layout: {
type: String,
default: 'default'
},
index: {
type: [Number, String],
},
isSeatFee: {
//是否为餐位费
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {
return {
chooseNumber: 0
}
}
},
gap: {
//px
type: Number,
default: 20
}
})
watch(() => props.windowWidth, (newval) => {
console.log(newval);
})
const computedImgStyle = computed(() => {
const stylobj = {
width: props.img.width,
height: props.img.height
}
if (props.layout == 'default') {
stylobj.width = (props.windowWidth - props.gap * 3) / 2 + 'px'
stylobj.height = (props.windowHeight - props.gap * 2 - 40) / 2 + 'px'
console.log(stylobj);
return stylobj
}
return stylobj
})
// function computedImgStyle() {
// return {
// width: props.img.width,
// height: props.img.height
// }
// }
//判断是否是菜品
function isGoods() {
return props.data.hasOwnProperty('id')
}
//判断商品是否售尽
const isSellout = computed(() => {
const item = props.data
if(!isGoods()){
return false
}
return (
item.isPauseSale ||
(item.typeEnum !== "sku" && item.isStock==1&& item.stockNumber <= 0)
);
})
const emits = defineEmits(['add', 'reduce', 'chooseGuige','showDetail'])
function emitEvent(emitName) {
if (isGoods()) {
emits(emitName, props.index)
}
}
</script>
<style lang="scss" scoped>
.icon {
width: 60rpx;
height: 60rpx;
}
.icon-btn {
gap: 14rpx;
}
.btn {
background: #EB4F4F;
border-radius: 100rpx;
font-size: 32rpx;
font-weight: bold;
padding: 0 50rpx;
color: #fff;
}
.btn-hover-class {
opacity: .6;
}
.item {
// width: 250rpx;
// height: 272rpx;
background: #F9B798;
border-radius: 12px;
overflow: hidden;
width: 100%;
height: 100%;
position: relative;
&.default {
.img {}
}
.img {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 1;
object-fit: contain;
image {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.info {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
// background: rgba(37, 22, 15, 0.5);
border-radius: 0 0 12px 12px;
overflow: hidden;
z-index: 2;
}
}
</style>

View File

@@ -0,0 +1,249 @@
<template>
<my-model ref="model" borderRadius="12" :title="title" width="50vw">
<template #desc>
<scroll-view scroll-y="true" style="height: 50vh;" class="u-p-30 guigeModel">
<view class="u-m-b-40" v-for="(item,index) in skus" :key="index">
<view class="u-text-left">
<view class="color-333">{{item.name}}</view>
</view>
<view class="u-flex u-m-t-20 u-flex-wrap">
<view class="item" @tap="chooseSkd(index,skd)"
:class="{active:item.sel===skd.name,disabled:skd.disabled}"
v-for="(skd,skdIndex) in item.values" :key="skdIndex">
{{skd.name}}
</view>
</view>
</view>
</scroll-view>
</template>
<template #btn>
<view class="u-p-30 border-top ">
<view class="u-flex u-p-b-30 u-row-between">
<view class="price">
<template v-if="goods&&goods.isGrounding">
<text></text>
<text>{{to2(goods.salePrice*number) }}</text>
</template>
</view>
<view class="u-flex">
<view class="u-flex" @tap="reduce">
<image src="/pagesCreateOrder/static/images/icon-reduce-black.svg" class="icon" mode="">
</image>
</view>
<view class="u-m-l-30 u-m-r-30 color-333">
{{number}}
</view>
<view class="u-flex" @tap="add">
<image src="/pagesCreateOrder/static/images/icon-add-black.svg" class="icon" mode="">
</image>
</view>
</view>
</view>
<view class="u-m-t-10">
<my-button @tap="close" type="cancel" v-if="isDisabled">
<view class="color-999">已下架/售罄</view>
</my-button>
<my-button @tap="confirm" v-else>添加</my-button>
</view>
</view>
</template>
</my-model>
</template>
<script setup>
import {
computed,
reactive,
ref,
watch
} from 'vue';
import util from '../util.js';
import infobox from '@/commons/utils/infoBox.js'
import myModel from '@/components/my-components/my-model.vue'
import myButton from '@/components/my-components/my-button.vue'
const props = defineProps({
goodsData: {
type: Object,
default: () => {}
},
title: {
type: String,
default: ''
},
skuMap: {
type: Object,
default: () => {
return {}
}
},
skus: {
type: Array,
default: () => {
return []
}
},
defaultIndex: {
type: Array,
default: () => {
return []
}
}
})
function to2(number) {
return Number(number).toFixed(2)
}
const selSku = computed(() => {
return props.skus.reduce((prve, cur) => {
prve.push(cur.sel)
return prve
}, []).join()
})
const goods = computed(() => {
return props.skuMap[selSku.value]
})
watch(() => goods.value, (newval) => {
console.log(props.goodsData.isStock);
number.value = newval.suit || 1
})
const isCanBuy=computed(()=>{
if(!goods.value) {
return false
}
console.log(util.isCanBuy({
...goods.value,
isStock: props.goodsData.isStock
}));
return util.isCanBuy({
...goods.value,
isStock: props.goodsData.isStock
})
})
//全部规格是否都无法使用
const isAllDisabled = computed(() => {
console.log(props.skus);
return props.skus.reduce((prve, cur) => {
return prve && cur.values.filter(v => v.disabled).length === cur.values.length
}, true)
})
const emits = defineEmits(['confirm', 'updateSku'])
let number = ref(1)
function chooseSkd(skusIndex, skd) {
const {
name,
disabled
} = skd
if (disabled) {
return
}
if (props.skus[skusIndex].sel != name) {
emits('updateSku', skusIndex, name)
}
}
const defaultIndex = reactive(new Array(props.skus.length).fill(''))
for (let i in props.defaultIndex) {
defaultIndex[i] = props.defaultIndex[i]
}
const activeArr = defaultIndex
const model = ref(null)
function open() {
model.value.open()
}
function close() {
model.value.close()
}
const isDisabled=computed(()=>{
return isAllDisabled.value || !isCanBuy.value
})
function reduce() {
if (isDisabled.value) {
return
}
const suit = goods.value.suit || 1
const newval = number.value - 1
if (newval < suit) {
return infobox.showToast(suit + '个起售')
}
number.value = newval <= 1 ? 1 : newval
}
function add() {
if (isDisabled.value) {
return
}
const newval = number.value + 1
number.value = newval
}
function confirm() {
close()
if (isDisabled.value) {
return
}
emits('confirm', goods.value, number.value)
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.border-top {}
.icon {
width: 60rpx;
height: 60rpx;
}
.guigeModel {
.item {
color: #666;
font-size: 28rpx;
padding: 4rpx 28rpx;
border: 1px solid #E5E5E5;
border-radius: 8rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
transition: all .2s ease-in-out;
&.active {
border-color: $my-main-color;
color: $my-main-color;
}
&.disabled {
color: #ccc;
border-color: #eee;
}
}
}
.price {
color: #EB4F4F;
}
.border-top {
border-top: 1px solid #E5E5E5;
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<up-popup :show="popShow" @close="close" @open="open" mode="center" :round="12">
<view class="bg-fff box u-font-28 w-full u-relative">
<view class="u-absolute close">
<u-icon name="close" size="20" @click="close"></u-icon>
</view>
<scroll-view scroll-y="true" class="scroll-box" >
<template v-if="data.images.length>1">
<swiper class="scroll-box" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="300">
<swiper-item v-for="(item,index) in data.images" :key="index">
<view class="swiper-item">
<!-- <image class="coverImg w-full" @click="prveImg(data.images,item)" :src="item" mode="widthFix"></image> -->
<image class="coverImg w-full" :src="item" mode="widthFix"></image>
</view>
</swiper-item>
</swiper>
</template>
<template v-else>
<view class="u-flex u-row-center">
<!-- <image class="coverImg w-full" @click="prveImg([data.coverImg],data.coverImg) " :src="data.coverImg" mode="widthFix"></image> -->
<image class="coverImg w-full" :src="data.coverImg" mode="widthFix"></image>
</view>
</template>
<view class="u-p-20">
<view class="u-font-16 font-bold">{{data.name}}</view>
<view class="u-m-t-12 color-666">
<rich-text :nodes="data.shortTitle"></rich-text>
</view>
</view>
</scroll-view>
</view>
</up-popup>
</template>
<script setup>
import {
computed,
reactive,
ref,
watch,
nextTick
} from 'vue';
import {prveImg} from '@/commons/utils/prveImg.js'
const refForm = ref(null)
let searchVal = ref('')
const props = defineProps({
show: {
type: Boolean,
default: false
},
goods: {
type: Object,
default: () => {
return {
images: []
}
}
}
})
let data = ref(props.goods)
const emits = defineEmits(['update:show', 'search'])
const form = reactive({
note: ''
})
let popShow = ref(props.show)
watch(() => props.show, (newval) => {
popShow.value = newval
if (newval) {
data.value = {
...props.goods,
images: typeof props.goods.images === 'string' ? JSON.parse(props.goods.images) : props.goods
.images
}
}
})
watch(() => popShow.value, (newval) => {
emits('update:show', newval)
})
function close() {
popShow.value = false
}
function open() {
}
function search() {
emits('search', searchVal.value)
close()
}
</script>
<style lang="scss" scoped>
.coverImg {
// width: calc(100vw - 80px);
}
.box {
width: calc(100vw - 80px);
border-radius: 14px;
overflow: hidden;
box-sizing: border-box;
}
.scroll-box {
height: calc(100vh - var(--status-bar-height) - 20px);
}
.close {
position: absolute;
right: 14px;
top: 14px;
background-color: #fff;
z-index: 10;
width: 22px;
height: 22px;
border-radius: 50%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 2px #eee;
}
.number {
color: #EE4646;
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<up-popup :show="popShow" @close="close" @open="open" mode="top" :round="0">
<view class="u-p-32 box u-font-28">
<up-search v-model="searchVal" @search="search" @clear="search" @click="search"></up-search>
</view>
</up-popup>
</template>
<script setup>
import {
computed,
reactive,
ref,
watch,
nextTick
} from 'vue';
const refForm = ref(null)
let searchVal=ref('')
const props = defineProps({
show: {
type: Boolean,
default: false
}
})
let data = ref(props.goods)
const emits = defineEmits(['update:show', 'search'])
const form = reactive({
note: ''
})
let popShow = ref(props.show)
watch(() => props.show, (newval) => {
popShow.value = newval
if (newval) {
data.value = {
...props.goods
}
}
})
watch(() => popShow.value, (newval) => {
emits('update:show', newval)
})
function close() {
popShow.value = false
}
function open() {
}
function search(){
emits('search',searchVal.value)
close()
}
</script>
<style lang="scss" scoped>
.box {
width: 556rpx;
border-radius: 18rpx 18rpx 18rpx 18rpx;
box-sizing: border-box;
}
.close {
position: absolute;
right: 0;
}
.number {
color: #EE4646;
}
</style>

View File

@@ -0,0 +1,155 @@
<template>
<view class="all-page position-all bg-gray u-flex u-flex-col" @click="skeletonClick">
<view class="u-flex category u-flex-row">
<view class="category-item u-flex u-flex-row skeletion " v-for="(item,index) in 14" :key="index">
</view>
</view>
<view class="u-flex-1 u-flex u-flex-row bottom">
<view class="left skeletion u-flex-1"></view>
<view class="right skeletion u-flex-1"></view>
</view>
<view class="car">
<view class="icon-car-box" >
<image src="/pagesCreateOrder/static/images/icon-car.svg" class="icon-car" />
<view class="dot">0</view>
</view>
</view>
</view>
</template>
<script setup>
import {
onMounted
} from 'vue';
import myCar from './car'
const emits=defineEmits(['skeletonClick'])
function skeletonClick(){
emits('skeletonClick')
}
</script>
<style lang="scss" scoped>
$categoryLen: 10;
.gap-20 {
gap: 20px;
}
.all-page {
position: fixed;
z-index: 10;
}
@keyframes skeleton {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
.skeletion {
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
border-radius: 3px;
animation: skeleton 1.8s ease infinite;
}
.left {
background-color: #F1F2F4;
width: 400px;
border-radius: 12px;
height: calc(100vh - 84px);
flex: 1;
// height: calc(100vh - 64px);
}
.right {
border-radius: 12px;
height: calc(100vh - 84px);
flex: 1;
}
.category {
background-color: #fff;
padding-bottom: 10px;
/* #ifdef H5 */
padding-top: 10px;
/* #endif */
/* #ifndef H5 */
padding-top: calc(var(--status-bar-height));
/* #endif */
.category-item {
width: calc(100vw / 14);
height: 24px;
margin-right: 10px;
border-radius: 4px;
}
}
.bottom {
width: 100%;
height: 100%;
// background-color: red;
padding: 20px 20px 20px 20px;
gap: 20px;
box-sizing: border-box;
.left{
flex: 1;
height: 100%;
}
.right{
height: 100%;
flex: 1;
}
}
$car-size: 70px;
$car-top: -16rpx;
.car {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
// top: 50%;
// transform: translateY(-50%);
.icon-car-box {
position: relative;
display: flex;
width: $car-size;
height: $car-size;
justify-content: center;
align-items: center;
z-index: 2;
.dot {
position: absolute;
right: 0;
top: 0;
width: 28rpx;
height: 28rpx;
background: #EB4F4F;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 20rpx;
font-weight: bold;
color: #FFFFFF;
}
}
.price {
color: #EB4F4F;
margin-left: calc(38rpx + $car-size);
transform: translateY(calc($car-top / 2));
}
.icon-car {
width: $car-size;
height: $car-size;
}
}
</style>

View File

@@ -0,0 +1,109 @@
<template>
<my-model ref="model" :title="title" iconColor="#000" @close="resetForm">
<template #desc>
<view class="u-text-left u-p-30 ">
<view>
<view>名称</view>
<view class="u-m-t-24 border u-flex input-box">
<input v-model="form.name" type="text" placeholder-class="placeholder-class"
placeholder="请输入名称" />
</view>
</view>
<view class="u-m-t-32">
<view>价格</view>
<view class="u-m-t-24 border u-flex input-box">
<input v-model="form.price" type="digit" placeholder-class="placeholder-class"
placeholder="请输入价格" />
</view>
</view>
</view>
</template>
<template #btn>
<view class="u-p-30">
<view class="u-m-t-10">
<my-button @tap="confirm" shape="circle" showShadow>添加</my-button>
<my-button type="cancel" bgColor="#fff" @tap="confirm">取消</my-button>
</view>
</view>
</template>
</my-model>
</template>
<script setup>
import {
reactive,
ref
} from 'vue';
import myModel from '@/components/my-components/my-model.vue'
import myButton from '@/components/my-components/my-button.vue'
const props = defineProps({
title: {
type: String,
default: ''
},
data: {
type: Array,
default: []
}
})
const $form = {
name: '',
price: ''
}
const form = reactive({...$form})
function resetForm() {
Object.assign(form,{...$form})
}
const model = ref(null)
function open() {
model.value.open()
}
function close() {
model.value.close()
}
const emits = defineEmits(['confirm'])
function confirm() {
const {
name,
price
} = form
if (!name) {
return uni.showToast({
icon: 'none',
title: '请输入附加费名称'
})
}
close()
emits('confirm',{
name,
price
})
}
defineExpose({
open,
close
})
</script>
<style lang="scss">
.border {
border: 1px solid #E5E5E5;
border-radius: 4rpx;
}
.input-box {
padding: 22rpx 32rpx;
font-size: 28rpx;
color: #666;
}
.placeholder-class {
font-size: 28rpx;
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<view class="uni-swiper-page">
<list ref="list" class="list" :offset-accuracy="5" :bounce="true" isSwiperList="true" :show-scrollbar="false">
<cell v-for="(item, index) in dataList" :key="item.id" :ref="'item'+index" @click="onclick">
<view class="list-item">
<text>{{item.name}}</text>
</view>
</cell>
<cell class="loading"></cell>
</list>
</view>
</template>
<script>
export default {
props: {
pid: {
type: [Number, String],
default: ''
},
parentId: {
type: String,
default: ''
}
},
data() {
return {
scrollable: true,
dataList: []
}
},
created() {
for (var i = 1; i <= 32; i++) {
this.dataList.push({
id: i,
name: i
});
}
},
methods: {
setScrollRef(height) {
if (this.$refs['list'].setSpecialEffects) {
this.$refs['list'].setSpecialEffects({
id: this.parentId,
headerHeight: height
});
}
},
onclick(e) {
console.log("onclick");
},
loadData() {
// 首次激活时被调用
},
clear() {
// 释放数据时被调用,参考 swiper-list 缓存配置
this.dataList.length = 0;
}
}
}
</script>
<style scoped>
.uni-swiper-page {
flex: 1;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.list {
flex: 1;
background-color: #ebebeb;
}
.list-item {
margin-left: 12px;
margin-right: 12px;
margin-top: 12px;
padding: 20px;
background-color: #fff;
border-radius: 5px;
}
.loading {
height: 20px;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
import {
$productCategory,
$layoutpage
} from '@/http/yskApi/pad.js'
//根据布局返回商品列表
export function returnSelCategotyGoods(arr, size) {
// 检查size是否为正整数
if (size <= 0) {
throw new Error('Size must be a positive integer.');
}
// 计算数组的长度并确保size不会超过数组长度
const length = arr.length;
size = Math.min(size, length);
// 创建一个新数组来存储结果
const groups = [];
// 循环遍历原始数组每size个元素分为一组
for (let i = 0; i < length; i += size) {
groups.push(arr.slice(i, i + size)); // 使用slice方法获取子数组
}
return groups; // 返回新的数组
}
//根据店铺信息返回是否是后付款
export function $trturnPayAfter(shop) {
//munchies 先付 restaurant 后付
const payAfter = shop.registerType == "munchies" ? false : true;
return payAfter
}
//根据店铺信息返回就餐类型
export function $returnUseType(shop, useType) {
//是否是后付款
const payAfter = $trturnPayAfter(shop)
let result = "takeout";
if (useType == "takeout") {
result = 'takeout'
} else {
//堂食
result = `dine-in-${payAfter ? "after" : "before"}`;
}
return result
}
//判断商品是否可以下单
export function isCanBuy(goods, isStock) {
return goods.isGrounding && goods.isPauseSale == 0 && (isStock ? goods.stockNumber > 0 : true);
}
// 一个数组是否包含另外一个数组全部元素
function arrayContainsAll(arr1, arr2) {
for (let i = 0; i < arr2.length; i++) {
if (!arr1.includes(arr2[i])) {
return false;
}
}
return true;
}
//n项 n-1项组合生成全部结果
function generateCombinations(arr, k) {
let result = [];
function helper(index, current) {
if (current.length === k) {
result.push(current.slice()); // 使用slice()来避免直接修改原始数组
} else {
for (let i = index; i < arr.length; i++) {
current.push(arr[i]); // 将当前元素添加到组合中
helper(i + 1, current); // 递归调用,索引增加以避免重复选择相同的元素
current.pop(); // 回溯,移除当前元素以便尝试其他组合
}
}
}
helper(0, []); // 从索引0开始初始空数组作为起点
return result;
}
export function returnReverseVal(val, isReturnString = true) {
const isBol = typeof val === "boolean";
const isString = typeof val === "string";
let reverseNewval = "";
if (isBol) {
reverseNewval = !val;
}
if (isString) {
reverseNewval = val === "true" ? "false" : "true";
}
return reverseNewval;
}
export function returnPrveId(par) {
const obj = {
prveData: [],
nowData: [],
nextData: [],
page: 0
}
Object.assign(obj, par)
if (par.page == 0 || par.nowData.length <= 1) {
const prveIndex = obj.prveData.length - 1 <= 0 ? 0 : obj.prveData.length - 1
return obj.prveData[prveIndex] ? obj.prveData[prveIndex].id : undefined
}
return obj.nowData[par.page - 1] ? obj.nowData[par.page - 1].id : undefined
}
export function returnNowId(par) {
const obj = {
prveData: [],
nowData: [],
nextData: [],
page: 0
}
Object.assign(obj, par)
if (!par.nowData[par.page]) {
return undefined
}
return obj.nowData[par.page] ? obj.nowData[par.page].id : undefined
}
export function returnNextId(par) {
const obj = {
prveData: [],
nowData: [],
nextData: [],
page: 0
}
Object.assign(obj, par)
if (par.page >= par.nowData.length - 1 || par.nowData.length <= 1) {
const nextIndex = obj.nextData.length - 1 <= 0 ? 0 : obj.nextData.length - 1
return obj.nextData[nextIndex] ? obj.nextData[nextIndex].id : undefined
}
return obj.nextData[par.page + 1] ? obj.nextData[par.page + 1].id : undefined
}
export async function returnLayoutPage(id) {
if (!id) {
return {
content: [],
totalElements: 0
}
}
return $layoutpage({
page: 1,
size: 999,
productCategoryId: id,
padLayoutId: ''
})
}
export async function returnCategoryLayoutGoods(id,category) {
if (!id) {
return {
productList: [],
padLayoutCode: "single",
productCategoryId:category?category.id:''
}
}
return $productCategory(id)
}
export default {
isCanBuy,
returnNowId,
returnCategoryLayoutGoods,
returnLayoutPage,
returnPrveId,
returnNextId,
arrayContainsAll,
generateCombinations,
returnReverseVal,
$returnUseType
}