对接台桌列表

This commit is contained in:
gyq 2024-02-28 15:02:31 +08:00
parent 56f9d83447
commit d65e3db7c0
17 changed files with 655 additions and 37 deletions

View File

@ -11,6 +11,7 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.6.2",
"dayjs": "^1.11.10",
"electron": "^29.0.1",
"element-plus": "^2.4.3",
"lodash": "^4.17.21",

View File

@ -79,6 +79,12 @@ router.beforeEach((to, from) => {
--el-component-size-large: 50px !important;
}
@font-face {
font-family: 'num';
src: url('@/assets/font/Ignotum-Regular.ttf');
}
html {
font-size: var(--el-font-size-base);
color: #333;

27
src/api/table.js Normal file
View File

@ -0,0 +1,27 @@
import request from "@/utils/request.js"
/**
* 查询台桌分类
* @param {*} params
* @returns
*/
export function queryShopArea(params) {
return request({
method: "get",
url: "shopInfo/queryShopArea",
params
});
}
/**
* 查询台桌信息
* @param {*} params
* @returns
*/
export function queryShopTable(params) {
return request({
method: "get",
url: "shopInfo/queryShopTable",
params
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

View File

@ -99,7 +99,7 @@ const menus = ref([
}
&.more {
margin-top: 30px;
margin-top: 50px;
}
.icon {

View File

@ -1,9 +1,9 @@
<template>
<el-dialog title="备注" width="800" v-model="dialogVisible">
<div class="tag_wrap">
<div class="item" v-for="item in tagList" :key="item.remark" @click="remark = item.remark">
<el-button plain type="primary" v-for="item in tagList" :key="item.remark" @click="remark = item.remark">
{{ item.remark }}
</div>
</el-button>
</div>
<div class="content">
<el-input type="textarea" :rows="6" v-model="remark" placeholder="请输入备注"></el-input>
@ -45,21 +45,6 @@ defineExpose({
.tag_wrap {
display: flex;
flex-wrap: wrap;
gap: 20px;
.item {
padding: 10px 20px;
border: 1px solid var(--primary-color);
border-radius: 4px;
color: var(--primary-color);
font-size: var(--el-font-size-base);
&:hover {
cursor: pointer;
background-color: var(--primary-color);
color: #fff;
}
}
}
.content {

View File

@ -5,15 +5,19 @@
<div class="row" v-for="(item, index) in goods.tbProductSpec.specList" :key="index">
<div class="title">{{ item.name }}</div>
<div class="sku_wrap">
<div class="item" :class="{ active: val.active }" v-for="(val, i) in item.value" :key="i"
@click="selectedSku(index, i)">{{ val.name }}</div>
<!-- <div class="item" :class="{ active: val.active }" v-for="(val, i) in item.value" :key="i"
@click="selectedSku(index, i)">{{ val.name }}</div> -->
<el-button :plain="!val.active" type="primary" v-for="(val, i) in item.value" :key="i"
@click="selectedSku(index, i)">{{ val.name }}</el-button>
</div>
</div>
</div>
<div class="footer">
<div class="info" v-if="goodsInfo.id">
<span>库存{{ goodsInfo.stockNumber }}</span>
<span>{{ goodsInfo.salePrice }}</span>
<div class="info">
<template v-if="goodsInfo.id">
<span>库存{{ goodsInfo.stockNumber }}</span>
<span>{{ goodsInfo.salePrice }}</span>
</template>
</div>
<div class="btn_wrap">
<div class="btn">
@ -165,8 +169,9 @@ defineExpose({
padding-top: 100px;
.info {
padding-bottom: 20px;
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20px;
}

View File

@ -1,13 +1,80 @@
<!-- 取餐号组件 -->
<template>
<el-dialog title="修改取餐号" v-model="dialogVisible">
<el-input v-model="number" placeholder="请输入取餐号"></el-input>
<el-dialog title="修改取餐号" width="600" v-model="dialogVisible" @open="opne">
<el-input v-model="number" placeholder="请输入取餐号" readonly></el-input>
<div class="keybord_wrap">
<div v-for="item in 9" :key="item">
<el-button plain type="info" style="width: 100%;" @click="inputHandle(item)">{{ item }}</el-button>
</div>
<div>
<el-button plain type="info" disabled style="width: 100%;">.</el-button>
</div>
<div>
<el-button plain type="info" style="width: 100%;" @click="inputHandle(0)">0</el-button>
</div>
<div>
<el-button plain type="info" icon="CloseBold" style="width: 100%;" @click="delHandle"></el-button>
</div>
</div>
<div class="footer">
<el-button type="primary" style="width: 100%;" @click="confirmHandle">确认</el-button>
</div>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue';
import { ref, defineExpose, defineEmits } from 'vue';
const dialogVisible = ref(false)
const number = ref('')
</script>
const emit = defineEmits(['success'])
function show() {
dialogVisible.value = true
}
function opne() {
number.value = ''
}
//
function inputHandle(n) {
number.value += n
}
//
function delHandle() {
if (!number.value) return
number.value = number.value.substring(0, number.value.length - 1)
}
//
function confirmHandle() {
emit('success', number.value)
dialogVisible.value = false
}
defineExpose({
show
})
</script>
<style scoped lang="scss">
:deep(.el-input__inner) {
height: 70px;
font-size: 36px;
}
.keybord_wrap {
padding: 20px 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
gap: 20px;
:deep(.el-button--large) {
height: 70px;
}
}
</style>

View File

@ -29,7 +29,7 @@ const routes = [
meta: {
index: 1,
},
component: () => import("@/views/table.vue"),
component: () => import("@/views/table/index.vue"),
},
{
path: "/order",

View File

@ -6,7 +6,7 @@
import { queryCategory } from '@/api/product'
import { ref, onMounted } from 'vue'
import { useUser } from "@/store/user.js"
const store = useUser();
const store = useUser()
const categorys = ref([])
const categorysActive = ref(0)

View File

@ -15,7 +15,7 @@
</div>
<div class="search_wrap">
<div class="input">
<el-input placeholder="商品名称或首字母简称" prefix-icon="Search" v-model="commdityName" clearable
<el-input placeholder="商品名称或首字母简称" prefix-icon="Search" v-model="commdityName" style="width: 400px;" clearable
@input="inputChange"></el-input>
</div>
<el-button :icon="shopListType == 'text' ? 'PictureRounded' : 'PriceTag'" @click="changeShopListType"></el-button>
@ -64,7 +64,7 @@ const commdityName = ref('')
const originalGoods = ref([])
const goodsList = ref([])
const inputChange = _.debounce(function (e) {
const inputChange = _.debounce(function () {
productqueryCommodityInfoAjax()
}, 500)

View File

@ -8,7 +8,7 @@
</el-icon>
<el-text class="t">(1)</el-text>
</div>
<div class="number">
<div class="number" @click="takeFoodCodeRef.show()">
<el-text class="t">#2</el-text>
</div>
<div class="select_user">
@ -126,7 +126,7 @@
<!-- 备注 -->
<remarkModal ref="remarkRef" />
<!-- 修改取餐号 -->
<takeFoodCode />
<takeFoodCode ref="takeFoodCodeRef" @success="takeFoodCodeSuccess" />
</template>
<script setup>
@ -139,8 +139,14 @@ import takeFoodCode from '@/components/takeFoodCode.vue'
import goods from '@/views/home/components/goods.vue'
const remarkRef = ref(null)
const takeFoodCodeRef = ref(null)
const allSelected = ref(false)
//
function takeFoodCodeSuccess(code) {
console.log('取餐号===', code)
}
</script>
<style scoped lang="scss">

View File

@ -1,3 +0,0 @@
<template>
<el-text>台桌</el-text>
</template>

View File

@ -0,0 +1,97 @@
<template>
<div class="count_wrap">
<div class="date_wrap">
<div class="time">{{ nowTime }}</div>
<div class="date">
<span>{{ nowDate }}</span>
<span>{{ week }}</span>
</div>
</div>
<div class="order_info">
<div class="item">
<div class="title">未结算订单</div>
<div class="num">0</div>
</div>
<div class="item">
<div class="title">未结算金额</div>
<div class="num">0.00</div>
</div>
</div>
</div>
</template>
<script setup>
import dayjs from 'dayjs'
import weekday from 'dayjs/plugin/weekday'
dayjs.extend(weekday)
import { ref, onMounted, onUnmounted } from 'vue'
const nowTime = ref(dayjs().format('HH:mm'))
const nowDate = ref(dayjs().format('M月D日 '))
const weekFormat = {
1: '星期一',
2: '星期二',
3: '星期三',
4: '星期四',
5: '星期五',
6: '星期六',
7: '星期天',
}
const week = ref(weekFormat[dayjs().weekday()])
const timer = ref(null)
function updateTime() {
timer.value = setInterval(() => {
nowTime.value = dayjs().format('HH:mm')
console.log('时间更新了')
}, 30000)
}
onMounted(() => {
updateTime()
})
onUnmounted(() => {
clearInterval(timer.value)
timer.value = null
})
</script>
<style scoped lang="scss">
.time {
font-family: 'num';
font-size: 82px;
letter-spacing: 10px;
}
.count_wrap {
padding: 0 20px;
.date_wrap {
padding: 40px 0;
border-bottom: 1px solid #ececec;
.date {
font-size: 26px;
padding-left: 6px;
}
}
.order_info {
padding: 40px 0;
display: flex;
.item {
flex: 1;
.num {
font-family: 'num';
font-size: 46px;
letter-spacing: 4px;
padding-top: 10px;
}
}
}
}
</style>

View File

@ -0,0 +1,141 @@
<!-- 空闲台桌 -->
<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">{{ status[props.tableInfo.status] }}</span>
</div>
<div class="place_order">
<router-link class="btn" :to="{ name: 'home', query: { table_code: 1 } }">
<div class="top">
<el-icon class="icon">
<TakeawayBox />
</el-icon>
<span class="t">点单</span>
</div>
<span class="tips">开始新订单</span>
</router-link>
</div>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const emit = defineEmits(['close'])
const props = defineProps({
tableInfo: {
type: Object,
default: {}
}
})
const status = ref({
'subscribe': '预定',
'closed': '关台',
'opening': '开台中',
'cleaning': '台桌清理中'
})
//
function close() {
emit('close')
}
</script>
<style scoped lang="scss">
.table_wrap {
padding: 20px;
.header {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: 26px;
}
.close {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: flex-end;
.icon {
font-size: 30px;
color: #999;
}
}
}
.status_wrap {
display: flex;
align-items: center;
padding-bottom: 20px;
.icon {
color: #666;
font-size: 24px;
}
.t {
color: #666;
margin-left: 4px;
}
}
.place_order {
background-color: #efefef;
height: calc(100vh - 180px);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
.btn {
display: flex;
flex-direction: column;
align-items: center;
text-decoration: none;
.top {
background-color: var(--el-color-danger);
width: 130px;
height: 130px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 6px;
.icon {
color: #fff;
font-size: 50px;
}
.t {
color: #fff;
}
}
.tips {
color: #999;
padding-top: 6px;
}
}
}
}
</style>

286
src/views/table/index.vue Normal file
View File

@ -0,0 +1,286 @@
<template>
<div class="content">
<div class="cart_wrap card">
<div class="header">
<div class="menus">
<div class="item" :class="{ active: tabActive == index }" v-for="(item, index) in tabAreas"
:key="item.id" @click="tabChange(item, index)">
<el-text>{{ item.label }}</el-text>
</div>
</div>
<div class="all">
<el-button type="primary" icon="Clock">预定管理</el-button>
</div>
</div>
<div class="tab_container">
<div class="tab_head">
<el-radio-group v-model="area" @change="queryShopTableAjax">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button :label="item.id" v-for="item in areaList" :key="item.id">{{ item.name
}}</el-radio-button>
</el-radio-group>
</div>
<div class="overflow_y" v-loading="loading">
<div class="tab_list">
<div class="item" :class="{ active: tableItemActive == index }" v-for="(item, index) in tableList"
:key="item.id" @click="slectTableHandle(index, item)">
<div class="tab_title" :class="`${item.status}`">
<span>{{ item.name }}</span>
<span>0/{{ item.maxCapacity }}</span>
</div>
<div class="tab_cont">
<el-icon class="icon">
<CircleClose />
</el-icon>
</div>
</div>
</div>
<div class="empty">
<el-empty description="空空如也~" v-if="!tableList.length" />
</div>
</div>
</div>
</div>
<div class="right_card card">
<!-- 台桌统计 -->
<countCard v-if="!slectTable.id" />
<!-- 台桌信息 -->
<tableInfo v-else :tableInfo="slectTable" @close="slectTableClose" />
</div>
</div>
</template>
<script setup>
import { queryShopArea, queryShopTable } from '@/api/table'
import countCard from '@/views/table/components/countCard.vue'
import tableInfo from '@/views/table/components/tableInfo.vue'
import { ref, onMounted } from 'vue'
import { useUser } from "@/store/user.js"
const store = useUser()
const tabActive = ref(0)
const tabAreas = ref([
{
label: '全部',
type: 0,
},
{
label: '空闲',
type: 1,
},
{
label: '使用中',
type: 2,
},
{
label: '已预订',
type: 3,
}
])
const loading = ref(false)
//
const areaList = ref([])
//
const tableList = ref([])
//
const area = ref('')
//
const tableItemActive = ref(-1)
//
const slectTable = ref('')
//
function tabChange(item, index) {
tabActive.value = index
}
//
function slectTableHandle(index, item) {
if (tableItemActive.value == index) {
tableItemActive.value = -1
slectTable.value = ''
} else {
tableItemActive.value = index
slectTable.value = item
}
}
//
function slectTableClose() {
tableItemActive.value = -1
slectTable.value = ''
}
//
async function queryShopAreaAjax() {
try {
const res = await queryShopArea({
shopId: store.userInfo.shopId
})
areaList.value = res
} catch (error) {
console.log(error)
}
}
//
async function queryShopTableAjax() {
try {
loading.value = true
const res = await queryShopTable({
shopId: store.userInfo.shopId,
areaId: area.value,
status: '',
page: 1,
pageSize: 500
})
tableList.value = res.list
setTimeout(() => {
loading.value = false
}, 500)
} catch (error) {
loading.value = false
console.log(error)
}
}
onMounted(() => {
queryShopAreaAjax()
queryShopTableAjax()
})
</script>
<style scoped lang="scss">
.cart_wrap {
flex: 1;
}
.right_card {
width: 550px;
height: 100%;
margin-left: 20px;
}
.header {
display: flex;
height: 80px;
justify-content: space-between;
border-bottom: 1px solid #ececec;
.menus {
display: flex;
padding: 0 10px;
.item {
padding: 0 10px;
display: flex;
align-items: center;
position: relative;
span {
font-size: 24px;
}
&.active {
&::after {
content: "";
width: 70%;
height: 4px;
border-radius: 4px;
position: absolute;
bottom: 0;
left: 15%;
background-color: var(--primary-color);
}
span {
color: var(--primary-color);
}
}
}
}
.all {
display: flex;
align-items: center;
padding-right: 20px;
}
}
.tab_container {
padding: 20px;
.tab_head {
padding-bottom: 20px;
}
.overflow_y {
height: calc(100vh - 225px);
overflow-y: auto;
}
.tab_list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: auto;
gap: 20px;
.item {
background-color: #efefef;
border-radius: 6px;
overflow: hidden;
&.active {
box-shadow: inset 0 0 0 2px var(--primary-color);
}
&:hover {
cursor: pointer;
}
.tab_title {
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
color: #fff;
&.subscribe {
background-color: var(--el-color-success);
}
&.closed {
background-color: #999;
}
&.opening {
background-color: var(--primary-color);
}
&.cleaning {
background-color: var(--el-color-danger);
}
}
.tab_cont {
height: 160px;
display: flex;
align-items: center;
justify-content: center;
.icon {
color: #555;
font-size: 40px;
transform: rotate(45deg);
}
}
}
}
}
</style>