优化下单

This commit is contained in:
gyq 2025-04-21 17:45:05 +08:00
parent 694cb154a6
commit b5773cf78c
12 changed files with 275 additions and 16268 deletions

View File

@ -5,10 +5,10 @@ ENV = development
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
# 正式ws
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
# 本地ws
VITE_API_WSS = 'ws://192.168.1.31:2348'
# VITE_API_WSS = 'ws://192.168.1.31:2348'
# 正式 php
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
@ -20,10 +20,10 @@ VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
# 本地调试连接
VITE_API_URL = 'http://192.168.1.31/'
# VITE_API_URL = 'http://192.168.1.31/'
# 线上测试
# VITE_API_URL = 'https://tapi.cashier.sxczgkj.cn'
# 线上正式
# VITE_API_URL = 'https://cashier.sxczgkj.com'
VITE_API_URL = 'https://cashier.sxczgkj.com'

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"name": "vite-electron",
"private": true,
"version": "2.0.6",
"version": "2.0.7",
"main": "dist-electron/main.js",
"scripts": {
"dev": "chcp 65001 && vite",

View File

@ -282,7 +282,6 @@ watch(props, () => {
money.value = formatDecimal(props.amount)
originOrderAmount.value = formatDecimal(props.amount - (goodsStore.tableInfo.tableFee || 0) -
(goodsStore.cartInfo.packFee || 0))
payData.value.checkOrderPay.isPrint = props.isPrint
})
const originOrderAmount = ref(0)
@ -912,7 +911,26 @@ function discountConfirm() {
/** 添加优惠 end */
//
function reset() {
async function payCardInit() {
console.log('payCardInit111111==============================', goodsStore.orderListInfo);
// const maxRetries = 10;
// let retries = 0;
// const waitForOrderId = async () => {
// while (retries < maxRetries && !goodsStore.orderListInfo.id) {
// await new Promise(resolve => setTimeout(resolve, 200));
// retries++;
// }
// return goodsStore.orderListInfo.id;
// };
// const orderId = await waitForOrderId();
// if (!orderId) {
// console.error(' ID');
// return;
// }
discountAmount.value = null
roundAmount.value = 0
discountRateVlaue.value = 0
@ -926,7 +944,7 @@ function reset() {
orderId: goodsStore.orderListInfo.id,
vipPrice: store.shopInfo.isMemberPrice ? goodsStore.showVipPrice : 0, // 使
allPack: goodsStore.allSelected, //
userId: goodsStore.vipUserInfo.userId,
userId: goodsStore.vipUserInfo.userId || '',
seatNum: goodsStore.tableInfo.num, //
originAmount: formatDecimal(+goodsStore.cartInfo.totalAmount), // +
discountRatio: '', // ( )
@ -942,13 +960,15 @@ function reset() {
},
};
console.log('payData================================', payData.value);
if (!payList.value.length) {
queryPayTypeAjax()
}
}
defineExpose({
reset
payCardInit
})
</script>

View File

@ -341,7 +341,9 @@ export const useGoods = defineStore("goods", {
this.originGoodsList = originGoodsListRes;
const socket = useSocket();
socket.init();
if (socket.ws == null) {
socket.init();
}
res.map((val, index) => {
val.showMore = false;
@ -568,8 +570,7 @@ export const useGoods = defineStore("goods", {
item.group_text = group_text;
item.packFee = val.packFee;
item.unitName = val.unitName;
item.isStock =
item.number >= val.stockNumber && val.isStock ? 1 : 0;
item.stockNumber = val.stockNumber;
}
});
@ -613,17 +614,9 @@ export const useGoods = defineStore("goods", {
},
// 删除购物车商品
deleteCartItem() {
let tableCode = "";
if (this.tableInfo.tableCode) {
tableCode = this.tableInfo.tableCode;
} else {
if (this.cartList.length) {
tableCode = this.cartList[0].table_code;
}
}
this.operateCart(
{
table_code: tableCode,
table_code: this.cartList[0].table_code,
id: this.cartList[this.cartActiveIndex].id,
},
"del"

View File

@ -10,6 +10,11 @@ import { printerList } from "@/api/account.js";
export const usePrint = defineStore("print", {
state: () => ({
isPrintService: false, // 打印服务是否启动
printServiceTimer: false, // 打印服务定时器
printServiceTimerCount: 0, // 打印服务定时器计数
printServiceTimerMaxCount: 10, // 打印服务定时器最大计数
showPrintNotService: false, // 是否显示重启软件,
localDevices: [], // 本地打印机列表
deviceNoteList: [], // 添加的打印机
deviceLableList: [], // 添加的打印机
@ -43,6 +48,36 @@ export const usePrint = defineStore("print", {
} catch (error) {
console.error("获取已添加的打印机列表失败", error);
}
// 检测打印服务是否启动
this.checkPrintService();
},
// 检测打印组件服务是否启动
checkPrintService() {
this.printServiceTimer = setInterval(() => {
if (
typeof LODOP !== "undefined" &&
LODOP.webskt &&
LODOP.webskt.readyState == 1
) {
// 准备好
this.isPrintService = true;
clearInterval(this.printServiceTimer);
this.printServiceTimer = null;
} else {
this.printServiceTimerCount++;
console.log("打印服务未启动", this.printServiceTimerCount);
if (this.printServiceTimerCount >= this.printServiceTimerMaxCount) {
// 超过最大次数
this.isPrintService = false;
this.showPrintNotService = true;
clearInterval(this.printServiceTimer);
this.printServiceTimer = null;
}
}
console.log("打印服务是否启动:", this.isPrintService);
}, 1000);
},
// 检查本地打印机是否能正常使用
checkLocalPrint(address) {
@ -135,7 +170,8 @@ export const usePrint = defineStore("print", {
} else {
if (
this.deviceNoteList.length &&
this.checkLocalPrint(this.deviceNoteList[0].address)
this.checkLocalPrint(this.deviceNoteList[0].address) &&
this.isPrintService
) {
const store = useUser();
props.deviceName = this.deviceNoteList[0].address;

View File

@ -151,7 +151,15 @@ export const useSocket = defineStore("socket", {
break;
}
} else {
ElMessage.error(data.msg || "操作失败");
if (data.type == "no_suit_num") {
let product = goodsStore.cartList[goodsStore.cartActiveIndex];
ElMessage.error(
`${product.product_name}库存不足,已删除,请选择其他商品`
);
goodsStore.operateCart(product, "del");
} else {
ElMessage.error(data.msg || "操作失败");
}
}
} else if (data.data_type == "order") {
// 收到订单消息,打印订单小票

View File

@ -18,7 +18,7 @@
</el-text>
</div>
<div class="item"
:class="{ disabled: goodsStore.cartList.length && (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1) || goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].isStock }"
:class="{ disabled: goodsStore.cartList.length && (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1) || (goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].number >= goodsStore.cartList[goodsStore.cartActiveIndex].stockNumber) }"
@click="numberChange('add')">
<el-icon class="icon add">
<CloseBold />
@ -393,31 +393,24 @@ function showEditNumber() {
function numberChange(t) {
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
if (!item || (item.goods_type == 'package' && item.group_type == 1)) return
let number = +goodsStore.cartList[goodsStore.cartActiveIndex].number
switch (t) {
case 'sub':
goodsStore.cartList[goodsStore.cartActiveIndex].number--
if (item.number < item.suitNum) {
if (item.number - 1 < item.suitNum) {
goodsStore.deleteCartItem()
} else {
if (goodsStore.allSelected) {
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: goodsStore.cartList[goodsStore.cartActiveIndex].number }, 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number - 1, number: number - 1 }, 'edit')
} else {
goodsStore.operateCart(goodsStore.cartList[goodsStore.cartActiveIndex], 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: number - 1 }, 'edit')
}
}
break;
case 'add':
let goods = goodsStore.originGoodsList.find(pro => pro.id == item.product_id)
if (item.number >= goods.stockNumber && goods.isStock) {
ElMessage.error('库存不足')
return
}
goodsStore.cartList[goodsStore.cartActiveIndex].number++
if (goodsStore.allSelected) {
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: goodsStore.cartList[goodsStore.cartActiveIndex].number }, 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number + 1 }, 'edit')
} else {
goodsStore.operateCart(goodsStore.cartList[goodsStore.cartActiveIndex], 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: +number + 1 }, 'edit')
}
break;
default:
@ -427,18 +420,10 @@ function numberChange(t) {
//
function updateNumber(num) {
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
let goods = goodsStore.originGoodsList.find(pro => pro.id == item.product_id)
if (num > goods.stockNumber && goods.isStock) {
ElMessage.error('库存不足')
return
}
goodsStore.cartList[goodsStore.cartActiveIndex].number = num
if (goodsStore.allSelected) {
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: goodsStore.cartList[goodsStore.cartActiveIndex].number }, 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: num, number: num }, 'edit')
} else {
goodsStore.operateCart(goodsStore.cartList[goodsStore.cartActiveIndex], 'edit')
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: num }, 'edit')
}
}

View File

@ -78,7 +78,8 @@
<img class="sell_out_icon" src="@/assets/icon_goods_yxj.svg">
</div>
<!-- 未开售不在可售时间内 -->
<div class="sell_out" v-else-if="!item.isSaleTime">
<div class="sell_out"
v-else-if="!isProductAvailable(item.days, item.startTime, item.endTime)">
<img class="sell_out_icon" src="@/assets/icon_goods_wks.svg">
</div>
<!-- 售罄 -->
@ -259,15 +260,18 @@
</template>
<script setup>
import { ElMessage } from 'element-plus'
import _ from 'lodash'
import { dayjs, ElMessage } from 'element-plus'
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
import { Search } from '@element-plus/icons-vue'
import { ref, watch, onMounted } from 'vue'
import _ from 'lodash'
import useStorage from "@/utils/useStorage";
import skuModal from '@/components/skuModal.vue'
import WeightModal from './weightModal.vue'
import GroupModal from './groupModal.vue'
import { queryProductSku, productStock, getUnitList } from '@/api/product'
import { productStock, getUnitList } from '@/api/product'
import { useUser } from "@/store/user.js"
import { useGoods } from '@/store/goods.js'
import { Swiper, SwiperSlide } from 'swiper/vue'
@ -441,13 +445,14 @@ function searchHandle() {
//
function skuConfirm(params) {
console.log(params);
let goodsItem = goodsStore.cartList.find(goods => goods.product_id == params.productId && goods.sku_id == params.id)
console.log('params===', params);
// console.log('goodsItem===', goodsItem);
if (goodsItem && goodsItem.id) {
//
if (params.goods_type == 'weight') {
if (params.goods_type == 'weight' || params.type == 'weight') {
//
console.log('编辑称重商品');
console.log('编辑称重商品', params);
goodsStore.operateCart({ ...goodsItem, number: params.number }, 'edit')
} else if (params.goods_type == 'package') {
//
@ -459,9 +464,20 @@ function skuConfirm(params) {
} else {
//
console.log('直接添加');
let goods = goodsStore.originGoodsList.find(goods => goods.id == params.productId)
console.log('goods===', goods.isStock);
if (params.type == 'weight') {
goodsStore.addCart({ ...params, number: params.number })
} else {
//
if (goods.isStock && params.suitNum > goods.stockNumber) {
ElMessage({
type: 'error',
message: '库存不足',
})
return
}
goodsStore.addCart({ ...params, number: params.suitNum })
}
}
@ -507,31 +523,30 @@ function showSkuHandle(item) {
item.showMore = true
}
} else {
if (item.isStock && item.stockNumber <= 0) {
let cartItem = goodsStore.cartList.find(goods => goods.product_id == item.id)
if (!item.isSale) {
ElMessage({
type: 'error',
message: '库存不足',
message: '该商品已下架,请编辑上架后操作',
})
return
}
if (item.isSoldStock) {
ElMessage({
type: 'error',
message: '该商品已售罄',
})
return
}
if (!item.isSaleTime) {
} else if (!isProductAvailable(item.days, item.startTime, item.endTime)) {
ElMessage({
type: 'error',
message: '不在可售时间内',
})
return
}
if (!item.isSale) {
} else if (item.isSoldStock) {
ElMessage({
type: 'error',
message: '该商品已下架,请编辑上架后操作',
message: '该商品已售罄',
})
return
} else if (item.isStock && (item.stockNumber <= 0 || (cartItem && cartItem.number >= item.stockNumber))) {
ElMessage({
type: 'error',
message: '库存不足',
})
return
}
@ -543,20 +558,10 @@ function showSkuHandle(item) {
} else if (item.type == 'single') {
//
if (goodsItem && goodsItem.id) {
//
goodsStore.operateCart({ ...goodsItem, number: +goodsItem.number + 1 }, 'edit')
} else {
console.log(item);
console.log(11111111);
//
//
if (item.isStock && item.skuList[0].suitNum > item.stockNumber) {
ElMessage({
type: 'error',
message: '库存不足',
})
return
}
goodsStore.addCart({ ...item.skuList[0], lowPrice: item.skuList[0].salePrice, number: item.skuList[0].suitNum })
}
} else if (item.type == 'weight') {
@ -588,21 +593,6 @@ function showPackage(item) {
GroupModalRef.value.show(item, 'edit')
}
//
const queryProductSkuAjax = _.throttle(async function (goods) {
try {
const res = await queryProductSku({
shopId: store.userInfo.shopId,
productId: goods.id,
spec_tag: ''
})
loading.value = false
emit('success', res)
} catch (error) {
console.log(error)
}
}, 1500)
//
function changeShopListType() {
if (shopListType.value == 'text') {
@ -849,6 +839,40 @@ async function goodsEditorStockConfirm() {
goodsEditorStockLoading.value = false
}
//
function isProductAvailable(sellDaysStr, startTimeStr, endTimeStr) {
//
const sellDays = sellDaysStr.split(',');
const now = dayjs();
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const currentDay = days[now.day()];
// console.log(':', currentDay);
// console.log(':', sellDays);
//
if (!sellDays.includes(currentDay)) {
// console.log('');
return false;
}
const startTime = dayjs(`${now.format('YYYY-MM-DD')} ${startTimeStr}`);
let endTime = dayjs(`${now.format('YYYY-MM-DD')} ${endTimeStr}`);
//
if (endTime.isBefore(startTime)) {
endTime = endTime.add(1, 'day');
}
// console.log(':', now.format('YYYY-MM-DD HH:mm:ss'));
// console.log(':', startTime.format('YYYY-MM-DD HH:mm:ss'));
// console.log(':', endTime.format('YYYY-MM-DD HH:mm:ss'));
const isInRange = now.isBetween(startTime, endTime, null, '[)');
// console.log(':', isInRange);
return isInRange;
}
defineExpose({
updateGoods,
clearDot,
@ -859,6 +883,7 @@ onMounted(() => {
if (goodsStore.categoryList.length) {
tabContentAni(goodsStore.categoryIndex)
}
// console.log(isProductAvailable("Friday", '17:00:00', '02:00:00'));
})
</script>
@ -1089,13 +1114,12 @@ onMounted(() => {
.weight {
position: absolute;
left: 2px;
bottom: 2px;
left: 4px;
bottom: 4px;
color: #fff;
font-size: 12px;
padding: 2px 6px;
background-color: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
background-color: rgba(250, 82, 82);
border-radius: 4px;
}

View File

@ -79,7 +79,7 @@
<script setup>
import _ from 'lodash'
import { ref } from "vue";
import { ref, nextTick } from "vue";
import { useUser } from "@/store/user.js";
import payCard from "@/components/payCard/payCard.vue";
import SettleItem from './settleItem.vue'
@ -245,13 +245,14 @@ const payCardRef = ref(null)
function show(t) {
dialogVisible.value = true;
cartInfo.value = { ...goodsStore.cartInfo }
console.log(cartInfo.value);
orderList.value = [...goodsStore.cartList, ...goodsStore.orderList.map(item => item.goods).flat()]
console.log('orderListInfo===================', { ...goodsStore.orderListInfo });
// paycard
setTimeout(() => {
payCardRef.value.reset()
}, 100)
nextTick(() => {
payCardRef.value.payCardInit()
})
}
defineExpose({

View File

@ -8,7 +8,10 @@
<el-button type="primary" plain>{{ goodsItem.lowPrice }}/{{ goodsItem.unitName }}</el-button>
</div>
<div class="item">
<div class="title">重量</div>
<div class="title" v-if="goodsItem.skuList && goodsItem.skuList.length">
重量{{
`${goodsItem.skuList[0].suitNum}${goodsItem.unitName}起售` }}
</div>
<el-input v-model="number" readonly placeholder="请输入">
<template #append>{{ goodsItem.unitName }}</template>
</el-input>
@ -29,15 +32,22 @@
</div>
</div>
<div class="price_item">
{{ formatDecimal(goodsItem.lowPrice * number) }}
<span class="p">{{ formatDecimal(goodsItem.lowPrice * number) }}</span>
<span v-if="goodsItem.isStock">库存{{ goodsItem.stockNumber }}</span>
</div>
<div class="footer">
<el-button style="width: 100%" :loading="loading" @click="dialogVisible = false">
取消
</el-button>
<el-button type="primary" style="width: 100%" :loading="loading" :disabled="number <= 0"
<el-button type="primary" style="width: 100%" :loading="loading"
:disabled="!!(number <= 0 || number < goodsItem.skuList[0].suitNum || (goodsItem.isStock && number > goodsItem.stockNumber))"
@click="confirmHandle">
确认
<template v-if="goodsItem.isStock && number > goodsItem.stockNumber">
库存不足
</template>
<template v-else>
确认
</template>
</el-button>
</div>
</el-dialog>
@ -80,6 +90,10 @@ const loading = ref(false)
//
function confirmHandle() {
if (!number.value) return
if (number.value < goodsItem.value.skuList[0].suitNum) {
ElMessage.error(`最少${goodsItem.value.skuList[0].suitNum}${goodsItem.value.unitName}`);
return;
}
// goodsItem.value.productId = goodsItem.value.id
// goodsItem.value.number = number.value
dialogVisible.value = false;
@ -119,9 +133,15 @@ defineExpose({
.price_item {
font-size: 18px;
font-weight: bold;
color: var(--el-color-danger);
padding: 15px 0;
border-top: 1px solid #ececec;
display: flex;
align-items: center;
justify-content: space-between;
.p {
color: var(--el-color-danger);
}
}
.footer {

View File

@ -168,6 +168,19 @@
<div class="no_permission" v-if="!store.menus.length || (store.menus.length && !store.menus[0].state)">
无操作权限请联系管理员(´д)
</div>
<!-- 打印插件是否加载好的提示 -->
<div class="print_tip" v-if="!printStore.isPrintService"
v-loading="!printStore.isPrintService && !printStore.showPrintNotService" element-loading-text="打印服务加载中...">
<el-dialog title="注意" v-model="printStore.showPrintNotService" :modal="false" top="30vh">
<span class="print_tip_title">打印服务未启动请重新加载程序或者退出后重新打开</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="printReloadHandle">重新加载</el-button>
<el-button type="primary" @click="quitAPPhandle">退出程序</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
<!-- 备注 -->
<remarkModal ref="remarkRef" @success="(e) => (remark = e)" />
@ -212,6 +225,11 @@ import goods from "@/views/home/components/goods.vue";
import member from "@/views/member/index.vue";
import { useUser } from '@/store/user.js'
import { useSocket } from '@/store/socket.js'
import { usePrint } from '@/store/print.js'
import { ipcRenderer } from 'electron';
import { ElMessage } from 'element-plus'
const printStore = usePrint()
const SelectVipUserRef = ref(null)
@ -236,6 +254,15 @@ const cartLoading = ref(false);
const orderInfo = ref({});
const createOrderLoading = ref(false);
function quitAPPhandle(params) {
ipcRenderer.send("quitHandler", "退出吧");
}
//
function printReloadHandle() {
location.reload()
}
//
function selectUser(row) {
console.log('selectUser===', row);
@ -264,9 +291,6 @@ async function quickCashHandle() {
async function createOrderHandle(t = 0) {
try {
if (goodsStore.cartList.length) {
// console.log(goodsStore.allSelected );
// console.log(goodsStore.allSelected ? store.shopInfo.eatModel.split(',')[1] : store.shopInfo.eatModel.split(',')[0]);
const data = {
orderId: goodsStore.orderListInfo.id || '', // id
shopId: store.shopInfo.id, // id
@ -284,19 +308,22 @@ async function createOrderHandle(t = 0) {
createOrderLoading.value = true;
goodsStore.calcCartInfo()
const res = await createOrder(data)
//
goodsStore.orderListInfo = res
if (t == 1) {
//
goodsStore.operateCart({ table_code: goodsStore.orderListInfo.tableCode }, "cleanup");
settleAccountRef.value.show(t)
if (res.id) {
//
goodsStore.orderListInfo = res
if (t == 1) {
//
goodsStore.operateCart({ table_code: goodsStore.orderListInfo.tableCode }, "cleanup");
console.log('生成订单===', res);
settleAccountRef.value.show(t)
} else {
goodsStore.clearCart()
}
//
goodsStore.updateOrderList()
} else {
goodsStore.clearCart()
ElMessage.error('订单成功失败,请重新下单')
}
//
goodsStore.updateOrderList()
} else {
settleAccountRef.value.show(t)
}
@ -389,6 +416,31 @@ function clearVipUserHandle() {
</script>
<style scoped lang="scss">
.print_tip {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(5px);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
.print_tip_title {
font-size: 18px;
font-weight: bold;
color: var(--el-color-danger);
}
.dialog-footer {
padding: var(--el-font-size-base);
}
}
.content {
position: relative;
}