Files
cashier_desktop/src/views/table/components/tableInfo.vue

507 lines
15 KiB
Vue

<!-- 空闲台桌 -->
<template>
<div class="table_wrap">
<!-- <div class="header">
<span class="t">{{ props.tableInfo.name }}</span>
<div class="close" @click="close">
<el-icon class="icon">
<Close />
</el-icon>
</div>
</div>
<div class="status_wrap">
<el-icon class="icon">
<Clock />
</el-icon>
<span class="t">{{tableStatusList.find(val => val.type == props.tableInfo.status).label}}</span>
</div> -->
<div class="cart" v-loading="payLoading" v-if="props.tableInfo.status == 'unsettled'">
<div class="cart_list">
<div class="item" v-for="item in cartList" :key="item.id">
<div class="top">
<span class="name">
<span v-if="item.isTemporary" style="color: #999;">[临时菜]</span>
<span v-if="item.isGift" style="color: #999;">[]</span>
{{ item.productName }}
</span>
<span class="n">x{{ item.num - item.returnNum }}</span>
<span class="p">{{ item.unitPrice }}</span>
</div>
<div class="top" v-if="item.returnNum > 0" style="font-size: 12px;color: #999;">
<span class="name">[退菜]</span>
<span class="n">x{{ item.returnNum }}</span>
<span class="p">-{{ item.returnNum * item.price }}</span>
</div>
<div class="top" v-if="item.discountSaleAmount > 0 && item.isTemporary == 0"
style="font-size: 12px;color: #999;">
<span class="name">[改价优惠]</span>
<span class="n"></span>
<span class="p">-{{ item.price - item.unitPrice }}</span>
</div>
<div class="tag_wrap" v-if="item.skuName">
<div class="tag" v-for="item in item.skuName.split(',')">
{{ item }}
</div>
</div>
</div>
</div>
<div class="btn_container">
<div class="btn_wrap">
<el-button type="success" style="width: 100%;" @click="toOrderMeal(1)">加菜/管理</el-button>
</div>
<div class="btn_wrap">
<el-button type="primary" style="width: 100%;" :loading="payLoading" @click="showPayHandle">结算({{
orderInfo.orderAmount || 0 }})</el-button>
</div>
</div>
</div>
<div class="place_order" v-else>
<div class="btn">
<div class="top"
:style="{ '--color': tableStatusList.find(val => val.type == props.tableInfo.status).color }">
<el-icon class="icon">
<TakeawayBox />
</el-icon>
<!-- <span class="t">点单</span> -->
</div>
<!-- <span class="tips">开始新订单</span> -->
<div class="btn_wrap" v-if="props.tableInfo.status == 'idle'">
<el-button type="primary" style="width: 100%;" @click="showPeopleNumHandle">开始新订单</el-button>
</div>
<div class="btn_wrap" v-if="props.tableInfo.status == 'settled'">
<el-button type="primary" style="width: 100%;" @click="clearTableStatus">清理完成</el-button>
</div>
<div class="btn_wrap" v-if="props.tableInfo.status == 'unbound'">
<el-button type="default" disabled style="width: 100%;">{{ props.tableInfo.statusMsg }}</el-button>
</div>
</div>
<transition name="el-fade-in">
<div class="people_num_wrap" v-show="showPeopleNum">
<div class="title">应选择就餐人数</div>
<div class="num_btns">
<div class="item" :class="{ active: peopleNum == item }"
v-for="item in props.tableInfo.maxCapacity" @click="peopleNum = item">{{ item }}</div>
<!-- <div class="item" :class="{ active: peopleNum == 'custom' }">
<input class="ipt" @focus="inputFocus" placeholder="自定义" v-model="peopleNumInputValue"
@change="" />
</div> -->
</div>
<div class="btn">
<el-button type="primary" style="width: 100%;"
:disabled="(!peopleNum && !peopleNumInputValue) || (peopleNum == 'custom' && !peopleNumInputValue)"
@click="orderDownHandle">确认</el-button>
</div>
</div>
</transition>
</div>
<!-- 结算订单 -->
<SettleAccount ref="SettleAccountRef" type="table" @success="emits('success')" />
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useUser } from "@/store/user.js"
import { formatDecimal } from '@/utils/index.js'
import SettleAccount from '@/views/home/components/settleAccount.vue'
import { ElMessage } from 'element-plus'
import { shopTableClear } from '@/api/account.js'
import { useGoods } from "@/store/goods.js";
import { getOrderByIdAjax } from '@/utils/index.js'
import tableStatusList from '../statusList.js'
const goodsStore = useGoods()
const router = useRouter()
const store = useUser()
const SettleAccountRef = ref(null)
const emits = defineEmits(['close', 'success'])
const props = defineProps({
tableInfo: {
type: Object,
default: {}
}
})
const showPeopleNum = ref(false)
const peopleNum = ref(0)
const peopleNumInputValue = ref('')
watch(props, () => {
getOrderDetail()
})
// 自定义人数输入获得焦点
function inputFocus() {
peopleNum.value = 'custom'
}
const orderInfo = ref({})
const cartList = ref([])
const payLoading = ref(false)
// 显示结算页面
async function showPayHandle() {
try {
payLoading.value = true
await goodsStore.historyOrderAjax('', props.tableInfo.orderId)
goodsStore.selectTable({
...props.tableInfo,
num: props.tableInfo.useNum
})
goodsStore.calcCartInfo()
SettleAccountRef.value.show()
} catch (error) {
console.log(error);
}
payLoading.value = false
}
// 显示就就餐人数
function showPeopleNumHandle() {
if (store.shopInfo.isTableFee == 1) {
orderDownHandle()
} else {
showPeopleNum.value = true
}
}
// 清理桌台
const clearLoading = ref(false)
async function clearTableStatus() {
try {
clearLoading.value = true
await shopTableClear({
tableId: props.tableInfo.id
})
emits('success')
} catch (error) {
console.log(error);
}
clearLoading.value = false
}
// 获取订单详情
async function getOrderDetail() {
try {
if (props.tableInfo.orderId) {
payLoading.value = true
const res = await getOrderByIdAjax(props.tableInfo.orderId)
console.log(res);
payLoading.value = false
orderInfo.value = res
cartList.value = res.cartList
let total = 0
res.cartList.forEach(item => {
total += +item.payAmount - (item.returnNum * item.price)
})
orderInfo.value.orderAmount = formatDecimal(total)
}
} catch (error) {
payLoading.value = false
console.log(error);
}
}
// 关闭
function close() {
emits('close')
}
// 判断数字是不是正整数
function isPositiveInteger(num) {
return Number.isInteger(num) && num > 0;
}
// 选择人数后确认下单
function orderDownHandle() {
// if (peopleNum.value == 'custom') {
// if (!isPositiveInteger(parseFloat(peopleNumInputValue.value))) {
// ElMessage.error('请输入有效的就餐人数')
// return
// }
// }
if (!props.tableInfo.tableCode) {
ElMessage.error('请绑定桌码后操作')
return
}
// 选择完人数后跳转首页
goodsStore.selectTable({
...props.tableInfo,
num: peopleNum.value
})
router.push({
name: 'home',
})
}
// 点单
function toOrderMeal(t) {
if (t == 1) {
// 直接点单
goodsStore.selectTable({
...props.tableInfo,
num: props.tableInfo.useNum
})
router.push({
name: 'home',
})
} else {
// 选择会员点单
showDialog.value = true
getMemberList()
}
}
function paySuccess() {
getOrderDetail()
emits('success')
}
onMounted(() => {
getOrderDetail()
})
</script>
<style scoped lang="scss">
.table_wrap {
// padding: 20px;
padding-top: 14px;
.header {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: calc(var(--el-font-size-base) + 10px);
}
.close {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: flex-end;
.icon {
font-size: 24px;
color: #999;
}
}
}
.status_wrap {
display: flex;
align-items: center;
padding-bottom: var(--el-font-size-base);
.icon {
color: #666;
font-size: var(--el-font-size-base);
}
.t {
color: #666;
margin-left: 4px;
}
}
.cart {
height: calc(100vh - 75px);
display: flex;
flex-direction: column;
.cart_list {
flex: 1;
border-radius: 6px;
background-color: #fff;
padding: 0 var(--el-font-size-base);
overflow-y: auto;
.item {
padding: var(--el-font-size-base) 0;
&:not(:last-child) {
border-bottom: 1px solid #ddd;
}
.top {
display: flex;
padding-bottom: 6px;
.name {
flex: 1;
padding-right: 10px;
}
.n {
width: 50px;
color: #555;
}
.p {
width: 50px;
color: #555;
}
}
.tag_wrap {
display: flex;
flex-wrap: wrap;
.tag {
padding: 2px 6px;
background-color: var(--el-color-danger);
color: #fff;
margin-right: 10px;
margin-bottom: 10px;
font-size: 12px;
}
}
}
}
.btn_container {
display: flex;
gap: 10px;
.btn_wrap {
flex: 1;
padding-top: var(--el-font-size-base);
}
}
}
.place_order {
background-color: #efefef;
height: calc(100vh - 160px);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
.btn {
display: flex;
gap: 10px;
flex-direction: column;
align-items: center;
text-decoration: none;
$size: 150px;
.top {
background-color: #fff;
width: $size;
height: $size;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 6px;
.icon {
color: var(--color);
font-size: 40px;
}
.t {
color: #fff;
}
}
.tips {
color: #999;
padding-top: 6px;
}
.btn_wrap {
width: $size;
}
}
.people_num_wrap {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 9;
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.title {
padding-bottom: 40px;
font-size: 18px;
font-weight: bold;
}
.num_btns {
width: 80%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 40px 40px 40px;
gap: 20px;
.item {
color: #fff;
border-radius: 4px;
background-color: var(--el-color-danger);
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: all .1s ease-in-out;
&.active {
font-size: 14px;
background-color: #e96565;
box-shadow: inset 0 4px 5px rgba(0, 0, 0, 0.3);
.ipt {
font-size: 14px;
}
}
.ipt {
width: 100%;
height: 100%;
outline: none;
border: none;
background: transparent;
color: #fff;
text-align: center;
font-size: 16px;
transition: all .1s ease-in-out;
&::-webkit-input-placeholder {
color: #fff;
}
}
}
}
.btn {
width: 80%;
padding-top: 40px;
}
}
}
}
</style>