Merge branch 'test' of e.coding.net:g-cphe0354/yinshoukeguanliduan/management into gyq

This commit is contained in:
gyq 2024-09-20 15:03:44 +08:00
commit 673afeb5f3
26 changed files with 6862 additions and 569 deletions

View File

@ -3,10 +3,10 @@ ENV = 'production'
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇Nginx 配置
# 接口地址,注意协议,如果你没有配置 ssl需要将 https 改为 http
# 测试
# VUE_APP_BASE_API = 'https://admintestpapi.sxczgkj.cn'
VUE_APP_BASE_API = 'https://admintestpapi.sxczgkj.cn'
# 生产
VUE_APP_BASE_API = 'https://cashieradmin.sxczgkj.cn'
# VUE_APP_BASE_API = 'https://cashieradmin.sxczgkj.cn'
# 预发布接口
# VUE_APP_BASE_API = 'https://pre-cashieradmin.sxczgkj.cn'

View File

@ -595,7 +595,86 @@ export function updateStatus(data) {
data
});
}
// 叫号记录
export function callRecord(params) {
return request({
url: `/callTable/callRecord`,
method: "get",
params
});
}
// 删除桌型
export function callTabledelete(data) {
return request({
url: `/callTable`,
method: "delete",
data
});
}
export function callTablepost(data) {
return request({
url: '/callTable',
method: 'post',
data
})
}
// 桌型列表
export function callTable(params) {
return request({
url: `/callTable`,
method: "get",
params
});
}
// 修改桌号
export function callTabledataput(data) {
return request({
url: `/callTable`,
method: "put",
data
});
}
// 叫号列表
export function callTablequeue(params) {
return request({
url: '/callTable/queue',
method: 'get',
params
})
}
// 取消叫号
export function callTableput(data) {
return request({
url: `/callTable/updateState`,
method: "put",
data
});
}
export function callTabletakeNumber(data) {
return request({
url: '/callTable/takeNumber',
method: 'post',
data: {
...data
}
})
}
// 叫号配置获取
export function callTableconfig(params) {
return request({
url: '/callTable/config',
method: 'get',
params
})
}
// 叫号配置修改
export function callTableconfigput(data) {
return request({
url: `/callTable/config`,
method: "put",
data
});
}
/**
* 员工删除
* @returns

View File

@ -9,7 +9,10 @@ export function tbShopTableGet(params) {
return request({
url: `/api/tbShopTable`,
method: "get",
params
params:{
shopId: localStorage.getItem("shopId"),
...params
}
});
}
@ -327,4 +330,76 @@ export function $payOrder(data) {
...data
}
});
}
}
//退单
export function $returnCart(data) {
return request({
url: '/api/place/returnCart',
method: "put",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}
// 选择台桌
export function $choseTable(data) {
return request({
url: '/api/place/choseTable',
method: "put",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}
// 用餐人数
export function $choseCount(data) {
return request({
url: '/api/place/choseCount',
method: "put",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}
// 批量生成台桌
export function $fastCreateTable(data) {
return request({
url: '/api/tbShopTable/generate',
method: "post",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}
//打印当前台桌订单
export function $printOrder(data) {
return request({
url: '/api/place/printOrder',
method: "post",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}
//打印当前台桌菜品
export function $printDishes(data) {
return request({
url: '/api/place/printDishes',
method: "post",
data:{
shopId: localStorage.getItem("shopId"),
...data
}
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

View File

@ -99,13 +99,16 @@ export default {
},
filters: {
devicesName(value) {
return devices.find(item => item.value == value).name
const item=devices.find(item => item.value == value)
return item?item.name:''
},
modelsName(value) {
return models.find(item => item.value == value).name
const item=models.find(item => item.value == value)
return item?item.name:''
},
subTypesName(value) {
return subTypes.find(item => item.value == value).name
const item=subTypes.find(item => item.value == value)
return item?item.name:''
},
timeFilter(s) {
return dayjs(s).format('YYYY-MM-DD HH:mm:ss')

383
src/views/lineUp/basic.vue Normal file
View File

@ -0,0 +1,383 @@
<template>
<div class="basicStyle">
<div>
<el-form ref="form" :model="form" :rules="rules" label-width="140px" label-position="left">
<el-form-item label="排队页地址">
<span style="color: #999999;">{{ form.pageAddress }}</span>
<span @click="copydata">复制</span>
</el-form-item>
<el-form-item label="线上取号">
<el-switch v-model="form.isOnline" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item label="背景图片">
<el-image :src="form.bgCover || require('@/assets/images/upload.png')" fit="contain"
style="width: 80px;height: 80px;" @click="
showUpload = true;
uploadIndex = 1;
"></el-image>
</el-form-item>
<el-form-item label="桌型">
<el-button type="primary" @click="showLocation = true; title = '新增'">添加</el-button>
<el-table :data="formtable.records" border style="width:50%;margin-top: 20px;">
<el-table-column prop="name" label="名称">
</el-table-column>
<el-table-column prop="note" label="描述">
</el-table-column>
<el-table-column prop="waitTime" label="等待时间「桌」">
</el-table-column>
<el-table-column prop="prefix" label="号码前缀">
</el-table-column>
<el-table-column prop="start" label="开始号码">
</el-table-column>
<el-table-column prop="name" label="操作">
<template v-slot="scope">
<div style="display: flex;gap: 10px;">
<el-button type="text" @click="editPop(scope.row)">编辑</el-button>
<el-button type="text" style="color: #FF4D4F;"
@click="deleteevnt(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<h2>通知模板</h2>
<el-form ref="form" :model="form" :rules="rules" label-width="140px" label-position="left">
<el-form-item label="排队成功提醒">
<el-input v-model="form.successMsg" placeholder="请输入排队成功提醒" disabled
style="width: 500px;"></el-input>
</el-form-item>
<el-form-item label="排队即将排到通知">
<el-input v-model="form.nearMsg" placeholder="请输入排队成功提醒" disabled style="width: 500px;"></el-input>
<div class="duoshaozhuo">
<div>前面等待</div>
<el-input v-model="form.nearNum" placeholder="" disabled></el-input>
<div>桌时提醒</div>
</div>
</el-form-item>
<el-form-item label="排队到号提醒">
<el-input v-model="form.callingMsg" placeholder="请输入排队到号提醒" disabled
style="width: 500px;"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog :title="title" :visible.sync="showLocation" width="500px">
<el-form :model="forms" label-width="140px" label-position="left">
<el-form-item label="名称">
<el-input v-model="forms.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="forms.note" placeholder="如1-2人"></el-input>
</el-form-item>
<el-form-item label="等待时间">
<el-input v-model="forms.waitTime" placeholder="0">
<template slot="append">分钟/1</template>
</el-input>
</el-form-item>
<el-form-item label="号码前缀">
<el-input v-model="forms.prefix" placeholder="请输入英文字母「不支持中文」"></el-input>
</el-form-item>
<el-form-item label="开始号码">
<el-input v-model="forms.start" placeholder="请输入开始号码"></el-input>
</el-form-item>
<el-form-item label="过号保留">
<el-input v-model="forms.postponeNum" :disabled="!forms.isPostpone" placeholder="请输入名称">
<template slot="append"></template>
<div slot="prepend">
<span> <el-checkbox v-model="forms.isPostpone">开启顺延</el-checkbox></span>
</div>
</el-input>
</el-form-item>
<el-form-item label="" width="120">
<template v-slot="scope">
<div style="display: flex;gap: 10px;">
<el-button plain @click="showLocation = false; forms = {}">取消</el-button>
<el-button type="primary" @click="submitE">确定</el-button>
</div>
</template>
</el-form-item>
</el-form>
</el-dialog>
<el-dialog :visible.sync="showUpload" :close-on-click-modal="false" append-to-body width="500px"
@close="showUpload = false">
<el-upload :before-remove="handleBeforeRemove" :on-success="handleSuccess" :on-error="handleError"
:file-list="fileList" :headers="headers" :action="qiNiuUploadApi" class="upload-demo" multiple>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" style="display: block;" class="el-upload__tip">
请勿上传违法文件且文件不超过15M
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="doSubmit">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import crudQiNiu from "@/api/tools/qiniu";
import { callTableconfig, callTable, callTableconfigput, callTablepost,callTabledataput, callTabledelete } from "@/api/shop";
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["qiNiuUploadApi"])
},
data() {
return {
showLocation: false,
showUpload: false,
uploadIndex: 1,
startTime: "",
endTime: "",
formLoading: false,
form: {},
forms: {},
formtable: "",
rules: {
shopName: [
{
required: true,
message: " ",
trigger: "blur"
}
],
phone: [
{
required: true,
message: " ",
trigger: "blur"
}
],
settleTime: [
{
required: true,
message: " ",
trigger: "blur"
}
]
},
fileList: [],
files: [],
headers: {
Authorization: getToken()
},
title: ""
};
},
mounted() {
this.tbShopInfo();
},
methods: {
async editPop(item) {
this.forms = item
console.log(item, '调试131')
console.log(item.isPostpone, '调试131')
this.showLocation = true
this.title = '编辑'
},
async deleteevnt(item) {
const res = await callTabledelete({
shopId: localStorage.getItem("shopId"),
callTableId: item.id
});
this.tbShopInfo()
},
async submitE() {
if (this.title == '新增') {
const res = await callTablepost({
shopId: localStorage.getItem("shopId"),
...this.forms
});
if (res) {
this.showLocation = false
this.tbShopInfo()
}
} else {
console.log(this.forms.nearNum,'调试121')
const res = await callTabledataput({
shopId: localStorage.getItem("shopId"),
...this.forms,
callTableId:this.forms.id
});
if (res) {
this.showLocation = false
this.tbShopInfo()
}
}
},
//
async tbShopInfo() {
try {
const res = await callTableconfig({ shopId: localStorage.getItem("shopId") });
this.form = res;
const data = await callTable({
shopId: localStorage.getItem("shopId"),
page: 1,
size: 10,
});
this.formtable = data
} catch (error) { }
},
//
submitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
this.formLoading = true;
try {
// if (this.startTime && this.endTime) {
// this.form.businessTime = `${this.startTime}-${this.endTime}`;
// }
const res = await callTableconfigput(this.form);
this.formLoading = false;
this.forms = {}
this.$notify({
title: "成功",
message: "提交成功",
type: "success"
});
} catch (error) { }
}
});
},
handleSuccess(response, file, fileList) {
// const uid = file.uid
// const id = response.id
// this.files.push({ uid, id })
console.log("上传成功", response);
this.files = response.data;
this.form.bgCover = response.data[0]
},
handleBeforeRemove(file, fileList) {
for (let i = 0; i < this.files.length; i++) {
if (this.files[i].uid === file.uid) {
crudQiNiu.del([this.files[i].id]).then(res => { });
return true;
}
}
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
//
handleError(e, file, fileList) {
const msg = JSON.parse(e.message);
this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR);
},
async copydata(content) {
let copyResult = true
//
const text = this.form.pageAddress || '复制内容为空哦~';
// clipboard
if (!!window.navigator.clipboard) {
// clipboardpromise
await window.navigator.clipboard.writeText(text).then((res) => {
console.log('复制成功');
}).catch((err) => {
console.log('复制失败--采取第二种复制方案', err);
// clipboard document.execCommand()
copyResult = copyContent2(text)
})
} else {
// clipboard document.execCommand()
copyResult = copyContent2(text)
}
//
// return copyResult;
},
//
doSubmit() {
this.fileList = [];
this.showUpload = false;
switch (this.uploadIndex) {
case 1:
this.form.bgCover = this.files[0];
break;
case 2:
this.form.coverImg = this.files[0];
break;
case 3:
this.form.shopQrcode = this.files[0];
break;
default:
break;
}
}
}
};
</script>
<style scoped lang="scss">
.basicStyle {
padding: 20px;
}
.map_box {
width: 100%;
position: relative;
.map {
height: 300px;
}
.search_box {
position: absolute;
top: 10px;
left: 10px;
}
.search_wrap {
padding: 6px 0;
.item {
display: flex;
padding: 12px 0;
.left {
flex: 1;
display: flex;
flex-direction: column;
padding-right: 20px;
.location {
color: #999;
padding-top: 4px;
}
}
}
}
}
.duoshaozhuo {
display: flex;
align-items: center;
>input {
width: 120px;
border: none !important;
}
>div {
color: #999;
width: 118px;
height: 33px;
line-height: 33px;
text-align: center;
border: 1px solid #DDDFE6;
background-color: #f5f7fa;
margin-top: 9px;
}
}
</style>

447
src/views/lineUp/index.vue Normal file
View File

@ -0,0 +1,447 @@
<template>
<div class="lineUpBox">
<div class="lineUpBoxTop">
<ul class="lineUpBoxUl">
<li :class="[[selecttopType == '' ? 'active' : '']]" @click="gettypeevent('')">
<div>全部</div>
<div>{{ tableData.totalCount }}</div>
<div class="postionStyle" v-if="selecttopType == ''">
<i class="el-icon-check postionStyleI"></i>
</div>
</li>
<li v-for="item in tableData.records" :key="item.id" @click="gettypeevent(item.id)"
:class="[[selecttopType == item.id ? 'active' : '']]">
<div>{{ item.name }}</div>
<div>{{ item.totalCount }}</div>
<div class="postionStyle" v-if="selecttopType == item.id">
<i class="el-icon-check postionStyleI"></i>
</div>
</li>
</ul>
<div class="buttonstyle">
<el-button type="primary" @click="dialogVisibles = true">取号</el-button>
<el-button plain type="primary" @click="toUrl">叫号记录</el-button>
</div>
</div>
<div style="display: flex;align-items: center;flex-wrap: wrap;justify-content: space-between; ">
<div class="lineUpBoxList" v-for="item in list.records" :key="item.id">
<ul>
<li>
<div>用户</div>
<div>{{ item.phone }}</div>
</li>
<li>
<div>号码</div>
<div>{{ item.callNum }}</div>
</li>
<li>
<div>桌型</div>
<div>{{ item.name }}{{ item.note }}</div>
</li>
<li>
<div>等待</div>
<div>{{ item.waitingCount }}</div>
</li>
</ul>
<div>
<el-button type="primary" @click="dialogConfirm(1, item)">取消</el-button>
<el-button type="primary" @click="profilepicture(item)">播报</el-button>
</div>
</div>
</div>
<!-- 播报弹窗 -->
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
<span>通知消息已发送</span>
<span slot="footer" class="dialog-footer">
<el-button style="" @click="dialogConfirm(2)">完成</el-button>
<el-button type="primary" @click="dialogConfirm(3)">过号</el-button>
</span>
</el-dialog>
<!-- 取号 -->
<el-dialog title="取号" :visible.sync="dialogVisibles" width="30%">
<div>
<div style="color: #000;">选择桌型</div>
<ul class="lineUpBoxUl" style="margin-top: 10px;">
<li v-for="item in tableData.records" :key="item.id" @click="selectTabletype = item"
:class="[[selectTabletype.id == item.id ? 'active' : '']]">
<div>{{ item.name }}</div>
<div>{{ item.totalCount }}</div>
<div class="postionStyle" v-if="selectTabletype.id == item.id">
<i class="el-icon-check postionStyleI"></i>
</div>
</li>
</ul>
<div style="margin-top: 20px;color: #000;">手机号码</div>
<div style="margin-top: 10px;">
<input v-model="phone" style="height: 30px;" type="text" placeholder="填写号码" />
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="callTabletakeNumberEvent">确认取号</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { callTable, callTablequeue, callTableput, callTabletakeNumber } from '@/api/shop'
export default {
data() {
return {
query: {
productId: '',
name: '',
categoryId: '',
typeEnum: ''
},
tableData: {
data: [],
page: 0,
size: 30,
loading: false,
total: 0
},
selecttopType: "",
list: "",
dialogVisible: false,
dialogVisibles: false,
profilepictureInfo: "",
phone: "",
selectTabletype: ""
}
},
async mounted() {
await this.getlist()
await this.getTableData()
},
methods: {
async callTabletakeNumberEvent() {
const res = await callTabletakeNumber({
callTableId: this.selectTabletype.id,
shopId: localStorage.getItem('shopId'),
phone: this.phone,
note: this.selectTabletype.note,
name: this.selectTabletype.name,
})
if (res.callNum) {
this.getTableData()
this.getlist()
this.dialogVisibles = false
}
},
profilepicture(d) {
this.dialogVisible = true
this.profilepictureInfo = d
},
gettypeevent(d) {
this.selecttopType = d
this.getTableData()
this.getlist()
},
async dialogConfirm(value, item) {
if (value == 1) {
const res = await callTableput({
shopId: localStorage.getItem('shopId'),
state: -1,
callQueueId: item.id
})
if (res) {
this.getTableData()
this.getlist()
}
} else if (value == 2) {
const res = await callTableput({
shopId: localStorage.getItem('shopId'),
state: 1,
callQueueId: this.profilepictureInfo.id
})
if (res) {
this.getTableData()
this.getlist()
this.dialogVisible = false
}
} else if (value == 3) {
const res = await callTableput({
shopId: localStorage.getItem('shopId'),
state: 3,
callQueueId: this.profilepictureInfo.id
})
if (res) {
this.getTableData()
this.getlist()
this.dialogVisible = false
}
}
}
,
toUrl() {
this.$router.push({ path: '/lineUp/record' })
},
//
async getTableData() {
try {
const res = await callTable({
shopId: localStorage.getItem('shopId'),
page: 1,
size: 10,
})
// this.tableData.loading = false
this.tableData = res
this.selectTabletype = res.records[0]
// this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
},
async getlist() {
const res = await callTablequeue({
shopId: localStorage.getItem('shopId'),
page: 1,
size: 9999,
callTableId: this.selecttopType,
state: 0
})
this.list = res
}
},
}
</script>
<style scoped lang="scss">
* {
margin: 0;
text-decoration: none;
outline: none;
}
ul,
li {
list-style: none;
}
.show {
display: none !important;
}
.hidden {
display: block !important;
}
.lineUpBox {
padding: 20px;
}
.lineUpBoxTop {
display: flex;
align-items: center;
justify-content: space-between;
.lineUpBoxUl {
display: flex;
align-items: center;
padding: 0;
>li {
border-radius: 4px 4px 4px 4px;
border: 1px solid #DDDFE6;
width: 112px;
height: 55px;
text-align: center;
margin-right: 52px;
position: relative;
>div {
margin-top: 8px;
color: #999;
}
>div:first-child {
color: #333333;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 14px;
line-height: 16px;
text-align: center;
}
.postionStyle {
position: absolute;
right: 0px;
top: -9px;
width: 0;
height: 0;
border: 14px solid;
border-color: #318AFE #318AFE #fff #fff;
}
.postionStyleI {
position: absolute;
right: -13px;
top: -13px;
color: #fff;
font-size: 14px;
}
}
.active {
border: 2px solid #318AFE;
>view:first-child {
color: #318AFE;
}
}
}
.buttonstyle {
>button {
height: 31px;
padding: 5px 16px;
font-weight: 500;
font-size: 14px;
}
}
}
.lineUpBoxList {
width: 507px;
// flex: 0 0 50%;
height: 148px;
background: #FFFFFF;
border-radius: 6px 6px 6px 6px;
border: 1px solid #DDDFE6;
margin-top: 30px;
>ul {
padding: 16px;
display: flex;
align-items: center;
justify-content: space-between;
>li {
>div:nth-child(2) {
margin-top: 15px;
}
}
}
>div {
display: flex;
justify-content: space-around;
>button {
width: 169px;
height: 32px;
box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.02);
border-radius: 1px 1px 1px 1px;
border: 1px solid #D9D9D9;
}
>button:first-child {
background: #FFFFFF;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 14px;
color: #666666;
text-align: center;
}
}
}
.lineUpBoxUl {
display: flex;
align-items: center;
padding: 0;
>li {
border-radius: 4px 4px 4px 4px;
border: 1px solid #DDDFE6;
width: 112px;
height: 55px;
text-align: center;
margin-right: 52px;
position: relative;
>div {
margin-top: 8px;
color: #999;
}
>div:first-child {
color: #333333;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 14px;
line-height: 16px;
text-align: center;
}
.postionStyle {
position: absolute;
right: 0px;
top: -9px;
width: 0;
height: 0;
border: 14px solid;
border-color: #318AFE #318AFE #fff #fff;
}
.postionStyleI {
position: absolute;
right: -13px;
top: -13px;
color: #fff;
font-size: 14px;
}
}
.active {
border: 2px solid #318AFE;
>view:first-child {
color: #318AFE;
}
}
}
.handle {
font-size: 18px;
color: #999;
&:hover {
cursor: grab;
}
}
.shop_info {
display: flex;
.info {
flex: 1;
padding-left: 8px;
display: flex;
flex-direction: column;
.tag_wrap {
display: flex;
}
}
}
</style>

124
src/views/lineUp/record.vue Normal file
View File

@ -0,0 +1,124 @@
<template>
<div class="app-container">
<div class="head-container">
叫号记录
</div>
<div class="head-container" id="table_drag">
<el-table ref="table" :data="tableData.data" v-loading="tableData.loading" row-key="id">
<el-table-column label="桌号" prop="callNum"> </el-table-column>
<el-table-column label="桌型" prop="typeEnum">
<template v-slot="scope">
{{ scope.row.name }}({{ scope.row.note }})
</template>
</el-table-column>
<el-table-column label="手机号" prop="phone"> </el-table-column>
<el-table-column label="状态">
<template v-slot="scope">
<span>{{ scope.row.state | stateFilter }}</span>
</template>
</el-table-column>
<el-table-column label="时间" prop="callTime"> </el-table-column>
</el-table>
</div>
<!-- <div class="head-container">
<el-pagination :total="tableData.total" @size-change="handleSizeChange" :current-page="tableData.page + 1"
:page-size="tableData.size" @current-change="paginationChange"
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div> -->
</div>
</template>
<script>
import { callRecord, } from '@/api/shop'
export default {
data() {
return {
query: {
productId: '',
name: '',
categoryId: '',
typeEnum: ''
},
tableData: {
data: [],
page: 0,
size: 30,
loading: false,
total: 0
}
}
},
async mounted() {
await this.getTableData()
},
methods: {
//
// paginationChange(e) {
// this.tableData.page = e - 1
// this.getTableData()
// },
//
async getTableData() {
try {
const res = await callRecord({
shopId: localStorage.getItem('shopId'),
page: 1,
size: 9999
})
this.tableData.data = res.records
} catch (error) {
console.log(error)
}
},
// handleSizeChange(val) {
// this.tableData.size = val
// this.getTableData()
// },
},
filters: {
stateFilter(i) {
if (i == -1) {
return '已取消'
} else if (i == 0) {
return '排队中'
} else if (i == 1) {
return '叫号中'
} else if (i == 2) {
return '已入座'
} else if (i == 3) {
return '已过号 '
}
}
}
}
</script>
<style scoped lang="scss">
.handle {
font-size: 18px;
color: #999;
&:hover {
cursor: grab;
}
}
.shop_info {
display: flex;
.info {
flex: 1;
padding-left: 8px;
display: flex;
flex-direction: column;
.tag_wrap {
display: flex;
}
}
}
</style>

View File

@ -743,7 +743,7 @@ export default {
costPrice: undefined,
originPrice: undefined,
stockNumber: undefined,
firstShared: undefined,
firstShared: 0,
barCode: `${localStorage.getItem("shopId")}${dayjs().valueOf()}`,
isGrounding: 1,
productId: this.$route.query.goods_id ? this.$route.query.goods_id : "",

View File

@ -1,137 +1,229 @@
<template>
<el-dialog :title="form.id ? '编辑台桌' : '添加台桌'" :visible.sync="dialogVisible" @open="tbShopAreaGet" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="选择区域" prop="areaId">
<el-select v-model="form.areaId" placeholder="请选择区域">
<el-option :label="item.name" :value="item.id" v-for="item in areaList" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌状态" prop="status" v-if="form.id">
<el-select v-model="form.status" placeholder="请选择台桌状态">
<el-option :label="item.name" :value="item.value" v-for="item in status" :key="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌名称">
<el-input v-model="form.name" placeholder="请输入台桌名称"></el-input>
</el-form-item>
<el-form-item label="客座数">
<el-input-number v-model="form.maxCapacity" :min="0" controls-position="right"></el-input-number>
</el-form-item>
<el-form-item label="网络预定开关">
<el-switch v-model="form.isPredate" :active-value="1" :inactive-value="2"></el-switch>
</el-form-item>
<el-form-item label="类型">
<el-radio-group v-model="form.type">
<el-radio-button :label="0">低消</el-radio-button>
<el-radio-button :label="2">计时</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="最低消费" v-if="form.type == 0">
<el-input-number v-model="form.amount" :min="0" controls-position="right"></el-input-number>
</el-form-item>
<el-form-item label="每小时收费" v-if="form.type == 2">
<el-input-number v-model="form.perhour" :min="0" controls-position="right"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="loading" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
<el-dialog
:title="form.id ? '编辑台桌' : '添加台桌'"
:visible.sync="dialogVisible"
@open="tbShopAreaGet"
@close="reset"
>
<el-form
ref="form"
:model="form"
:rules="rules"
label-width="120px"
label-position="left"
>
<el-form-item label="选择区域" prop="areaId">
<el-select v-model="form.areaId" placeholder="请选择区域">
<el-option
:label="item.name"
:value="item.id"
v-for="item in areaList"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌状态" prop="status" v-if="form.id">
<el-select v-model="form.status" placeholder="请选择台桌状态">
<el-option
:label="item.name"
:value="item.value"
v-for="item in status"
:key="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌标识" >
<div class="u-flex">
<div class="u-flex" style="width: 57px;">
<el-input
v-model="form.sign"
placeholder="A"
></el-input>
</div>
<div class="u-flex u-m-l-30" >
<div class="u-flex">
<div class="u-m-r-4">起始</div>
<el-input v-model="form.start" style="width: 57px;" placeholder="请输入起始值" >
</el-input>
</div>
<div
style="
background-color: #D9D9D9;
height: 1px;
width: 32px;
border-radius: 1px;
"
class="u-m-l-16 u-m-r-16"
></div>
<div class="u-flex">
<span class="u-m-r-4">结束</span>
<el-input v-model="form.end" style="width: 57px;" placeholder="请输入结束值">
</el-input>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="客座数">
<el-input-number
v-model="form.capacity"
:min="0"
controls-position="right"
></el-input-number>
</el-form-item>
<el-form-item label="清台管理">
<el-radio-group v-model="form.autoClear">
<el-radio-button :label="0">手动清台</el-radio-button>
<el-radio-button :label="1">自动清台</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="网络预定开关">
<el-switch
v-model="form.isPredate"
:active-value="1"
:inactive-value="2"
></el-switch>
</el-form-item>
<el-form-item label="类型">
<el-radio-group v-model="form.type">
<el-radio-button :label="0">低消</el-radio-button>
<el-radio-button :label="2">计时</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="最低消费" v-if="form.type == 0">
<el-input-number
v-model="form.amount"
:min="0"
controls-position="right"
></el-input-number>
</el-form-item>
<el-form-item label="每小时收费" v-if="form.type == 2">
<el-input-number
v-model="form.perhour"
:min="0"
controls-position="right"
></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="loading" @click="onSubmitHandle"
> </el-button
>
</span>
</el-dialog>
</template>
<script>
import { tbShopTable, tbShopAreaGet } from '@/api/table'
import { tbShopTable, tbShopAreaGet ,$fastCreateTable} from "@/api/table";
export default {
data() {
return {
dialogVisible: false,
resetForm: '',
loading: false,
status:[
{value:'pending',name:'挂单中'},
{value:'using',name:'开台中'},
{value:'paying',name:'结算中'},
{value:'idle',name:'空闲'},
{value:'subscribe',name:'预定'},
{value:'closed',name:'关台'},
// {value:'opening',name:''},
{value:'cleaning',name:'台桌清理中'},
],
form: {
id: '',
name: '',
areaId: '',
maxCapacity: 0,
isPredate: 1,
type: 2,
perhour: 0,
amount: 0
},
rules: {
areaId: [
{
required: true,
message: '请选择区域',
trigger: 'blur'
}
]
},
areaList: []
data() {
return {
dialogVisible: false,
resetForm: "",
loading: false,
status: [
{ value: "pending", name: "挂单中" },
{ value: "using", name: "开台中" },
{ value: "paying", name: "结算中" },
{ value: "idle", name: "空闲" },
{ value: "subscribe", name: "预定" },
{ value: "closed", name: "关台" },
// {value:'opening',name:''},
{ value: "cleaning", name: "台桌清理中" },
],
form: {
id: "",
areaId: "",
sign:'',
start:1,
end:10,
capacity: 0,
isPredate: 1,
type: 2,
perhour: 0,
amount: 0,
autoClear: 1,
},
rules: {
areaId: [
{
required: true,
message: "请选择区域",
trigger: "blur",
},
],
sign: [
{
required: true,
message: "请输入台桌标识",
trigger: "blur",
},
],
},
areaList: [],
};
},
mounted() {
this.resetForm = { ...this.form };
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.loading = true;
try {
let res = await $fastCreateTable(
{
...this.form,
qrcode: this.form.tableId,
shopId: localStorage.getItem("shopId"),
},
this.form.id ? "put" : "post"
);
this.$emit("success", res);
this.close();
this.$notify({
title: "成功",
message: `${this.form.id ? "编辑" : "添加"}成功`,
type: "success",
});
this.loading = false;
} catch (error) {
this.loading = false;
console.log(error);
}
}
});
},
mounted() {
this.resetForm = { ...this.form }
show(obj) {
this.dialogVisible = true;
if (obj && obj.id) {
this.form = JSON.parse(JSON.stringify(obj));
}
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
this.loading = true
try {
let res = await tbShopTable({
...this.form,
qrcode:this.form.tableId,
shopId: localStorage.getItem('shopId')
}, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
this.loading = false
} catch (error) {
this.loading = false
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = JSON.parse(JSON.stringify(obj))
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form = { ...this.resetForm }
},
//
async tbShopAreaGet() {
try {
const { content } = await tbShopAreaGet({
shopId: localStorage.getItem('shopId')
})
this.areaList = content
} catch (error) {
console.log(error);
}
}
}
}
close() {
this.dialogVisible = false;
},
reset() {
this.form = { ...this.resetForm };
},
//
async tbShopAreaGet() {
try {
const { content } = await tbShopAreaGet({
shopId: localStorage.getItem("shopId"),
});
this.areaList = content;
} catch (error) {
console.log(error);
}
},
},
};
</script>

View File

@ -18,7 +18,7 @@
</el-form-item> -->
<el-form-item>
<div class="flex gap-20">
<el-button type="success" @click="getTableData" size="medium"
<el-button type="primary" @click="getTableData" size="medium"
>搜索</el-button
>
<!-- <el-button @click="resetHandle" size="medium">重置</el-button> -->
@ -77,7 +77,7 @@
<el-table-column label="操作" width="90" fixed="right">
<template v-slot="scope">
<el-button type="success" size="mini" @click="choose(scope.row)">选择</el-button>
<el-button type="primary" size="mini" @click="choose(scope.row)">选择</el-button>
<!-- <el-button type="text" @click="charge(scope.row)">充值</el-button> -->
</template>
</el-table-column>

View File

@ -1,7 +1,11 @@
<template>
<div class="simple-Keyboard-number">
<div class="carts">
<div class="box_status">{{ number }}</div>
<div class="box_status">
<slot name="input">
<span> {{ number }}</span>
</slot>
</div>
<div class="number_list_box">
<div class="yd-keyboard">
<div class="mini-number-box1">
@ -22,7 +26,9 @@
<div class="key" @click="keyboradAdd('9')">9</div>
</div>
<div class="key-line">
<div class="key"></div>
<div class="key" @click="clearFunction">
<slot name="clear"> </slot>
</div>
<div class="key" @click="keyboradAdd('0')">0</div>
<div
class="key"
@ -64,10 +70,18 @@ export default {
type: Boolean,
default: false,
},
maxTips: {
type: String,
default: "输入值超范围",
},
showConfirm: {
type: Boolean,
default: false,
},
max: {
type: Number,
default: Infinity,
},
value: {
type: [String, Number],
default: 0,
@ -79,22 +93,33 @@ export default {
};
},
watch: {
value(newval) {
this.number = newval;
},
number(newval) {
console.log(newval);
this.$emit("input", newval);
},
},
methods: {
clearFunction() {
this.$emit("clear", this.number);
},
keyboradAdd(n) {
if (Number(this.number) == 0) {
return (this.number = n);
}
this.number += n;
const newval = this.number + n;
if (newval > this.max) {
return this.$message( this.maxTips);
}
this.number = newval;
},
keyboradReduce() {
if (this.number.length <= 1) {
return (this.number =this.isCanEmpty?'': "0");
return (this.number = this.isCanEmpty ? "" : "0");
}
this.number = this.number.substring(0, this.number.length - 1);
this.number = `${this.number}`.substring(0, this.number.length - 1);
},
keyboradConfirm() {
this.$emit("confirm", this.number);

View File

@ -9,7 +9,7 @@
@click="changeSel(item)"
v-for="(item, index) in list"
:key="index"
:type="sel === item.payType ? 'success' : ''"
:type="sel === item.payType ? 'primary' : ''"
>
{{ item.payName }}
</el-button>

File diff suppressed because one or more lines are too long

View File

@ -1,17 +1,22 @@
<template>
<div
class="flex order-item relative"
:class="{ active: selIndex === index }"
:class="[isActive]"
@click="itemClick"
>
<span class="absolute pack" v-if="item.isPack === 'true'"> </span>
<span class="absolute tui" v-if="item.status === 'return'"> 退 </span>
<div class="flex">
<div class="img">
<img :src="item.coverImg" class="" alt="" />
<div class="isSeatFee img u-line-1 u-flex u-col-center u-row-center" v-if="isSeatFee">
<span>{{ item.name }}</span>
</div>
<img v-else :src="item.coverImg" class="" alt="" />
</div>
<div class="good-info">
<div class="flex lh-16">
<div class="name">{{ item.name }}</div>
<div class="name" :class="{ 'free-price': item.status === 'return' }">{{ item.name }}</div>
<span class="good_info_discount" v-if="item.isGift === 'true'"
></span
>
@ -23,7 +28,8 @@
</div>
<div class="flex">
<div class="order-number-box">
<div class="" style="">X{{ item.number }}</div>
<div class="" v-if="isSeatFee">X{{ item.totalNumber }}</div>
<div class="" v-else>X{{ item.number }}</div>
<div class="absolute" v-if="canChangeNumber">
<div class="order-input-number">
<i class="icon-remove" @click="changeOrderNumber(true)"></i>
@ -44,11 +50,12 @@
</div>
</div>
</div>
<div class="color-333 total-price">
<div v-if="item.isGift === 'true'">0</div>
<div :class="{ 'free-price': item.isGift === 'true' }">
{{ item.salePrice }}
<div v-if="item.isGift === 'true'||item.status=='return' ">0</div>
<div :class="{ 'free-price': item.isGift === 'true'||item.status=='return' }">
<span v-if="isSeatFee"> {{ item.totalAmount }}</span>
<span v-else> {{ item.salePrice }}</span>
</div>
</div>
</div>
@ -58,7 +65,26 @@
<script>
export default {
props: {
//
//
isSeatFee:{
type: Boolean,
default: false,
},
//
isOld:{
type: Boolean,
default: false,
},
// 1 0
placeNum:{
type: [String,Number],
default: 0,
},
selPlaceNum:{
type: [String,Number],
default: -1,
},
//
canChangeNumber: {
type: Boolean,
default: true,
@ -85,6 +111,13 @@ export default {
number: 0,
};
},
computed: {
isActive(){
const isSel= (this.selIndex === this.index)&&(this.placeNum===this.selPlaceNum)
console.log(isSel)
return isSel?'active':'';
}
},
watch: {
"item.number": function (val) {
this.number = val;
@ -118,7 +151,10 @@ export default {
this.$emit("changeOrderNumber", this.index, isReduce);
},
itemClick() {
this.$emit("itemClick", this.index,this.canChangeNumber);
if(this.isSeatFee){
return
}
this.$emit("itemClick", this.index,this.canChangeNumber,this.placeNum);
},
},
};
@ -135,6 +171,11 @@ export default {
padding: 0 4px;
text-align: center;
}
.isSeatFee{
background: #3F9EFF;
color: #fff;
font-size: 12px;
}
.icon-remove {
border: 1px solid #d8d8d8;
width: 22px;
@ -179,6 +220,17 @@ export default {
text-align: center;
line-height: 17px;
}
.tui{
right: 100%;
width: 18px;
height: 18px;
background: #ac4735;
border-radius: 4px 0 4px 0;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 17px;
}
&.active {
background-color: rgba(0, 0, 0, 0.04);
}

View File

@ -0,0 +1,274 @@
<template>
<div class="select_desk">
<el-dialog width="410px" title="就餐人数" :visible.sync="show">
<div class="select_desk_dialog u-p-b-20">
<key-board
isCanEmpty
v-model="number"
@clear="clear"
:max="max"
:maxTips=" '最多'+max+'位'"
>
<div slot="clear">清空</div>
<div slot="input" class="u-p-l-20 u-p-r-20 u-flex w-full">
<el-input
placeholder="请输入就餐人数"
v-model="number"
@input="inputNumber"
@change="inputChange"
type="number"
>
<template slot="append"></template>
</el-input>
</div>
</key-board>
<div class="confirm_btns">
<el-button size="medium" @click="close">取消</el-button>
<el-button type="primary" size="medium" @click="confirm"
>确定</el-button
>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import keyBoard from "../keyboard.vue";
export default {
components: { keyBoard },
props:{
max:{
type:Number,
default:99
}
},
data() {
return {
number: "",
show: false,
hasOpen: false,
loading: false,
};
},
watch: {
number(newval) {
console.log(newval)
console.log(this.max)
if (newval >this.max) {
this.number = this.max;
this.$message("最多只能选择"+this.max+"位就餐人数");
}
console.log(newval);
// 使
const regex = /^[1-9]\d*$/;
//
if (!regex.test(newval)) {
this.number = newval.substring(0, newval.length - 1);
}
},
},
methods: {
inputNumber(e) {},
inputChange(e) {},
clear(e) {
console.log(e);
this.number = "";
},
confirm() {
console.log(this.number)
console.log(this.max)
if (this.number >this.max) {
return this.$message("最多只能选择"+this.max+"位就餐人数");
}
if (!this.number) {
return this.$message("请选择就餐人数");
}
this.$emit("confirm", this.number);
this.close();
},
open(number) {
this.number = number || "";
this.show = true;
},
close() {
this.show = false;
this.number = "";
},
},
mounted() {},
};
</script>
<style lang="scss" scoped>
::v-deep.el-button {
padding: 12px 20px;
}
::v-deep .el-input__inner::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
::v-deep .el-input__inner::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
::v-deep .el-button--success {
border-color: #22bf64;
background-color: #22bf64;
}
.select_desk .btn {
height: 34px;
}
.tags {
font-size: 16px;
&.using {
color: rgb(234, 64, 37);
}
&.wait {
color: rgb(252, 236, 79);
}
&.idle {
color: rgb(137, 234, 71);
}
&.closed {
color: rgb(221, 221, 221);
filter: grayscale(1);
}
}
::v-deep .inputs .el-input__inner {
border-color: transparent !important;
color: rgba(0, 0, 0, 0.8);
letter-spacing: 1.25px;
font-size: 20px;
}
.select_desk .select_desk_dialog {
display: flex;
flex-direction: column;
align-items: center;
}
.select_desk .select_desk_dialog .nav {
width: 286px;
height: 38px;
background: #dcf0e8;
justify-content: space-around;
}
.select_desk .select_desk_dialog .nav .li,
.select_desk .select_desk_dialog .nav {
border-radius: 4px;
display: flex;
align-items: center;
}
.select_desk .select_desk_dialog .nav .li {
width: 140px;
height: 34px;
color: #0fc161;
justify-content: center;
font-size: 14px;
cursor: pointer;
}
.select_desk .select_desk_dialog .nav .lion {
background: #0fc161;
color: #fff;
}
.select_desk .select_desk_dialog .inputs {
width: 370px;
line-height: 54px;
margin-top: 24px;
height: 54px;
margin-bottom: 20px;
background: #fff;
border: 1px solid #dcdfe6;
border-radius: 4px;
color: rgba(0, 0, 0, 0.8);
letter-spacing: 1.25px;
text-align: center;
font-size: 20px;
position: relative;
}
.select_desk .select_desk_dialog .inputs .close {
color: #aaa;
position: absolute;
right: 10px;
height: 30px;
width: 30px;
line-height: 30px;
top: 50%;
margin-top: -15px;
cursor: pointer;
}
.select_desk .select_desk_dialog .keyboard {
display: flex;
flex-wrap: wrap;
width: 100%;
margin-top: 20px;
margin-bottom: 10px;
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
}
.select_desk .select_desk_dialog .keyboard .li {
height: 60px;
width: 33.333%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: #212121;
cursor: pointer;
user-select: none;
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
transition: all 0.1s;
}
.select_desk .select_desk_dialog .keyboard .li:hover {
background: #dcdfe6;
}
.select_desk .select_desk_dialog .keyboard .li .icon {
font-size: 1.3em;
}
.select_desk .select_desk_dialog .keyboard .confirm {
height: 140px;
background: #ff9f2e;
position: absolute;
bottom: 0;
right: 0;
border-right: none;
}
.select_desk .select_desk_dialog .keyboard .confirm:hover {
background: #f88502;
}
.confirm_btns {
display: flex;
justify-content: space-between;
width: 100%;
}
.confirm_btns .el-button {
width: 175px;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="select_desk">
<el-dialog width="410px" title="桌台号/取餐号" :visible.sync="show">
<div class="select_desk_dialog">
<div class="select_desk_dialog u-p-t-20 u-p-b-20">
<div class="nav">
<div
class="li"
@ -30,16 +30,25 @@
:label="item.name"
:value="item.id"
>
<div class="u-flex u-row-between ">
<span>{{ item.name }}</span>
<span :class="['tags',item.status]">
{{ status[item.status] ? status[item.status].label : "" }}
</span>
</div>
</el-option>
</el-select>
</template>
<template v-else>
<key-board isCanEmpty v-model="masterId"></key-board>
<template v-else>
<key-board isCanEmpty v-model="masterId"></key-board>
</template>
<div class="confirm_btns">
<el-button size="medium" @click="close">取消</el-button>
<el-button type="success" size="medium" @click="confirm">确定</el-button>
<el-button size="medium" @click="close">取消</el-button>
<el-button type="primary" size="medium" @click="confirm"
>确定</el-button
>
</div>
</div>
</el-dialog>
@ -48,13 +57,14 @@
<script>
import { tbShopTableGet } from "@/api/table";
import keyBoard from '../keyboard.vue';
import keyBoard from "../keyboard.vue";
import $status from "../../status.js";
export default {
components:{keyBoard},
components: { keyBoard },
data() {
return {
masterId:'',
masterId: "",
//0 ,1
type: 0,
show: false,
@ -63,14 +73,15 @@ export default {
loading: false,
tableList: [],
selTableId: "",
status:$status
};
},
methods: {
confirm(){
const item=this.tableList.find(v=>v.id==this.selTableId)
this.$emit('confirm',item)
this.close()
confirm() {
const item = this.tableList.find((v) => v.id == this.selTableId);
this.$emit("confirm", item);
this.close();
},
//
async tbShopTableGet() {
@ -119,6 +130,22 @@ export default {
.select_desk .btn {
height: 34px;
}
.tags {
font-size: 16px;
&.using {
color: rgb(234, 64, 37);
}
&.wait{
color: rgb(252, 236, 79);
}
&.idle{
color: rgb(137, 234, 71);
}
&.closed {
color: rgb(221, 221, 221);
filter: grayscale(1);
}
}
::v-deep .inputs .el-input__inner {
border-color: transparent !important;
color: rgba(0, 0, 0, 0.8);

View File

@ -42,7 +42,7 @@
</el-form-item>
<div class="u-flex u-row-center u-m-t-50">
<el-button size="medium" @click="close">取消</el-button>
<el-button size="medium" type="success" @click="confirm"
<el-button size="medium" type="primary" @click="confirm"
>确定</el-button
>
</div>

View File

@ -19,7 +19,7 @@
:key="index"
closable
@close="delTag(index)"
type="success"
type="primary"
>
{{ tag }}
</el-tag>
@ -32,7 +32,7 @@
取消
</el-button>
<el-button size="medium"
type="success"
type="primary"
@click="confirm">确定</el-button>
</div>
</el-dialog>

View File

@ -0,0 +1,109 @@
<template>
<el-dialog title="撤单" width="410px" :visible.sync="show" @close="reset">
<div>
<div><span>撤单原因</span> <span class="color-red">*</span></div>
</div>
<div class="u-flex u-flex-wrap tags">
<div
class="tag"
v-for="(tag, index) in tags"
@click="changeSel(index)"
:key="index"
:class="{ active: tagSel == index }"
>
{{ tag }}
</div>
</div>
<div class="u-m-t-20">
<el-input
v-model="note"
size="medium"
placeholder="请输入自定义备注"
></el-input>
</div>
<div class="u-m-t-20">
<el-checkbox v-model="isPrint"
>打印退菜单</el-checkbox
>
</div>
<div slot="footer">
<el-button size="medium" @click="close"> 取消 </el-button>
<el-button size="medium" type="primary" @click="confirm">确定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
isPrint:false,
tagSel: -1,
show: false,
tags: ["人手不足", "店满无法招待", "顾客要求", "商品质量问题"],
note: "",
};
},
methods: {
changeSel(i) {
this.tagSel = i;
},
reset() {
this.note = "";
},
delTag(index) {
this.tags.splice(index, 1);
},
addNote(tag) {
if (this.note.length <= 0) {
return (this.note = tag);
}
this.note = tag + "," + this.note;
},
open(note) {
this.show = true;
},
close() {
this.show = false;
},
confirm() {
this.$emit("confirm", this.note);
this.close();
},
},
mounted() {},
};
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__body {
margin-bottom: 14px;
margin-top: 14px;
}
::v-deep .el-tag {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 5px;
cursor: pointer;
font-size: 15px;
line-height: 35px;
height: 35px;
}
.tags {
.tag {
margin: 10px 10px 0 0;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px 13px;
font-size: 14px;
color: #000;
cursor: pointer;
&.active {
color: #1890ff;
background: #e8f4ff;
border-color: #a3d3ff;
}
}
}
</style>

View File

@ -0,0 +1,109 @@
<template>
<el-dialog title="退菜" width="410px" :visible.sync="show" @close="reset">
<div>
<div><span>退菜原因</span> <span class="color-red">*</span></div>
</div>
<div class="u-flex u-flex-wrap tags">
<div
class="tag"
v-for="(tag, index) in tags"
@click="changeSel(tag)"
:key="index"
:class="{ active: tag.checked }"
>
{{ tag.label }}
</div>
</div>
<div class="u-m-t-20">
<el-input
v-model="note"
size="medium"
placeholder="请输入自定义备注"
></el-input>
</div>
<div class="u-m-t-20">
<el-checkbox v-model="isPrint"
>打印退菜单</el-checkbox
>
</div>
<div slot="footer">
<el-button size="medium" @click="close"> 取消 </el-button>
<el-button size="medium" type="primary" @click="confirm">确定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
isPrint:false,
tagSel: -1,
show: false,
tags: [{label:"不想要了",checked:false} ,{label:"食材不足",checked:false} ,{label:"等待时间过长",checked:false}],
note: "",
};
},
methods: {
changeSel(item) {
item.checked = !item.checked ;
},
reset() {
this.note = "";
},
delTag(index) {
this.tags.splice(index, 1);
},
addNote(tag) {
if (this.note.length <= 0) {
return (this.note = tag);
}
this.note = tag + "," + this.note;
},
open(note) {
this.show = true;
},
close() {
this.show = false;
},
confirm() {
this.$emit("confirm", this.note);
this.close();
},
},
mounted() {},
};
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__body {
margin-bottom: 14px;
margin-top: 14px;
}
::v-deep .el-tag {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 5px;
cursor: pointer;
font-size: 15px;
line-height: 35px;
height: 35px;
}
.tags {
.tag {
margin: 10px 10px 0 0;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px 13px;
font-size: 14px;
color: #000;
cursor: pointer;
&.active {
color: #1890ff;
background: #e8f4ff;
border-color: #a3d3ff;
}
}
}
</style>

View File

@ -37,7 +37,7 @@
</el-form-item>
<div class="u-flex u-row-center u-m-t-50">
<el-button size="medium" @click="close">取消</el-button>
<el-button size="medium" type="success" @click="confirm"
<el-button size="medium" type="primary" @click="confirm"
>确定</el-button
>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
<template>
<el-dialog :title="form.id ? '编辑台桌' : '添加台桌'" :visible.sync="dialogVisible" @open="tbShopAreaGet" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="选择区域" prop="areaId">
<el-select v-model="form.areaId" placeholder="请选择区域">
<el-option :label="item.name" :value="item.id" v-for="item in areaList" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌状态" prop="status" v-if="form.id">
<el-select v-model="form.status" placeholder="请选择台桌状态">
<el-option :label="item.label" :value="item.value" v-for="item in status" :key="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="台桌名称">
<el-input v-model="form.name" placeholder="请输入台桌名称"></el-input>
</el-form-item>
<el-form-item label="客座数">
<el-input-number v-model="form.maxCapacity" :min="0" controls-position="right"></el-input-number>
</el-form-item>
<el-form-item label="清台管理">
<el-radio-group v-model="form.autoClear">
<el-radio-button :label="0">手动清台</el-radio-button>
<el-radio-button :label="1">自动清台</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="网络预定开关">
<el-switch v-model="form.isPredate" :active-value="1" :inactive-value="2"></el-switch>
</el-form-item>
<el-form-item label="类型">
<el-radio-group v-model="form.type">
<el-radio-button :label="0">低消</el-radio-button>
<el-radio-button :label="2">计时</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="最低消费" v-if="form.type == 0">
<el-input-number v-model="form.amount" :min="0" controls-position="right"></el-input-number>
</el-form-item>
<el-form-item label="每小时收费" v-if="form.type == 2">
<el-input-number v-model="form.perhour" :min="0" controls-position="right"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="loading" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopTable, tbShopAreaGet } from '@/api/table'
import $status from "../status.js";
export default {
data() {
return {
dialogVisible: false,
resetForm: '',
loading: false,
status:[],
form: {
id: '',
name: '',
areaId: '',
maxCapacity: 0,
isPredate: 1,
type: 2,
perhour: 0,
amount: 0,
autoClear: 1,
},
rules: {
areaId: [
{
required: true,
message: '请选择区域',
trigger: 'blur'
}
]
},
areaList: []
}
},
mounted() {
this.resetForm = { ...this.form }
this.status = Object.keys($status).map(key =>{
return {...$status[key],value:key}
});
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
this.loading = true
try {
let res = await tbShopTable({
...this.form,
qrcode:this.form.tableId,
shopId: localStorage.getItem('shopId')
}, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
this.loading = false
} catch (error) {
this.loading = false
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = JSON.parse(JSON.stringify(obj))
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form = { ...this.resetForm }
},
//
async tbShopAreaGet() {
try {
const { content } = await tbShopAreaGet({
shopId: localStorage.getItem('shopId')
})
this.areaList = content
} catch (error) {
console.log(error);
}
}
}
}
</script>

34
src/views/table/status.js Normal file
View File

@ -0,0 +1,34 @@
export default {
pending: {
label: "挂单中",
type: "#E6A23C",
},
using: {
label: "开台中",
type: "#fa5555",
},
paying: {
label: "结算中",
type: "#E6A23C",
},
idle: {
label: "空闲",
type: "#3F9EFF",
},
subscribe: {
label: "预定",
type: "rgb(34, 191, 100)",
},
closed: {
label: "关台",
type: "rgb(221,221,221)",
},
// opening: {
// label: "开台中",
// type: "#67C23A",
// },
cleaning: {
label: "待清台",
type: "#FAAD14",
}
}

View File

@ -41,17 +41,35 @@
<el-button type="primary" icon="el-icon-download">下载店铺码</el-button>
</div>
</div>
<div class="u-flex u-p-b-15 u-font-14">
<div class="state u-m-r-24" v-for="(item, key) in status" :key="key">
<span
class="dot"
:style="{
backgroundColor: status[key] ? status[key].type : '',
}"
></span>
{{ item.label }}
</div>
</div>
<div class="head-container">
<div class="table_list" v-loading="loading">
<div
class="item"
v-for="item in tableList"
:key="item.id"
:class="[item.status]"
:style="{ 'background-color': status[item.status].type }"
>
<div class="new-top flex u-row-between">
<span class="name">{{ item.name }}</span>
<el-dropdown trigger="click" @command="tableComman($event,item)">
<div class="u-flex u-flex-1 u-p-r-10">
<span class="name u-line-1" style="max-width: 50px">
{{ item.name }}</span
>
<span class="u-font-14 u-line-1"
>{{ areaMap[item.areaId] || "" }}</span
>
</div>
<el-dropdown trigger="click" @command="tableComman($event, item)">
<i class="el-icon-more cur-pointer color-fff"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">
@ -59,14 +77,15 @@
<span>编辑</span>
</el-dropdown-item>
<el-dropdown-item command="del">
<i class="i el-icon-delete"></i>
<span>删除</span>
</el-dropdown-item>
<i class="i el-icon-delete"></i>
<span>删除</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="top">
<div class="row row1">
<div class="box">
<div class="top">
<!-- <div class="row row1">
<span>{{ item.name }}</span>
<div class="state">
<span
@ -79,71 +98,99 @@
></span>
{{ status[item.status] ? status[item.status].label : "" }}
</div>
</div>
<div class="row">
</div> -->
<!-- <div class="row">
<el-tag type="warning" size="mini">{{
item.type == 0 ? "低消" : "计时"
}}</el-tag>
<el-tag :type="item.isPredate == 1 ? '' : 'info'" size="mini">{{
item.isPredate == 1 ? "可预约" : "不可预约"
}}</el-tag>
</div>
<div class="row">
</div> -->
<!-- <div class="row">
<span class="tips">客座次数{{ item.maxCapacity }}</span>
</div>
<div class="row btn-group">
<template v-if="item.status == 'idle'">
<el-button
type="primary"
:disabled="!item.tableId || item.status === 'closed'"
@click="diancanShow(item)"
>开始点餐</el-button
>
</template>
<template v-else >
<template v-if="item.status == 'using'">
<el-button
:disabled="!item.tableId || item.status === 'closed'"
</div> -->
<div class="u-font-18 font-600 total-price">
<span
class="cur-pointer"
v-if="item.status == 'using'"
@click="diancanShow(item, 'isAddGoods')"
>加菜</el-button
>
<el-button
type="danger"
:disabled="!item.tableId || item.status === 'closed'"
@click="diancanShow(item, 'isPayOrder')"
>结账</el-button
>
¥{{ item.totalAmount || 0 }}{{ item.productNum }}
</span>
<span class="color-fff" v-else>|</span>
</div>
<div class="row btn-group">
<template v-if="item.status == 'idle'">
<el-button
type="primary"
:disabled="!item.tableId || item.status === 'closed'"
@click="diancanShow(item)"
>点餐</el-button
>
</template>
<template v-else>
<el-button
type="info"
disabled
>开始点餐</el-button
>
</template>
</template>
</div>
<!-- <div class="u-flex u-col-center">
<img style="width: 16px;height: 16px;" src="@/assets/images/perpole.png" alt="">
<span class="color-000 u-font-12">{{ item.maxCapacity }}</span>
</div> -->
</div>
<!-- <div class="btm">
<div class="btm_item" @click="$refs.addTable.show(item)">
<i class="i el-icon-edit"></i>
</div>
<el-popconfirm
title="确定删除吗?"
@confirm="delTableHandle([item.id])"
style="flex: 1"
>
<div class="btm_item" slot="reference">
<i class="i el-icon-delete"></i>
<template v-if="item.status == 'using'">
<el-button
:disabled="!item.tableId || item.status === 'closed'"
@click="diancanShow(item, 'isAddGoods')"
>加菜</el-button
>
<el-button
type="danger"
:disabled="!item.tableId || item.status === 'closed'"
@click="diancanShow(item, 'isPayOrder')"
>结账</el-button
>
</template>
<template v-else-if="item.status == 'closed'">
<el-button type="info" disabled>已关台</el-button>
</template>
<template v-else-if="item.status == 'cleaning'">
<el-button
type="info"
@click="cleanTableHandle(item)"
:style="{
backgroundColor: status[item.status].type,
borderColor: status[item.status].type,
}"
>清台</el-button
>
</template>
<template v-else>
<el-button type="info" disabled>点餐</el-button>
</template>
</template>
</div>
</el-popconfirm>
</div> -->
</div>
<div
class="u-flex u-col-bottom bottom u-row-between color-666"
:class="{ 'opacity-0': item.status == 'closed' }"
>
<div class="u-flex u-col-center">
<img
style="width: 16px; height: 16px; filter: contrast(0.5)"
src="@/assets/images/perpole.png"
alt=""
/>
<span class="u-m-t-4 u-font-12 u-m-l-2"
>{{ item.useNum || 0 }}/{{ item.maxCapacity }}</span
>
</div>
<div class="u-flex" v-if="item.status == 'using'">
<img
style="width: 16px; height: 16px; filter: contrast(0.5)"
src="@/assets/images/shalou.png"
alt=""
/>
<span class="u-m-t-4 u-font-12">{{
item.durationTime | formatTime
}}</span>
</div>
</div>
</div>
</div>
<div class="empty_wrap">
<el-empty description="空空如也~" v-if="!tableList.length"></el-empty>
@ -151,31 +198,48 @@
</div>
</div>
<addEara ref="addEara" @success="tbShopAreaGet" />
<!-- 批量添加台桌 -->
<addTable ref="addTable" @success="tbShopTableGet" />
<!-- 编辑台桌 -->
<table-edit ref="editTable" @success="tbShopTableGet"></table-edit>
<downloadTableCode :total="total" ref="downloadTableCode" />
<!-- 点餐 -->
<table-diancan ref="dianan" @close="onDiancanClose"></table-diancan>
<table-diancan ref="diancan" @close="onDiancanClose"></table-diancan>
<!-- 选择人数 -->
<choose-diners-number
ref="refChooseDinersNumber"
:max="selTable.maxCapacity"
@confirm="chooseDinersNumberConfirm"
></choose-diners-number>
</div>
</template>
<script>
import addEara from "./components/addEara";
import addTable from "./components/addTable";
import tableEdit from "./components/table-edit";
import downloadTableCode from "./components/downloadTableCode";
import tableDiancan from "./components/table-diancan.vue";
import $status from "./status.js";
import chooseDinersNumber from "./components/table-diancan-components/choose-diners-number.vue";
import {
tbShopTableGet,
tbShopAreaGet,
tbShopAreaDelete,
tbShopTableDelete,
tbShopTable,
} from "@/api/table";
import dayjs from "dayjs";
export default {
components: {
addEara,
addTable,
downloadTableCode,
tableDiancan,
chooseDinersNumber,
tableEdit,
},
data() {
return {
@ -184,64 +248,58 @@ export default {
loading: false,
total: 0,
tableList: [],
status: {
pending: {
label: "挂单中",
type: "#E6A23C",
},
using: {
label: "开台中",
type: "#E6A23C",
},
paying: {
label: "结算中",
type: "#E6A23C",
},
idle: {
label: "空闲",
type: "#67C23A",
},
subscribe: {
label: "预定",
type: "#E6A23C",
},
closed: {
label: "关台",
type: "rgb(221,221,221)",
},
// opening: {
// label: "",
// type: "#67C23A",
// },
cleaning: {
label: "台桌清理中",
type: "#909399",
},
},
status: $status,
selTable: "", //
areaMap: {},
};
},
mounted() {
this.tbShopAreaGet();
},
filters: {
formatTime(time) {
return dayjs(time).format("HH小时mm分");
},
},
methods: {
tableComman(command,item){
if(command=='edit'){
return this.$refs.addTable.show(item)
//
cleanTableHandle(item) {
this.$confirm("确定要清台:"+item.name, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
tbShopTable(
{
...item,
status: "idle",
qrcode: item.tableId,
shopId: localStorage.getItem("shopId"),
},
"put"
).then((res) => {
this.tbShopTableGet();
});
});
},
tableComman(command, item) {
if (command == "edit") {
return this.$refs.editTable.show(item);
}
if(command=='del'){
return this.delPop(item)
if (command == "del") {
return this.delPop(item);
}
},
delPop(item){
this.$confirm('是否删除'+item.name+'台桌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.delTableHandle([item.id])
}).catch(() => {
});
delPop(item) {
this.$confirm("是否删除" + item.name + "台桌", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.delTableHandle([item.id]);
})
.catch(() => {});
},
onDiancanClose() {
this.tbShopTableGet();
@ -249,7 +307,17 @@ export default {
diancanShow(item, key) {
//key isAddGoods
//key isPayOrder
this.$refs.dianan.open(item, key);
this.selTable = item;
const num = item.useNum || 0;
if (item.useNum <= 0) {
return this.$refs.refChooseDinersNumber.open();
}
this.$refs.diancan.open(item, key, num);
},
chooseDinersNumberConfirm(num) {
//
console.log(num);
this.$refs.diancan.open(this.selTable, undefined, num);
},
tabClick() {
this.tbShopTableGet();
@ -281,7 +349,6 @@ export default {
shopId: localStorage.getItem("shopId"),
areaId: this.tabVlaue,
});
console.log(content);
this.tableList = content;
// this.tableList = content.sort((a,b)=>{
// if(a.status=='idle'&&b.status!='idle'){
@ -306,6 +373,10 @@ export default {
shopId: localStorage.getItem("shopId"),
});
this.tabs = content;
this.areaMap = content.reduce((prve, cur) => {
prve[cur.id] = cur.name;
return prve;
}, {});
this.tbShopTableGet();
} catch (error) {
console.log(error);
@ -321,10 +392,16 @@ export default {
}
</style>
<style scoped lang="scss">
.cur-pointer {
cursor: pointer;
}
.opacity-0 {
opacity: 0;
}
.icon {
margin-left: 10px;
}
::v-deep .btn-group .el-button {
::v-deep .btn-group .el-button {
width: 100%;
}
::v-deep .el-dropdown-menu__item {
@ -333,6 +410,18 @@ export default {
min-width: 60px;
text-align: center;
}
.state {
display: flex;
align-items: center;
.dot {
$size: 8px;
width: $size;
height: $size;
border-radius: 50%;
margin-right: $size;
}
}
.table_list {
display: flex;
flex-wrap: wrap;
@ -358,14 +447,22 @@ export default {
justify-content: space-between;
border-radius: 6px;
background-color: #1890ff;
min-width: 162px;
max-width: 172px;
min-width: 160px;
&.using {
background-color: rgb(250, 85, 85);
}
&.closed{
&.closed {
background-color: rgb(221, 221, 221);
filter: grayscale(1);
}
.total-price {
line-height: 35px;
height: 35px;
&:hover {
text-decoration: underline;
}
}
.new-top {
height: 30px;
color: #fff;
@ -378,12 +475,19 @@ export default {
overflow: hidden;
text-overflow: ellipsis;
}
.top {
padding: 20px;
.box {
background-color: #fff;
flex:1;
// border-radius: 6px 6px 0 0;
border-radius: 6px;
border-radius: 3px 3px 6px 6px;
}
.bottom {
border-top: 1px solid #f7f7fa;
padding: 6px 15px;
}
.top {
padding: 10px;
background-color: #fff;
flex: 1;
border-radius: 3px 3px 0 0;
.row {
display: flex;
gap: 10px;
@ -392,26 +496,9 @@ export default {
font-size: 12px;
}
&:not(:first-child) {
margin-top: 10px;
}
&.row1 {
justify-content: space-between;
font-size: 14px;
.state {
display: flex;
align-items: center;
.dot {
$size: 6px;
width: $size;
height: $size;
border-radius: 50%;
margin-right: $size;
}
}
}
}
}
@ -451,4 +538,4 @@ export default {
}
}
}
</style>
</style>