cashier_desktop/src/views/order/index.vue

912 lines
33 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="orderbox">
<div class="orderbox_left">
<el-tabs v-model="ordereData.status" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="全部" name="">
<div class="demo_tabs_div">
<el-input v-model="ordereData.orderNo" placeholder="请输入订单号查询" @input="inputChange" clearable
@focus="
global.updateData(false)" @blur="global.updateData(true)" />
<!-- <el-button style="margin-left: 10px;" type="primary" @click="onSubmit">搜索</el-button> -->
</div>
<add :loading="loadingboxshow" :ordereData="ordereData" @emititemboxshow="emititemboxshow"
v-if="ordereData.list.length">
</add>
<div v-else style="width: 100%; text-align: center; margin: 30px 0;">暂无数据</div>
<el-pagination v-if="ordereData.list.length" layout="prev, pager, next, jumper"
style="margin-top: 20px;" :total="Number(ordereData.total)"
@current-change="handleCurrentChange" />
</el-tab-pane>
<el-tab-pane label="销售" name="closed">
<add :ordereData="ordereData" @emititemboxshow="emititemboxshow" v-if="ordereData.list.length">
</add>
<div v-else style="width: 100%; text-align: center; margin: 30px 0;">暂无数据</div>
<el-pagination v-if="ordereData.list.length" layout="prev, pager, next, jumper"
style="margin-top: 20px;" :total="Number(ordereData.total)"
@current-change="handleCurrentChange" />
</el-tab-pane>
<el-tab-pane label="退单" name="refund">
<add :ordereData="ordereData" @emititemboxshow="emititemboxshow" v-if="ordereData.list.length">
</add>
<div v-else style="width: 100%; text-align: center; margin: 30px 0;">暂无数据</div>
<el-pagination v-if="ordereData.list.length" layout="prev, pager, next, jumper"
style="margin-top: 20px;" :total="Number(ordereData.total)"
@current-change="handleCurrentChange" />
</el-tab-pane>
<el-tab-pane label="快捷收银" name="cash">
<cashTable />
</el-tab-pane>
</el-tabs>
</div>
<div class="orderbox_right" v-if="itemboxshow" v-loading="orderDetaildata.loading" :loading="loadingboxshow">
<div class="orderbox_right_top">
<span>堂食订单</span>
<el-icon :size="32" style="color: var(--primary-color) ;" @click="itemboxshow = false">
<CircleCloseFilled />
</el-icon>
</div>
<div class="tableDataclass">
<div class="orderbox_right_item">
<span class="span">订单号:</span><span class="nunber">{{ orderDetaildata.orderNo }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">收银员:</span><span class="nunber">{{ orderDetaildata.userName }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">创建时间:</span><span class="nunber">{{ dayjs(
orderDetaildata.createdAt).format("YYYY-MM-DD HH:mm:ss") }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">终端:</span><span class="nunber">{{ orderDetaildata.zdNo }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">会员:</span><span class="nunber">{{ orderDetaildata.memberName }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">台桌:</span><span class="nunber">{{ orderDetaildata.tableId }}</span>
</div>
<div class="orderbox_right_item">
<span class="span">流水号:</span><span class="nunber">{{ orderDetaildata.masterId }}</span>
</div>
<div class="orderbox_right_top" style="margin-top: 20px; border-bottom: 2px solid #ccc;">
<span>合计:</span>
<span>¥{{ orderDetaildata.orderAmount }}</span>
</div>
<div class="orderbox_right_top" style="margin-top: 20px; border-bottom: 2px solid #ccc;">
<span style="font-size: 16px;" v-if="orderDetaildata.status == 'pending'">挂单</span>
<span style="font-size: 16px; color: red;"
v-if="orderDetaildata.status == 'refund' && orderDetaildata.orderType == 'return'">退单</span>
<span style="font-size: 16px; color:#21c36b;"
v-if="orderDetaildata.orderType != 'return' && (orderDetaildata.status == 'refund' || orderDetaildata.status == 'closed')">订单完成</span>
</div>
<div class="orderbox_right_top" style="margin-top: 20px;">
<span>商品明细</span>
<span>{{ orderDetaildata.detailList.length }}项</span>
</div>
<div class="orderbox_right_list" style="margin-top: 20px;">
<div>商品</div>
<div>数量</div>
<div>单价</div>
<div>小计</div>
</div>
<div class="orderbox_right_list_item" style="margin-top: 20px;"
v-for="(item, index) in orderDetaildata.detailList" :key="index">
<div>{{ item.productName }} {{ item.productSkuName }}</div>
<div style="text-align: center;">{{ item.num }}</div>
<div style="text-align: center;">{{ item.price }}</div>
<div v-if="item.status == 'refund'"><span
style="border: 2px solid red; color: red; padding: 4px 2px;">已退</span></div>
<div v-else>{{ item.priceAmount }}</div>
</div>
<div :style="{ 'height': reforderboxrightbuttonheight + 'px' }"></div>
</div>
<div class="orderbox_right_button" ref="reforderboxrightbutton">
<div class="orderbox_right_buttonbutton">
<el-button style="width: 100%;" type="warning" :loading="callLoading" @click="callNumberHandle">
叫号
</el-button>
</div>
<div class="orderbox_right_buttonbutton">
<el-button style="width: 100%;"
v-if="orderDetaildata.orderType != 'return' && (orderDetaildata.status == 'refund' || orderDetaildata.status == 'closed')"
type="primary" @click="recharge = true">退单</el-button>
</div>
<div class="orderbox_right_buttonbutton">
<el-button @click="print('normal')" style="flex: 1;">重打收银打票</el-button>
<el-button @click="print('label')" style="flex: 1;">重打标签小票</el-button>
</div>
</div>
</div>
<div class="orderbox_rightbox" v-else>
<div class="orderbox_rightbox_top">
<div
style="padding: 6px; background:#187ead; border-radius:50%;width: 50px;height: 50px; display: flex; align-items: center; justify-content: center;">
<el-icon :size="30" color="#fff">
<Document />
</el-icon>
</div>
<div class="orderbox_rightbox_top_div">
<div>今日普通订单</div>
<div style="font-size:14px;">今日本终端处理的订单</div>
</div>
</div>
<!-- <div class="orderbox_rightbox_top">
<div
style="padding: 6px; background:#187ead; border-radius:50%;width: 50px;height: 50px; display: flex; align-items: center; justify-content: center;">
<el-icon :size="30" color="#fff">
<Connection />
</el-icon>
</div>
<div class="orderbox_rightbox_top_div">
<div>今日普通订单</div>
<div style="font-size:14px;">今日本终端处理的订单</div>
</div>
</div>
<div class="orderbox_rightbox_top">
<div
style="padding: 6px; background:#187ead; border-radius:50%;width: 50px;height: 50px; display: flex; align-items: center; justify-content: center;">
<el-icon :size="30" color="#fff">
<Crop />
</el-icon>
</div>
<div class="orderbox_rightbox_top_div">
<div>今日普通订单</div>
<div style="font-size:14px;">今日本终端处理的订单</div>
</div>
</div> -->
</div>
<el-dialog v-model="recharge" title="退单" width="800" :before-close="handlerecharge">
<div class="recharge_footer">
<div class="recharge_footer_item">
<el-input v-model="remark" style="width: 100%" :rows="2" type="textarea" placeholder="请输入退单原因"
@focus="
global.updateData(false)" @blur="global.updateData(true)" />
<div class="recharge_footer_items" @click="remark = '顾客取消'">
<div>顾客取消</div>
</div>
<div class="recharge_footer_items" @click="remark = '等待时间长'">
<div>等待时间长</div>
</div>
<div class="recharge_footer_items" @click="remark = '支付错误'">
<div>支付错误</div>
</div>
<div class="recharge_footer_items" @click="remark = '商品不满意'">
<div>商品不满意</div>
</div>
<div class="recharge_footer_items" @click="remark = '服务态度不满意'">
<div>服务态度不满意</div>
</div>
</div>
<div class="recharge_footer_itemright">
<div class="recharge_footer_itemright_top">
<div>
单号:{{ orderDetaildata.orderNo }}
</div>
<div>
下单时间:{{ dayjs(orderDetaildata.createdAt).format("YYYY-MM-DD HH:mm:ss") }}
</div>
<div>
<span>金额:¥{{ orderDetaildata.orderAmount }}</span>
<!-- <span>优惠¥0.00</span> -->
<span>包装费:¥{{ orderDetaildata.packFee }}</span>
<!-- <span>可退款:¥{{ orderDetaildata.packFee }}</span> -->
<!-- <el-icon class="icon">
<ShoppingBag />
</el-icon> -->
</div>
</div>
<div class="recharge_footer_itemright_botton">
<div class="recharge_footer_itemright_botton_top">
<el-checkbox @change="changezong" v-model="changechecked" size="large" /><span
style="margin-left: 10px;">全选,共项目</span>
</div>
<div class="recharge_footer_itemright_botton_item"
v-for="(item, index) in orderDetaildata.detailList" :key="index">
<div class="recharge_footer_itemright_botton_itemone">
<el-checkbox @change="changezong(item, index, 1, 'quan')"
:disabled="item.status == 'refund' ? true : false" v-model="item.checked"
size="large" />
<span style="margin-left: 10px;">{{ item.productName }}</span>
</div>
<div class="recharge_footer_itemright_botton_itemtow">
<!-- {{ item.num }} -->
<el-input-number v-model="item.num" :min="1" size="small"
:disabled="item.status == 'refund' ? true : false" :max="item.maxnum"
@change="(currentValue, oldValue) => changezong(item, index, 1, 'num', currentValue, oldValue)"
@focus="
global.updateData(false)" @blur="global.updateData(true)" />
<!-- @change="changezong(item, index, 1, 'num')" -->
</div>
<div class="recharge_footer_itemright_botton_itemthere">
¥{{ item.price }}
</div>
</div>
</div>
<div class="recharge_footer_itemright_botton_box">
<div class="recharge_footer_itemright_botton_boxone">
<div class="recharge_footer_itemright_botton_boxoneabsolute">退单金额:</div>
<div class="recharge_footer_itemright_botton_boxonetext">¥{{ refundamount > 0 ? refundamount
: '0.00' }}</div>
</div>
<div class="recharge_footer_itemright_botton_boxtow">
<el-button type="primary" style="width: 100%; height: 100%;" :loading="buttonloading"
@click="payreturnOrderclick">
<span v-if="!buttonloading">支付退回</span>
<span v-else>支付退回...</span>
</el-button>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import { ElMessage, dayjs } from 'element-plus'
import { useUser } from "@/store/user.js"
import lodash from 'lodash'
import { orderfindOrder, orderorderDetail, payreturnOrder, cloudPrinterprint, sendMessage } from '@/api/order/index.js'
import add from '@/views/order/components/add.vue'
import cashTable from '@/views/order/components/cashTable.vue'
import { clearNoNum } from '@/utils'
import { useGlobal } from '@/store/global.js'
const global = useGlobal()
const store = useUser()
const itemboxshow = ref(false)
import { usePrint } from '@/store/print.js'
const printStore = usePrint()
import { ipcRenderer } from 'electron'
const reforderboxrightbutton = ref(null);//定义ref
const reforderboxrightbuttonheight = ref(null)//获取元素高度
const handleClick = (Name) => {//切换teb
ordereData.status = Name.props.name
asyncorderfindOrder()
}
const recharge = ref(false)//退单切换
const handlerecharge = () => { //退单切换
recharge.value = !recharge.value
}
const buttonloading = ref() //loading
const payreturnOrderclick = lodash.debounce(async () => { //搜索手机号
buttonloading.value = true
if (refundamount.value == 0) {
buttonloading.value = false
ElMessage.error('退款金额不能为0')
return false
}
try {
let arr = orderDetaildata.value.detailList.map(item => {
if (item.checked && item.status == 'closed') {
var obj = {
id: item.id,
orderId: orderDetaildata.value.id,
remark: remark.value,
num: item.num
}
}
return obj
})
arr = arr.filter(item => { return item && item })
if (arr.length != 0) {
await payreturnOrder(arr)
changechecked.value = false
recharge.value = false
itemboxshow.value = false
refundamount.value = 0
ElMessage.success('退款成功!')
buttonloading.value = false
asyncorderfindOrder()
} else {
buttonloading.value = false
ElMessage.error('以没有退款项目!')
}
} catch (error) {
buttonloading.value = false
}
}, 500)
// 重新打印标签/小票
const print = lodash.throttle(async function (e) {
try {
if (e == 'label') {
// checkLabelPrint(printLabelOrder.value)
const data = {
shop_name: store.userInfo.merchantName,
carts: [],
orderInfo: printLabelOrder.value,
outNumber: printLabelOrder.value.outNumber,
createdAt: dayjs(printLabelOrder.value.createdAt).format(
"YYYY-MM-DD HH:mm:ss"
)
}
printLabelOrder.value.skuInfos.map(item => {
data.carts.push(
{
categoryId: item.categoryId,
name: item.productName,
number: item.num,
skuName: item.productSkuName
}
)
})
// console.log('重打标签小票', data);
printStore.labelPrint(data)
} else {
await cloudPrinterprint({
type: e,
orderId: orderDetaildata.value.id,
ispre: false
})
ElMessage({
message: '成功打票',
type: 'success',
})
}
} catch (error) {
console.log(error);
}
}, 1500, { leading: true, trailing: false })
const loadingboxshow = ref(false);
// 要打印标签的订单数据
const printLabelOrder = ref('')
const emititemboxshow = async (e) => { //接收子组件值 并赋值给父组件
// console.log('emititemboxshow', e);
printLabelOrder.value = e
loadingboxshow.value = true
try {
let res = await orderorderDetail({
shopId: store.userInfo.shopId,
id: e.id
})
itemboxshow.value = true
loadingboxshow.value = false
orderDetaildata.value = res
if (reforderboxrightbutton.value) { //点击动态获取元素高度
reforderboxrightbuttonheight.value = reforderboxrightbutton.value.offsetHeight;
}
orderDetaildata.value.detailList.forEach((e) => {
e.checked = false
e.zongprice = e.priceAmount / e.num
e.maxnum = e.num - e.returnNum // 添加最大数量
})
changechecked.value = false //清空全选
refundamount.value = 0 //退款金额清0
} catch (error) {
loadingboxshow.value = false
}
}
const remark = ref('')//备注
const changechecked = ref(false) //全选
const refundamount = ref(0)//退款金额
const changezong = (e, b, c, d, currentValue, oldValue) => {
console.log(e)
if (c == 1) {
if (d == 'num' && e.checked) {
orderDetaildata.value.detailList.forEach((item, a, b) => {
if (item.id == e.id) {
if (currentValue > oldValue) {
refundamount.value = (Number(refundamount.value) + (Number(currentValue - oldValue) * Number(item.zongprice))).toFixed(2)
} else {
refundamount.value = (Number(refundamount.value) + (Number(currentValue - oldValue) * Number(item.zongprice))).toFixed(2)
}
}
})
}
if (d == 'quan') {//这是选择选项
if (e.checked) {
console.log(Number(refundamount.value), Number(e.num) * Number(e.zongprice))
refundamount.value = ((Number(refundamount.value) + (Number(e.num) * Number(e.zongprice)))).toFixed(2)
} else {
refundamount.value = ((Number(refundamount.value) - (Number(e.num) * Number(e.zongprice)))).toFixed(2)
}
}
if (orderDetaildata.value.detailList.every(item => item.checked == true)) {//判断是否全选
changechecked.value = true
} else {
changechecked.value = false
}
} else {
refundamount.value = 0
orderDetaildata.value.detailList.forEach((e, a, b) => {
if (changechecked.value) {
if (e.status == 'refund') {
e.checked = false
} else {
e.checked = true
refundamount.value = clearNoNum({ value: JSON.stringify(Number(refundamount.value) + (Number(e.num) * Number(e.zongprice))) })
}
} else {
e.checked = false
refundamount.value = 0
}
})
}
}
const orderDetaildata = ref({//详情数据
// loading
})
const ordereData = reactive({//表格数据
list: [],
size: 10,
page: 1,
status: '',
total: '',
orderNo: '',
})
const asyncorderfindOrder = async () => {//获取流水
try {
let res = await orderfindOrder({
shopId: store.userInfo.shopId,
status: ordereData.status,
size: ordereData.size,
page: ordereData.page,
orderNo: ordereData.orderNo
})
ordereData.total = res.total
ordereData.list = res.list
} catch (error) {
// ElMessage({
// message: '获取失败',
// type: 'error',
// })
}
}
const handleCurrentChange = (val) => { //页码
// ordereData.page = 1
ordereData.page = val
asyncorderfindOrder()
}
const inputChange = lodash.debounce(function () { //搜索手机号
asyncorderfindOrder()
}, 500)
// 叫号
const callLoading = ref(false)
const callNumberHandle = async () => {
try {
callLoading.value = true
const res = await sendMessage({
orderId: orderDetaildata.value.id
})
callLoading.value = false
ElMessage.success('叫号成功')
} catch (error) {
callLoading.value = false
console.log(error);
}
}
onMounted(() => {
// resetMembrform.value = { ...membrform.value }
asyncorderfindOrder()
})
</script>
<style scoped lang="scss">
.orderbox {
display: flex;
height: 100%;
.orderbox_left {
width: 60%;
height: 100%;
background: #fff;
border-radius: 10px;
.demo-tabs {
height: 100%;
:deep(.el-tabs__content) {
height: 90%;
}
:deep(.el-tab-pane) {
height: 100%;
}
:deep(.el-tabs__nav) {
width: 100%;
}
:deep(.el-tabs__item) {
width: 33.33%;
padding: 0;
position: relative;
// width: 10px !important;
}
:deep(.el-tabs__active-bar) {
height: 0 !important;
}
:deep(.el-tabs__active-bar)::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
height: 2px;
width: 10px;
background: red;
transform: translateX(-50%);
// width: 10px !important;
}
:deep(.el-is-active) {
width: 33.33%;
color: var(--primary-color);
}
.demo_tabs_div {
padding: 0 20px;
display: flex;
}
.demo_tabs_box {
width: 100%;
padding: 10px 20px;
height: 82%;
overflow: auto;
.demo_tabs_boxitem {
width: 100%;
padding: 6px 16px;
border-radius: 6px;
display: flex;
justify-content: space-between;
// background: #eeeeee;
border-bottom: 1px solid #ccc;
.demo_tabs_boxitem_one {
display: flex;
justify-content: flex-start;
.demo_tabs_boxitem_oneone {
display: flex;
margin-left: 20px;
flex-direction: column;
height: 70px;
justify-content: space-around;
}
.demo_tabs_boxitem_onetow {
// width: 40%;
display: flex;
margin-left: 20px;
flex-direction: column;
height: 70px;
justify-content: space-around;
div {
// width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.demo_tabs_boxitem_tow {
// width: 20%;
display: flex;
flex-direction: column;
height: 70px;
justify-content: space-around;
align-items: flex-end;
}
}
}
}
.orderbox_rightbox {
position: relative;
width: 40%;
padding: 20px;
margin-left: 10px;
background: #fff;
border-radius: 10px;
.orderbox_rightbox_top:nth-child(1) {
margin-top: 0;
}
.orderbox_rightbox_top {
margin-top: 10px;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 10px 16px;
width: 100%;
border-radius: 10px;
background: #e7e5e5;
.orderbox_rightbox_top_div {
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: space-around;
}
}
}
.recharge_footer {
display: flex;
justify-content: space-between;
.recharge_footer_item {
background: #f2f2f2;
width: 40%;
border-radius: 10px;
padding: 20px;
display: flex;
flex-flow: wrap;
.recharge_footer_items {
margin-left: 10px;
// background: #187ead;
border: 1px solid #187ead;
padding: 10px 22px;
color: #187ead;
height: fit-content;
text-align: center;
border-radius: 6px;
margin-top: 10px;
}
}
.recharge_footer_itemright {
padding-left: 20px;
width: 60%;
position: relative;
bottom: 0;
left: 0;
.recharge_footer_itemright_top {
width: 100%;
padding: 6px 10px;
background: #f2f2f2;
border-radius: 10px;
div:nth-child(1) {
margin-top: 0px;
}
div:nth-child(3) {
display: flex;
justify-content: flex-start;
span:nth-child(1) {
margin-left: 0;
}
span:nth-child(2) {
color: red;
}
span:nth-child(4) {
font-weight: bold;
}
span {
margin-left: 6px;
}
}
div {
margin-top: 10px;
}
}
.recharge_footer_itemright_botton {
max-height: 300px;
overflow: auto;
.recharge_footer_itemright_botton_top {
margin-top: 10px;
color: #757575;
}
.recharge_footer_itemright_botton_item {
display: flex;
justify-content: space-around;
align-items: center;
border-bottom: 1px solid #ccc;
.recharge_footer_itemright_botton_itemone {
flex: 2;
display: flex;
justify-content: flex-start;
align-items: center;
}
.recharge_footer_itemright_botton_itemtow {
flex: 1;
}
.recharge_footer_itemright_botton_itemthere {
flex: 1;
text-align: right;
}
}
}
.recharge_footer_itemright_botton_box {
border-top: 1px solid #ccc;
padding: calc(var(--el-dialog-padding-primary) + 10px) 12px 0 12px;
display: flex;
justify-content: space-between;
align-items: center;
.recharge_footer_itemright_botton_boxone {
width: 60%;
height: 60px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
.recharge_footer_itemright_botton_boxoneabsolute {
position: absolute;
top: 0;
left: 0;
color: #c0c0c0;
}
.recharge_footer_itemright_botton_boxonetext {
font-size: 26px;
height: 60px;
line-height: 60px;
}
}
.recharge_footer_itemright_botton_boxtow {
width: 40%;
height: 60px;
}
}
}
}
.orderbox_right {
position: relative;
width: 40%;
padding: 20px;
margin-left: 10px;
background: #fff;
border-radius: 10px;
.orderbox_right_top {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
border-bottom: 2px solid #000;
}
.orderbox_right_list {
display: flex;
font-size: 14px;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
text-align: center;
border-bottom: 2px solid #ccc;
div:nth-child(1) {
text-align: left;
width: 45%;
}
div:nth-child(2) {
width: 15%;
align-items: center;
}
div:nth-child(3) {
width: 15%;
align-items: center;
}
div:nth-child(4) {
text-align: right;
width: 25%;
}
}
.orderbox_right_list_item {
display: flex;
font-size: 14px;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
div:nth-child(1) {
text-align: left;
width: 45%;
}
div:nth-child(2) {
width: 15%;
align-items: center;
}
div:nth-child(3) {
width: 15%;
align-items: center;
}
div:nth-child(4) {
text-align: right;
width: 25%;
}
}
.tableDataclass {
width: 100%;
overflow: auto;
height: 90%;
.orderbox_right_item {
margin-top: 6px;
span {
font-size: var(--el-font-size-base);
// color: var(--primary-color);
}
}
}
.orderbox_right_button {
position: absolute;
width: 96%;
left: 50%;
background: #fff;
bottom: 16px;
.orderbox_right_buttonbutton {
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
transform: translateX(-50%) !important;
}
}
}
</style>