Compare commits
53 Commits
gyq_zhuan_
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 492b3a45d5 | |||
| 4ce20c91bb | |||
| 91e094ee6b | |||
| 9018708e87 | |||
| 97b18651ef | |||
| c1ee82ee8a | |||
| bb06553701 | |||
| bca332f7b8 | |||
| 4478cc01fe | |||
| 7c7fc3ef0f | |||
| bec6bd6668 | |||
| 25ae5a7b80 | |||
| 125365f3dc | |||
| 8e3bc9cc3b | |||
| aa82851361 | |||
| aabbeced98 | |||
| b3b788d8d4 | |||
| ec5ae0e7d4 | |||
| 2ba61eab19 | |||
| 4d939b2889 | |||
| ca3b0eddbc | |||
| 3a11828f3c | |||
| 47ccfd0544 | |||
| b5773cf78c | |||
| 694cb154a6 | |||
| 0a0f672a02 | |||
| f466bdc9f4 | |||
| e443b5b51e | |||
| ebf912ecd8 | |||
| 429283e542 | |||
| 117df7d7bd | |||
| 0c45fd9de1 | |||
| e13727e6ff | |||
| 48280f92df | |||
| dd6189b51b | |||
| 95ab7730f5 | |||
| 4245b5a098 | |||
| 3e84edbb6c | |||
| a914adc9f8 | |||
| 87e8976353 | |||
| a101cc4fb7 | |||
| 177d987769 | |||
| 64f539623f | |||
| d08a629b0a | |||
| 745b8675ea | |||
| cfe9f7bb36 | |||
| 48c9f24d4c | |||
| 1e66b2ad1f | |||
| 3df0cce9ec | |||
| 5cf2355d28 | |||
| db3fc1f6dc | |||
| 573dd88b24 | |||
| d3ed4ec8e6 |
@@ -1,17 +1,17 @@
|
||||
# 本地环境
|
||||
ENV = development
|
||||
|
||||
# 测试ws
|
||||
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
|
||||
|
||||
# 正式ws
|
||||
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
#测试ws
|
||||
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||
|
||||
# 阿伟本地ws
|
||||
# VITE_API_WSS = 'ws://192.168.2.17:9998/client'
|
||||
# 本地ws
|
||||
VITE_API_WSS = 'ws://192.168.1.42:2348'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 测试 php 开票
|
||||
# VITE_API_KP_URL = 'http://192.168.1.13:8888/api'
|
||||
@@ -19,23 +19,11 @@ VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 阿伟
|
||||
# VITE_API_URL = 'http://192.168.2.96:10587/cashier-client'
|
||||
# 本地调试连接
|
||||
VITE_API_URL = 'http://192.168.1.42/'
|
||||
|
||||
# 鹏辉
|
||||
# VITE_API_URL = 'http://192.168.1.106:10589/cashier-client'
|
||||
# 线上测试
|
||||
# VITE_API_URL = 'https://tapi.cashier.sxczgkj.cn'
|
||||
|
||||
# 杰哥
|
||||
# VITE_API_URL = 'http://192.168.1.34:10589/cashier-client'
|
||||
|
||||
# 测试
|
||||
# VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 预发布
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 张松本地
|
||||
# VITE_API_URL = 'https://36z1017t45.goho.co/cashier-client'
|
||||
|
||||
# 正式
|
||||
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||
# 线上正式
|
||||
# VITE_API_URL = 'https://cashier.sxczgkj.com'
|
||||
@@ -2,16 +2,13 @@
|
||||
ENV = production
|
||||
|
||||
# 正式ws
|
||||
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 线上环境接口地址
|
||||
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client/'
|
||||
|
||||
# 预发布接口
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client/'
|
||||
VITE_API_URL = 'https://cashier.sxczgkj.com/'
|
||||
28
.env.test
28
.env.test
@@ -1,14 +1,17 @@
|
||||
# 线上环境
|
||||
# 测试环境
|
||||
ENV = test
|
||||
|
||||
#测试ws
|
||||
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||
# 测试ws
|
||||
VITE_API_WSS = 'ws://192.168.1.42:2348'
|
||||
|
||||
# 测试ws
|
||||
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
|
||||
|
||||
# 正式ws
|
||||
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 测试 php 开票
|
||||
# VITE_API_KP_URL = 'http://192.168.1.13:8888/api'
|
||||
@@ -16,14 +19,11 @@ VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 测试
|
||||
VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||
# 测试Java
|
||||
# VITE_API_URL = 'https://fv901fw8033.vicp.fun/'
|
||||
|
||||
# 预发布
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client'
|
||||
# 正式Java
|
||||
# VITE_API_URL = 'https://cashier.sxczgkj.com/'
|
||||
|
||||
# 张松本地
|
||||
# VITE_API_URL = 'https://36z1017t45.goho.co/cashier-client'
|
||||
|
||||
# 正式
|
||||
# VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||
# 本地调试连接
|
||||
VITE_API_URL = 'http://192.168.1.42/'
|
||||
15849
dist-electron/main.js
15849
dist-electron/main.js
File diff suppressed because one or more lines are too long
@@ -32,6 +32,7 @@ app.whenReady().then(() => {
|
||||
win.loadFile(path.resolve(__dirname, "../dist/index.html")); // 打包后使用文件路径访问应用
|
||||
}
|
||||
|
||||
// 安装最新版本的exe文件
|
||||
const installExe = async (exePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`${exePath}`, (error, stdout, stderr) => {
|
||||
|
||||
7692
package-lock.json
generated
Normal file
7692
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -1,18 +1,20 @@
|
||||
{
|
||||
"name": "vite-electron",
|
||||
"private": true,
|
||||
"version": "1.4.27",
|
||||
"version": "2.0.8",
|
||||
"main": "dist-electron/main.js",
|
||||
"scripts": {
|
||||
"dev": "chcp 65001 && vite",
|
||||
"build": "node ./addVersion.js && vite build && electron-builder",
|
||||
"build:test": "vite build --mode test && electron-builder",
|
||||
"preview": "vite preview",
|
||||
"build:win": "node ./addVersion.js && vite build && electron-builder --w"
|
||||
"build:win": "node ./addVersion.js && vite build && electron-builder --w",
|
||||
"postinstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.2",
|
||||
"bignumber.js": "^9.3.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"electron-pos-printer": "^1.3.6",
|
||||
"electron-pos-printer-vue": "^1.0.9",
|
||||
@@ -23,16 +25,16 @@
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"serialport": "^12.0.0",
|
||||
"speak-tts": "^2.0.8",
|
||||
"swiper": "^11.1.1",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.3.8",
|
||||
"vue-router": "^4.2.5"
|
||||
"vue-router": "^4.2.5",
|
||||
"ysk-utils": "^1.0.77"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.5.0",
|
||||
"electron": "^28.2.3",
|
||||
"electron": "^28.3.3",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"path": "^0.12.7",
|
||||
|
||||
@@ -67,7 +67,7 @@ body {
|
||||
font-weight: bold;
|
||||
}
|
||||
.print_view .number_wrap .info {
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.print_view .time {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<!-- <span class="title">{{data.ticket_logo}}</span> -->
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
<div class="num" v-if="data.outNumber">{{data.outNumber}}</div>
|
||||
<!-- <div class="num" v-if="data.outNumber">{{data.outNumber}}</div> -->
|
||||
<div class="info" v-if="data.masterId">座位号:{{data.masterId}}</div>
|
||||
</div>
|
||||
<div class="shop_info">
|
||||
|
||||
@@ -53,7 +53,7 @@ body {
|
||||
font-weight: bold;
|
||||
}
|
||||
.info {
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
29
src/App.vue
29
src/App.vue
@@ -26,21 +26,19 @@ import _ from 'lodash'
|
||||
import { ref, reactive, watch, onMounted } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import leftMenu from "@/components/leftMenu.vue";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { dayjs, ElMessage, ElMessageBox } from "element-plus";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { scanSendMessage } from "@/api/order/index";
|
||||
import { useGlobal } from "@/store/global.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const socket = useSocket();
|
||||
|
||||
const global = useGlobal();
|
||||
|
||||
const leftMenuRef = ref(null);
|
||||
|
||||
const store = useUser();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const includeList = reactive([]);
|
||||
@@ -165,13 +163,16 @@ async function getBarCode(e) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener("keydown", (e) => {
|
||||
getBarCode(e);
|
||||
});
|
||||
// 全局监听叫号
|
||||
// document.addEventListener("keydown", (e) => {
|
||||
// getBarCode(e);
|
||||
// });
|
||||
|
||||
// 防止刷新页面长连接丢失
|
||||
if (store.userInfo && store.userInfo.shopId) {
|
||||
socket.init();
|
||||
if (store.userInfo && store.userInfo.id) {
|
||||
goodsStore.initGoods()
|
||||
store.getShopInfo()
|
||||
store.shopPagePermissionMineAjax()
|
||||
}
|
||||
|
||||
ipcRenderer.on('showCloseDialog', (event, arg) => {
|
||||
@@ -333,7 +334,7 @@ html {
|
||||
.empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 100px;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
/*定义滚动条高宽及背景
|
||||
@@ -449,4 +450,8 @@ html {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.height_auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
417
src/api/account.js
Normal file
417
src/api/account.js
Normal file
@@ -0,0 +1,417 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 商户登录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function login(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/auth/login",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function logout(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/auth/logout",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function captcha(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/auth/captcha",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 店铺详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopInfo_detail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopInfo/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前店铺拓展通过key
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopExtendDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopExtend/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopUserList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取台桌区域
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopArea(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopArea",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取台桌列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopTable",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付方式列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getPayType(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/payType",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前登录员工信息
|
||||
*/
|
||||
export function shopStaffInfo() {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopStaff/info",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户充值记录
|
||||
*/
|
||||
export function shopUserChargeFlow(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser/flow",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户充值记录
|
||||
*/
|
||||
export function addShopUser(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/shopUser",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取叫号队列
|
||||
*/
|
||||
export function callTableQueue(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/queue",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取叫号配置
|
||||
*/
|
||||
export function callTableConfig(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/config",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改叫号配置
|
||||
*/
|
||||
export function callTableConfigPut(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/callTable/config",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号桌型新增
|
||||
*/
|
||||
export function addCallTable(data) {
|
||||
return request({
|
||||
method: data.id ? "put" : "post",
|
||||
url: "/account/admin/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号桌型删除
|
||||
*/
|
||||
export function delCallTable(data) {
|
||||
return request({
|
||||
method: "delete",
|
||||
url: "/account/admin/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取桌型列表
|
||||
*/
|
||||
export function getCallTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增叫号号码
|
||||
*/
|
||||
export function takeNumber(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/callTable/takeNumber",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取桌型列表
|
||||
*/
|
||||
export function callRecord(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/callRecord",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行叫号
|
||||
*/
|
||||
export function callTableCall(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/callTable/call",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改叫号队列状态
|
||||
*/
|
||||
export function callTableCallState(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/callTable/updateState",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班数据统计
|
||||
*/
|
||||
export function handoverTotal(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/handoverRecord/total",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班
|
||||
*/
|
||||
export function handover(isPrint) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/handoverRecord/handover?isPrint=" + isPrint,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班记录-详情
|
||||
*/
|
||||
export function handoverData(id) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/account/admin/handoverRecord/detail/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 交班记录-分页
|
||||
*/
|
||||
export function handoverRecordPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/account/admin/handoverRecord/page`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班/关班-网络打印机打印交班小票
|
||||
*/
|
||||
export function handoverNetworkPrint(id) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: `/account/admin/handoverRecord/network/print/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机列表
|
||||
*/
|
||||
export function printerList(subType = "") {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/printer",
|
||||
params: {
|
||||
name: "",
|
||||
subType: subType,
|
||||
connectionType: "USB",
|
||||
page: 1,
|
||||
size: 100,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机详情
|
||||
*/
|
||||
export function printerDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/printer/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增打印机
|
||||
*/
|
||||
export function printerAdd(data, method = "post") {
|
||||
return request({
|
||||
method: method,
|
||||
url: "/account/admin/printer",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找优惠券 生成订单后使用
|
||||
*/
|
||||
export function findCoupon(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/coupon/findCoupon",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 002-获取订单可用积分及抵扣金额(支付页面使用)
|
||||
*/
|
||||
export function calcUsablePoints(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/points/memberPoints/calcUsablePoints",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 003-根据积分计算可抵扣金额
|
||||
*/
|
||||
export function calcDeductionAmount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/points/memberPoints/calcDeductionAmount",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户详情
|
||||
*/
|
||||
export function shopUserDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前员工已拥有页面路径
|
||||
*/
|
||||
export function shopPagePermissionMine(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopPagePermission/mine",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 台桌清台
|
||||
*/
|
||||
export function shopTableClear(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/shopTable/clear",
|
||||
data,
|
||||
});
|
||||
}
|
||||
54
src/api/market.js
Normal file
54
src/api/market.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 智慧充值 配置信息获取
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function shopRecharge(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/shopRecharge",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前可用限时折扣
|
||||
* @param {shopId} params
|
||||
* @returns
|
||||
*/
|
||||
export function getLimitTimeDiscount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/limitTimeDiscount",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前可用的满减活动
|
||||
* @param {shopId} params
|
||||
* @returns
|
||||
*/
|
||||
export function getDiscountActivity(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/discountActivity",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户id获取新客立减金额,返回null代表不可用
|
||||
* @param {shopId} params
|
||||
* @returns
|
||||
*/
|
||||
export function getDiscountByUserId(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/consumeDiscount/getDiscountByUserId",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
261
src/api/order.js
Normal file
261
src/api/order.js
Normal file
@@ -0,0 +1,261 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 反扫
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function microPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/microPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金支付订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/cashPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单状态
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function queryOrderStatus(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/order/pay/queryOrderStatus`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单列表
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/order/admin/order`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function createOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/createOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史订单(多次下单使用)
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function historyOrder(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/historyOrder",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单退款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/refundOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function getOrderById(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/getOrderByIdPrint",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 现金充值
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPayVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/cashPayVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 反扫
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function microPayVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/microPayVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 会员退款前置接口
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundVipBefore(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/refundVipBefore",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 会员退款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/refundVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 分页
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function buyerPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/credit/buyer/page",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 付款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function creditPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/creditPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 会员支付订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function vipPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/vipPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单打印
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderPrint(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/print",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会员充值支付状态
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function queryPayStatus(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/pay/queryPayStatus",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单转桌
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function mergeOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/mergeOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cancelOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/cancelOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消某一次 下单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function rmPlaceOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/rmPlaceOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
53
src/api/product_new.js
Normal file
53
src/api/product_new.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询分类信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function categoryList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/product/admin/prod/category/list",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询商品列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function productPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/product/admin/product/list",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品上下架
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function productOnOff(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/product/admin/product/onOff",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品售罄
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function markIsSoldOut(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/product/admin/product/markIsSoldOut",
|
||||
data,
|
||||
});
|
||||
}
|
||||
12
src/api/system.js
Normal file
12
src/api/system.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 获取版本 pc:pc端 type 0 windows,1 安卓,2 iOS
|
||||
* @returns
|
||||
*/
|
||||
export function findVersion(source = "pc", type = 0) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/system/admin/version/${source}/${type}`,
|
||||
});
|
||||
}
|
||||
14
src/assets/icon_goods_kcbz.svg
Normal file
14
src/assets/icon_goods_kcbz.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="121" height="120" viewBox="0 0 121 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5_38)">
|
||||
<circle cx="60.2939" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.2938" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.8277" y1="50.637" x2="82.4435" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.7388" y1="93.3029" x2="99.3547" y2="70.5335" stroke="white"/>
|
||||
<path d="M22.4599 62.0201C23.1265 62.5176 23.7976 63.0902 24.4821 63.7599L32.6011 60.8049L33.2304 62.3625L16.5189 68.445L18.5688 73.5186C20.4655 78.4692 21.3126 82.6787 21.0559 86.1414L19.2488 85.4463C19.4643 82.4581 18.6888 78.6819 16.8999 74.126L14.2207 67.4948L22.7005 64.4084C22.0609 63.8499 21.4032 63.3746 20.7815 62.9883L22.4599 62.0201ZM22.7471 66.8928L24.4471 66.6825C24.4958 67.3794 24.5266 68.0319 24.5574 68.6843L33.3529 65.483L33.9193 66.8849L24.56 70.2914C24.5039 71.9454 24.3398 73.4601 24.0676 74.8353L28.285 73.3004L27.1971 70.6078L28.8209 70.0168L29.9088 72.7093L34.938 70.8789L35.5224 72.3253L30.4932 74.1558L31.5001 76.648L38.2433 74.1937L38.8367 75.6623L32.0935 78.1167L33.514 81.6326L31.8902 82.2236L30.4697 78.7077L22.3282 81.671L21.7348 80.2023L29.8763 77.239L28.8694 74.7468L22.9606 76.8974L22.0649 75.6409C22.4993 74.2831 22.7672 72.7051 22.846 70.9153L19.4405 72.1547L18.8741 70.7528L22.8659 69.2999C22.8353 68.5198 22.7957 67.7175 22.7471 66.8928ZM35.6949 60.0106L41.8292 57.7779C41.8077 56.8924 41.7637 56.015 41.6655 55.1319L43.3928 54.7329C43.464 55.5493 43.5261 56.3435 43.5658 57.1459L55.1127 52.9431L55.742 54.5008L43.5862 58.9252C43.5249 61.1426 43.1977 63.2781 42.6272 65.3235L47.2034 76.65L45.6247 77.2246L41.8217 67.8118C41.3876 68.9143 40.9129 69.9804 40.3616 71.0489L38.8343 70.1499C40.6237 66.7675 41.6063 63.2448 41.8045 59.5736L36.3242 61.5683L35.6949 60.0106ZM45.8068 68.1992L52.3471 65.8187L51.511 63.7492C52.5088 62.5693 53.394 61.3027 54.1711 59.8967L45.6913 62.9831L45.089 61.4922L55.6436 57.6506L56.246 59.1415C55.4777 60.6974 54.5335 62.2662 53.4045 63.8258L53.9709 65.2277L59.609 63.1756L60.2294 64.711L54.5912 66.7631L56.2905 70.9688C56.8209 72.2817 56.414 73.1955 55.0834 73.6798L52.2644 74.7059L51.2245 73.3487C52.0454 73.0754 52.9114 72.7858 53.836 72.4492C54.5126 72.203 54.7296 71.7156 54.4599 71.048L52.9674 67.3541L46.4272 69.7346L45.8068 68.1992ZM57.6942 50.7528L76.9993 43.7263L77.6286 45.284L70.2313 47.9764C70.194 49.0365 70.08 50.099 69.8894 51.1638L70.303 52.1874C74.7565 52.9658 78.7948 54.125 82.4178 55.6651L81.8432 57.3802C78.698 55.8704 75.0971 54.7051 70.9862 53.8786L75.967 66.2065L74.2981 66.8139L69.1555 54.0855C68.0785 57.4384 66.217 60.7705 63.5756 64.0291L61.9582 63.0352C65.9314 58.2709 68.0832 53.4803 68.4271 48.6331L58.3236 52.3105L57.6942 50.7528ZM82.9851 41.1903L97.1482 36.0354L100.205 43.6012L94.1383 45.8093L95.6308 49.5032L103.073 46.7944L103.702 48.3521L96.2601 51.0609L98.1391 55.7116C99.4425 55.4159 100.989 54.955 102.749 54.3147C104.44 53.6991 105.843 53.1374 106.989 52.6438L107.185 54.4102C105.809 54.9109 104.56 55.3401 103.446 55.7201C99.3998 57.1671 96.5271 57.8043 94.796 57.6176C93.2813 57.4542 91.6187 56.6044 89.8622 55.0741C89.8232 57.5387 89.4373 59.7211 88.6821 61.6296L87.1322 60.7388C88.2721 57.6694 88.4342 54.0369 87.5961 49.8496L89.2916 49.5643C89.5381 50.8784 89.7124 52.1423 89.8056 53.3335C91.7197 55.0617 93.4544 55.9618 95.0413 56.0478C95.4336 56.0582 95.8709 56.0522 96.3669 55.9993L92.492 46.4085L86.0419 48.7561L82.9851 41.1903ZM97.9473 42.6873L96.1222 38.17L85.2293 42.1347L87.0544 46.652L97.9473 42.6873Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5_38">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.293854)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
14
src/assets/icon_goods_sq.svg
Normal file
14
src/assets/icon_goods_sq.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_36)">
|
||||
<circle cx="60" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.5338" y1="50.637" x2="82.1497" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.445" y1="93.3029" x2="99.0608" y2="70.5335" stroke="white"/>
|
||||
<path d="M57.134 66.8373L60.6344 75.5009L58.4994 76.278L57.912 74.8242L41.9748 80.6248L42.5622 82.0786L40.4272 82.8557L36.9269 74.1921L57.134 66.8373ZM41.2076 78.7259L57.1448 72.9253L55.7423 69.4539L39.8051 75.2546L41.2076 78.7259ZM32.5035 63.2439C31.9245 64.8841 31.2192 66.468 30.3698 68.0364L28.8571 66.1707C30.8456 62.2138 31.8241 58.3182 31.7745 54.5246L34.0473 54.1738C34.046 55.1952 34.0028 56.1979 33.8994 57.2225L41.3568 54.5083C40.4981 53.6637 39.6574 52.9487 38.7805 52.3149L40.8618 51.149C41.7145 51.8936 42.5852 52.7679 43.4617 53.7421L52.2121 50.5573L52.9313 52.3374L43.79 55.6646L44.6651 57.8305L52.4833 54.9849L53.1666 56.6761L45.3484 59.5217L46.1875 61.5986L54.0659 58.7311L54.7491 60.4223L46.8708 63.2898L47.7698 65.515L57.3923 62.0127L58.1235 63.8226L35.9919 71.8779L32.5035 63.2439ZM45.6348 66.2921L44.7358 64.0669L36.4364 67.0876L37.3355 69.3128L45.6348 66.2921ZM44.0525 62.3757L43.2134 60.2988L34.914 63.3195L35.7531 65.3964L44.0525 62.3757ZM42.5301 58.6076L41.655 56.4417L33.5661 59.3858C33.5239 59.5373 33.4997 59.6482 33.4875 59.7888L34.2307 61.6283L42.5301 58.6076ZM56.4839 47.471L62.7084 45.2054L62.121 43.7516L64.2259 42.9855L64.8133 44.4393L69.8952 42.5897L70.5185 44.1325L65.4367 45.9821L66.0001 47.3766L70.27 45.8225L70.8454 47.2466L59.6593 51.318L59.0839 49.8939L63.8951 48.1427L63.3317 46.7483L57.1072 49.0138L56.4839 47.471ZM65.8022 52.0091L62.7651 53.1145L63.0168 53.7375C63.1607 54.0936 63.2864 54.4902 63.3701 54.8682L66.4974 53.7299L65.8022 52.0091ZM68.1212 53.1389L70.7674 52.1758L70.0721 50.4549L67.426 51.4181L68.1212 53.1389ZM63.615 56.2425C63.7454 57.7605 63.5032 59.21 62.8703 60.6315L60.9416 59.8701C61.7612 58.1424 61.8294 56.3478 61.0923 54.438L60.3131 52.5095L71.379 48.4818L73.1171 52.784L63.615 56.2425ZM71.9233 40.6944L79.1401 38.0676L80.0991 40.4412C80.2669 40.8566 80.5433 41.0283 80.9342 40.886L83.1894 40.0652L83.8128 41.608L81.1065 42.593C79.9037 43.0308 79.0505 42.6266 78.559 41.4102L78.0795 40.2234L74.2306 41.6243C74.5542 42.4254 74.6495 43.1735 74.5766 43.8466C74.4254 44.5823 74.0097 45.3462 73.3114 46.1789L71.635 45.5299C72.189 44.6816 72.4844 43.9615 72.5694 43.318C72.5942 42.6964 72.3788 41.8218 71.9233 40.6944ZM83.3605 42.7936L83.84 43.9804C83.6458 45.5486 82.9887 47.081 81.8387 48.5886C83.4017 48.5302 85.2234 48.3436 87.3038 48.0288L87.0971 49.9078C84.4457 50.2603 82.2093 50.3595 80.358 50.2166C79.0219 51.5197 77.3552 52.7729 75.358 53.9763L73.9227 52.729C75.6071 51.7756 77.0149 50.8208 78.1882 49.8832C76.5055 49.4747 75.1958 48.7942 74.2712 47.8716L73.0984 48.2984L72.4751 46.7556L83.3605 42.7936ZM75.925 47.2696C76.6817 47.9471 77.9255 48.3793 79.6446 48.5363C80.7641 47.3802 81.5169 46.2553 81.8789 45.1026L75.925 47.2696ZM68.9973 59.4905C68.6716 60.3918 68.2738 61.2853 67.8219 62.1304L65.6343 61.6674C66.8993 59.5054 67.5631 57.392 67.6858 55.3053L69.8683 54.9874C69.8194 55.7199 69.7283 56.4337 69.6134 57.0882L83.8967 51.8895L84.6639 53.7883L77.0862 56.5464L78.177 59.2463L89.6338 55.0764L90.401 56.9753L78.9442 61.1452L80.3468 64.6166L87.2328 62.1103L86.2619 59.707L88.3668 58.9409L90.5605 64.3705L88.4556 65.1366L87.988 63.9795L71.9907 69.802L72.4582 70.9591L70.3533 71.7253L68.1836 66.355L70.2885 65.5889L71.2355 67.9328L78.2118 65.3937L76.8093 61.9223L64.4204 66.4315L63.6532 64.5326L76.0421 60.0234L74.9512 57.3235L68.9973 59.4905Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_36">
|
||||
<rect width="120" height="120" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
14
src/assets/icon_goods_wks.svg
Normal file
14
src/assets/icon_goods_wks.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="121" height="120" viewBox="0 0 121 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_35)">
|
||||
<circle cx="60.2939" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.2938" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.8277" y1="50.637" x2="82.4435" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.7388" y1="93.3029" x2="99.3547" y2="70.5335" stroke="white"/>
|
||||
<path d="M26.044 58.3135L28.1301 57.5543L29.6698 61.365L39.3392 57.8456L40.1259 59.7927L30.4565 63.3121L32.4456 68.2354L43.6092 64.1722L44.3958 66.1193L35.0929 69.5053C38.3977 72.3226 42.9265 74.2477 48.6624 75.3187L47.9721 77.6119C41.831 76.0184 36.9817 73.5399 33.4578 70.1004L33.2323 70.1825L38.3569 82.8664L36.2708 83.6257L31.1462 70.9418L30.8925 71.0341C30.7058 76.3346 28.8006 81.3035 25.1994 85.9962L23.2907 84.5532C26.8122 80.4638 28.8237 76.1582 29.3138 71.6087L19.9826 75.005L19.196 73.0579L30.3595 68.9947L28.3703 64.0714L18.8982 67.5189L18.1116 65.5718L27.5837 62.1243L26.044 58.3135ZM44.9692 53.2121L66.9298 45.2191L67.7165 47.1662L63.0086 48.8797L65.9867 56.2508L72.1605 54.0037L72.936 55.923L66.7622 58.1701L71.7407 70.4923L69.6828 71.2414L64.7042 58.9191L56.5571 61.8844C57.4609 64.8417 57.8806 67.401 57.799 69.6003C57.6718 72.3267 56.6263 74.7811 54.6624 76.9636L52.8662 75.6392C54.6327 73.5285 55.5541 71.2469 55.6021 68.8046C55.5422 66.9758 55.1727 64.9407 54.4992 62.6334L47.9871 65.0036L47.2117 63.0843L53.8365 60.6731C53.6904 60.3115 53.5837 59.9675 53.4714 59.6893L50.8866 53.2917L45.7559 55.1592L44.9692 53.2121ZM52.9727 52.5324L55.5575 58.93C55.6923 59.2638 55.799 59.6079 55.9226 59.9138L63.9288 56.9998L60.9507 49.6287L52.9727 52.5324ZM100.444 51.1754L103.725 59.2975L101.724 60.026L101.173 58.6631L86.2321 64.1012L86.7828 65.4641L84.7812 66.1927L81.4997 58.0705L100.444 51.1754ZM85.5128 62.321L100.454 56.8829L99.1391 53.6285L84.198 59.0666L85.5128 62.321ZM77.3528 47.8066C76.8099 49.3442 76.1488 50.8292 75.3524 52.2996L73.9343 50.5504C75.7985 46.8408 76.7158 43.1887 76.6693 39.6322L78.8 39.3034C78.7989 40.261 78.7583 41.201 78.6614 42.1616L85.6527 39.6169C84.8477 38.8251 84.0595 38.1548 83.2374 37.5607L85.1887 36.4676C85.9881 37.1657 86.8043 37.9853 87.626 38.8987L95.8295 35.9128L96.5038 37.5818L87.9338 40.701L88.7542 42.7315L96.0838 40.0638L96.7244 41.6493L89.3948 44.317L90.1815 46.2641L97.5675 43.5758L98.208 45.1613L90.8221 47.8496L91.6649 49.9358L100.686 46.6524L101.371 48.3491L80.6231 55.9009L77.3528 47.8066ZM89.6634 50.6643L88.8205 48.5781L81.0399 51.41L81.8827 53.4962L89.6634 50.6643ZM88.1799 46.9926L87.3933 45.0455L79.6126 47.8774L80.3993 49.8245L88.1799 46.9926ZM86.7527 43.46L85.9323 41.4295L78.349 44.1896C78.3094 44.3317 78.2867 44.4356 78.2753 44.5674L78.972 46.292L86.7527 43.46Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_35">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.293854)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
14
src/assets/icon_goods_yxj.svg
Normal file
14
src/assets/icon_goods_yxj.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="121" height="121" viewBox="0 0 121 121" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_37)">
|
||||
<circle cx="60.706" cy="60.1438" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.706" cy="60.1438" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="20.2398" y1="50.7807" x2="82.8557" y2="28.0114" stroke="white"/>
|
||||
<line x1="37.151" y1="93.4466" x2="99.7668" y2="70.6773" stroke="white"/>
|
||||
<path d="M41.9891 67.1295L24.2853 73.5732L27.6006 81.7788C28.095 83.0027 29.0019 83.4064 30.2987 82.9344L44.4505 77.7836C45.127 77.5373 45.6234 77.1652 45.9114 76.6775C46.273 75.9717 45.9202 74.0581 44.8531 70.9368L47.0737 70.8305C48.1854 74.3822 48.5377 76.615 48.1534 77.5845C47.7692 78.3943 46.9625 79.0389 45.8009 79.5255L30.5215 85.0867C28.2381 85.9178 26.6385 85.16 25.7169 82.8791L19.8169 68.276L21.8466 67.5372L23.5099 71.6539L39.1557 65.9593L36.2226 58.6994L17.4193 65.5433L16.6326 63.5962L37.4938 56.0033L41.9891 67.1295ZM43.6958 53.746L68.7574 44.6243L69.5553 46.5992L57.3205 51.0523L59.0175 55.2525C63.2099 55.7047 67.5711 56.4146 72.101 57.3821L71.6081 59.6035C66.8697 58.5204 62.9482 57.7781 59.8716 57.3664L66.2549 73.1657L64.1969 73.9147L55.2626 51.8013L44.4937 55.7209L43.6958 53.746ZM86.686 38.737L95.7634 35.4331L99.6406 45.0294L90.5631 48.3333L86.686 38.737ZM96.9649 43.9294L94.5487 37.949L89.3334 39.8473L91.7496 45.8276L96.9649 43.9294ZM75.9761 40.4016L77.9495 39.6834L78.9609 42.1868L84.4581 40.1859C86.3629 44.9805 87.2273 47.9203 87.0456 49.0712C86.8357 50.2324 86.04 51.0644 84.6305 51.5774C84.1795 51.7416 83.6495 51.8707 83.0069 52.0408L81.769 50.4174L83.432 49.9717C84.4357 49.5745 84.9379 48.9769 84.9389 48.1789C84.8947 47.4292 84.3052 45.5699 83.1815 42.6288L79.5167 43.9626C80.5827 48.0415 80.0148 51.5983 77.8133 54.633L75.791 53.8695C77.823 51.2155 78.4015 48.1653 77.5434 44.6809L73.4557 46.1687L72.759 44.4441L76.9876 42.905L75.9761 40.4016ZM77.6697 56.9187L88.8896 52.835L87.9793 50.5819L90.009 49.8431L90.9193 52.0962L102.167 48.0022L102.932 49.8937L93.5441 53.3104C96.3883 54.8277 100.451 55.6783 105.709 55.8065L104.996 58.0441C99.2876 57.4416 94.9159 56.0655 91.8527 53.9261L91.6835 53.9876L95.1337 62.527L93.1039 63.2658L89.6538 54.7264L89.5128 54.7777C88.7079 58.708 86.3138 62.5466 82.3811 66.339L80.4836 64.9239C84.269 61.7275 86.7018 58.5448 87.7932 55.4036L78.4339 58.8101L77.6697 56.9187Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_37">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.706001 0.143768)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.1 KiB |
1
src/assets/no-sale.svg
Normal file
1
src/assets/no-sale.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.9 KiB |
@@ -5,8 +5,8 @@
|
||||
<div class="list_title">{{ item.name }}</div>
|
||||
<div class="item_wrap">
|
||||
<el-button :type="item.active ? 'primary' : ''" @click="selectHandle(item)">全部</el-button>
|
||||
<el-button :type="val.active ? 'primary' : ''" v-for="val in item.childrenList" :key="val.id"
|
||||
@click="selectHandle(val, index)">{{ val.name }}</el-button>
|
||||
<!-- <el-button :type="val.active ? 'primary' : ''" v-for="val in item.childrenList" :key="val.id"
|
||||
@click="selectHandle(val, index)">{{ val.name }}</el-button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,9 +18,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { tbShopCategoryGet } from "@/api/device";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const store = useUser();
|
||||
const emit = defineEmits(["success"]);
|
||||
@@ -29,6 +31,7 @@ const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const categorys = ref([]);
|
||||
|
||||
// 确定
|
||||
function onSubmitHandle() {
|
||||
let categorysArr = [];
|
||||
for (let item of categorys.value) {
|
||||
@@ -38,16 +41,16 @@ function onSubmitHandle() {
|
||||
id: item.id,
|
||||
});
|
||||
}
|
||||
if (item.childrenList.length) {
|
||||
for (let val of item.childrenList) {
|
||||
if (val.active) {
|
||||
categorysArr.push({
|
||||
name: `${val.name}`,
|
||||
id: val.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (item.childrenList.length) {
|
||||
// for (let val of item.childrenList) {
|
||||
// if (val.active) {
|
||||
// categorysArr.push({
|
||||
// name: `${val.name}`,
|
||||
// id: val.id,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
emit("success", categorysArr);
|
||||
dialogVisible.value = false;
|
||||
@@ -55,38 +58,34 @@ function onSubmitHandle() {
|
||||
|
||||
// 选择分类
|
||||
function selectHandle(item, index = -1) {
|
||||
if (index != -1) {
|
||||
categorys.value[index].active = false;
|
||||
} else {
|
||||
item.childrenList.map((item) => {
|
||||
item.active = false;
|
||||
});
|
||||
}
|
||||
// if (index != -1) {
|
||||
// categorys.value[index].active = false;
|
||||
// } else {
|
||||
// item.childrenList.map((item) => {
|
||||
// item.active = false;
|
||||
// });
|
||||
// }
|
||||
item.active = !item.active;
|
||||
}
|
||||
|
||||
// 获取分类
|
||||
async function tbShopCategoryGetAjax() {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await tbShopCategoryGet({
|
||||
shopId: store.userInfo.shopId,
|
||||
sort: "sort,desc",
|
||||
page: 0,
|
||||
pageSize: 200,
|
||||
// loading.value = true;
|
||||
// const res = await categoryList();
|
||||
// res.list.map((item) => {
|
||||
// item.active = false;
|
||||
// item.childrenList.map((item) => {
|
||||
// item.active = false;
|
||||
// });
|
||||
// });
|
||||
categorys.value = goodsStore.originCategoryList.map(item => {
|
||||
item.active = false
|
||||
return item
|
||||
});
|
||||
// console.log(res);
|
||||
res.list.map((item) => {
|
||||
item.active = false;
|
||||
item.childrenList.map((item) => {
|
||||
item.active = false;
|
||||
});
|
||||
});
|
||||
categorys.value = res.list;
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 300);
|
||||
// setTimeout(() => {
|
||||
// loading.value = false;
|
||||
// }, 300);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
loading.value = false;
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
</div>
|
||||
<div class="t1" v-else>
|
||||
<span class="title">会员:</span>
|
||||
<span class="num">{{
|
||||
props.userInfo.id && props.userInfo.telephone
|
||||
}}</span>
|
||||
<span class="num">
|
||||
{{ props.userInfo.id && props.userInfo.phone }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="t2">
|
||||
<span>已付:¥0.00</span>
|
||||
@@ -33,6 +33,21 @@
|
||||
<span class="title">{{ item.payName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quick_charge">
|
||||
<div class="item" :class="{active:chargeActive == index }" v-for="(item,index) in chargeList" :key="item.id" @click="changeCharge(index,item)">
|
||||
<div class="row">
|
||||
<span class="icon">¥</span>
|
||||
<span class="num">{{ item.amount }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="t1">赠¥{{ item.rewardAmount }}</span>
|
||||
<span class="t1">送{{ item.rewardPoints }}积分</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="t2">送{{item.couponCount}}张券</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input_wrap">
|
||||
<div class="input" style="flex: 1">储值:¥{{ money }}</div>
|
||||
</div>
|
||||
@@ -59,35 +74,31 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<scanModal ref="scanModalRef" fast :amount="money" :money="money" :selecttype="props.type" :orderId="props.userInfo.id"
|
||||
@success="scanCodeSuccess" />
|
||||
<scanModal ref="scanModalRef" fast :amount="money" :money="money" :selecttype="props.type"
|
||||
:orderId="props.userInfo.id" :chargeId="chargeId" @success="scanCodeSuccess" />
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" :type="2" input-type="password" placeholder="请输入支付密码"
|
||||
@success="passwordSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { queryPayType, quickPay } from "@/api/pay";
|
||||
import {
|
||||
queryMembermember,
|
||||
createMembermember,
|
||||
membermemberScanPay,
|
||||
accountPaymember,
|
||||
} from "@/api/member/index.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { shopRecharge } from '@/api/market.js'
|
||||
import { getPayType } from '@/api/account.js'
|
||||
import { cashPayVip } from "@/api/order.js";
|
||||
import { clearNoNum } from "@/utils";
|
||||
import md5 from "js-md5";
|
||||
|
||||
import { queryPwdInfo } from '@/api/user.js'
|
||||
import scanModal from "@/components/payCard/scanModal.vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
import { useUser } from '@/store/user.js'
|
||||
|
||||
const takeFoodCodeRef = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: [String, Number],
|
||||
default: 0, // 1快捷收银 2会员支付
|
||||
default: 0, // 0 订单支付 1 会员充值 2 快捷收款
|
||||
},
|
||||
userInfo: {
|
||||
type: Object,
|
||||
@@ -132,14 +143,18 @@ function payTypeChange(index, item) {
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
payLoading.value = true;
|
||||
await accountPaymember({
|
||||
shopId: store.userInfo.shopId,
|
||||
memberId: props.userInfo.id,
|
||||
await cashPayVip({
|
||||
shopId: store.shopInfo.id,
|
||||
shopUserId: props.userInfo.id,
|
||||
amount: money.value,
|
||||
pwd: e ? md5(e) : '',
|
||||
// pwd: e ? md5(e) : '',
|
||||
pwd: e,
|
||||
orderId: '',
|
||||
allPack: '',
|
||||
rechargeDetailId: chargeId.value
|
||||
});
|
||||
payLoading.value = false;
|
||||
ElMessage.success("支付成功");
|
||||
ElMessage.success("充值成功");
|
||||
emit("paySuccess");
|
||||
} catch (error) {
|
||||
payLoading.value = false;
|
||||
@@ -176,15 +191,12 @@ async function confirmOrder() {
|
||||
emit("paySuccess");
|
||||
} else {
|
||||
// 会员充值
|
||||
|
||||
let res = await queryPwdInfo()
|
||||
if (res.isMemberIn == 1) {
|
||||
await store.getShopInfo()
|
||||
if (store.shopInfo.isMemberInPwd == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
// takeFoodCodeRef.value.show();
|
||||
// // passwordSuccess()
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -201,12 +213,16 @@ async function confirmOrder() {
|
||||
// 输入
|
||||
function amountInput(num) {
|
||||
money.value = clearNoNum({ value: (money.value += num) });
|
||||
chargeActive.value = null
|
||||
chargeId.value = ''
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!money.value) return;
|
||||
money.value = money.value.substring(0, money.value.length - 1);
|
||||
chargeActive.value = null
|
||||
chargeId.value = ''
|
||||
money.value = money.value.substring(0, money.value.length - 1);
|
||||
if (!money.value) {
|
||||
money.value = "0";
|
||||
}
|
||||
@@ -215,9 +231,7 @@ function delHandle() {
|
||||
// 获取支付方式
|
||||
async function queryPayTypeAjax() {
|
||||
try {
|
||||
const res = await queryPayType({
|
||||
shopId: store.userInfo.shopId,
|
||||
});
|
||||
const res = await getPayType();
|
||||
|
||||
const arr = [];
|
||||
res.map((item) => {
|
||||
@@ -232,15 +246,49 @@ async function queryPayTypeAjax() {
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
function reset() {
|
||||
money.value = 0;
|
||||
payActive.value = 0;
|
||||
chargeActive.value = null;
|
||||
}
|
||||
|
||||
// 获取智慧充值的配置信息
|
||||
const chargeActive = ref(null);
|
||||
const chargeList = ref([])
|
||||
const chargeId = ref('')
|
||||
|
||||
function changeCharge(index,item) {
|
||||
chargeActive.value = index
|
||||
chargeId.value = item.id
|
||||
money.value = ''
|
||||
money.value = clearNoNum({ value: (money.value += item.amount) })
|
||||
}
|
||||
|
||||
async function shopRechargeAjax() {
|
||||
try {
|
||||
const res = await shopRecharge()
|
||||
res.rechargeDetailList.map((item) => {
|
||||
item.couponCount = 0
|
||||
item.couponInfoList.map(val => {
|
||||
item.couponCount += val.num;
|
||||
})
|
||||
})
|
||||
|
||||
chargeList.value = res.rechargeDetailList
|
||||
|
||||
console.log(chargeList.value)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defineExpose({ reset });
|
||||
|
||||
onMounted(() => {
|
||||
queryPayTypeAjax();
|
||||
shopRechargeAjax()
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -307,7 +355,7 @@ onMounted(() => {
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.item {
|
||||
height: 130px;
|
||||
height: 80px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -337,9 +385,56 @@ onMounted(() => {
|
||||
width: $size;
|
||||
height: $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding-top: 10px;
|
||||
.quick_charge {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
overflow-x: auto;
|
||||
margin-top: var(--el-font-size-base);
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
$activeColor: #FF6300;
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background-color: #F5F5F5;
|
||||
border-radius: 8px;
|
||||
padding: var(--el-font-size-base);
|
||||
margin-right: var(--el-font-size-base);
|
||||
border: 2px solid #F5F5F5;
|
||||
&.active {
|
||||
border-color: $activeColor;
|
||||
.row {
|
||||
.icon {
|
||||
color: $activeColor;
|
||||
}
|
||||
.num {
|
||||
color: $activeColor;
|
||||
}
|
||||
.t1 {
|
||||
color: $activeColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.icon {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
.num {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.t2 {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +447,7 @@ onMounted(() => {
|
||||
.input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
height: 50px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--primary-color);
|
||||
font-size: calc(var(--el-font-size-base) + 6px);
|
||||
@@ -370,7 +465,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
--item-height: calc((100vh - 440px) / 4);
|
||||
--item-height: calc((100vh - 440px) / 5);
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
<template>
|
||||
<div class="left_menu_wrap">
|
||||
<div class="item first" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||
<el-icon class="icon">
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
<el-text :type="socketStore.online ? 'success' : 'danger'">
|
||||
<template v-if="socketStore.online">
|
||||
在线
|
||||
</template>
|
||||
<template v-else>
|
||||
离线
|
||||
</template>
|
||||
</el-text>
|
||||
<div class="top_item_wra">
|
||||
<div class="item first" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||
<el-icon class="icon">
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
<el-text :type="socketStore.online ? 'success' : 'danger'">
|
||||
{{ socketStore.online ? '在线' : '离线' }}
|
||||
</el-text>
|
||||
</div>
|
||||
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in store.menus"
|
||||
:key="item.path" :to="item.path">
|
||||
<el-icon class="icon">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
<el-text class="text">{{ item.label }}</el-text>
|
||||
</router-link>
|
||||
<div class="item" @click="workRef.show()">
|
||||
<el-icon class="icon">
|
||||
<component is="SwitchButton" />
|
||||
</el-icon>
|
||||
<el-text class="text">交班</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in menus" :key="item.path"
|
||||
:to="item.path">
|
||||
<el-icon class="icon">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
<el-text class="text">{{ item.label }}</el-text>
|
||||
</router-link>
|
||||
<div class="item" @click="workRef.show()">
|
||||
<el-icon class="icon">
|
||||
<component is="SwitchButton" />
|
||||
</el-icon>
|
||||
<el-text class="text">交班</el-text>
|
||||
</div>
|
||||
<div class="item more" @click="moreref.show()">
|
||||
<div class="item" @click="moreref.show()">
|
||||
<el-icon class="icon">
|
||||
<Operation />
|
||||
</el-icon>
|
||||
@@ -38,66 +35,24 @@
|
||||
<!-- 更多 -->
|
||||
<more ref="moreref" @openCall="openCall"></more>
|
||||
<!-- 叫号 -->
|
||||
<callNumber ref="callNumberRef" />
|
||||
<!-- <callNumber ref="callNumberRef" /> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
import { useUser } from '@/store/user.js'
|
||||
import more from '@/components/more.vue'
|
||||
import callNumber from './callNumber.vue'
|
||||
import work from '@/views/work/index.vue'
|
||||
|
||||
const socketStore = useSocket()
|
||||
|
||||
const route = useRoute()
|
||||
const moreref = ref(null)
|
||||
const callNumberRef = ref(null)
|
||||
const workRef = ref(null)
|
||||
|
||||
const menus = ref([
|
||||
{
|
||||
label: '收银',
|
||||
path: '/',
|
||||
icon: 'ShoppingCartFull'
|
||||
},
|
||||
{
|
||||
label: '台桌',
|
||||
path: '/table',
|
||||
icon: 'Reading'
|
||||
},
|
||||
{
|
||||
label: '团购',
|
||||
path: '/group_buy',
|
||||
icon: 'Handbag'
|
||||
},
|
||||
{
|
||||
label: '订单',
|
||||
path: '/order',
|
||||
icon: 'Tickets'
|
||||
},
|
||||
// {
|
||||
// label: '网络',
|
||||
// path: '/internat',
|
||||
// icon: 'Paperclip'
|
||||
// },
|
||||
{
|
||||
label: '会员',
|
||||
path: '/member',
|
||||
icon: 'User'
|
||||
},
|
||||
{
|
||||
label: '排队',
|
||||
path: '/queue',
|
||||
icon: 'Timer'
|
||||
},
|
||||
// {
|
||||
// label: '交班',
|
||||
// path: '/work',
|
||||
// icon: 'SwitchButton'
|
||||
// }
|
||||
])
|
||||
const store = useUser()
|
||||
|
||||
// 更新叫号记录
|
||||
function updateCallNumber() {
|
||||
@@ -110,7 +65,6 @@ function openCall() {
|
||||
|
||||
// 手动重新连接ws
|
||||
function connectWsHandle() {
|
||||
// if (socketStore.online) return
|
||||
location.reload()
|
||||
}
|
||||
|
||||
@@ -203,9 +157,16 @@ defineExpose({
|
||||
background-color: #555;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.top_item_wra {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -237,10 +198,6 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
&.more {
|
||||
margin-top: 90px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #999;
|
||||
font-size: 22px;
|
||||
|
||||
@@ -12,53 +12,68 @@ export default (data) => {
|
||||
LODOP.SET_PRINTER_INDEX(data.deviceName);
|
||||
// 文字内容
|
||||
let html = `
|
||||
<div style="font-size: 30px;display:flex;justify-content:center;">
|
||||
${data.merchantName}
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shopName}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
交班小票
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top:50px;">
|
||||
当班时间:${data.startTime}
|
||||
当班时间:${data.loginTime}
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
交班时间:${data.endTime}
|
||||
交班时间:${data.handoverTime}
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
收银员:${data.staff}
|
||||
收银员:${data.staffName}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
当班收入:${data.totalAmount}
|
||||
当班总收入:${data.handAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
现金收入:${data.cashAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
微信收入:${data.wechatAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
支付宝收入:${data.alipayAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
会员支付:${data.vipPay}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
会员充值:${data.vipRecharge}
|
||||
</div>
|
||||
`;
|
||||
|
||||
let payInfos = "";
|
||||
if (data.payInfos && data.payInfos.length) {
|
||||
for (let item of data.payInfos) {
|
||||
payInfos += `
|
||||
<div style="font-size: 12px;padding-left:20px;">
|
||||
${item.payType}:${item.amount}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
// let payInfos = "";
|
||||
// if (data.payInfos && data.payInfos.length) {
|
||||
// for (let item of data.payInfos) {
|
||||
// payInfos += `
|
||||
// <div style="font-size: 12px;padding-left:20px;">
|
||||
// ${item.payType}:${item.amount}
|
||||
// </div>
|
||||
// `;
|
||||
// }
|
||||
// }
|
||||
|
||||
let memberTitle = `
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
会员数据
|
||||
</div>
|
||||
`;
|
||||
// let memberTitle = `
|
||||
// <div style="font-size: 12px;margin-top: 4px;">
|
||||
// 会员数据
|
||||
// </div>
|
||||
// `;
|
||||
|
||||
let memberData = "";
|
||||
if (data.memberData && data.memberData.length) {
|
||||
for (let item of data.memberData) {
|
||||
memberData += `
|
||||
<div style="font-size: 12px;padding-left:20px;">
|
||||
${item.deposit}:${item.amount}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
// let memberData = "";
|
||||
// if (data.memberData && data.memberData.length) {
|
||||
// for (let item of data.memberData) {
|
||||
// memberData += `
|
||||
// <div style="font-size: 12px;padding-left:20px;">
|
||||
// ${item.deposit}:${item.amount}
|
||||
// </div>
|
||||
// `;
|
||||
// }
|
||||
// }
|
||||
|
||||
let productCategoriesTabHead = `
|
||||
<div style="font-size: 12px;margin-top: 4px;">分类数据</div>
|
||||
@@ -71,8 +86,8 @@ export default (data) => {
|
||||
`;
|
||||
|
||||
let productCategoriesTableBody = "";
|
||||
if (data.productCategories && data.productCategories.length) {
|
||||
for (let item of data.productCategories) {
|
||||
if (data.categoryDataList && data.categoryDataList.length) {
|
||||
for (let item of data.categoryDataList) {
|
||||
productCategoriesTableBody += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:50%;">
|
||||
@@ -98,8 +113,8 @@ export default (data) => {
|
||||
`;
|
||||
|
||||
let tableBody = "";
|
||||
if (data.productInfos && data.productInfos.length) {
|
||||
for (let item of data.productInfos) {
|
||||
if (data.productDataList && data.productDataList.length) {
|
||||
for (let item of data.productDataList) {
|
||||
tableBody += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:75%;">
|
||||
@@ -120,27 +135,23 @@ export default (data) => {
|
||||
</table>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
<span>快捷收款金额:</span>
|
||||
<span>${data.quickAmount}</span>
|
||||
<span>${data.quickInAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>退款金额:</span>
|
||||
<span>${data.returnAmount}</span>
|
||||
<span>${data.refundAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>总收入:</span>
|
||||
<span>${data.totalAmount}</span>
|
||||
<span>${data.handAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>备用金:</span>
|
||||
<span>${data.imprest}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>应交金额:</span>
|
||||
<span>${data.payable}</span>
|
||||
<span>挂账金额:</span>
|
||||
<span>${data.creditAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 20px; font-size: 12px;">
|
||||
<span>总订单数:</span>
|
||||
<span>${data.orderNum}</span>
|
||||
<span>${data.orderCount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
打印时间:${data.printTime}
|
||||
@@ -151,7 +162,9 @@ export default (data) => {
|
||||
<div>.</div>
|
||||
`;
|
||||
|
||||
let lastHtml = `${html}${payInfos}${memberTitle}${memberData}${productCategoriesTabHead}${productCategoriesTableBody}${tabHead}${tableBody}${str}`;
|
||||
// let lastHtml = `${html}${payInfos}${memberTitle}${memberData}${productCategoriesTabHead}${productCategoriesTableBody}${tabHead}${tableBody}${str}`;
|
||||
|
||||
let lastHtml = `${html}${productCategoriesTabHead}${productCategoriesTableBody}${tabHead}${tableBody}${str}`;
|
||||
|
||||
setTimeout(() => {
|
||||
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
|
||||
|
||||
@@ -17,19 +17,14 @@ export default (data) => {
|
||||
let t1 = 40;
|
||||
let t2 = (100 - t1) / 3;
|
||||
let html = `
|
||||
<div style="font-size: 30px;display:flex;justify-content:center;">
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shop_name}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
${data.isBefore ? "预" : ""}结算单【${
|
||||
data.orderInfo.masterId ? data.orderInfo.masterId : ""
|
||||
}】
|
||||
${data.isBefore ? "预" : ""}结算单 #${data.orderInfo.orderNum || ''}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
桌号:${data.orderInfo && data.orderInfo.tableName || ''}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:20px;">
|
||||
${data.orderInfo.outNumber ? data.orderInfo.outNumber : ""}
|
||||
桌号:${data.orderInfo && data.orderInfo.tableName || '无'}
|
||||
</div>
|
||||
<div style="margin-top: 30px;font-size: 12px;">
|
||||
订单号:${data.orderInfo && data.orderInfo.orderNo}
|
||||
@@ -64,7 +59,7 @@ export default (data) => {
|
||||
</tr>
|
||||
`;
|
||||
|
||||
let proGroupInfo = JSON.parse(item.proGroupInfo);
|
||||
let proGroupInfo = item.proGroupInfo;
|
||||
for (let item of proGroupInfo) {
|
||||
table += `
|
||||
<tr>
|
||||
@@ -106,18 +101,18 @@ export default (data) => {
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 12px;display:flex;justify-content: space-between;">
|
||||
<span>原价</span>
|
||||
<span>${data.amount}</span>
|
||||
<span>${data.originAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 12px;display:flex;justify-content: space-between;">
|
||||
<span>折扣</span>
|
||||
<span>-${formatDecimal(data.amount - data.discountAmount)}</span>
|
||||
<span>-${data.discountAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 22px;display:flex;justify-content: space-between;">
|
||||
<span>实付</span>
|
||||
<span>¥${data.discountAmount}</span>
|
||||
<span>¥${data.amount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
|
||||
@@ -13,12 +13,9 @@ export default (data) => {
|
||||
let t1 = 40;
|
||||
let t2 = (100 - t1) / 3;
|
||||
let html = `
|
||||
<div style="font-size: 30px;display:flex;justify-content:center;">
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shop_name}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
退款单【${data.orderInfo.masterId ? data.orderInfo.masterId : ""}】
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
桌号:${data.orderInfo && data.orderInfo.tableName || ''}
|
||||
</div>
|
||||
@@ -80,6 +77,9 @@ export default (data) => {
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 4px; font-size: 16px;font-weight: bold;">备注:${
|
||||
data.remark
|
||||
}</div>
|
||||
<div style="margin-top: 4px; font-size: 12px;">
|
||||
打印时间:${data.printTime}
|
||||
</div>
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
<div class="drawerbox_bo_top">
|
||||
<div class="drawerbox_bo_top_left" @click="computeExpired">
|
||||
<div class="drawerbox_bo_top_left_one" style="font-size: 24px;">
|
||||
{{ store.userInfo.shopName }}
|
||||
{{ store.shopInfo.shopName }}
|
||||
</div>
|
||||
<div class="tips" style="margin-top: 4px; color: var(--el-color-warning);" v-if="!showTips">注意:您的账号将于{{
|
||||
store.userInfo.expireDate }}后过期,请尽快续期!</div>
|
||||
<div class="tips" style="margin-top: 4px; color: var(--el-color-warning);" v-if="showTips">注意:您的账号将于{{
|
||||
store.shopInfo.expireTime }}后过期,请尽快续期!</div>
|
||||
<div class="drawerbox_bo_top_left_tow" style="margin-top: 10px">
|
||||
收银员:{{ store.userInfo.loginAccount }}
|
||||
收银员:{{ store.userInfo.name }}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #666">{{ dayjs(store.userInfo.loginTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
<span style="color: #999">{{ dayjs(store.userInfo.loginTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="drawerbox_bo_top_ring">
|
||||
@@ -32,7 +32,7 @@
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="drawerbox_bo_box">
|
||||
<div style="padding: 10px; color: #999; font-weight: bold">系统</div>
|
||||
<!-- <div style="padding: 10px 0; color: #999; font-weight: bold">系统</div> -->
|
||||
<div class="drawerbox_bo_box_itemb_felx">
|
||||
<!-- <div class="drawerbox_bo_box_itembox">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
@@ -50,22 +50,22 @@
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">设备管理</div>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_itembox" @click="openCallHandle">
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="openCallHandle">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Bell />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">叫号</div>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_itembox" @click="screenref.shows()">
|
||||
</div> -->
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="screenref.shows()">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Lock />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">锁屏</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="to('webview', {
|
||||
url: 'https://cashiernewadmin.sxczgkj.cn/',
|
||||
title: '后台管理'
|
||||
@@ -123,9 +123,11 @@ function computeExpired() {
|
||||
// 当前日期
|
||||
let now = dayjs()
|
||||
// 到期时间
|
||||
let expired = dayjs(store.userInfo.expireDate).subtract(30, 'day')
|
||||
let expired = dayjs(store.userInfo.expireTime).subtract(30, 'day')
|
||||
// 判断当前时间是否大于到期时间30天
|
||||
showTips.value = now.isBefore(expired)
|
||||
|
||||
console.log("computeExpired===", showTips.value);
|
||||
}
|
||||
|
||||
// 打开叫号弹窗
|
||||
@@ -178,7 +180,7 @@ defineExpose({
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-bottom: 1px solid #47484b;
|
||||
|
||||
.drawerbox_bo_top_left {
|
||||
display: flex;
|
||||
@@ -212,12 +214,12 @@ defineExpose({
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
padding: 20px 0;
|
||||
|
||||
.drawerbox_bo_box_itembox {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
|
||||
512
src/components/payCard/couponModal.vue
Normal file
512
src/components/payCard/couponModal.vue
Normal file
@@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" title="选择优惠券" top="12vh" width="80%" @closed="resetHandle">
|
||||
<el-radio-group v-model="querForm.statusActiveIndex" @change="typeChange">
|
||||
<el-radio-button :label="`商品兑换券(${goodsCoupon.length})`" :value="0"></el-radio-button>
|
||||
<el-radio-button :label="`折扣优惠券(${discountCoupon.length})`" :value="1"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<div style="height: 50vh;overflow-y: auto;">
|
||||
<div class="table" v-if="querForm.statusActiveIndex == 0">
|
||||
<div class="title">可用优惠券</div>
|
||||
<el-table ref="tableRef1" :data="list.canUseCoupons" border stripe v-loading="tableData.loading"
|
||||
row-key="id">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="抵扣" prop="discountAmount"></el-table-column>
|
||||
<el-table-column label="限制" prop="fullAmount">
|
||||
<template v-slot="scope">
|
||||
满{{ scope.row.fullAmount }}减{{ scope.row.discountAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="选择" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.selected" :true-value="1" :false-value="0"
|
||||
:disabled="scope.row.disabled" @change="selectCoupon($event, scope.row)"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="title">不可用优惠券</div>
|
||||
<el-table ref="tableRef2" :data="list.noCanUseCoupons" border v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="不可用原因">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.canuseResult.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="table" v-if="querForm.statusActiveIndex == 1">
|
||||
<div class="title">可用优惠券</div>
|
||||
<el-table ref="tableRef1" :data="list.canUseDiscountCoupon" border stripe v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="抵扣" prop="discountAmount"></el-table-column>
|
||||
<el-table-column label="限制" prop="fullAmount">
|
||||
<template v-slot="scope">
|
||||
满{{ scope.row.fullAmount }}减{{ scope.row.discountAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="选择" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.selected" :true-value="1" :false-value="0"
|
||||
:disabled="scope.row.disabled" @change="selectCoupon($event, scope.row)"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="title">不可用优惠券</div>
|
||||
<el-table ref="tableRef2" :data="list.noUseDiscountCoupon" border v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="不可用原因">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.canuseResult.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog_footer">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="selectCouponConfirm">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { findCoupon } from '@/api/account.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { couponUtils } from "ysk-utils";
|
||||
|
||||
const props = defineProps({
|
||||
orderList: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const store = useUser()
|
||||
const goodsStore = useGoods()
|
||||
const tableRef1 = ref(null)
|
||||
const tableRef2 = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const query = ref({
|
||||
type: 1,
|
||||
userId: ''
|
||||
})
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 关闭初始化
|
||||
function resetHandle() {
|
||||
query.value.type = 1
|
||||
tableData.loading = false
|
||||
tableData.list = []
|
||||
}
|
||||
|
||||
function typeChange() {
|
||||
tableData.loading = false
|
||||
// tableData.list = []
|
||||
list.canUseCoupons = []
|
||||
list.noCanUseCoupons = []
|
||||
list.canUseDiscountCoupon = []
|
||||
list.noUseDiscountCoupon = []
|
||||
findCouponAjax()
|
||||
// if (query.type == 2) {
|
||||
// tableRef2.value.clearSelection()
|
||||
// }
|
||||
}
|
||||
|
||||
function groupByPropertyAndCount(arr, property) {
|
||||
// 创建一个空对象来存储每个属性值对应的数量
|
||||
const propertyMap = {};
|
||||
|
||||
// 遍历原始数组
|
||||
arr.forEach(item => {
|
||||
const key = item[property];
|
||||
const num = item.number || 1;
|
||||
if (!propertyMap[key]) {
|
||||
// 如果该属性值还没有在 propertyMap 中,初始化一个对象
|
||||
propertyMap[key] = {
|
||||
value: item[property],
|
||||
count: num
|
||||
};
|
||||
} else {
|
||||
// 如果该属性值已经存在,增加数量
|
||||
propertyMap[key].count += num;
|
||||
}
|
||||
});
|
||||
|
||||
// 将 propertyMap 中的结果转换为数组
|
||||
return Object.values(propertyMap);
|
||||
}
|
||||
|
||||
// 选择优惠券
|
||||
const goodsCoupon = ref([]) // 商品券
|
||||
const discountCoupon = ref([]) // 其他优惠券
|
||||
function selectCoupon($event, e) {
|
||||
console.log($event);
|
||||
console.log(e);
|
||||
if (querForm.value.statusActiveIndex == 0) {
|
||||
goodsCoupon.value = []
|
||||
if ($event) {
|
||||
goodsCoupon.value.push(e)
|
||||
list.canUseCoupons.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
list.canUseCoupons.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
discountCoupon.value = []
|
||||
if ($event) {
|
||||
discountCoupon.value.push(e)
|
||||
list.canUseDiscountCoupon.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
list.canUseDiscountCoupon.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
updateSelCoupon()
|
||||
console.log('goodsStore.cartInfo===', goodsStore.cartInfo);
|
||||
}
|
||||
|
||||
let orderPrice = ref(goodsStore.cartInfo.costSummary.goodsRealAmount);
|
||||
function updateSelCoupon() {
|
||||
const newval = [...goodsCoupon.value, ...discountCoupon.value];
|
||||
|
||||
const user = goodsStore.vipUserInfo;
|
||||
let shopInfo = store.shopInfo;
|
||||
|
||||
if (!shopInfo.isMemberPrice) {
|
||||
shopInfo = {};
|
||||
}
|
||||
|
||||
console.log('updateSelCoupon.user', user);
|
||||
console.log('updateSelCoupon.shopInfo', shopInfo);
|
||||
|
||||
const canDikouGoodsArr = couponUtils.returnCanDikouGoods(goodsStore.cartInfo.allGoods, [], user);
|
||||
|
||||
if (newval.length >= 2) {
|
||||
let goodsCoupon = newval.filter((v) => v.type == 2);
|
||||
let otherCoupon = newval.filter((v) => v.type != 2);
|
||||
goodsCoupon = goodsCoupon.map((v) => {
|
||||
const discount = couponUtils.returnCouponDiscount(
|
||||
canDikouGoodsArr,
|
||||
v,
|
||||
user,
|
||||
orderPrice.value,
|
||||
[],
|
||||
shopInfo,
|
||||
goodsStore.limitDiscountRes
|
||||
);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount,
|
||||
};
|
||||
});
|
||||
otherCoupon = otherCoupon.map((v) => {
|
||||
const canuseResult = couponUtils.returnCouponCanUse({
|
||||
canDikouGoodsArr,
|
||||
coupon: v,
|
||||
orderPrice: orderPrice.value,
|
||||
user: user,
|
||||
selCoupon: goodsCoupon,
|
||||
shopInfo: shopInfo,
|
||||
limitTimeDiscount: goodsStore.limitDiscountRes
|
||||
});
|
||||
|
||||
const discount = couponUtils.returnCouponDiscount(
|
||||
canDikouGoodsArr,
|
||||
v,
|
||||
user,
|
||||
orderPrice.value,
|
||||
goodsCoupon,
|
||||
shopInfo,
|
||||
goodsStore.limitDiscountRes
|
||||
);
|
||||
return {
|
||||
...v,
|
||||
canuseResult,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount,
|
||||
};
|
||||
});
|
||||
if (!otherCoupon[0].canuseResult.canUse) {
|
||||
ElMessage.warning('已为您自动剔除叠加不可用的优惠券')
|
||||
discountCoupon.value = [];
|
||||
goodsCoupon.value = goodsCoupon;
|
||||
return;
|
||||
}
|
||||
goodsCoupon.value = goodsCoupon;
|
||||
discountCoupon.value = otherCoupon;
|
||||
}
|
||||
}
|
||||
|
||||
// 确认选择优惠券,然后关闭弹窗
|
||||
function selectCouponConfirm() {
|
||||
updateSelCoupon();
|
||||
|
||||
let ngoodsCoupon = goodsCoupon.value.filter(item => item.discountAmount > 0)
|
||||
let ndiscountCoupon = discountCoupon.value.filter(item => item.discountAmount > 0)
|
||||
|
||||
if (ngoodsCoupon.length != goodsCoupon.value.length || ndiscountCoupon.length != discountCoupon.value.length) {
|
||||
ElMessage.warning('已为您自动剔除叠加不可用的优惠券')
|
||||
}
|
||||
|
||||
console.log('ngoodsCoupon', ngoodsCoupon);
|
||||
console.log('ndiscountCoupon', ndiscountCoupon);
|
||||
|
||||
const data = [...ngoodsCoupon, ...ndiscountCoupon]
|
||||
|
||||
console.log(data);
|
||||
|
||||
// return
|
||||
emits('success', data)
|
||||
goodsCoupon.value = []
|
||||
discountCoupon.value = []
|
||||
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
const querForm = ref({
|
||||
searchValue: '',
|
||||
shopId: '',
|
||||
shopName: '',
|
||||
statusActiveIndex: 0
|
||||
});
|
||||
|
||||
const list = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
status: 'nomore',
|
||||
data: [],
|
||||
noCanUseCoupons: [],
|
||||
canUseCoupons: [],
|
||||
noUseDiscountCoupon: [],
|
||||
canUseDiscountCoupon: []
|
||||
});
|
||||
|
||||
const couponSel = ref({
|
||||
id: ''
|
||||
});
|
||||
const goodsCouponSel = ref({
|
||||
id: ''
|
||||
});
|
||||
const quansSelArr = computed(() => {
|
||||
return [couponSel.value, goodsCouponSel.value].filter((v) => v.id);
|
||||
});
|
||||
|
||||
// 格式化优惠券
|
||||
function formatCoupon() {
|
||||
let canUseGoodsCoupon = [];
|
||||
let canUseDiscountCoupon = [];
|
||||
|
||||
let noUseGoodsCoupon = [];
|
||||
let noUseDiscountCoupon = [];
|
||||
const user = goodsStore.vipUserInfo;
|
||||
let shopInfo = store.shopInfo;
|
||||
if (!shopInfo.isMemberPrice) {
|
||||
shopInfo = {};
|
||||
}
|
||||
const goodsOrderPrice = goodsStore.cartInfo.costSummary.goodsRealAmount;
|
||||
|
||||
console.log('goodsOrderPrice==========', goodsOrderPrice);
|
||||
|
||||
|
||||
const canDikouGoodsArr = couponUtils.returnCanDikouGoods(goodsStore.cartInfo.allGoods, user, shopInfo);
|
||||
for (let i = 0; i < couponList.value.length; i++) {
|
||||
const coupon = couponList.value[i];
|
||||
const canuseResult = couponUtils.returnCouponCanUse({
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
goodsOrderPrice,
|
||||
user,
|
||||
selCoupon: quansSelArr.value,
|
||||
shopInfo,
|
||||
limitTimeDiscount: goodsStore.limitDiscountRes
|
||||
});
|
||||
const { canUse, reason } = canuseResult;
|
||||
if (coupon.type == 2) {
|
||||
if (canUse || goodsCouponSel.value.id == coupon.id) {
|
||||
canUseGoodsCoupon.push(coupon);
|
||||
} else {
|
||||
noUseGoodsCoupon.push({
|
||||
...coupon,
|
||||
canuseResult
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (canUse || couponSel.value.id == coupon.id) {
|
||||
canUseDiscountCoupon.push(coupon);
|
||||
} else {
|
||||
noUseDiscountCoupon.push({
|
||||
...coupon,
|
||||
canuseResult
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
//商品券
|
||||
canUseGoodsCoupon = canUseGoodsCoupon.map((v) => {
|
||||
const discount = couponUtils.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo, goodsStore.limitDiscountRes);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount
|
||||
};
|
||||
});
|
||||
//非商品券
|
||||
canUseDiscountCoupon = canUseDiscountCoupon.map((v) => {
|
||||
const discount = couponUtils.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo, goodsStore.limitDiscountRes);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount
|
||||
};
|
||||
});
|
||||
|
||||
if (querForm.value.statusActiveIndex == 0) {
|
||||
list.noCanUseCoupons = noUseGoodsCoupon;
|
||||
|
||||
canUseGoodsCoupon.map(item => {
|
||||
item.selected = false
|
||||
item.disabled = false
|
||||
})
|
||||
|
||||
list.canUseCoupons = canUseGoodsCoupon;
|
||||
} else {
|
||||
list.noUseDiscountCoupon = noUseDiscountCoupon;
|
||||
|
||||
canUseDiscountCoupon.map(item => {
|
||||
item.selected = false
|
||||
item.disabled = false
|
||||
})
|
||||
|
||||
list.canUseDiscountCoupon = canUseDiscountCoupon;
|
||||
}
|
||||
|
||||
console.log('canUseGoodsCoupon', canUseGoodsCoupon);
|
||||
console.log('noUseGoodsCoupon', noUseGoodsCoupon);
|
||||
console.log('canUseDiscountCoupon', canUseDiscountCoupon);
|
||||
console.log('noUseDiscountCoupon', noUseDiscountCoupon);
|
||||
|
||||
console.log('list===', list);
|
||||
}
|
||||
|
||||
// 获取用户可用的优惠券
|
||||
const couponList = ref([])
|
||||
async function findCouponAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await findCoupon({
|
||||
shopUserId: query.value.userId
|
||||
})
|
||||
couponList.value = res
|
||||
formatCoupon()
|
||||
// if (query.value.type == 1) {
|
||||
// tableData.list = res
|
||||
// } else {
|
||||
// let arr = []
|
||||
// let ids = props.orderList.map(item => item.product_id)
|
||||
// res && res.map((item, index) => {
|
||||
|
||||
// let found = ids.find(val => val == item.proId)
|
||||
// let result = found !== undefined
|
||||
|
||||
// if (result) {
|
||||
// let pro = props.orderList.find(val => val.product_id == item.proId)
|
||||
|
||||
// console.log('pro===', pro);
|
||||
|
||||
// let discount = pro.lowPrice
|
||||
|
||||
// if (goodsStore.showVipPrice) {
|
||||
// discount = pro.memberPrice
|
||||
// }
|
||||
|
||||
// if (+pro.discount_sale_amount) {
|
||||
// discount = pro.discount_sale_amount
|
||||
// }
|
||||
|
||||
// arr.push({
|
||||
// ...item,
|
||||
// productName: pro.productName,
|
||||
// lowPrice: pro.lowPrice,
|
||||
// discount: discount
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// tableData.list = arr
|
||||
|
||||
// console.log('tableData.list===', tableData.list);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
tableData.loading = false
|
||||
}
|
||||
|
||||
async function show(userId) {
|
||||
showDialog.value = true
|
||||
query.value.userId = userId
|
||||
await findCouponAjax()
|
||||
console.log('couponModal.orderList===', props.orderList);
|
||||
// updateSelCoupon()
|
||||
// formatCoupon()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog_footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 20px 0 10px 0;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
<!-- 扫码弹窗 -->
|
||||
|
||||
<template>
|
||||
<div class="dialog">
|
||||
<el-dialog title="扫码支付" width="600" v-model="dialogVisible" @open="reset" @close="clearAutoCheckOrder">
|
||||
<el-dialog title="扫码支付" width="600" v-model="dialogVisible" :close-on-click-modal="false" :show-close="!userPayWait"
|
||||
@open="reset" @closed="resetScanCode">
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<el-image :src="icon" style="width: 60px; height: 60px"></el-image>
|
||||
@@ -10,11 +10,12 @@
|
||||
<div class="right" v-if="!userPayWait">
|
||||
<div class="amount">
|
||||
<span class="t">扫码支付</span>
|
||||
<span class="n">{{ props.money }}</span>
|
||||
<span class="n">{{ goodsStore.cartInfo.costSummary.finalPayAmount }}</span>
|
||||
</div>
|
||||
<div class="input">
|
||||
<el-input ref="inputRef" v-model="scanCode" style="height: calc(var(--el-component-size-large) + 30px)"
|
||||
placeholder="请扫描付款码" clearable @change="inputChange"></el-input>
|
||||
<el-input ref="inputRef" v-model="scanCode" :maxlength="18"
|
||||
style="height: calc(var(--el-component-size-large) + 30px)" placeholder="请扫描付款码" clearable
|
||||
@change="inputChange"></el-input>
|
||||
<div class="tips">注意:扫码支付请保证输入框获得焦点,输入内容结束后会自动支付,请勿重复操作</div>
|
||||
</div>
|
||||
<!-- <div class="number_warp">
|
||||
@@ -28,20 +29,23 @@
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" v-loading="loading">立即支付</el-button>
|
||||
<el-button type="primary" style="width: 100%" v-loading="loading" @click="submitHandle">
|
||||
立即支付
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_wait" v-else>
|
||||
<div class="loading" v-loading="loading" element-loading-text="用户支付中..."></div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" v-loading="checkPayStatusLoading" @click="checkPayStauts">
|
||||
<span v-if="!checkPayStatusLoading">查询用户支付状态</span>
|
||||
<span v-else>查询中...</span>
|
||||
<el-button style="width: 100%" :disabled="!closeState" type="primary" @click="resetScanCode">
|
||||
<span v-if="!closeState">{{ closeStateTime }}秒后可重新扫码</span>
|
||||
<span v-else>重新扫码</span>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%" @click="resetScanCode">
|
||||
重新扫码
|
||||
<el-button style="width: 100%" :disabled="!closeState" @click="closeScanCode">
|
||||
<span v-if="!closeState">{{ closeStateTime }}秒后可关闭</span>
|
||||
<span v-else>关闭</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,28 +56,26 @@
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ref } from "vue";
|
||||
import icon from "@/assets/icon_scan.png";
|
||||
import { scanpay, queryOrder, quickPay, queryQuickPayStatus, accountPay, queryScanPay } from "@/api/pay";
|
||||
import { quickPay, queryQuickPayStatus, accountPay } from "@/api/pay";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { formatDecimal } from '@/utils'
|
||||
const store = useUser();
|
||||
const global = useGlobal()
|
||||
import {
|
||||
queryMembermember,
|
||||
createMembermember,
|
||||
membermemberScanPay,
|
||||
accountPaymember,
|
||||
} from "@/api/member/index.js";
|
||||
import { microPay, queryOrderStatus, microPayVip, vipPay, queryPayStatus } from '@/api/order.js'
|
||||
import { ElMessage } from "element-plus";
|
||||
const emits = defineEmits(["success"]);
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
const goodsStore = useGoods();
|
||||
|
||||
const store = useUser();
|
||||
const emits = defineEmits(["success", 'orderExpired']);
|
||||
|
||||
const props = defineProps({
|
||||
amount: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 0 订单支付 1 会员充值 2 快捷收款
|
||||
selecttype: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
@@ -86,6 +88,7 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 支付类型
|
||||
payType: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
@@ -93,6 +96,14 @@ const props = defineProps({
|
||||
money: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
payData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
chargeId: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
}
|
||||
});
|
||||
|
||||
@@ -102,25 +113,54 @@ const inputRef = ref(null);
|
||||
|
||||
const loading = ref(false);
|
||||
const userPayWait = ref(false);
|
||||
const checkPayStatusLoading = ref(false);
|
||||
|
||||
const fastOrder = ref('')
|
||||
|
||||
const submitHandle = _.throttle(submitHandleAjax, 200);
|
||||
const table_code = ref('')
|
||||
|
||||
// 提交扫码支付
|
||||
async function submitHandle() {
|
||||
async function submitHandleAjax() {
|
||||
// console.log('props.selecttype===', props.selecttype);
|
||||
try {
|
||||
if (!scanCode.value) return;
|
||||
if (!scanCode.value || scanCode.value.length > 18) return;
|
||||
loading.value = true;
|
||||
if (props.selecttype == 1) {
|
||||
await membermemberScanPay({
|
||||
shopId: store.userInfo.shopId,
|
||||
memberId: props.orderId,
|
||||
|
||||
console.log('props.selecttype===', props.selecttype);
|
||||
console.log('props.payType===', props.payType);
|
||||
|
||||
// return;
|
||||
|
||||
// 判断订单是否锁定
|
||||
await goodsStore.isOrderLock({
|
||||
table_code: goodsStore.orderListInfo.tableCode
|
||||
})
|
||||
|
||||
if (props.selecttype == 0) {
|
||||
// 下单扫码支付
|
||||
if (props.payType == 'scanCode') {
|
||||
await microPay({
|
||||
...props.payData,
|
||||
authCode: scanCode.value
|
||||
});
|
||||
} else if (props.payType == 'deposit') {
|
||||
await vipPay({
|
||||
...props.payData,
|
||||
payType: 'scanCode',
|
||||
authCode: scanCode.value
|
||||
});
|
||||
}
|
||||
} else if (props.selecttype == 1) {
|
||||
// 会员扫码充值
|
||||
await microPayVip({
|
||||
shopId: store.shopInfo.id,
|
||||
shopUserId: props.orderId,
|
||||
amount: props.amount,
|
||||
authCode: scanCode.value,
|
||||
// payAmount: props.money < props.amount ? props.money : '',
|
||||
// discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
});
|
||||
rechargeDetailId: props.chargeId,
|
||||
})
|
||||
} else {
|
||||
// 快捷收银
|
||||
if (props.fast) {
|
||||
await quickPay({
|
||||
amount: props.amount,
|
||||
@@ -129,12 +169,11 @@ async function submitHandle() {
|
||||
});
|
||||
} else {
|
||||
if (props.payType == 'scanCode') {
|
||||
await scanpay({
|
||||
orderId: props.orderId,
|
||||
authCode: scanCode.value,
|
||||
payAmount: props.money < props.amount ? props.money : '',
|
||||
discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
});
|
||||
if (props.selecttype == 1) {
|
||||
|
||||
} else if (props.selecttype == 2) {
|
||||
|
||||
}
|
||||
}
|
||||
if (props.payType == 'deposit') {
|
||||
await accountPay({
|
||||
@@ -147,18 +186,24 @@ async function submitHandle() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
ElMessage.success("支付成功");
|
||||
dialogVisible.value = false;
|
||||
emits("success");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (error.code === "100015") {
|
||||
if (error.code === 211) {
|
||||
// 开始锁单
|
||||
goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_lock')
|
||||
|
||||
userPayWait.value = true;
|
||||
fastOrder.value = error.data
|
||||
autoCheckOrder()
|
||||
} else if (error.code == 701) {
|
||||
// 订单已过期需刷新购物车和订单
|
||||
emits('orderExpired')
|
||||
} else {
|
||||
scanCode.value = "";
|
||||
loading.value = false;
|
||||
@@ -167,21 +212,37 @@ async function submitHandle() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const timer = ref(null)
|
||||
// 自动查询订单状态
|
||||
function autoCheckOrder() {
|
||||
timer.value = setInterval(() => {
|
||||
checkPayStauts(false)
|
||||
}, 2000)
|
||||
// 关闭扫码支付
|
||||
function closeScanCode() {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
// 清除自动查询扫码支付订单
|
||||
function clearAutoCheckOrder() {
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
// 开启叫号功能
|
||||
global.updateData(true)
|
||||
const closeState = ref(false)
|
||||
const closeStateTime = ref(5);
|
||||
const closeStateTimer = ref(null)
|
||||
|
||||
function closeStateTimerFuc() {
|
||||
closeStateTimer.value = setInterval(() => {
|
||||
closeStateTime.value--
|
||||
if (closeStateTime.value <= 0) {
|
||||
clearInterval(closeStateTimer.value)
|
||||
closeStateTimer.value = null
|
||||
closeState.value = true
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 自动查询订单状态
|
||||
const timer = ref(null)
|
||||
function autoCheckOrder() {
|
||||
closeStateTimerFuc()
|
||||
timer.value = setInterval(() => {
|
||||
// 开始锁单
|
||||
goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_lock')
|
||||
checkPayStauts(false)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// 查询用户支付状态
|
||||
@@ -189,8 +250,11 @@ async function checkPayStauts(tips = true) {
|
||||
try {
|
||||
if (props.selecttype == 1) {
|
||||
// 会员扫码充值
|
||||
const res = await queryScanPay({ flowId: fastOrder.value.id });
|
||||
if (res.status == 0) {
|
||||
const res = await queryPayStatus({
|
||||
shopId: store.shopInfo.id,
|
||||
payOrderNo: fastOrder.value.payOrderNo,
|
||||
});
|
||||
if (res == 'TRADE_SUCCESS') {
|
||||
userPayWait.value = false
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
@@ -199,8 +263,7 @@ async function checkPayStauts(tips = true) {
|
||||
clearAutoCheckOrder()
|
||||
emits("success");
|
||||
return;
|
||||
}
|
||||
if (res.status == 7) {
|
||||
} else if (res == 'TRADE_AWAIT') {
|
||||
if (tips) {
|
||||
ElMessage.warning("用户支付中...");
|
||||
}
|
||||
@@ -237,25 +300,29 @@ async function checkPayStauts(tips = true) {
|
||||
}
|
||||
} else {
|
||||
// 扫码下单
|
||||
const res = await queryOrder({ orderId: props.orderId });
|
||||
if (res.status == "closed") {
|
||||
const res = await queryOrderStatus({ orderId: props.payData.checkOrderPay.orderId });
|
||||
if (res == "done") {
|
||||
// 支付成功,解锁订单
|
||||
await goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_unlock')
|
||||
|
||||
userPayWait.value = false
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
ElMessage.success("支付成功");
|
||||
dialogVisible.value = false;
|
||||
clearAutoCheckOrder()
|
||||
emits("success");
|
||||
return;
|
||||
}
|
||||
if (res.status == "paying") {
|
||||
if (res == "unpaid") {
|
||||
if (tips) {
|
||||
ElMessage.warning("用户支付中...");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
clearAutoCheckOrder()
|
||||
ElMessage.error(res.payRemark || "支付失败!");
|
||||
ElMessage.warning(res.msg || '');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -265,13 +332,23 @@ async function checkPayStauts(tips = true) {
|
||||
}
|
||||
}
|
||||
|
||||
function clearAutoCheckOrder() {
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
}
|
||||
|
||||
// 重新扫码
|
||||
function resetScanCode() {
|
||||
clearAutoCheckOrder()
|
||||
userPayWait.value = false;
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
inputRef.value.focus();
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
|
||||
clearInterval(closeStateTimer.value)
|
||||
closeStateTimer.value = null
|
||||
|
||||
reset()
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// 输入
|
||||
@@ -293,12 +370,12 @@ function delHandle() {
|
||||
// }
|
||||
|
||||
const inputChange = _.debounce(function (e) {
|
||||
// console.log(e);
|
||||
submitHandle();
|
||||
}, 100);
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
table_code.value = goodsStore.orderListInfo.tableCode
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500);
|
||||
@@ -309,10 +386,16 @@ function close() {
|
||||
}
|
||||
|
||||
function reset() {
|
||||
userPayWait.value = false;
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
// 关闭叫号功能
|
||||
global.updateData(false)
|
||||
closeState.value = false
|
||||
closeStateTime.value = 5
|
||||
|
||||
// 关闭锁单
|
||||
// goodsStore.isOrderLock({
|
||||
// table_code: table_code.value
|
||||
// }, 'pay_unlock')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
144
src/components/selectVipUser.vue
Normal file
144
src/components/selectVipUser.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<el-dialog title="选择用户" top="3vh" v-model="showDialog" width="80%">
|
||||
<el-form inline>
|
||||
<el-form-item>
|
||||
<el-input placeholder="请输入手机号搜索用户" v-model="tableData.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select v-model="tableData.isVips" placeholder="是否为会员" style="width: 150px;" @change="changeIsVips">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="是" :value="1"></el-option>
|
||||
<el-option label="否" :value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getMemberList">搜索</el-button>
|
||||
<el-button @click="resetTable">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="tableData.list" height="400px" border stripe v-loading="tableData.loading">
|
||||
<el-table-column prop="nickName" label="昵称" width="200px">
|
||||
<template #default="scope">
|
||||
<div class="center">
|
||||
<el-avatar :src="scope.row.headImg" :size="20"></el-avatar>
|
||||
<span>{{ scope.row.nickName }}</span>
|
||||
<el-tag type="success" size="small" disable-transitions v-if="scope.row.new">新</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="手机" width="150px" />
|
||||
<!-- <el-table-column prop="code" label="编号" width="150px" /> -->
|
||||
<el-table-column prop="level" label="等级">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.isVip">
|
||||
<span v-if="scope.row.memberLevelName">
|
||||
{{ scope.row.memberLevelName }}
|
||||
</span>
|
||||
<span v-else>是</span>
|
||||
</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="accountPoints" label="积分" />
|
||||
<el-table-column prop="amount" label="余额" width="120px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.amount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120px" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" @click="toHomeMember(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination layout="prev, pager, next, total" background style="margin-top: 20px;"
|
||||
:total="Number(tableData.total)" v-model:current-page="tableData.page" @current-change="getMemberList" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { shopUserList } from "@/api/account.js";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
amount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
const showDialog = ref(false)
|
||||
const tableData = reactive({
|
||||
phone: '',
|
||||
isVips: "",
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 选择会员去下单
|
||||
async function toHomeMember(row) {
|
||||
try {
|
||||
emits('success', { ...row })
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
// 重置表格
|
||||
function resetTable() {
|
||||
tableData.phone = ''
|
||||
tableData.isVips = ''
|
||||
tableData.page = 1
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
function changeIsVips() {
|
||||
tableData.page = 1
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
// 获取会员列表
|
||||
async function getMemberList() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await shopUserList({
|
||||
key: tableData.phone,
|
||||
isVips: tableData.isVips,
|
||||
page: tableData.page,
|
||||
size: tableData.size,
|
||||
amount: props.amount
|
||||
})
|
||||
tableData.list = res.records
|
||||
tableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
tableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 显示选择会员弹窗
|
||||
function show() {
|
||||
showDialog.value = true
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog :title="goods.name" width="600" v-model="dialogVisible">
|
||||
<el-dialog :title="goods.name" width="600" v-model="dialogVisible" top="5vh">
|
||||
<div class="header">选择规格</div>
|
||||
<div v-loading="loading">
|
||||
<div class="row" v-for="(item, index) in goods.selectSpec" :key="index">
|
||||
@@ -14,18 +14,30 @@
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="info">
|
||||
<template v-if="goodsInfo.id">
|
||||
<span>库存:{{ goodsInfo.stockNumber }}</span>
|
||||
<span>¥{{ goodsInfo.salePrice }}</span>
|
||||
</template>
|
||||
<div class="price" v-if="goodsInfo.id">
|
||||
<span class="i">¥</span>
|
||||
<span class="n">{{ formatDecimal(+goodsInfo.salePrice) }}</span>
|
||||
</div>
|
||||
<span>库存:{{ stockNumber }}</span>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%;" @click="dialogVisible = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :disabled="!goodsInfo.id"
|
||||
@click="submitSku">确认</el-button>
|
||||
<el-button type="primary" style="width: 100%;"
|
||||
:disabled="!goodsInfo.id || !+goodsInfo.isGrounding || !!+goodsInfo.isSoldStock"
|
||||
@click="submitSku">
|
||||
<template v-if="goodsInfo.id && !+goodsInfo.isGrounding">
|
||||
未上架
|
||||
</template>
|
||||
<template v-if="goodsInfo.id && +goodsInfo.isSoldStock">
|
||||
已售罄
|
||||
</template>
|
||||
<template v-if="(+goodsInfo.isGrounding && !+goodsInfo.isPauseSale) || !goodsInfo.id">
|
||||
确认
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,52 +46,47 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { queryProductSku } from '@/api/product'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const store = useUser();
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const type = ref('shop')
|
||||
const dialogVisible = ref(false)
|
||||
const goods = ref({})
|
||||
|
||||
const selectedSkuNum = ref(0)
|
||||
const selectedSkuTag = ref('')
|
||||
|
||||
const goodsInfo = ref({})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const selecSkuArray = ref([])
|
||||
const stockNumber = ref(0)
|
||||
|
||||
// 确认选择规格
|
||||
function submitSku() {
|
||||
dialogVisible.value = false
|
||||
switch (type.value) {
|
||||
case 'shop':
|
||||
emit('success', goodsInfo.value)
|
||||
break;
|
||||
case 'cart':
|
||||
emit('success', goods.value)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// switch (type.value) {
|
||||
// case 'shop':
|
||||
// break;
|
||||
// case 'cart':
|
||||
// emit('success', goodsInfo.value)
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
emit('success', goodsInfo.value)
|
||||
}
|
||||
|
||||
// 选择规格
|
||||
function selectedSku(index = 0, i = 0) {
|
||||
goodsInfo.value = {}
|
||||
|
||||
goods.value.selectSpec[index].selectSpecResult.map(item => {
|
||||
item.active = false
|
||||
})
|
||||
|
||||
|
||||
if (index == 0) {
|
||||
selecSkuArray.value = []
|
||||
}
|
||||
|
||||
|
||||
if (selecSkuArray.value.length - 1 > index) {
|
||||
// console.log(selecSkuArray.value.length - 1);
|
||||
// console.log(index);
|
||||
@@ -90,21 +97,20 @@ function selectedSku(index = 0, i = 0) {
|
||||
|
||||
if (index < goods.value.selectSpec.length - 1) {
|
||||
selectedSkuNum.value = 0
|
||||
goods.value.selectSpec.map((item, idx) => {
|
||||
if (index < idx) {
|
||||
item.selectSpecResult.map(val => {
|
||||
val.disabled = true
|
||||
val.active = false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// goods.value.selectSpec.map((item, idx) => {
|
||||
// if (index < idx) {
|
||||
// item.selectSpecResult.map(val => {
|
||||
// val.disabled = true
|
||||
// val.active = false
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
goods.value.selectSpec[index + 1].selectSpecResult.map(item => {
|
||||
goods.value.groundingSpecInfo.map(val => {
|
||||
goods.value.skuList.map(val => {
|
||||
// console.log(val);
|
||||
// console.log(`${selecSkuArray.value.join(',')},${item.name}`);
|
||||
// console.log(val.specSnap.indexOf(`${selecSkuArray.value.join(',')},${item.name}`));
|
||||
if (val.specSnap.indexOf(`${selecSkuArray.value.join(',')},${item.name}`) != -1 && val.isGrounding) {
|
||||
// console.log(val.specInfo.indexOf(`${selecSkuArray.value.join(',')},${item.name}`));
|
||||
if (val.specInfo.indexOf(`${selecSkuArray.value.join(',')},${item.name}`) != -1 && val.isGrounding) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
@@ -147,80 +153,64 @@ function selectedSuccess() {
|
||||
|
||||
// 通过选中的商品规格查询价格
|
||||
async function queryProductSkuAjax() {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await queryProductSku({
|
||||
shopId: store.userInfo.shopId,
|
||||
productId: type.value == 'shop' ? goods.value.id : goods.value.productId,
|
||||
spec_tag: selectedSkuTag.value
|
||||
})
|
||||
goodsInfo.value = res
|
||||
if (type.value == 'cart') {
|
||||
goods.value.skuId = res.id
|
||||
goods.value.skuList.map(item => {
|
||||
if (item.specInfo == selectedSkuTag.value) {
|
||||
goodsInfo.value = item
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 100)
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('goodsInfo.value===', goodsInfo.value);
|
||||
}
|
||||
|
||||
// 显示规格
|
||||
function show(item, t = 'shop') {
|
||||
stockNumber.value = item.stockNumber
|
||||
type.value = t
|
||||
let arr = []
|
||||
for (let val in item.selectSpecInfo) {
|
||||
if (item.selectSpecInfo[val].length) {
|
||||
switch (type.value) {
|
||||
case 'shop':
|
||||
arr.push({
|
||||
name: val,
|
||||
selectSpecResult: item.selectSpecInfo[val].map(item => {
|
||||
return {
|
||||
active: false,
|
||||
name: item,
|
||||
disabled: false
|
||||
}
|
||||
})
|
||||
})
|
||||
break;
|
||||
case 'cart':
|
||||
// 如果从购物车选择规格需要做选中效果
|
||||
const skus = item.sku_name.split(',')
|
||||
arr.push({
|
||||
name: val,
|
||||
selectSpecResult: item.selectSpecInfo[val].map(item => {
|
||||
return {
|
||||
active: !!skus.find(val => val === item),
|
||||
name: item,
|
||||
disabled: false
|
||||
}
|
||||
})
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item.selectSpec = arr
|
||||
|
||||
// 赋值新的规格数据
|
||||
goodsInfo.value = {}
|
||||
goods.value = {}
|
||||
selectedSkuNum.value = 0
|
||||
dialogVisible.value = true
|
||||
goods.value = ""
|
||||
goods.value = item
|
||||
type.value = t
|
||||
goods.value.selectSpec = JSON.parse(goods.value.selectSpec)
|
||||
goods.value.selectSpec.map((item, index) => {
|
||||
let arr = []
|
||||
item.selectSpecResult.map(val => {
|
||||
switch (type.value) {
|
||||
case 'shop':
|
||||
let disabled = true
|
||||
if (index == 0) {
|
||||
goods.value.groundingSpecInfo.map(item => {
|
||||
if (item.specSnap.indexOf(val) != -1 && item.isGrounding) {
|
||||
disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
arr.push({
|
||||
active: false,
|
||||
name: val,
|
||||
disabled: index == 0 ? disabled : true
|
||||
})
|
||||
break;
|
||||
case 'cart':
|
||||
// 如果从购物车选择规格需要做选中效果
|
||||
const skus = goods.value.skuName.split(',')
|
||||
arr.push({
|
||||
active: !!skus.find(item => item === val),
|
||||
name: val,
|
||||
disabled: true
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
item.selectSpecResult = arr
|
||||
})
|
||||
|
||||
let arr = []
|
||||
|
||||
goods.value.selectSpec.map(item => {
|
||||
if (item.selectSpecResult.length) {
|
||||
arr.push({ ...item })
|
||||
}
|
||||
})
|
||||
|
||||
goods.value.selectSpec = arr
|
||||
|
||||
selectedSuccess()
|
||||
}
|
||||
@@ -261,6 +251,24 @@ defineExpose({
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 20px;
|
||||
|
||||
.price {
|
||||
color: var(--el-color-danger);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
|
||||
.i {
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.n {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn_wrap {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle(item)">{{ item }}</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button plain type="info" disabled style="width: 100%">.</el-button>
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle('.')">.</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle(0)">0</el-button>
|
||||
@@ -17,7 +17,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">确认</el-button>
|
||||
<el-button type="primary" style="width: 100%" :disabled="number <= 0" :loading="loading"
|
||||
@click="confirmHandle">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -25,6 +26,7 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { clearNoNum } from '@/utils/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
@@ -61,6 +63,7 @@ function opne() {
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
number.value += n;
|
||||
number.value = clearNoNum({ value: number.value })
|
||||
}
|
||||
|
||||
// 删除
|
||||
@@ -72,7 +75,7 @@ function delHandle() {
|
||||
const loading = ref(false)
|
||||
// 确认
|
||||
function confirmHandle() {
|
||||
if (!number.value) return
|
||||
if (!number.value || number.value <= 0) return
|
||||
if (props.type == 2) {
|
||||
if (number.value.length < 6) {
|
||||
ElMessage.error('请输入正确的密码')
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" title="发现新版本" width="500" :close-on-click-modal="false"
|
||||
<el-dialog v-model="showDialog" :title="`发现新版本v${newVersionRef}`" top="30vh" width="500" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" :show-close="false">
|
||||
<div class="message">
|
||||
{{ updataInfo.message }}
|
||||
</div>
|
||||
<div class="message" v-html="updataInfo.message"></div>
|
||||
<div class="progress_wrap" style="padding-top: 20px;">
|
||||
<el-progress :percentage="uploadPro" :stroke-width="15" striped :striped-flow="uploadPro < 100" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="footer" style="padding: 0 20px 20px;">
|
||||
<el-button v-if="!updataInfo.isUp && !isUpload" @click="closeHandle">下次更新</el-button>
|
||||
<el-button v-if="!updataInfo.isForce && !isUpload" @click="closeHandle">下次更新</el-button>
|
||||
<el-button type="primary" :loading="isUpload" @click="uplaodHandle">
|
||||
<template v-if="!uploadSucess">
|
||||
<template v-if="!isUpload">
|
||||
@@ -30,7 +28,7 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { findVersion } from '@/api/user.js'
|
||||
import { findVersion } from '@/api/system.js'
|
||||
import packageData from "../../package.json";
|
||||
import { ipcRenderer } from 'electron'
|
||||
import useStorage from '@/utils/useStorage.js'
|
||||
@@ -44,8 +42,7 @@ const updataInfo = ref({})
|
||||
const isUpload = ref(false)
|
||||
const uploadPro = ref(0)
|
||||
const uploadSucess = ref(false)
|
||||
const uploadResponse = ref({})
|
||||
const tempFilePath = ref('')
|
||||
const newVersionRef = ref('')
|
||||
|
||||
// 关闭更新弹窗,下次登录在提示
|
||||
function closeHandle() {
|
||||
@@ -58,16 +55,46 @@ async function findVersionAjax() {
|
||||
try {
|
||||
let updateFlag = useStorage.get('updateFlag')
|
||||
const res = await findVersion()
|
||||
let reg = /\./g;
|
||||
if (res.version.replace(reg, '') > packageData.version.replace(reg, '') && res.url && !updateFlag) {
|
||||
showDialog.value = true
|
||||
updataInfo.value = res
|
||||
if (res && res.version) {
|
||||
const newVersion = res.version;
|
||||
const oldVersion = packageData.version;
|
||||
|
||||
console.log('当前版本:', oldVersion);
|
||||
console.log('获取版本:', newVersion);
|
||||
|
||||
const result = compareVersions(newVersion, oldVersion);
|
||||
if (result > 0) {
|
||||
if (!updateFlag) {
|
||||
newVersionRef.value = newVersion
|
||||
showDialog.value = true
|
||||
updataInfo.value = res
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log('检查版本更新===', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 比较版本号
|
||||
function compareVersions(version1, version2) {
|
||||
const v1 = version1.split('.').map(Number);
|
||||
const v2 = version2.split('.').map(Number);
|
||||
const maxLength = Math.max(v1.length, v2.length);
|
||||
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
const num1 = v1[i] || 0;
|
||||
const num2 = v2[i] || 0;
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
} else if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 下载新版本
|
||||
async function uplaodHandle() {
|
||||
try {
|
||||
@@ -86,7 +113,7 @@ async function uplaodHandle() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (store.userInfo) {
|
||||
if (store.shopInfo.id) {
|
||||
findVersionAjax()
|
||||
}
|
||||
ipcRenderer.on('updateProgress', (event, res) => {
|
||||
|
||||
@@ -14,22 +14,23 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import userStore from '@/utils/useStorage.js'
|
||||
import { ElUpload, ElMessage } from 'element-plus';
|
||||
|
||||
|
||||
const fileList = ref([])
|
||||
|
||||
// 定义接收的外部属性
|
||||
const props = defineProps({
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: import.meta.env.MODE == 'development' ? '/api/shopInfo/upload' : import.meta.env.VITE_API_URL + '/shopInfo/upload',
|
||||
default: import.meta.env.MODE == 'development' ? '/api/account/admin/common/upload' : import.meta.env.VITE_API_URL + '/account/admin/common/upload',
|
||||
},
|
||||
headers: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
token: useStorage.get("token"),
|
||||
loginName: useStorage.get("userInfo").loginName,
|
||||
token: userStore.get('token'),
|
||||
shopId: userStore.get('shopInfo').id,
|
||||
clientType: 'pc'
|
||||
}),
|
||||
},
|
||||
@@ -102,13 +103,11 @@ const beforeUpload = (file) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
function init(arr) {
|
||||
function init(arr = []) {
|
||||
fileList.value = arr
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
</script>
|
||||
0
src/lib/carts.ts
Normal file
0
src/lib/carts.ts
Normal file
800
src/lib/coupon.ts
Normal file
800
src/lib/coupon.ts
Normal file
@@ -0,0 +1,800 @@
|
||||
import { BigNumber } from "bignumber.js";
|
||||
import _ from "lodash";
|
||||
|
||||
import {
|
||||
ShopInfo,
|
||||
couponCalcParams,
|
||||
BaseCartItem,
|
||||
TimeLimitDiscountConfig,
|
||||
CanDikouGoodsArrArgs,
|
||||
Coupon,
|
||||
ShopUserInfo,
|
||||
GoodsType,
|
||||
BackendCoupon,
|
||||
ExchangeCalculationResult,
|
||||
PointDeductionRule,
|
||||
OrderCostSummary,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* 返回商品单价
|
||||
* @param goods 商品
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo
|
||||
*/
|
||||
export function returnGoodsPrice(
|
||||
goods: BaseCartItem,
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
if (!goods) {
|
||||
return 0;
|
||||
}
|
||||
//是否可以使用会员价
|
||||
const canUseVipPrice =
|
||||
user &&
|
||||
user.isVip &&
|
||||
user.isMemberPrice &&
|
||||
goods.memberPrice * 1 > 0 &&
|
||||
shopInfo &&
|
||||
shopInfo.isMemberPrice;
|
||||
// 商家改价
|
||||
if (goods.discount_sale_amount && goods.discount_sale_amount * 1 > 0) {
|
||||
return goods.salePrice;
|
||||
}
|
||||
// 限时折扣
|
||||
if (limitTimeDiscount && limitTimeDiscount.id) {
|
||||
//优先使用
|
||||
if (goods.isTimeDiscount || goods.is_time_discount) {
|
||||
return new BigNumber(goods.salePrice)
|
||||
.times(limitTimeDiscount.discountRate / 100)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber();
|
||||
}
|
||||
const canUseFoods = limitTimeDiscount.foods.split(",");
|
||||
const canUseLimit =
|
||||
limitTimeDiscount.foodType == 1 ||
|
||||
canUseFoods.includes(`${goods.productId}`);
|
||||
if (canUseLimit && limitTimeDiscount.discountPriority == "limit-time") {
|
||||
return new BigNumber(goods.salePrice)
|
||||
.times(limitTimeDiscount.discountRate / 100)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber();
|
||||
}
|
||||
|
||||
if (canUseLimit && limitTimeDiscount.discountPriority == "vip-price") {
|
||||
if (canUseVipPrice) {
|
||||
return goods.memberPrice;
|
||||
} else {
|
||||
return new BigNumber(goods.salePrice)
|
||||
.times(limitTimeDiscount.discountRate / 100)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canUseVipPrice) {
|
||||
return goods.memberPrice;
|
||||
}
|
||||
return goods.salePrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品分组
|
||||
* @param arr 商品列表
|
||||
*/
|
||||
export function returnGoodsGroupMap(arr: BaseCartItem[]) {
|
||||
let map: { [key: string]: BaseCartItem[] } = {};
|
||||
arr.forEach((v) => {
|
||||
const key = v.productId + "_" + v.skuId;
|
||||
if (!map[key]) {
|
||||
map[key] = [];
|
||||
}
|
||||
map[key].push(v);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
interface CouponTypes {
|
||||
1: "满减券";
|
||||
2: "商品券";
|
||||
3: "折扣券";
|
||||
4: "第二件半价券";
|
||||
5: "消费送券";
|
||||
6: "买一送一券";
|
||||
7: "固定价格券";
|
||||
8: "免配送费券";
|
||||
}
|
||||
/**
|
||||
* 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||||
* @param coupon
|
||||
*/
|
||||
export function returnCoupType(coupon: Coupon) {
|
||||
const couponTypes: CouponTypes = {
|
||||
1: "满减券",
|
||||
2: "商品券",
|
||||
3: "折扣券",
|
||||
4: "第二件半价券",
|
||||
5: "消费送券",
|
||||
6: "买一送一券",
|
||||
7: "固定价格券",
|
||||
8: "免配送费券",
|
||||
};
|
||||
return couponTypes[coupon.type as keyof CouponTypes] || "未知类型";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品券抵扣后的商品列表
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param user 用户信息
|
||||
*/
|
||||
export function returnCanDikouGoodsArr(args: CanDikouGoodsArrArgs) {
|
||||
const { canDikouGoodsArr, selCoupon, user, shopInfo, limitTimeDiscount } =
|
||||
args;
|
||||
const types = [2, 4, 6];
|
||||
// 收集已抵扣商品并关联对应的优惠券类型
|
||||
const goodsCouponGoods = selCoupon
|
||||
.filter((v) => types.includes(v.type))
|
||||
.reduce((prev: BaseCartItem[], cur) => {
|
||||
// 给每个抵扣商品添加所属优惠券类型
|
||||
if (cur && cur.discount) {
|
||||
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
|
||||
...goods,
|
||||
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
|
||||
}));
|
||||
prev.push(...goodsWithType);
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
const arr = _.cloneDeep(canDikouGoodsArr)
|
||||
.map((v) => {
|
||||
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
|
||||
if (findCart) {
|
||||
// 根据优惠券类型判断扣减数量
|
||||
if ([4, 6].includes(findCart.couponType ?? 0)) {
|
||||
// 类型4(第二件半价)或6(买一送一),数量减2
|
||||
if (v.num) {
|
||||
v.num -= 2;
|
||||
}
|
||||
} else {
|
||||
// 其他类型(如类型2商品券),按原逻辑扣减对应数量
|
||||
if (v.num) {
|
||||
v.num -= findCart.num ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
})
|
||||
.filter((v) => {
|
||||
const canUseNum = (v.num ?? 0) - (v.returnNum || 0);
|
||||
if (canUseNum <= 0 || v.is_temporary || v.is_gift) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}); // 过滤掉数量<=0的商品,赠菜,临时菜
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品是否享用了会员价/会员折扣
|
||||
* @param {*} goods
|
||||
*/
|
||||
function returnGoodsIsUseVipPrice(
|
||||
shopInfo: ShopInfo,
|
||||
user: ShopUserInfo,
|
||||
goods: BaseCartItem
|
||||
) {
|
||||
if (goods.is_time_discount) {
|
||||
return false;
|
||||
}
|
||||
if (shopInfo.isMemberPrice != 1 || user.isVip != 1) {
|
||||
return false;
|
||||
}
|
||||
if (shopInfo.isMemberPrice == 1 && user.isVip == 1) {
|
||||
if (goods.memberPrice <= 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可以计算抵扣金额的商品列表
|
||||
*/
|
||||
function returnCanCalcGoodsList(
|
||||
canCalcGoodsArr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
shopInfo: ShopInfo,
|
||||
user: ShopUserInfo
|
||||
) {
|
||||
return canCalcGoodsArr.filter((goods) => {
|
||||
if (
|
||||
!coupon.discountShare &&
|
||||
(goods.is_time_discount || goods.isTimeDiscount)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!coupon.vipPriceShare &&
|
||||
returnGoodsIsUseVipPrice(shopInfo, user, goods)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断优惠券是否可使用,并返回不可用原因
|
||||
*
|
||||
* @param {Object} args - 函数参数集合
|
||||
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表
|
||||
* @param {Object} args.coupon - 优惠券信息对象
|
||||
* @param {boolean} args.coupon.use - 优惠券是否启用
|
||||
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表
|
||||
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
|
||||
* @param {number} args.coupon.type - 优惠券类型
|
||||
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额
|
||||
* @param {Object} args.user - 用户信息对象
|
||||
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
|
||||
* @param {Object} args.shopInfo
|
||||
* @param {boolean} args.limitTimeDiscount - 限时折扣
|
||||
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
|
||||
*/
|
||||
export function returnCouponCanUse(args: couponCalcParams) {
|
||||
let {
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
goodsOrderPrice,
|
||||
user,
|
||||
selCoupon,
|
||||
shopInfo,
|
||||
isMemberPrice,
|
||||
limitTimeDiscount,
|
||||
} = args;
|
||||
// 优惠券未启用
|
||||
if (!coupon.use) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: coupon.noUseRestrictions || "不在可用时间段内",
|
||||
};
|
||||
}
|
||||
if (
|
||||
limitTimeDiscount &&
|
||||
limitTimeDiscount.id &&
|
||||
limitTimeDiscount.foodType == 1 &&
|
||||
!coupon.discountShare
|
||||
) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
|
||||
};
|
||||
}
|
||||
|
||||
// 计算门槛金额
|
||||
let fullAmount = goodsOrderPrice;
|
||||
canDikouGoodsArr = returnCanDikouGoodsArr(args);
|
||||
//优惠券指定门槛商品列表
|
||||
let canCalcGoodsArr = [...canDikouGoodsArr];
|
||||
//部分商品参与门槛计算
|
||||
if (coupon.thresholdFoods.length) {
|
||||
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.thresholdFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
}
|
||||
canCalcGoodsArr = returnCanCalcGoodsList(
|
||||
canCalcGoodsArr,
|
||||
coupon,
|
||||
shopInfo,
|
||||
user
|
||||
);
|
||||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||||
return (
|
||||
pre +
|
||||
returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * (cur.num || 0)
|
||||
);
|
||||
}, 0);
|
||||
|
||||
// 是否全部商品可用
|
||||
const isDikouAll = coupon.useFoods.length === 0;
|
||||
// 订单可用商品列表
|
||||
let canUseGoodsArr: BaseCartItem[] = [];
|
||||
if (!isDikouAll) {
|
||||
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.useFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
}
|
||||
// if (user.isVip && !coupon.vipPriceShare) {
|
||||
// return {
|
||||
// canUse: false,
|
||||
// reason: "非会员可用",
|
||||
// };
|
||||
// }
|
||||
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
// 满减券和折扣券计算门槛金额是否满足
|
||||
if ([1, 3].includes(coupon.type)) {
|
||||
if (canCalcGoodsArr.length <= 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有可参与计算门槛的商品",
|
||||
};
|
||||
}
|
||||
// 不满足门槛金额
|
||||
if (fullAmount < (coupon.fullAmount || 0)) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
}
|
||||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||||
if ([2, 4, 5].includes(coupon.type)) {
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
if (!isDikouAll && canUseGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
if (coupon.type == 2) {
|
||||
if (canCalcGoodsArr.length <= 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合计算门槛条件的商品",
|
||||
};
|
||||
}
|
||||
if (fullAmount < (coupon.fullAmount || 0)) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
//商品兑换券是否达到门槛金额
|
||||
if (coupon.type == 2 && goodsOrderPrice < (coupon.fullAmount || 0)) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 买一送一券特殊验证
|
||||
if (coupon.type === 6) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 第二件半价券特殊验证
|
||||
if (coupon.type === 4) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
|
||||
}
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 所有条件都满足
|
||||
return {
|
||||
canUse: true,
|
||||
reason: "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算抵扣商品金额
|
||||
* @param discountGoodsArr 可抵扣商品列表
|
||||
* @param discountNum 抵扣数量
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo 店铺信息
|
||||
*/
|
||||
export function calcDiscountGoodsArrPrice(
|
||||
discountGoodsArr: BaseCartItem[],
|
||||
discountNum: number,
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
let hasCountNum = 0;
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
|
||||
for (let i = 0; i < discountGoodsArr.length; i++) {
|
||||
if (hasCountNum >= discountNum) {
|
||||
break;
|
||||
}
|
||||
const goods = discountGoodsArr[i];
|
||||
const shengyuNum = discountNum - hasCountNum;
|
||||
const num = Math.min(goods.num || 0, shengyuNum);
|
||||
const realPrice = returnGoodsPrice(
|
||||
goods,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
|
||||
discountPrice += realPrice * num;
|
||||
|
||||
hasCountNum += num;
|
||||
hasDiscountGoodsArr.push({
|
||||
...goods,
|
||||
num,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算优惠券抵扣金额
|
||||
* @param arr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param shopInfo 店铺信息
|
||||
* @param limitTimeDiscount 限时折扣
|
||||
*/
|
||||
export function returnCouponDiscount(
|
||||
arr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
user: ShopUserInfo,
|
||||
goodsOrderPrice: number,
|
||||
selCoupon: Coupon[],
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
arr = returnCanDikouGoods(arr, user, shopInfo, limitTimeDiscount);
|
||||
const canDikouGoodsArr = returnCanDikouGoodsArr({
|
||||
canDikouGoodsArr: arr,
|
||||
selCoupon,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount,
|
||||
});
|
||||
if (coupon.type == 2) {
|
||||
return returnCouponProductDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
}
|
||||
if (coupon.type == 6) {
|
||||
const result = returnCouponBuyOneGiveOneDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
return result;
|
||||
}
|
||||
if (coupon.type == 4) {
|
||||
return returnSecoendDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
}
|
||||
if (coupon.type == 3) {
|
||||
return returnCouponZhekouDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
goodsOrderPrice,
|
||||
selCoupon,
|
||||
limitTimeDiscount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 折扣券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param limitTimeDiscount 限时折扣
|
||||
*/
|
||||
export function returnCouponZhekouDiscount(
|
||||
canDikouGoodsArr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
user: ShopUserInfo,
|
||||
goodsOrderPrice: number,
|
||||
selCoupon: Coupon[],
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
let { discountRate, maxDiscountAmount } = coupon;
|
||||
maxDiscountAmount = maxDiscountAmount || 0;
|
||||
// 计算商品优惠券折扣总和,使用BigNumber避免精度问题
|
||||
const goodsCouponDiscount = selCoupon
|
||||
.filter((v) => v.type == 2)
|
||||
.reduce((prve, cur) => {
|
||||
return new BigNumber(prve).plus(
|
||||
new BigNumber(cur?.discount?.discountPrice || 0)
|
||||
);
|
||||
}, new BigNumber(0));
|
||||
|
||||
// 将商品订单价格转换为BigNumber并减去优惠券折扣
|
||||
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
|
||||
goodsCouponDiscount
|
||||
);
|
||||
|
||||
// 计算优惠比例:(100 - 折扣率) / 100
|
||||
const discountAmountRatio = new BigNumber(100)
|
||||
.minus(discountRate || 0)
|
||||
.dividedBy(100);
|
||||
|
||||
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
|
||||
let discountPrice = adjustedGoodsOrderPrice
|
||||
.times(discountAmountRatio)
|
||||
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
|
||||
.toNumber();
|
||||
|
||||
// 应用最大折扣金额限制
|
||||
if (maxDiscountAmount !== 0) {
|
||||
discountPrice =
|
||||
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice, // 折扣抵扣金额(即优惠的金额)
|
||||
hasDiscountGoodsArr: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponProductDiscount(
|
||||
canDikouGoodsArr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
let { useFoods, discountNum, useRule } = coupon;
|
||||
discountNum = discountNum || 0;
|
||||
//抵扣商品数组
|
||||
let discountGoodsArr = [];
|
||||
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
} else {
|
||||
//抵扣选中商品
|
||||
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
|
||||
useFoods.find((food) => food.id == v.productId)
|
||||
);
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
}
|
||||
|
||||
const result = calcDiscountGoodsArrPrice(
|
||||
discountGoodsArr,
|
||||
discountNum,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回买一送一券抵扣详情
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnCouponBuyOneGiveOneDiscount(
|
||||
canDikouGoodsArr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合买一送一条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => (v.num || 0) >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) =>
|
||||
useFoods.find((food) => food.id == v.productId)
|
||||
);
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr: BaseCartItem[] = [];
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(
|
||||
discountGoods,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
return {
|
||||
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回第二件半价券抵扣详情
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnSecoendDiscount(
|
||||
canDikouGoodsArr: BaseCartItem[],
|
||||
coupon: Coupon,
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => (v.num || 0) >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) =>
|
||||
useFoods.find((food) => food.id == v.productId)
|
||||
);
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr: BaseCartItem[] = [];
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(
|
||||
discountGoods,
|
||||
user,
|
||||
shopInfo,
|
||||
limitTimeDiscount
|
||||
);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
//返回半价价格
|
||||
return {
|
||||
discountPrice:
|
||||
discountPrice <= 0
|
||||
? 0
|
||||
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
|
||||
* @param arr 商品列表
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
* @param limitTimeDiscount 限时折扣
|
||||
*/
|
||||
export function returnCanDikouGoods(
|
||||
arr: BaseCartItem[],
|
||||
user: ShopUserInfo,
|
||||
shopInfo: ShopInfo,
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||||
) {
|
||||
const result = arr
|
||||
.filter((v) => {
|
||||
return !v.is_temporary && !v.is_gift;
|
||||
})
|
||||
.filter((v) => {
|
||||
return (v.num || 0) > 0;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return (
|
||||
returnGoodsPrice(b, user, shopInfo, limitTimeDiscount) -
|
||||
returnGoodsPrice(a, user, shopInfo, limitTimeDiscount)
|
||||
);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const utils = {
|
||||
returnGoodsPrice,
|
||||
returnGoodsGroupMap,
|
||||
returnCoupType,
|
||||
returnCanDikouGoods,
|
||||
returnCanDikouGoodsArr,
|
||||
returnCouponCanUse,
|
||||
calcDiscountGoodsArrPrice,
|
||||
returnCouponDiscount,
|
||||
returnCouponProductDiscount,
|
||||
returnCouponZhekouDiscount,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
1275
src/lib/goods-1.0.47-back.ts
Normal file
1275
src/lib/goods-1.0.47-back.ts
Normal file
File diff suppressed because it is too large
Load Diff
1378
src/lib/goods.ts
Normal file
1378
src/lib/goods.ts
Normal file
File diff suppressed because it is too large
Load Diff
11
src/lib/index.ts
Normal file
11
src/lib/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from "./types";
|
||||
import OrderPriceCalculator from "./goods";
|
||||
import couponUtils from "./coupon";
|
||||
import limitUtils from "./limit";
|
||||
|
||||
export { OrderPriceCalculator, couponUtils, limitUtils };
|
||||
export default {
|
||||
OrderPriceCalculator,
|
||||
couponUtils,
|
||||
limitUtils,
|
||||
};
|
||||
216
src/lib/limit.ts
Normal file
216
src/lib/limit.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import BigNumber from "bignumber.js";
|
||||
|
||||
import _ from "lodash";
|
||||
|
||||
import {
|
||||
BaseCartItem,
|
||||
ShopUserInfo,
|
||||
ShopInfo,
|
||||
TimeLimitDiscountConfig,
|
||||
CanReturnMemberPriceArgs,
|
||||
returnPriceArgs,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* 判断商品是否可以使用限时折扣
|
||||
* @param goods 商品对象
|
||||
* @param limitTimeDiscountRes 限时折扣配置
|
||||
* @param shopInfo 店铺信息
|
||||
* @param shopUserInfo 店铺用户信息
|
||||
* @param idKey 商品ID键名,默认"id"
|
||||
* @returns
|
||||
*/
|
||||
export function canUseLimitTimeDiscount(
|
||||
goods: BaseCartItem,
|
||||
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined,
|
||||
shopInfo: ShopInfo,
|
||||
shopUserInfo: ShopUserInfo,
|
||||
idKey = "id" as keyof BaseCartItem
|
||||
) {
|
||||
shopInfo = shopInfo || {};
|
||||
shopUserInfo = shopUserInfo || {};
|
||||
if(shopInfo.isMemberPrice){
|
||||
shopUserInfo.isMemberPrice=1
|
||||
}
|
||||
if (!limitTimeDiscountRes || !limitTimeDiscountRes.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
|
||||
|
||||
const goodsCanUse =
|
||||
limitTimeDiscountRes.foodType == 1 ||
|
||||
canUseFoods.includes(`${goods[idKey]}`);
|
||||
if (!goodsCanUse) {
|
||||
return false;
|
||||
}
|
||||
if (limitTimeDiscountRes.discountPriority == "limit-time") {
|
||||
return true;
|
||||
}
|
||||
if (limitTimeDiscountRes.discountPriority == "vip-price") {
|
||||
if (
|
||||
shopUserInfo.isVip == 1 &&
|
||||
shopUserInfo.isMemberPrice == 1 &&
|
||||
goods.memberPrice * 1 > 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品显示价格
|
||||
* @params {*} args 参数对象
|
||||
* @params {*} args.goods 商品对象
|
||||
* @params {*} args.shopInfo 店铺信息
|
||||
* @params {*} args.limitTimeDiscountRes 限时折扣信息
|
||||
* @params {*} args.shopUserInfo 店铺用户信息
|
||||
* @returns
|
||||
*/
|
||||
export function returnPrice(args: returnPriceArgs) {
|
||||
let {
|
||||
goods,
|
||||
shopInfo,
|
||||
limitTimeDiscountRes,
|
||||
shopUserInfo,
|
||||
idKey = "product_id",
|
||||
} = args;
|
||||
limitTimeDiscountRes = limitTimeDiscountRes || {
|
||||
foods: "",
|
||||
foodType: 2,
|
||||
discountPriority: "",
|
||||
discountRate: 0,
|
||||
id: 0,
|
||||
shopId: 0,
|
||||
useType: "",
|
||||
};
|
||||
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
|
||||
const includesGoods =
|
||||
limitTimeDiscountRes.foodType == 1 ||
|
||||
canUseFoods.includes("" + goods[idKey]);
|
||||
shopInfo = shopInfo || {};
|
||||
shopUserInfo = shopUserInfo || {};
|
||||
if (
|
||||
shopUserInfo.isMemberPrice == 1 &&
|
||||
shopUserInfo.isVip == 1 &&
|
||||
shopInfo.isMemberPrice == 1
|
||||
) {
|
||||
const memberPrice = goods.memberPrice || goods.salePrice;
|
||||
|
||||
//是会员而且启用会员价
|
||||
if (limitTimeDiscountRes) {
|
||||
//使用限时折扣
|
||||
//限时折扣优先
|
||||
if (limitTimeDiscountRes.discountPriority == "limit-time") {
|
||||
if (includesGoods) {
|
||||
return returnLimitPrice({
|
||||
price: goods.salePrice,
|
||||
limitTimeDiscountRes,
|
||||
});
|
||||
} else {
|
||||
return memberPrice;
|
||||
}
|
||||
}
|
||||
if (
|
||||
limitTimeDiscountRes.discountPriority == "vip-price" &&
|
||||
includesGoods
|
||||
) {
|
||||
if (goods.memberPrice * 1 > 0) {
|
||||
//会员优先
|
||||
return memberPrice;
|
||||
} else {
|
||||
const price = returnLimitPrice({
|
||||
price: goods.salePrice,
|
||||
limitTimeDiscountRes,
|
||||
goods: goods,
|
||||
});
|
||||
|
||||
return price;
|
||||
}
|
||||
} else {
|
||||
return memberPrice;
|
||||
}
|
||||
} else {
|
||||
//是会员没有限时折扣
|
||||
return memberPrice;
|
||||
}
|
||||
} else {
|
||||
//不是会员或者没有启用会员价
|
||||
if (limitTimeDiscountRes && limitTimeDiscountRes.id && includesGoods) {
|
||||
const price = returnLimitPrice({
|
||||
price: goods.salePrice,
|
||||
limitTimeDiscountRes,
|
||||
goods: goods,
|
||||
});
|
||||
|
||||
return price;
|
||||
} else {
|
||||
return goods.salePrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface returnLimitPriceArgs {
|
||||
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined;
|
||||
price: number;
|
||||
goods?: BaseCartItem;
|
||||
}
|
||||
/**
|
||||
* 返回限时折扣价格
|
||||
* @params {*} args 参数对象
|
||||
* @params {*} args.limitTimeDiscountRes 限时折扣信息
|
||||
* @params {*} args.price 商品价格
|
||||
* @param {*} args.goods 商品对象
|
||||
* @returns
|
||||
*/
|
||||
export function returnLimitPrice(args: returnLimitPriceArgs) {
|
||||
const { limitTimeDiscountRes, price, goods } = args;
|
||||
const discountRate = new BigNumber(
|
||||
limitTimeDiscountRes ? limitTimeDiscountRes.discountRate : 100
|
||||
).dividedBy(100);
|
||||
|
||||
const result = BigNumber(price)
|
||||
.times(discountRate)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否返回会员价
|
||||
* @param {*} args 参数对象
|
||||
* @param {*} args.shopInfo 店铺信息
|
||||
* @param {*} args.shopUserInfo 店铺用户信息
|
||||
* @returns
|
||||
*/
|
||||
export function canReturnMemberPrice(args: CanReturnMemberPriceArgs) {
|
||||
const { shopInfo, shopUserInfo } = args;
|
||||
if (shopUserInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回会员价格
|
||||
* @param {*} goods
|
||||
* @returns
|
||||
*/
|
||||
export function returnMemberPrice(goods: BaseCartItem) {
|
||||
return goods.memberPrice || goods.salePrice;
|
||||
}
|
||||
|
||||
export const utils = {
|
||||
returnPrice,
|
||||
canUseLimitTimeDiscount,
|
||||
returnLimitPrice,
|
||||
canReturnMemberPrice,
|
||||
returnMemberPrice,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
0
src/lib/socket.ts
Normal file
0
src/lib/socket.ts
Normal file
430
src/lib/types.ts
Normal file
430
src/lib/types.ts
Normal file
@@ -0,0 +1,430 @@
|
||||
/** 商品类型枚举 */
|
||||
export enum GoodsType {
|
||||
NORMAL = "normal", // 普通商品
|
||||
WEIGHT = "weight", // 称重商品
|
||||
GIFT = "gift", // 赠菜(继承普通商品逻辑,标记用)
|
||||
EMPTY = "", // 空字符串类型(后端未返回时默认归类为普通商品)
|
||||
PACKAGE = "package", // 打包商品(如套餐/预打包商品,按普通商品逻辑处理,可扩展特殊规则)
|
||||
}
|
||||
|
||||
/** 优惠券计算结果类型(新增细分字段) */
|
||||
export interface CouponResult {
|
||||
deductionAmount: number; // 抵扣金额
|
||||
excludedProductIds: string[]; // 不适用商品ID列表(注意:是商品ID,非购物车ID)
|
||||
usedCoupon: Coupon | undefined; // 实际使用的优惠券
|
||||
productCouponDeduction: number; // 新增:商品优惠券抵扣(兑换券等)
|
||||
fullCouponDeduction: number; // 新增:满减优惠券抵扣
|
||||
}
|
||||
|
||||
/** 兑换券计算结果类型(新增细分字段) */
|
||||
export interface ExchangeCalculationResult {
|
||||
deductionAmount: number;
|
||||
excludedProductIds: string[]; // 不适用商品ID列表(商品ID)
|
||||
productCouponDeduction: number; // 新增:兑换券属于商品券,同步记录
|
||||
}
|
||||
|
||||
export interface CouponTypes {
|
||||
1: "满减券";
|
||||
2: "商品券";
|
||||
3: "折扣券";
|
||||
4: "第二件半价券";
|
||||
5: "消费送券";
|
||||
6: "买一送一券";
|
||||
7: "固定价格券";
|
||||
8: "免配送费券";
|
||||
}
|
||||
|
||||
/** 优惠券类型枚举 */
|
||||
export enum CouponType {
|
||||
FULL_REDUCTION = "full_reduction", // 满减券
|
||||
DISCOUNT = "discount", // 折扣券
|
||||
SECOND_HALF = "second_half", // 第二件半价券
|
||||
BUY_ONE_GET_ONE = "buy_one_get_one", // 买一送一券
|
||||
EXCHANGE = "exchange", // 商品兑换券
|
||||
}
|
||||
|
||||
/** 后端返回的优惠券原始字段类型 */
|
||||
export interface BackendCoupon {
|
||||
id?: number; // 自增主键(int64)
|
||||
shopId?: number; // 店铺ID(int64)
|
||||
syncId?: number; // 同步Id(int64)
|
||||
type?: number; // 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||||
name?: string; // 券名称
|
||||
useShopType?: string; // 可用门店类型:only-仅本店;all-所有门店,custom-指定门店
|
||||
useShops?: string; // 可用门店(逗号分隔字符串,如"1,2,3")
|
||||
useType?: string; // 可使用类型:dine堂食/pickup自取/deliv配送/express快递
|
||||
validType?: string; // 有效期类型:fixed(固定时间),custom(自定义时间)
|
||||
validDays?: number; // 有效期(天)
|
||||
validStartTime?: string; // 有效期开始时间(如"2024-01-01 00:00:00")
|
||||
validEndTime?: string; // 有效期结束时间
|
||||
daysToTakeEffect?: number; // 隔天生效
|
||||
useDays?: string; // 可用周期(如"周一,周二")
|
||||
useTimeType?: string; // 可用时间段类型:all-全时段,custom-指定时段
|
||||
useStartTime?: string; // 可用开始时间(每日)
|
||||
useEndTime?: string; // 可用结束时间(每日)
|
||||
getType?: string; // 发放设置:不可自行领取/no,可领取/yes
|
||||
getMode?: string; // 用户领取方式
|
||||
giveNum?: number; // 总发放数量,-10086为不限量
|
||||
getUserType?: string; // 可领取用户:全部/all,新用户一次/new,仅会员/vip
|
||||
getLimit?: number; // 每人领取限量,-10086为不限量
|
||||
useLimit?: number; // 每人每日使用限量,-10086为不限量
|
||||
discountShare?: number; // 与限时折扣同享:0-否,1-是
|
||||
vipPriceShare?: number; // 与会员价同享:0-否,1-是
|
||||
ruleDetails?: string; // 附加规则说明
|
||||
status?: number; // 状态:0-禁用,1-启用
|
||||
useNum?: number; // 已使用数量
|
||||
leftNum?: number; // 剩余数量
|
||||
foods?: string; // 指定门槛商品(逗号分隔字符串,如"101,102",此处为商品ID)
|
||||
fullAmount?: number; // 使用门槛:满多少金额(元)
|
||||
discountAmount?: number; // 使用门槛:减多少金额(元)
|
||||
discountRate?: number; // 折扣%(如90=9折)
|
||||
maxDiscountAmount?: number; // 可抵扣最大金额(元)
|
||||
useRule?: string; // 使用规则:price_asc-价格低到高,price_desc-高到低
|
||||
discountNum?: number; // 抵扣数量
|
||||
otherCouponShare?: number; // 与其它优惠共享:0-否,1-是
|
||||
createTime?: string; // 创建时间
|
||||
updateTime?: string; // 更新时间
|
||||
}
|
||||
|
||||
/** 营销活动类型枚举 */
|
||||
export enum ActivityType {
|
||||
TIME_LIMIT_DISCOUNT = "time_limit_discount", // 限时折扣
|
||||
}
|
||||
|
||||
/** 基础购物车商品项(核心修正:新增product_id,明确各ID含义) */
|
||||
export interface BaseCartItem {
|
||||
id: string | number; // 购物车ID(唯一标识购物车中的条目,如购物车项主键)
|
||||
product_id: string | number; // 商品ID(唯一标识商品,用于优惠券/活动匹配,必选)
|
||||
productId?: string | number; // 商品ID
|
||||
salePrice: number; // 商品原价(元)
|
||||
number: number; // 商品数量
|
||||
num?: number; // 商品数量
|
||||
isTimeDiscount?: boolean; // 是否限时折扣商品(默认false)
|
||||
is_time_discount?: boolean; // 是否限时折扣商品(默认false)
|
||||
product_type: GoodsType; // 商品类型
|
||||
is_temporary?: boolean; // 是否临时菜(默认false)
|
||||
isTemporary?: boolean; // 是否临时菜(默认false)
|
||||
is_gift?: boolean; // 是否赠菜(默认false)
|
||||
isGift?: boolean; // 是否赠菜(默认false)
|
||||
returnNum?: number; // 退货数量(历史订单用,默认0)
|
||||
memberPrice: number; // 商品会员价(元,优先级:商品会员价 > 会员折扣)
|
||||
discountSaleAmount?: number; // 商家改价后单价(元,优先级最高)
|
||||
discount_sale_amount?: number; // 商家改价后单价(元,优先级最高)
|
||||
packFee?: number; // 单份打包费(元,默认0)
|
||||
packNumber?: number; // 堂食打包数量(默认0)
|
||||
activityInfo?: {
|
||||
// 商品参与的营销活动(如限时折扣)
|
||||
type: ActivityType;
|
||||
discountRate: number; // 折扣率(如0.8=8折)
|
||||
vipPriceShare: boolean; // 是否与会员优惠同享(默认false)
|
||||
};
|
||||
skuData?: {
|
||||
// SKU扩展数据(可选)
|
||||
id: string | number; // SKU ID(唯一标识商品规格,如颜色/尺寸)
|
||||
memberPrice: number; // SKU会员价
|
||||
salePrice?: number; // SKU原价
|
||||
};
|
||||
skuId?: string | number; // SKU ID(唯一标识商品规格,如颜色/尺寸)
|
||||
couponType?: number; // 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||||
}
|
||||
|
||||
export interface CouponFoods {
|
||||
id: string;
|
||||
name: string;
|
||||
images: string;
|
||||
}
|
||||
|
||||
/** 基础优惠券接口(所有券类型继承,包含统一门槛商品字段) */
|
||||
export interface BaseCoupon {
|
||||
otherCouponShare?: number; // 与其它优惠共享:0-否,1-是
|
||||
id: string | number; // 优惠券ID
|
||||
type: number; // 工具库字符串枚举(由后端couponType转换)
|
||||
name: string; // 对应后端title
|
||||
available: boolean; // 基于BackendCoupon字段计算的可用性
|
||||
useShopType?: string; // only-仅本店;all-所有门店,custom-指定门店
|
||||
useShops: string[]; // 可用门店ID列表
|
||||
discountShare: boolean; // 与限时折扣同享:0-否,1-是(后端字段转换为布尔值)
|
||||
vipPriceShare: boolean; // 与会员价同享:0-否,1-是(后端字段转换为布尔值)
|
||||
useType?: string[]; // 可使用类型:dine堂食/pickup自取/deliv配送/express快递
|
||||
isValid: boolean; // 是否在有效期内
|
||||
discountAmount?: number; // 减免金额 (满减券有)
|
||||
fullAmount?: number; // 使用门槛:满多少金额
|
||||
maxDiscountAmount?: number; // 可抵扣最大金额 元
|
||||
use: boolean;
|
||||
discountNum?: number; // 抵扣数量
|
||||
useRule?: string; // 使用规则:price_asc-价格低到高,price_desc-高到低
|
||||
discountRate?: number; // 折扣%(如90=9折)
|
||||
noUseRestrictions?: boolean; // 是不可用原因
|
||||
thresholdFoods: CouponFoods[]; // 门槛商品ID列表(空数组=全部商品,非空=指定商品ID)
|
||||
useFoods: CouponFoods[]; // 可用商品ID列表(空数组=全部商品,非空=指定商品ID)
|
||||
}
|
||||
export interface couponDiscount {
|
||||
discountPrice: number;
|
||||
hasDiscountGoodsArr: BaseCartItem[];
|
||||
}
|
||||
/** 满减券(适配后端字段) */
|
||||
export interface FullReductionCoupon extends BaseCoupon {
|
||||
fullAmount: number; // 对应后端fullAmount(满减门槛)
|
||||
discountAmount: number; // 对应后端discountAmount(减免金额)
|
||||
maxDiscountAmount?: number; // 对应后端maxDiscountAmount(最大减免)
|
||||
discount?: couponDiscount;
|
||||
}
|
||||
|
||||
/** 折扣券(适配后端字段) */
|
||||
export interface DiscountCoupon extends BaseCoupon {
|
||||
discountRate: number; // 后端discountRate(%)转小数(如90→0.9)
|
||||
maxDiscountAmount: number; // 对应后端maxDiscountAmount(最大减免)
|
||||
discount?: couponDiscount;
|
||||
}
|
||||
|
||||
/** 第二件半价券(适配后端字段) */
|
||||
export interface SecondHalfPriceCoupon extends BaseCoupon {
|
||||
maxUseCountPerOrder?: number; // 对应后端useLimit(-10086=不限)
|
||||
discount?: couponDiscount;
|
||||
}
|
||||
|
||||
/** 买一送一券(适配后端字段) */
|
||||
export interface BuyOneGetOneCoupon extends BaseCoupon {
|
||||
maxUseCountPerOrder?: number; // 对应后端useLimit(-10086=不限)
|
||||
discount?: couponDiscount;
|
||||
}
|
||||
|
||||
/** 商品兑换券(适配后端字段) */
|
||||
export interface ExchangeCoupon extends BaseCoupon {
|
||||
deductCount: number; // 对应后端discountNum(抵扣数量)
|
||||
sortRule: "low_price_first" | "high_price_first"; // 后端useRule转换
|
||||
discount?: couponDiscount;
|
||||
}
|
||||
|
||||
/** 所有优惠券类型联合 */
|
||||
export type Coupon =
|
||||
| FullReductionCoupon
|
||||
| DiscountCoupon
|
||||
| SecondHalfPriceCoupon
|
||||
| BuyOneGetOneCoupon
|
||||
| ExchangeCoupon;
|
||||
|
||||
/** 营销活动配置(如限时折扣,applicableProductIds为商品ID列表) */
|
||||
export interface ActivityConfig {
|
||||
type: ActivityType;
|
||||
applicableProductIds?: string[]; // 适用商品ID列表(与BaseCartItem.product_id匹配)
|
||||
discountRate: number; // 折扣率(如0.8=8折)
|
||||
vipPriceShare: boolean; // 是否与会员优惠同享
|
||||
}
|
||||
|
||||
/** 积分抵扣规则 */
|
||||
export interface PointDeductionRule {
|
||||
pointsPerYuan: number; // X积分=1元(如100=100积分抵1元)
|
||||
maxDeductionAmount?: number; // 最大抵扣金额(元,默认不限)
|
||||
}
|
||||
|
||||
/** 餐位费配置 */
|
||||
export interface SeatFeeConfig {
|
||||
pricePerPerson: number; // 每人餐位费(元)
|
||||
personCount: number; // 用餐人数(默认1)
|
||||
isEnabled: boolean; // 是否启用餐位费(默认false)
|
||||
}
|
||||
/** 商家减免类型枚举 */
|
||||
export enum MerchantReductionType {
|
||||
FIXED_AMOUNT = "fixed_amount", // 固定金额减免(如直接减 10 元)
|
||||
DISCOUNT_RATE = "discount_rate", // 比例折扣减免(如打 9 折,即减免 10%)
|
||||
}
|
||||
|
||||
/** 商家减免配置(新增,替代原单一金额字段) */
|
||||
export interface MerchantReductionConfig {
|
||||
type: MerchantReductionType; // 减免类型(二选一)
|
||||
fixedAmount?: number; // 固定减免金额(元,仅 FIXED_AMOUNT 生效,≥0)
|
||||
discountRate?: number; // 折扣率(%,仅 DISCOUNT_RATE 生效,0-100,如 90 代表 9 折)
|
||||
}
|
||||
/**商家霸王餐配置 */
|
||||
export interface FreeDineConfig {
|
||||
enable: boolean; //是否开启
|
||||
rechargeThreshold: number; //订单满多少元可以使用
|
||||
rechargeTimes: number; //充值多少倍免单
|
||||
withCoupon: boolean; //与优惠券同享
|
||||
withPoints: boolean; //与积分同享
|
||||
useType?: string[]; //使用类型 dine-in店内 takeout 自取 post快递,takeaway外卖
|
||||
useShopType?: string; //all 全部 part部分
|
||||
shopIdList?: number[]; //可用门店id
|
||||
}
|
||||
|
||||
//限时折扣配置
|
||||
export interface TimeLimitDiscountConfig {
|
||||
/**
|
||||
* 折扣优先级 limit-time/vip-price
|
||||
*/
|
||||
discountPriority: string;
|
||||
/**
|
||||
* 折扣% 范围1-99
|
||||
*/
|
||||
discountRate: number;
|
||||
/**
|
||||
* 参与商品
|
||||
*/
|
||||
foods: string;
|
||||
/**
|
||||
* 参与商品 1全部 2部分
|
||||
*/
|
||||
foodType: number;
|
||||
/**
|
||||
* 自增主键
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* 店铺ID
|
||||
*/
|
||||
shopId: number;
|
||||
/**
|
||||
* 可使用类型:堂食 dine-in 外带 take-out 外卖 take-away 配送 post
|
||||
*/
|
||||
useType: string;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
//用户信息
|
||||
export interface ShopUserInfo {
|
||||
isVip: number | null; //是否会员
|
||||
discount: number | null; //用户折扣
|
||||
isMemberPrice: number | null; //会员折扣与会员价是否同时使用
|
||||
id?: number; //用户ID
|
||||
}
|
||||
/** 订单额外费用配置 */
|
||||
export interface OrderExtraConfig {
|
||||
// merchantReduction: number; // 商家减免金额(元,默认0)
|
||||
// 替换原单一金额字段,支持两种减免形式
|
||||
merchantReduction: MerchantReductionConfig;
|
||||
additionalFee: number; // 附加费(元,如余额充值、券包,默认0)
|
||||
pointDeductionRule: PointDeductionRule; // 积分抵扣规则
|
||||
seatFeeConfig: SeatFeeConfig; // 餐位费配置
|
||||
currentStoreId: string; // 当前门店ID(用于验证优惠券适用门店)
|
||||
userPoints: number; // 用户当前积分(用于积分抵扣)
|
||||
isMember: boolean; // 用户是否会员(用于会员优惠)
|
||||
memberDiscountRate?: number; // 会员折扣率(如0.95=95折,无会员价时用)
|
||||
newUserDiscount?: number; // 新用户减免金额(元,默认0)
|
||||
fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构)
|
||||
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型(匹配useType)
|
||||
isFreeDine?: boolean; //是否霸王餐
|
||||
freeDineConfig?: FreeDineConfig;
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig; //限时折扣
|
||||
shopUserInfo: ShopUserInfo; // 用户信息
|
||||
}
|
||||
|
||||
/** 订单费用汇总(修改:补充商家减免类型和明细) */
|
||||
export interface OrderCostSummary {
|
||||
goodsList: BaseCartItem[];
|
||||
// 商品总件数
|
||||
goodsTotal: number;
|
||||
totalDiscountAmount: number;
|
||||
goodsRealAmount: number; // 商品真实原价总和
|
||||
goodsOriginalAmount: number; // 商品原价总和
|
||||
goodsDiscountAmount: number; // 商品折扣金额
|
||||
couponDeductionAmount: number; // 优惠券总抵扣
|
||||
productCouponDeduction: number; // 商品优惠券抵扣
|
||||
fullCouponDeduction: number; // 满减优惠券抵扣
|
||||
pointDeductionAmount: number; // 积分抵扣金额
|
||||
seatFee: number; // 餐位费
|
||||
packFee: number; // 打包费
|
||||
scoreMaxMoney: number; // 积分最大可抵扣金额
|
||||
// 新增:商家减免明细
|
||||
merchantReduction: {
|
||||
type: MerchantReductionType; // 实际使用的减免类型
|
||||
originalConfig: MerchantReductionConfig; // 原始配置(便于前端展示)
|
||||
actualAmount: number; // 实际减免金额(计算后的值,≥0)
|
||||
};
|
||||
additionalFee: number; // 附加费
|
||||
finalPayAmount: number; // 最终实付金额
|
||||
couponUsed?: Coupon; // 实际使用的优惠券
|
||||
pointUsed: number; // 实际使用的积分
|
||||
newUserDiscount: number; // 新用户减免金额(元,默认0)
|
||||
dinnerType?: "dine-in" | "take-out"; // 就餐类型(堂食/自取/配送/快递)
|
||||
config: OrderExtraConfig; // 订单额外费用配置
|
||||
//满减活动
|
||||
fullReduction: {
|
||||
usedFullReductionActivityFullAmount: number; // 计算出的满减活动的门槛金额
|
||||
usedActivity?: FullReductionActivity; // 实际使用的满减活动
|
||||
usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优)
|
||||
actualAmount: number; // 满减实际减免金额(元)
|
||||
};
|
||||
vipDiscountAmount: number; //会员折扣减免金额
|
||||
// 订单原支付金额
|
||||
orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费)
|
||||
}
|
||||
|
||||
/** 满减活动阈值(单条满减规则:满X减Y)- 对应 MkDiscountThresholdInsertGroupDefaultGroup */
|
||||
export interface FullReductionThreshold {
|
||||
activityId?: number; // 关联满减活动ID
|
||||
fullAmount?: number; // 满多少金额(元,必填)
|
||||
discountAmount?: number; // 减多少金额(元,必填)
|
||||
}
|
||||
|
||||
/** 满减活动主表 - 对应 Request 接口(后端真实字段) */
|
||||
export interface FullReductionActivity {
|
||||
id?: number; // 自增主键(后端字段:id)
|
||||
shopId?: number; // 店铺ID(后端字段:shopId)
|
||||
status?: number; // 活动状态:1=未开始,2=进行中,3=已结束(后端字段:status)
|
||||
sort?: number; // 排序值(越大优先级越高,后端字段:sort)
|
||||
createTime?: string; // 创建时间(后端字段:createTime,格式如"2025-10-14 13:56:07")
|
||||
updateTime?: string; // 最新修改时间(后端字段:updateTime,用于优先级排序)
|
||||
validStartTime?: string; // 有效期开始时间(后端字段:validStartTime,格式如"2025-10-14")
|
||||
validEndTime?: string; // 有效期结束时间(后端字段:validEndTime,格式如"2025-12-14")
|
||||
useType?: string; // 可使用类型(后端字段:useType,如"dine,pickup,deliv,express")
|
||||
useDays?: string; // 可用周期(后端字段:useDays,如"周一,周二,周三,周四,周五,周六,周日")
|
||||
useTimeType?: string; // 可用时间段类型(后端字段:useTimeType,all=全时段,custom=指定时段)
|
||||
useStartTime?: string; // 每日可用开始时间(后端字段:useStartTime,如"09:00:00",仅custom时有效)
|
||||
useEndTime?: string; // 每日可用结束时间(后端字段:useEndTime,如"22:00:00",仅custom时有效)
|
||||
couponShare?: number; // 与优惠券同享:0=否,1=是(后端字段:couponShare)
|
||||
discountShare?: number; // 与限时折扣同享:0=否,1=是(后端字段:discountShare)
|
||||
vipPriceShare?: number; // 与会员价同享:0=否,1=是(后端字段:vipPriceShare)
|
||||
pointsShare?: number; // 与积分抵扣同享:0=否,1=是(后端字段:pointsShare)
|
||||
thresholds?: FullReductionThreshold[]; // 满减阈值列表(多门槛,后端字段:thresholds)
|
||||
isDel?: boolean; // 是否删除:0=否,1=是(后端字段:isDel,默认false)
|
||||
}
|
||||
|
||||
// 辅助枚举:星期映射(用于useDays校验)
|
||||
export const WEEKDAY_MAP = {
|
||||
周一: 1,
|
||||
周二: 2,
|
||||
周三: 3,
|
||||
周四: 4,
|
||||
周五: 5,
|
||||
周六: 6,
|
||||
周日: 0, // JS中getDay()返回0=周日
|
||||
};
|
||||
|
||||
export interface ShopInfo {
|
||||
isMemberPrice: number; // 是否开启会员价 1是开启
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
export interface couponCalcParams {
|
||||
canDikouGoodsArr: BaseCartItem[];
|
||||
coupon: Coupon;
|
||||
user: ShopUserInfo;
|
||||
shopInfo: ShopInfo;
|
||||
selCoupon: Coupon[];
|
||||
goodsOrderPrice: number; //商品订单总价
|
||||
isMemberPrice: number; // 是否开启会员价 1是开启
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
|
||||
}
|
||||
export interface CanDikouGoodsArrArgs {
|
||||
canDikouGoodsArr: BaseCartItem[];
|
||||
selCoupon: Coupon[];
|
||||
user: ShopUserInfo;
|
||||
shopInfo: ShopInfo;
|
||||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
|
||||
}
|
||||
export interface returnPriceArgs {
|
||||
goods: BaseCartItem;
|
||||
selCoupon: Coupon[];
|
||||
user: ShopUserInfo;
|
||||
shopInfo: ShopInfo;
|
||||
shopUserInfo: ShopUserInfo;
|
||||
limitTimeDiscountRes?: TimeLimitDiscountConfig | null | undefined;
|
||||
idKey?: keyof BaseCartItem;
|
||||
}
|
||||
|
||||
|
||||
export interface CanReturnMemberPriceArgs {
|
||||
shopInfo?: ShopInfo;
|
||||
shopUserInfo: ShopUserInfo;
|
||||
}
|
||||
@@ -1,25 +1,176 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useGlobal = defineStore({
|
||||
id: "global",
|
||||
export const useGlobal = defineStore("global", {
|
||||
state: () => ({
|
||||
// 是否监听叫号
|
||||
isCallNumber: true,
|
||||
orderMemberInfo: {},
|
||||
tableInfo: {},
|
||||
orderStatus: [
|
||||
{
|
||||
type: "unpaid",
|
||||
label: "待支付",
|
||||
},
|
||||
{
|
||||
type: "in_production",
|
||||
label: "制作中",
|
||||
},
|
||||
{
|
||||
type: "wait_out",
|
||||
label: "待取餐",
|
||||
},
|
||||
{
|
||||
type: "done",
|
||||
label: "订单完成",
|
||||
},
|
||||
{
|
||||
type: "refunding",
|
||||
label: "申请退单",
|
||||
},
|
||||
{
|
||||
type: "refund",
|
||||
label: "退单",
|
||||
},
|
||||
{
|
||||
type: "part_refund",
|
||||
label: "部分退单",
|
||||
},
|
||||
{
|
||||
type: "cancelled",
|
||||
label: "取消订单",
|
||||
},
|
||||
],
|
||||
orderType: [
|
||||
{
|
||||
type: "cash",
|
||||
label: "收银",
|
||||
},
|
||||
{
|
||||
type: "miniapp",
|
||||
label: "小程序",
|
||||
},
|
||||
],
|
||||
platformType: [
|
||||
{
|
||||
type: "WX",
|
||||
label: "微信小程序",
|
||||
},
|
||||
{
|
||||
type: "ALI",
|
||||
label: "支付宝小程序",
|
||||
},
|
||||
{
|
||||
type: "PC",
|
||||
label: "收银机客户端",
|
||||
},
|
||||
{
|
||||
type: "WEB",
|
||||
label: "PC管理端",
|
||||
},
|
||||
{
|
||||
type: "APP",
|
||||
label: "APP管理端",
|
||||
},
|
||||
{
|
||||
type: "H5",
|
||||
label: "收款码",
|
||||
},
|
||||
],
|
||||
dineMode: [
|
||||
{
|
||||
type: "dine-in",
|
||||
label: "堂食",
|
||||
},
|
||||
{
|
||||
type: "take-out",
|
||||
label: "外带",
|
||||
},
|
||||
{
|
||||
type: "take-away",
|
||||
label: "外卖",
|
||||
},
|
||||
],
|
||||
payType: [
|
||||
{
|
||||
type: "main_scan",
|
||||
label: "主扫",
|
||||
},
|
||||
{
|
||||
type: "back_scan",
|
||||
label: "被扫",
|
||||
},
|
||||
{
|
||||
type: "wechat_mini",
|
||||
label: "微信小程序",
|
||||
},
|
||||
{
|
||||
type: "alipay_mini",
|
||||
label: "支付宝小程序",
|
||||
},
|
||||
{
|
||||
type: "vip_pay",
|
||||
label: "会员支付",
|
||||
},
|
||||
{
|
||||
type: "cash_pay",
|
||||
label: "现金支付",
|
||||
},
|
||||
{
|
||||
type: "credit_pay",
|
||||
label: "挂账支付",
|
||||
},
|
||||
],
|
||||
bizCodes: [
|
||||
{
|
||||
type: "cashIn",
|
||||
label: "现金充值",
|
||||
},
|
||||
{
|
||||
type: "wechatIn",
|
||||
label: "微信小程序充值",
|
||||
},
|
||||
{
|
||||
type: "alipayIn",
|
||||
label: "支付宝小程序充值",
|
||||
},
|
||||
{
|
||||
type: "awardIn",
|
||||
label: "充值奖励",
|
||||
},
|
||||
{
|
||||
type: "rechargeRefund",
|
||||
label: "充值退款",
|
||||
},
|
||||
{
|
||||
type: "orderPay",
|
||||
label: "订单消费",
|
||||
},
|
||||
{
|
||||
type: "orderRefund",
|
||||
label: "订单退款",
|
||||
},
|
||||
{
|
||||
type: "adminIn",
|
||||
label: "管理员充值",
|
||||
},
|
||||
{
|
||||
type: "adminOut",
|
||||
label: "管理员消费",
|
||||
},
|
||||
],
|
||||
refundType: [
|
||||
{
|
||||
type: "cash",
|
||||
label: "手动退款",
|
||||
},
|
||||
{
|
||||
type: "payBack",
|
||||
label: "原路退回",
|
||||
},
|
||||
],
|
||||
}),
|
||||
actions: {
|
||||
// 更新状态
|
||||
updateData(state) {
|
||||
this.isCallNumber = state;
|
||||
},
|
||||
// 设置订单会员信息
|
||||
setOrderMember(obj) {
|
||||
this.orderMemberInfo = obj;
|
||||
},
|
||||
// 设置订单台桌信息
|
||||
setOrderTable(obj) {
|
||||
this.tableInfo = obj;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
1033
src/store/goods.js
Normal file
1033
src/store/goods.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,20 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { bySubType } from "@/api/device";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useShop } from "@/store/shop.js";
|
||||
import dayjs from "dayjs";
|
||||
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||
import lodopPrintWork from "@/components/lodop/lodopPrintWork.js";
|
||||
import invoicePrint from "@/components/lodop/invoicePrint.js";
|
||||
import refundPrint from "@/components/lodop/refundPrint.js";
|
||||
import { printerList } from "@/api/account.js";
|
||||
|
||||
export const usePrint = defineStore({
|
||||
id: "print",
|
||||
export const usePrint = defineStore("print", {
|
||||
state: () => ({
|
||||
isPrintService: false, // 打印服务是否启动
|
||||
printServiceTimer: false, // 打印服务定时器
|
||||
printServiceTimerCount: 0, // 打印服务定时器计数
|
||||
printServiceTimerMaxCount: 10, // 打印服务定时器最大计数
|
||||
showPrintNotService: false, // 是否显示重启软件,
|
||||
localDevices: [], // 本地打印机列表
|
||||
deviceNoteList: [], // 添加的打印机
|
||||
deviceLableList: [], // 添加的打印机
|
||||
@@ -23,36 +26,64 @@ export const usePrint = defineStore({
|
||||
actions: {
|
||||
// 获取本地打印机和已添加的可以用打印机列表
|
||||
async init() {
|
||||
const store = useUser();
|
||||
|
||||
// 获取本地打印机
|
||||
ipcRenderer.send("getPrintList");
|
||||
ipcRenderer.on("printList", (event, arg) => {
|
||||
// localPrintList.value = arg;
|
||||
// console.log(localPrintList.value);
|
||||
this.localDevices = arg;
|
||||
});
|
||||
|
||||
// 获取已添加的小票打印机
|
||||
this.deviceNoteList = await bySubType({
|
||||
shopId: store.userInfo.shopId,
|
||||
contentType: "local",
|
||||
subType: "cash",
|
||||
});
|
||||
try {
|
||||
// 获取已添加的打印机
|
||||
const res = await printerList();
|
||||
this.deviceNoteList = res.records.filter(
|
||||
(item) => item.status && item.subType == "cash"
|
||||
);
|
||||
this.deviceLableList = res.records.filter(
|
||||
(item) => item.status && item.subType == "label"
|
||||
);
|
||||
console.log("打印队列初始化成功", {
|
||||
deviceNoteList: this.deviceNoteList,
|
||||
deviceLableList: this.deviceLableList,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取已添加的打印机列表失败", error);
|
||||
}
|
||||
|
||||
// 获取已添加的标签打印机
|
||||
this.deviceLableList = await bySubType({
|
||||
shopId: store.userInfo.shopId,
|
||||
contentType: "local",
|
||||
subType: "label",
|
||||
});
|
||||
console.log("打印队列初始化成功");
|
||||
// 检测打印服务是否启动
|
||||
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(deviceName) {
|
||||
checkLocalPrint(address) {
|
||||
let print = "";
|
||||
for (let item of this.localDevices) {
|
||||
if (item.name == deviceName) {
|
||||
if (item.name == address) {
|
||||
print = item;
|
||||
}
|
||||
}
|
||||
@@ -65,16 +96,13 @@ export const usePrint = defineStore({
|
||||
},
|
||||
// 打印标签小票
|
||||
labelPrint(props) {
|
||||
const shopInfo = useShop();
|
||||
const store = useUser();
|
||||
|
||||
if (
|
||||
this.deviceLableList.length &&
|
||||
this.checkLocalPrint(this.deviceLableList[0].config.deviceName)
|
||||
this.checkLocalPrint(this.deviceLableList[0].address)
|
||||
) {
|
||||
let pids = this.deviceLableList[0].config.categoryList.map(
|
||||
(item) => item.id
|
||||
);
|
||||
|
||||
let pids = this.deviceLableList[0].categoryList;
|
||||
let count = 0;
|
||||
let sum = 0;
|
||||
|
||||
@@ -95,20 +123,23 @@ export const usePrint = defineStore({
|
||||
name: item.name,
|
||||
skuName: item.skuName,
|
||||
masterId: props.orderInfo.tableName,
|
||||
deviceName: this.deviceLableList[0].config.deviceName,
|
||||
// deviceName: "Xprinter XP-T202UA",
|
||||
deviceName: this.deviceLableList[0].address,
|
||||
createdAt: dayjs(props.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||
isPrint: false,
|
||||
count: `${count}/${sum}`,
|
||||
ticketLogo: shopInfo.info.ticketLogo,
|
||||
ticketLogo: store.shopInfo.ticketLogo,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("this.labelList===", this.labelList);
|
||||
// return;
|
||||
|
||||
// 执行打印操作
|
||||
this.startLabelPrint();
|
||||
} else {
|
||||
console.log("没有标签打印机");
|
||||
console.log("标签打印:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 开始打印标签数据
|
||||
@@ -127,34 +158,25 @@ export const usePrint = defineStore({
|
||||
this.labelList.splice(0, 1);
|
||||
}
|
||||
}
|
||||
}, 800);
|
||||
}, 2000);
|
||||
},
|
||||
// 添加小票打印对列表数据
|
||||
// 添加小票打印队列数据
|
||||
pushReceiptData(props, isDevice = true) {
|
||||
console.log("pushReceiptData===", props);
|
||||
// console.log("pushReceiptData===", props);
|
||||
if (!isDevice) {
|
||||
// 测试打印,无需校验本地打印机
|
||||
const store = useUser();
|
||||
props.shop_name = store.userInfo.shopName;
|
||||
props.loginAccount = store.userInfo.loginAccount;
|
||||
props.createdAt = dayjs(props.createdAt).format("YYYY-MM-DD HH:mm:ss");
|
||||
props.printTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
if (!props.orderInfo.masterId) {
|
||||
props.orderInfo.masterId = props.orderInfo.tableName;
|
||||
}
|
||||
props.orderInfo.outNumber = props.outNumber;
|
||||
|
||||
this.receiptList.push(props);
|
||||
this.startReceiptPrint();
|
||||
} else {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address) &&
|
||||
this.isPrintService
|
||||
) {
|
||||
const store = useUser();
|
||||
props.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||
props.shop_name = store.userInfo.shopName;
|
||||
props.loginAccount = store.userInfo.loginAccount;
|
||||
props.deviceName = this.deviceNoteList[0].address;
|
||||
props.shop_name = store.shopInfo.shopName;
|
||||
props.loginAccount = store.userInfo.name;
|
||||
props.createdAt = dayjs(props.createdAt).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
);
|
||||
@@ -170,7 +192,7 @@ export const usePrint = defineStore({
|
||||
this.receiptList.push(props);
|
||||
this.startReceiptPrint();
|
||||
} else {
|
||||
console.log("订单小票:没有小票打印机");
|
||||
console.log("订单小票:未在本机查询到打印机");
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -185,42 +207,42 @@ export const usePrint = defineStore({
|
||||
receiptPrint(this.receiptList[0]);
|
||||
this.receiptList.splice(0, 1);
|
||||
}
|
||||
}, 800);
|
||||
}, 2000);
|
||||
},
|
||||
// 打印交班小票
|
||||
printWork(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
lodopPrintWork(data);
|
||||
} else {
|
||||
console.log("交班小票:没有小票打印机");
|
||||
console.log("交班小票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 打印订单发票
|
||||
printInvoice(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
invoicePrint(data);
|
||||
} else {
|
||||
console.log("订单发票:没有小票打印机");
|
||||
console.log("订单发票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 打印退单小票
|
||||
printRefund(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
refundPrint(data);
|
||||
} else {
|
||||
console.log("退单小票:没有小票打印机");
|
||||
console.log("退单小票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { queryShopInfo } from "@/api/user";
|
||||
import { shopInfo_detail } from "@/api/account.js";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
|
||||
export const useShop = defineStore({
|
||||
@@ -11,7 +11,7 @@ export const useShop = defineStore({
|
||||
// 获取店铺信息
|
||||
async queryShopInfo() {
|
||||
try {
|
||||
const res = await queryShopInfo();
|
||||
const res = await shopInfo_detail();
|
||||
useStorage.set("shopInfo", res);
|
||||
this.info = useStorage.get("shopInfo");
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,37 +1,24 @@
|
||||
import _ from "lodash";
|
||||
import { dayjs } from "element-plus";
|
||||
import { defineStore } from "pinia";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { getOrderByIdAjax, commOrderPrintData } from "@/utils/index.js";
|
||||
|
||||
export const useSocket = defineStore({
|
||||
id: uuidv4(),
|
||||
export const useSocket = defineStore("socket", {
|
||||
state: () => ({
|
||||
online: false, // 在线状态
|
||||
ws: null, // websocket实例
|
||||
uuid: "", // 长连接唯一id
|
||||
heartbeatTimer: null, // 心跳计时器
|
||||
orderList: [],
|
||||
log: true,
|
||||
orderListTimer: null,
|
||||
log: false,
|
||||
isPrinting: false,
|
||||
}),
|
||||
actions: {
|
||||
// 创建uuid
|
||||
createUUID() {
|
||||
if (!useStorage.get("uuid")) {
|
||||
ipcRenderer.send("getOSmacSync");
|
||||
// useStorage.set("uuid", uuidv4());
|
||||
ipcRenderer.on("getOSmacRes", (event, arg) => {
|
||||
useStorage.set("uuid", arg);
|
||||
this.uuid = useStorage.get("uuid");
|
||||
});
|
||||
} else {
|
||||
this.uuid = useStorage.get("uuid");
|
||||
}
|
||||
},
|
||||
// 关闭ws
|
||||
close() {
|
||||
if (this.log) console.log("关闭ws");
|
||||
@@ -49,91 +36,188 @@ export const useSocket = defineStore({
|
||||
2000,
|
||||
{ leading: true, trailing: false }
|
||||
),
|
||||
cartInit() {
|
||||
const store = useUser();
|
||||
const goodsStore = useGoods();
|
||||
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "cashier",
|
||||
account: `cashier_${store.shopInfo.id}`,
|
||||
operate_type: "init",
|
||||
shop_id: store.shopInfo.id,
|
||||
table_code:
|
||||
goodsStore.tableInfo.tableCode || useStorage.get("tableCode"),
|
||||
})
|
||||
);
|
||||
},
|
||||
// 初始化
|
||||
init(wsUrl = import.meta.env.VITE_API_WSS) {
|
||||
this.createUUID();
|
||||
const store = useUser();
|
||||
const printStore = usePrint();
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = useUser();
|
||||
const printStore = usePrint();
|
||||
const goodsStore = useGoods();
|
||||
|
||||
printStore.init();
|
||||
if (!store.shopInfo.id) return;
|
||||
|
||||
if (this.ws == null) {
|
||||
if (this.log) console.log("创建新的ws连接");
|
||||
printStore.init();
|
||||
|
||||
const protocols = []; // 可选的子协议数组
|
||||
const options = {
|
||||
// 自动重新连接的选项(可选)
|
||||
connectionTimeout: 1000,
|
||||
maxRetries: 100,
|
||||
};
|
||||
this.ws = new ReconnectingWebSocket(wsUrl, protocols, options);
|
||||
} else {
|
||||
if (this.log) console.log("重新连接ws");
|
||||
this.wsReconnect();
|
||||
}
|
||||
if (this.ws == null) {
|
||||
if (this.log) console.log("创建新的ws连接");
|
||||
|
||||
this.ws.addEventListener("open", (event) => {
|
||||
if (this.log) console.log("wss连接成功");
|
||||
this.online = true;
|
||||
// 清除心跳
|
||||
this.clearHeartBeat();
|
||||
const protocols = []; // 可选的子协议数组
|
||||
const options = {
|
||||
// 自动重新连接的选项(可选)
|
||||
connectionTimeout: 1000,
|
||||
maxRetries: 100,
|
||||
};
|
||||
this.ws = new ReconnectingWebSocket(wsUrl, protocols, options);
|
||||
} else {
|
||||
if (this.log) console.log("重新连接ws");
|
||||
this.wsReconnect();
|
||||
}
|
||||
|
||||
if (this.log) console.log(this);
|
||||
this.ws.addEventListener("open", (event) => {
|
||||
if (this.log) console.log("wss连接成功");
|
||||
this.online = true;
|
||||
// 清除心跳
|
||||
this.clearHeartBeat();
|
||||
if (this.log) console.log(this);
|
||||
this.cartInit();
|
||||
this.startheartbeat();
|
||||
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "connect",
|
||||
shopId: store.userInfo.shopId,
|
||||
clientId: this.uuid,
|
||||
})
|
||||
);
|
||||
this.startheartbeat();
|
||||
});
|
||||
resolve()
|
||||
});
|
||||
|
||||
this.ws.addEventListener("message", async (e) => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.operate_type == "init") {
|
||||
// console.log("接收消息", data);
|
||||
if (!goodsStore.tableInfo.tableCode) {
|
||||
useStorage.set("tableCode", data.table_code);
|
||||
}
|
||||
goodsStore.getCartList(data.data);
|
||||
}
|
||||
|
||||
this.ws.addEventListener("message", (e) => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.type == "order") {
|
||||
if (this.log) console.log("接收消息", data);
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "send",
|
||||
orderNo: data.orderInfo.orderNo,
|
||||
type: "receipt",
|
||||
msg_id: data.msg_id,
|
||||
})
|
||||
);
|
||||
// 接收订单消息,打印小票
|
||||
// printBill(data)
|
||||
// 打印标签小票
|
||||
if (!this.orderList.some((el) => el == data.orderInfo.orderNo)) {
|
||||
// console.log("打印", data);
|
||||
printStore.labelPrint(data);
|
||||
printStore.pushReceiptData(data);
|
||||
this.orderList.push(data.orderInfo.orderNo);
|
||||
if (this.orderList.length > 30) {
|
||||
this.orderList.splice(0, 1);
|
||||
|
||||
if (data.data_type == "cart") {
|
||||
if (data.status == 1) {
|
||||
// 返回成功状态
|
||||
switch (data.operate_type) {
|
||||
case "add":
|
||||
// 添加购物车商品
|
||||
goodsStore.successAddCart(data.data);
|
||||
break;
|
||||
case "edit":
|
||||
// 编辑购物车商品
|
||||
goodsStore.successEditCart(data.data);
|
||||
break;
|
||||
case "del":
|
||||
// 删除购物车商品
|
||||
if (data.type && data.type == "bc") {
|
||||
goodsStore.successDeleteCartItem(data.data);
|
||||
} else {
|
||||
goodsStore.successDeleteCartItem();
|
||||
}
|
||||
break;
|
||||
case "cleanup":
|
||||
// 清空购物车
|
||||
if (
|
||||
data.data.table_code == goodsStore.orderListInfo.tableCode &&
|
||||
!data.type
|
||||
)
|
||||
return;
|
||||
goodsStore.successClearCart();
|
||||
break;
|
||||
case "batch":
|
||||
// 整单打包
|
||||
this.cartInit();
|
||||
break;
|
||||
case "rottable":
|
||||
// 转桌
|
||||
useStorage.set("tableCode", data.data.new_table_code);
|
||||
goodsStore.successClearCart();
|
||||
goodsStore.historyOrderAjax(data.data.new_table_code);
|
||||
this.cartInit();
|
||||
break;
|
||||
case "clearOrder":
|
||||
// 清空订单或删除订单
|
||||
goodsStore.historyOrderAjax(data.data.table_code);
|
||||
break;
|
||||
case "bulk_edit":
|
||||
// 限时折扣更新
|
||||
// goodsStore.updateGoodsList();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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") {
|
||||
// 收到订单消息,打印订单小票
|
||||
let orderInfo = data.data.split("_");
|
||||
let orderId = orderInfo[0]; // 订单ID
|
||||
let orderModel = orderInfo[1]; // 订单类型
|
||||
let orderStatus = orderInfo[2]; // 订单状态
|
||||
|
||||
let printList = useStorage.get("printList") || [];
|
||||
|
||||
if (goodsStore.orderListInfo.tableCode) {
|
||||
goodsStore.historyOrderAjax(goodsStore.orderListInfo.tableCode);
|
||||
}
|
||||
|
||||
// 防止重复打印
|
||||
if (!printList.some((el) => el == orderId) && orderStatus == 1) {
|
||||
printList.push(orderId);
|
||||
useStorage.set("printList", _.uniq(printList));
|
||||
|
||||
this.orderList.push(orderId);
|
||||
this.startPrintInterval();
|
||||
}
|
||||
} else if (data.data_type == "product_update") {
|
||||
// 商品更新
|
||||
this.updateGoods();
|
||||
}
|
||||
} else if (data.type == "heartbeat") {
|
||||
if (this.log) console.log("接收心跳");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", () => {
|
||||
if (this.log) console.log("WebSocket连接发生错误");
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
this.ws.addEventListener("error", () => {
|
||||
if (this.log) console.log("WebSocket连接发生错误");
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
reject('WebSocket连接发生错误')
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", (e) => {
|
||||
if (this.log) console.log("ws关闭了", e);
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
this.ws.addEventListener("error", (e) => {
|
||||
if (this.log) console.log("ws关闭了", e);
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
})
|
||||
},
|
||||
updateGoods: _.throttle(function () {
|
||||
const goodsStore = useGoods();
|
||||
goodsStore.updateGoodsList();
|
||||
}, 1000),
|
||||
// 启动心跳连接
|
||||
startheartbeat() {
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
if (this.log) console.log("发送心跳");
|
||||
this.ws.send(JSON.stringify({ type: "heartbeat" }));
|
||||
this.ws.send(JSON.stringify({ type: "ping_interval", set: "cashier" }));
|
||||
}, 10000);
|
||||
},
|
||||
// 清除心跳
|
||||
@@ -142,5 +226,37 @@ export const useSocket = defineStore({
|
||||
clearInterval(this.heartbeatTimer);
|
||||
this.heartbeatTimer = null;
|
||||
},
|
||||
// 打印队列开始执行
|
||||
startPrintInterval() {
|
||||
if (this.isPrinting) return; // 如果正在打印,直接返回
|
||||
this.isPrinting = true; // 标记为正在打印
|
||||
let printTime = 2000; // 定时器
|
||||
const printStore = usePrint();
|
||||
const printNextOrder = async () => {
|
||||
try {
|
||||
if (!this.orderList.length) {
|
||||
this.isPrinting = false; // 订单处理完,标记为不在打印
|
||||
return;
|
||||
}
|
||||
const orderInfo = await getOrderByIdAjax(this.orderList[0]);
|
||||
if (orderInfo.status == "done") {
|
||||
// 打印订单小票
|
||||
printStore.pushReceiptData(commOrderPrintData(orderInfo));
|
||||
// 打印标签小票
|
||||
printStore.labelPrint(commOrderPrintData(orderInfo));
|
||||
}
|
||||
this.orderList.splice(0, 1);
|
||||
// 递归调用打印下一个订单
|
||||
setTimeout(printNextOrder, printTime);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// 发生错误时继续尝试下一个订单
|
||||
// this.orderList.splice(0, 1);
|
||||
setTimeout(printNextOrder, printTime);
|
||||
}
|
||||
};
|
||||
// 开始打印第一个订单
|
||||
printNextOrder();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,24 +1,174 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { login } from "@/api/user";
|
||||
import {
|
||||
login,
|
||||
shopStaffInfo,
|
||||
shopInfo_detail,
|
||||
logout,
|
||||
shopExtendDetail,
|
||||
shopPagePermissionMine,
|
||||
} from "@/api/account.js";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
export const useUser = defineStore({
|
||||
id: "user",
|
||||
export const useUser = defineStore("user", {
|
||||
state: () => ({
|
||||
userInfo: useStorage.get("userInfo"),
|
||||
shopInfo: useStorage.get("shopInfo"),
|
||||
token: useStorage.get("token"),
|
||||
loginType: useStorage.get("loginType") || 0,
|
||||
menus: [
|
||||
{
|
||||
label: "收银",
|
||||
path: "/",
|
||||
state: 0,
|
||||
icon: "ShoppingCartFull",
|
||||
},
|
||||
],
|
||||
menuList: [
|
||||
{
|
||||
label: "台桌",
|
||||
path: "/table",
|
||||
icon: "Reading",
|
||||
},
|
||||
{
|
||||
label: "团购",
|
||||
path: "/group_buy",
|
||||
icon: "Handbag",
|
||||
},
|
||||
{
|
||||
label: "订单",
|
||||
path: "/order",
|
||||
icon: "Tickets",
|
||||
},
|
||||
{
|
||||
label: "会员",
|
||||
path: "/member",
|
||||
icon: "User",
|
||||
},
|
||||
{
|
||||
label: "排队",
|
||||
path: "/queue",
|
||||
icon: "Timer",
|
||||
},
|
||||
],
|
||||
route: null,
|
||||
router: null,
|
||||
}),
|
||||
actions: {
|
||||
// 登录
|
||||
userlogin(param) {
|
||||
return login(param).then((res) => {
|
||||
this.userInfo = res;
|
||||
this.token = res.token;
|
||||
return login(param).then(async (res) => {
|
||||
this.token = res.tokenInfo.tokenValue;
|
||||
useStorage.set("token", this.token);
|
||||
// this.userInfo.shopId = "24";
|
||||
useStorage.set("userInfo", this.userInfo);
|
||||
return this.userInfo;
|
||||
|
||||
const logo = shopExtendDetail({ autoKey: "ticket_logo" });
|
||||
useStorage.set("shopInfo", {
|
||||
...res.shopInfo,
|
||||
ticketLogo: logo ? logo.value : "",
|
||||
});
|
||||
this.shopInfo = useStorage.get("shopInfo");
|
||||
useStorage.set("loginType", param.loginType);
|
||||
this.shopPagePermissionMineAjax(param.loginType);
|
||||
return await this.shopStaffInfo();
|
||||
});
|
||||
},
|
||||
// 初始化路由信息
|
||||
initRoute() {
|
||||
this.route = useRoute();
|
||||
this.router = useRouter();
|
||||
},
|
||||
// 获取当前员工已拥有页面路径
|
||||
async shopPagePermissionMineAjax(loginType = useStorage.get("loginType")) {
|
||||
try {
|
||||
if (this.route == null) {
|
||||
this.initRoute();
|
||||
}
|
||||
if (loginType == 0) {
|
||||
this.menus[0].state = 1;
|
||||
this.menus.push(...this.menuList);
|
||||
} else {
|
||||
const res = await shopPagePermissionMine();
|
||||
|
||||
let pathFlag = true;
|
||||
res.map((item) => {
|
||||
if (item.path == "/") {
|
||||
this.menus[0].state = 1;
|
||||
}
|
||||
|
||||
if (this.route.path != item.path) {
|
||||
pathFlag = false;
|
||||
}
|
||||
|
||||
this.menuList.map((menu) => {
|
||||
if (item.path === menu.path) {
|
||||
this.menus.push(menu);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log("当前路由===", this.route);
|
||||
if (!pathFlag) {
|
||||
this.router.push("/");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("获取当前员工已拥有页面路径失败===", error);
|
||||
}
|
||||
},
|
||||
// 获取用户信息
|
||||
async shopStaffInfo() {
|
||||
try {
|
||||
const res = await shopStaffInfo();
|
||||
useStorage.set("userInfo", res);
|
||||
this.userInfo = useStorage.get("userInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 更新店铺信息
|
||||
async getShopInfo() {
|
||||
try {
|
||||
const res = await shopInfo_detail();
|
||||
// 获取标签小票的logo
|
||||
const logo = await shopExtendDetail({ autoKey: "ticket_logo" });
|
||||
useStorage.set("shopInfo", {
|
||||
...res,
|
||||
ticketLogo: logo ? logo.value : "",
|
||||
});
|
||||
this.shopInfo = useStorage.get("shopInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 退出登录
|
||||
async logout() {
|
||||
try {
|
||||
const socket = useSocket();
|
||||
await logout();
|
||||
socket.close();
|
||||
|
||||
useStorage.del("userInfo");
|
||||
useStorage.del("shopInfo");
|
||||
useStorage.del("token");
|
||||
useStorage.del("douyin");
|
||||
useStorage.del("categoryIndex");
|
||||
useStorage.del("tableCode");
|
||||
|
||||
this.userInfo = {};
|
||||
this.shopInfo = {};
|
||||
this.token = "";
|
||||
this.menus = [
|
||||
{
|
||||
label: "收银",
|
||||
path: "/",
|
||||
state: 0,
|
||||
icon: "ShoppingCartFull",
|
||||
},
|
||||
];
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
499
src/utils/coupon-utils.js
Normal file
499
src/utils/coupon-utils.js
Normal file
@@ -0,0 +1,499 @@
|
||||
import { BigNumber } from "bignumber.js";
|
||||
import _ from "lodash";
|
||||
|
||||
/**
|
||||
* 返回商品单价
|
||||
* @param goods 商品
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo
|
||||
*/
|
||||
export function returnGoodsPrice(goods, user, shopInfo) {
|
||||
if (!goods) {
|
||||
return 0;
|
||||
}
|
||||
if (goods.discount_sale_amount * 1 > 0) {
|
||||
return goods.discount_sale_amount;
|
||||
}
|
||||
if (shopInfo && !shopInfo.isMemberPrice) {
|
||||
return goods.salePrice;
|
||||
}
|
||||
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) {
|
||||
return goods.memberPrice;
|
||||
}
|
||||
return goods.salePrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品分组
|
||||
* @param arr 商品列表
|
||||
*/
|
||||
export function returnGoodsGroupMap(arr) {
|
||||
let map = {};
|
||||
arr.forEach((v) => {
|
||||
const key = v.productId + "_" + v.skuId;
|
||||
if (!map[key]) {
|
||||
map[key] = [];
|
||||
}
|
||||
map[key].push(v);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||||
* @param coupon
|
||||
*/
|
||||
export function returnCoupType(coupon) {
|
||||
const couponTypes = {
|
||||
1: "满减券",
|
||||
2: "商品券",
|
||||
3: "折扣券",
|
||||
4: "第二件半价券",
|
||||
5: "消费送券",
|
||||
6: "买一送一券",
|
||||
7: "固定价格券",
|
||||
8: "免配送费券",
|
||||
};
|
||||
return couponTypes[coupon.type] || "未知类型";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品券抵扣后的商品列表
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param user 用户信息
|
||||
*/
|
||||
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
|
||||
const types = [2, 4, 6];
|
||||
// 收集已抵扣商品并关联对应的优惠券类型
|
||||
const goodsCouponGoods = selCoupon
|
||||
.filter((v) => types.includes(v.type))
|
||||
.reduce((prev, cur) => {
|
||||
// 给每个抵扣商品添加所属优惠券类型
|
||||
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
|
||||
...goods,
|
||||
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
|
||||
}));
|
||||
prev.push(...goodsWithType);
|
||||
return prev;
|
||||
}, []);
|
||||
const arr = _.cloneDeep(canDikouGoodsArr)
|
||||
.map((v) => {
|
||||
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
|
||||
if (findCart) {
|
||||
// 根据优惠券类型判断扣减数量
|
||||
if ([4, 6].includes(findCart.couponType)) {
|
||||
// 类型4(第二件半价)或6(买一送一),数量减2
|
||||
v.num -= 2;
|
||||
} else {
|
||||
// 其他类型(如类型2商品券),按原逻辑扣减对应数量
|
||||
v.num -= findCart.num;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
})
|
||||
.filter((v) => v.num > 0); // 过滤掉数量<=0的商品
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断优惠券是否可使用,并返回不可用原因
|
||||
*
|
||||
* @param {Object} args - 函数参数集合
|
||||
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表
|
||||
* @param {Object} args.coupon - 优惠券信息对象
|
||||
* @param {boolean} args.coupon.use - 优惠券是否启用
|
||||
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表
|
||||
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
|
||||
* @param {number} args.coupon.type - 优惠券类型
|
||||
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额
|
||||
* @param {Object} args.user - 用户信息对象
|
||||
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
|
||||
* @param {Object} args.shopInfo
|
||||
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
|
||||
*/
|
||||
export function returnCouponCanUse(args) {
|
||||
let { canDikouGoodsArr, coupon, goodsOrderPrice, user, selCoupon, shopInfo } = args;
|
||||
// 优惠券未启用
|
||||
if (!coupon.use) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: coupon.noUseRestrictions || "不在可用时间段内",
|
||||
};
|
||||
}
|
||||
|
||||
// 计算门槛金额
|
||||
let fullAmount = goodsOrderPrice;
|
||||
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user, shopInfo);
|
||||
//优惠券指定门槛商品列表
|
||||
let canCalcGoodsArr = [...canDikouGoodsArr];
|
||||
//部分商品参与门槛计算
|
||||
if (coupon.thresholdFoods.length) {
|
||||
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.thresholdFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||||
return pre + returnGoodsPrice(cur, user, shopInfo) * cur.num;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 是否全部商品可用
|
||||
const isDikouAll = coupon.useFoods.length === 0;
|
||||
// 订单可用商品列表
|
||||
let canUseGoodsArr = [];
|
||||
if (!isDikouAll) {
|
||||
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.useFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
}
|
||||
if (user.isVip && !coupon.vipPriceShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "非会员可用",
|
||||
};
|
||||
}
|
||||
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
// 满减券和折扣券计算门槛金额是否满足
|
||||
if ([1, 3].includes(coupon.type)) {
|
||||
if (canCalcGoodsArr.length <= 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有可参与计算门槛的商品",
|
||||
};
|
||||
}
|
||||
// 不满足门槛金额
|
||||
if (fullAmount < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
}
|
||||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||||
if ([2, 4, 5].includes(coupon.type)) {
|
||||
if (coupon.type == 2 && fullAmount < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
if (!isDikouAll && canUseGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
}
|
||||
//商品兑换券是否达到门槛金额
|
||||
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 买一送一券特殊验证
|
||||
if (coupon.type === 6) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 第二件半价券特殊验证
|
||||
if (coupon.type === 4) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 所有条件都满足
|
||||
return {
|
||||
canUse: true,
|
||||
reason: "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算抵扣商品金额
|
||||
* @param discountGoodsArr 可抵扣商品列表
|
||||
* @param discountNum 抵扣数量
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo 店铺信息
|
||||
*/
|
||||
export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo) {
|
||||
let hasCountNum = 0;
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
for (let i = 0; i < discountGoodsArr.length; i++) {
|
||||
if (hasCountNum >= discountNum) {
|
||||
break;
|
||||
}
|
||||
const goods = discountGoodsArr[i];
|
||||
const shengyuNum = discountNum - hasCountNum;
|
||||
const num = Math.min(goods.num, shengyuNum);
|
||||
discountPrice += returnGoodsPrice(goods, user, shopInfo) * num;
|
||||
|
||||
hasCountNum += num;
|
||||
hasDiscountGoodsArr.push({
|
||||
...goods,
|
||||
num,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算优惠券抵扣金额
|
||||
* @param arr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon, shopInfo) {
|
||||
arr=returnCanDikouGoods(arr,user,shopInfo)
|
||||
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user);
|
||||
console.log('canDikouGoodsArr',canDikouGoodsArr)
|
||||
if (coupon.type == 2) {
|
||||
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
}
|
||||
if (coupon.type == 6) {
|
||||
const result = returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
return result;
|
||||
}
|
||||
if (coupon.type == 4) {
|
||||
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
}
|
||||
if (coupon.type == 3) {
|
||||
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 折扣券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
*
|
||||
*/
|
||||
export function returnCouponZhekouDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
goodsOrderPrice,
|
||||
selCoupon
|
||||
) {
|
||||
const { discountRate, maxDiscountAmount } = coupon;
|
||||
|
||||
// 计算商品优惠券折扣总和,使用BigNumber避免精度问题
|
||||
const goodsCouponDiscount = selCoupon
|
||||
.filter((v) => v.type == 2)
|
||||
.reduce((prve, cur) => {
|
||||
return new BigNumber(prve).plus(new BigNumber(cur.discount.discountPrice));
|
||||
}, new BigNumber(0));
|
||||
|
||||
// 将商品订单价格转换为BigNumber并减去优惠券折扣
|
||||
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(goodsCouponDiscount);
|
||||
|
||||
// 计算优惠比例:(100 - 折扣率) / 100
|
||||
const discountAmountRatio = new BigNumber(100).minus(discountRate).dividedBy(100);
|
||||
|
||||
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
|
||||
let discountPrice = adjustedGoodsOrderPrice
|
||||
.times(discountAmountRatio)
|
||||
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
|
||||
.toNumber();
|
||||
|
||||
// 应用最大折扣金额限制
|
||||
if (maxDiscountAmount !== 0) {
|
||||
discountPrice = discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice, // 折扣抵扣金额(即优惠的金额)
|
||||
hasDiscountGoodsArr: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, discountNum, useRule } = coupon;
|
||||
//抵扣商品数组
|
||||
let discountGoodsArr = [];
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
} else {
|
||||
//抵扣选中商品
|
||||
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
|
||||
useFoods.find((food) => food.id == v.productId)
|
||||
);
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
}
|
||||
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 返回买一送一券抵扣详情
|
||||
/**
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合买一送一条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
console.log("returnCouponBuyOneGiveOneDiscount:discountGoods", discountGoods);
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
return {
|
||||
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回第二件半价券抵扣详情
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
//返回半价价格
|
||||
return {
|
||||
discountPrice: discountPrice <= 0 ? 0 : new BigNumber(discountPrice).dividedBy(2).toNumber(),
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
|
||||
* @param arr 商品列表
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCanDikouGoods(arr, user, shopInfo) {
|
||||
const result = arr
|
||||
.filter((v) => {
|
||||
return v.is_temporary != 1 && v.is_gift != 1;
|
||||
})
|
||||
.filter((v) => {
|
||||
return v.num > 0;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return returnGoodsPrice(b, user, shopInfo) - returnGoodsPrice(a, user, shopInfo);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
import { getOrderById } from "@/api/order.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
/**
|
||||
* 生成范围随机数
|
||||
* @param {Object} Min
|
||||
@@ -15,20 +19,29 @@ export function RandomNumBoth(Max, Min = 0) {
|
||||
* @param {Object} obj
|
||||
*/
|
||||
export function clearNoNum(obj) {
|
||||
//如果用户第一位输入的是小数点,则重置输入框内容
|
||||
// 如果用户第一位输入的是小数点,则重置输入框内容
|
||||
if (obj.value != "" && obj.value.substr(0, 1) == ".") {
|
||||
obj.value = "";
|
||||
}
|
||||
obj.value = obj.value.replace(/^0*(0\.|[1-9])/, "$1"); //粘贴不生效
|
||||
obj.value = obj.value.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
|
||||
obj.value = obj.value.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
|
||||
|
||||
// 去除数字前面多余的 0,但保留 0. 这种情况
|
||||
obj.value = obj.value.replace(/^0*(0\.|[1-9])/, "$1");
|
||||
|
||||
// 清除“数字”和“.”以外的字符
|
||||
obj.value = obj.value.replace(/[^\d.]/g, "");
|
||||
|
||||
// 只保留第一个. 清除多余的
|
||||
obj.value = obj.value.replace(/\.{2,}/g, ".");
|
||||
obj.value = obj.value
|
||||
.replace(".", "$#$")
|
||||
.replace(/\./g, "")
|
||||
.replace("$#$", ".");
|
||||
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3"); //只能输入两个小数
|
||||
|
||||
// 只能输入两个小数
|
||||
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3");
|
||||
|
||||
if (obj.value.indexOf(".") < 0 && obj.value != "") {
|
||||
//以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
|
||||
// 以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02 的金额
|
||||
if (obj.value.substr(0, 1) == "0" && obj.value.length == 2) {
|
||||
obj.value = obj.value.substr(1, obj.value.length);
|
||||
}
|
||||
@@ -96,3 +109,97 @@ export function inputFilterFloat(value) {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将手机号中间四位替换为*号
|
||||
* @param {*} phone
|
||||
* @returns
|
||||
*/
|
||||
export function formatPhoneNumber(phone, isFormat = true) {
|
||||
if (isFormat) {
|
||||
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
||||
} else {
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* @param {*} orderId
|
||||
* @returns
|
||||
*/
|
||||
export async function getOrderByIdAjax(orderId) {
|
||||
try {
|
||||
if (!orderId) return;
|
||||
const res = await getOrderById({ orderId: orderId });
|
||||
|
||||
let arr = [];
|
||||
for (let key in res.detailMap) {
|
||||
arr.push(res.detailMap[key]);
|
||||
}
|
||||
|
||||
arr = arr.flat();
|
||||
arr.map((item) => {
|
||||
if (item.productType == "package" && item.proGroupInfo) {
|
||||
item.proGroupInfo = JSON.parse(item.proGroupInfo).flat();
|
||||
}
|
||||
});
|
||||
res.cartList = arr;
|
||||
return Promise.resolve(res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将订单小票打印的数据组合起来
|
||||
* @param {*} orderDetail
|
||||
*/
|
||||
export function commOrderPrintData(orderInfo) {
|
||||
const userStore = useUser();
|
||||
let data = {
|
||||
isBefore: orderInfo.isBefore || false,
|
||||
shop_name: userStore.shopInfo.shopName,
|
||||
loginAccount: userStore.userInfo.name,
|
||||
carts: [],
|
||||
amount: formatDecimal(+orderInfo.payAmount),
|
||||
originAmount: formatDecimal(+orderInfo.originAmount),
|
||||
discountAmount:
|
||||
orderInfo.status == "unpaid"
|
||||
? "0.00"
|
||||
: formatDecimal(orderInfo.originAmount - orderInfo.orderAmount),
|
||||
discount: orderInfo.discountRatio,
|
||||
remark: orderInfo.remark,
|
||||
orderInfo: orderInfo,
|
||||
outNumber: orderInfo.tableCode,
|
||||
createdAt: orderInfo.createTime,
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
|
||||
orderInfo.cartList.map((item) => {
|
||||
data.carts.push({
|
||||
categoryId: item.categoryId,
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.skuName,
|
||||
salePrice: formatDecimal(+item.price),
|
||||
totalAmount: formatDecimal(+item.payAmount),
|
||||
proGroupInfo: item.proGroupInfo
|
||||
? item.proGroupInfo.map((item) => item.goods).flat()
|
||||
: "",
|
||||
});
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验手机号
|
||||
* @param {*} phone
|
||||
* @returns
|
||||
*/
|
||||
export function regPhone(phone) {
|
||||
let reg = /^(?:(?:\+|00)86)?1\d{10}$/;
|
||||
return reg.test(phone);
|
||||
}
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
import axios from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import router from '@/router'
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import router from "@/router";
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.MODE == 'development' ? '/api/' : import.meta.env.VITE_API_URL,
|
||||
baseURL:
|
||||
import.meta.env.MODE == "development"
|
||||
? "/api/"
|
||||
: import.meta.env.VITE_API_URL,
|
||||
// withCredentials: true, // 跨域请求时发送 cookies
|
||||
timeout: 5000, // 请求超时
|
||||
timeout: 20000, // 请求超时
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前做些什么 token
|
||||
config.headers["platformType"] = "PC";
|
||||
if (useStorage.get("token")) {
|
||||
// 让每个请求携带 token
|
||||
// ['X-Token'] 是自定义标题键
|
||||
// 请根据实际情况修改
|
||||
config.headers["token"] = useStorage.get("token");
|
||||
config.headers["loginName"] = useStorage.get("userInfo").loginName;
|
||||
config.headers["clientType"] = 'pc';
|
||||
if (useStorage.get("shopInfo") && useStorage.get("shopInfo").id) {
|
||||
config.headers["shopId"] = useStorage.get("shopInfo").id;
|
||||
}
|
||||
// config.headers["loginName"] = useStorage.get("userInfo").loginName;
|
||||
// config.headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
return config;
|
||||
@@ -35,18 +41,20 @@ service.interceptors.response.use(
|
||||
(response) => {
|
||||
// 对响应数据做点什么
|
||||
if (+response.status === 200) {
|
||||
if (+response.data.code == '0') {
|
||||
if (+response.data.code == 200) {
|
||||
return response.data.data;
|
||||
} else if (+response.data.code == '9999') {
|
||||
ElMessage.error('登录已过期,请重新登录')
|
||||
useStorage.clear()
|
||||
router.replace("/login")
|
||||
window.location.reload()
|
||||
return Promise.reject('登录已过期,请重新登录')
|
||||
} else if (+response.data.code == 501) {
|
||||
useStorage.del("token");
|
||||
useStorage.del("userInfo");
|
||||
useStorage.del("shopInfo");
|
||||
useStorage.del("douyin");
|
||||
ElMessage.error("登录已过期,请重新登录");
|
||||
window.location.reload();
|
||||
return Promise.reject("登录已过期,请重新登录");
|
||||
} else {
|
||||
// 响应错误
|
||||
ElMessage.error(response.data.msg)
|
||||
return Promise.reject(response.data)
|
||||
ElMessage.error(response.data.msg);
|
||||
return Promise.reject(response.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="device_container">
|
||||
<div class="device_container" v-loading="requestLoading">
|
||||
<div class="header" @click="router.back()">
|
||||
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
|
||||
<ArrowLeft />
|
||||
@@ -9,28 +9,31 @@
|
||||
<div class="d_content">
|
||||
<div class="d_list">
|
||||
<el-form :model="form" label-position="left" label-width="60%">
|
||||
<el-form-item label="设备名称">
|
||||
<el-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="打印机品牌">
|
||||
<el-input v-model="form.contentType" placeholder="请输入打印机品牌"></el-input>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="设备尺寸">
|
||||
<el-select v-model="form.config.width">
|
||||
<el-option label="58mm" value="58"></el-option>
|
||||
<el-option label="80mm" value="80"></el-option>
|
||||
<el-select v-model="form.receiptSize">
|
||||
<el-option label="58mm" value="58mm"></el-option>
|
||||
<el-option label="80mm" value="80mm"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型">
|
||||
<el-select v-model="form.connectionType">
|
||||
<el-option label="USB" value="USB"></el-option>
|
||||
<el-option label="网络" value="network"></el-option>
|
||||
<!-- <el-option label="网络" value="network"></el-option> -->
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择设备">
|
||||
<el-select v-model="form.config.deviceName">
|
||||
<el-select v-model="form.address">
|
||||
<el-option :label="item.name" :value="item.name" v-for="item in printList" :key="item.name"></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-select v-model="form.config.printerNum">
|
||||
<!-- <el-form-item label="打印份数">
|
||||
<el-select v-model="form.printQty">
|
||||
<el-option :label="item" :value="item" v-for="item in 4" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -56,13 +59,18 @@
|
||||
<el-select v-model="form.config.feet">
|
||||
<el-option :label="`${item}行`" :value="`${item}`" v-for="item in feets" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="menu_wrap">
|
||||
<div class="print_view">
|
||||
<div class="title t1">{{ printData.shop_name }}</div>
|
||||
<div class="title t2">预结算单【{{ printData.orderInfo.masterId }}】</div>
|
||||
<div class="title t2">
|
||||
预结算单 <span style="margin-left: 6px;">#{{ printData.orderInfo.orderNum }}</span>
|
||||
</div>
|
||||
<div class="title t2" style="margin-bottom: 20px;">
|
||||
桌号:无
|
||||
</div>
|
||||
<div class="row">订单号:{{ printData.orderInfo.orderNo }}</div>
|
||||
<div class="row">交易时间:{{ printData.createdAt }}</div>
|
||||
<div class="row">收银员:{{ printData.loginAccount }}</div>
|
||||
@@ -86,27 +94,32 @@
|
||||
</table>
|
||||
<div class="line"></div>
|
||||
<div class="row between">
|
||||
<span>合计:</span>
|
||||
<span>{{ printData.amount }}</span>
|
||||
<span>原价:</span>
|
||||
<span>{{ printData.originAmount }}</span>
|
||||
</div>
|
||||
<div class="row between">
|
||||
<span>余额:</span>
|
||||
<span>0.00</span>
|
||||
<span>折扣:</span>
|
||||
<span>-0.00</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">备注:{{ printData.remark }}</div>
|
||||
<div class="row">打印时间:{{ printData.printTime }}</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%" :loading="printDataLoading" @click="printHandle">
|
||||
打印测试小票
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="row between" style="font-size: 24px;">
|
||||
<span>实付:</span>
|
||||
<span>¥{{ printData.amount }}</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row" style="font-weight: bold;">备注:{{ printData.remark }}</div>
|
||||
<div class="row" style="font-size: 14px;">打印时间:{{ printData.printTime }}</div>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%" :loading="printDataLoading" @click="printHandle">
|
||||
打印测试小票
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,15 +128,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dayjs from 'dayjs'
|
||||
import dayjs from "dayjs";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { tbPrintMachinePost, tbPrintMachineDetail } from "@/api/device";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { Loading } from "element-plus/es/components/loading/src/service";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { printerAdd, printerDetail } from "@/api/account.js";
|
||||
|
||||
const printStore = usePrint();
|
||||
const store = useUser();
|
||||
@@ -134,61 +146,54 @@ const route = useRoute();
|
||||
const printList = ref([]);
|
||||
const feets = ref([0, 1, 2, 3, 4, 5, 8]);
|
||||
const loading = ref(false);
|
||||
const requestLoading = ref(false);
|
||||
const form = ref({
|
||||
id: "",
|
||||
contentType: "",
|
||||
connectionType: "USB",
|
||||
config: {
|
||||
deviceName: "",
|
||||
width: "58", // 设备尺寸毫米mm
|
||||
printerNum: 1, //打印份数
|
||||
categoryList: [], // 商品分类
|
||||
model: "normal", // 出品模式,
|
||||
feet: "2",
|
||||
autoCut: 0,
|
||||
printSub: 1,
|
||||
},
|
||||
name: "小票打印机",
|
||||
subType: "cash", // 打印类型
|
||||
status: 1,
|
||||
sort: "",
|
||||
shopId: store.userInfo.shopId,
|
||||
name: '', // 设备名称
|
||||
connectionType: 'USB', // 现在打印机支持USB 和 网络、蓝牙
|
||||
address: '', // 打印机名称
|
||||
port: '', // 端口
|
||||
subType: 'cash', // 打印类型(分类)label标签cash小票kitchen出品
|
||||
contentType: '', // 打印机品牌
|
||||
categoryIds: [], // 打印分类Id
|
||||
categoryList: [], // 分类
|
||||
sort: '',
|
||||
receiptSize: '58mm', // 小票尺寸 58mm 80mm
|
||||
classifyPrint: 1, // 分类打印 0-所有 1-部分分类 2-部分商品
|
||||
printQty: '', // 打印数量 c1m1^2 = 顾客+商家[2张] m1^1 = 商家[1张] c1^1顾客[1张] c2m1^3顾客2+商家1[3张]
|
||||
printMethod: 'all', // 打印方式 all-全部打印 normal-仅打印结账单「前台」one-仅打印制作单「厨房」queue-仅打印排队取号
|
||||
printType: [], // 打印类型,JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
|
||||
status: 1
|
||||
});
|
||||
|
||||
const printDataLoading = ref(false)
|
||||
const printDataLoading = ref(false);
|
||||
const printData = reactive({
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
shop_name: '',
|
||||
loginAccount: '',
|
||||
isBefore: true,
|
||||
carts: [
|
||||
{
|
||||
id: 1,
|
||||
name: '【测试】娃哈哈矿泉水',
|
||||
skuName: '500ml',
|
||||
salePrice: '1.0',
|
||||
number: '10',
|
||||
totalAmount: '10'
|
||||
name: "【测试勿管】娃哈哈矿泉水",
|
||||
skuName: "500ml",
|
||||
salePrice: "1.0",
|
||||
number: "10",
|
||||
totalAmount: "10",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '【测试】柠檬奶茶',
|
||||
skuName: '加冰、加珍珠',
|
||||
salePrice: '10',
|
||||
number: '2',
|
||||
totalAmount: '20'
|
||||
}
|
||||
],
|
||||
amount: '30.00',
|
||||
discountAmount: '30.00',
|
||||
amount: "10.00",
|
||||
originAmount: '10.00',
|
||||
discountAmount: "0.00",
|
||||
discount: 0,
|
||||
remark: '给我多放点辣椒,谢谢老板',
|
||||
remark: "给我多放点辣椒,谢谢老板",
|
||||
orderInfo: {
|
||||
masterId: '#002',
|
||||
orderNo: '202404021023542223445'
|
||||
masterId: "",
|
||||
orderNo: "202404021023542223445",
|
||||
orderNum: '12'
|
||||
},
|
||||
deviceName: '',
|
||||
createdAt: '2024-04-02 10:15',
|
||||
printTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
deviceName: "",
|
||||
createdAt: "2024-04-02 10:15",
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
|
||||
// 获取打印机列表
|
||||
@@ -201,50 +206,59 @@ function getPrintList() {
|
||||
|
||||
// 测试打印
|
||||
function printHandle() {
|
||||
if (!form.value.config.deviceName) {
|
||||
ElMessage.warning("请选择打印设备");
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
printDataLoading.value = true
|
||||
printData.deviceName = form.value.config.deviceName
|
||||
printData.printTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||
printStore.pushReceiptData(printData, false)
|
||||
printDataLoading.value = true;
|
||||
printData.shop_name = store.shopInfo.shopName
|
||||
printData.loginAccount = store.userInfo.name
|
||||
printData.deviceName = form.value.address;
|
||||
printData.printTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
printStore.pushReceiptData(printData, false);
|
||||
setTimeout(() => {
|
||||
printDataLoading.value = false
|
||||
}, 1500)
|
||||
printDataLoading.value = false;
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
// 提交打印机
|
||||
async function submitHandle() {
|
||||
try {
|
||||
if (!form.value.config.deviceName) {
|
||||
ElMessage.warning("请选择打印设备");
|
||||
if (!form.value.name) {
|
||||
ElMessage.error("请输入设备名称");
|
||||
return;
|
||||
}
|
||||
Loading.value = true;
|
||||
await tbPrintMachinePost(form.value, form.value.id ? "put" : "post");
|
||||
Loading.value = false;
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
await printerAdd(form.value, form.value.id ? "put" : "post");
|
||||
ElMessage.success(form.value.id ? "编辑成功" : "添加成功");
|
||||
|
||||
printStore.init();
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// 查询打印机详情
|
||||
async function tbPrintMachineDetailAjax() {
|
||||
async function tbPrintMachineDetailAjax(id) {
|
||||
try {
|
||||
const res = await tbPrintMachineDetail(route.query.id);
|
||||
requestLoading.value = true;
|
||||
const res = await printerDetail({ id: id });
|
||||
form.value = res;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
requestLoading.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
printData.shop_name = store.shopInfo.shopName
|
||||
printData.loginAccount = store.userInfo.name
|
||||
|
||||
getPrintList();
|
||||
if (route.query.id) {
|
||||
tbPrintMachineDetailAjax(route.query.id);
|
||||
@@ -282,13 +296,26 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.menu_wrap {
|
||||
flex: 1.5;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 0 15px;
|
||||
|
||||
.btn_wrap {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.print_view {
|
||||
flex: 1;
|
||||
padding: 20px 0;
|
||||
|
||||
.title {
|
||||
@@ -299,10 +326,6 @@ onMounted(() => {
|
||||
&.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&.t2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
@@ -314,15 +337,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.btn_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 20px 0;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 10px 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="device_container">
|
||||
<div class="device_container" v-loading="requestLoading">
|
||||
<div class="header" @click="router.back()">
|
||||
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
|
||||
<ArrowLeft />
|
||||
@@ -9,43 +9,32 @@
|
||||
<div class="d_content">
|
||||
<div class="d_list">
|
||||
<el-form :model="form" label-position="left" label-width="60%">
|
||||
<!-- <el-form-item label="设备尺寸">
|
||||
<el-select v-model="form.config.width">
|
||||
<el-option label="58mm" value="58"></el-option>
|
||||
<el-option label="80mm" value="80"></el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="设备类型">
|
||||
<el-select v-model="form.connectionType">
|
||||
<el-option label="USB" value="USB"></el-option>
|
||||
<el-option label="网络" value="network"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择设备">
|
||||
<el-select v-model="form.config.deviceName">
|
||||
<el-option :label="item.name" :value="item.name" v-for="item in printList" :key="item.name"></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-select v-model="form.config.printerNum">
|
||||
<el-option :label="item" :value="item" v-for="item in 4" :key="item"></el-option>
|
||||
<el-form-item label="设备尺寸">
|
||||
<el-select v-model="form.receiptSize">
|
||||
<el-option label="58mm" value="58mm"></el-option>
|
||||
<el-option label="80mm" value="80mm"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品模式">
|
||||
<el-select v-model="form.config.model">
|
||||
<el-option label="普通出单" value="normal"></el-option>
|
||||
<el-option label="分类出单" value="category"></el-option>
|
||||
<el-form-item label="设备类型">
|
||||
<el-select v-model="form.connectionType">
|
||||
<el-option label="USB" value="USB"></el-option>
|
||||
<!-- <el-option label="网络" value="network"></el-option> -->
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择设备">
|
||||
<el-select v-model="form.address">
|
||||
<el-option :label="item.name" :value="item.name" v-for="item in printList" :key="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类">
|
||||
<div style="cursor: pointer" @click="classifyRef.show()">
|
||||
<span style="color: #409eff" v-for="item in form.config.categoryList">
|
||||
{{ item.name }},
|
||||
<span style="color: #409eff" v-if="form.categoryList.length">
|
||||
{{form.categoryList.map(item => item.name).join(',')}}
|
||||
</span>
|
||||
<span style="color: #e65d6e" v-if="!form.config.categoryList.length">
|
||||
<span style="color: #e65d6e" v-else>
|
||||
请选择分类
|
||||
</span>
|
||||
</div>
|
||||
@@ -78,12 +67,12 @@
|
||||
<div class="print_view">
|
||||
<canvas class="ewm" ref="canvasRef"></canvas>
|
||||
<div class="header">
|
||||
<img class="logo" :src="shopInfo.info.ticketLogo" />
|
||||
<img class="logo" :src="printData.ticketLogo || logo" />
|
||||
<!-- <span class="title">双屿Pisces</span> -->
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
<div class="num" v-if="printData.outNumber">{{ printData.outNumber }}</div>
|
||||
<div class="info" v-if="printData.masterId">座位号:{{ printData.masterId }}</div>
|
||||
<!-- <div class="num" v-if="printData.outNumber">{{ printData.outNumber }}</div> -->
|
||||
<div class="info">座位号:{{ printData.masterId }}</div>
|
||||
</div>
|
||||
<div class="shop_info">
|
||||
<div class="name">{{ printData.name }}</div>
|
||||
@@ -94,7 +83,7 @@
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%" @click="printHandle">
|
||||
<el-button plain style="width: 100%" :loading="printLoading" @click="printHandle">
|
||||
打印测试小票
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -107,7 +96,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<classify ref="classifyRef" @success="(e) => (form.config.categoryList = e)" />
|
||||
<classify ref="classifyRef" @success="(e) => (form.categoryList = e)" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -116,45 +105,43 @@ import { ipcRenderer } from "electron";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { ElMessage, dayjs } from "element-plus";
|
||||
import { tbPrintMachinePost, tbPrintMachineDetail } from "@/api/device";
|
||||
import { printerAdd, printerDetail } from "@/api/account.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { Loading } from "element-plus/es/components/loading/src/service";
|
||||
import classify from "@/components/classify/index.vue";
|
||||
import QRCode from 'qrcode'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useShop } from "@/store/shop.js";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import logo from '@/assets/prinnt_label_logo.png';
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const printStore = usePrint();
|
||||
|
||||
const store = useUser();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const shopInfo = useShop();
|
||||
|
||||
const printLoading = ref(false);
|
||||
const classifyRef = ref(null);
|
||||
const printList = ref([]);
|
||||
const feets = ref([0, 1, 2, 3, 4, 5, 8]);
|
||||
const loading = ref(false);
|
||||
const requestLoading = ref(false);
|
||||
const form = ref({
|
||||
id: "",
|
||||
contentType: "",
|
||||
connectionType: "USB",
|
||||
config: {
|
||||
deviceName: "",
|
||||
width: "40", // 设备尺寸毫米mm
|
||||
printerNum: 1, //打印份数
|
||||
categoryList: [], // 商品分类
|
||||
model: "normal", // 出品模式,
|
||||
feet: "2",
|
||||
autoCut: 0,
|
||||
printSub: 1,
|
||||
},
|
||||
name: "标签打印机",
|
||||
subType: "label", // 打印类型
|
||||
status: 1,
|
||||
sort: "",
|
||||
shopId: store.userInfo.shopId,
|
||||
name: '', // 设备名称
|
||||
connectionType: 'USB', // 现在打印机支持USB 和 网络、蓝牙
|
||||
address: '', // 打印机名称
|
||||
port: '', // 端口
|
||||
subType: 'label', // 打印类型(分类)label标签cash小票kitchen出品
|
||||
contentType: '', // 打印机品牌
|
||||
categoryIds: [], // 打印分类Id
|
||||
categoryList: [], // 分类
|
||||
sort: '',
|
||||
receiptSize: '58mm', // 小票尺寸 58mm 80mm
|
||||
classifyPrint: 1, // 分类打印 0-所有 1-部分分类 2-部分商品
|
||||
printQty: '', // 打印数量 c1m1^2 = 顾客+商家[2张] m1^1 = 商家[1张] c1^1顾客[1张] c2m1^3顾客2+商家1[3张]
|
||||
printMethod: 'all', // 打印方式 all-全部打印 normal-仅打印结账单「前台」one-仅打印制作单「厨房」queue-仅打印排队取号
|
||||
printType: [], // 打印类型,JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
|
||||
status: 1
|
||||
});
|
||||
|
||||
const canvasRef = ref(null)
|
||||
@@ -165,7 +152,7 @@ const printData = ref({
|
||||
skuName: '测试、加珍珠',
|
||||
masterId: '#A9',
|
||||
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
ticketLogo: shopInfo.info.ticketLogo,
|
||||
ticketLogo: store.shopInfo.ticketLogo,
|
||||
})
|
||||
|
||||
// 获取打印机列表
|
||||
@@ -178,27 +165,40 @@ function getPrintList() {
|
||||
|
||||
// 测试打印
|
||||
const printHandle = _.throttle(function () {
|
||||
if (!form.value.config.deviceName) {
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
printData.value.deviceName = form.value.config.deviceName
|
||||
printLoading.value = true;
|
||||
printData.value.deviceName = form.value.address
|
||||
ipcRenderer.send(
|
||||
"printerTagSync",
|
||||
JSON.stringify(printData.value)
|
||||
);
|
||||
setTimeout(() => {
|
||||
printLoading.value = false;
|
||||
}, 2500);
|
||||
}, 1500, { leading: true, trailing: false })
|
||||
|
||||
// 提交打印机
|
||||
async function submitHandle() {
|
||||
try {
|
||||
if (!form.value.config.deviceName) {
|
||||
ElMessage.warning("请选择打印设备");
|
||||
if (!form.value.name) {
|
||||
ElMessage.error("请输入设备名称");
|
||||
return;
|
||||
}
|
||||
Loading.value = true;
|
||||
await tbPrintMachinePost(form.value, form.value.id ? "put" : "post");
|
||||
Loading.value = false;
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
if (!form.value.categoryList.length) {
|
||||
ElMessage.error("请选择商品分类");
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
form.value.categoryIds = form.value.categoryList.map(item => item.id)
|
||||
await printerAdd(form.value, form.value.id ? "put" : "post");
|
||||
loading.value = false;
|
||||
ElMessage.success(form.value.id ? "编辑成功" : "添加成功");
|
||||
printStore.init();
|
||||
router.back();
|
||||
@@ -210,12 +210,26 @@ async function submitHandle() {
|
||||
// 查询打印机详情
|
||||
async function tbPrintMachineDetailAjax() {
|
||||
try {
|
||||
const res = await tbPrintMachineDetail(route.query.id);
|
||||
requestLoading.value = true;
|
||||
const res = await printerDetail({ id: route.query.id });
|
||||
form.value = res;
|
||||
printData.value.deviceName = res.config.deviceName
|
||||
|
||||
let arr = []
|
||||
goodsStore.originCategoryList.map(item => {
|
||||
res.categoryList.map(val => {
|
||||
if (item.id == val) {
|
||||
arr.push({
|
||||
id: item.id,
|
||||
name: item.name
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
form.value.categoryList = arr
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
requestLoading.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -306,8 +320,8 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 12px;
|
||||
padding-bottom: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="xh">{{ item.config.deviceName }}</div>
|
||||
<div class="xh">{{ item.address }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
@@ -114,20 +114,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
tbPrintMachineGet,
|
||||
tbPrintMachineDelete,
|
||||
tbPrintMachinePost,
|
||||
} from "@/api/device";
|
||||
import { printerList, printerAdd } from '@/api/account.js'
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
import icons from "./icons";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
|
||||
const printStore = usePrint();
|
||||
const store = useUser();
|
||||
|
||||
const router = useRouter();
|
||||
const list = ref([]);
|
||||
@@ -142,7 +136,7 @@ const deviceRoute = ref({
|
||||
|
||||
async function statusChange(e, item) {
|
||||
try {
|
||||
await tbPrintMachinePost(item, "put");
|
||||
await printerAdd(item, "put");
|
||||
tbPrintMachineGetAjax();
|
||||
printStore.init();
|
||||
} catch (error) {
|
||||
@@ -160,8 +154,7 @@ function showDelete(item) {
|
||||
async function tbPrintMachineDeleteAjax() {
|
||||
try {
|
||||
delLoading.value = true;
|
||||
await tbPrintMachineDelete({ id: deleteId.value });
|
||||
delLoading.value = false;
|
||||
await printerAdd({ id: deleteId.value }, 'delete');
|
||||
dialogVisible.value = false;
|
||||
ElMessage.success("删除成功");
|
||||
tbPrintMachineGetAjax();
|
||||
@@ -169,17 +162,14 @@ async function tbPrintMachineDeleteAjax() {
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
delLoading.value = false;
|
||||
}
|
||||
|
||||
// 获取打印机列表
|
||||
async function tbPrintMachineGetAjax() {
|
||||
try {
|
||||
const res = await tbPrintMachineGet({
|
||||
shopId: store.userInfo.shopId,
|
||||
page: 0,
|
||||
pageSize: 100,
|
||||
});
|
||||
list.value = res.list;
|
||||
const res = await printerList();
|
||||
list.value = res.records;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ function refundConfirm() {
|
||||
emits('succcess')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
refundLoading.value = false
|
||||
}
|
||||
refundLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -200,9 +200,9 @@ async function groupOrdergroupScanHandle() {
|
||||
ElMessage.success('核销成功')
|
||||
emits('succcess')
|
||||
} catch (error) {
|
||||
groupDetailLoading.value = false
|
||||
console.log('groupOrdergroupScanHandle.error', error);
|
||||
}
|
||||
groupDetailLoading.value = false
|
||||
}
|
||||
|
||||
const douyin_table = ref(null)
|
||||
@@ -259,12 +259,12 @@ async function submitHandle() {
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log('submitHandle.error', error);
|
||||
if (error.code == 4399) {
|
||||
BindShopRef.value.show()
|
||||
}
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 重新扫码
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<el-table :data="tableData.list" height="540px" v-loading="tableData.loading"
|
||||
v-if="tableData.type == 2">
|
||||
<el-table-column label="抖音订单号" prop="d_order_id" width="240"></el-table-column>
|
||||
<el-table-column label="总金额" prop="pay_amount" width="100">
|
||||
<el-table-column label="总金额" prop="pay_amount">
|
||||
<template v-slot="scope">
|
||||
<span style="color: var(--primary-color);">¥{{ scope.row.pay_amount }}</span>
|
||||
</template>
|
||||
@@ -194,10 +194,10 @@ function payTypeFilter(t) {
|
||||
|
||||
// 订单类型
|
||||
const typeList = reactive([
|
||||
{
|
||||
value: 1,
|
||||
label: '自营'
|
||||
},
|
||||
// {
|
||||
// value: 1,
|
||||
// label: '自营'
|
||||
// },
|
||||
{
|
||||
value: 2,
|
||||
label: '抖音'
|
||||
|
||||
297
src/views/home/components/cartItem.vue
Normal file
297
src/views/home/components/cartItem.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div class="cart_item" :class="{ active: props.item.active, border: props.border }"
|
||||
@click="selectCartItemHandle(index)">
|
||||
<div class="name_wrap">
|
||||
<span>{{ props.item.product_name }}</span>
|
||||
<template v-if="props.item.is_gift">
|
||||
<div class="price">
|
||||
<span class="dis" v-if="props.item.is_temporary">
|
||||
¥{{ formatDecimal(+props.item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
<span class="dis" v-else>
|
||||
¥{{ formatDecimal(goodsStore.showVipPrice ? +props.item.memberPrice || +props.item.lowPrice :
|
||||
+props.item.lowPrice, 2,
|
||||
true) }}
|
||||
</span>
|
||||
<span v-if="props.item.discount_sale_amount">
|
||||
¥0.00
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="price" v-if="item.is_time_discount == 1 && item.discount_sale_amount <= 0">
|
||||
<span class="dis">
|
||||
¥{{ formatDecimal(+item.salePrice, 2, true) }}
|
||||
</span>
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.time_discount_price, 2, true) }}
|
||||
</span>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="price" v-if="props.item.is_temporary">
|
||||
<span>
|
||||
¥{{ formatDecimal(+props.item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="price" v-else>
|
||||
<template v-if="+item.discount_sale_amount > 0">
|
||||
<span class="dis">
|
||||
¥{{ formatDecimal(+item.salePrice, 2, true) }}
|
||||
</span>
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
</template>
|
||||
<div class="flex" v-else>
|
||||
<template v-if="goodsStore.showVipPrice && item.memberPrice > 0">
|
||||
<span class="dis">
|
||||
¥{{ formatDecimal(+props.item.salePrice, 2, true) }}
|
||||
</span>
|
||||
<span>
|
||||
¥{{ formatDecimal(+props.item.memberPrice, 2, true) }}
|
||||
</span>
|
||||
</template>
|
||||
<span v-else>
|
||||
¥{{ formatDecimal(+item.salePrice, 2, true) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<div class="remark_wrap" @click="showRemark(props.item)">
|
||||
备注:<span class="t">{{ props.item.remark }}</span><el-icon class="icon" v-if="props.type == 'cart'">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="sku_list" v-if="props.item.sku_name">
|
||||
<div class="tag" v-for="item in item.sku_name.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grooup_wrap" v-if="props.item.goods_type == 'package' && props.item.group_text">
|
||||
{{ props.item.group_type == 0 ? '固定套餐:' : '自选套餐:' }}
|
||||
<span>{{ props.item.group_text }}</span>
|
||||
</div>
|
||||
<div class="num">
|
||||
<div class="left">
|
||||
<div class="icon_item zen" v-if="item.is_time_discount && item.discount_sale_amount <= 0">
|
||||
<span class="t">限时折扣</span>
|
||||
</div>
|
||||
<div class="icon_item zen" v-if="props.item.is_gift">
|
||||
<span class="t">赠</span>
|
||||
</div>
|
||||
<div class="icon_item bao" v-if="+props.item.pack_number">
|
||||
<span class="t">打包({{ +props.item.pack_number }})</span>
|
||||
</div>
|
||||
<div class="icon_item tui" v-if="props.item.returnNum">
|
||||
<span class="t">退({{ props.item.returnNum }})</span>
|
||||
</div>
|
||||
<div class="icon_item lin" v-if="props.item.is_temporary == 1">
|
||||
<span class="t">临</span>
|
||||
</div>
|
||||
<div class="icon_item zhe" v-if="props.item.discount_sale_amount > 0 && !props.item.is_temporary">
|
||||
<span class="t">折</span>
|
||||
</div>
|
||||
<div class="icon_item chu" v-if="props.item.is_print == 0">
|
||||
<span class="t">免厨打印</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-text class="t">x{{ formatDecimal(+props.item.number, 2, true) }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 备注 -->
|
||||
<remarkModal ref="remarkRef" @success="remarkSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import remarkModal from "@/components/remarkModal.vue";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'cart'
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
index: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
i: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
// 购物车选中
|
||||
function selectCartItemHandle() {
|
||||
if (props.type == 'cart') {
|
||||
goodsStore.selectCartItemHandle(props.index)
|
||||
} else if (props.type == 'order') {
|
||||
goodsStore.selectOrderItem(props.index, props.i)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加单品备注
|
||||
const remarkRef = ref(null)
|
||||
function showRemark() {
|
||||
if (props.type == 'cart') {
|
||||
remarkRef.value.show()
|
||||
}
|
||||
}
|
||||
|
||||
// 修改备注
|
||||
function remarkSuccess(e) {
|
||||
goodsStore.operateCart({ ...props.item, remark: e }, 'edit')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.remark_wrap {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
padding-top: 10px;
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.cart_item {
|
||||
padding: var(--el-font-size-base);
|
||||
|
||||
&.active {
|
||||
background-color: var(--primary-color-hover);
|
||||
}
|
||||
|
||||
&.border {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.name_wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: var(--el-font-size-base);
|
||||
|
||||
.dis {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
text-decoration: line-through;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vip {
|
||||
color: var(--el-color-danger);
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.sku_list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 10px;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.grooup_wrap {
|
||||
padding-top: 10px;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
}
|
||||
|
||||
.num {
|
||||
padding-top: var(--el-font-size-base);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.icon_item {
|
||||
$size: 20px;
|
||||
height: $size;
|
||||
padding: 0 6px;
|
||||
border-radius: 2px;
|
||||
background-color: #e2e2e2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
|
||||
&.zen {
|
||||
background-color: #FFB0B1;
|
||||
color: #FF4D4F;
|
||||
}
|
||||
|
||||
&.bao {
|
||||
background-color: #52C41A;
|
||||
}
|
||||
|
||||
&.tui {
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
&.lin {
|
||||
background-color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
&.zhe {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
&.chu {
|
||||
background-color: #ffe7ba;
|
||||
color: #e69f1c;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,92 +1,185 @@
|
||||
<template>
|
||||
<div class="operation_wrap">
|
||||
<div class="item" :class="{ disabled: props.item.number <= 1 || !props.item.id }" @click="numberChange('sub')">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number" @click="props.item.id && takeFoodCodeRef.show()">
|
||||
<el-text class="num">{{ formatDecimal(props.item.number || 1, 2, true) }}</el-text>
|
||||
</div>
|
||||
<div class="item" @click="numberChange('add')">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<!-- <div class="item" :class="{ disabled: (props.item.id && !props.item.tbProductSpec) }" @click="showSkuModal">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div> -->
|
||||
<div class="item" @click="showDiscountModalHandle">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">打折</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isGift == 'true' }" @click="giftPackHandle('isGift')">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isPack == 'true' }" @click="giftPackHandle('isPack')"
|
||||
v-if="JSON.parse(shopStore.info.eatModel).some(item => item == 'take-out')">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isPrint == 0 }" @click="kitchenPrint">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item" @click="props.item.id && emit('delete', props.item)">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">删除</el-text>
|
||||
</div>
|
||||
<div class="item" @click="props.item.id && emit('pending', props.item)">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingHandle"
|
||||
v-if="shopStore.info.registerType == 'restaurant' && props.item.tableId && props.item.orderId">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item" @click="props.item.id && emit('clearCart')">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
<template v-if="goodsStore.cartType == 'cart'">
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && (!goodsStore.cartList[goodsStore.cartActiveIndex].id || (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1)) }"
|
||||
@click="numberChange('sub')">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number"
|
||||
:class="{ disabled: goodsStore.cartList.length && (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1) }"
|
||||
@click="showEditNumber">
|
||||
<el-text class="num">
|
||||
{{ formatDecimal(goodsStore.cartList.length ?
|
||||
+goodsStore.cartList[goodsStore.cartActiveIndex].number :
|
||||
1, 2, true) }}
|
||||
</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].number >= goodsStore.cartList[goodsStore.cartActiveIndex].stockNumber && goodsStore.cartList[goodsStore.cartActiveIndex].isStock) }"
|
||||
@click="numberChange('add')">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: (goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].id && goodsStore.cartList[goodsStore.cartActiveIndex].goods_type != 'sku' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type != 1) }"
|
||||
@click="showSkuModal">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_temporary || goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_gift }"
|
||||
@click="showDiscountModalHandle">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">改价</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_gift }"
|
||||
@click="giftPackHandle('is_gift')">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: goodsStore.allSelected }" @click="packHandle">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_print == 0 }"
|
||||
@click="giftPackHandle('is_print')">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item" @click="deleteHandle">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">删除</el-text>
|
||||
</div>
|
||||
<div class="item" @click="pendingOrderHandle">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingRef.show()">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item" @click="clearCart">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="goodsStore.cartType == 'order'">
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number disabled">
|
||||
<el-text class="num">
|
||||
{{ formatDecimal(goodsStore.cartList.length ?
|
||||
+goodsStore.cartList[goodsStore.cartActiveIndex].number :
|
||||
1, 2, true) }}
|
||||
</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">改价</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartOrderItem.returnNum >= goodsStore.cartOrderItem.number }"
|
||||
@click="returnOrderItemHandle">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">退菜</el-text>
|
||||
</div>
|
||||
<div class="item" @click="pendingOrderHandle">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingRef.show()">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="修改商品数量" placeholder="请输入商品数量" @success="updateNumber" />
|
||||
<!-- 购物车选择规格 -->
|
||||
<skuModal ref="skuModalRef" @success="skuConfirm" />
|
||||
<!-- 单品打折 -->
|
||||
<el-dialog v-model="showDiscountModal" title="单品打折" @open="resetDiscountForm = { ...discountForm }"
|
||||
<!-- 单品改价 -->
|
||||
<el-dialog v-model="showDiscountModal" title="单品改价" @open="resetDiscountForm = { ...discountForm }"
|
||||
@closed="discountModalClose">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
<el-form ref="discountFormRef" :model="discountForm" :rules="discountFormRules" label-width="100px"
|
||||
label-position="left">
|
||||
<el-form-item label="价格更改" prop="amount">
|
||||
<el-input v-model="discountForm.amount" placeholder="减8.88元请输入8.88" @input="priceInput">
|
||||
<el-form-item label="价格更改" prop="discount_sale_amount">
|
||||
<el-input v-model="discountForm.discount_sale_amount" placeholder="请输入改价金额" @input="priceInput">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="更改原因">
|
||||
<el-input v-model="discountForm.note" type="textarea" placeholder="请输入自定义备注" />
|
||||
<el-input v-model="discountForm.note" type="textarea" placeholder="请输入更改原因" />
|
||||
<div class="remark_list">
|
||||
<div class="item" v-for="item in noteList" :key="item" @click="addNote(item)">
|
||||
{{ item }}
|
||||
@@ -106,105 +199,292 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 修改打包数量 -->
|
||||
<el-dialog v-model="showPackModal" title="打包数量" @open="packModalOpen" width="350">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
<el-form ref="packNumerFormRef" :model="packNumberForm" :rules="packNumberFormRules" label-width="100px"
|
||||
label-position="left">
|
||||
<el-form-item :label="`数量(${packItem.unitName})`" prop="number">
|
||||
<!-- <el-input v-model="packNumberForm.number"
|
||||
:placeholder="`最多输入${+packItem.number}${packItem.unitName}`" @input="packNumberInput">
|
||||
<template #append></template>
|
||||
</el-input> -->
|
||||
<el-input-number v-model="packNumberForm.number" :min="1"
|
||||
:max="+packItem.number"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showPackModal = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" @click="packFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 合并/转桌 -->
|
||||
<tableMerging ref="tableMergingRef" @success="" />
|
||||
<!-- 退菜数量 -->
|
||||
<el-dialog
|
||||
:title="`退菜:${goodsStore.cartOrderItem.product_name} x ${goodsStore.cartOrderItem.number - goodsStore.cartOrderItem.returnNum}`"
|
||||
v-model="showReturnForm" width="350" top="20%">
|
||||
<el-form :model="returnForm" label-width="0" label-position="left">
|
||||
<el-form-item prop="num">
|
||||
<el-input-number v-model="returnForm.num" :min="1"
|
||||
:max="goodsStore.cartOrderItem.number - goodsStore.cartOrderItem.returnNum" style="width: 100%;">
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showReturnForm = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="returnFormLoading"
|
||||
@click="returnFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import takeFoodCode from '@/components/takeFoodCode.vue'
|
||||
import TableMerging from './tableMerging.vue'
|
||||
import skuModal from '@/components/skuModal.vue'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
import { updatePrice, orderPrint } from '@/api/product.js'
|
||||
import { refundOrder } from '@/api/order.js'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const socket = useSocket()
|
||||
|
||||
const tableMergingRef = ref(null)
|
||||
|
||||
const shopStore = useShop()
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart', 'merging'])
|
||||
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart', 'merging', 'showPackage'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const skuModalRef = ref([])
|
||||
|
||||
const showReturnForm = ref(false)
|
||||
const returnFormLoading = ref(false)
|
||||
const returnForm = ref({
|
||||
num: 1
|
||||
})
|
||||
|
||||
// 挂单
|
||||
function pendingOrderHandle() {
|
||||
let cart = goodsStore.cartList;
|
||||
let order = goodsStore.orderList;
|
||||
if (cart.length || order.length) {
|
||||
goodsStore.pendingCart()
|
||||
goodsStore.successClearCart();
|
||||
socket.cartInit();
|
||||
|
||||
ElMessage.success('挂单成功')
|
||||
}
|
||||
}
|
||||
|
||||
// 退菜
|
||||
async function returnOrderItemHandle() {
|
||||
if (goodsStore.cartOrderItem.returnNum >= goodsStore.cartOrderItem.number) return
|
||||
if (goodsStore.cartOrderItem.number == 1) {
|
||||
returnOrderItemAjax()
|
||||
} else {
|
||||
showReturnForm.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 提交自定义数量退菜
|
||||
async function returnFormSubmit() {
|
||||
try {
|
||||
returnFormLoading.value = true
|
||||
await returnOrderItemAjax(returnForm.value.num)
|
||||
showReturnForm.value = false
|
||||
ElMessage.success('退菜成功')
|
||||
} catch (error) {
|
||||
console.log('退菜失败了');
|
||||
}
|
||||
returnFormLoading.value = false
|
||||
}
|
||||
|
||||
// 提交退菜
|
||||
async function returnOrderItemAjax(num = 1) {
|
||||
try {
|
||||
let data = {
|
||||
orderId: goodsStore.orderListInfo.id,
|
||||
refundAmount: 0,
|
||||
modify: 0,
|
||||
cash: false,
|
||||
refundReason: '',
|
||||
refundDetails: [
|
||||
{
|
||||
id: goodsStore.cartOrderItem.id,
|
||||
returnAmount: goodsStore.cartOrderItem.lowPrice,
|
||||
num: num
|
||||
}
|
||||
]
|
||||
}
|
||||
await refundOrder(data)
|
||||
goodsStore.cartOrderItem.returnNum += num
|
||||
goodsStore.calcCartInfo()
|
||||
// await goodsStore.historyOrderAjax('', data.orderId)
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示打包
|
||||
function packHandle() {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id && !goodsStore.allSelected) {
|
||||
if (!item.pack_number || item.pack_number <= 0) {
|
||||
if (item.number > 1 && item.goods_type != 'weight') {
|
||||
// 大于1时需要编辑
|
||||
showPackModal.value = true
|
||||
} else {
|
||||
// 小于1时直接提交
|
||||
goodsStore.operateCart({ ...item, pack_number: 1 }, 'edit')
|
||||
}
|
||||
} else {
|
||||
// 取消打包
|
||||
goodsStore.operateCart({ ...item, pack_number: 0 }, 'edit')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 赠送打包操作
|
||||
function giftPackHandle(key) {
|
||||
if (!props.item.id) return
|
||||
if (props.item[key] == 'true') {
|
||||
props.item[key] = false
|
||||
} else {
|
||||
props.item[key] = true
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id) {
|
||||
if (key == 'is_gift' && goodsStore.cartList[goodsStore.cartActiveIndex] == 0) {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_amount = 0
|
||||
}
|
||||
|
||||
if (goodsStore.cartList[goodsStore.cartActiveIndex][key] == 0) {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex][key] = 1
|
||||
} else {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex][key] = 0
|
||||
}
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex] }, 'edit')
|
||||
goodsStore.calcCartInfo()
|
||||
}
|
||||
emit('confirm', props.item)
|
||||
|
||||
}
|
||||
|
||||
// 显示直接修改数量
|
||||
function showEditNumber() {
|
||||
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
|
||||
if (!item || (item.goods_type == 'package' && item.group_type == 1)) return
|
||||
takeFoodCodeRef.value.show()
|
||||
}
|
||||
|
||||
// 加减修改数量
|
||||
function numberChange(t) {
|
||||
console.log(props.item);
|
||||
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
|
||||
|
||||
|
||||
if (!props.item.id) return
|
||||
switch (t) {
|
||||
case 'sub':
|
||||
if (props.item.number <= 1) return
|
||||
props.item.number--
|
||||
if (item.number - 1 < item.suitNum) {
|
||||
goodsStore.deleteCartItem()
|
||||
} else {
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number - 1, number: number - 1 }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: number - 1 }, 'edit')
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'add':
|
||||
props.item.number++
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number + 1, number: number + 1 }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: +number + 1 }, 'edit')
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit('confirm', props.item)
|
||||
|
||||
console.log('numberChange===', goodsStore.cartList[goodsStore.cartActiveIndex].number);
|
||||
}
|
||||
|
||||
// 输入修改数量
|
||||
function updateNumber(num) {
|
||||
if (!props.item.id) return
|
||||
props.item.number = num
|
||||
emit('confirm', props.item)
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: num, number: num }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: num }, 'edit')
|
||||
}
|
||||
}
|
||||
|
||||
// 显示规格
|
||||
function showSkuModal() {
|
||||
if (!props.item.id) return
|
||||
if (props.item.tbProductSpec && props.item.tbProductSpec.specList) {
|
||||
skuModalRef.value.show(props.item, 'cart')
|
||||
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
|
||||
if (!item || (item.goods_type == 'package' && item.group_type == 0)) return
|
||||
|
||||
switch (item.goods_type) {
|
||||
case 'sku':
|
||||
skuModalRef.value.show({ ...goodsStore.cartList[goodsStore.cartActiveIndex] }, 'cart')
|
||||
break;
|
||||
case 'package':
|
||||
emit('showPackage', item)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改规格
|
||||
function skuConfirm(e) {
|
||||
if (!props.item.id) return
|
||||
emit('confirm', e)
|
||||
if (goodsStore.cartList[goodsStore.cartActiveIndex].sku_id != e.id) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], sku_id: e.id, sku_name: e.specInfo }, 'edit')
|
||||
}
|
||||
}
|
||||
|
||||
/**单品打折 start */
|
||||
/**单品改价 start */
|
||||
const showDiscountModal = ref(false)
|
||||
const resetDiscountForm = ref({})
|
||||
const discountFormRef = ref(null)
|
||||
const discountFormLoading = ref(false)
|
||||
const discountForm = ref({
|
||||
masterId: '',
|
||||
cartId: '',
|
||||
amount: '',
|
||||
note: '',
|
||||
shopId: ''
|
||||
discount_sale_amount: '',
|
||||
note: ''
|
||||
})
|
||||
|
||||
function validateAmount(rule, value, callback) {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
let lowPrice = 0
|
||||
if (goodsStore.showVipPrice) {
|
||||
lowPrice = +item.memberPrice
|
||||
} else {
|
||||
lowPrice = +item.discount_sale_amount || +item.lowPrice
|
||||
}
|
||||
if (value == '') {
|
||||
callback(new Error('请输入折扣价格'))
|
||||
} else if (value <= 0) {
|
||||
callback(new Error('输入价格有误'))
|
||||
} else if (value <= 0 || value >= lowPrice) {
|
||||
callback(new Error(`输入大于0小于${lowPrice}的数字`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const discountFormRules = ref({
|
||||
amount: [
|
||||
discount_sale_amount: [
|
||||
{
|
||||
required: true,
|
||||
validator: validateAmount,
|
||||
@@ -220,7 +500,9 @@ const noteList = ref([
|
||||
|
||||
// 显示
|
||||
function showDiscountModalHandle() {
|
||||
if (props.item.id) {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if ((item && item.id) && (!item.is_temporary && !item.is_gift)) {
|
||||
// 存在商品并且不能为临时菜或者赠送
|
||||
showDiscountModal.value = true
|
||||
}
|
||||
}
|
||||
@@ -254,47 +536,86 @@ function discountFormSubmit() {
|
||||
if (valid) {
|
||||
discountFormLoading.value = true
|
||||
|
||||
discountForm.value.masterId = props.item.masterId
|
||||
discountForm.value.cartId = props.item.id
|
||||
discountForm.value.shopId = props.item.shopId
|
||||
|
||||
await updatePrice(discountForm.value)
|
||||
discountFormLoading.value = false
|
||||
goodsStore.operateCart({
|
||||
...goodsStore.cartList[goodsStore.cartActiveIndex],
|
||||
discount_sale_amount: discountForm.value.discount_sale_amount,
|
||||
discount_sale_note: discountForm.value.note
|
||||
}, 'edit')
|
||||
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_amount = discountForm.value.discount_sale_amount
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_note = discountForm.value.note
|
||||
showDiscountModal.value = false
|
||||
ElMessage.success('操作成功')
|
||||
emit('confirm', { isTemporary: true })
|
||||
|
||||
goodsStore.calcCartInfo()
|
||||
}
|
||||
} catch (error) {
|
||||
discountFormLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
discountFormLoading.value = false
|
||||
})
|
||||
}
|
||||
/**单品打折 end */
|
||||
|
||||
/**免厨打印 start */
|
||||
async function kitchenPrint() {
|
||||
try {
|
||||
const res = await orderPrint({
|
||||
isPrint: props.item.isPrint ? 0 : 1,
|
||||
shopId: props.item.shopId,
|
||||
cartId: props.item.id
|
||||
})
|
||||
emit('confirm', { isTemporary: true })
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// 删除
|
||||
function deleteHandle() {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id) {
|
||||
goodsStore.deleteCartItem()
|
||||
}
|
||||
}
|
||||
/**免厨打印 end */
|
||||
|
||||
// 清空购物车
|
||||
function clearCart() {
|
||||
goodsStore.clearCart()
|
||||
}
|
||||
|
||||
// 显示合并转桌
|
||||
function tableMergingHandle() {
|
||||
if (props.item.id) {
|
||||
emit('merging')
|
||||
/** 修改打包数量 start */
|
||||
const showPackModal = ref(false)
|
||||
const packNumerFormRef = ref(null)
|
||||
const packItem = ref('')
|
||||
const packNumberForm = ref({
|
||||
number: 1
|
||||
})
|
||||
const packNumberFormRules = {
|
||||
number: [
|
||||
{
|
||||
required: true,
|
||||
validator: validatePackNumber,
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 校验数量是否合法
|
||||
function validatePackNumber(rule, value, callback) {
|
||||
if (!packNumberForm.value.number) {
|
||||
callback(new Error('请输入打包数量'))
|
||||
} else if (packNumberForm.value.number < 1) {
|
||||
callback(new Error('输入有误'))
|
||||
} else if (packNumberForm.value.number > packItem.value.number) {
|
||||
callback(new Error(`最多输入${+packItem.value.number}${packItem.value.unitName}`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
// modal打开时
|
||||
function packModalOpen() {
|
||||
packNumberForm.value.number = 1
|
||||
packItem.value = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
}
|
||||
|
||||
// 提交
|
||||
function packFormSubmit() {
|
||||
packNumerFormRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
showPackModal.value = false
|
||||
goodsStore.operateCart({ ...packItem.value, pack_number: packNumberForm.value.number }, 'edit')
|
||||
}
|
||||
})
|
||||
}
|
||||
/** 修改打包数量 end */
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -302,7 +623,7 @@ function tableMergingHandle() {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
|
||||
.item {
|
||||
width: 70px;
|
||||
@@ -313,6 +634,10 @@ function tableMergingHandle() {
|
||||
background-color: #efefef;
|
||||
border-radius: 6px;
|
||||
|
||||
&:active {
|
||||
background-color: #d3d3d3;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
|
||||
.t {
|
||||
@@ -322,6 +647,10 @@ function tableMergingHandle() {
|
||||
.icon {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.number {
|
||||
@@ -348,20 +677,21 @@ function tableMergingHandle() {
|
||||
}
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
|
||||
.content {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark_list {
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<!-- 分类 -->
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryCategory } from '@/api/product'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const categorys = ref([])
|
||||
const categorysActive = ref(0)
|
||||
|
||||
// 查询分类信息
|
||||
async function queryCategoryAjax() {
|
||||
try {
|
||||
const res = await queryCategory({
|
||||
shopId: store.userInfo.shopId,
|
||||
page: 1,
|
||||
pageSize: 100
|
||||
})
|
||||
categorys.value = res.list
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryCategoryAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header {
|
||||
display: flex;
|
||||
height: 80px;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.menus {
|
||||
display: flex;
|
||||
padding: 0 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
span {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
&::after {
|
||||
content: "";
|
||||
width: 70%;
|
||||
height: 2px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 15%;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
span {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.all {
|
||||
width: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
height: 60%;
|
||||
border-left: 1px solid #ececec;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #555;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
<!-- 称重商品组件 -->
|
||||
<template>
|
||||
<el-dialog title="可选套餐" width="70%" :close-on-click-modal="false" v-model="dialogVisible" top="10vh">
|
||||
<div class="row" v-for="(item, index) in goodsItem.proGroupVo" :key="index">
|
||||
<div class="row" v-for="(item, index) in goodsItem.groupSnap" :key="index">
|
||||
<div class="title_wrap">
|
||||
<div class="item">规格组名:{{ item.title }}</div>
|
||||
<div class="item"
|
||||
v-html="`本组菜品<span style='color: var(--el-color-danger)'>${item.count}</span>选<span style='color: var(--el-color-danger)'>${item.number}</span>`">
|
||||
v-html="`本组菜品<span style='color: var(--el-color-danger)'>${item.count || 0}</span>选<span style='color: var(--el-color-danger)'>${item.number || 0}</span>`">
|
||||
</div>
|
||||
</div>
|
||||
<div class="error">
|
||||
@@ -43,6 +43,9 @@
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const number = ref("");
|
||||
@@ -52,23 +55,55 @@ const emit = defineEmits(["success"]);
|
||||
|
||||
const tabRefs = ref([])
|
||||
|
||||
function show(item) {
|
||||
disabled.value = true
|
||||
const confirmType = ref('')
|
||||
const cartItem = ref('')
|
||||
|
||||
function show(item, type = 'add') {
|
||||
confirmType.value = type
|
||||
dialogVisible.value = true;
|
||||
goodsItem.value = { ...item }
|
||||
goodsItem.value.proGroupVo.map(item => {
|
||||
item.isError = false
|
||||
})
|
||||
setTimeout(() => {
|
||||
tabRefs.value.map(item => {
|
||||
item.clearSelection()
|
||||
if (type == 'add') {
|
||||
disabled.value = true
|
||||
goodsItem.value = { ...item }
|
||||
goodsItem.value.groupSnap.map(item => {
|
||||
item.isError = false
|
||||
})
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
tabRefs.value.map(item => {
|
||||
item.clearSelection()
|
||||
})
|
||||
}, 100);
|
||||
} else {
|
||||
cartItem.value = { ...item }
|
||||
|
||||
disabled.value = false
|
||||
goodsItem.value = goodsStore.originGoodsList.find(val => val.id == item.product_id)
|
||||
|
||||
// console.log('item===', item)
|
||||
// console.log('goodsItem.value===', goodsItem.value);
|
||||
|
||||
let selectGroup = JSON.parse(item.pro_group_info)
|
||||
console.log('selectGroup===', selectGroup);
|
||||
|
||||
setTimeout(() => {
|
||||
goodsItem.value.groupSnap.map((item, index) => {
|
||||
item.goods.map((val, i) => {
|
||||
selectGroup[index].goods.map(sg => {
|
||||
if (val.proId == sg.proId) {
|
||||
tabRefs.value[index].toggleRowSelection(val, true)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
goodsItem.value.groupSnap.map(item => {
|
||||
item.isError = false
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
// 选择表格触发
|
||||
function selectChange($event, index) {
|
||||
let item = goodsItem.value.proGroupVo[index]
|
||||
let item = goodsItem.value.groupSnap[index]
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
|
||||
if (selectNum.length != item.number) {
|
||||
@@ -79,7 +114,7 @@ function selectChange($event, index) {
|
||||
|
||||
let flags = []
|
||||
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
goodsItem.value.groupSnap.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
if (selectNum.length != item.number) {
|
||||
flags.push({ flag: false })
|
||||
@@ -103,7 +138,7 @@ const disabled = ref(true)
|
||||
function confirmHandle() {
|
||||
let flags = []
|
||||
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
goodsItem.value.groupSnap.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
if (selectNum.length != item.number) {
|
||||
flags.push({ flag: false })
|
||||
@@ -122,17 +157,26 @@ function confirmHandle() {
|
||||
disabled.value = false
|
||||
|
||||
let goodIds = []
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
goodIds.push(selectNum)
|
||||
goodsItem.value.groupSnap.map((item, index) => {
|
||||
let obj = { ...item }
|
||||
obj.goods = tabRefs.value[index].getSelectionRows()
|
||||
goodIds.push(obj)
|
||||
})
|
||||
|
||||
// 将商品数据转为一维数组返回
|
||||
emit("success", {
|
||||
...goodsItem.value,
|
||||
productId: goodsItem.value.id,
|
||||
groupProductIdList: goodIds.flat().map(item => item.proId)
|
||||
});
|
||||
if (confirmType.value == 'add') {
|
||||
emit("success", {
|
||||
...goodsItem.value.skuList[0],
|
||||
goods_type: goodsItem.value.type,
|
||||
pro_group_info: goodIds
|
||||
});
|
||||
} else {
|
||||
// 编辑
|
||||
goodsStore.operateCart({
|
||||
...cartItem.value,
|
||||
pro_group_info: goodIds
|
||||
}, 'edit')
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog title="恢复挂起的订单" width="800" v-model="dialogVisible">
|
||||
<div class="pending_carts">
|
||||
<div class="item" v-for="(item, index) in cartList" :key="index" @click="select(item)">
|
||||
<div class="item" v-for="(item, index) in goodsStore.pendingList" :key="index" @click="select(item)">
|
||||
<div class="time">
|
||||
<el-icon class="icon">
|
||||
<Clock />
|
||||
@@ -9,12 +9,12 @@
|
||||
<span>{{ dayjs(item.pendingAt).format('HH:mm') }}</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="name">{{ item.productName }}</span>
|
||||
<span class="p">¥{{ item.totalAmount }}</span>
|
||||
<span class="name">【{{ item.tableCode }}】{{ item.productName }}</span>
|
||||
<span class="p">¥{{ formatDecimal(item.totalAmount) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty">
|
||||
<el-empty description="暂无挂单" v-if="!cartList.length" />
|
||||
<el-empty description="暂无挂单" v-if="!goodsStore.pendingList.length" />
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -23,40 +23,20 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { dayjs } from 'element-plus'
|
||||
import { getCartList } from "@/api/product";
|
||||
import { useUser } from "@/store/user"
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const emit = defineEmits(['select'])
|
||||
|
||||
const store = useUser()
|
||||
const goodsStore = useGoods()
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
const loading = ref(false)
|
||||
const cartList = ref([])
|
||||
|
||||
// 恢复挂单
|
||||
function select(item) {
|
||||
emit('select', item)
|
||||
async function select(item) {
|
||||
dialogVisible.value = false
|
||||
await goodsStore.recoverPending(item)
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true
|
||||
getCartListAjax()
|
||||
}
|
||||
|
||||
// 获取挂起购物车列表
|
||||
async function getCartListAjax() {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await getCartList({
|
||||
shopId: store.userInfo.shopId
|
||||
})
|
||||
cartList.value = res
|
||||
loading.value = false
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -1,74 +1,63 @@
|
||||
<!-- 结算订单 -->
|
||||
<template>
|
||||
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible" @closed="drawerClose">
|
||||
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible">
|
||||
<div class="drawer_wrap">
|
||||
<div class="cart_list">
|
||||
<div class="nav_wrap card">
|
||||
<div class="return" @click="dialogVisible = false">
|
||||
<div class="return" @click="returnHandle">
|
||||
<el-icon class="icon">
|
||||
<ArrowLeftBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="master_id">
|
||||
<span>{{ props.masterId }}</span>
|
||||
<span class="member_info" v-if="global.orderMemberInfo.telephone">
|
||||
会员:{{ global.orderMemberInfo.telephone }}
|
||||
</span>
|
||||
<span>{{ goodsStore.orderListInfo.tableCode || store.shopInfo.shopName }}</span>
|
||||
<div class="member_info" v-if="goodsStore.vipUserInfo.id">
|
||||
<span>用户昵称:{{ formatPhoneNumber(goodsStore.vipUserInfo.phone) }}</span>
|
||||
<span class="vip" v-if="goodsStore.vipUserInfo.memberLevelName">{{
|
||||
goodsStore.vipUserInfo.memberLevelName }}</span>
|
||||
</div>
|
||||
<div class="member_info s" v-if="goodsStore.vipUserInfo.id">当前积分:
|
||||
{{ goodsStore.vipUserInfo.accountPoints }}
|
||||
</div>
|
||||
<div class="member_info s between" v-if="goodsStore.vipUserInfo.id">
|
||||
<span>当前余额:{{ goodsStore.vipUserInfo.amount }}</span>
|
||||
<el-button size="small" @click="userChangeRef.show()">去充值</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<span class="p">服务员:{{ store.userInfo.loginAccount || "暂无" }}</span>
|
||||
<span class="t">{{
|
||||
props.orderInfo.createdAt &&
|
||||
dayjs(props.orderInfo.createdAt).format("MM-DD HH:mm")
|
||||
}}</span>
|
||||
<span class="p">服务员:{{ store.userInfo.name || store.shopInfo.shopName }}</span>
|
||||
<span class="t">{{ dayjs().format("M月D日 HH:mm") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list_wrap card" style="margin-top: var(--el-font-size-base)">
|
||||
<div class="item" v-for="item in cartList" :key="item.id">
|
||||
<div class="top">
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<span class="n">x{{ item.number }}</span>
|
||||
<span class="p">¥{{ item.salePrice }}</span>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="item.isGift == 'true'">
|
||||
<span>[赠送]</span>
|
||||
<span>¥-{{ item.salePrice }}</span>
|
||||
</div>
|
||||
<div class="tag_wrap" v-if="item.skuName">
|
||||
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="packge_Wrap" v-if="item.isPack == 'true'">
|
||||
<div class="icon_item" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
|
||||
<el-icon class="icon" style="color: var(--primary-color)">
|
||||
<Box />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <SettleItem :list="cartList" /> -->
|
||||
<SettleItem :list="orderList" />
|
||||
<SettleItem
|
||||
:list="[{ id: 'tableFee', product_name: '客座费', number: goodsStore.tableInfo.num, salePrice: store.shopInfo.tableFee, memberPrice: store.shopInfo.tableFee }]"
|
||||
v-if="!store.shopInfo.isTableFee && goodsStore.tableInfo.name && (goodsStore.cartList.length || goodsStore.orderList.length) && !goodsStore.allSelected" />
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <el-button icon="Edit"></el-button> -->
|
||||
<div class="button">
|
||||
<el-checkbox v-model="isPrint" border label="打印结算小票" style="width: 100%" />
|
||||
<el-checkbox v-model="isPrint" :true-value="1" :false-value="0" border label="打印结算小票" style="width: 100%" />
|
||||
</div>
|
||||
<div class="print">
|
||||
<!-- <div class="print">
|
||||
<el-button type="warning" :loading="discountLoading" @click="showStaffDiscountHandle">添加折扣</el-button>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="print">
|
||||
<el-button type="primary" :loading="printLoading" @click="printHandle">打印预结单</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_wrap">
|
||||
<payCard :amount="props.amount" :discount="propsDiscount" :orderId="props.orderInfo.id" @paySuccess="paySuccess"
|
||||
@cancelDiscount="propsDiscount = 0" />
|
||||
<payCard ref="payCardRef" :orderList="orderList" :amount="cartInfo.totalAmount"
|
||||
:orderId="goodsStore.orderListInfo.id" @paySuccess="paySuccess" @orderExpired="orderExpiredHnadle"
|
||||
:isPrint="0" @reset="show" />
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="showStaffDiscount" title="员工折扣" @close="global.updateData(true)">
|
||||
<!-- <el-dialog v-model="showStaffDiscount" title="员工折扣" @close="global.updateData(true)">
|
||||
<el-form>
|
||||
<el-form-item label="折扣比例">
|
||||
<div>
|
||||
@@ -77,6 +66,13 @@
|
||||
<div class="tips">最低折扣比例:{{ staffDiscount }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="优惠金额">
|
||||
<div>
|
||||
<el-input-number v-model="discount" :min="staffDiscount" :max="0.99" :step="0.1"
|
||||
:disabled="staffDiscount == 0" />
|
||||
<div class="tips">最低折扣比例:{{ staffDiscount }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
@@ -86,48 +82,53 @@
|
||||
<el-button type="primary" style="width: 100%;" @click="discountConfirm">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-dialog> -->
|
||||
</el-drawer>
|
||||
<user-charge ref="userChangeRef" :userInfo="goodsStore.vipUserInfo" @pay-success="chargeSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from 'lodash'
|
||||
import { onMounted, 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'
|
||||
import { print } from "@/api/pay";
|
||||
import { orderfindOrder, getStaffDiscount } from '@/api/order/index.js'
|
||||
import { ElMessage } from "element-plus";
|
||||
import dayjs from "dayjs";
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import { ipcRenderer } from "electron";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||
import { shopStaffInfo, shopUserDetail } from '@/api/account.js'
|
||||
import { dayjs, ElMessage } from "element-plus";
|
||||
import { formatPhoneNumber, getOrderByIdAjax, commOrderPrintData } from '@/utils/index.js'
|
||||
import useStorage from '@/utils/useStorage.js'
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { usePrint } from '@/store/print.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
import { orderPrint } from '@/api/order.js'
|
||||
import { } from '@/utils/coupon-utils.js'
|
||||
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
import UserCharge from "@/views/member/components/userCharge.vue";
|
||||
|
||||
const userChangeRef = ref(null);
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const global = useGlobal()
|
||||
const printStore = usePrint()
|
||||
|
||||
const store = useUser();
|
||||
const socket = useSocket()
|
||||
|
||||
const emit = defineEmits("paySuccess");
|
||||
const emits = defineEmits(['success']);
|
||||
|
||||
const cartInfo = ref('')
|
||||
|
||||
const printLoading = ref(false);
|
||||
|
||||
const showStaffDiscount = ref(false)
|
||||
const staffDiscount = ref(0)
|
||||
const staffDiscount = ref('')
|
||||
const discount = ref(0)
|
||||
const propsDiscount = ref(0)
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const props = defineProps({
|
||||
cart: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
amount: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
@@ -136,10 +137,6 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
orderInfo: {
|
||||
type: Object,
|
||||
default: "",
|
||||
},
|
||||
masterId: {
|
||||
type: String,
|
||||
default: "",
|
||||
@@ -150,17 +147,23 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const cartList = ref([])
|
||||
|
||||
const isPrint = ref(true);
|
||||
|
||||
|
||||
const orderList = ref([])
|
||||
const isPrint = ref(1);
|
||||
const discountLoading = ref(false)
|
||||
|
||||
// 支付失败,订单已过期
|
||||
function orderExpiredHnadle() {
|
||||
dialogVisible.value = false
|
||||
useStorage.del('tableCode')
|
||||
socket.cartInit()
|
||||
goodsStore.successClearCart()
|
||||
}
|
||||
|
||||
// 显示员工折扣
|
||||
async function showStaffDiscountHandle() {
|
||||
try {
|
||||
discountLoading.value = true
|
||||
await staffPermission('yun_xu_da_zhe')
|
||||
// await staffPermission('yun_xu_da_zhe')
|
||||
await getStaffDiscountAjax()
|
||||
discountLoading.value = false
|
||||
if (staffDiscount.value <= 0) {
|
||||
@@ -168,164 +171,133 @@ async function showStaffDiscountHandle() {
|
||||
} else {
|
||||
showStaffDiscount.value = true
|
||||
discountLoading.value = false
|
||||
global.updateData(false)
|
||||
// global.updateData(false)
|
||||
}
|
||||
} catch (error) {
|
||||
discountLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
discountLoading.value = false
|
||||
}
|
||||
|
||||
// 获取员工折扣
|
||||
async function getStaffDiscountAjax() {
|
||||
try {
|
||||
const res = await getStaffDiscount({
|
||||
orderId: props.orderInfo.id,
|
||||
staffId: store.userInfo.staffId
|
||||
})
|
||||
staffDiscount.value = res
|
||||
discount.value = res
|
||||
const res = await shopStaffInfo()
|
||||
if (res.data) {
|
||||
staffDiscount.value = res
|
||||
discount.value = res
|
||||
} else {
|
||||
Promise.reject()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认折扣
|
||||
function discountConfirm() {
|
||||
if (discount.value >= staffDiscount.value) {
|
||||
propsDiscount.value = discount.value
|
||||
}
|
||||
showStaffDiscount.value = false
|
||||
}
|
||||
|
||||
// 关闭结算弹窗
|
||||
function drawerClose() {
|
||||
propsDiscount.value = 0
|
||||
}
|
||||
|
||||
// 预打印操作
|
||||
const printHandle = _.throttle(async function () {
|
||||
try {
|
||||
if (!isPrint.value) return;
|
||||
printLoading.value = true;
|
||||
const data = {
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
isBefore: true,
|
||||
carts: cartList.value,
|
||||
amount: formatDecimal(props.amount),
|
||||
discountAmount: propsDiscount.value > 0 ? formatDecimal(props.amount * propsDiscount.value) : formatDecimal(props.amount),
|
||||
discount: formatDecimal(propsDiscount.value * 10, 1, true),
|
||||
remark: props.remark,
|
||||
orderInfo: props.orderInfo,
|
||||
createdAt: dayjs(props.orderInfo.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
printStore.labelPrint(data)
|
||||
setTimeout(() => {
|
||||
printLoading.value = false;
|
||||
}, 1500)
|
||||
if (printStore.deviceNoteList.length) {
|
||||
printStore.pushReceiptData(data)
|
||||
} else {
|
||||
await print({
|
||||
type: "normal",
|
||||
ispre: true,
|
||||
orderId: props.orderInfo.id,
|
||||
});
|
||||
printLoading.value = false;
|
||||
ElMessage.success("打印成功");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
printLoading.value = true
|
||||
await printOrderLable(true)
|
||||
}, 1500, { leading: true, trailing: false })
|
||||
|
||||
// 打印订单标签
|
||||
async function printOrderLable() {
|
||||
async function printOrderLable(isBefore = false) {
|
||||
try {
|
||||
if (!isPrint.value) return
|
||||
const res = await orderfindOrder({
|
||||
shopId: store.userInfo.shopId,
|
||||
status: '',
|
||||
size: 10,
|
||||
page: 1,
|
||||
orderNo: props.orderInfo.orderNo
|
||||
})
|
||||
let orderId = goodsStore.orderListInfo.id
|
||||
const data = await getOrderByIdAjax(orderId);
|
||||
|
||||
const printLabelOrder = res.list[0]
|
||||
let printList = useStorage.get("printList") || [];
|
||||
|
||||
const data = {
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
carts: [],
|
||||
amount: formatDecimal(printLabelOrder.orderAmount),
|
||||
discountAmount: printLabelOrder.discountRatio > 0 ? formatDecimal(printLabelOrder.orderAmount - printLabelOrder.discountAmount) : formatDecimal(printLabelOrder.orderAmount),
|
||||
discount: formatDecimal(printLabelOrder.discountRatio * 10, 1, true) || 0,
|
||||
remark: printLabelOrder.remark,
|
||||
orderInfo: printLabelOrder,
|
||||
outNumber: printLabelOrder.outNumber,
|
||||
createdAt: dayjs(printLabelOrder.createdAt).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
),
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
}
|
||||
printLabelOrder.skuInfos.map(item => {
|
||||
data.carts.push(
|
||||
{
|
||||
categoryId: item.categoryId,
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.productSkuName,
|
||||
salePrice: formatDecimal(item.price),
|
||||
totalAmount: formatDecimal(item.num * item.price),
|
||||
proGroupInfo: item.proGroupInfo
|
||||
// 防止重复打印
|
||||
if (!printList.some((el) => el == orderId)) {
|
||||
if (!isBefore) {
|
||||
printList.push(orderId);
|
||||
useStorage.set("printList", _.uniq(printList));
|
||||
}
|
||||
|
||||
if (printStore.deviceLableList.length) {
|
||||
if (!isBefore) {
|
||||
// 预结算不打印标签
|
||||
printStore.labelPrint(commOrderPrintData(data))
|
||||
}
|
||||
)
|
||||
})
|
||||
// 打印标签
|
||||
printStore.labelPrint(data)
|
||||
}
|
||||
|
||||
if (printStore.deviceNoteList.length) {
|
||||
// 打印小票
|
||||
printStore.pushReceiptData(data)
|
||||
} else {
|
||||
await print({
|
||||
type: "normal",
|
||||
ispre: true,
|
||||
orderId: props.orderInfo.id,
|
||||
});
|
||||
printLoading.value = false;
|
||||
ElMessage.success("打印成功");
|
||||
if (printStore.deviceNoteList.length) {
|
||||
// 使用本地打印机打印
|
||||
printStore.pushReceiptData(commOrderPrintData({ ...data, isBefore: isBefore }));
|
||||
} else {
|
||||
// 本地没有可用打印机使用云打印机
|
||||
await orderPrint({
|
||||
type: isBefore ? 1 : 0,
|
||||
id: orderId,
|
||||
});
|
||||
ElMessage.success(`云打印${isBefore ? '预' : ''}结算单成功`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
printLoading.value = false
|
||||
}, 2500)
|
||||
}
|
||||
|
||||
// 订单已支付
|
||||
function paySuccess() {
|
||||
propsDiscount.value = 0
|
||||
if (isPrint.value) printOrderLable()
|
||||
emits('success')
|
||||
dialogVisible.value = false;
|
||||
global.setOrderMember({})
|
||||
global.setOrderTable({})
|
||||
printOrderLable()
|
||||
|
||||
emit("paySuccess");
|
||||
ElMessage.success('支付成功')
|
||||
goodsStore.clearCart()
|
||||
useStorage.del('tableCode')
|
||||
socket.cartInit()
|
||||
goodsStore.successClearCart()
|
||||
goodsStore.clearVipUserInfo()
|
||||
payCardRef.value.resetCouponFormHandle()
|
||||
}
|
||||
|
||||
function show() {
|
||||
const payCardRef = ref(null)
|
||||
function show(t) {
|
||||
dialogVisible.value = true;
|
||||
cartList.value = []
|
||||
props.cart.map(item => {
|
||||
if (item.info && item.info.length) {
|
||||
item.info.map(item => {
|
||||
cartList.value.push({ ...item })
|
||||
})
|
||||
} else {
|
||||
cartList.value.push({ ...item })
|
||||
}
|
||||
cartInfo.value = { ...goodsStore.cartInfo }
|
||||
orderList.value = [...goodsStore.cartList, ...goodsStore.orderList.map(item => item.goods).flat()]
|
||||
|
||||
console.log('orderListInfo===================', { ...goodsStore.orderListInfo });
|
||||
|
||||
// 每次初始化paycard
|
||||
nextTick(() => {
|
||||
payCardRef.value.payCardInit()
|
||||
})
|
||||
|
||||
console.log('vipUserInfo===', goodsStore.vipUserInfo)
|
||||
}
|
||||
|
||||
// 会员充值成功
|
||||
async function chargeSuccess() {
|
||||
try {
|
||||
const res = await shopUserDetail({
|
||||
id: goodsStore.vipUserInfo.id,
|
||||
})
|
||||
|
||||
console.log(res)
|
||||
goodsStore.vipUserInfo = res
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 不支付返回清楚所有优惠
|
||||
function returnHandle() {
|
||||
dialogVisible.value = false
|
||||
goodsStore.calcCartInfo({
|
||||
pointsPerYuan: '',
|
||||
maxDeductionAmount: '',
|
||||
userPoints: '',
|
||||
backendCoupons: [],
|
||||
fixedAmount: ''
|
||||
})
|
||||
|
||||
payCardRef.value.resetCouponFormHandle()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@@ -385,16 +357,37 @@ defineExpose({
|
||||
$padding: 10px;
|
||||
|
||||
.master_id {
|
||||
height: 127px;
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding: $padding 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.member_info {
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
&.s {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&.between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.vip {
|
||||
background-color: #F8F8F8;
|
||||
border-radius: 6px;
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,68 +410,8 @@ defineExpose({
|
||||
|
||||
.list_wrap {
|
||||
padding: 0 var(--el-font-size-base);
|
||||
height: calc(100vh - 200px);
|
||||
height: calc(100vh - 270px);
|
||||
overflow-y: auto;
|
||||
|
||||
.item {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
border-bottom: 1px solid #ececec;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.n {
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.p {
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.gift_wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tag_wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.packge_Wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon_item {
|
||||
$size: 40px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: #e2e2e2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
236
src/views/home/components/settleItem.vue
Normal file
236
src/views/home/components/settleItem.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div class="item" v-for="item in props.list" :key="item.id">
|
||||
<div class="top">
|
||||
<div class="name">
|
||||
<span v-if="item.is_temporary" style="color: #999;"> [临时菜]</span>
|
||||
{{ item.product_name }}
|
||||
</div>
|
||||
<div class="n">x{{ formatDecimal(+item.number, 2, true) }}</div>
|
||||
<div class="p"
|
||||
:class="{ undeline: (goodsStore.showVipPrice && item.memberPrice) || item.is_time_discount }">
|
||||
<template v-if="item.is_temporary">
|
||||
<template v-if="item.is_gift">
|
||||
<span class="t_line">¥{{ formatDecimal(+item.discount_sale_amount) }}</span>
|
||||
¥0.00
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>¥{{ formatDecimal(item.discount_sale_amount * item.number) }}</span>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="item.is_gift">
|
||||
<span class="t_line">¥{{ formatDecimal(+item.salePrice) }}</span>
|
||||
¥0.00
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="+item.discount_sale_amount > 0">
|
||||
<!-- <span class="t_line">
|
||||
¥{{ formatDecimal(+item.salePrice) }}
|
||||
</span> -->
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.discount_sale_amount) }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
¥{{ formatDecimal(+item.salePrice) }}
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap" style="padding-bottom: 10px;">
|
||||
<div class="name">备注:{{ item.remark || '无' }}</div>
|
||||
</div>
|
||||
<div class="tag_wrap" v-if="item.sku_name">
|
||||
<div class="tag" v-for="item in item.sku_name.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="item.is_gift">
|
||||
<div class="name">
|
||||
<span v-if="item.is_gift">[赠送]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span>
|
||||
-¥<template v-if="item.is_temporary || +item.discount_sale_amount">
|
||||
{{ formatDecimal(item.discount_sale_amount * item.number) }}
|
||||
</template>
|
||||
<template v-else>{{ formatDecimal(item.lowPrice * item.number) }}</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="item.returnNum">
|
||||
<div class="name">
|
||||
<span>[退菜]</span>
|
||||
</div>
|
||||
<div class="n">x{{ item.returnNum }}</div>
|
||||
<div class="p">
|
||||
<span>
|
||||
-¥<template v-if="item.is_temporary || +item.discount_sale_amount">
|
||||
{{ formatDecimal(item.discount_sale_amount * item.returnNum) }}
|
||||
</template>
|
||||
<template v-else>{{ formatDecimal(item.lowPrice * item.returnNum) }}</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="!item.is_temporary && !item.is_gift && +item.discount_sale_amount">
|
||||
<div class="name">
|
||||
<span>[改价优惠]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span>
|
||||
-¥{{ formatDecimal((item.lowPrice - item.discount_sale_amount) * item.number) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap"
|
||||
v-if="goodsStore.showVipPrice && item.memberPrice && !item.is_time_discount && item.discount_sale_amount <= 0">
|
||||
<div class="name">
|
||||
<span>[会员价]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.memberPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="item.is_time_discount && item.discount_sale_amount <= 0">
|
||||
<template v-if="item.time_dicount_mode == 'vip-price'">
|
||||
<div class="name">
|
||||
<span>[会员价]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.memberPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="name">
|
||||
<span>[限时折扣]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span>
|
||||
¥{{ formatDecimal(+item.time_discount_price) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="gift_wrap" v-if="+item.pack_number">
|
||||
<div class="name">
|
||||
<span>[打包费]</span>
|
||||
</div>
|
||||
<div class="n"></div>
|
||||
<div class="p">
|
||||
<span v-if="item.is_temporary">
|
||||
+¥0.00
|
||||
</span>
|
||||
<span v-else>
|
||||
+¥{{ formatDecimal(item.pack_number * item.packFee) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: [Array],
|
||||
default: []
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.item {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
border-bottom: 1px solid #ececec;
|
||||
|
||||
|
||||
.name {
|
||||
flex: 1.5;
|
||||
}
|
||||
|
||||
.n {
|
||||
width: 30px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.p {
|
||||
flex: 1;
|
||||
color: #555;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
&.undeline {
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
.t_line {
|
||||
text-decoration: line-through;
|
||||
color: #999;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.gift_wrap {
|
||||
display: flex;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
|
||||
.n {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.p {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
.tag_wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.packge_Wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon_item {
|
||||
$size: 40px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: #e2e2e2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,29 +1,41 @@
|
||||
<!-- 合并/转桌 -->
|
||||
<template>
|
||||
<el-dialog title="转桌/并桌" width="700px" v-model="visible" @closed="onClose" top="10vh">
|
||||
<el-dialog title="转桌/并桌" width="700px" v-model="visible" @closed="onClose" top="3vh">
|
||||
<div class="scroll_y">
|
||||
<el-form :model="form" ref="formRef" :rules="rules" label-position="top">
|
||||
<el-form-item label="当前台桌" v-if="goodsStore.tableInfo.id">
|
||||
{{ goodsStore.tableInfo.name }}
|
||||
</el-form-item>
|
||||
<el-form-item label="转入台桌" prop="targetTableId">
|
||||
<el-select v-model="form.targetTableId" style="width: 200px;" placeholder="请选择目标台桌">
|
||||
<el-option :label="item.name" :value="item.qrcode" v-for="item in tableList"
|
||||
:key="item.qrcode"></el-option>
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in tableList"
|
||||
:key="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="转入类型">
|
||||
<el-radio-group v-model="form.isFull">
|
||||
<el-form-item label="转入类型" prop="cartIds">
|
||||
<el-radio-group v-model="form.isFull" @change="tableChange">
|
||||
<el-radio :value="false" border>转桌(可将部分商品转入)</el-radio>
|
||||
<el-radio :value="true" border>并桌(并台会将全部购物车商品转入)</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="转入商品" prop="cartIds" v-if="!form.isFull">
|
||||
<div v-for="item in props.data" style="width: 100%;">
|
||||
<div>{{ `第${item.placeNum}次下单` }}</div>
|
||||
<el-table ref="tableRefs" :data="item.info" border>
|
||||
<el-form-item label="购物车商品" v-if="!form.isFull">
|
||||
<el-table ref="cartTableRefs" :data="goodsStore.cartList" border stripe>
|
||||
<el-table-column type="selection" align="center" width="50px"></el-table-column>
|
||||
<el-table-column label="名称" prop="product_name"></el-table-column>
|
||||
<el-table-column label="数量" prop="number"></el-table-column>
|
||||
<el-table-column label="规格" prop="sku_name"></el-table-column>
|
||||
<el-table-column label="价格" prop="lowPrice"></el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<el-form-item label="已下单商品" v-if="!form.isFull && goodsStore.orderList.length">
|
||||
<div v-for="item in goodsStore.orderList" style="width: 100%;">
|
||||
<div>{{ `第${item.orderNum}次下单` }}</div>
|
||||
<el-table ref="orderTableRefs" :data="item.goods" border stripe>
|
||||
<el-table-column type="selection" align="center" width="50px"></el-table-column>
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="名称" prop="product_name"></el-table-column>
|
||||
<el-table-column label="数量" prop="number"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="salePrice"></el-table-column>
|
||||
<el-table-column label="规格" prop="sku_name"></el-table-column>
|
||||
<el-table-column label="价格" prop="lowPrice"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -41,39 +53,26 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { queryShopTable } from '@/api/table.js'
|
||||
import { orderSwitcht } from '@/api/product.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const store = useUser()
|
||||
const global = useGlobal()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const props = reactive({
|
||||
data: []
|
||||
})
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { mergeOrder } from '@/api/order.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { shopTable } from "@/api/account.js";
|
||||
import useStorage from '@/utils/useStorage.js'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const tableRefs = ref([])
|
||||
|
||||
const list = ref([])
|
||||
|
||||
const socket = useSocket()
|
||||
const goodsStore = useGoods()
|
||||
const visible = ref(false)
|
||||
const cartTableRefs = ref(null)
|
||||
const orderTableRefs = ref([])
|
||||
const loading = ref(false)
|
||||
const formRef = ref(null)
|
||||
const resetForm = ref({})
|
||||
const form = ref({
|
||||
shopId: store.userInfo.shopId,
|
||||
masterId: '',
|
||||
orderId: '',
|
||||
cartIds: [],
|
||||
isFull: false,
|
||||
currentTableId: '',
|
||||
targetTableId: '',
|
||||
isFull: false,
|
||||
})
|
||||
|
||||
const rules = ref({
|
||||
@@ -88,14 +87,19 @@ const rules = ref({
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
let arr = []
|
||||
props.data.map((item, index) => {
|
||||
arr.push(...tableRefs.value[index].getSelectionRows())
|
||||
})
|
||||
if (!form.value.isFull) {
|
||||
let arr = []
|
||||
arr.push(...cartTableRefs.value.getSelectionRows())
|
||||
|
||||
if (!arr.length) {
|
||||
ElMessage.error('至少选择一个商品')
|
||||
callback(new Error('至少选择一个商品'))
|
||||
goodsStore.orderList.map((item, index) => {
|
||||
arr.push(...orderTableRefs.value[index].getSelectionRows())
|
||||
})
|
||||
|
||||
if (!arr.length) {
|
||||
callback(new Error('至少选择一个商品'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
@@ -105,18 +109,20 @@ const rules = ref({
|
||||
]
|
||||
})
|
||||
|
||||
// 切换道并桌时清除掉所有验证
|
||||
function tableChange(e) {
|
||||
if (e) formRef.value.clearValidate('cartIds')
|
||||
}
|
||||
|
||||
const tableList = ref([])
|
||||
// 获取台桌列表
|
||||
async function queryShopTableAjax() {
|
||||
try {
|
||||
const res = await queryShopTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
areaId: '',
|
||||
status: '',
|
||||
page: 1,
|
||||
pageSize: 100
|
||||
const res = await shopTable({
|
||||
// status: 'using',
|
||||
// isBind: true
|
||||
})
|
||||
tableList.value = res.list.filter(item => item.qrcode != props.data[0].info[0].tableId && item.status == 'using')
|
||||
tableList.value = res.records
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -128,32 +134,66 @@ function confirmHandle() {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
form.value.masterId = props.data[0].info[0].masterId
|
||||
form.value.orderId = props.data[0].info[0].orderId
|
||||
form.value.currentTableId = props.data[0].info[0].tableId
|
||||
|
||||
if (!form.value.isFull) {
|
||||
let arr = []
|
||||
props.data.map((item, index) => {
|
||||
arr.push(...tableRefs.value[index].getSelectionRows())
|
||||
let targetTable = tableList.value.find(item => item.id == form.value.targetTableId)
|
||||
|
||||
let sourceOrderId = goodsStore.orderListInfo.id
|
||||
let targetOrderId = targetTable.orderId
|
||||
let targetTableCode = targetTable.tableCode
|
||||
let detailIds = []
|
||||
|
||||
if (form.value.isFull) {
|
||||
goodsStore.orderList.map((item, index) => {
|
||||
item.goods.map(val => {
|
||||
detailIds.push(val.id)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
goodsStore.orderList.map((item, index) => {
|
||||
detailIds.push(...orderTableRefs.value[index].getSelectionRows().map(item => item.id))
|
||||
})
|
||||
form.value.cartIds = arr.map(item => item.id)
|
||||
}
|
||||
|
||||
await orderSwitcht(form.value)
|
||||
loading.value = false
|
||||
|
||||
// 更新台桌信息
|
||||
global.setOrderTable(tableList.value.find(item => item.qrcode == form.value.targetTableId))
|
||||
if (detailIds.length) {
|
||||
await mergeOrder({
|
||||
sourceOrderId: sourceOrderId, // 来源订单id
|
||||
targetOrderId: targetOrderId, // 目标台桌订单id
|
||||
targetTableCode: targetTableCode, // 目标台桌码
|
||||
detailIds: detailIds // 转台详情
|
||||
})
|
||||
if (!goodsStore.cartList.length) {
|
||||
useStorage.set('tableCode', targetTableCode)
|
||||
|
||||
goodsStore.successClearCart();
|
||||
goodsStore.historyOrderAjax(targetTableCode);
|
||||
socket.cartInit();
|
||||
}
|
||||
}
|
||||
|
||||
if (goodsStore.cartList.length) {
|
||||
let table_code = goodsStore.cartList[0].table_code
|
||||
let new_table_code = targetTable.tableCode
|
||||
let cart_id = []
|
||||
|
||||
if (form.value.isFull) {
|
||||
cart_id = goodsStore.cartList.map(item => item.id)
|
||||
} else {
|
||||
cart_id = cartTableRefs.value.getSelectionRows().map(item => item.id)
|
||||
}
|
||||
|
||||
goodsStore.operateCart({
|
||||
table_code: table_code,
|
||||
new_table_code: new_table_code,
|
||||
cart_id: cart_id
|
||||
}, 'rottable')
|
||||
}
|
||||
visible.value = false
|
||||
|
||||
emits('success', { isTemporary: true })
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -162,10 +202,11 @@ function onClose() {
|
||||
formRef.value.resetFields()
|
||||
}
|
||||
|
||||
function show(data) {
|
||||
props.data = data
|
||||
visible.value = true
|
||||
queryShopTableAjax()
|
||||
function show() {
|
||||
if (goodsStore.cartList.length || goodsStore.orderList.length) {
|
||||
visible.value = true
|
||||
queryShopTableAjax()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@@ -181,7 +222,7 @@ onMounted(() => {
|
||||
$btmH: 50px;
|
||||
|
||||
.scroll_y {
|
||||
height: 50vh;
|
||||
height: 68vh;
|
||||
overflow-y: auto;
|
||||
padding-bottom: $btmH;
|
||||
}
|
||||
|
||||
@@ -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,11 +90,14 @@ const loading = ref(false)
|
||||
// 确认
|
||||
function confirmHandle() {
|
||||
if (!number.value) return
|
||||
goodsItem.value.productId = goodsItem.value.id
|
||||
goodsItem.value.number = number.value
|
||||
|
||||
emit("success", goodsItem.value);
|
||||
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;
|
||||
emit("success", { ...goodsItem.value.skuList[0], number: number.value, type: goodsItem.value.type });
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@@ -120,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 {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" title="发现新版本" width="500" :close-on-click-modal="false"
|
||||
<!-- <el-dialog v-model="showDialog" title="发现新版本" width="500" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" :show-close="false">
|
||||
<div class="message">
|
||||
{{ updataInfo.message }}
|
||||
@@ -15,17 +15,19 @@
|
||||
<template v-if="!isUpload">
|
||||
立即更新
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
下载中...
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
</template>
|
||||
<template v-else>
|
||||
立即安装
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog> -->
|
||||
<el-input v-model="authCode" placeholder="请扫描支付码"></el-input>
|
||||
<el-button type="primary" @click="microPayAjax">反扫支付</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -33,6 +35,7 @@ import { onMounted, ref } from 'vue'
|
||||
import { findVersion } from '@/api/user.js'
|
||||
import packageData from "../../../package.json";
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { microPay } from '@/api/order.js'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const updataInfo = ref({})
|
||||
@@ -42,6 +45,8 @@ const uploadSucess = ref(false)
|
||||
const uploadResponse = ref({})
|
||||
const tempFilePath = ref('')
|
||||
|
||||
const authCode = ref('')
|
||||
|
||||
// 检查版本更新
|
||||
async function findVersionAjax() {
|
||||
try {
|
||||
@@ -73,8 +78,24 @@ async function uplaodHandle() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 反扫支付
|
||||
async function microPayAjax() {
|
||||
try {
|
||||
const res = await microPay({
|
||||
authCode: authCode.value,
|
||||
shopId: 1,
|
||||
orderId: 1,
|
||||
buyerRemark: ''
|
||||
})
|
||||
console.log('res===', res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
findVersionAjax()
|
||||
// findVersionAjax()
|
||||
ipcRenderer.on('updateProgress', (event, res) => {
|
||||
// console.log('updateProgress===', event, res);
|
||||
uploadPro.value = res
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
<span class="t2">收银、库存、营销、支付等业务一体化解决方案</span>
|
||||
</div>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" hide-required-asterisk>
|
||||
<el-form-item label="商户号" prop="merchantName">
|
||||
<el-input v-model="form.merchantName" placeholder="请输入注册商户号"></el-input>
|
||||
<el-form-item>
|
||||
<el-radio-group v-model="form.loginType">
|
||||
<el-radio-button label="商户" :value="0"></el-radio-button>
|
||||
<el-radio-button label="员工" :value="1"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="loginName">
|
||||
<el-input v-model="form.loginName" placeholder="请输入11位手机号码"></el-input>
|
||||
<el-form-item label="商户号" prop="username">
|
||||
<el-input v-model="form.username" placeholder="请输入商户号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户号" prop="username" v-if="form.loginType == 1">
|
||||
<el-input v-model="form.staffUserName" placeholder="请输入用户号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录密码" prop="password">
|
||||
<el-input v-model="form.password" :type="passwordType" placeholder="请输入登录密码">
|
||||
@@ -33,6 +39,16 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码" prop="code">
|
||||
<div class="code_wrap">
|
||||
<div class="ipt" style="flex: 1;">
|
||||
<el-input v-model="form.code" placeholder="请输入验证码" style="width: 100%;"></el-input>
|
||||
</div>
|
||||
<el-image :src="codeUrl" style="width: 150px;height: 40px;border-radius: 4px;background-color: #fff;"
|
||||
fit="contain" @click="captchaAjax" v-loading="codeUrlLoading"
|
||||
element-loading-spinner="loading"></el-image>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<div style="width: 100%; display: flex; justify-content: flex-end">
|
||||
<router-link :to="{ name: 'register' }">
|
||||
@@ -71,38 +87,35 @@ import { RandomNumBoth } from "@/utils";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import { douyincheckIn } from "@/api/group";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
import { captcha } from '@/api/account.js'
|
||||
|
||||
const global = useGlobal()
|
||||
|
||||
const shopInfo = useShop()
|
||||
|
||||
const store = useUser();
|
||||
const socket = useSocket();
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const router = useRouter();
|
||||
const formRef = ref(null);
|
||||
const loading = ref(false);
|
||||
const passwordType = ref('password')
|
||||
|
||||
const codeUrl = ref('')
|
||||
const codeUrlLoading = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
serialNumber: RandomNumBoth(1000, 9999),
|
||||
clientType: "pc",
|
||||
merchantName: "",
|
||||
loginName: "",
|
||||
username: "",
|
||||
staffUserName: '',
|
||||
password: "",
|
||||
code: "",
|
||||
uuid: "",
|
||||
loginType: 0, // 0: 商户 1: 员工
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
merchantName: [
|
||||
{
|
||||
required: true,
|
||||
message: " ",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
loginName: [
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: " ",
|
||||
@@ -116,6 +129,13 @@ const rules = reactive({
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
code: [
|
||||
{
|
||||
required: true,
|
||||
message: " ",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 提交
|
||||
@@ -127,25 +147,27 @@ const submitHandle = () => {
|
||||
.userlogin(form)
|
||||
.then(async (res) => {
|
||||
// 登录成功后保存商户号
|
||||
useStorage.set('merchantLoginAccount', form.merchantName)
|
||||
useStorage.set('merchantLoginAccount', form.username)
|
||||
ElMessage.success("登录成功");
|
||||
socket.init();
|
||||
await shopInfo.queryShopInfo()
|
||||
goodsStore.initGoods()
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
name: "home",
|
||||
});
|
||||
}, 1000);
|
||||
const douyin = await douyincheckIn({
|
||||
token: res.token,
|
||||
loginName: res.loginName,
|
||||
token: store.token,
|
||||
loginName: form.username,
|
||||
clientType: 'pc'
|
||||
})
|
||||
useStorage.set('douyin', douyin.userInfo)
|
||||
global.updateData(true)
|
||||
// global.updateData(true)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
loading.value = false;
|
||||
// 重新获取验证码
|
||||
captchaAjax()
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -159,12 +181,30 @@ const logout = () => {
|
||||
.catch(() => { });
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
global.updateData(false)
|
||||
// 获取验证码
|
||||
async function captchaAjax() {
|
||||
try {
|
||||
codeUrlLoading.value = true
|
||||
const res = await captcha()
|
||||
codeUrl.value = res.code
|
||||
form.uuid = res.uuid
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
codeUrlLoading.value = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
store.initRoute()
|
||||
global.updateData(false)
|
||||
captchaAjax()
|
||||
let merchantLoginAccount = useStorage.get('merchantLoginAccount')
|
||||
if (merchantLoginAccount) {
|
||||
form.merchantName = merchantLoginAccount
|
||||
form.username = merchantLoginAccount
|
||||
form.loginType = useStorage.get('loginType')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -221,10 +261,20 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.version {
|
||||
padding-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.code_wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.code_img {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="visableDialog" title="余额明细" width="500">
|
||||
<div class="box">
|
||||
<div class="box1" v-loading="tableData.loading">
|
||||
<div class="dialog_footer" v-for="(item, index) in tableData.list" :key="index">
|
||||
<div class="dialog_footer_left">
|
||||
<span>{{ item.biz_name }}</span>
|
||||
<span>{{ dayjs(item.create_time).format("YYYY-MM-DD HH:mm:ss") }}</span>
|
||||
</div>
|
||||
<div class="dialog_footer_right">
|
||||
<span :class="{ active: item.type == '+' }">
|
||||
<template v-if="item.type == '+'">+</template>
|
||||
<template v-else>-</template>
|
||||
¥{{ formatDecimal(item.amount) }}
|
||||
</span>
|
||||
<span>余额:¥{{ formatDecimal(item.balance) }}</span>
|
||||
</div>
|
||||
<div class="btm" style="width: 80px;">
|
||||
<el-button type="primary"
|
||||
v-if="item.biz_code == 'scanMemberIn' || item.biz_code == 'cashMemberIn'"
|
||||
@click="showRefundHandle(item)" :disabled="item.is_return == 1">
|
||||
<template v-if="item.is_return == 0">退款</template>
|
||||
<template v-if="item.is_return == 1">已退</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty description="暂无数据" v-if="!tableData.list.length" />
|
||||
</div>
|
||||
<div class="page_wrap">
|
||||
<el-pagination v-model:current-page="tableData.page" background layout="prev, pager, next, total"
|
||||
:total="tableData.total" @current-change="memberqueryMemberAccountAjax" />
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" title="会员充值退款">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
|
||||
<el-form-item label="退款金额" prop="amount">
|
||||
<el-input-number v-model="form.amount" :min="1" :max="refundItem.amount"
|
||||
placeholder="请输入退款金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退款说明">
|
||||
<el-input v-model="form.remark" placeholder="请输入退款说明" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div style="padding: 0 20px 20px;">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="refundHandle">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="退款密码" :type="2" input-type="password" placeholder="请输入退款密码"
|
||||
@success="passwordSuccess" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import md5 from "js-md5";
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { dayjs, ElMessage } from 'element-plus'
|
||||
import { formatDecimal } from '@/utils/index'
|
||||
import { returnFlow, memberqueryMemberAccount } from '@/api/member/index.js'
|
||||
import { queryPwdInfo, staffPermission } from '@/api/user.js'
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
|
||||
const memberId = ref('')
|
||||
|
||||
const visableDialog = ref(false)
|
||||
|
||||
const tableData = reactive({
|
||||
page: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 会员流水
|
||||
async function memberqueryMemberAccountAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
let res = await memberqueryMemberAccount({
|
||||
memberId: memberId.value,
|
||||
page: tableData.page,
|
||||
pageSize: 10
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.total = res.total
|
||||
tableData.list = res.list
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const emits = defineEmits(['refund'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const form = reactive({
|
||||
amount: 1,
|
||||
remark: ''
|
||||
})
|
||||
const rules = reactive({
|
||||
amount: [
|
||||
{
|
||||
trigger: 'blur',
|
||||
required: true,
|
||||
message: '请输入退款金额'
|
||||
}
|
||||
]
|
||||
})
|
||||
const loading = ref(false)
|
||||
const refundItem = ref({})
|
||||
const formRef = ref(null)
|
||||
|
||||
async function showRefundHandle(item) {
|
||||
try {
|
||||
await staffPermission('yun_xu_tui_kuan')
|
||||
refundItem.value = item
|
||||
form.amount = item.amount
|
||||
showDialog.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 线上充值退款
|
||||
function refundHandle() {
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
let res = await queryPwdInfo()
|
||||
loading.value = false
|
||||
if (res.isMemberReturn == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 得到退款密码
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await returnFlow({
|
||||
flowId: refundItem.value.id,
|
||||
remark: form.remark,
|
||||
amount: form.amount,
|
||||
pwd: e ? md5(e) : '',
|
||||
})
|
||||
ElMessage.success('退款成功')
|
||||
form.amount = 1
|
||||
form.remark = ''
|
||||
showDialog.value = false
|
||||
loading.value = false
|
||||
emits('refund')
|
||||
memberqueryMemberAccountAjax()
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
memberId.value = id
|
||||
visableDialog.value = true
|
||||
memberqueryMemberAccountAjax()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
|
||||
.box1 {
|
||||
height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.page_wrap {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.dialog_footer:nth-child(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dialog_footer {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.dialog_footer_left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog_footer_right {
|
||||
width: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-right: 20px;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 16px;
|
||||
|
||||
&.active {
|
||||
color: #fc3d3d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
167
src/views/member/components/addUserDrawer.vue
Normal file
167
src/views/member/components/addUserDrawer.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" title="添加会员" top="10vh" @closed="resetHandle">
|
||||
<div class="height_auto" style="height: 400px;">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="left">
|
||||
<el-form-item label="用户头像">
|
||||
<UploadImg ref="UploadImgRef" @success="e => form.headImg = e" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" placeholder="请输入用户昵称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号码" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请输入电话号码"
|
||||
@input="phoneInput($event, 'phone')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="会员生日">
|
||||
<el-date-picker v-model="form.birthDay" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
|
||||
placeholder="请选择会员生日">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="form.sex">
|
||||
<el-radio-button label="男" :value="1"></el-radio-button>
|
||||
<el-radio-button label="女" :value="0"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="账户积分">
|
||||
<el-input v-model="form.accountPoints" placeholder="请输入账户积分"
|
||||
@input="phoneInput($event, 'accountPoints')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="钱包余额">
|
||||
<el-input v-model="form.amount" placeholder="请输入钱包余额"
|
||||
@input="phoneInput($event, 'amount')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否会员">
|
||||
<el-radio-group v-model="form.isVip">
|
||||
<el-radio-button label="否" :value="0"></el-radio-button>
|
||||
<el-radio-button label="是" :value="1"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="closeHandle">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" @click="confirmHandle">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import UploadImg from '@/components/uploadImg.vue'
|
||||
import { addShopUser } from '@/api/account.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { inputFilterInt, regPhone, inputFilterFloat } from '@/utils/index.js'
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const UploadImgRef = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const formRef = ref(null)
|
||||
|
||||
const form = ref({
|
||||
headImg: '', // 用户头像
|
||||
nickName: '', // 用户昵称
|
||||
phone: '', // 电话号码
|
||||
birthDay: '', // 会员生日
|
||||
sex: '', // 0-女 1男
|
||||
accountPoints: '', // 账户积分
|
||||
amount: '', // 钱包余额
|
||||
isVip: 0, // 是否会员
|
||||
})
|
||||
|
||||
const rules = ref({
|
||||
nickName: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户昵称',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) {
|
||||
return callback(new Error('请输入电话号码'))
|
||||
} else if (!regPhone(value)) {
|
||||
return callback(new Error('请输入正确的电话号码'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const resetForm = ref({})
|
||||
|
||||
function phoneInput(e, key) {
|
||||
if (key == 'amount') {
|
||||
setTimeout(() => {
|
||||
form.value[key] = inputFilterFloat(e)
|
||||
}, 50)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
form.value[key] = inputFilterInt(e)
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
// 提交
|
||||
function confirmHandle() {
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
await addShopUser(form.value)
|
||||
ElMessage.success('添加成功')
|
||||
closeHandle()
|
||||
emits('success')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function closeHandle() {
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
function resetHandle() {
|
||||
form.value = { ...resetForm.value }
|
||||
}
|
||||
|
||||
function show() {
|
||||
showDialog.value = true
|
||||
|
||||
setTimeout(() => {
|
||||
UploadImgRef.value.init()
|
||||
}, 50)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetForm.value = { ...form.value }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
padding-top: var(--el-font-size-base);
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
394
src/views/member/components/recordDialog.vue
Normal file
394
src/views/member/components/recordDialog.vue
Normal file
@@ -0,0 +1,394 @@
|
||||
<template>
|
||||
<el-dialog v-model="visableDialog" title="余额明细" top="10vh" width="550" @closed="closeHandle">
|
||||
<div class="box">
|
||||
<div class="box1" v-loading="tableData.loading">
|
||||
<div class="dialog_footer" v-for="(item, index) in tableData.list" :key="index">
|
||||
<div class="dialog_footer_left">
|
||||
<span>{{ labelFilter(item.bizCode) }}</span>
|
||||
<span>{{ item.createTime }}</span>
|
||||
</div>
|
||||
<div class="dialog_footer_right">
|
||||
<span class="active" v-if="item.amount > 0">
|
||||
+¥{{ formatDecimal(item.amount) }}
|
||||
</span>
|
||||
<span v-else>
|
||||
-¥{{ formatDecimal(+JSON.stringify(item.amount).replace('-', '')) }}
|
||||
</span>
|
||||
<span>余额:¥{{ formatDecimal(item.balance) }}</span>
|
||||
</div>
|
||||
<div class="btm" style="width: 80px;">
|
||||
<el-button type="primary"
|
||||
v-if="item.bizCode == 'cashIn' || item.bizCode == 'wechatIn' || item.bizCode == 'alipayIn'"
|
||||
@click="showRefundHandle(item)" :disabled="item.amount == item.refundAmount">
|
||||
<template v-if="item.refundAmount < item.amount">退款</template>
|
||||
<template v-if="item.amount == item.refundAmount">已退</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty description="暂无数据" v-if="!tableData.list.length" />
|
||||
</div>
|
||||
<div class="page_wrap">
|
||||
<el-pagination v-model:current-page="tableData.page" background layout="prev, pager, next, total"
|
||||
:total="tableData.total" :pager-count="5" @current-change="memberqueryMemberAccountAjax" />
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" top="1vh" title="会员充值退款">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
|
||||
<el-form-item label="当前余额">
|
||||
<span>{{ refundItem.amount }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="充值金额">
|
||||
<span>{{ refundItem.inAmount }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="已退金额">
|
||||
<el-input v-model="refundItem.inRefundAmount" disabled />
|
||||
</el-form-item>
|
||||
<template v-if="refundItem.giftAmount - refundItem.giftRefundAmount > 0">
|
||||
<el-form-item label="赠送金额">
|
||||
<el-input v-model="refundItem.giftAmount" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="已退赠送金额">
|
||||
<el-input v-model="refundItem.giftRefundAmount" disabled />
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="退款金额" prop="amount">
|
||||
<el-input-number v-model="form.amount" :min="0.01" :max="form.max" placeholder="请输入" />
|
||||
<div class="tips" v-if="refundItem.giftAmount - refundItem.giftRefundAmount > 0">
|
||||
注意:一旦退款,优先扣除赠送金额</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="退款说明" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入退款说明" />
|
||||
<div class="remark_tag">
|
||||
<div class="item" v-for="(item, index) in remarkTagList" :key="index"
|
||||
@click="addRmarkHandle(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
<div class="item" @click="form.remark = ''">
|
||||
<el-icon>
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
清空
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div style="padding: 0 20px 20px;width: 100%;display: flex;justify-content: space-between;">
|
||||
<el-button type="danger" @click="handleRefund">手动退款</el-button>
|
||||
<div class="btn" style="display: flex;">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="refundHandle">原路返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="退款密码" :type="2" input-type="password" placeholder="请输入退款密码"
|
||||
@success="passwordSuccess" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import md5 from "js-md5";
|
||||
import { reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { formatDecimal } from '@/utils/index'
|
||||
import { shopUserChargeFlow } from '@/api/account.js'
|
||||
import { refundVipBefore, refundVip } from '@/api/order.js'
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { useUser } from '@/store/user.js'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
|
||||
const userStore = useUser()
|
||||
const globalStore = useGlobal()
|
||||
const userInfo = ref('')
|
||||
const visableDialog = ref(false)
|
||||
const tableData = reactive({
|
||||
page: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 重置
|
||||
function closeHandle() {
|
||||
tableData.page = 1
|
||||
tableData.total = 0
|
||||
tableData.loading = false
|
||||
tableData.list = []
|
||||
}
|
||||
|
||||
// 过滤流水名称
|
||||
function labelFilter(type) {
|
||||
let item = globalStore.bizCodes.find(item => item.type == type)
|
||||
if (item) {
|
||||
return item.label
|
||||
} else {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
// 会员流水
|
||||
async function memberqueryMemberAccountAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
let res = await shopUserChargeFlow({
|
||||
userId: userInfo.value.userId,
|
||||
bizCode: '',
|
||||
page: tableData.page,
|
||||
pageSize: 10
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.total = +res.totalRow
|
||||
tableData.list = res.records
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const emits = defineEmits(['refund'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const form = reactive({
|
||||
amount: 0,
|
||||
max: 999,
|
||||
remark: ''
|
||||
})
|
||||
const rules = reactive({
|
||||
amount: [
|
||||
{
|
||||
trigger: 'blur',
|
||||
required: true,
|
||||
message: '请输入退款金额'
|
||||
}
|
||||
],
|
||||
remark: [
|
||||
{
|
||||
trigger: 'blur',
|
||||
required: true,
|
||||
message: '请输入退款原因'
|
||||
}
|
||||
]
|
||||
})
|
||||
const loading = ref(false)
|
||||
const refundItem = ref({})
|
||||
const formRef = ref(null)
|
||||
const flowItem = ref({})
|
||||
const cashRefund = ref(false)
|
||||
const remarkTagList = ref([
|
||||
'点错了',
|
||||
'不要了',
|
||||
'没货了'
|
||||
])
|
||||
|
||||
// 添加备注
|
||||
function addRmarkHandle(item) {
|
||||
if (form.remark.length) {
|
||||
form.remark += `,${item}`
|
||||
} else {
|
||||
form.remark = item
|
||||
}
|
||||
}
|
||||
|
||||
// 显示充值退款
|
||||
async function showRefundHandle(item) {
|
||||
try {
|
||||
// await staffPermission('yun_xu_tui_kuan')
|
||||
// 退款前置操作
|
||||
flowItem.value = item
|
||||
const res = await refundVipBefore({
|
||||
shopId: item.shopId,
|
||||
userId: item.userId,
|
||||
flowId: item.id
|
||||
})
|
||||
refundItem.value = res
|
||||
|
||||
if (res.amount - (res.giftAmount - res.giftRefundAmount) - (res.inAmount - res.inRefundAmount) <= 0) {
|
||||
ElMessage.error('剩余可退款金额不足')
|
||||
form.amount = 0
|
||||
return
|
||||
}
|
||||
|
||||
if (res.amount - (res.giftAmount - res.giftRefundAmount) >= (res.inAmount - res.inRefundAmount)) {
|
||||
form.amount = formatDecimal(res.inAmount - res.inRefundAmount, 2, true)
|
||||
} else {
|
||||
form.amount = formatDecimal(res.amount - res.giftAmount - res.giftRefundAmount, 2, true)
|
||||
}
|
||||
|
||||
form.max = form.amount
|
||||
showDialog.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 线上充值退款
|
||||
function refundHandle() {
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
// 更新店铺详情获取最新的密码规则
|
||||
await userStore.getShopInfo()
|
||||
loading.value = false
|
||||
if (userStore.shopInfo.isMemberInPwd == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 显示手动退款
|
||||
function handleRefund() {
|
||||
ElMessageBox.confirm('请线下手动转账给客户或现金,一旦操作完成无法修改订单状态,请慎重操作!', '注意', {
|
||||
confirmButtonText: '已在线下完成退款'
|
||||
}).then(async () => {
|
||||
cashRefund.value = true
|
||||
await userStore.getShopInfo()
|
||||
loading.value = false
|
||||
if (userStore.shopInfo.isMemberInPwd == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 得到退款密码
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
loading.value = true
|
||||
await refundVip({
|
||||
shopId: flowItem.value.shopId,
|
||||
userId: flowItem.value.userId,
|
||||
flowId: flowItem.value.id,
|
||||
refAmount: form.amount,
|
||||
remark: form.remark,
|
||||
outOfRange: false,
|
||||
cashRefund: cashRefund.value,
|
||||
pwd: e,
|
||||
})
|
||||
ElMessage.success('退款成功')
|
||||
form.amount = 1
|
||||
form.remark = ''
|
||||
showDialog.value = false
|
||||
loading.value = false
|
||||
emits('refund')
|
||||
memberqueryMemberAccountAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function show(row) {
|
||||
userInfo.value = row
|
||||
visableDialog.value = true
|
||||
cashRefund.value = false
|
||||
memberqueryMemberAccountAjax()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.remark_tag {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding-top: 10px;
|
||||
|
||||
.item {
|
||||
height: 35px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
|
||||
&:active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
|
||||
.box1 {
|
||||
height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.page_wrap {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.dialog_footer:nth-child(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dialog_footer {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.dialog_footer_left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog_footer_right {
|
||||
width: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-right: 20px;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 16px;
|
||||
|
||||
&.active {
|
||||
color: #fc3d3d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -15,7 +15,7 @@ import fastPayCard from "@/components/fastPayCard.vue";
|
||||
|
||||
const props = defineProps({
|
||||
userInfo: {
|
||||
type: Object,
|
||||
type: [Object,String],
|
||||
default: {}
|
||||
}
|
||||
})
|
||||
@@ -33,7 +33,9 @@ function paySuccess() {
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
fastPayCardRef.value.reset();
|
||||
setTimeout(() => {
|
||||
fastPayCardRef.value.reset();
|
||||
}, 100)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
807
src/views/member/index copy.vue
Normal file
807
src/views/member/index copy.vue
Normal file
@@ -0,0 +1,807 @@
|
||||
<template>
|
||||
<div class="orderbox">
|
||||
<div class="orderbox_left">
|
||||
<div class="demo_tabs" v-if="props.membershow == '0'">
|
||||
<div class="demo_tabs_div">
|
||||
<el-input v-model="tableData.phone" placeholder="请输入手机号" @input="inputChange" clearable @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" />
|
||||
<el-button style="margin-left: 10px;" type="primary" @click="addMemberHandle">添加</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="tableData.list" style="width: 100%;margin-top: 10px;height:80%;"
|
||||
:row-class-name="tableRowClassName" @cell-click="cellclicktableData" v-loading="loading">
|
||||
<el-table-column prop="name" label="昵称" />
|
||||
<el-table-column prop="telephone" label="手机" width="200px" />
|
||||
<el-table-column prop="code" label="编号" width="150px" />
|
||||
<el-table-column prop="level" label="等级" />
|
||||
<el-table-column prop="levelConsume" label="积分" />
|
||||
<el-table-column prop="amount" label="余额" />
|
||||
</el-table>
|
||||
<el-pagination layout="prev, pager, next, jumper" style="margin-top: 20px;" :total="Number(tableData.total)"
|
||||
@current-change="handleCurrentChange" />
|
||||
</div>
|
||||
<div class="orderbox_right">
|
||||
<div class="orderbox_right_top">
|
||||
<div class="orderbox_right_topdiv">
|
||||
<span>会员昵称:</span>
|
||||
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].name : '无' }}</span>
|
||||
</div>
|
||||
<div class="orderbox_right_topdiv">
|
||||
<span>手机号码:</span>
|
||||
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].telephone : '无' }}</span>
|
||||
</div>
|
||||
<div class="orderbox_right_topdiv">
|
||||
<span>会员编号:</span>
|
||||
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].code : '无' }}</span>
|
||||
</div>
|
||||
<div class="orderbox_right_topdiv">
|
||||
<span>会员等级:</span>
|
||||
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].level : '无' }}</span>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item">
|
||||
<div class="orderbox_right_top_item_one">
|
||||
<el-icon :size="24" style="color:#ffbc42 ;">
|
||||
<Money />
|
||||
</el-icon>
|
||||
<span class="orderbox_right_top_item_onespan">会员积分</span>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item_tow">{{ tableData.list.length != 0 ?
|
||||
tableData.list[datarow].levelConsume : '无' }}</div>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item" @click="dialogRef.show(tableData.list[datarow].id)">
|
||||
<div class="orderbox_right_top_item_one">
|
||||
<el-icon :size="24" style="color:#00b58d ;">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<span class="orderbox_right_top_item_onespan">储值余额</span>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item_tow">
|
||||
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].amount : '无' }}</span>
|
||||
<el-icon size="10">
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="orderbox_right_top_item">
|
||||
<div class="orderbox_right_top_item_one">
|
||||
<el-icon :size="24" style="color:#00b58d ;">
|
||||
<CopyDocument />
|
||||
</el-icon>
|
||||
<span class="orderbox_right_top_item_onespan">优惠券</span>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item_tow">
|
||||
<span>0</span>
|
||||
<el-icon size="10">
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="orderbox_right_input" style="margin-top:20px ;" v-if="props.membershow == '1'">
|
||||
<el-input placeholder="请输入会员手机号或者编号" v-model="tableData.phone" clearable
|
||||
@input="inputChange"></el-input>
|
||||
</div>
|
||||
<keyboard v-if="props.membershow == '1'" @consumeFees="consumeFees"></keyboard>
|
||||
<div class="orderbox_right_button" v-if="props.membershow == '0'">
|
||||
<!-- <el-button style="width: 100%;" @click="toHome">创建订单</el-button> -->
|
||||
<!-- <el-button style="width: 60%;" type="primary" @click="recharge = true">账户充值</el-button> -->
|
||||
<el-button style="width: 100%;" type="primary" @click="menberAddNnum">账户充值</el-button>
|
||||
</div>
|
||||
<div class="orderbox_right_button" v-if="props.membershow == '1'">
|
||||
<router-link to="/" style="width: 35%;">
|
||||
<el-button style="width: 100%;" @click="memberaddshowclose">添加会员</el-button>
|
||||
</router-link>
|
||||
<el-button style="width: 60%;" type="primary">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<add ref="dialogRef" @refund="refundSuccess" @page-change="MemberAccount" />
|
||||
<el-dialog v-model="memberaddshow" title="添加会员" width="600" :before-close="memberaddshowclose"
|
||||
@open="membrform = { ...resetMembrform }">
|
||||
<el-form ref="formRef" :rules="rules" :model="membrform" label-width="70px" hide-required-asterisk>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="membrform.phone" @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickName">
|
||||
<el-input v-model="membrform.nickName" @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生日" prop="birthDay">
|
||||
<el-col :span="11">
|
||||
<el-date-picker v-model="membrform.birthDay" type="date" placeholder="请选择生日" style="width: 100%"
|
||||
@focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" />
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-radio-group v-model="membrform.sex">
|
||||
<el-radio :label="1">男</el-radio>
|
||||
<el-radio :label="2">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="等级" prop="level">
|
||||
<el-select v-model="membrform.level" placeholder="请选择等级">
|
||||
<el-option label="等级1" value="1" />
|
||||
<el-option label="等级2" value="2" />
|
||||
<el-option label="等级3" value="3" />
|
||||
<el-option label="等级4" value="4" />
|
||||
<el-option label="等级5" value="5" />
|
||||
<el-option label="等级6" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button style="width: 100%;" type="primary" @click="createMembermemberSubmit">确认</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="recharge" title="会员充值" width="400" :before-close="handlerecharge">
|
||||
<div class="recharge_footer">
|
||||
<!-- <div class="recharge_footer_item">
|
||||
<div class="recharge_footer_items" v-for="(item, index) in 6" :key="index">
|
||||
<div>充1000送300</div>
|
||||
<div>充1000.00到13000.00</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="recharge_footer_itemright">
|
||||
<div class="recharge_footer_itemright_input">
|
||||
<div>充值金额:</div>
|
||||
<div v-if="moneys">{{ moneys ? moneys : '请输入充值金额' }}</div>
|
||||
|
||||
</div>
|
||||
<div class='keyboard'>
|
||||
<cwxeyboard @confirmEvent="confirmEvent" @consumeFee="consumeFee" btn-color="orange" title="支付">
|
||||
</cwxeyboard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<el-dialog width="500" v-model="payCarddialogVisible" style="padding: 0; " title="会员充值"
|
||||
:close-on-click-modal="false">
|
||||
<payCard :amount="moneys" :orderId="orderId" :selecttype="1" @paySuccess="paySuccess" />
|
||||
</el-dialog>
|
||||
<userCharge ref="userChargeRef" :userInfo="tableData.list[datarow]" @paySuccess="asyncqueryMembermember" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted } from 'vue'
|
||||
import { ElMessage, dayjs } from 'element-plus'
|
||||
import { queryMembermember, createMembermember, memberqueryMemberAccount, accountPaymember } from '@/api/member/index.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import lodash from 'lodash'
|
||||
import add from '@/views/member/components/add.vue'
|
||||
import cwxeyboard from '@/components/cwx-keyboard/cwx-keyboard.vue'
|
||||
import keyboard from '@/views/home/components/keyboard.vue'
|
||||
import payCard from '@/components/payCard/payCard.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import userCharge from './components/userCharge.vue'
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
|
||||
const userChargeRef = ref(null)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const store = useUser()
|
||||
|
||||
const stored = ref(false)//储值余额
|
||||
|
||||
const handleClose = async () => {
|
||||
stored.value = !stored.value
|
||||
}
|
||||
|
||||
const dialogRef = ref(null)
|
||||
|
||||
const emit = defineEmits('paySuccess')
|
||||
|
||||
function paySuccess() {
|
||||
payCarddialogVisible.value = false
|
||||
recharge.value = false
|
||||
moneys.value = 0
|
||||
asyncqueryMembermember()
|
||||
emit('paySuccess')
|
||||
}
|
||||
|
||||
const props = defineProps({//首页传值
|
||||
membershow: {
|
||||
type: String,
|
||||
default: '0'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '提示'
|
||||
},
|
||||
amount: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const flowingwater = reactive({//获取流水初始化
|
||||
total: '',
|
||||
list: []
|
||||
})
|
||||
|
||||
const consumeFee = (e) => { //接收子组件值 并赋值给父组件
|
||||
moneys.value = e
|
||||
}
|
||||
|
||||
const consumeFees = (e) => {
|
||||
tableData.phone = e
|
||||
}
|
||||
|
||||
const payCarddialogVisible = ref(false)
|
||||
|
||||
const orderId = ref('')
|
||||
|
||||
// 添加会员
|
||||
async function addMemberHandle() {
|
||||
try {
|
||||
await staffPermission('yun_xu_guan_li_hui_yuan_xin_xi')
|
||||
memberaddshow.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 账户充值
|
||||
async function menberAddNnum() {
|
||||
try {
|
||||
await staffPermission('yun_xu_xiu_gai_hui_yuan_yu_e')
|
||||
userChargeRef.value.show()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 退款成功
|
||||
function refundSuccess() {
|
||||
asyncqueryMembermember()
|
||||
MemberAccount()
|
||||
}
|
||||
|
||||
const confirmEvent = async () => {//子组件 确认按钮
|
||||
orderId.value = tableData.list[datarow.value].id
|
||||
payCarddialogVisible.value = true
|
||||
// try {
|
||||
// let res = await accountPaymember({
|
||||
// shopId: store.userInfo.shopId,
|
||||
// memberId: tableData.list[datarow.value].id,
|
||||
// amount: moneys.value
|
||||
// })
|
||||
// if (res == null) {
|
||||
// recharge.value = false
|
||||
// moneys.value = 0
|
||||
// ElMessage({
|
||||
// message: '充值成功',
|
||||
// type: 'success',
|
||||
// })
|
||||
// resetMembrform.value = { ...membrform.value }
|
||||
// asyncqueryMembermember()
|
||||
// }
|
||||
// } catch (error) {
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
const MemberAccount = async (page = 1) => {//获取流水
|
||||
try {
|
||||
let res = await memberqueryMemberAccount({
|
||||
memberId: tableData.list[datarow.value].id,
|
||||
page: page,
|
||||
pageSize: 10
|
||||
})
|
||||
flowingwater.total = res.total
|
||||
// flowingwater.list = res.list
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const recharge = ref(false)//充值
|
||||
|
||||
const memberaddshow = ref(false) //添加会员
|
||||
|
||||
const memberaddshowclose = () => {
|
||||
memberaddshow.value = !memberaddshow.value
|
||||
}
|
||||
|
||||
const tableData = reactive({//表格数据
|
||||
list: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
phone: '',
|
||||
total: ''
|
||||
})
|
||||
|
||||
const inputChange = lodash.debounce(function () { //搜索手机号
|
||||
asyncqueryMembermember()
|
||||
}, 500)
|
||||
|
||||
const asyncqueryMembermember = async () => {//会员列表数据
|
||||
loading.value = true
|
||||
let res = await queryMembermember({
|
||||
shopId: store.userInfo.shopId,
|
||||
page: tableData.page,
|
||||
pageSize: 10,
|
||||
phone: tableData.phone,
|
||||
isFlag: 0
|
||||
})
|
||||
if (res) {
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 300)
|
||||
tableData.list = res.list
|
||||
MemberAccount()
|
||||
tableData.total = res.total
|
||||
}
|
||||
}
|
||||
|
||||
const tableRowClassName = ({ row, rowIndex }) => {//动态给tab加样式
|
||||
if (rowIndex === datarow.value) {
|
||||
return 'warning-row'
|
||||
} return ''
|
||||
}
|
||||
|
||||
const datarow = ref(0) //初始化右边
|
||||
const cellclicktableData = (row, column, cell, event) => {
|
||||
const index = tableData.list.findIndex(item => item.id == row.id)
|
||||
datarow.value = index
|
||||
MemberAccount()
|
||||
|
||||
}
|
||||
|
||||
const handleCurrentChange = (val) => { //页码
|
||||
tableData.page = val
|
||||
datarow.value = 0
|
||||
asyncqueryMembermember()
|
||||
}
|
||||
|
||||
const handlerecharge = () => {
|
||||
recharge.value = !recharge.value
|
||||
}
|
||||
|
||||
const resetMembrform = ref({})
|
||||
|
||||
const membrform = ref({ //membrform 添加会员表单
|
||||
phone: '',
|
||||
nickName: '',
|
||||
level: '',
|
||||
birthDay: '',
|
||||
sex: '',
|
||||
level: ''
|
||||
})
|
||||
|
||||
const formRef = ref(null); //ref membrform
|
||||
|
||||
const rules = reactive({ // membrform验证
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入11位手机号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
nickName: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入昵称",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
sex: [
|
||||
{
|
||||
required: true,
|
||||
message: "请选择性别",
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
level: [
|
||||
{
|
||||
required: true,
|
||||
message: "请选择等级",
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
birthDay: [
|
||||
{
|
||||
type: 'date',
|
||||
required: true,
|
||||
message: '请选择生日日期',
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
});
|
||||
const createMembermemberSubmit = async () => { ///添加会员
|
||||
formRef.value.validate(async (valid) => {
|
||||
console.log(valid)
|
||||
if (valid) {
|
||||
|
||||
let res = await createMembermember({
|
||||
shopId: store.userInfo.shopId,
|
||||
phone: membrform.value.phone,
|
||||
nickName: membrform.value.nickName,
|
||||
sex: membrform.value.sex,
|
||||
level: membrform.value.level,
|
||||
birthDay: dayjs(membrform.value.birthDay).format("YYYY-MM-DD")
|
||||
})
|
||||
if (res == null) {
|
||||
|
||||
memberaddshowclose()
|
||||
ElMessage({
|
||||
message: '添加成功',
|
||||
type: 'success',
|
||||
})
|
||||
asyncqueryMembermember()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
const moneys = ref('')// 钱数
|
||||
|
||||
// 创建会员订单
|
||||
const toHome = () => {
|
||||
// useStorage.set('memberInfo', tableData.list[datarow.value])
|
||||
global.setOrderMember(tableData.list[datarow.value])
|
||||
router.push({
|
||||
name: 'home'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// resetMembrform.value = { ...membrform.value }
|
||||
asyncqueryMembermember()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.orderbox {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
|
||||
.orderbox_left {
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 16px 0;
|
||||
|
||||
.demo_tabs {
|
||||
.demo_tabs_div {
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.demo_tabs_box {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
|
||||
.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 {
|
||||
display: flex;
|
||||
margin-left: 20px;
|
||||
flex-direction: column;
|
||||
height: 70px;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.demo_tabs_boxitem_tow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 70px;
|
||||
justify-content: space-around;
|
||||
align-items: flex-end;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.orderbox_right {
|
||||
position: relative;
|
||||
width: 40%;
|
||||
padding: 20px;
|
||||
margin-left: 10px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
|
||||
.orderbox_right_top {
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
background: #8b008b;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
|
||||
.orderbox_right_topdiv:nth-child(1) {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.orderbox_right_topdiv {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.orderbox_right_top_item {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
padding: 6px 10px;
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
border-radius: 10px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.orderbox_right_top_item_one {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.orderbox_right_top_item_onespan {
|
||||
color: black;
|
||||
margin-left: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.orderbox_right_top_item_tow {
|
||||
color: black;
|
||||
margin-left: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.orderbox_right_button {
|
||||
position: absolute;
|
||||
width: 90%;
|
||||
left: 50%;
|
||||
bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transform: translateX(-50%) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog_footer:nth-child(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dialog_footer {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.dialog_footer_left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog_footer_right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
|
||||
span:nth-child(1) {
|
||||
color: #fc3d3d;
|
||||
font-size: 16px;
|
||||
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recharge_footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.recharge_footer_item {
|
||||
width: 60%;
|
||||
background: #f2f2f2;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-flow: wrap;
|
||||
|
||||
.recharge_footer_items {
|
||||
background: #187ead;
|
||||
padding: 16px 22px;
|
||||
width: 45%;
|
||||
height: fit-content;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
|
||||
div:nth-child(1) {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div:nth-child(2) {
|
||||
color: #bad9e7;
|
||||
font-size: 14px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recharge_footer_itemright {
|
||||
padding-left: 20px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
.recharge_footer_itemright_input {
|
||||
width: 100%;
|
||||
background: #333333;
|
||||
border-radius: 10px;
|
||||
padding: 0 6px;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
div:nth-child(1) {
|
||||
color: #56792e;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
div:nth-child(2) {
|
||||
color: #88937c;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.keyboard {
|
||||
width: 100%;
|
||||
height: 40vh;
|
||||
background: #FFFFFF;
|
||||
|
||||
.key-row {
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
position: relative;
|
||||
height: 10vh;
|
||||
line-height: 10vh;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.keyboard .key-cell {
|
||||
flex: 1;
|
||||
-webkit-box-flex: 1;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.keyboard .key-confirm {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
height: 30vh;
|
||||
width: 25%;
|
||||
line-height: 30vh;
|
||||
color: #FFFFFF;
|
||||
z-index: 5;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.keyboard .key-confirm2 {
|
||||
position: absolute;
|
||||
height: 10vh;
|
||||
width: 25%;
|
||||
line-height: 10vh;
|
||||
z-index: 9999;
|
||||
right: 0;
|
||||
top: 60px;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.key-zero-and-point {
|
||||
display: flex;
|
||||
height: 10vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 75%;
|
||||
font-size: 30px;
|
||||
|
||||
.zero {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 66.66%;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.point {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 33.33%;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.key-cell:active {
|
||||
color: white;
|
||||
background: black; //黑色
|
||||
opacity: 0.1; //这里重要,就是通过这个透明度来设置
|
||||
}
|
||||
|
||||
.a:active,
|
||||
.key-confirm2:active {
|
||||
color: white;
|
||||
background: black; //黑色
|
||||
opacity: 0.1; //这里重要,就是通过这个透明度来设置
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
112
src/views/order/components/allGoodsDialog.vue
Normal file
112
src/views/order/components/allGoodsDialog.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<!-- 全部商品弹窗 -->
|
||||
<template>
|
||||
<el-dialog :title="`全部商品(${allOrderGoods.length})`" width="600px" v-model="allOrderGoodsShow" top="2vh"
|
||||
@close="allOrderGoodsShow = false">
|
||||
<div class="goods_wrap">
|
||||
<div class="row" v-for="item in allOrderGoods" :key="item.id">
|
||||
<div class="cover">
|
||||
<el-image :src="item.productImg" fit="cover"
|
||||
style="width: 100px;height: 100px;border-radius: 8px;"></el-image>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
<span class="t">{{ item.productName }}</span>
|
||||
<span class="amount">¥{{ formatDecimal(+item.payAmount) }}</span>
|
||||
</div>
|
||||
<div class="num remark">
|
||||
<span>备注: {{ item.remark || "无" }}</span>
|
||||
<div class="n">
|
||||
<span>¥{{ formatDecimal(+item.unitPrice) }}</span>
|
||||
<span>x{{ item.num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="num">
|
||||
<span>出菜时间:{{ item.dishOutTime }}</span>
|
||||
</div>
|
||||
<div class="num">
|
||||
<span>上菜时间:{{ item.foodServeTime }}</span>
|
||||
</div>
|
||||
<div class="num" v-if="item.returnNum">
|
||||
<span>退菜数量:{{ item.returnNum }}</span>
|
||||
</div>
|
||||
<div class="num" v-if="item.refundNum">
|
||||
<span>退单数量:{{ item.refundNum }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const allOrderGoods = ref([])
|
||||
const allOrderGoodsShow = ref(false)
|
||||
|
||||
function show(obj) {
|
||||
allOrderGoodsShow.value = true
|
||||
allOrderGoods.value = obj
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.goods_wrap {
|
||||
height: 75vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
padding: 10px 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: space-between;
|
||||
|
||||
.t {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 16px;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
.num {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 6px;
|
||||
|
||||
&.remark {
|
||||
color: #999;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.n {
|
||||
color: #999;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,20 @@
|
||||
<template>
|
||||
<el-date-picker v-model="dateVlaue" type="daterange" :editable="false" :shortcuts="shortcuts" range-separator="至"
|
||||
start-placeholder="开始时间" end-placeholder="结束时间" :clearable="false" @change="dateConfirm" />
|
||||
start-placeholder="开始时间" end-placeholder="结束时间" :clearable="false" :style="{ width: `${props.width}px` }"
|
||||
@change="dateConfirm" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { dayjs } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 200
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const shortcuts = [
|
||||
@@ -56,7 +64,7 @@ const shortcuts = [
|
||||
},
|
||||
]
|
||||
|
||||
const dateVlaue = ref([dayjs(), dayjs()])
|
||||
const dateVlaue = ref([])
|
||||
const format = ["YYYY-MM-DD 00:00:00", "YYYY-MM-DD 23:59:59"];
|
||||
|
||||
// 确认选择时间
|
||||
@@ -68,11 +76,20 @@ function dateConfirm(value) {
|
||||
])
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 创建组件后执行一次时间传递
|
||||
emits('success', [
|
||||
dayjs(dateVlaue[0]).format(format[0]),
|
||||
dayjs(dateVlaue[1]).format(format[1]),
|
||||
])
|
||||
// 重置
|
||||
function reset() {
|
||||
dateVlaue.value = []
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
reset
|
||||
})
|
||||
|
||||
// onMounted(() => {
|
||||
// // 创建组件后执行一次时间传递
|
||||
// emits('success', [
|
||||
// dayjs(dateVlaue[0]).format(format[0]),
|
||||
// dayjs(dateVlaue[1]).format(format[1]),
|
||||
// ])
|
||||
// })
|
||||
</script>
|
||||
241
src/views/order/components/printDrawer.vue
Normal file
241
src/views/order/components/printDrawer.vue
Normal file
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<el-drawer v-model="showDrawer" direction="rtl" size="300px">
|
||||
<template #header>
|
||||
<h4>订单打印</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="prinr_wrap" v-loading="loading">
|
||||
<div class="header center">{{ userStore.shopInfo.shopName }}</div>
|
||||
<div class="row center">结算单 <span style="margin-left: 10px;">#{{ orderInfo.orderNum }}</span></div>
|
||||
<div class="row center">桌号:{{ orderInfo.tableName || '无' }}</div>
|
||||
<div class="row" style="margin-top: 20px">
|
||||
订单号:{{ orderInfo.orderNo }}
|
||||
</div>
|
||||
<div class="row">交易时间:{{ orderInfo.paidTime }}</div>
|
||||
<div class="row">收银员:{{ userStore.userInfo.name }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="row" style="margin-top: 10px">
|
||||
<div class="table">
|
||||
<div class="table_head">
|
||||
<div class="item">品名</div>
|
||||
<div class="item">单价</div>
|
||||
<div class="item">数量</div>
|
||||
<div class="item">小计</div>
|
||||
</div>
|
||||
<div class="table_content">
|
||||
<div class="table_row" v-for="item in orderInfo.cartList" :key="item.id">
|
||||
<div v-if="item.productType == 'package'">
|
||||
<div class="flex">
|
||||
<div class="item">
|
||||
{{ item.productName }}
|
||||
</div>
|
||||
<div class="item">
|
||||
{{ formatDecimal(item.payAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex" v-for="val in item.proGroupInfo.map(item => item.goods).flat()" :key="val.proId">
|
||||
<div class="item">>{{ val.proName }}</div>
|
||||
<div class="item">0.00</div>
|
||||
<div class="item">{{ val.number }}</div>
|
||||
<div class="item">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex" v-else>
|
||||
<div class="item">
|
||||
<div>{{ item.productName }}</div>
|
||||
<div v-if="item.skuName">规格:{{ item.skuName }}</div>
|
||||
</div>
|
||||
<div class="item">{{ formatDecimal(item.price) }}</div>
|
||||
<div class="item">{{ item.num }}</div>
|
||||
<div class="item">{{ formatDecimal(item.payAmount) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row between">
|
||||
<span>原价</span>
|
||||
<span>{{ formatDecimal(+orderInfo.originAmount) }}</span>
|
||||
</div>
|
||||
<div class="row between">
|
||||
<span>折扣</span>
|
||||
<span>-{{ orderInfo.status == "unpaid"
|
||||
? "0.00"
|
||||
: formatDecimal(orderInfo.originAmount - orderInfo.orderAmount) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row between blod">
|
||||
<span>实付</span>
|
||||
<span> ¥{{ formatDecimal(+orderInfo.payAmount) }} </span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">备注:{{ orderInfo.remark }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="drawer_footer">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%" :loading="printLoading" @click="printHandle('label')">
|
||||
打印标签
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" :loading="printLoading" @click="printHandle('normal')">
|
||||
打印小票
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import {
|
||||
formatDecimal,
|
||||
getOrderByIdAjax,
|
||||
commOrderPrintData,
|
||||
} from "@/utils/index.js";
|
||||
import { orderPrint } from "@/api/order.js";
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const userStore = useUser();
|
||||
const printStore = usePrint();
|
||||
|
||||
const showDrawer = ref(false);
|
||||
const orderInfo = ref({});
|
||||
const loading = ref(false);
|
||||
const printLoading = ref(false);
|
||||
|
||||
// 打印操作
|
||||
async function printHandle(type) {
|
||||
try {
|
||||
printLoading.value = true;
|
||||
switch (type) {
|
||||
case "normal":
|
||||
// 打印订单小票
|
||||
if (printStore.deviceNoteList.length) {
|
||||
printStore.pushReceiptData(commOrderPrintData(orderInfo.value));
|
||||
} else {
|
||||
await orderPrint({
|
||||
id: orderInfo.value.id,
|
||||
type: 0 // 0结算单 1预结算单 2退款单
|
||||
})
|
||||
ElMessage.success('云打印小票成功')
|
||||
}
|
||||
break;
|
||||
case "label":
|
||||
// 打印标签小票
|
||||
printStore.labelPrint(commOrderPrintData(orderInfo.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
printLoading.value = false;
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
async function show(row) {
|
||||
try {
|
||||
showDrawer.value = true;
|
||||
loading.value = true;
|
||||
orderInfo.value = await getOrderByIdAjax(row.id);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.prinr_wrap {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 50px;
|
||||
color: #333;
|
||||
|
||||
.header {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 14px 0;
|
||||
border-bottom: 1px dashed #666;
|
||||
}
|
||||
|
||||
.blod {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.table {
|
||||
--itemWidth: 45px;
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.item {
|
||||
&:nth-child(1) {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: var(--itemWidth);
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
width: var(--itemWidth);
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
width: var(--itemWidth);
|
||||
}
|
||||
}
|
||||
|
||||
.table_head {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.table_row {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer_footer {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
528
src/views/order/components/refundDrawer.vue
Normal file
528
src/views/order/components/refundDrawer.vue
Normal file
@@ -0,0 +1,528 @@
|
||||
<template>
|
||||
<el-drawer v-model="isShow" direction="rtl" size="80%">
|
||||
<template #header>
|
||||
<h4>订单号:{{ item.orderNo }}</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<!-- <div class="order_info">
|
||||
<div class="row"><span>订单类型:</span>{{ filterLable('orderType', item.orderType) }}</div>
|
||||
<div class="row"><span>平台类型:</span>{{ filterLable('platformType', item.platformType) }}</div>
|
||||
<div class="row"><span>用餐模式:</span>{{ filterLable('dineMode', item.dineMode) }}</div>
|
||||
<div class="row"><span>订单备注:</span>{{ item.remark }}</div>
|
||||
<div class="row"><span>支付类型:</span>{{ filterLable('payType', item.payType) }}</div>
|
||||
<div class="row"><span>支付单号:</span>{{ item.payOrderNo }}</div>
|
||||
<div class="row"><span>支付金额:</span>¥{{ item.payAmount }}</div>
|
||||
<div class="row"><span>支付时间:</span>{{ item.paidTime }}</div>
|
||||
<div class="row"><span>订单金额(含折扣):</span>¥{{ item.orderAmount }}</div>
|
||||
<div class="row"><span>订单原金额(不含折扣):</span>¥{{ item.originAmount }}</div>
|
||||
</div> -->
|
||||
<div class="table">
|
||||
<div class="tab_head">
|
||||
<el-radio-group v-model="refundType" @change="refundTypeChange">
|
||||
<el-radio-button label="整单退" :value="1" />
|
||||
<el-radio-button label="部分退" :value="2" />
|
||||
<el-radio-button label="自定义" :value="3" />
|
||||
</el-radio-group>
|
||||
<div class="amount">
|
||||
<el-input ref="amountInputRef" v-model="refundAmount" style="width: 400px;height: 42px;"
|
||||
:readonly="refundType != 3" placeholder="请输入退款金额" @input="inputChange">
|
||||
<template #prepend>¥</template>
|
||||
<template #append>最多可退¥{{ formatDecimal(item.payAmount - item.refundAmount, 2) }}</template>
|
||||
</el-input>
|
||||
<!-- <template>
|
||||
退款金额:¥{{ formatDecimal(refundType == 1 ? item.originAmount - item.refundAmount : amount) }}
|
||||
</template> -->
|
||||
</div>
|
||||
</div>
|
||||
<el-table ref="tableRef" :data="item.onGoods" brder stripe @selection-change="tabSelectChange">
|
||||
<el-table-column type="selection" width="35" :selectable="selectable"></el-table-column>
|
||||
<el-table-column label="商品信息">
|
||||
<template v-slot="scope">
|
||||
<div class="goods_info">
|
||||
<el-image :src="scope.row.productImg" style="width: 50px;height: 50px;"></el-image>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
<span>{{ scope.row.productName }}</span>
|
||||
</div>
|
||||
<div class="sku" v-if="scope.row.skuName">{{ scope.row.skuName }}</div>
|
||||
<div class="sku">¥{{ formatDecimal(+scope.row.unitPrice) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单数量" prop="num" width="100"></el-table-column>
|
||||
<el-table-column label="支付金额" width="100">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(+scope.row.payAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="退款数量" width="170">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.refund_number" :disabled="refundType != 2" :min="0"
|
||||
:max="formatDecimal(scope.row.num - scope.row.refundNum - scope.row.returnNum, 2, true)"
|
||||
style="width: 130px;" @change="numberChange">
|
||||
</el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template v-if="item.returnGoods.length">
|
||||
<div class="tips" style="margin-top: 20px;padding-bottom: 10px;">以下为已退部分退单/退菜</div>
|
||||
<el-table :data="item.returnGoods" brder stripe>
|
||||
<el-table-column label="商品信息">
|
||||
<template v-slot="scope">
|
||||
<div class="goods_info">
|
||||
<el-image :src="scope.row.productImg" style="width: 50px;height: 50px;"></el-image>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
<span>{{ scope.row.productName }}</span>
|
||||
</div>
|
||||
<div class="sku" v-if="scope.row.skuName">{{ scope.row.skuName }}</div>
|
||||
<div class="sku">¥{{ formatDecimal(+scope.row.unitPrice) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单数量" prop="num" width="100"></el-table-column>
|
||||
<el-table-column label="支付金额" width="100">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(+scope.row.payAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已退款数量" width="170">
|
||||
<template v-slot="scope">
|
||||
<div class="column">
|
||||
<div class="row">退单数量:{{ scope.row.refundNum }}</div>
|
||||
<div class="row">退菜数量:{{ scope.row.returnNum }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<div class="ipt">
|
||||
<el-input type="textarea" :rows="4" v-model="remark" placeholder="请输入退单原因" />
|
||||
</div>
|
||||
<div class="remark_tag">
|
||||
<div class="item" v-for="(item, index) in remarkTagList" :key="index" @click="addRmarkHandle(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
<div class="item" @click="remark = ''">
|
||||
<el-icon>
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
清空
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="drawer_footer">
|
||||
<div class="btn">
|
||||
<el-button type="danger" style="width: 100%;" :loading="loading"
|
||||
@click="handleRefund">手动退款</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="loading"
|
||||
@click="refundHandle()">原路退回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="退款密码" :type="2" input-type="password" placeholder="请输入退款密码"
|
||||
@success="passwordSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from 'lodash'
|
||||
import { ref } from 'vue'
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { formatDecimal, inputFilterFloat } from "@/utils/index.js";
|
||||
import { refundOrder, orderPrint } from '@/api/order.js'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useUser } from '@/store/user.js'
|
||||
import dayjs from 'dayjs'
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const store = useUser()
|
||||
const printStore = usePrint();
|
||||
const globalStore = useGlobal()
|
||||
const isShow = ref(false)
|
||||
const item = ref({})
|
||||
const tableRef = ref(null)
|
||||
const modify = ref(false)
|
||||
const refundAmount = ref('')
|
||||
const refundType = ref(1)
|
||||
const remark = ref('')
|
||||
const remarkTagList = ref([
|
||||
'顾客取消',
|
||||
'等待时间长',
|
||||
'支付错误',
|
||||
'商品不满意',
|
||||
'服务态度不满意',
|
||||
'打包费'
|
||||
])
|
||||
const loading = ref(false)
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const cash = ref(false)
|
||||
const amountInputRef = ref(null)
|
||||
|
||||
// 退款密码
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
loading.value = true
|
||||
let rows = tableRef.value.getSelectionRows()
|
||||
let refundDetails = []
|
||||
if (refundType.value != 1) {
|
||||
refundDetails = tableRef.value.getSelectionRows().map(val => {
|
||||
return {
|
||||
id: val.id,
|
||||
returnAmount: val.payAmount,
|
||||
num: val.refund_number
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let data = {
|
||||
orderId: item.value.id,
|
||||
refundAmount: formatDecimal(+refundAmount.value),
|
||||
modify: modify.value,
|
||||
cash: cash.value,
|
||||
refundReason: remark.value,
|
||||
refundDetails: refundDetails,
|
||||
pwd: e,
|
||||
};
|
||||
|
||||
await refundOrder(data)
|
||||
ElMessage.success('退款成功')
|
||||
await printRefund(rows)
|
||||
isShow.value = false
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 显示手动退款
|
||||
function handleRefund() {
|
||||
ElMessageBox.confirm('请线下手动转账给客户或现金,一旦操作完成无法修改订单状态,请慎重操作!', '注意', {
|
||||
confirmButtonText: '已在线下完成退款'
|
||||
}).then(() => {
|
||||
cash.value = true
|
||||
refundHandle()
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 开始退款
|
||||
async function refundHandle(cash = false) {
|
||||
try {
|
||||
let rows = tableRef.value.getSelectionRows()
|
||||
if (refundType.value == 2) {
|
||||
if (!rows.length) {
|
||||
ElMessage.error('请选择退款商品')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!refundAmount.value) {
|
||||
ElMessage.error('请请输入退款金额')
|
||||
return
|
||||
}
|
||||
|
||||
if (!remark.value) {
|
||||
ElMessage.error('请请输入退款原因')
|
||||
return
|
||||
}
|
||||
|
||||
if (refundAmount.value <= 0) {
|
||||
ElMessage.error('无可退金额')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
await store.getShopInfo()
|
||||
if (store.shopInfo.isReturnPwd == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 打印退款小票
|
||||
async function printRefund(rows) {
|
||||
try {
|
||||
if (printStore.deviceNoteList.length) {
|
||||
// 本地打印
|
||||
const data = {
|
||||
shop_name: store.shopInfo.shopName,
|
||||
loginAccount: store.userInfo.name,
|
||||
carts: [],
|
||||
amount: formatDecimal(+refundAmount.value),
|
||||
remark: remark.value,
|
||||
orderInfo: item.value,
|
||||
outNumber: item.value.id,
|
||||
createdAt: item.value.createTime,
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
}
|
||||
|
||||
rows.map(item => {
|
||||
data.carts.push(
|
||||
{
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.skuName,
|
||||
salePrice: formatDecimal(+item.unitPrice),
|
||||
totalAmount: formatDecimal(+item.payAmount)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
printStore.printRefund(data);
|
||||
} else {
|
||||
// 云打印
|
||||
await orderPrint({ id: item.value.id, type: 2 })
|
||||
ElMessage.success('云打印退款单成功')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 数量变化
|
||||
function numberChange() {
|
||||
let rows = tableRef.value.getSelectionRows()
|
||||
tabSelectChange(rows)
|
||||
}
|
||||
|
||||
// 选择退款项
|
||||
const tabSelectChange = _.debounce(function (val) {
|
||||
refundAmount.value = ''
|
||||
let num = 0
|
||||
val.map(item => {
|
||||
if ((+item.refundNum + +item.returnNum) < item.num) {
|
||||
num += item.refund_number * item.unitPrice
|
||||
}
|
||||
})
|
||||
if (num) {
|
||||
if (num >= item.value.payAmount) {
|
||||
refundAmount.value = formatDecimal(item.value.payAmount - item.value.refundAmount)
|
||||
} else {
|
||||
refundAmount.value = formatDecimal(num)
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
|
||||
// 禁用所有行的选择
|
||||
const selectable = (row, index) => {
|
||||
return refundType.value == 2;
|
||||
};
|
||||
|
||||
// 初始化抽屉
|
||||
function resetDrawer() {
|
||||
modify.value = false
|
||||
refundAmount.value = ''
|
||||
refundType.value = 1
|
||||
remark.value = ''
|
||||
cash.value = false
|
||||
}
|
||||
|
||||
function show(row) {
|
||||
resetDrawer()
|
||||
|
||||
isShow.value = true
|
||||
let newRow = { ...row }
|
||||
remark.value = ''
|
||||
|
||||
let onGoods = []
|
||||
let returnGoods = []
|
||||
newRow.goods.map(item => {
|
||||
// 可退的最大数量,下单数量 - 已退数量 - 退菜数量
|
||||
let refundMaxNum = item.num - item.refundNum - item.returnNum
|
||||
|
||||
if (refundMaxNum <= 0) {
|
||||
item.refund_number = item.num
|
||||
// 已经退过,不在允许操作
|
||||
returnGoods.push(item)
|
||||
} else {
|
||||
// 可以操作的退款数量
|
||||
item.refund_number = item.num
|
||||
onGoods.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
newRow.onGoods = onGoods
|
||||
newRow.returnGoods = returnGoods
|
||||
|
||||
item.value = newRow
|
||||
|
||||
setTimeout(() => {
|
||||
tableRef.value.clearSelection()
|
||||
refundTypeChange(1)
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 筛选类型
|
||||
function filterLable(key, type) {
|
||||
let item = globalStore[key].find(item => item.type == type)
|
||||
if (item && item.type) {
|
||||
return item.label
|
||||
} else {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
// 切换退单类型
|
||||
function refundTypeChange(val) {
|
||||
switch (val) {
|
||||
case 1:
|
||||
modify.value = false
|
||||
// tableRef.value.toggleAllSelection()
|
||||
// 遍历数据,将每一行设置为选中状态
|
||||
item.value.onGoods.forEach((row) => {
|
||||
tableRef.value.toggleRowSelection(row, true);
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
modify.value = false
|
||||
if (item.value.onGoods.length == 1) {
|
||||
item.value.onGoods.forEach((row) => {
|
||||
tableRef.value.toggleRowSelection(row, true);
|
||||
});
|
||||
} else {
|
||||
tableRef.value.clearSelection()
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
tableRef.value.clearSelection()
|
||||
refundAmount.value = ''
|
||||
modify.value = true
|
||||
amountInputRef.value.focus()
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义退款金额输入
|
||||
const inputChange = _.debounce(function (n) {
|
||||
if (n > item.value.payAmount - item.value.refundAmount) {
|
||||
refundAmount.value = formatDecimal(item.value.payAmount - item.value.refundAmount, 2)
|
||||
} else {
|
||||
refundAmount.value = inputFilterFloat(n)
|
||||
}
|
||||
}, 300)
|
||||
|
||||
// 添加备注
|
||||
function addRmarkHandle(item) {
|
||||
if (remark.value.length) {
|
||||
remark.value += `,${item}`
|
||||
} else {
|
||||
remark.value = item
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
// onMounted(() => {
|
||||
// setTimeout(() => {
|
||||
// refundTypeChange(1)
|
||||
// }, 100)
|
||||
// })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.drawer_footer {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.order_info {
|
||||
.row {
|
||||
margin-bottom: 4px;
|
||||
|
||||
span {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
.ipt {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
}
|
||||
|
||||
.tab_head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: var(--el-font-size-base);
|
||||
|
||||
.amount {
|
||||
color: var(--el-color-danger);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.remark_tag {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
|
||||
&:active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 6px;
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.n {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.sku {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1209
src/views/order/index copy.vue
Normal file
1209
src/views/order/index copy.vue
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,9 @@
|
||||
<template #append>桌</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="顺延数量" v-if="addTabForm.isPostpone">
|
||||
<el-input-number v-model="addTabForm.postponeNum" :min="1" placeholder="请输入顺延数量" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer" style="display: flex;">
|
||||
<el-button style="width: 100%" @click="showAddTable = false">
|
||||
@@ -42,7 +45,7 @@
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { addCallTable } from '@/api/queue.js'
|
||||
import { addCallTable } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -59,7 +62,8 @@ const addTabForm = ref({
|
||||
prefix: '',
|
||||
start: '',
|
||||
isPostpone: 0,
|
||||
nearNum: ''
|
||||
postponeNum: 1, // 顺延数量
|
||||
nearNum: 1
|
||||
})
|
||||
|
||||
const addTabFormRules = ref({
|
||||
@@ -109,7 +113,7 @@ function addTabConfirmHandle() {
|
||||
if (addTabForm.value.id) {
|
||||
addTabForm.value.callTableId = addTabForm.value.id
|
||||
}
|
||||
const res = await addCallTable(addTabForm.value)
|
||||
await addCallTable(addTabForm.value)
|
||||
addTabFormLoading.value = false
|
||||
showAddTable.value = false
|
||||
ElMessage.success(addTabForm.value.id ? '编辑成功' : '添加成功')
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<el-form-item label="选择桌型">
|
||||
<el-radio-group v-model="form.callTableId">
|
||||
<el-radio :value="item.id" border v-for="item in list" :key="item.id">{{ item.name
|
||||
}}</el-radio>
|
||||
}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phone">
|
||||
@@ -26,7 +26,7 @@
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { takeNumber } from '@/api/queue.js'
|
||||
import { takeNumber } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -41,7 +41,7 @@ const formRef = ref(null)
|
||||
const resetForm = ref({})
|
||||
const form = ref({
|
||||
callTableId: '',
|
||||
shopId: '',
|
||||
userId: '',
|
||||
phone: '',
|
||||
note: '',
|
||||
name: ''
|
||||
@@ -70,9 +70,12 @@ function confirmHandle() {
|
||||
try {
|
||||
if (vaild) {
|
||||
loading.value = true
|
||||
form.value.shopId = store.userInfo.shopId
|
||||
form.value.note = list.value.find(item => item.id == form.value.callTableId).note
|
||||
form.value.name = list.value.find(item => item.id == form.value.callTableId).name
|
||||
|
||||
console.log(form.value);
|
||||
|
||||
|
||||
await takeNumber(form.value)
|
||||
loading.value = false
|
||||
ElMessage.success('取号成功')
|
||||
@@ -103,6 +106,6 @@ defineExpose({
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetForm.value = { ...form }
|
||||
resetForm.value = { ...form.value }
|
||||
})
|
||||
</script>
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
<script setup>
|
||||
import { dayjs } from 'element-plus'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callRecord } from '@/api/queue.js'
|
||||
import { reactive, ref } from 'vue';
|
||||
import { callRecord } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -72,16 +72,16 @@ async function callRecordAjax() {
|
||||
tableData.loading = true
|
||||
const res = await callRecord({
|
||||
callTableId: '',
|
||||
shopId: store.userInfo.shopId,
|
||||
shopId: store.shopInfo.id,
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = res.records
|
||||
tableData.total = res.total
|
||||
tableData.total = +res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
tableData.loading = false
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<el-dialog title="提示" v-model="visible">
|
||||
<div class="content">
|
||||
<div style="font-size: 18px;">正在叫号,请稍等</div>
|
||||
<el-alert :title="statusList[item.status].text" :type="statusList[item.status].type" :closable="false" />
|
||||
<el-alert :title="statusList[item.state].text" :type="statusList[item.state].type" :closable="false" />
|
||||
</div>
|
||||
<div class="footer" style="display: flex;">
|
||||
<el-button style="width: 100%" @click="confirmHandle(2)">完成</el-button>
|
||||
@@ -13,8 +13,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { updateState } from '@/api/queue.js'
|
||||
import { ref } from 'vue';
|
||||
import { callTableCallState } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -41,8 +41,7 @@ const statusList = {
|
||||
// 过号修改状态
|
||||
async function confirmHandle(state) {
|
||||
try {
|
||||
await updateState({
|
||||
shopId: store.userInfo.shopId,
|
||||
await callTableCallState({
|
||||
callQueueId: item.value.id,
|
||||
state: state
|
||||
})
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<el-form-item label="排队即将排到通知">
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<el-input disabled style="width: 50%;" v-model="config.nearMsg"></el-input>
|
||||
<el-input v-model="config.nearNum" disabled style="margin-top: 10px;">
|
||||
<el-input v-model="config.nearNum" style="margin-top: 10px;">
|
||||
<template #prepend>前面等待</template>
|
||||
<template #append>桌时提醒</template>
|
||||
</el-input>
|
||||
@@ -64,8 +64,8 @@ import UploadImg from '@/components/uploadImg.vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import AddTab from './addTab.vue'
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callTable, delCallTable, callTableConfig, callTableConfigPut } from '@/api/queue.js'
|
||||
import { reactive, ref } from 'vue';
|
||||
import { callTableConfig, callTableConfigPut, getCallTable, delCallTable } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -103,8 +103,7 @@ function delCallTableHandle(row) {
|
||||
ElMessageBox.confirm('确认要删除吗?', '注意').then(async () => {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await delCallTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
await delCallTable({
|
||||
callTableId: row.id
|
||||
})
|
||||
getTableAjax()
|
||||
@@ -118,10 +117,10 @@ function delCallTableHandle(row) {
|
||||
async function getTableAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await callTable({
|
||||
const res = await getCallTable({
|
||||
page: 1,
|
||||
size: 100,
|
||||
shopId: store.userInfo.shopId,
|
||||
shopId: store.shopInfo.id,
|
||||
callTableId: '',
|
||||
state: ''
|
||||
})
|
||||
@@ -138,7 +137,7 @@ const config = ref({})
|
||||
const UploadImgRef = ref(null)
|
||||
async function callTableConfigAjax() {
|
||||
try {
|
||||
const res = await callTableConfig({ shopId: store.userInfo.shopId })
|
||||
const res = await callTableConfig({ shopId: store.shopInfo.id })
|
||||
config.value = res
|
||||
form.value.nearNum = res.nearNum
|
||||
if (res.bgCover) {
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<el-empty description="暂无数据~" v-if="!queueList.list.length" style="width: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<div class="pagination" style="display: flex;justify-content: flex-end;">
|
||||
<el-pagination v-model:current-page="queueList.page" v-model:page-size="queueList.size"
|
||||
layout="total, prev, pager, next" :total="queueList.total" background
|
||||
@current-change="queueListChange" @size-change="queueListChange">
|
||||
@@ -64,7 +64,7 @@ import Record from './components/record.vue'
|
||||
import GetNumber from './components/getNumber.vue'
|
||||
import ResultModal from './components/resultModal.vue'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callRecord, callTable, callTableQueue, updateState, callTableCall } from '@/api/queue.js'
|
||||
import { callTableQueue, getCallTable, callTableCall, callTableCallState } from '@/api/account.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
@@ -78,10 +78,9 @@ const tabHeader = ref([])
|
||||
const tabActive = ref('')
|
||||
async function callTableAjax() {
|
||||
try {
|
||||
const res = await callTable({
|
||||
const res = await getCallTable({
|
||||
page: 1,
|
||||
size: 100,
|
||||
shopId: store.userInfo.shopId,
|
||||
callTableId: '',
|
||||
state: ''
|
||||
})
|
||||
@@ -111,17 +110,16 @@ async function callTableQueueAjax() {
|
||||
const res = await callTableQueue({
|
||||
page: queueList.page,
|
||||
size: queueList.size,
|
||||
shopId: store.userInfo.shopId,
|
||||
shopId: store.shopInfo.id,
|
||||
callTableId: tabActive.value,
|
||||
state: ''
|
||||
})
|
||||
queueList.loading = false
|
||||
queueList.list = res.records
|
||||
queueList.total = res.total
|
||||
queueList.total = +res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
queueList.loading = false
|
||||
}
|
||||
queueList.loading = false
|
||||
}
|
||||
// 取号 排队列表获取 end
|
||||
|
||||
@@ -129,8 +127,7 @@ async function callTableQueueAjax() {
|
||||
function cancaleHandle(item) {
|
||||
ElMessageBox.confirm('确定要取消排队吗?', '注意').then(async () => {
|
||||
try {
|
||||
await updateState({
|
||||
shopId: store.userInfo.shopId,
|
||||
await callTableCallState({
|
||||
callQueueId: item.id,
|
||||
state: '-1'
|
||||
})
|
||||
@@ -147,7 +144,6 @@ async function callHandle(item) {
|
||||
try {
|
||||
startSpeech(`请${item.callNum}用餐`)
|
||||
const res = await callTableCall({
|
||||
shopId: store.userInfo.shopId,
|
||||
callQueueId: item.id,
|
||||
})
|
||||
ResultModalRef.value.show({
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
<el-icon class="icon">
|
||||
<Clock />
|
||||
</el-icon>
|
||||
<span class="t">{{ status[props.tableInfo.status] }}</span>
|
||||
<span class="t">{{tableStatusList.find(val => val.type == props.tableInfo.status).label}}</span>
|
||||
</div>
|
||||
<div class="cart" v-loading="payLoading" v-if="props.tableInfo.status == 'using'">
|
||||
<div class="cart" v-loading="payLoading" v-if="props.tableInfo.status == 'unsettled'">
|
||||
<div class="cart_list">
|
||||
<div class="item" v-for="item in cartList" :key="item.id">
|
||||
<div class="top">
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<span class="n">x{{ item.number }}</span>
|
||||
<span class="p">¥{{ item.salePrice }}</span>
|
||||
<span class="name">{{ item.productName }}</span>
|
||||
<span class="n">x{{ item.num }}</span>
|
||||
<span class="p">¥{{ item.price }}</span>
|
||||
</div>
|
||||
<div class="tag_wrap" v-if="item.skuName">
|
||||
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||
@@ -35,14 +35,15 @@
|
||||
<el-button type="success" style="width: 100%;" @click="toOrderMeal(1)">加菜/管理</el-button>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<el-button type="primary" style="width: 100%;" @click="showPayHandle">结算(¥{{
|
||||
<el-button type="primary" style="width: 100%;" :loading="payLoading" @click="showPayHandle">结算(¥{{
|
||||
orderInfo.orderAmount || 0 }})</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="place_order" v-else>
|
||||
<div class="btn">
|
||||
<div class="top">
|
||||
<div class="top"
|
||||
:style="{ '--color': tableStatusList.find(val => val.type == props.tableInfo.status).color }">
|
||||
<el-icon class="icon">
|
||||
<TakeawayBox />
|
||||
</el-icon>
|
||||
@@ -52,7 +53,7 @@
|
||||
<div class="btn_wrap" v-if="props.tableInfo.status == 'idle'">
|
||||
<el-button type="primary" style="width: 100%;" @click="showPeopleNumHandle">开始新订单</el-button>
|
||||
</div>
|
||||
<div class="btn_wrap" v-if="props.tableInfo.status == 'cleaning'">
|
||||
<div class="btn_wrap" v-if="props.tableInfo.status == 'settled'">
|
||||
<el-button type="primary" style="width: 100%;" @click="clearTableStatus">清理完成</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,29 +77,26 @@
|
||||
</transition>
|
||||
</div>
|
||||
<!-- 结算订单 -->
|
||||
<settleAccount ref="settleAccountRef" :cart="cartList" :amount="orderInfo.orderAmount"
|
||||
:remark="orderInfo.remark" :masterId="orderInfo.masterId" :orderInfo="orderInfo" @paySuccess="paySuccess" />
|
||||
<SettleAccount ref="SettleAccountRef" @success="emits('success')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { queryMembermember } from '@/api/member/index.js'
|
||||
import { orderDetail } from '@/api/order/index.js'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import settleAccount from "@/views/home/components/settleAccount.vue";
|
||||
import SettleAccount from '@/views/home/components/settleAccount.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { clearTable } from '@/api/table.js'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
|
||||
const shopStore = useShop()
|
||||
import { shopTableClear } from '@/api/account.js'
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
import { getOrderByIdAjax } from '@/utils/index.js'
|
||||
import tableStatusList from '../statusList.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const router = useRouter()
|
||||
const global = useGlobal()
|
||||
const store = useUser()
|
||||
const SettleAccountRef = ref(null)
|
||||
|
||||
const emits = defineEmits(['close', 'success'])
|
||||
|
||||
@@ -109,7 +107,6 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const showPeopleNum = ref(false)
|
||||
const peopleNum = ref(0)
|
||||
const peopleNumInputValue = ref('')
|
||||
@@ -123,30 +120,31 @@ function inputFocus() {
|
||||
peopleNum.value = 'custom'
|
||||
}
|
||||
|
||||
const settleAccountRef = ref(null)
|
||||
const orderInfo = ref({})
|
||||
const cartList = ref([])
|
||||
|
||||
const status = ref({
|
||||
'subscribe': '预定',
|
||||
'closed': '关台',
|
||||
'idle': '空闲',
|
||||
'using': '开台中',
|
||||
'pending': '挂单中',
|
||||
'paying': '结算中',
|
||||
'cleaning': '台桌清理中'
|
||||
})
|
||||
|
||||
const payLoading = ref(false)
|
||||
|
||||
// 显示结算页面
|
||||
function showPayHandle() {
|
||||
settleAccountRef.value.show()
|
||||
async function showPayHandle() {
|
||||
try {
|
||||
payLoading.value = true
|
||||
await goodsStore.historyOrderAjax('', props.tableInfo.orderId)
|
||||
goodsStore.selectTable({
|
||||
...props.tableInfo,
|
||||
num: props.tableInfo.useNum
|
||||
})
|
||||
goodsStore.calcCartInfo()
|
||||
SettleAccountRef.value.show()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
payLoading.value = false
|
||||
}
|
||||
|
||||
// 显示就就餐人数
|
||||
function showPeopleNumHandle() {
|
||||
if (shopStore.info.isTableFee == 1) {
|
||||
if (store.shopInfo.isTableFee == 1) {
|
||||
orderDownHandle()
|
||||
} else {
|
||||
showPeopleNum.value = true
|
||||
@@ -158,15 +156,14 @@ const clearLoading = ref(false)
|
||||
async function clearTableStatus() {
|
||||
try {
|
||||
clearLoading.value = true
|
||||
const res = await clearTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
tableId: props.tableInfo.qrcode
|
||||
await shopTableClear({
|
||||
tableId: props.tableInfo.id
|
||||
})
|
||||
clearLoading.value = false
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
clearLoading.value = false
|
||||
}
|
||||
|
||||
// 获取订单详情
|
||||
@@ -174,22 +171,21 @@ async function getOrderDetail() {
|
||||
try {
|
||||
if (props.tableInfo.orderId) {
|
||||
payLoading.value = true
|
||||
const res = await orderDetail({
|
||||
shopId: store.userInfo.shopId,
|
||||
id: props.tableInfo.orderId
|
||||
})
|
||||
const res = await getOrderByIdAjax(props.tableInfo.orderId)
|
||||
|
||||
console.log(res);
|
||||
|
||||
payLoading.value = false
|
||||
orderInfo.value = res
|
||||
|
||||
cartList.value = res.detailList.map(item => {
|
||||
let obj = {
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
salePrice: item.price,
|
||||
skuName: item.productSkuName
|
||||
}
|
||||
return obj
|
||||
cartList.value = res.cartList
|
||||
|
||||
let total = 0
|
||||
res.cartList.forEach(item => {
|
||||
total += item.payAmount * item.num
|
||||
})
|
||||
|
||||
orderInfo.value.orderAmount = formatDecimal(total)
|
||||
}
|
||||
} catch (error) {
|
||||
payLoading.value = false
|
||||
@@ -215,8 +211,14 @@ function orderDownHandle() {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// 直接点单
|
||||
global.setOrderTable({
|
||||
|
||||
if (!props.tableInfo.tableCode) {
|
||||
ElMessage.error('请绑定桌码后操作')
|
||||
return
|
||||
}
|
||||
|
||||
// 选择完人数后跳转首页
|
||||
goodsStore.selectTable({
|
||||
...props.tableInfo,
|
||||
num: peopleNum.value
|
||||
})
|
||||
@@ -229,7 +231,10 @@ function orderDownHandle() {
|
||||
function toOrderMeal(t) {
|
||||
if (t == 1) {
|
||||
// 直接点单
|
||||
global.setOrderTable(props.tableInfo)
|
||||
goodsStore.selectTable({
|
||||
...props.tableInfo,
|
||||
num: props.tableInfo.useNum
|
||||
})
|
||||
router.push({
|
||||
name: 'home',
|
||||
})
|
||||
@@ -380,7 +385,7 @@ onMounted(() => {
|
||||
$size: 150px;
|
||||
|
||||
.top {
|
||||
background-color: var(--el-color-danger);
|
||||
background-color: #fff;
|
||||
width: $size;
|
||||
height: $size;
|
||||
display: flex;
|
||||
@@ -390,7 +395,7 @@ onMounted(() => {
|
||||
border-radius: 6px;
|
||||
|
||||
.icon {
|
||||
color: #fff;
|
||||
color: var(--color);
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
<div class="tab_container">
|
||||
<div class="tab_head">
|
||||
<el-radio-group v-model="area" @change="queryShopTableAjax">
|
||||
<el-radio-group v-model="area" @change="shopTableAjax">
|
||||
<el-radio-button label="全部" value=""></el-radio-button>
|
||||
<el-radio-button :label="item.name" :value="item.id" v-for="item in areaList"
|
||||
:key="item.id"></el-radio-button>
|
||||
@@ -22,8 +22,8 @@
|
||||
</div>
|
||||
<div class="overflow_y" v-loading="loading">
|
||||
<div class="tab_list">
|
||||
<div class="item"
|
||||
:class="{ active: tableItemActive == index, using: item.status == 'using', closed: item.status == 'closed' }"
|
||||
<div class="item" :class="{ active: tableItemActive == index }"
|
||||
:style="{ '--color': tableStatusList.find(val => val.type == item.status).color }"
|
||||
v-for="(item, index) in tableList" :key="item.id" @click="slectTableHandle(index, item)">
|
||||
<div class="tab_title" :class="`${item.status}`">
|
||||
<span>{{ item.name }}</span>
|
||||
@@ -45,10 +45,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty">
|
||||
<el-empty description="空空如也~" v-if="!tableList.length" />
|
||||
<div class="empty" v-if="!tableList.length">
|
||||
<el-empty description="空空如也~" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<el-pagination background v-model:current-page="query.page" :pager-count="5"
|
||||
layout=" pager, jumper, total" :total="query.total"
|
||||
@current-change="shopTableAjax"></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_card card">
|
||||
@@ -61,16 +66,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryShopArea, queryShopTable } from '@/api/table'
|
||||
|
||||
import { shopArea, shopTable } from "@/api/account.js";
|
||||
import countCard from '@/views/table/components/countCard.vue'
|
||||
import tableInfo from '@/views/table/components/tableInfo.vue'
|
||||
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { dayjs } from 'element-plus'
|
||||
const store = useUser()
|
||||
|
||||
import tableStatusList from './statusList.js'
|
||||
|
||||
const tabActive = ref(0)
|
||||
const tabAreas = ref([
|
||||
@@ -84,14 +85,23 @@ const tabAreas = ref([
|
||||
},
|
||||
{
|
||||
label: '使用中',
|
||||
type: 'using'
|
||||
type: 'unsettled'
|
||||
},
|
||||
// {
|
||||
// label: '已预订',
|
||||
// type: 3,
|
||||
// }
|
||||
{
|
||||
label: '待清理',
|
||||
type: 'settled',
|
||||
},
|
||||
{
|
||||
label: '已预订',
|
||||
type: 'subscribe',
|
||||
}
|
||||
])
|
||||
|
||||
const query = ref({
|
||||
page: 1,
|
||||
size: 12,
|
||||
total: 0
|
||||
})
|
||||
const loading = ref(false)
|
||||
// 区域列表
|
||||
const areaList = ref([])
|
||||
@@ -107,7 +117,7 @@ const slectTable = ref('')
|
||||
// 切换类型
|
||||
function tabChange(item, index) {
|
||||
tabActive.value = index
|
||||
queryShopTableAjax()
|
||||
shopTableAjax()
|
||||
}
|
||||
|
||||
// 计算当前的时间差
|
||||
@@ -118,7 +128,7 @@ function countTime(t) {
|
||||
|
||||
// 支付成功,刷新状态
|
||||
async function paySuccess() {
|
||||
await queryShopTableAjax()
|
||||
await shopTableAjax()
|
||||
slectTableHandle(tableItemActive.value, tableList.value[tableItemActive.value])
|
||||
}
|
||||
|
||||
@@ -140,29 +150,32 @@ function slectTableClose() {
|
||||
}
|
||||
|
||||
// 获取台桌区域
|
||||
async function queryShopAreaAjax() {
|
||||
async function shopAreaAjax() {
|
||||
try {
|
||||
const res = await queryShopArea({
|
||||
shopId: store.userInfo.shopId
|
||||
const res = await shopArea({
|
||||
page: 1,
|
||||
size: 500
|
||||
})
|
||||
areaList.value = res
|
||||
areaList.value = res.records
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取台桌列表
|
||||
async function queryShopTableAjax() {
|
||||
async function shopTableAjax() {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await queryShopTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
const res = await shopTable({
|
||||
page: query.value.page,
|
||||
size: query.value.size,
|
||||
areaId: area.value,
|
||||
tableCode: '',
|
||||
name: '',
|
||||
status: tabAreas.value[tabActive.value].type,
|
||||
page: 1,
|
||||
pageSize: 500
|
||||
})
|
||||
tableList.value = res.list
|
||||
tableList.value = res.records
|
||||
query.value.total = +res.totalRow
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 500)
|
||||
@@ -173,12 +186,18 @@ async function queryShopTableAjax() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryShopAreaAjax()
|
||||
queryShopTableAjax()
|
||||
shopAreaAjax()
|
||||
shopTableAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.cart_wrap {
|
||||
flex: 2;
|
||||
}
|
||||
@@ -243,7 +262,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.overflow_y {
|
||||
height: calc(100vh - 225px);
|
||||
height: calc(100vh - 220px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -251,53 +270,27 @@ onMounted(() => {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
grid-template-rows: auto;
|
||||
gap: var(--el-font-size-base);
|
||||
gap: 10px;
|
||||
|
||||
.item {
|
||||
$closedColor: #aeb8c9;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
padding: 2px;
|
||||
background-color: var(--primary-color);
|
||||
background-color: var(--color);
|
||||
|
||||
&.active {
|
||||
background-color: var(--primary-color);
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.using {
|
||||
background-color: var(--el-color-success);
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.closed {
|
||||
background-color: $closedColor;
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: $closedColor;
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: $closedColor;
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: var(--color);
|
||||
opacity: .2;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,42 +309,20 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.tab_cont {
|
||||
height: 120px;
|
||||
height: 112px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
.icon {
|
||||
color: var(--primary-color);
|
||||
color: var(--color);
|
||||
font-size: 30px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.using {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.t1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 2px;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
position: relative;
|
||||
z-index: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
src/views/table/statusList.js
Normal file
42
src/views/table/statusList.js
Normal file
@@ -0,0 +1,42 @@
|
||||
export default [
|
||||
{
|
||||
label: "未绑定",
|
||||
type: "unbound",
|
||||
color: "#909090",
|
||||
},
|
||||
{
|
||||
label: "空闲",
|
||||
type: "idle",
|
||||
color: "#187CAA",
|
||||
},
|
||||
{
|
||||
label: "点餐中",
|
||||
type: "ordering",
|
||||
color: "#46AEA4",
|
||||
},
|
||||
{
|
||||
label: "未结账",
|
||||
type: "unsettled",
|
||||
color: "#DD3F41",
|
||||
},
|
||||
{
|
||||
label: "支付中",
|
||||
type: "paying",
|
||||
color: "#909090",
|
||||
},
|
||||
{
|
||||
label: "待清台",
|
||||
type: "settled ",
|
||||
color: "#FF9500",
|
||||
},
|
||||
{
|
||||
label: "关台",
|
||||
type: "closed",
|
||||
color: "#DDDDDD",
|
||||
},
|
||||
{
|
||||
label: "预定",
|
||||
type: "subscribe",
|
||||
color: "#58B22C",
|
||||
},
|
||||
];
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="box_content_left_top_item">
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div style="color:#ff5252; font-size: 30px;">
|
||||
{{ infoData.orderNum || 0 }}
|
||||
{{ infoData.orderCount || 0 }}
|
||||
</div>
|
||||
<div style="margin-top: 6px; color: #666;">
|
||||
总订单
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div style="color:#ff5252; font-size: 30px;">
|
||||
¥{{ formatDecimal(infoData.amount || 0) }}
|
||||
¥{{ formatDecimal(infoData.handAmount || 0) }}
|
||||
</div>
|
||||
<div style="margin-top: 6px; color: #666;">
|
||||
营业额
|
||||
@@ -47,7 +47,7 @@
|
||||
</div>
|
||||
<div class="box_content_left_top_item_botton">
|
||||
<div style=" font-size: 20px;">
|
||||
¥{{ formatDecimal(infoData.returnAmount || 0) }}
|
||||
¥{{ formatDecimal(infoData.refundAmount || 0) }}
|
||||
</div>
|
||||
<div style="margin-top: 6px;">
|
||||
退款金额
|
||||
@@ -59,7 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_left_bottom">
|
||||
<el-table :data="infoData.detailList" border style="width: 100%;" height="360px">
|
||||
<el-table :data="infoData.detailList" border style="width: 100%;" height="382px">
|
||||
<el-table-column prop="productName" label="商品名称" />
|
||||
<el-table-column prop="skuName" label="规格名称" />
|
||||
<el-table-column prop="num" label="商品数量" />
|
||||
@@ -73,6 +73,14 @@
|
||||
</div>
|
||||
<div class="box_content_right">
|
||||
<div class="top">
|
||||
<div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
店铺:
|
||||
</div>
|
||||
<div class="box_content_right_tiemright">
|
||||
{{ infoData.shopName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
上岗时间:
|
||||
@@ -86,38 +94,39 @@
|
||||
交班时间:
|
||||
</div>
|
||||
<div class="box_content_right_tiemright">
|
||||
{{ dayjs(infoData.loginOutTime).format("YYYY-MM-DD HH:mm:ss") }}
|
||||
{{ dayjs(infoData.handoverTime).format("YYYY-MM-DD HH:mm:ss") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_right_tiem">
|
||||
<!-- <div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
终端名称:
|
||||
</div>
|
||||
<div class="box_content_right_tiemright">
|
||||
{{ infoData.equipment || '无' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_right_tiem">
|
||||
</div> -->
|
||||
<!-- <div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
备用金:
|
||||
</div>
|
||||
<div class="box_content_right_tiemright">
|
||||
{{ infoData.pettyCash || '无' }}
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
收营员:
|
||||
</div>
|
||||
<div class="box_content_right_tiemright">
|
||||
{{ infoData.userName || '无' }}
|
||||
{{ infoData.staffName || '无' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="is_shop">
|
||||
<div class="button">
|
||||
<el-checkbox v-model="isPrint" border label="是否打印商品销售数据" style="width: 100%" />
|
||||
<el-checkbox v-model="isPrint" :true-value="1" :false-value="0" border
|
||||
label="是否打印商品销售数据" style="width: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_right_tiembutton" :loading="loading" @click="exit">
|
||||
@@ -133,40 +142,31 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ipcRenderer } from "electron";
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage, dayjs } from 'element-plus'
|
||||
import { tglogout } from '@/api/group.js'
|
||||
import { shopInfoqueryDuty, loginlogout, handoverData, handoverprint } from '@/api/work/index.js'
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import { handoverTotal, handover, handoverData, handoverNetworkPrint } from '@/api/account.js'
|
||||
import { useRouter } from "vue-router";
|
||||
import { bySubType } from "@/api/device";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
|
||||
const goodsStore = useGoods();
|
||||
const printStore = usePrint();
|
||||
|
||||
const socket = useSocket();
|
||||
|
||||
const store = useUser();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const dialogVisible = ref(false) //交班
|
||||
//详情数据
|
||||
const infoData = ref({})
|
||||
const loading = ref(false);
|
||||
|
||||
const isPrint = ref(true)
|
||||
const isPrint = ref(1)
|
||||
|
||||
// 查看交班记录
|
||||
async function checkRecord() {
|
||||
try {
|
||||
const res = await staffPermission('yun_xu_cha_kan_suo_you_jiao_ban_ji_lu')
|
||||
// await staffPermission('yun_xu_cha_kan_suo_you_jiao_ban_ji_lu')
|
||||
router.push('/workrecord')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -176,84 +176,49 @@ async function checkRecord() {
|
||||
// 开始交班
|
||||
const exit = async () => {
|
||||
try {
|
||||
await staffPermission('yun_xu_jiao_ban')
|
||||
|
||||
let data = {}
|
||||
// 获取交班打印小票数据
|
||||
data = await handoverData({
|
||||
id: infoData.value.id
|
||||
})
|
||||
|
||||
if (loading.value) return
|
||||
loading.value = true;
|
||||
// await staffPermission('yun_xu_jiao_ban')
|
||||
const res = await handover(isPrint.value)
|
||||
const data = await handoverData(res)
|
||||
if (printStore.deviceNoteList.length) {
|
||||
loading.value = true;
|
||||
|
||||
// 使用本地打印机 打印交班数据
|
||||
data.printTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||
data.printShop = isPrint.value
|
||||
printStore.printWork(data)
|
||||
|
||||
// return
|
||||
await loginlogout({
|
||||
status: 1
|
||||
})
|
||||
|
||||
useStorage.del('userInfo')
|
||||
useStorage.del('token')
|
||||
useStorage.del('douyin')
|
||||
useStorage.del('categorysActive')
|
||||
useStorage.del('updateFlag')
|
||||
|
||||
ElMessage.success("交班成功");
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
name: "login",
|
||||
});
|
||||
}, 1000);
|
||||
loading.value = false;
|
||||
} else {
|
||||
console.log('云打印交班数据');
|
||||
loading.value = true;
|
||||
|
||||
await tglogout()
|
||||
|
||||
// 退出登录
|
||||
await loginlogout({
|
||||
status: 1
|
||||
})
|
||||
|
||||
// 打印交班数据
|
||||
await handoverprint({
|
||||
id: infoData.value.id,
|
||||
isprintProduct: isPrint.value
|
||||
})
|
||||
|
||||
// useStorage.clear()
|
||||
useStorage.del('userInfo')
|
||||
useStorage.del('token')
|
||||
useStorage.del('douyin')
|
||||
useStorage.del('categorysActive')
|
||||
useStorage.del('updateFlag')
|
||||
ElMessage.success("交班成功");
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
name: "login",
|
||||
});
|
||||
}, 1000);
|
||||
loading.value = false;
|
||||
// 使用云打印机 打印交班数据
|
||||
await handoverNetworkPrint(data.id)
|
||||
}
|
||||
socket.close()
|
||||
logoutHandle()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
loading.value = false;
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
async function logoutHandle() {
|
||||
try {
|
||||
loading.value = true;
|
||||
await store.logout()
|
||||
goodsStore.clearAllGoods()
|
||||
ElMessage.success("交班成功");
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
name: "login",
|
||||
});
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
loading.value = false;
|
||||
console.log('退出失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 获取交班打印数据前置
|
||||
const infoshopInfoqueryDutys = async () => {
|
||||
try {
|
||||
let res = await shopInfoqueryDuty({
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
let res = await handoverTotal()
|
||||
infoData.value = res
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -261,19 +226,15 @@ const infoshopInfoqueryDutys = async () => {
|
||||
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true
|
||||
infoshopInfoqueryDutys()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// getPrintList()
|
||||
// bySubTypeAjax()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -286,7 +247,7 @@ onMounted(() => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
padding: 6px 10px;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
color: #161718;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="box_top" @click="clickrecord">
|
||||
<div class="box_top_left" @click="router.back()">
|
||||
<el-icon size="20">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<div class="box_top_right">
|
||||
交班记录
|
||||
<div class="contenr_wrap" style="flex: 1;">
|
||||
<div class="box">
|
||||
<div class="box_top" @click="clickrecord">
|
||||
<div class="box_top_left" @click="router.back()">
|
||||
<el-icon size="20">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<div class="box_top_right">
|
||||
交班记录
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content">
|
||||
<div class="box_content_left">
|
||||
<div class="box_content_left_top">
|
||||
<div class="box_content_left_top_item">
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div>
|
||||
{{ infoData.total }}
|
||||
<div class="box_content">
|
||||
<div class="box_content_left">
|
||||
<div class="box_content_left_top">
|
||||
<div class="box_content_left_top_item">
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div>
|
||||
{{ infoData.total }}
|
||||
</div>
|
||||
<div>
|
||||
交班数
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
交班数
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div>
|
||||
{{ infoData.amount }}
|
||||
</div>
|
||||
<div>
|
||||
总收款
|
||||
<div class="box_content_left_top_item_top">
|
||||
<div>
|
||||
{{ formatDecimal(+infoData.amount) }}
|
||||
</div>
|
||||
<div>
|
||||
总收款
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content_left_bouttom">
|
||||
<div class="box_content_left_bouttomox">
|
||||
<div class="box_content_left_bouttom_item" v-for="(item, index) in infoData.pageInfo.list"
|
||||
:key="index">
|
||||
<div class="wbox_content_left_bouttom_item_top">
|
||||
<div>
|
||||
{{ dayjs(item.loginTime).format("YYYY-MM-DD HH:mm:ss") }}
|
||||
<div class="box_content_left_bouttom">
|
||||
<div class="box_content_left_bouttomox">
|
||||
<div class="box_content_left_bouttom_item" v-for="(item, index) in infoData.list"
|
||||
:key="index">
|
||||
<div class="wbox_content_left_bouttom_item_top">
|
||||
<div>
|
||||
{{ item.loginTime }}
|
||||
</div>
|
||||
<div>
|
||||
¥{{ item.handAmount }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
¥{{ item.amount }}
|
||||
<div class="wbox_content_left_bouttom_item_topone">
|
||||
<div style="display: flex;">
|
||||
<span>收营员:</span>
|
||||
<span style="font-weight: bold;">{{ item.staffName }}</span>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<span>总订单数:</span>
|
||||
<span style="font-weight: bold;">{{ item.orderCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbox_content_left_bouttom_item_topone">
|
||||
<div style="display: flex;">
|
||||
<span>收营员:</span>
|
||||
<span style="font-weight: bold;">{{ item.userName }}</span>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<span>总订单数:</span>
|
||||
<span style="font-weight: bold;">{{ item.orderNum }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbox_content_left_bouttom_item_topone">
|
||||
<div style="display: flex;">
|
||||
<span>起止时间:</span>
|
||||
<span style="font-weight: bold;"> {{
|
||||
dayjs(item.loginTime).format("YYYY-MM-DD HH:mm:ss") }}</span>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<span>备用金:</span>
|
||||
<span style="font-weight: bold;">{{ item.pettyCash }}</span>
|
||||
<div class="wbox_content_left_bouttom_item_topone">
|
||||
<div style="display: flex;">
|
||||
<span>起止时间:</span>
|
||||
<span style="font-weight: bold;"> {{ item.loginTime }}</span>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<span>挂账金额</span>
|
||||
<span style="font-weight: bold;">{{ formatDecimal(+item.creditAmount) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="box_content_right">
|
||||
<!-- <div class="box_content_right">
|
||||
<div class="box_content_right_tiem">
|
||||
<div class="box_content_right_tiemleft">
|
||||
上岗时间:
|
||||
@@ -114,36 +114,42 @@
|
||||
关班/退出
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { shopinfoqueryDutyFlow } from '@/api/work/index.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { ElMessage, dayjs } from 'element-plus'
|
||||
import { handoverRecordPage } from '@/api/account.js'
|
||||
import { formatDecimal } from "@/utils/index.js";
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const store = useUser()
|
||||
const record = ref(true)//交班记录
|
||||
//详情数据
|
||||
const infoData = ref({
|
||||
pageInfo: {
|
||||
list: []
|
||||
}
|
||||
const infoData = reactive({
|
||||
list: [],
|
||||
total: 0,
|
||||
amount: 0
|
||||
})
|
||||
|
||||
// 获取交班总记录
|
||||
const infoshopInfoqueryDuty = async () => {
|
||||
let res = await shopinfoqueryDutyFlow({
|
||||
shopId: store.userInfo.shopId,
|
||||
let res = await handoverRecordPage({
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
size: 99999
|
||||
})
|
||||
infoData.value = res
|
||||
console.log(infoData.value)
|
||||
infoData.list = res.records
|
||||
infoData.total = +res.totalRow
|
||||
|
||||
let amount = 0
|
||||
|
||||
res.records.map(item => {
|
||||
amount += item.handAmount
|
||||
})
|
||||
|
||||
infoData.amount = amount
|
||||
}
|
||||
onMounted(() => {
|
||||
infoshopInfoqueryDuty()
|
||||
@@ -152,7 +158,7 @@ onMounted(() => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
padding: 16px;
|
||||
height: 100vh;
|
||||
background-color: #efefef;
|
||||
@@ -162,8 +168,8 @@ onMounted(() => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
/* 取消下划线效果 */
|
||||
|
||||
.box_top_left {
|
||||
@@ -191,7 +197,7 @@ onMounted(() => {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
// padding: 30px 20px;
|
||||
|
||||
.box_content_left_top {
|
||||
|
||||
Reference in New Issue
Block a user