Compare commits
41 Commits
397f4b2bcf
...
test
| Author | SHA1 | Date | |
|---|---|---|---|
| ffad9432c5 | |||
| 6d09813aa4 | |||
| e2338b3888 | |||
| c7f22e193a | |||
| 50139a5e57 | |||
| 209be704e1 | |||
| 6a20930a7d | |||
| 506dcbb804 | |||
| 75e46ec6dd | |||
| c87c999d42 | |||
| f648a7ea5e | |||
| 0ab8852656 | |||
| 03883e1b26 | |||
| b9308c1f21 | |||
| be12089ffe | |||
| e5cdf0a3dc | |||
| 51812fb0cc | |||
| 6e39a94f01 | |||
| d6a33aea3b | |||
| 2f2a152b46 | |||
| e3ddd70ce6 | |||
| 3c68d25286 | |||
| f5105cad87 | |||
| 372a1b35ec | |||
| e058aaacf7 | |||
| 2a47effa45 | |||
| b3d153ab86 | |||
| 392d4aa676 | |||
| 40b9d09671 | |||
| 4fcd2cc2cf | |||
| 13890e3f8d | |||
| d30407b26f | |||
| 647e32567b | |||
| ead5aaf458 | |||
| e2fa92d33d | |||
| f01cbf0f5b | |||
| ea2b9fcf9e | |||
| b87b4c000e | |||
| ddd39ec031 | |||
| 76af0f5a83 | |||
| a5b11cf4f4 |
@@ -10,6 +10,8 @@ VITE_APP_BASE_API=/dev-api
|
||||
# VITE_APP_API_URL=https://cashier.sxczgkj.com/ # 正式
|
||||
VITE_APP_API_URL=http://192.168.1.42/ # 本地
|
||||
VITE_APP_API_PHP_URL=http://192.168.1.42:8000 #php抖音美团测试环境
|
||||
VITE_APP_API_PHP_IMPORT_URL=http://192.168.1.42:8789 #本地php批量导入
|
||||
# VITE_APP_API_PHP_IMPORT_URL=https://diftcs.sxczgkj.com #本地线上php批量导入
|
||||
|
||||
|
||||
# WebSocket 端点(不配置则关闭),线上 ws://api.youlai.tech/ws ,本地 ws://localhost:8989/ws
|
||||
|
||||
@@ -12,6 +12,9 @@ VITE_APP_BASE_API = https://cashier.sxczgkj.com/
|
||||
VITE_APP_API_PHP_URL=https://newblockwlx.sxczgkj.cn #php抖音美团正式环境
|
||||
|
||||
|
||||
VITE_APP_API_PHP_IMPORT_URL=https://diftcs.sxczgkj.com #线上php批量导入
|
||||
|
||||
|
||||
|
||||
|
||||
# WebSocket 端点(不配置则关闭),线上 ws://api.youlai.tech/ws ,本地 ws://localhost:8989/ws
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"vite-plugin-mock-dev-server": "^1.8.3",
|
||||
"vite-plugin-strip-code": "^1.1.0",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-plugin-vue-devtools": "^8.1.0",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-tsc": "^2.2.0"
|
||||
},
|
||||
|
||||
12
src/App.vue
@@ -3,7 +3,17 @@
|
||||
<!-- 开启水印 -->
|
||||
<el-watermark :font="{ color: fontColor }" :content="watermarkEnabled ? defaultSettings.watermarkContent : ''"
|
||||
:z-index="9999" class="wh-full">
|
||||
<router-view />
|
||||
<!-- 🔴 修改开始:使用 v-slot 处理路由组件 -->
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<!--
|
||||
1. 使用 <transition> 包裹,防止渲染冲突
|
||||
2. 加上 :key="route.path" 强制 Vue 在路由变化时重新渲染,避免复用导致的空白
|
||||
-->
|
||||
<transition name="fade" mode="out-in">
|
||||
<component :is="Component" :key="route.path" />
|
||||
</transition>
|
||||
</router-view>
|
||||
<!-- 🟢 修改结束 -->
|
||||
</el-watermark>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
@@ -72,6 +72,39 @@ const OrderApi = {
|
||||
data
|
||||
});
|
||||
},
|
||||
// 查询财务报表
|
||||
financeSts(params: any) {
|
||||
return request<any>({
|
||||
url: `${Order_BaseUrl}/admin/finance/sts`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
// 导出财务报表
|
||||
financeExport(params: any) {
|
||||
return request<any>({
|
||||
url: `${Order_BaseUrl}/admin/finance/export`,
|
||||
method: "get",
|
||||
params,
|
||||
responseType: 'blob'
|
||||
});
|
||||
},
|
||||
// 打印经营日报
|
||||
printDayReport(params: any) {
|
||||
return request<any>({
|
||||
url: `${Order_BaseUrl}/admin/finance/printDayReport`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
// 打印日结单
|
||||
printDaySettle(params: any) {
|
||||
return request<any>({
|
||||
url: `${Order_BaseUrl}/admin/finance/printDaySettle`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default OrderApi;
|
||||
|
||||
@@ -28,6 +28,14 @@ const Api = {
|
||||
responseType: 'blob'
|
||||
});
|
||||
},
|
||||
// 商品报表打印
|
||||
print(params: any) {
|
||||
return request<any>({
|
||||
url: `${baseURL}/print`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default Api;
|
||||
|
||||
@@ -48,6 +48,14 @@ const AuthAPI = {
|
||||
data,
|
||||
});
|
||||
},
|
||||
// 商品-标记自动售罄
|
||||
markIsAutoSoldOut(data: Object) {
|
||||
return request<any, Responseres>({
|
||||
url: `${baseURL}/markIsAutoSoldOut`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
},
|
||||
// 删除
|
||||
deleteByIds(id: number | String) {
|
||||
return request<any, Responseres>({
|
||||
@@ -72,7 +80,7 @@ const AuthAPI = {
|
||||
});
|
||||
},
|
||||
|
||||
// 耗材列表
|
||||
// 耗材列表分页
|
||||
productcons(params: any) {
|
||||
return request<any, Responseres>({
|
||||
url: `/product/admin/product/cons/page`,
|
||||
@@ -80,7 +88,22 @@ const AuthAPI = {
|
||||
params
|
||||
});
|
||||
},
|
||||
|
||||
// 耗材列表
|
||||
productconsList(params: any) {
|
||||
return request<any, Responseres>({
|
||||
url: `/product/admin/product/cons/list`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
// 耗材列表
|
||||
consStock(params: any) {
|
||||
return request<any, Responseres>({
|
||||
url: `/product/admin/product/cons/consStock`,
|
||||
method: "get",
|
||||
params
|
||||
});
|
||||
},
|
||||
// 上下架
|
||||
onOff(data: any) {
|
||||
return request<any, Responseres>({
|
||||
|
||||
15
src/api/system/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from "@/utils/request";
|
||||
import {
|
||||
Account_BaseUrl,
|
||||
Product_BaseUrl,
|
||||
Market_BaseUrl,
|
||||
System_BaseUrl
|
||||
} from "@/api/config";
|
||||
|
||||
// 帮助中心
|
||||
export function getHelp() {
|
||||
return request({
|
||||
url: `${System_BaseUrl + "/user/getHelp"}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
BIN
src/assets/index_bg.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
src/assets/index_quick1.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
src/assets/index_quick2.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
src/assets/index_quick3.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/index_quick4.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
src/assets/index_quick5.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/assets/index_quick6.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
@@ -3,68 +3,49 @@
|
||||
<!-- 表格工具栏 -->
|
||||
<div class="flex-x-between mb-[10px]">
|
||||
<!-- 左侧工具栏 -->
|
||||
<div>
|
||||
<div style="display: flex;">
|
||||
<template v-for="item in toolbar" :key="item">
|
||||
<template v-if="typeof item === 'string'">
|
||||
<!-- 新增 -->
|
||||
<template v-if="item === 'add'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleToolbar(item)"
|
||||
>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item}`]" type="primary" icon="plus"
|
||||
@click="handleToolbar(item)">
|
||||
新增
|
||||
</el-button>
|
||||
</template>
|
||||
<!-- 删除 -->
|
||||
<template v-else-if="item === 'delete'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
type="danger"
|
||||
icon="delete"
|
||||
:disabled="removeIds.length === 0"
|
||||
@click="handleToolbar(item)"
|
||||
>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item}`]" type="danger" icon="delete"
|
||||
:disabled="removeIds.length === 0" @click="handleToolbar(item)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
<!-- 导入 -->
|
||||
<template v-else-if="item === 'import'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
type="default"
|
||||
icon="upload"
|
||||
@click="handleToolbar(item)"
|
||||
>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item}`]" type="default" icon="upload"
|
||||
@click="handleToolbar(item)">
|
||||
导入
|
||||
</el-button>
|
||||
</template>
|
||||
<!-- 导出 -->
|
||||
<template v-else-if="item === 'export'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
type="default"
|
||||
icon="download"
|
||||
@click="handleToolbar(item)"
|
||||
>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item}`]" type="default" icon="download"
|
||||
@click="handleToolbar(item)">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 其他 -->
|
||||
<template v-else-if="typeof item === 'object'">
|
||||
<el-button
|
||||
v-if="item.hidden === undefined || item.hidden === false"
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]"
|
||||
:icon="item.icon"
|
||||
:type="item.type ?? 'default'"
|
||||
@click="handleToolbar(item.name)"
|
||||
>
|
||||
<el-button v-if="item.hidden === undefined || item.hidden === false"
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]" :icon="item.icon" :type="item.type ?? 'default'"
|
||||
@click="handleToolbar(item.name)">
|
||||
{{ item.text }}
|
||||
</el-button>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 插槽 -->
|
||||
<slot name="custom" />
|
||||
</div>
|
||||
<!-- 右侧工具栏 -->
|
||||
<div>
|
||||
@@ -89,68 +70,36 @@
|
||||
</template>
|
||||
<!-- 导出 -->
|
||||
<template v-else-if="item === 'exports'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:export`]"
|
||||
icon="download"
|
||||
circle
|
||||
title="导出"
|
||||
@click="handleToolbar(item)"
|
||||
/>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:export`]" icon="download" circle title="导出"
|
||||
@click="handleToolbar(item)" />
|
||||
</template>
|
||||
<!-- 导入 -->
|
||||
<template v-else-if="item === 'imports'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:import`]"
|
||||
icon="upload"
|
||||
circle
|
||||
title="导入"
|
||||
@click="handleToolbar(item)"
|
||||
/>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:import`]" icon="upload" circle title="导入"
|
||||
@click="handleToolbar(item)" />
|
||||
</template>
|
||||
<!-- 搜索 -->
|
||||
<template v-else-if="item === 'search'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:query`]"
|
||||
icon="search"
|
||||
circle
|
||||
title="搜索"
|
||||
@click="handleToolbar(item)"
|
||||
/>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:query`]" icon="search" circle title="搜索"
|
||||
@click="handleToolbar(item)" />
|
||||
</template>
|
||||
</template>
|
||||
<!-- 其他 -->
|
||||
<template v-else-if="typeof item === 'object'">
|
||||
<template v-if="item.auth">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]"
|
||||
:icon="item.icon"
|
||||
circle
|
||||
:title="item.title"
|
||||
@click="handleToolbar(item.name)"
|
||||
/>
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]" :icon="item.icon" circle
|
||||
:title="item.title" @click="handleToolbar(item.name)" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button
|
||||
:icon="item.icon"
|
||||
circle
|
||||
:title="item.title"
|
||||
@click="handleToolbar(item.name)"
|
||||
/>
|
||||
<el-button :icon="item.icon" circle :title="item.title" @click="handleToolbar(item.name)" />
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 列表 -->
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
v-bind="contentConfig.table"
|
||||
:data="pageData"
|
||||
:row-key="pk"
|
||||
@selection-change="handleSelectionChange"
|
||||
@filter-change="handleFilterChange"
|
||||
>
|
||||
<el-table ref="tableRef" v-loading="loading" v-bind="contentConfig.table" :data="pageData" :row-key="pk"
|
||||
@selection-change="handleSelectionChange" @filter-change="handleFilterChange">
|
||||
<template v-for="col in cols" :key="col">
|
||||
<el-table-column v-if="col.show" v-bind="col">
|
||||
<template #default="scope">
|
||||
@@ -159,24 +108,15 @@
|
||||
<template v-if="col.prop">
|
||||
<template v-if="Array.isArray(scope.row[col.prop])">
|
||||
<template v-for="(item, index) in scope.row[col.prop]" :key="item">
|
||||
<el-image
|
||||
:src="item"
|
||||
:preview-src-list="scope.row[col.prop]"
|
||||
:initial-index="index"
|
||||
:preview-teleported="true"
|
||||
:style="`width: ${col.imageWidth ?? 40}px; height: ${
|
||||
col.imageHeight ?? 40
|
||||
}px`"
|
||||
/>
|
||||
<el-image :src="item" :preview-src-list="scope.row[col.prop]" :initial-index="index"
|
||||
:preview-teleported="true" :style="`width: ${col.imageWidth ?? 40}px; height: ${col.imageHeight ?? 40
|
||||
}px`" />
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-image
|
||||
:src="scope.row[col.prop]"
|
||||
:preview-src-list="[scope.row[col.prop]]"
|
||||
<el-image :src="scope.row[col.prop]" :preview-src-list="[scope.row[col.prop]]"
|
||||
:preview-teleported="true"
|
||||
:style="`width: ${col.imageWidth ?? 40}px; height: ${col.imageHeight ?? 40}px`"
|
||||
/>
|
||||
:style="`width: ${col.imageWidth ?? 40}px; height: ${col.imageHeight ?? 40}px`" />
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
@@ -198,30 +138,20 @@
|
||||
<template v-else-if="col.templet === 'switch'">
|
||||
<template v-if="col.prop">
|
||||
<!-- pageData.length>0: 解决el-switch组件会在表格初始化的时候触发一次change事件 -->
|
||||
<el-switch
|
||||
v-model="scope.row[col.prop]"
|
||||
:active-value="col.activeValue ?? 1"
|
||||
:inactive-value="col.inactiveValue ?? 0"
|
||||
:inline-prompt="true"
|
||||
:active-text="col.activeText ?? ''"
|
||||
:inactive-text="col.inactiveText ?? ''"
|
||||
:validate-event="false"
|
||||
:disabled="!hasAuth(`${contentConfig.pageName}:modify`)"
|
||||
@change="
|
||||
<el-switch v-model="scope.row[col.prop]" :active-value="col.activeValue ?? 1"
|
||||
:inactive-value="col.inactiveValue ?? 0" :inline-prompt="true" :active-text="col.activeText ?? ''"
|
||||
:inactive-text="col.inactiveText ?? ''" :validate-event="false"
|
||||
:disabled="!hasAuth(`${contentConfig.pageName}:modify`)" @change="
|
||||
pageData.length > 0 && handleModify(col.prop, scope.row[col.prop], scope.row)
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</template>
|
||||
</template>
|
||||
<!-- 生成输入框组件 -->
|
||||
<template v-else-if="col.templet === 'input'">
|
||||
<template v-if="col.prop">
|
||||
<el-input
|
||||
v-model="scope.row[col.prop]"
|
||||
:type="col.inputType ?? 'text'"
|
||||
<el-input v-model="scope.row[col.prop]" :type="col.inputType ?? 'text'"
|
||||
:disabled="!hasAuth(`${contentConfig.pageName}:modify`)"
|
||||
@blur="handleModify(col.prop, scope.row[col.prop], scope.row)"
|
||||
/>
|
||||
@blur="handleModify(col.prop, scope.row[col.prop], scope.row)" />
|
||||
</template>
|
||||
</template>
|
||||
<!-- 格式化为价格 -->
|
||||
@@ -253,7 +183,7 @@
|
||||
{{
|
||||
scope.row[col.prop]
|
||||
? useDateFormat(scope.row[col.prop], col.dateFormat ?? "YYYY-MM-DD HH:mm:ss")
|
||||
.value
|
||||
.value
|
||||
: ""
|
||||
}}
|
||||
</template>
|
||||
@@ -264,21 +194,15 @@
|
||||
<template v-if="typeof item === 'string'">
|
||||
<!-- 编辑/删除 -->
|
||||
<template v-if="item === 'edit' || item === 'delete'">
|
||||
<el-button
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
:type="item === 'edit' ? 'primary' : 'danger'"
|
||||
:icon="item"
|
||||
size="small"
|
||||
link
|
||||
@click="
|
||||
<el-button v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||
:type="item === 'edit' ? 'primary' : 'danger'" :icon="item" size="small" link @click="
|
||||
handleOperat({
|
||||
name: item,
|
||||
row: scope.row,
|
||||
column: scope.column,
|
||||
$index: scope.$index,
|
||||
})
|
||||
"
|
||||
>
|
||||
">
|
||||
{{ item === "edit" ? "编辑" : "删除" }}
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -286,63 +210,43 @@
|
||||
<!-- 其他 -->
|
||||
<template v-else-if="typeof item === 'object'">
|
||||
<template v-if="item.hidden === undefined || item.hidden === false">
|
||||
<el-button
|
||||
v-if="item.isBtn"
|
||||
v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]"
|
||||
:icon="item.icon"
|
||||
:type="item.type ?? 'primary'"
|
||||
size="small"
|
||||
link
|
||||
@click="
|
||||
<el-button v-if="item.isBtn" v-hasPerm="[`${contentConfig.pageName}:${item.auth}`]"
|
||||
:icon="item.icon" :type="item.type ?? 'primary'" size="small" link @click="
|
||||
handleOperat({
|
||||
name: item.name,
|
||||
row: scope.row,
|
||||
column: scope.column,
|
||||
$index: scope.$index,
|
||||
})
|
||||
"
|
||||
>
|
||||
">
|
||||
{{ item.text }}
|
||||
</el-button>
|
||||
|
||||
<el-dropdown style="margin-top: 4px" v-else>
|
||||
<el-button
|
||||
v-if="item.render === undefined || item.render(scope.row)"
|
||||
v-bind="
|
||||
item.auth
|
||||
? { 'v-hasPerm': [`${contentConfig.pageName}:${item.auth}`] }
|
||||
: {}
|
||||
"
|
||||
:icon="item.icon"
|
||||
:type="item.type ?? 'primary'"
|
||||
size="small"
|
||||
link
|
||||
@click="
|
||||
<el-button v-if="item.render === undefined || item.render(scope.row)" v-bind="item.auth
|
||||
? { 'v-hasPerm': [`${contentConfig.pageName}:${item.auth}`] }
|
||||
: {}
|
||||
" :icon="item.icon" :type="item.type ?? 'primary'" size="small" link @click="
|
||||
handleOperat({
|
||||
name: item.name,
|
||||
row: scope.row,
|
||||
column: scope.column,
|
||||
$index: scope.$index,
|
||||
})
|
||||
"
|
||||
>
|
||||
">
|
||||
{{ item.text }}
|
||||
</el-button>
|
||||
<template #dropdown v-if="item.options && item.options.length > 0">
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
@click="
|
||||
handleOperat({
|
||||
name: item.name,
|
||||
row: scope.row,
|
||||
column: scope.column,
|
||||
$index: scope.$index,
|
||||
command: opt.command ? opt.command : '',
|
||||
})
|
||||
"
|
||||
v-for="opt in item.options"
|
||||
:key="opt.value"
|
||||
>
|
||||
<el-dropdown-item @click="
|
||||
handleOperat({
|
||||
name: item.name,
|
||||
row: scope.row,
|
||||
column: scope.column,
|
||||
$index: scope.$index,
|
||||
command: opt.command ? opt.command : '',
|
||||
})
|
||||
" v-for="opt in item.options" :key="opt.value">
|
||||
{{ opt.label }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -364,33 +268,18 @@
|
||||
<template v-if="showPagination">
|
||||
<el-scrollbar>
|
||||
<div class="mt-[12px]">
|
||||
<el-pagination
|
||||
v-bind="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
<el-pagination v-bind="pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
<!-- 导出弹窗 -->
|
||||
<el-dialog
|
||||
v-model="exportsModalVisible"
|
||||
:align-center="true"
|
||||
title="导出数据"
|
||||
width="600px"
|
||||
style="padding-right: 0"
|
||||
@close="handleCloseExportsModal"
|
||||
>
|
||||
<el-dialog v-model="exportsModalVisible" :align-center="true" title="导出数据" width="600px" style="padding-right: 0"
|
||||
@close="handleCloseExportsModal">
|
||||
<!-- 滚动 -->
|
||||
<el-scrollbar max-height="60vh">
|
||||
<!-- 表单 -->
|
||||
<el-form
|
||||
ref="exportsFormRef"
|
||||
label-width="auto"
|
||||
style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="exportsFormData"
|
||||
:rules="exportsFormRules"
|
||||
>
|
||||
<el-form ref="exportsFormRef" label-width="auto" style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="exportsFormData" :rules="exportsFormRules">
|
||||
<el-form-item label="文件名" prop="filename">
|
||||
<el-input v-model="exportsFormData.filename" clearable />
|
||||
</el-form-item>
|
||||
@@ -400,16 +289,10 @@
|
||||
<el-form-item label="数据源" prop="origin">
|
||||
<el-select v-model="exportsFormData.origin">
|
||||
<el-option label="当前数据 (当前页的数据)" :value="ExportsOriginEnum.CURRENT" />
|
||||
<el-option
|
||||
label="选中数据 (所有选中的数据)"
|
||||
:value="ExportsOriginEnum.SELECTED"
|
||||
:disabled="selectionData.length <= 0"
|
||||
/>
|
||||
<el-option
|
||||
label="全量数据 (所有分页的数据)"
|
||||
:value="ExportsOriginEnum.REMOTE"
|
||||
:disabled="contentConfig.exportsAction === undefined"
|
||||
/>
|
||||
<el-option label="选中数据 (所有选中的数据)" :value="ExportsOriginEnum.SELECTED"
|
||||
:disabled="selectionData.length <= 0" />
|
||||
<el-option label="全量数据 (所有分页的数据)" :value="ExportsOriginEnum.REMOTE"
|
||||
:disabled="contentConfig.exportsAction === undefined" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="字段" prop="fields">
|
||||
@@ -430,35 +313,17 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 导入弹窗 -->
|
||||
<el-dialog
|
||||
v-model="importModalVisible"
|
||||
:align-center="true"
|
||||
title="导入数据"
|
||||
width="600px"
|
||||
style="padding-right: 0"
|
||||
@close="handleCloseImportModal"
|
||||
>
|
||||
<el-dialog v-model="importModalVisible" :align-center="true" title="导入数据" width="600px" style="padding-right: 0"
|
||||
@close="handleCloseImportModal">
|
||||
<!-- 滚动 -->
|
||||
<el-scrollbar max-height="60vh">
|
||||
<!-- 表单 -->
|
||||
<el-form
|
||||
ref="importFormRef"
|
||||
label-width="auto"
|
||||
style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="importFormData"
|
||||
:rules="importFormRules"
|
||||
>
|
||||
<el-form ref="importFormRef" label-width="auto" style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="importFormData" :rules="importFormRules">
|
||||
<el-form-item label="文件名" prop="files">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="importFormData.files"
|
||||
class="w-full"
|
||||
<el-upload ref="uploadRef" v-model:file-list="importFormData.files" class="w-full"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:drag="true"
|
||||
:limit="1"
|
||||
:auto-upload="false"
|
||||
:on-exceed="handleFileExceed"
|
||||
>
|
||||
:drag="true" :limit="1" :auto-upload="false" :on-exceed="handleFileExceed">
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
<span>将文件拖到此处,或</span>
|
||||
@@ -467,13 +332,8 @@
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
*.xlsx / *.xls
|
||||
<el-link
|
||||
v-if="contentConfig.importTemplate"
|
||||
type="primary"
|
||||
icon="download"
|
||||
:underline="false"
|
||||
@click="handleDownloadTemplate"
|
||||
>
|
||||
<el-link v-if="contentConfig.importTemplate" type="primary" icon="download" :underline="false"
|
||||
@click="handleDownloadTemplate">
|
||||
下载模板
|
||||
</el-link>
|
||||
</div>
|
||||
@@ -485,11 +345,7 @@
|
||||
<!-- 弹窗底部操作按钮 -->
|
||||
<template #footer>
|
||||
<div style="padding-right: var(--el-dialog-padding-primary)">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="importFormData.files.length === 0"
|
||||
@click="handleImportSubmit"
|
||||
>
|
||||
<el-button type="primary" :disabled="importFormData.files.length === 0" @click="handleImportSubmit">
|
||||
确 定
|
||||
</el-button>
|
||||
<el-button @click="handleCloseImportModal">取 消</el-button>
|
||||
@@ -1005,10 +861,10 @@ function fetchPageData(formData: IObject = {}, isRestart = false) {
|
||||
.indexAction(
|
||||
showPagination
|
||||
? {
|
||||
[request.pageName]: pagination.currentPage,
|
||||
[request.limitName]: pagination.pageSize,
|
||||
...formData,
|
||||
}
|
||||
[request.pageName]: pagination.currentPage,
|
||||
[request.limitName]: pagination.pageSize,
|
||||
...formData,
|
||||
}
|
||||
: formData
|
||||
)
|
||||
.then((data) => {
|
||||
@@ -1073,7 +929,7 @@ function saveXlsx(fileData: BlobPart, fileName: string) {
|
||||
document.body.removeChild(downloadLink);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
}
|
||||
function test(rows: any[]) {}
|
||||
function test(rows: any[]) { }
|
||||
|
||||
const defaultSelData = ref<IObject[]>([]);
|
||||
// 设置默认选择
|
||||
@@ -1115,17 +971,21 @@ defineExpose({
|
||||
:deep(.el-table .el-table__cell) {
|
||||
z-index: inherit;
|
||||
}
|
||||
|
||||
.el-card {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
overflow: visible;
|
||||
|
||||
.el-table__header-wrapper {
|
||||
position: sticky;
|
||||
z-index: calc(var(--el-table-index) + 2);
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table td.el-table__cell div) {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -1,44 +1,42 @@
|
||||
<!-- 文件上传组件 -->
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
v-model:file-list="fileList"
|
||||
:style="props.style"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:http-request="handleUpload"
|
||||
:on-progress="handleProgress"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:accept="props.accept"
|
||||
:limit="props.limit"
|
||||
multiple
|
||||
>
|
||||
<!-- 上传文件按钮 -->
|
||||
<el-button type="primary" :disabled="fileList.length >= props.limit">
|
||||
{{ props.uploadBtnText }}
|
||||
</el-button>
|
||||
|
||||
<el-upload v-model:file-list="fileList" :style="props.style" :before-upload="handleBeforeUpload"
|
||||
:http-request="handleUpload" :on-progress="handleProgress" :on-success="handleSuccess" :on-error="handleError"
|
||||
:accept="props.accept" :limit="props.limit" multiple drag :tip="'支持多个文件上传,单个文件不超过 ' + props.maxFileSize + 'MB'">
|
||||
<!-- 拖拽上传区域 -->
|
||||
<div>
|
||||
<el-icon class="el-icon--upload">
|
||||
<UploadFilled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或 <em>点击上传</em>
|
||||
<br />
|
||||
<small>支持格式:{{ props.accept }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文件列表 -->
|
||||
<template #file="{ file }">
|
||||
<div class="el-upload-list__item-info">
|
||||
<a class="el-upload-list__item-name" @click="handleDownload(file)">
|
||||
<el-icon><Document /></el-icon>
|
||||
<el-icon>
|
||||
<Document />
|
||||
</el-icon>
|
||||
<span class="el-upload-list__item-file-name">{{ file.name }}</span>
|
||||
<span class="el-icon--close" @click="handleRemove(file.url!)">
|
||||
<el-icon><Close /></el-icon>
|
||||
<span class="el-icon--close" @click="handleRemove(file.url)">
|
||||
<el-icon>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
<el-progress
|
||||
:style="{
|
||||
display: showProgress ? 'inline-flex' : 'none',
|
||||
width: '100%',
|
||||
}"
|
||||
:percentage="progressPercent"
|
||||
/>
|
||||
<el-progress :style="{
|
||||
display: showProgress ? 'inline-flex' : 'none',
|
||||
width: '100%',
|
||||
marginTop: '10px',
|
||||
}" :percentage="progressPercent" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -48,9 +46,14 @@ import {
|
||||
UploadProgressEvent,
|
||||
UploadRequestOptions,
|
||||
} from "element-plus";
|
||||
import { Upload, Document, Close } from "@element-plus/icons-vue";
|
||||
|
||||
import CommonApi, { FileInfo, uploadResponse } from "@/api/account/common";
|
||||
|
||||
const emit = defineEmits<{
|
||||
"upload-success": [fileInfo: string];
|
||||
}>();
|
||||
|
||||
const props = defineProps({
|
||||
/**
|
||||
* 请求携带的额外参数
|
||||
@@ -96,7 +99,6 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: "上传文件",
|
||||
},
|
||||
|
||||
/**
|
||||
* 样式
|
||||
*/
|
||||
@@ -104,7 +106,7 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
width: "300px",
|
||||
width: "100%",
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -147,6 +149,7 @@ function handleBeforeUpload(file: UploadRawFile) {
|
||||
ElMessage.warning("上传图片不能大于" + props.maxFileSize + "M");
|
||||
return false;
|
||||
}
|
||||
showProgress.value = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -190,10 +193,13 @@ const handleProgress = (event: UploadProgressEvent) => {
|
||||
const handleSuccess = (fileInfo: string) => {
|
||||
ElMessage.success("上传成功");
|
||||
modelValue.value = [...modelValue.value, fileInfo];
|
||||
emit("upload-success", fileInfo);
|
||||
showProgress.value = false;
|
||||
};
|
||||
|
||||
const handleError = (error: any) => {
|
||||
ElMessage.error("上传失败");
|
||||
showProgress.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
242
src/components/Upload/GfileUpload.vue
Normal file
@@ -0,0 +1,242 @@
|
||||
<!-- 文件上传组件 -->
|
||||
<template>
|
||||
<div>
|
||||
<el-upload v-model:file-list="fileList" :style="props.style" :before-upload="handleBeforeUpload"
|
||||
:on-change="handleChange" :accept="accept" multiple drag :tip="'支持多个文件上传,单个文件不超过 ' + props.maxFileSize + 'MB'"
|
||||
:auto-upload="false">
|
||||
<!-- 拖拽上传区域 -->
|
||||
<div>
|
||||
<el-icon class="el-icon--upload">
|
||||
<UploadFilled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或 <em>点击上传</em>
|
||||
<br />
|
||||
<small>支持格式:{{ accept }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文件列表 -->
|
||||
<template #file="{ file }">
|
||||
<div class="el-upload-list__item-info">
|
||||
<a class="el-upload-list__item-name" @click="handleDownload(file)">
|
||||
<el-icon>
|
||||
<Document />
|
||||
</el-icon>
|
||||
<span class="el-upload-list__item-file-name">{{ file.name }}</span>
|
||||
<span class="el-icon--close" @click="handleRemove(file.url)">
|
||||
<el-icon>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { UploadFilled, Document, Close } from "@element-plus/icons-vue";
|
||||
|
||||
const emit = defineEmits({
|
||||
"file-selected": null,
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
/**
|
||||
* 文件上传数量限制
|
||||
*/
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
/**
|
||||
* 单个文件上传大小限制(单位MB)
|
||||
*/
|
||||
maxFileSize: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
/**
|
||||
* 上传文件类型
|
||||
*/
|
||||
accept: {
|
||||
type: String,
|
||||
default: "*",
|
||||
},
|
||||
/**
|
||||
* 选择文件成功的回调函数
|
||||
*/
|
||||
successCallback: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 样式
|
||||
*/
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
width: "100%",
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const fileList = defineModel({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
/**
|
||||
* 文件选择变化
|
||||
*/
|
||||
function handleChange(file, fileList) {
|
||||
if (file.status === 'ready') {
|
||||
// 如果限制为1个文件,移除之前的文件,只保留当前新文件
|
||||
if (props.limit === 1 && fileList.length > 1) {
|
||||
fileList.splice(0, fileList.length - 1);
|
||||
}
|
||||
const rawFile = file.raw;
|
||||
// 限制文件类型
|
||||
if (props.accept !== "*") {
|
||||
const acceptedTypes = props.accept.split(',').map(type => type.trim());
|
||||
const isAccepted = acceptedTypes.some(type => {
|
||||
let checkType = type;
|
||||
if (!type.startsWith('.') && !type.includes('/')) {
|
||||
checkType = '.' + type;
|
||||
}
|
||||
if (checkType.startsWith('.')) {
|
||||
return rawFile.name.toLowerCase().endsWith(checkType.toLowerCase());
|
||||
} else if (checkType.includes('*')) {
|
||||
const [main] = checkType.split('/');
|
||||
return rawFile.type.startsWith(main + '/');
|
||||
} else {
|
||||
return rawFile.type === checkType;
|
||||
}
|
||||
});
|
||||
if (!isAccepted) {
|
||||
ElMessage.warning("文件类型不符合要求");
|
||||
// 从 fileList 中移除不符合的文件
|
||||
fileList.splice(fileList.indexOf(file), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (props.successCallback) {
|
||||
props.successCallback(rawFile);
|
||||
} else {
|
||||
emit("file-selected", rawFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传前校验
|
||||
*/
|
||||
function handleBeforeUpload(file) {
|
||||
// 限制文件大小
|
||||
if (file.size > props.maxFileSize * 1024 * 1024) {
|
||||
ElMessage.warning("上传文件不能大于" + props.maxFileSize + "M");
|
||||
return false;
|
||||
}
|
||||
// 限制文件类型
|
||||
if (props.accept !== "*") {
|
||||
const acceptedTypes = props.accept.split(',').map(type => type.trim());
|
||||
const isAccepted = acceptedTypes.some(type => {
|
||||
if (type.startsWith('.')) {
|
||||
return file.name.toLowerCase().endsWith(type.toLowerCase());
|
||||
} else {
|
||||
return file.type === type;
|
||||
}
|
||||
});
|
||||
if (!isAccepted) {
|
||||
ElMessage.warning("文件类型不符合要求");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*/
|
||||
function handleRemove(fileUrl) {
|
||||
// 从 fileList 中移除
|
||||
fileList.value = fileList.value.filter(f => f.url !== fileUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
function handleDownload(file) {
|
||||
// 本地文件,不支持下载
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-upload-list__item .el-icon--close {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
color: var(--el-text-color-regular);
|
||||
cursor: pointer;
|
||||
opacity: 0.75;
|
||||
transition: opacity var(--el-transition-duration);
|
||||
transform: translateY(-50%);
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-upload-list) {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
:deep(.el-upload-list__item) {
|
||||
margin: 5px 0;
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f0f0f0;
|
||||
border-color: var(--el-color-primary-light-3);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.el-upload-list__item-info {
|
||||
flex: 1;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: var(--el-text-color-primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
margin-right: 8px;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-upload-list__item-file-name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-icon--close {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
258
src/components/importData/index.vue
Normal file
@@ -0,0 +1,258 @@
|
||||
<!-- 批量导入数据dialog -->
|
||||
<template>
|
||||
<div>
|
||||
<div class="btn_row">
|
||||
<el-button type="primary" icon="Upload" @click="show">批量导入</el-button>
|
||||
<el-button icon="Download" @click="downloadTemplateAjax">下载银收客模板</el-button>
|
||||
</div>
|
||||
<el-dialog title="批量导入" width="800px" v-model="visible" :close-on-click-modal="false" :close-on-press-escape="false"
|
||||
@close="dialogClose">
|
||||
<div class="row">
|
||||
<tabHeader v-model="tabActive" :list="tabs" />
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<div class="import_container" v-if="tabActive == 0">
|
||||
<div class="header_title">第一步:选择模板</div>
|
||||
<div class="row mt14 pb50">
|
||||
<div class="list">
|
||||
<div class="item" :class="{ active: platformActive == index }" v-for="(item, index) in platformList"
|
||||
:key="item.id" @click="selectPlatform(item)">
|
||||
<img class="img" :src="item.img" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header_title">第二步:上传文件
|
||||
<span>单次仅可上传一个文件</span>
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<GfileUpload v-model="form.files" :accept="platformList[platformActive]?.file_type || ''" :limit="1"
|
||||
@file-selected="fileSelected" />
|
||||
</div>
|
||||
<div class="row mt14">
|
||||
<div class="footer_wrap">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" :disabled="!form.files.length" :loading="loading" @click="startImportHandle">
|
||||
<template v-if="!form.files.length">请选择文件</template>
|
||||
<template v-else>开始导入</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="tableData" border stripe v-if="tabActive == 1" height="419px">
|
||||
<el-table-column prop="file_name" label="文件名称" width="300" />
|
||||
<el-table-column prop="created_time" label="导入时间" width="200" />
|
||||
<el-table-column prop="status_text" label="导入状态" width="150">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status == 0" type="info" disable-transitions>待处理...</el-tag>
|
||||
<el-tag v-else-if="scope.row.status == 1" type="warning" disable-transitions>处理中...</el-tag>
|
||||
<el-tag v-else-if="scope.row.status == 2" type="success" disable-transitions>处理完成</el-tag>
|
||||
<el-tag v-else-if="scope.row.status == -1" type="danger" disable-transitions>导入失败</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="importResult" label="导入结果">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.status == 2">
|
||||
<div class="column">
|
||||
<div>
|
||||
<el-text type="success">成功:{{ scope.row.success_num }} 条</el-text>
|
||||
</div>
|
||||
<div>
|
||||
<el-text type="danger">失败:{{ scope.row.fail_num }} 条</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { getplatlist, uploadFile, importlist, downloadTemp } from '@/importDataApi/index.js';
|
||||
import GfileUpload from '../Upload/GfileUpload.vue';
|
||||
import tabHeader from '@/views/marketing_center/components/tabHeader.vue';
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: [String, Number],
|
||||
default: 3, // 3商品 4台桌区域 5台桌 6会员 7菜品销售统计 8台桌销售统计 9订单销售统计
|
||||
},
|
||||
});
|
||||
|
||||
const platformList = ref([]);
|
||||
const platformActive = ref(0);
|
||||
function selectPlatform(item) {
|
||||
form.value.files = [];
|
||||
platformActive.value = platformList.value.findIndex(i => i.id === item.id);
|
||||
}
|
||||
|
||||
const tabs = ref([
|
||||
{ label: '导入数据', name: 'importData' },
|
||||
{ label: '导入记录', name: 'importRecord' },
|
||||
]);
|
||||
|
||||
const tabActive = ref(0)
|
||||
|
||||
watch(tabActive, (newVal) => {
|
||||
if (newVal === 1) {
|
||||
getImportRecord();
|
||||
}
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const form = ref({
|
||||
files: [],
|
||||
platform: ''
|
||||
})
|
||||
|
||||
function fileSelected(file) {
|
||||
console.log('fileSelected', file);
|
||||
}
|
||||
|
||||
// 开始导入
|
||||
async function startImportHandle() {
|
||||
try {
|
||||
form.value.platform = platformList.value[platformActive.value]?.id;
|
||||
const formData = new FormData();
|
||||
formData.append('file', form.value.files[0].raw);
|
||||
formData.append('shop_id', localStorage.getItem('shopId'));
|
||||
formData.append('type', props.type);
|
||||
formData.append('platform', form.value.platform);
|
||||
loading.value = true;
|
||||
await uploadFile(formData);
|
||||
ElMessage.success('文件上传成功,正在导入数据,请在导入记录中查看导入结果');
|
||||
form.value.files = []
|
||||
tabActive.value = 1
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 获取平台列表
|
||||
async function getPlatformList() {
|
||||
try {
|
||||
const res = await getplatlist({ plat_type: props.type });
|
||||
platformList.value = res;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 导入记录
|
||||
const tableData = ref([]);
|
||||
async function getImportRecord() {
|
||||
try {
|
||||
const res = await importlist({ shop_id: localStorage.getItem('shopId') });
|
||||
tableData.value = res;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 下载模板
|
||||
async function downloadTemplateAjax() {
|
||||
try {
|
||||
const res = await downloadTemp({ plat_type: props.type });
|
||||
window.open(res, '_blank');
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const emits = defineEmits(['close'])
|
||||
|
||||
function dialogClose() {
|
||||
emits('close')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getPlatformList()
|
||||
});
|
||||
|
||||
function show() {
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.btn_row {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.header_title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
&.mt14 {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
&.pb50 {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.import_container {
|
||||
.list {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
|
||||
.item {
|
||||
width: 122px;
|
||||
height: 42px;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
120
src/components/printBusinessDialog.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<el-dialog title="打印确认" width="400px" v-model="showDayBusiness">
|
||||
<div class="business_wrap">
|
||||
<div class="title">
|
||||
<el-text>请选择要打印的日期:</el-text> <el-text type="danger">周期最长为7天</el-text>
|
||||
</div>
|
||||
<div class="row">
|
||||
<el-date-picker v-model="printDayBusinessParams.date" type="daterange" start-placeholder="开始日期"
|
||||
end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" :disabled-date="disabledDate"
|
||||
@change="handleDateChange" clearable />
|
||||
</div>
|
||||
<div class="business_tips">
|
||||
<el-text type="info">若数据过多,打印时间会比较长,请耐心等待</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="showDayBusiness = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmHandle" :loading="printDayBusinessLoading">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '经营日报'
|
||||
}
|
||||
})
|
||||
|
||||
const showDayBusiness = ref(false)
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
// 打印参数
|
||||
const printDayBusinessParams = ref({
|
||||
date: [],
|
||||
})
|
||||
const printDayBusinessLoading = ref(false)
|
||||
|
||||
// 取消
|
||||
const confirmHandle = () => {
|
||||
// 校验日期
|
||||
if (!printDayBusinessParams.value.date || printDayBusinessParams.value.date.length !== 2) {
|
||||
ElMessage.warning('请选择日期范围')
|
||||
return
|
||||
}
|
||||
showDayBusiness.value = false
|
||||
emits('success', { date: printDayBusinessParams.value.date })
|
||||
}
|
||||
|
||||
// 日期禁用规则:只能选昨天及更早,不能选未来
|
||||
const disabledDate = (time) => {
|
||||
const yesterday = dayjs().subtract(1, 'day').format('YYYY-MM-DD')
|
||||
return dayjs(time).isAfter(yesterday)
|
||||
}
|
||||
|
||||
// 日期选择后校验:区间长度不能超过7天
|
||||
const handleDateChange = (val) => {
|
||||
if (!val || val.length !== 2) return
|
||||
const [start, end] = val
|
||||
const days = dayjs(end).diff(start, 'day') + 1 // 包含起止日
|
||||
if (days > 7) {
|
||||
ElMessage.warning('日期范围最多只能选择7天')
|
||||
printDayBusinessParams.value.date = [] // 清空选择
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前时间 是否在 00:00 ~ 05:20 之间
|
||||
const time = ref(['00:00', '05:20'])
|
||||
const isInTimeRange = () => {
|
||||
const now = dayjs()
|
||||
const startTime = dayjs(time.value[0], 'HH:mm')
|
||||
const endTime = dayjs(time.value[1], 'HH:mm')
|
||||
return now.isAfter(startTime) && now.isBefore(endTime)
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const show = () => {
|
||||
if (isInTimeRange()) {
|
||||
ElMessage.warning(`当前时间不能打印${props.title},打印时间:${time.value[0]}点至${time.value[1]}点`)
|
||||
return
|
||||
}
|
||||
showDayBusiness.value = true
|
||||
}
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({ show })
|
||||
|
||||
// 初始化默认选中昨天
|
||||
onMounted(() => {
|
||||
const yesterday = dayjs().subtract(1, 'day').format('YYYY-MM-DD')
|
||||
printDayBusinessParams.value.date = [yesterday, yesterday]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.business_wrap {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.business_tips {
|
||||
padding-top: 6px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
83
src/components/refundConsModal.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<el-dialog title="提示" width="450px" v-model="visible">
|
||||
<div class="refund_content">
|
||||
<div class="title_wrap">请确认当前菜品是否已上菜</div>
|
||||
<div class="list_wrap">
|
||||
<div class="item" v-for="(item, index) in list" :key="index">
|
||||
<span>{{ item.name }}</span>
|
||||
<span>x{{ item.num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog_footer">
|
||||
<div class="btn">
|
||||
<el-button @click="handleCancel" style="width: 100%;">未上菜(退还库存)</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" @click="handleOk" style="width: 100%;">已上菜(不退库存)</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
// 未上菜 1退菜图库存
|
||||
function handleCancel() {
|
||||
visible.value = false
|
||||
emits('success', 1)
|
||||
}
|
||||
|
||||
// 已上菜 2仅退菜不退库存
|
||||
function handleOk() {
|
||||
visible.value = false
|
||||
emits('success', 2)
|
||||
}
|
||||
|
||||
function show() {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.refund_content {
|
||||
.title_wrap {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.list_wrap {
|
||||
padding-top: 14px;
|
||||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog_footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
padding-top: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
57
src/importDataApi/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import request from "@/utils/request-import-php";
|
||||
|
||||
/**
|
||||
* 平台列表
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function getplatlist(data) {
|
||||
return request({
|
||||
url: "plat/getplatlist",
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function uploadFile(data) {
|
||||
return request({
|
||||
url: "upload",
|
||||
method: "post",
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入记录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function importlist(data) {
|
||||
return request({
|
||||
url: "plat/importlist",
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载模板
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function downloadTemp(data) {
|
||||
return request({
|
||||
url: "plat/downloadTemp",
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
212
src/layout/components/NavBar/components/HellpCenter.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-text size="large" style="margin: 0 14px;" @click="visible = true">帮助中心</el-text>
|
||||
<el-dialog title="帮助中心" width="1000px" v-model="visible" append-to-body>
|
||||
<div class="help_container">
|
||||
<div class="header">关注官方公众号,查看详细教程视频,快速掌握使用方法</div>
|
||||
<div class="wrap">
|
||||
<div class="item">
|
||||
<div class="title">联系方式</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<div class="icon">
|
||||
<el-icon color="#fff">
|
||||
<PhoneFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-text>客服电话</el-text>
|
||||
</div>
|
||||
<div class="right hover" @click="copyHandle(helpInfo.service_phone)">
|
||||
<el-text type="primary">{{ helpInfo.service_phone }}</el-text>
|
||||
<el-icon color="#666">
|
||||
<CopyDocument />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<div class="icon">
|
||||
<el-icon color="#fff">
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-text>QQ告前咨询</el-text>
|
||||
</div>
|
||||
<div class="right hover" @click="copyHandle(helpInfo.qq_consult)">
|
||||
<el-text type="primary">{{ helpInfo.qq_consult }}</el-text>
|
||||
<el-icon color="#666">
|
||||
<CopyDocument />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 4px;">
|
||||
<div class="left">
|
||||
<div class="icon" style="background-color: #fff;">
|
||||
</div>
|
||||
<el-text>QQ投诉通道</el-text>
|
||||
</div>
|
||||
<div class="right hover" @click="copyHandle(helpInfo.qq_complaint)">
|
||||
<el-text type="primary">{{ helpInfo.qq_complaint }}</el-text>
|
||||
<el-icon color="#666">
|
||||
<CopyDocument />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<div class="icon">
|
||||
<el-icon color="#fff">
|
||||
<Check />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-text>上班时间</el-text>
|
||||
</div>
|
||||
<div class="right">
|
||||
<el-text type="primary">{{ helpInfo.work_time }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">官方公众号</div>
|
||||
<div class="intro">
|
||||
<el-text type="info">关注后即可查看所有操作教程视频</el-text>
|
||||
</div>
|
||||
<div class="ewm_wrap">
|
||||
<el-image :src="helpInfo.help_ac_qrcode" style="width: 145px;height:145px;"></el-image>
|
||||
<el-text type="danger">关注后即可查看所有操作教程视频</el-text>
|
||||
<el-text type="info">微信扫描识别二维码关注,获取更多服务</el-text>
|
||||
</div>
|
||||
<div class="step_wrap" v-if="helpInfo.official_account">
|
||||
<div class="row" v-for="(item, index) in helpInfo.official_account.split(';')" :key="index">
|
||||
<div class="left">
|
||||
<div class="icon">
|
||||
<span class="t">{{ index + 1 }}</span>
|
||||
</div>
|
||||
<el-text>{{ item }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import useClipboard from "vue-clipboard3";
|
||||
import { getHelp } from '@/api/system'
|
||||
const { toClipboard } = useClipboard();
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
// 复制
|
||||
async function copyHandle(text) {
|
||||
try {
|
||||
await toClipboard(text);
|
||||
ElNotification({
|
||||
title: "成功",
|
||||
message: `复制成功`,
|
||||
type: "success",
|
||||
});
|
||||
console.log("Copied to clipboard");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取帮助中心信息
|
||||
const helpInfo = ref({});
|
||||
async function getHelpAjax() {
|
||||
try {
|
||||
const res = await getHelp();
|
||||
helpInfo.value = res;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getHelpAjax()
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
margin-top: 37px;
|
||||
padding: 0 28px;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
|
||||
&:first-child {
|
||||
border-right: 2px solid #EDEDED;
|
||||
padding-right: 38px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-left: 38px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 16px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--el-color-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
.t {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&.hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ewm_wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,8 @@
|
||||
<div class="navbar__right">
|
||||
<!-- 非手机设备(窄屏)才显示 -->
|
||||
<template v-if="!isMobile">
|
||||
<!-- 帮助中心 -->
|
||||
<HellpCenter />
|
||||
<!-- 搜索 -->
|
||||
<MenuSearch />
|
||||
|
||||
@@ -35,6 +37,7 @@ import { useAppStore, useSettingsStore } from "@/store";
|
||||
|
||||
import UserProfile from "./UserProfile.vue";
|
||||
import Notification from "./Notification.vue";
|
||||
import HellpCenter from "./HellpCenter.vue";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const settingStore = useSettingsStore();
|
||||
@@ -48,7 +51,7 @@ const isMobile = computed(() => appStore.device === DeviceEnum.MOBILE);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& > * {
|
||||
&>* {
|
||||
display: inline-block;
|
||||
min-width: 40px;
|
||||
height: $navbar-height;
|
||||
@@ -67,12 +70,12 @@ const isMobile = computed(() => appStore.device === DeviceEnum.MOBILE);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.dark .navbar__right > *:hover {
|
||||
.dark .navbar__right>*:hover {
|
||||
background: rgb(255 255 255 / 20%);
|
||||
}
|
||||
|
||||
.layout-top .navbar__right > *,
|
||||
.layout-mix .navbar__right > * {
|
||||
.layout-top .navbar__right>*,
|
||||
.layout-mix .navbar__right>* {
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -24,53 +24,17 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
},
|
||||
|
||||
{
|
||||
path: "/",
|
||||
path: '/',
|
||||
component: Layout,
|
||||
redirect: "/index",
|
||||
meta: {
|
||||
title: "数据中心",
|
||||
icon: "数据统计",
|
||||
alwaysShow: true,
|
||||
},
|
||||
redirect: '/index',
|
||||
children: [
|
||||
{
|
||||
path: "index",
|
||||
component: () => import("@/views/data/index.vue"),
|
||||
name: "",
|
||||
path: 'index',
|
||||
component: () => import('@/views/index/index.vue'),
|
||||
name: 'index',
|
||||
meta: {
|
||||
title: "经营数据",
|
||||
affix: false,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "sales",
|
||||
name: "",
|
||||
component: () => import("@/views/data/sales.vue"),
|
||||
meta: {
|
||||
title: "销售统计",
|
||||
affix: false,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "table",
|
||||
name: "",
|
||||
component: () => import("@/views/data/table.vue"),
|
||||
meta: {
|
||||
title: "台桌统计",
|
||||
affix: false,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "work",
|
||||
name: "workStatistics",
|
||||
component: () => import("@/views/data/work.vue"),
|
||||
meta: {
|
||||
title: "收银交班记录",
|
||||
affix: false,
|
||||
keepAlive: true,
|
||||
title: '首页',
|
||||
icon: 'homepage',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -83,9 +47,79 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
component: () => import("@/views/error/404.vue"),
|
||||
meta: { hidden: true },
|
||||
},
|
||||
],
|
||||
]
|
||||
},
|
||||
// {
|
||||
// path: "/",
|
||||
// component: Layout,
|
||||
// redirect: "/index",
|
||||
// meta: {
|
||||
// title: "数据中心",
|
||||
// icon: "数据统计",
|
||||
// alwaysShow: true,
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: "index",
|
||||
// component: () => import("@/views/data/index.vue"),
|
||||
// name: "",
|
||||
// meta: {
|
||||
// title: "经营数据",
|
||||
// affix: false,
|
||||
// keepAlive: true,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: "sales",
|
||||
// name: "",
|
||||
// component: () => import("@/views/data/sales.vue"),
|
||||
// meta: {
|
||||
// title: "销售统计",
|
||||
// affix: false,
|
||||
// keepAlive: true,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: "table",
|
||||
// name: "",
|
||||
// component: () => import("@/views/data/table.vue"),
|
||||
// meta: {
|
||||
// title: "台桌统计",
|
||||
// affix: false,
|
||||
// keepAlive: true,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: "finance",
|
||||
// name: "",
|
||||
// component: () => import("@/views/data/finance.vue"),
|
||||
// meta: {
|
||||
// title: "财务报表"
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: "work",
|
||||
// name: "workStatistics",
|
||||
// component: () => import("@/views/data/work.vue"),
|
||||
// meta: {
|
||||
// title: "收银交班记录",
|
||||
// affix: false,
|
||||
// keepAlive: true,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: "401",
|
||||
// component: () => import("@/views/error/401.vue"),
|
||||
// meta: { hidden: true },
|
||||
// },
|
||||
// {
|
||||
// path: "404",
|
||||
// component: () => import("@/views/error/404.vue"),
|
||||
// meta: { hidden: true },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: "/shop",
|
||||
// component: Layout,
|
||||
// meta: {
|
||||
|
||||
@@ -3,6 +3,7 @@ import WebSocketManager, { type ApifoxModel, msgType } from "@/utils/websocket";
|
||||
import orderApi from "@/api/order/order";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import productApi from "@/api/product/index";
|
||||
import categoryApi from "@/api/product/productclassification";
|
||||
import shopUserApi from '@/api/account/shopUser'
|
||||
import limitTimeDiscountApi from '@/api/market/limitTimeDiscount.js'
|
||||
import { BigNumber } from "bignumber.js";
|
||||
@@ -82,8 +83,6 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
default: productType = GoodsType.NORMAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: item.id,
|
||||
@@ -350,11 +349,61 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
}
|
||||
});
|
||||
|
||||
const consList = await productApi.consStock({ shopId: localStorage.getItem("shopId") })
|
||||
|
||||
goods.value = addGoodsSoldOutStatus(goods.value, consList)
|
||||
|
||||
console.log('代客下单页面商品缓存.goods.value', goods.value);
|
||||
|
||||
setGoodsMap(goods.value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 给商品列表批量添加 isSoldOut 售罄状态字段
|
||||
* @param {Array} goodsList - 商品列表 [ { consList, isAutoSoldStock } ]
|
||||
* @param {Array} consStockList - 真实耗材库存列表 [ { consId, stockNumber } ]
|
||||
* @returns 带 isSoldOut 字段的新商品列表
|
||||
*/
|
||||
function addGoodsSoldOutStatus(goodsList, consStockList) {
|
||||
// console.log('addGoodsSoldOutStatus.goodsList', goodsList);
|
||||
// console.log('addGoodsSoldOutStatus.consStockList', consStockList);
|
||||
|
||||
// 耗材ID映射真实库存(保留)
|
||||
const consMap = _.keyBy(consStockList, item => String(item.consId));
|
||||
|
||||
return _.map(goodsList, goods => {
|
||||
let isSoldOut = false;
|
||||
|
||||
// 开启自动售罄才判断
|
||||
if (goods.isAutoSoldStock === 1 || goods.isAutoSoldStock === true) {
|
||||
const goodsConsList = goods.consList || [];
|
||||
|
||||
// 无耗材 → 不售罄
|
||||
if (goodsConsList.length === 0) {
|
||||
isSoldOut = false;
|
||||
} else {
|
||||
// 核心:只要有一个耗材 真实库存 < 商品需要量 → 售罄
|
||||
isSoldOut = _.some(goodsConsList, consItem => {
|
||||
// 商品绑定的耗材ID(对应真实库存ID)
|
||||
const consId = String(consItem.consInfoId);
|
||||
// 商品需要消耗的数量(你的需求量)
|
||||
const needStock = consItem.surplusStock || 0;
|
||||
// 起售数量
|
||||
const suitNum = goods.type == 'single' ? goods.skuList[0].suitNum : 1;
|
||||
// 真实库存
|
||||
const realStock = _.get(consMap, [consId, 'stockNumber'], 0);
|
||||
|
||||
// 真实库存 < 需要量 * 起售数量 → 不足 → 售罄
|
||||
return realStock < needStock * suitNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { ...goods, isSoldOut };
|
||||
});
|
||||
}
|
||||
|
||||
function setGoodsMap(goods: any[]) {
|
||||
for (let item of goods) {
|
||||
goodsMap[item.id] = item;
|
||||
@@ -660,7 +709,9 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
sendMessage('add', { ...basic_msg, ...data });
|
||||
}
|
||||
|
||||
// 添加购物车/编辑购物车
|
||||
function add(data: any) {
|
||||
// console.log('添加购物车/编辑购物车===', data);
|
||||
goods.value.map(item => {
|
||||
if (item.id == data.product_id) {
|
||||
data.is_time_discount = item.is_time_discount ? 1 : 0
|
||||
@@ -675,8 +726,29 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
console.log('carts.add===', data);
|
||||
|
||||
if (hasCart) {
|
||||
// console.log('编辑', msg);
|
||||
if (hasCart.number * 1 + msg.number * 1 == 2) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '购物车已有该商品,请确认是否重复',
|
||||
duration: 4000
|
||||
})
|
||||
}
|
||||
update({ ...hasCart, ...msg, number: hasCart.number * 1 + msg.number * 1 });
|
||||
} else {
|
||||
// console.log('添加', msg);
|
||||
let arr = _.flatten(_.values(oldOrder.value.detailMap))
|
||||
// console.log('添加.arr===', arr);
|
||||
const isExist = _.some(arr, item => Number(item.productId) === msg.product_id)
|
||||
|
||||
// console.log('添加.isExist===', isExist);
|
||||
if (msg.number == 1 && isExist) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '该商品已下单过,请确认是否重复',
|
||||
duration: 4000
|
||||
})
|
||||
}
|
||||
sendMessage('add', msg);
|
||||
}
|
||||
}
|
||||
@@ -688,11 +760,13 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
}
|
||||
|
||||
function rotTable(newVal: string | number, cart_id = []) {
|
||||
sendMessage('rottable', {
|
||||
new_table_code: newVal,
|
||||
table_code: table_code.value,
|
||||
cart_id
|
||||
});
|
||||
if (cart_id.length) {
|
||||
sendMessage('rottable', {
|
||||
new_table_code: newVal,
|
||||
table_code: table_code.value,
|
||||
cart_id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function del(data: any) {
|
||||
@@ -851,8 +925,9 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
}
|
||||
|
||||
// 初始话订单信息/补全历史订单信息
|
||||
async function setOldOrder(data: any) {
|
||||
console.log('补全订单信息', data);
|
||||
async function setOldOrder(data: any, t: number) {
|
||||
console.log('补全历史订单信息来源', t);
|
||||
// console.log('补全订单信息', data);
|
||||
oldOrder.value = {
|
||||
...data,
|
||||
detailMap: returnDetailMap(data.detailMap)
|
||||
@@ -867,10 +942,17 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
|
||||
let $initParams = {} as ApifoxModel;
|
||||
|
||||
async function init(initParams: ApifoxModel, $oldOrder: any | undefined) {
|
||||
await getGoods({});
|
||||
if ($oldOrder) setOldOrder($oldOrder);
|
||||
else oldOrder.value = { detailMap: [] };
|
||||
|
||||
// 标志位,表示是否正在清空历史订单
|
||||
const isClearingOldOrder = ref(false);
|
||||
|
||||
|
||||
async function init(initParams: ApifoxModel | undefined, $oldOrder: any | undefined) {
|
||||
console.log('cart.init.initParams', initParams);
|
||||
console.log('cart.init.$oldOrder', $oldOrder);
|
||||
|
||||
|
||||
|
||||
|
||||
if (initParams) {
|
||||
initParams.table_code = initParams.table_code || '';
|
||||
@@ -878,6 +960,16 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
$initParams = initParams;
|
||||
}
|
||||
|
||||
await getGoods({});
|
||||
|
||||
if ($oldOrder) {
|
||||
await setOldOrder($oldOrder);
|
||||
} else if (table_code.value) {
|
||||
await getOldOrder(table_code.value);
|
||||
} else {
|
||||
oldOrder.value = { detailMap: [] };
|
||||
}
|
||||
|
||||
concocatSocket($initParams);
|
||||
}
|
||||
|
||||
@@ -886,7 +978,7 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
console.log("收到消息:", msg);
|
||||
if (!msg.status) {
|
||||
if (msg.hasOwnProperty('status') && msg.status !== 1 && msg.operate_type !== 'bulk_edit') {
|
||||
return ElMessage.error(msg.message || '操作失败');
|
||||
return ElMessage.error(msg.msg || '操作失败');
|
||||
}
|
||||
}
|
||||
if (msg?.data) {
|
||||
@@ -995,8 +1087,15 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
concocatSocket({ ...$initParams, table_code: table_code.value });
|
||||
}
|
||||
|
||||
// WebSocket 监听 product_update 消息
|
||||
if (msg.operate_type === "product_update") {
|
||||
init($initParams, oldOrder.value);
|
||||
if (isClearingOldOrder.value) {
|
||||
console.log("忽略 product_update 消息,因为正在清空历史订单");
|
||||
isClearingOldOrder.value = false; // 重置标志位
|
||||
return;
|
||||
}
|
||||
console.log("处理 product_update 消息");
|
||||
init($initParams, oldOrder.value); // 重新初始化
|
||||
}
|
||||
|
||||
if (msg.type === "bc") {
|
||||
@@ -1102,7 +1201,7 @@ export const useCartsStore = defineStore("carts", () => {
|
||||
getAllGoodsList,
|
||||
vipUser,
|
||||
changeTableInfo,
|
||||
tableInfo,
|
||||
tableInfo, isClearingOldOrder,
|
||||
clearHistory
|
||||
};
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ export const useUserStore = defineStore("user", () => {
|
||||
setRefreshToken(token);
|
||||
localStorage.setItem("shopId", "" + data.shopInfo.id);
|
||||
localStorage.setItem("branch_shopId", data.shopInfo.id)
|
||||
resolve();
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
|
||||
131
src/utils/request-import-php.js
Normal file
@@ -0,0 +1,131 @@
|
||||
import axios from "axios";
|
||||
import router from "@/router";
|
||||
import { getDouyinToken, getToken } from "@/utils/auth";
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_API_PHP_IMPORT_URL, // api 的 base_url
|
||||
// baseURL: "/import_api", // api 的 base_url
|
||||
timeout: 1000 * 20, // 请求超时时间
|
||||
});
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
if (getToken()) {
|
||||
config.headers["token"] = getToken();
|
||||
}
|
||||
if (!config.headers["Content-Type"]) {
|
||||
config.headers["Content-Type"] = "application/json";
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 确保错误回调返回Promise,避免状态异常
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// response 拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const data = response.data;
|
||||
console.log(data);
|
||||
if (data.code == 0) {
|
||||
ElNotification.error({
|
||||
title: data.msg,
|
||||
duration: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.code == 439 || data.code == 303) {
|
||||
ElNotification.error({
|
||||
title: "请登录",
|
||||
duration: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.code == 4399) {
|
||||
ElNotification.error({
|
||||
title: data.msg,
|
||||
duration: 5000,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
// if (data.code == 1 && !data.data) {
|
||||
// ElNotification.success({
|
||||
// title: data.msg,
|
||||
// duration: 5000
|
||||
// })
|
||||
// return true;
|
||||
// }
|
||||
return data.data;
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
if (axios.isCancel(error)) {
|
||||
console.log("请求已取消");
|
||||
ElNotification.error({
|
||||
title: "请求已取消",
|
||||
duration: 5000,
|
||||
});
|
||||
return Promise.reject("请求已取消");
|
||||
}
|
||||
|
||||
// 兼容blob下载出错json提示
|
||||
if (
|
||||
error.response.data instanceof Blob &&
|
||||
error.response.data.type.toLowerCase().indexOf("json") !== -1
|
||||
) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(error.response.data, "utf-8");
|
||||
reader.onload = function (e) {
|
||||
const errorMsg = JSON.parse(reader.result).message;
|
||||
ElNotification.error({
|
||||
title: errorMsg,
|
||||
duration: 5000,
|
||||
});
|
||||
};
|
||||
} else {
|
||||
let code = 0;
|
||||
try {
|
||||
code = error.response.data.status;
|
||||
} catch (e) {
|
||||
if (error.toString().indexOf("Error: timeout") !== -1) {
|
||||
ElNotification.error({
|
||||
title: "网络请求超时",
|
||||
duration: 5000,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
console.log(code);
|
||||
if (code) {
|
||||
if (code === 401) {
|
||||
// store.dispatch("LogOut").then(() => {
|
||||
// // 用户登录界面提示
|
||||
// Cookies.set("point", 401);
|
||||
// location.reload();
|
||||
// });
|
||||
} else if (code === 403) {
|
||||
router.push({ path: "/401" });
|
||||
} else {
|
||||
const errorMsg = error.response.data.message;
|
||||
if (errorMsg !== undefined) {
|
||||
ElNotification.error({
|
||||
title: errorMsg,
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ElNotification.error({
|
||||
title: "接口请求失败",
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
export default service;
|
||||
@@ -3,6 +3,7 @@ import { useUserStoreHook } from "@/store";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
const user = useUserStoreHook();
|
||||
let isTips = false
|
||||
|
||||
export interface ApifoxModel {
|
||||
account: string;
|
||||
@@ -143,6 +144,7 @@ class WebSocketManager {
|
||||
this.autoConnect = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 自动重连机制
|
||||
private reconnect() {
|
||||
if (!this.autoConnect) {
|
||||
@@ -156,19 +158,24 @@ class WebSocketManager {
|
||||
}, this.reconnectDelay);
|
||||
} else {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
console.error("达到最大重连次数,停止重连");
|
||||
ElMessageBox.confirm('达到最大重连次数' + this.maxReconnectAttempts + '次,已停止重连,是否立即重连?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
// window.location.reload();
|
||||
// console.error("达到最大重连次数,停止重连");
|
||||
if (!isTips) {
|
||||
ElMessageBox.confirm('达到最大重连次数' + this.maxReconnectAttempts + '次,已停止重连,是否立即重连?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
|
||||
callback: (action: string) => {
|
||||
console.log(action);
|
||||
if (action == 'confirm') {
|
||||
this.setupWebSocket();
|
||||
this.reconnectAttempts = 0;
|
||||
callback: (action: string) => {
|
||||
console.log(action);
|
||||
if (action == 'confirm') {
|
||||
isTips = false
|
||||
this.setupWebSocket();
|
||||
this.reconnectAttempts = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
isTips = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ import call from "@/assets/images/application/call.png";
|
||||
|
||||
const list = ref([
|
||||
{ name: "存酒", icon: bear, path: "storingWine", desc: "用户未喝完的酒可暂存在店里" },
|
||||
{ name: "点歌", icon: song, path: "song", desc: "用户可以付费点歌" },
|
||||
{ name: "广告", icon: ad, path: "advertisement", desc: "添加弹窗广告" },
|
||||
// { name: "点歌", icon: song, path: "song", desc: "用户可以付费点歌" },
|
||||
// { name: "广告", icon: ad, path: "advertisement", desc: "添加弹窗广告" },
|
||||
{ name: "叫号", icon: call, path: "lineUplist", desc: "" },
|
||||
]);
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
<myDialog ref="myDialogRefqs" title="记录" @confirm="confirmqs" width="30%">
|
||||
<el-form-item label="选择用户">
|
||||
<el-select v-model="datas.DialogForm.userId" filterable placeholder="请选择选择用户" style="width: 240px">
|
||||
<el-option v-for="item in datas.options" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
<el-option v-for="item in datas.options" :key="item.userId" :label="`${item.nickName}/${item.phone}`"
|
||||
:value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量">
|
||||
@@ -128,7 +129,7 @@ function myDialogRefqsevent(item) {
|
||||
myDialogRefqs.value.open()
|
||||
}
|
||||
async function getshopUser(params) {
|
||||
const res = await API.getshopUser({})
|
||||
const res = await API.getshopUser({ page: 1, size: 999, ...params })
|
||||
datas.options = res.records
|
||||
}
|
||||
async function getList(data = {}) {
|
||||
|
||||
@@ -19,10 +19,11 @@ const AuthAPI = {
|
||||
});
|
||||
},
|
||||
// 获取用户店铺列表
|
||||
getshopUser() {
|
||||
getshopUser(params: any) {
|
||||
return request<any, Responseres>({
|
||||
url: `/account/admin/shopUser`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
},
|
||||
// 新增
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
<el-form ref="ruleFormRef" :rules="datas.rules" :model="datas.DialogForm" label-width="80px">
|
||||
<el-form-item label="选择用户">
|
||||
<el-select v-model="datas.DialogForm.userId" filterable placeholder="请选择选择用户" style="width: 240px">
|
||||
<el-option v-for="item in datas.options" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
<el-option v-for="item in datas.options" :key="item.userId" :label="`${item.nickName}/${item.phone}`"
|
||||
:value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择酒品">
|
||||
@@ -107,7 +108,7 @@ async function getList(data = {}) {
|
||||
datas.pagingConfig.pageNumber = res.pageNumber
|
||||
}
|
||||
async function getshopUser(params) {
|
||||
const res = await API.getshopUser({})
|
||||
const res = await API.getshopUser({ page: 1, size: 999, ...params })
|
||||
datas.options = res.records
|
||||
}
|
||||
async function getstorageGood() {
|
||||
|
||||
@@ -18,10 +18,11 @@ const AuthAPI = {
|
||||
});
|
||||
},
|
||||
// 获取用户店铺列表
|
||||
getshopUser() {
|
||||
getshopUser(params: any) {
|
||||
return request<any, Responseres>({
|
||||
url: `/account/admin/shopUser`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
},
|
||||
// 获取酒品列表
|
||||
|
||||
743
src/views/data/finance.vue
Normal file
@@ -0,0 +1,743 @@
|
||||
<template>
|
||||
<div class="gyq_container">
|
||||
<div class="row">
|
||||
<div class="between">
|
||||
<el-form :model="queryForm" inline>
|
||||
<el-form-item>
|
||||
<el-date-picker v-model="queryForm.queryDate" type="date" placeholder="选择日期" format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD" :disabled-date="disabledFutureDate" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" :loading="loading" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="handleReset" icon="Refresh" :loading="loading">重置</el-button>
|
||||
<el-button icon="Printer" @click="printBusinessDialogRef.show()">经营日报</el-button>
|
||||
<el-button icon="Printer" @click="printBusinessDialogRef2.show()">日结单</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form inline>
|
||||
<el-form-item>
|
||||
<el-select v-model="queryForm.platform" placeholder="选择平台" clearable style="width: 150px;">
|
||||
<el-option v-for="item in platformList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleExport" icon="Download">导出</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-loading="loading">
|
||||
<div class="warp" style="width: 400px;">
|
||||
<div class="card">
|
||||
<div class="header_title">营业额</div>
|
||||
<div class="num" style="color: var(--el-color-primary);">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.turnover || 0) }}
|
||||
</div>
|
||||
<div class="intro">营业额</div>
|
||||
<div class="pay_wrap">
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.wechat || 0) }}
|
||||
</div>
|
||||
<span class="t">微信支付金额</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.alipay || 0) }}
|
||||
</div>
|
||||
<span class="t">支付宝支付金额</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.selfScan || 0) }}
|
||||
</div>
|
||||
<span class="t">二维码收款</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.barScan || 0) }}
|
||||
</div>
|
||||
<span class="t">扫码收款</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.cash || 0) }}
|
||||
</div>
|
||||
<span class="t">现金收款</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.recharge || 0) }}
|
||||
</div>
|
||||
<span class="t">充值</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.owed || 0) }}
|
||||
</div>
|
||||
<span class="t">挂账</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.turnover.balance || 0) }}
|
||||
</div>
|
||||
<span class="t">余额支付</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="order_info">
|
||||
<div class="order_title">
|
||||
<span class="dot"></span>
|
||||
<span class="t">订单</span>
|
||||
</div>
|
||||
<div class="order_lits">
|
||||
<div class="item">
|
||||
<span class="t">订单金额</span>
|
||||
<span class="n">{{ tableData.order.orderAmount || 0 }}</span>
|
||||
</div>
|
||||
<span class="line">|</span>
|
||||
<div class="item">
|
||||
<span class="t">订单总数</span>
|
||||
<span class="n">{{ tableData.order.orderCount || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="header_title">数据统计</div>
|
||||
<div class="pay_wrap">
|
||||
<div class="item">
|
||||
<span class="n">{{ tableData.sts.customerCount || 0 }}</span>
|
||||
<span class="t">就餐人数</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="n">{{ tableData.sts.orderCount || 0 }}</span>
|
||||
<span class="t">订单数</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="n">{{ tableData.sts.tableCount || 0 }}</span>
|
||||
<span class="t">桌台数</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.sts.avgPayAmount || 0) }}
|
||||
</div>
|
||||
<div class="t">客单价
|
||||
<el-tooltip class="box-item" effect="dark" content="实付金额(包含现金支付 包含会员支付 包含挂账)/就餐人数没有具体人数时,默认一桌按照1人计算"
|
||||
placement="top">
|
||||
<el-icon color="#666">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="n">{{ tableData.sts.turnoverRate || 0 }}%</span>
|
||||
<div class="t">翻台率
|
||||
<el-tooltip class="box-item" effect="dark" content="(订单数-桌台数)/桌台数*100%" placement="top">
|
||||
<el-icon color="#666">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.sts.profitAmount || 0) }}
|
||||
</div>
|
||||
<div class="t">毛利润
|
||||
<el-tooltip class="box-item" effect="dark" content="(订单实付金额-商品成本)" placement="top">
|
||||
<el-icon color="#666">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.sts.productCostAmount || 0) }}
|
||||
</div>
|
||||
<span class="t">商品成本</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="n">{{ tableData.sts.profitRate || 0 }}%</span>
|
||||
<div class="t">毛利率
|
||||
<el-tooltip class="box-item" effect="dark" content="(订单实付金额-商品成本)/订单实付金额*100%" placement="top">
|
||||
<el-icon color="#666">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="item">
|
||||
<span class="n">{{ tableData.sts.netProfitAmount || 0 }}%</span>
|
||||
<span class="t">净利率</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.sts.netProfitRate || 0) }}
|
||||
</div>
|
||||
<span class="t">净利润</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="flex: 1;">
|
||||
<div class="header_title">商家经营数据</div>
|
||||
<div class="content">
|
||||
<div class="card" style="flex: 1;">
|
||||
<div class="num" style="color: var(--el-color-success);">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.discountAmount || 0) }}
|
||||
</div>
|
||||
<div class="intro">优惠金额</div>
|
||||
<div class="item_list">
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
{{ tableData.discount.discountCount || 0 }}
|
||||
</div>
|
||||
<div class="label">
|
||||
优惠笔数
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.newConsumerDiscount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
新客立减
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.freeCashAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
霸王餐
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.fullMinusAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
满减活动
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.couponAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
优惠券
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.memberDiscount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
会员折扣
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.pointsDiscountAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
积分抵扣金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.discount.orderDiscount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
订单改价
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="flex: 1;">
|
||||
<div class="num" style="color: var(--el-color-danger);">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.refundAmount || 0) }}
|
||||
</div>
|
||||
<div class="intro">退款金额</div>
|
||||
<div class="item_list">
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.onlineRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
线上退款金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.cashRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
现金退款金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.memberRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
余额退款金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.onlineRechargeRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
线上充值退款金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.cashRechargeRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
现金充值退款金额
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.refund.creditRefundAmount || 0) }}
|
||||
</div>
|
||||
<div class="label">
|
||||
挂账退款金额
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="flex: 1;">
|
||||
<div class="num" style="color: var(--el-color-warning);">
|
||||
<span class="i">¥</span>
|
||||
{{ multiplyAndFormat(tableData.order.orderAmount || 0) }}
|
||||
</div>
|
||||
<div class="intro">订单金额</div>
|
||||
<div class="item_list">
|
||||
<div class="item">
|
||||
<div class="n">
|
||||
{{ tableData.order.orderCount || 0 }}
|
||||
</div>
|
||||
<div class="label">
|
||||
订单总数
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<printBusinessDialog ref="printBusinessDialogRef" @success="printHandle" />
|
||||
<printBusinessDialog ref="printBusinessDialogRef2" @success="printHandle2" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
import { ref, onMounted } from "vue";
|
||||
import OrderApi from "@/api/order/order";
|
||||
import { downloadFile, multiplyAndFormat } from '@/utils'
|
||||
import printBusinessDialog from "@/components/printBusinessDialog.vue";
|
||||
|
||||
const printBusinessDialogRef = ref(null)
|
||||
|
||||
// 打印经营日报回调
|
||||
async function printHandle(res) {
|
||||
try {
|
||||
const shopStaff = JSON.parse(localStorage.getItem('shopStaff')) || { name: '' }
|
||||
const shopName = localStorage.getItem('shopName')
|
||||
await OrderApi.printDayReport({
|
||||
beginDate: res.date[0],
|
||||
endDate: res.date[1],
|
||||
rangeType: 'CUSTOM',
|
||||
shopId: localStorage.getItem('shopId') || '',
|
||||
operator: shopStaff.name || shopName
|
||||
})
|
||||
ElMessage.success('打印成功')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const printBusinessDialogRef2 = ref(null)
|
||||
// 打印日结单回调
|
||||
async function printHandle2(res) {
|
||||
try {
|
||||
const shopStaff = JSON.parse(localStorage.getItem('shopStaff')) || { name: '' }
|
||||
const shopName = localStorage.getItem('shopName')
|
||||
await OrderApi.printDaySettle({
|
||||
beginDate: res.date[0],
|
||||
endDate: res.date[1],
|
||||
rangeType: 'CUSTOM',
|
||||
shopId: localStorage.getItem('shopId') || '',
|
||||
operator: shopStaff.name || shopName
|
||||
})
|
||||
ElMessage.success('打印成功')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const queryForm = ref({
|
||||
queryDate: dayjs().format('YYYY-MM-DD'), // 查询日期 yyyy-MM-dd
|
||||
platform: 'czg',
|
||||
shopId: localStorage.getItem('shopId') || '',
|
||||
mainShopId: ''
|
||||
});
|
||||
|
||||
const platformList = ref([
|
||||
{ value: 'czg', label: '银收客' },
|
||||
{ value: 'MTuan', label: '美团' },
|
||||
{ value: 'CMeMe', label: '菜么么' },
|
||||
{ value: 'KRuYun', label: '客如云' },
|
||||
])
|
||||
|
||||
// 禁用今天以后的日期
|
||||
const disabledFutureDate = (time) => {
|
||||
return dayjs(time).isAfter(dayjs().startOf('day'))
|
||||
}
|
||||
|
||||
// 查询
|
||||
function handleQuery() {
|
||||
getData()
|
||||
}
|
||||
|
||||
// 重置
|
||||
function handleReset() {
|
||||
queryForm.value.queryDate = dayjs().format('YYYY-MM-DD')
|
||||
queryForm.value.platform = 'czg'
|
||||
getData()
|
||||
}
|
||||
|
||||
// 导出
|
||||
async function handleExport() {
|
||||
try {
|
||||
if (!queryForm.value.platform) {
|
||||
ElMessage.error('请选择导出平台')
|
||||
return
|
||||
}
|
||||
const res = await OrderApi.financeExport(queryForm.value)
|
||||
downloadFile(res, '财务报表', 'xlsx')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false);
|
||||
const tableData = ref({
|
||||
turnover: {},
|
||||
order: {},
|
||||
discount: {},
|
||||
refund: {},
|
||||
sts: {}
|
||||
});
|
||||
|
||||
// 查询财务报表
|
||||
async function getData() {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await OrderApi.financeSts(queryForm.value)
|
||||
tableData.value = res
|
||||
console.log('tableData.value', tableData.value);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.gyq_container {
|
||||
padding: 14px;
|
||||
|
||||
.gyq_content {
|
||||
padding: 14px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.between {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
|
||||
&.mt14 {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.warp {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
|
||||
.header_title {
|
||||
font-size: 16px;
|
||||
color: 333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: #F8F8F8;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
padding: 14px;
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
|
||||
.item_list {
|
||||
margin-top: 14px;
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.item {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 14px;
|
||||
|
||||
&:nth-child(odd) {
|
||||
background-color: #F3F7FA;
|
||||
}
|
||||
|
||||
.n {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.i {
|
||||
font-size: 10px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.i {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.intro {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.pay_wrap {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-column-gap: 0px;
|
||||
grid-row-gap: 14px;
|
||||
background-color: #F8F8F8;
|
||||
padding: 14px;
|
||||
margin-top: 14px;
|
||||
border-radius: 8px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.n {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.i {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order_info {
|
||||
border-top: 1px solid #ececec;
|
||||
padding-top: 14px;
|
||||
|
||||
.order_title {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.dot {
|
||||
--size: 12px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.order_lits {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
margin-top: 4px;
|
||||
|
||||
.line {
|
||||
color: #ececec;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
|
||||
.t {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.n {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.waterfall {
|
||||
/* 核心属性1:定义瀑布流列数(关键) */
|
||||
column-count: 3;
|
||||
/* 核心属性2:列之间的间距(替代margin,避免卡片间距错乱) */
|
||||
column-gap: 14px;
|
||||
/* 可选:防止卡片内容被列分割(关键!避免卡片跨列断裂) */
|
||||
break-inside: avoid;
|
||||
|
||||
.waterfall-card {
|
||||
/* 必须:适配多列布局,避免卡片宽度溢出 */
|
||||
width: 100%;
|
||||
/* 卡片间距:仅需设置底部外边距(上下间距),左右间距由column-gap控制 */
|
||||
margin-bottom: 14px;
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
/* 配合break-inside: avoid,强化卡片不可分割 */
|
||||
page-break-inside: avoid;
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.dot {
|
||||
--size: 10px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: 24px;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin-top: 6px;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
padding-left: 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -52,6 +52,7 @@
|
||||
<span>营业</span>
|
||||
</div>
|
||||
<div class="u-flex" style="flex-wrap: wrap">
|
||||
<importData :type="9" style="margin-right: 14px;" @close="importDataClose" />
|
||||
<el-select v-if="isHeadShop == 1 && loginType == 0" v-model="shopId" placeholder="选择分店"
|
||||
style="width: 200px; margin-right: 10px;" @change="shopChange">
|
||||
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
|
||||
@@ -101,7 +102,14 @@
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<img class="icon" src="@/assets/images/data/scan.png" />
|
||||
<span>主扫收款</span>
|
||||
<span>二维码收款</span>
|
||||
</div>
|
||||
<span class="num">{{ trade.mainScanPayAmount || 0 }}</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<img class="icon" src="@/assets/images/data/scan.png" />
|
||||
<span>扫码收款</span>
|
||||
</div>
|
||||
<span class="num">{{ trade.backScanPayAmount || 0 }}</span>
|
||||
</div>
|
||||
@@ -180,7 +188,7 @@
|
||||
<div class="gropress l" :style="{
|
||||
width: `${trade.rechargeAmount
|
||||
? (trade.rechargeAmount /
|
||||
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
|
||||
(trade.rechargeAmount * 1 + trade.rechargeRefundAmount * 1)) *
|
||||
100
|
||||
: 0
|
||||
}%`,
|
||||
@@ -188,7 +196,7 @@
|
||||
<div class="gropress r" :style="{
|
||||
width: `${trade.rechargeRefundAmount
|
||||
? (trade.rechargeRefundAmount /
|
||||
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
|
||||
(trade.rechargeAmount * 1 + trade.rechargeRefundAmount * 1)) *
|
||||
100
|
||||
: 0
|
||||
}%`,
|
||||
@@ -495,6 +503,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import dataSummaryApi from "@/api/order/data-summary";
|
||||
import ShopApi from "@/api/account/shop";
|
||||
import dayjs from "dayjs";
|
||||
@@ -504,6 +513,7 @@ import { formatDateRange } from './utils/index.js'
|
||||
import { multiplyAndFormat } from '@/utils/index.js'
|
||||
export default {
|
||||
name: "home",
|
||||
components: { importData },
|
||||
data() {
|
||||
return {
|
||||
multiplyAndFormat,
|
||||
@@ -704,6 +714,15 @@ export default {
|
||||
// this.initCardUserChart();
|
||||
},
|
||||
methods: {
|
||||
importDataClose() {
|
||||
// this.summaryGet();
|
||||
this.dateAmount();
|
||||
this.dateProduct();
|
||||
// this.summaryDateGet();
|
||||
this.timeChange(this.timeValue);
|
||||
this.profitRateBarChart()
|
||||
this.costLineChart()
|
||||
},
|
||||
/**
|
||||
* 获取分店列表
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
<span v-if="!downloadLoading">导出Excel</span>
|
||||
<span v-else>下载中...</span>
|
||||
</el-button>
|
||||
<el-button icon="Printer" :loading="printLoading" @click="$refs.printBusinessDialogRef.show()">打印</el-button>
|
||||
<importData :type="7" @close="getTableData" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -184,19 +186,23 @@
|
||||
@current-change="paginationChange" @size-change="sizeChange"
|
||||
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
|
||||
</div>
|
||||
<printBusinessDialog ref="printBusinessDialogRef" title="商品报表" @success="printBusinessConfirm" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import saleSummaryApi from "@/api/order/sale-summary";
|
||||
import categoryApi from "@/api/product/productclassification";
|
||||
import ShopApi from "@/api/account/shop";
|
||||
import dayjs from "dayjs";
|
||||
import { downloadFile, multiplyAndFormat } from "@/utils/index";
|
||||
import { formatDateRange } from './utils/index.js'
|
||||
import printBusinessDialog from '@/components/printBusinessDialog.vue';
|
||||
|
||||
export default {
|
||||
components: { importData, printBusinessDialog },
|
||||
data() {
|
||||
return {
|
||||
multiplyAndFormat,
|
||||
@@ -230,7 +236,8 @@ export default {
|
||||
// dayjs(time):将原生 Date 转为 dayjs 对象
|
||||
// isAfter:判断目标日期是否在今天之后
|
||||
return dayjs(time).isAfter(dayjs().startOf('day'));
|
||||
}
|
||||
},
|
||||
printLoading: false
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
@@ -252,6 +259,34 @@ export default {
|
||||
this.geiShopList();
|
||||
},
|
||||
methods: {
|
||||
// 确认打印
|
||||
printBusinessConfirm(res) {
|
||||
this.printHandle(res.date)
|
||||
},
|
||||
// 打印
|
||||
async printHandle(date) {
|
||||
try {
|
||||
const shopStaff = JSON.parse(localStorage.getItem('shopStaff')) || { name: '' }
|
||||
const shopName = localStorage.getItem('shopName')
|
||||
|
||||
this.printLoading = true
|
||||
|
||||
await saleSummaryApi.print({
|
||||
beginDate: date[0],
|
||||
endDate: date[1],
|
||||
categoryId: this.query.prodCategoryId,
|
||||
productName: this.query.productName,
|
||||
shopId: this.shopId,
|
||||
rangeType: this.timeValue,
|
||||
operator: shopStaff.name || shopName
|
||||
})
|
||||
ElMessage.success('操作成功')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
this.printLoading = false
|
||||
},
|
||||
/**
|
||||
* 获取分店列表
|
||||
*/
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: flex;">
|
||||
<el-button type="primary" @click="getTableData">查询</el-button>
|
||||
<el-button @click="resetHandle">重置</el-button>
|
||||
<el-button icon="download" v-loading="downloadLoading" @click="downloadHandle">
|
||||
<span v-if="!downloadLoading">导出Excel</span>
|
||||
<span v-else>下载中...</span>
|
||||
</el-button>
|
||||
<importData :type="8" @close="getTableData" />
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
@@ -90,16 +91,17 @@
|
||||
</el-table-column>
|
||||
</el-table> -->
|
||||
</div>
|
||||
<!-- <div class="head-container">
|
||||
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
|
||||
<div class="head-container">
|
||||
<el-pagination :total="tableData.total" :current-page="tableData.page" :page-size="tableData.size"
|
||||
@current-change="paginationChange" @size-change="sizeChange"
|
||||
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from "lodash";
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import tableSummaryApi from "@/api/order/table-summary";
|
||||
import ShopApi from "@/api/account/shop";
|
||||
import dayjs from "dayjs";
|
||||
@@ -107,6 +109,7 @@ import { downloadFile } from "@/utils/index";
|
||||
import { formatDateRange } from './utils/index.js'
|
||||
|
||||
export default {
|
||||
components: { importData },
|
||||
data() {
|
||||
return {
|
||||
timeValue: "today",
|
||||
@@ -199,13 +202,14 @@ export default {
|
||||
},
|
||||
// 重置查询
|
||||
resetHandle() {
|
||||
this.timeValue = "";
|
||||
this.timeValue = "today";
|
||||
this.query = { ...this.resetQuery };
|
||||
this.page = 1;
|
||||
this.getTableData();
|
||||
},
|
||||
// 分页大小改变
|
||||
sizeChange(e) {
|
||||
this.tableData.page = 1
|
||||
this.tableData.size = e;
|
||||
this.getTableData();
|
||||
},
|
||||
@@ -225,8 +229,11 @@ export default {
|
||||
// page: this.tableData.page,
|
||||
// size: this.tableData.size,
|
||||
rangeType: this.timeValue,
|
||||
// rangeType: 'custom',
|
||||
beginDate: this.query.createdAt[0],
|
||||
endDate: this.query.createdAt[1],
|
||||
// beginDate: '2026-01-26',
|
||||
// endDate: '2026-01-26',
|
||||
shopId: this.shopId
|
||||
});
|
||||
this.tableData.loading = false;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<el-table-column prop="shopName" align="center" label="商户名称" />
|
||||
<el-table-column prop="staffName" align="center" label="职员名称" />
|
||||
<el-table-column prop="orderCount" align="center" label="订单数量" />
|
||||
<el-table-column prop="handAmount" align="center" label="应交金额" />
|
||||
<el-table-column prop="quickInAmount" align="center" label="快捷收款金额" />
|
||||
<el-table-column prop="orderTurnover" align="center" label="应交金额" />
|
||||
<el-table-column prop="balance" align="center" label="余额支付" />
|
||||
<el-table-column prop="refundAmount" align="center" label="退款金额" />
|
||||
<el-table-column prop="handAmount" align="center" label="总收入" />
|
||||
<el-table-column prop="turnover" align="center" label="总收入" />
|
||||
<el-table-column prop="loginTime" align="center" label="开始时间" />
|
||||
<el-table-column prop="handoverTime" align="center" label="交班时间" />
|
||||
<el-table-column label="操作" align="center">
|
||||
|
||||
@@ -15,9 +15,13 @@ const modalConfig: IModalConfig<addRequest> = {
|
||||
},
|
||||
formAction: function (data) {
|
||||
let obj = { ...data }
|
||||
obj.printType = data.printType.join(',')
|
||||
console.log("打印类型", data);
|
||||
// obj.printType = data.printType.join(',')
|
||||
obj.categoryIds = JSON.stringify(data.categoryIdsArr)
|
||||
obj.categoryList = JSON.stringify(data.categoryIdsArr)
|
||||
if (data.classifyPrint == 0) {
|
||||
obj.categoryIds = ''
|
||||
}
|
||||
// obj.categoryIds = '[' + data.categoryIdsArr.join(',') + ']'
|
||||
return printerApi.add(obj);
|
||||
},
|
||||
@@ -85,7 +89,7 @@ const modalConfig: IModalConfig<addRequest> = {
|
||||
{
|
||||
type: "select",
|
||||
label: "打印类型",
|
||||
prop: "subType",
|
||||
prop: "printType",
|
||||
rules: [{ required: false, message: "请选择打印类型", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请选择打印类型",
|
||||
@@ -103,7 +107,7 @@ const modalConfig: IModalConfig<addRequest> = {
|
||||
{
|
||||
type: "select",
|
||||
label: "打印机品牌",
|
||||
prop: "contentType",
|
||||
prop: "brand",
|
||||
rules: [{ required: true, message: "请选择打印机品牌", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请选择打印机品牌",
|
||||
@@ -139,27 +143,27 @@ const modalConfig: IModalConfig<addRequest> = {
|
||||
label: "",
|
||||
initialValue: []
|
||||
},
|
||||
|
||||
{
|
||||
type: "radio",
|
||||
label: "打印数量",
|
||||
prop: "printQty",
|
||||
prop: "printNum",
|
||||
options: options.printQty,
|
||||
initialValue: options.printQty[0].value
|
||||
},
|
||||
{
|
||||
type: "radio",
|
||||
label: "打印方式",
|
||||
prop: "printMethod",
|
||||
prop: "kitchenPrintMode",
|
||||
options: options.printMethod,
|
||||
initialValue: options.printMethod[0].value
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
type: "custom",
|
||||
label: "打印类型",
|
||||
prop: "printType",
|
||||
prop: "printContentType",
|
||||
options: options.printType,
|
||||
initialValue: options.printType.map(v => v.value)
|
||||
initialValue: options.printType.map(v => v.value),
|
||||
slotName: 'printTypeSlot'
|
||||
},
|
||||
{
|
||||
label: "打印机状态",
|
||||
|
||||
@@ -59,8 +59,8 @@ const contentConfig: IContentConfig<getListRequest> = {
|
||||
label: "状态",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "switch",
|
||||
slotName: "status",
|
||||
templet: "custom",
|
||||
slotName: "status"
|
||||
},
|
||||
{ label: "创建时间", align: "center", prop: "createTime" },
|
||||
// {
|
||||
|
||||
@@ -20,6 +20,9 @@ const modalConfig: IModalConfig<editRequest> = {
|
||||
obj.categoryIds = JSON.stringify(data.categoryIdsArr)
|
||||
obj.categoryList = JSON.stringify(data.categoryIdsArr)
|
||||
}
|
||||
if (data.classifyPrint == 0) {
|
||||
obj.categoryIds = ''
|
||||
}
|
||||
return printerApi.edit(obj);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
@@ -157,13 +160,12 @@ const modalConfig: IModalConfig<editRequest> = {
|
||||
initialValue: options.printMethod[0].value
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
type: "custom",
|
||||
label: "打印类型",
|
||||
prop: "printType",
|
||||
options: options.printType,
|
||||
initialValue: options.printType.map(v => v.value)
|
||||
prop: "printContentType",
|
||||
options: '',
|
||||
initialValue: ''
|
||||
},
|
||||
|
||||
{
|
||||
label: "打印机状态",
|
||||
prop: "status",
|
||||
@@ -174,6 +176,16 @@ const modalConfig: IModalConfig<editRequest> = {
|
||||
inactiveValue: 0,
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "媒体音开关",
|
||||
prop: "volumeSwitch",
|
||||
type: "switch",
|
||||
initialValue: 1,
|
||||
attrs: {
|
||||
activeValue: 1,
|
||||
inactiveValue: 0,
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
|
||||
@edit-click="handleEditClick" @export-click="handleExportClick" @search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick" @operat-click="handleOperatClick" @filter-change="handleFilterChange">
|
||||
<template #status="scope">
|
||||
<!-- <template #status="scope">
|
||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</template> -->
|
||||
<template #contentType="scope">
|
||||
{{ scope.row.contentType == 'yxyPrinter' ? "云想印" : "飞鹅" }}
|
||||
{{ scope.row.contentType == "yxyPrinter" ? "云想印" : "飞鹅" }}
|
||||
</template>
|
||||
<template #subType="scope">
|
||||
{{ scope.row.subType == 'label' ? "标签" : "小票" }}
|
||||
{{ scope.row.subType == "label" ? "标签" : "小票" }}
|
||||
</template>
|
||||
<template #caozuo="scope">
|
||||
{{ scope }}
|
||||
@@ -26,10 +26,18 @@
|
||||
<template #gender="scope">
|
||||
<DictLabel v-model="scope.row[scope.prop]" code="gender" />
|
||||
</template>
|
||||
<template #status="scope">
|
||||
<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0"
|
||||
@click="statusChange($event, scope.row)"></el-switch>
|
||||
</template>
|
||||
<template #operate="scope">
|
||||
<div v-if="scope.row.connectionType != 'USB'">
|
||||
<el-button @click="handleEditClick(scope.row)" icon="Edit" type="primary" link>编辑</el-button>
|
||||
<el-button @click="handdeleteevent(scope.row)" icon="Delete" type="danger" link>删除</el-button>
|
||||
<el-button @click="handleEditClick(scope.row)" icon="Edit" type="primary" link>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button @click="handdeleteevent(scope.row)" icon="Delete" type="danger" link>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<!-- <template #mobile="scope">
|
||||
@@ -39,10 +47,21 @@
|
||||
</page-content>
|
||||
|
||||
<!-- 新增 -->
|
||||
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
|
||||
<!-- <page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
|
||||
<template #gender="scope">
|
||||
<Dict v-model="scope.formData[scope.prop]" code="gender" />
|
||||
</template>
|
||||
<template #printTypeSlot="scope">
|
||||
<div class="row" v-for="(item, index) in printTypeList" :key="index">
|
||||
<div class="title">{{ item.label }}</div>
|
||||
<div class="cont">
|
||||
<el-checkbox-group v-model="item.values" @change="printTypeChange($event, index, scope)">
|
||||
<el-checkbox :label="item.label" :value="item.value" v-for="item in item.list"
|
||||
:key="item.value"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #classifyPrintData="scope">
|
||||
<template v-if="scope.formData.classifyPrint == 1">
|
||||
<el-checkbox-group v-model="scope.formData.categoryIdsArr">
|
||||
@@ -52,13 +71,24 @@
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
</template>
|
||||
</page-modal>
|
||||
</page-modal> -->
|
||||
|
||||
<!-- 编辑 -->
|
||||
<page-modal ref="editModalRef" :modal-config="editModalConfig" @submit-click="handleSubmitClick">
|
||||
<!-- <page-modal ref="editModalRef" :modal-config="editModalConfig" @submit-click="handleSubmitClick">
|
||||
<template #gender="scope">
|
||||
<Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" />
|
||||
</template>
|
||||
<template #printTypeSlot="scope">
|
||||
<div class="row" v-for="(item, index) in printTypeList" :key="index">
|
||||
<div class="title">{{ item.label }}</div>
|
||||
<div class="cont">
|
||||
<el-checkbox-group v-model="item.values" @change="printTypeChange($event, index, scope)">
|
||||
<el-checkbox :label="item.label" :value="item.value" v-for="item in item.list"
|
||||
:key="item.value"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #classifyPrintData="scope">
|
||||
<template v-if="scope.formData.classifyPrint == 1">
|
||||
<el-checkbox-group v-model="scope.formData.categoryIdsArr">
|
||||
@@ -68,11 +98,103 @@
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
</template>
|
||||
</page-modal>
|
||||
</page-modal> -->
|
||||
|
||||
<el-dialog :title="form.id ? '编辑打印机' : '添加打印机'" width="800px" v-model="visible" @closed="dialogClosed"
|
||||
@open="dialogOpen">
|
||||
<div style="height: 60vh;overflow-y: auto;" ref="formDivRef">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-form-item label="设备名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型">
|
||||
<el-radio-group v-model="form.connectionType">
|
||||
<el-radio-button label="USB" value="USB"></el-radio-button>
|
||||
<el-radio-button label="云打印" value="云打印"></el-radio-button>
|
||||
<el-radio-button label="局域网" value="局域网"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="小票类型">
|
||||
<el-radio-group v-model="form.printType">
|
||||
<el-radio-button label="标签" value="label"></el-radio-button>
|
||||
<el-radio-button label="小票" value="cash"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="打印机品牌" prop="brand">
|
||||
<el-radio-group v-model="form.brand">
|
||||
<el-radio-button label="飞鹅"></el-radio-button>
|
||||
<el-radio-button label="云想印"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="ip地址/MAC地址" prop="address">
|
||||
<el-input v-model="form.address" placeholder="请输入ip地址/MAC地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="端口" prop="port">
|
||||
<el-input v-model="form.port" placeholder="请输入端口"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="小票尺寸" prop="receiptSize">
|
||||
<el-radio-group v-model="form.receiptSize">
|
||||
<el-radio-button label="58mm"></el-radio-button>
|
||||
<el-radio-button label="80mm"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="打印数量" prop="printNum">
|
||||
<el-input-number v-model="form.printNum" :step="1" :min="1"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="打印内容" prop="printContentType">
|
||||
<div class="row" v-for="(item, index) in printTypeList" :key="index">
|
||||
<div class="title">{{ item.label }}</div>
|
||||
<div class="cont">
|
||||
<el-checkbox-group v-model="item.values" @change="printTypeChange($event, index)">
|
||||
<el-checkbox :label="item.label" :value="item.value" v-for="item in item.list"
|
||||
:key="item.value"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="打印模式" prop="kitchenPrintMode">
|
||||
<el-radio-group v-model="form.kitchenPrintMode">
|
||||
<el-radio-button label="整单" value="all"></el-radio-button>
|
||||
<el-radio-button label="单个" value="only"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-text type="info" style="margin-left: 14px;">仅针对厨房制作单的打印</el-text>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="分类打印">
|
||||
<div class="column">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-radio-group v-model="form.classifyPrint">
|
||||
<el-radio-button label="所有" value="0"></el-radio-button>
|
||||
<el-radio-button label="部分分类" value="1" v-if="printTypeList[1].values.length > 0"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-text type="info" style="margin-left: 14px;">仅针对厨房制作单的打印</el-text>
|
||||
</div>
|
||||
<template v-if="form.classifyPrint == 1">
|
||||
<el-checkbox-group v-model="form.categoryIds">
|
||||
<el-checkbox v-for="item in PrinterTypeList" :value="item.id" :label="item.name"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="媒体音量">
|
||||
<el-switch v-model="form.volumeSwitch" :active-value="1" :inactive-value="0"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用状态">
|
||||
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="submitHandle">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import _ from 'lodash'
|
||||
import UserAPI from "@/api/account/printer";
|
||||
import type { IObject, IOperatData } from "@/components/CURD/types";
|
||||
import usePage from "@/components/CURD/usePage";
|
||||
@@ -80,6 +202,166 @@ import addModalConfig from "./config/add";
|
||||
import contentConfig from "./config/content";
|
||||
import editModalConfig from "./config/edit";
|
||||
import searchConfig from "./config/search";
|
||||
import { options } from './config/config'
|
||||
import printerApi, { type addRequest } from "@/api/account/printer";
|
||||
|
||||
const printTypeList = ref([
|
||||
{
|
||||
label: '前台',
|
||||
values: [],
|
||||
list: [
|
||||
{ label: '客看单', value: 'GUEST_ORDER' },
|
||||
{ label: '预结算单', value: 'PRE_ORDER' },
|
||||
{ label: '结算单', value: 'ORDER' },
|
||||
{ label: '退菜单', value: 'RETURN_ORDER' },
|
||||
{ label: '退款单', value: 'REFUND_ORDER' },
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '后厨',
|
||||
values: [],
|
||||
list: [
|
||||
{ label: '后厨-整单', value: 'ALL_KITCHEN' },
|
||||
{ label: '后厨-分单', value: 'ONLY_KITCHEN' },
|
||||
{ label: '后厨-退菜单', value: 'REFUND_KITCHEN' },
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '其它',
|
||||
values: [],
|
||||
list: [
|
||||
{ label: '交班单', value: 'HANDOVER' },
|
||||
{ label: '排队取号', value: 'CALL' },
|
||||
{ label: '储值单', value: 'RECHARGE' },
|
||||
{ label: '入库单', value: 'STOCK' },
|
||||
{ label: '盘点单', value: 'STOCK_CHECK' },
|
||||
{ label: '商品报表', value: 'PRODUCT_REPORT' },
|
||||
{ label: '经营日报', value: 'DAY_REPORT' },
|
||||
{ label: '日结单', value: 'DAY_ORDER' },
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
const loading = ref(false)
|
||||
const visible = ref(false)
|
||||
const formRef = ref(null)
|
||||
const obj = {
|
||||
id: '',
|
||||
name: '', // 设备名称
|
||||
connectionType: '云打印', // 连接方式 USB、云打印、局域网
|
||||
printType: 'cash', // 打印类型 label标签 cash小票
|
||||
brand: '', // 打印机品牌 飞鹅/云想印
|
||||
address: '', // ip地址/MAC地址
|
||||
port: '', // 端口
|
||||
receiptSize: '58mm', // 小票尺寸 58mm 80mm
|
||||
printNum: 1, // 打印数量
|
||||
printContentType: '', // 打印内容
|
||||
kitchenPrintMode: 'all', // 打印模式(厨房打印菜品) all整单 /only单个
|
||||
classifyPrint: '0', // 分类打印 0-所有 1-部分分类
|
||||
categoryIds: [], // 分类Id
|
||||
status: 1, // 0 禁用 1启用
|
||||
volumeSwitch: 1, // 媒体声音开关 0关1开
|
||||
}
|
||||
const form = ref({ ...obj })
|
||||
|
||||
const rules = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入设备名称',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
brand: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择打印机品牌',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
printNum: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择打印数量',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
// kitchenPrintMode: [
|
||||
// {
|
||||
// required: true,
|
||||
// message: '请选择打印模式',
|
||||
// trigger: 'change'
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
|
||||
function dialogClosed() {
|
||||
formRef.value.resetFields()
|
||||
form.value = { ...obj }
|
||||
}
|
||||
|
||||
const formDivRef = ref(null)
|
||||
async function dialogOpen() {
|
||||
await nextTick()
|
||||
if (formDivRef.value) {
|
||||
// console.log('开始滚动到顶部')
|
||||
formDivRef.value.scrollTop = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 打印类型切换
|
||||
function printTypeChange(e, index, scope) {
|
||||
if (index == 1 && printTypeList.value[index].values.length == 0) {
|
||||
form.value.categoryList = []
|
||||
}
|
||||
|
||||
let arr = []
|
||||
printTypeList.value.forEach(item => {
|
||||
arr.push(...item.values)
|
||||
})
|
||||
|
||||
form.value.printContentType = arr.join(',')
|
||||
}
|
||||
|
||||
function submitHandle() {
|
||||
console.log('submitHandle===', form.value);
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
const data = { ...form.value }
|
||||
data.categoryIds = form.value.categoryIds.join(',')
|
||||
if (form.value.id) {
|
||||
await printerApi.edit(data)
|
||||
} else {
|
||||
await printerApi.add(data)
|
||||
}
|
||||
ElMessage.success(form.value.id ? '编辑成功' : '添加成功')
|
||||
visible.value = false
|
||||
|
||||
handleQueryClick();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 300);
|
||||
})
|
||||
}
|
||||
|
||||
// 更改状态
|
||||
async function statusChange(e, data) {
|
||||
try {
|
||||
await printerApi.edit({
|
||||
id: data.id,
|
||||
status: data.status
|
||||
});
|
||||
handleQueryClick();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
@@ -98,11 +380,11 @@ const {
|
||||
onMounted(() => {
|
||||
getPrinterType();
|
||||
});
|
||||
let PrinterTypeList = ref([])
|
||||
let PrinterTypeList = ref([]);
|
||||
// 获取商品分类
|
||||
async function getPrinterType() {
|
||||
let res = await UserAPI.getPrinterType();
|
||||
PrinterTypeList.value = res.records
|
||||
PrinterTypeList.value = res.records;
|
||||
}
|
||||
function handdeleteevent(item) {
|
||||
ElMessageBox.confirm("确认删除?", "警告", {
|
||||
@@ -114,28 +396,45 @@ function handdeleteevent(item) {
|
||||
ElMessage.success("删除成功");
|
||||
handleQueryClick();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
// 新增
|
||||
async function handleAddClick() {
|
||||
addModalRef.value?.setModalVisible();
|
||||
// addModalRef.value?.setModalVisible();
|
||||
visible.value = true
|
||||
}
|
||||
// 编辑
|
||||
async function handleEditClick(row: IObject) {
|
||||
editModalRef.value?.handleDisabled(false);
|
||||
editModalRef.value?.setModalVisible();
|
||||
// 根据id获取数据进行填充
|
||||
let data = await UserAPI.get(row.id);
|
||||
data.printType = data.printType.split(',');
|
||||
form.value = { ...row }
|
||||
visible.value = true
|
||||
|
||||
if (data.categoryIds) {
|
||||
data.categoryIdsArr = JSON.parse(data.categoryIds)
|
||||
}
|
||||
form.value.categoryIds = form.value.categoryIds.split(',')
|
||||
|
||||
data.classifyPrint = data.classifyPrint * 1;
|
||||
const printContentTypes = row.printContentType.split(',')
|
||||
printTypeList.value.forEach(val => {
|
||||
val.values = _.map(
|
||||
_.filter(val.list, item => printContentTypes.includes(item.value)),
|
||||
'value'
|
||||
);
|
||||
})
|
||||
|
||||
editModalRef.value?.setFormData(data);
|
||||
// editModalRef.value?.handleDisabled(false);
|
||||
// editModalRef.value?.setModalVisible();
|
||||
// // 根据id获取数据进行填充
|
||||
// let data = await UserAPI.get(row.id);
|
||||
// data.printType = data.printType.split(",");
|
||||
|
||||
// if (data.categoryIds) {
|
||||
// data.categoryIdsArr = JSON.parse(data.categoryIds);
|
||||
// } else {
|
||||
// data.categoryIdsArr = [];
|
||||
// }
|
||||
// console.log(data.categoryIdsArr);
|
||||
// console.log(data);
|
||||
|
||||
// data.classifyPrint = data.classifyPrint * 1;
|
||||
|
||||
// editModalRef.value?.setFormData(data);
|
||||
}
|
||||
// 其他工具栏
|
||||
function handleToolbarClick(name: string) {
|
||||
|
||||
@@ -1,5 +1,112 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Index</h1>
|
||||
<div class="gyq_container">
|
||||
<div class="item_wrap">
|
||||
<div class="title">您好,欢迎登录</div>
|
||||
<div class="item_list">
|
||||
<div class="item" v-for="(item, index) in quickStore.quickMenus.splice(0, 6)" :key="item.id"
|
||||
@click="menuClick(item.menuId)">
|
||||
<img class="icon" :src="icons[index + 1]" alt="">
|
||||
{{ returnMenuName(item.menuId) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, nextTick } from "vue";
|
||||
import { useQuickStore, usePermissionStore, useUserStore } from "@/store";
|
||||
|
||||
import icon1 from "@/assets/index_quick1.png";
|
||||
import icon2 from "@/assets/index_quick2.png";
|
||||
import icon3 from "@/assets/index_quick3.png";
|
||||
import icon4 from "@/assets/index_quick4.png";
|
||||
import icon5 from "@/assets/index_quick5.png";
|
||||
import icon6 from "@/assets/index_quick6.png";
|
||||
|
||||
const icons = {
|
||||
1: icon1,
|
||||
2: icon2,
|
||||
3: icon3,
|
||||
4: icon4,
|
||||
5: icon5,
|
||||
6: icon6,
|
||||
};
|
||||
|
||||
const userStore = useUserStore();
|
||||
const quickStore = useQuickStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
|
||||
function returnMenuName(menuId) {
|
||||
return permissionStore.returnMenuName(menuId);
|
||||
}
|
||||
|
||||
function menuClick(menuId) {
|
||||
permissionStore.menuJump(menuId);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
console.log('quickStore.quickMenus', quickStore.quickMenus);
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.gyq_container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('@/assets/index_bg.png') no-repeat center center / cover;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.item_wrap {
|
||||
padding-left: 300px;
|
||||
|
||||
.title {
|
||||
font-size: 40px;
|
||||
margin-bottom: 50px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item_list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
grid-column-gap: 90px;
|
||||
grid-row-gap: 90px;
|
||||
|
||||
.item {
|
||||
width: 152px;
|
||||
height: 83px;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(115deg, #9EC4FF 5.9%, #6668E8 111.62%);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
padding-left: 30px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
left: -30px;
|
||||
top: -20px;
|
||||
width: 83px;
|
||||
height: 78px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -74,12 +74,19 @@ const accountList = reactive([
|
||||
{ username: "19107220837", type: 'danger', label: '快乐时光店铺' },
|
||||
// { username: "18199991111", type: 'success', label: '草莓加盟主店可直接管理' },
|
||||
{ username: "18821670757", type: 'success', label: '高歌的小店' },
|
||||
{ username: "18821670757", staffUserName: '18821670758', type: 'primary', label: '高歌的小店的员工-张三' },
|
||||
{ username: "191123456", type: 'primary', label: '酸橘子' },
|
||||
]);
|
||||
|
||||
// 快捷模拟登录
|
||||
function accountHandle(item) {
|
||||
state.loginForm.username = item.username;
|
||||
if (item.staffUserName) {
|
||||
state.loginForm.loginType = 1
|
||||
state.loginForm.staffUserName = item.staffUserName
|
||||
} else {
|
||||
state.loginForm.loginType = 0
|
||||
}
|
||||
state.loginForm.code = 666666
|
||||
const d = new Date();
|
||||
state.loginForm.password = `czg${d.getHours().toString().padStart(2, '0')}${d.getMinutes().toString().padStart(2, '0')}`;
|
||||
@@ -191,6 +198,12 @@ function handleLogin() {
|
||||
userStore
|
||||
.login(user)
|
||||
.then(async (res) => {
|
||||
|
||||
console.log('login===', res);
|
||||
|
||||
localStorage.setItem('shopStaff', JSON.stringify(res.shopStaff))
|
||||
|
||||
|
||||
const token = getToken();
|
||||
console.log("token", token);
|
||||
$douyin_checkIn({
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, nextTick } from 'vue'
|
||||
import { ref, onMounted, nextTick, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
// {label: '设置',value: 1}
|
||||
@@ -29,10 +29,8 @@ const modelValue = defineModel('modelValue', {
|
||||
required: true
|
||||
})
|
||||
|
||||
// 改变索引
|
||||
function changeHandle(index) {
|
||||
modelValue.value = index
|
||||
|
||||
// 更新active_wrap位置
|
||||
function updateActivePosition(index) {
|
||||
let left = 0
|
||||
itemsWidth.value.forEach((val, i) => {
|
||||
if (i < index) {
|
||||
@@ -40,7 +38,12 @@ function changeHandle(index) {
|
||||
}
|
||||
})
|
||||
leftValue.value = left + gap.value * index
|
||||
}
|
||||
|
||||
// 改变索引
|
||||
function changeHandle(index) {
|
||||
modelValue.value = index
|
||||
updateActivePosition(index)
|
||||
emits('change', index)
|
||||
}
|
||||
|
||||
@@ -57,10 +60,14 @@ onMounted(() => {
|
||||
console.log('itemRefs===', itemRefs.value);
|
||||
console.log('itemsWidth===', itemsWidth.value);
|
||||
|
||||
|
||||
changeHandle(modelValue.value)
|
||||
updateActivePosition(modelValue.value)
|
||||
})
|
||||
})
|
||||
|
||||
// 监听modelValue变化,更新位置
|
||||
watch(modelValue, (newVal) => {
|
||||
updateActivePosition(newVal)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<el-form-item label="获得佣金条件" prop="inviteCount">
|
||||
<div class="column">
|
||||
<el-input v-model="form.inviteCount" placeholder="请输入" :maxlength="8" style="width: 300px;"
|
||||
@input="e => form.inviteCount = filterNumberInput(e, 1)">
|
||||
@input="e => form.inviteCount = filterNumberInput(e, 0)">
|
||||
<template #append>人</template>
|
||||
</el-input>
|
||||
<div class="tips">邀请达到指定人数才可赚取佣金</div>
|
||||
@@ -202,7 +202,7 @@ const formRef = ref(null)
|
||||
const formLoading = ref(false)
|
||||
const levelConfigListObj = ref({
|
||||
name: '', // 名称
|
||||
inviteCount: '', // 有效人数
|
||||
inviteCount: 0, // 有效人数
|
||||
costAmount: '', // 消费金额
|
||||
commission: '', // 一级分销比例
|
||||
levelTwoCommission: '', // 二级分销比例
|
||||
@@ -210,7 +210,7 @@ const levelConfigListObj = ref({
|
||||
const form = ref({
|
||||
id: '',
|
||||
openType: 'pay', // pay购买开通 auto自动开通 manual手动开通
|
||||
inviteCount: '', // 邀请条件人数
|
||||
inviteCount: 0, // 邀请条件人数
|
||||
inviteConsume: 0, // 被邀请人消费有效 0 1
|
||||
payAmount: '', // 购买开通金额
|
||||
rewardCount: '', // 每人奖励次数
|
||||
|
||||
@@ -93,13 +93,8 @@
|
||||
<div>
|
||||
实收金额:
|
||||
<span style="color: red">¥{{ detail.payAmount }}</span>
|
||||
<el-button
|
||||
v-if="detail.status != 'unpaid' && detail.refundAmount < detail.payAmount"
|
||||
size="small"
|
||||
type="danger"
|
||||
class="u-m-l-10"
|
||||
@click="tuikuan()"
|
||||
>
|
||||
<el-button v-if="detail.status != 'unpaid' && detail.refundAmount < detail.payAmount" size="small"
|
||||
type="danger" class="u-m-l-10" @click="tuikuan()">
|
||||
<span>退款</span>
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -116,7 +111,11 @@
|
||||
退款详情>
|
||||
</span> -->
|
||||
</div>
|
||||
<div class="color-red">退款方式:{{ detail.refundType }}</div>
|
||||
<div class="color-red">
|
||||
<span v-if="detail.refundType">
|
||||
退款方式:{{ detail.refundType === "cash" ? "现金退款" : "原路退回" }}
|
||||
</span>
|
||||
</div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
@@ -126,35 +125,22 @@
|
||||
<div style="margin-bottom: 16px; font-size: 16px">商品信息</div>
|
||||
<template v-for="(item, index) in detail.detailMap" :key="index">
|
||||
<h4>第{{ index }}次下单</h4>
|
||||
<el-table
|
||||
:data="item"
|
||||
:ref="'refTable' + index"
|
||||
@select-all="tableSelectAll($event, index)"
|
||||
>
|
||||
<el-table :data="item" :ref="'refTable' + index" @select-all="tableSelectAll($event, index)">
|
||||
<!-- <el-table-column type="selection" width="55" /> -->
|
||||
<el-table-column label="数量" type="selection">
|
||||
<template v-slot="scope">
|
||||
<div v-if="detail.status == 'unpaid'">
|
||||
<el-checkbox
|
||||
v-if="scope.row.num - scope.row.returnNum > 0"
|
||||
v-model="scope.row.checked"
|
||||
/>
|
||||
<el-checkbox v-if="scope.row.num - scope.row.returnNum > 0" v-model="scope.row.checked" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-checkbox
|
||||
v-if="scope.row.num - scope.row.refundNum > 0"
|
||||
v-model="scope.row.checked"
|
||||
/>
|
||||
<el-checkbox v-if="scope.row.num - scope.row.refundNum > 0" v-model="scope.row.checked" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品" width="150">
|
||||
<template v-slot="scope">
|
||||
<div class="shop_info">
|
||||
<el-image
|
||||
:src="scope.row.productImg"
|
||||
style="width: 40px; height: 40px"
|
||||
></el-image>
|
||||
<el-image :src="scope.row.productImg" style="width: 40px; height: 40px"></el-image>
|
||||
<div class="info">
|
||||
<span :class="[scope.row.isVip == 1 ? 'colorStyle' : '']">
|
||||
{{ scope.row.productName }}
|
||||
@@ -187,32 +173,17 @@
|
||||
<el-table-column label="实付">
|
||||
<template v-slot="scope">¥{{ scope.row.payAmount }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="detail.status == 'unpaid'"
|
||||
label="可退菜数量"
|
||||
align="center"
|
||||
width="130px"
|
||||
>
|
||||
<el-table-column v-if="detail.status == 'unpaid'" label="可退菜数量" align="center" width="130px">
|
||||
<template v-slot="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.checked"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
v-model="scope.row.selNumber"
|
||||
:max="scope.row.num - scope.row.returnNum"
|
||||
></el-input-number>
|
||||
<el-input-number v-if="scope.row.checked" :min="0" style="width: 100px" v-model="scope.row.selNumber"
|
||||
:max="scope.row.num - scope.row.returnNum"></el-input-number>
|
||||
<span class="" v-else>{{ scope.row.num - scope.row.returnNum }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-else label="可退款数量" align="center" width="130px">
|
||||
<template v-slot="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.checked"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
v-model="scope.row.selNumber"
|
||||
:max="scope.row.num - scope.row.refundNum - scope.row.returnNum"
|
||||
></el-input-number>
|
||||
<el-input-number v-if="scope.row.checked" :min="0" style="width: 100px" v-model="scope.row.selNumber"
|
||||
:max="scope.row.num - scope.row.refundNum - scope.row.returnNum"></el-input-number>
|
||||
<span class="" v-else>
|
||||
{{ scope.row.num - scope.row.refundNum - scope.row.returnNum }}
|
||||
</span>
|
||||
@@ -227,23 +198,13 @@
|
||||
<el-table-column label="操作" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<template v-if="detail.status != 'unpaid'">
|
||||
<el-button
|
||||
v-if="canTuikuan(scope.row)"
|
||||
link
|
||||
size="small"
|
||||
@click="tuikuan(scope.row)"
|
||||
>
|
||||
<el-button v-if="canTuikuan(scope.row)" link size="small" @click="tuikuan(scope.row)">
|
||||
<span>退款</span>
|
||||
</el-button>
|
||||
<span class="color-999" v-if="scope.row.status == 'refund'">已退款</span>
|
||||
</template>
|
||||
<template v-if="detail.status == 'unpaid'">
|
||||
<el-button
|
||||
v-if="canTuicai(scope.row)"
|
||||
link
|
||||
size="small"
|
||||
@click="tuicai(scope.row)"
|
||||
>
|
||||
<el-button v-if="canTuicai(scope.row)" link size="small" @click="tuicai(scope.row)">
|
||||
<span>退菜</span>
|
||||
</el-button>
|
||||
<span class="color-999" v-else>已退菜</span>
|
||||
@@ -253,41 +214,25 @@
|
||||
</el-table>
|
||||
</template>
|
||||
<!-- 退款 -->
|
||||
<div
|
||||
class="u-p-20 u-flex u-row-right"
|
||||
v-if="
|
||||
detail.status !== 'refund' &&
|
||||
detail.status !== 'unpaid' &&
|
||||
detail.status !== 'cancelled'
|
||||
"
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="allSelected"
|
||||
@change="allSelectedChange"
|
||||
label="全选"
|
||||
></el-checkbox>
|
||||
<div class="u-p-20 u-flex u-row-right" v-if="
|
||||
detail.status !== 'refund' &&
|
||||
detail.status !== 'unpaid' &&
|
||||
detail.status !== 'cancelled'
|
||||
">
|
||||
<el-checkbox v-model="allSelected" @change="allSelectedChange" label="全选"></el-checkbox>
|
||||
<el-button type="danger" class="u-m-l-20" @click.stop="tuikuan('all')">退款</el-button>
|
||||
</div>
|
||||
<!-- 退菜 -->
|
||||
<div class="u-p-20 u-flex u-row-right" v-if="detail.status == 'unpaid'">
|
||||
<el-checkbox
|
||||
v-model="allSelected"
|
||||
@change="allSelectedChange"
|
||||
label="全选"
|
||||
></el-checkbox>
|
||||
<el-checkbox v-model="allSelected" @change="allSelectedChange" label="全选"></el-checkbox>
|
||||
<el-button type="danger" class="u-m-l-20" @click.stop="tuicai('all')">退菜</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<!-- 退款 -->
|
||||
<return-money
|
||||
:modal="false"
|
||||
ref="refReturnMoney"
|
||||
:max="selGoods.num"
|
||||
:goods="selGoods"
|
||||
@confirm="refReturnMoneyConfirm"
|
||||
></return-money>
|
||||
<return-money :modal="false" ref="refReturnMoney" :max="selGoods.num" :goods="selGoods"
|
||||
@confirm="refReturnMoneyConfirm"></return-money>
|
||||
<!-- 退菜 -->
|
||||
<order-return-cart ref="refReturnCart" @confirm="refReturnCartConfirm"></order-return-cart>
|
||||
</div>
|
||||
@@ -462,6 +407,12 @@ export default {
|
||||
},
|
||||
tuikuan(item) {
|
||||
if (!item) {
|
||||
let arrs = []
|
||||
for (let i in this.detail.detailMap) {
|
||||
this.detail.detailMap[i].map((v) => {
|
||||
arrs.push(v);
|
||||
});
|
||||
}
|
||||
this.$refs.refReturnMoney.open([], this.detail);
|
||||
return;
|
||||
}
|
||||
@@ -480,6 +431,9 @@ export default {
|
||||
if (arr.length == 0) {
|
||||
return ElMessage.error("请选择要退款的商品和数量");
|
||||
}
|
||||
|
||||
console.log('tuikuan===', arr);
|
||||
|
||||
this.$refs.refReturnMoney.open(arr, this.detail);
|
||||
},
|
||||
tuicai(item) {
|
||||
@@ -498,7 +452,7 @@ export default {
|
||||
if (arr.length == 0) {
|
||||
return ElMessage.error("请选择要退菜的商品和数量");
|
||||
}
|
||||
console.log(arr);
|
||||
console.log('tuicai===', arr);
|
||||
this.$refs.refReturnCart.open(arr, this.detail);
|
||||
},
|
||||
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
<div class="u-flex u-col-top" v-if="goodsList && goodsList.length">
|
||||
<span class="u-m-0">退款商品</span>
|
||||
<div class="u-p-l-20 goods-list">
|
||||
<div
|
||||
class="u-flex u-font-12 goods-list-item"
|
||||
v-for="(goods, index) in goodsList"
|
||||
:key="index"
|
||||
>
|
||||
<div class="u-flex u-font-12 goods-list-item" v-for="(goods, index) in goodsList" :key="index">
|
||||
<span class="">
|
||||
{{ goods.productName }}
|
||||
</span>
|
||||
@@ -35,12 +31,7 @@
|
||||
<div class="flex u-row-between">
|
||||
<span class="color-red">退款金额</span>
|
||||
<div class="u-flex u-flex-1 u-p-l-20">
|
||||
<el-input-number
|
||||
type="number"
|
||||
v-model="number"
|
||||
:min="min"
|
||||
:max="canReturnMoney"
|
||||
></el-input-number>
|
||||
<el-input-number type="number" v-model="number" :min="min" :max="canReturnMoney"></el-input-number>
|
||||
<span class="u-m-l-10">可退{{ canReturnMoney }}元</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,13 +64,8 @@
|
||||
</div>
|
||||
|
||||
<div class="u-flex u-flex-wrap tags">
|
||||
<div
|
||||
class="tag"
|
||||
v-for="(tag, index) in tags"
|
||||
@click="changeSel(tag)"
|
||||
:key="index"
|
||||
:class="{ active: tag.checked }"
|
||||
>
|
||||
<div class="tag" v-for="(tag, index) in tags" @click="changeSel(tag)" :key="index"
|
||||
:class="{ active: tag.checked }">
|
||||
{{ tag.label }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,16 +80,22 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
<safe-password ref="refPassword" @confirm="pwdConfirm"></safe-password>
|
||||
<!-- 退款退菜推库存的操作弹窗 -->
|
||||
<refundConsModal ref="refundConsModalRef" :list="refundList" @success="refundConsModalSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script>
|
||||
import { ElMessage } from "element-plus";
|
||||
import safePassword from "./password.vue";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useCartsStore } from "@/store/modules/carts";
|
||||
import categoryApi from "@/api/product/productclassification";
|
||||
import refundConsModal from "@/components/refundConsModal.vue";
|
||||
const shopUser = useUserStore();
|
||||
export default {
|
||||
components: {
|
||||
safePassword,
|
||||
refundConsModal
|
||||
},
|
||||
props: {
|
||||
modal: {
|
||||
@@ -135,6 +127,8 @@ export default {
|
||||
goods: {
|
||||
productId: -999,
|
||||
},
|
||||
refundList: [],
|
||||
refundStock: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -196,18 +190,26 @@ export default {
|
||||
.join(",");
|
||||
const note = selTag + (this.note.length > 0 ? "," + this.note : "");
|
||||
console.log(note);
|
||||
this.$emit("confirm", {
|
||||
|
||||
const data = {
|
||||
refundAmount: this.number,
|
||||
cash: this.cash,
|
||||
refundReason: note,
|
||||
refundDetails: this.goodsList.map((v) => {
|
||||
return { id: v.id, num: v.num };
|
||||
return { id: v.id, num: v.selNumber };
|
||||
}),
|
||||
...e,
|
||||
});
|
||||
refundStock: this.refundStock
|
||||
}
|
||||
this.$emit("confirm", data);
|
||||
this.close();
|
||||
},
|
||||
confirm() {
|
||||
// 退款推库存的操作
|
||||
refundConsModalSuccess(e) {
|
||||
this.refundStock = e
|
||||
this.emitTuikuan()
|
||||
},
|
||||
async confirm() {
|
||||
const selTag = this.tags
|
||||
.filter((item) => item.checked)
|
||||
.map((item) => item.label)
|
||||
@@ -220,14 +222,58 @@ export default {
|
||||
this.$refs.refPassword.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// 在这里给订单的商品补全库存信息 start
|
||||
const carts = useCartsStore();
|
||||
let categorys = JSON.parse(localStorage.getItem('categorys'))
|
||||
let shopInfo = JSON.parse(localStorage.getItem('userInfo'))
|
||||
|
||||
if (!categorys) {
|
||||
categorys = await categoryApi.getList({})
|
||||
}
|
||||
|
||||
this.goodsList.forEach(item => {
|
||||
carts.goods.forEach(val => {
|
||||
if (item.productId == val.id) {
|
||||
if (shopInfo.refundMode == 1) {
|
||||
// 跟随分类退款模式
|
||||
categorys.forEach(v => {
|
||||
if (val.categoryId == v.id) {
|
||||
item.refundMode = v.refundMode
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 跟随商品退款模式及
|
||||
item.refundMode = val.refundMode
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
console.log('this.goodsList===', this.goodsList);
|
||||
// 在这里给订单的商品补全库存信息 end
|
||||
|
||||
this.goodsList.forEach(item => {
|
||||
if (item.refundMode == 3) {
|
||||
this.refundList.push({
|
||||
name: item.productName,
|
||||
num: item.selNumber
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (this.refundList.length > 0) {
|
||||
this.$refs.refundConsModalRef.show()
|
||||
return
|
||||
}
|
||||
|
||||
this.emitTuikuan();
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() { },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-tag) {
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
@@ -237,6 +283,7 @@ export default {
|
||||
line-height: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
.tag {
|
||||
margin: 10px 10px 0 0;
|
||||
@@ -246,6 +293,7 @@ export default {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: #1890ff;
|
||||
background: #e8f4ff;
|
||||
@@ -253,14 +301,17 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.number-box .el-input__inner::-webkit-inner-spin-button) {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.number-box .el-input__inner::-webkit-outer-spin-button) {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.goods-list-item {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
@@ -268,6 +319,7 @@ export default {
|
||||
border-radius: 3px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.goods-list-item:not(:first-child) {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
|
||||
<template #refundMode="scope">
|
||||
<!-- <el-switch v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
@click="isRefundStockChange($event, scope)" /> -->
|
||||
<el-text>{{ returnLabel(scope.row[scope.prop]) }}</el-text>
|
||||
</template>
|
||||
<template #slotNameimage="scope">
|
||||
<el-image v-if="scope.row.pic" :src="scope.row.pic" lazy style="width: 40px; height: 40px" />
|
||||
<div v-else>无</div>
|
||||
@@ -68,6 +72,17 @@ import editModalConfig from "./categoryconfig/edit";
|
||||
import searchConfig from "./categoryconfig/search";
|
||||
import { isSyncStatus, downloadFile } from "@/utils/index";
|
||||
|
||||
const options = ref([
|
||||
{ label: "退菜退库存", value: 1 },
|
||||
{ label: "仅退菜不退库存", value: 2 },
|
||||
{ label: "每次询问-退菜后弹窗提示,可手动选择", value: 3 },
|
||||
])
|
||||
|
||||
function returnLabel(value: number) {
|
||||
const option = options.value.find((option) => option.value === value);
|
||||
return option ? option.label : "未知";
|
||||
}
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
contentRef,
|
||||
@@ -106,6 +121,16 @@ async function handleExportClick() {
|
||||
}
|
||||
}
|
||||
|
||||
// 退菜是否退库存开关切换
|
||||
async function isRefundStockChange(e: any, scope: any) {
|
||||
try {
|
||||
await UserAPI.update(scope.row);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage.error("操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 新增
|
||||
async function handleAddClick() {
|
||||
addModalRef.value?.setModalVisible();
|
||||
|
||||
@@ -10,7 +10,7 @@ const modalConfig: IModalConfig<UserForm> = {
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 100,
|
||||
labelWidth: 120,
|
||||
},
|
||||
formAction: UserAPI.addunit,
|
||||
beforeSubmit(data) {
|
||||
@@ -31,6 +31,26 @@ const modalConfig: IModalConfig<UserForm> = {
|
||||
prop: "pic",
|
||||
type: "UpImage",
|
||||
},
|
||||
{
|
||||
label: '退菜是否退库存',
|
||||
prop: 'refundMode',
|
||||
type: 'radio',
|
||||
options: [
|
||||
{ label: "退菜退库存", value: 1 },
|
||||
{ label: "仅退菜不退库存", value: 2 },
|
||||
{ label: "每次询问-退菜后弹窗提示,可手动选择", value: 3 },
|
||||
],
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
type: "input-number",
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "开关",
|
||||
prop: "status",
|
||||
@@ -44,15 +64,6 @@ const modalConfig: IModalConfig<UserForm> = {
|
||||
inactiveValue: 0,
|
||||
},
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
type: "input-number",
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 1,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
@@ -77,6 +77,13 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
templet: "switch",
|
||||
slotName: "status",
|
||||
},
|
||||
{
|
||||
label: "退菜是否退库存",
|
||||
align: "center",
|
||||
prop: "refundMode",
|
||||
templet: "custom",
|
||||
slotName: "refundMode",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
align: "center",
|
||||
|
||||
@@ -35,6 +35,26 @@ const modalConfig: IModalConfig<UserForm> = {
|
||||
prop: "pic",
|
||||
type: "UpImage",
|
||||
},
|
||||
{
|
||||
label: '退菜是否退库存',
|
||||
prop: 'refundMode',
|
||||
type: 'radio',
|
||||
options: [
|
||||
{ label: "退菜退库存", value: 1 },
|
||||
{ label: "仅退菜不退库存", value: 2 },
|
||||
{ label: "每次询问-退菜后弹窗提示,可手动选择", value: 3 },
|
||||
],
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
type: "input-number",
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "开关",
|
||||
prop: "status",
|
||||
@@ -48,15 +68,6 @@ const modalConfig: IModalConfig<UserForm> = {
|
||||
inactiveValue: 0,
|
||||
},
|
||||
initialValue: 1,
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
type: "input-number",
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 1,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<page-search ref="searchRef" :search-config="searchConfig" @query-click="newHandleQueryClick"
|
||||
@reset-click="handleResetClick2" />
|
||||
<!-- 顶部数据 -->
|
||||
<Statistics :data="gongjiData"></Statistics>
|
||||
<!-- <Statistics :data="gongjiData"></Statistics> -->
|
||||
<!-- 列表 -->
|
||||
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
|
||||
@edit-click="handleEditClick" @export-click="handleExportClick" @search-click="handleSearchClick"
|
||||
@@ -15,6 +15,9 @@
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template> -->
|
||||
<template #custom>
|
||||
<importData :type="3" @close="newHandleQueryClick" />
|
||||
</template>
|
||||
<template #type="scope">
|
||||
{{ typeFilter(scope.row[scope.prop]) }}
|
||||
</template>
|
||||
@@ -26,7 +29,8 @@
|
||||
@click="handleSwitchChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
<template #isStock="scope">
|
||||
<el-switch disabled v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"></el-switch>
|
||||
<el-switch v-if="!scope.row.productId" v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
:disabled="!scope.row.type" @click="isStockChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
|
||||
<template #kucunedit="scope">
|
||||
@@ -39,13 +43,18 @@
|
||||
</template>
|
||||
|
||||
<template #tuikuantuihui="scope">
|
||||
<el-switch v-if="!scope.row.productId" v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
@click="handleSwitchhaocai(scope.row)"></el-switch>
|
||||
<!-- <el-switch v-if="!scope.row.productId" v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
@click="handleSwitchhaocai(scope.row)"></el-switch> -->
|
||||
<el-text>{{ returnLabel(scope.row[scope.prop]) }}</el-text>
|
||||
</template>
|
||||
<template #sellOut="scope">
|
||||
<el-switch v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
@click="handleSwitchChangeTwo(scope.row)"></el-switch>
|
||||
</template>
|
||||
<template #autoSellOut="scope">
|
||||
<el-switch v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
|
||||
@click="handleSwitchChangeTwo2($event, scope.row)"></el-switch>
|
||||
</template>
|
||||
<template #mobile="scope">
|
||||
<el-text>{{ scope.row[scope.prop] }}</el-text>
|
||||
<copy-button v-if="scope.row[scope.prop]" :text="scope.row[scope.prop]" style="margin-left: 2px" />
|
||||
@@ -92,7 +101,7 @@
|
||||
<el-input-number v-model="datas.number" :min="1" label="描述文字"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="报损照片" label-width="">
|
||||
<MultiImageUpload v-model="datas.images" />
|
||||
<MultiImageUpload v-model="datas.imgUrls" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" label-width="">
|
||||
<el-input v-model="datas.remark" type="textarea" />
|
||||
@@ -118,9 +127,10 @@
|
||||
<el-table-column label="序号" type="index" width="60"></el-table-column>
|
||||
<el-table-column label="耗材名称" prop="consInfoId">
|
||||
<template v-slot="scope">
|
||||
<el-select v-model="scope.row.consInfoId" reserve-keyword placeholder="请输入关键词"
|
||||
<el-select filterable v-model="scope.row.consInfoId" reserve-keyword placeholder="请输入关键词"
|
||||
@change="selectionChange($event, scope.row)">
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.conName" :value="item.id"></el-option>
|
||||
<el-option v-for="item in options" :key="item.id * 1" :label="item.conName"
|
||||
:value="item.id * 1"></el-option>
|
||||
</el-select>
|
||||
<!-- <div class="tips" v-if="scope.row.stockNumber">库存:{{ scope.row.stockNumber }}</div> -->
|
||||
</template>
|
||||
@@ -166,10 +176,24 @@
|
||||
<MyDialog ref="myDialogRefkucun" @confirm="confirmkucun" width="30%" title="库存修改">
|
||||
<el-input-number v-model="kucundata.stockNumbers" :min="0" />
|
||||
</MyDialog>
|
||||
<!-- 报损记录 -->
|
||||
<MyDialog ref="myDialogRefRecord" :title="dataAll.dataTitle" width="70%" @confirm="myDialogRefRecord.close()">
|
||||
<!-- 表格 -->
|
||||
<Table :list="dataAll.tableData"
|
||||
v-if="dataAll.dataType == 'inSumTotal' || dataAll.dataType == 'winInNum' || dataAll.dataType == 'outSumTotal' || dataAll.dataType == 'lossOutNum'">
|
||||
</Table>
|
||||
<TableTwo :list="dataAll.tableData" v-else-if="dataAll.dataType == 'refundInNum'"></TableTwo>
|
||||
<TableThree :list="dataAll.tableData" v-else-if="dataAll.dataType == 'salesNum'"></TableThree>
|
||||
|
||||
<TableFour :list="dataAll.tableData" v-else-if="dataAll.dataType == 'damageNum'"></TableFour>
|
||||
<!-- 分页 -->
|
||||
<Paging :pagingConfig="dataAll.pagingConfig" @sizeChange="sizeChange" @currentChange="currentChange"></Paging>
|
||||
</MyDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import UserAPI from "@/api/product/index";
|
||||
import { useRouter } from "vue-router";
|
||||
import type { IObject, IOperatData } from "@/components/CURD/types";
|
||||
@@ -183,6 +207,91 @@ import editModalConfig from "./indexconfig/edit";
|
||||
import searchConfig from "./indexconfig/search";
|
||||
import MyDialog from "@/components/mycomponents/myDialog.vue";
|
||||
import Statistics from "./indexconfig/statistics.vue";
|
||||
import TableFour from './indexconfig/TableFour.vue'
|
||||
|
||||
const myDialogRefRecord = ref(null)
|
||||
|
||||
const refoundModeOptions = ref([
|
||||
{ label: "退菜退库存", value: 1 },
|
||||
{ label: "仅退菜不退库存", value: 2 },
|
||||
{ label: "每次询问-退菜后弹窗提示,可手动选择", value: 3 },
|
||||
])
|
||||
|
||||
function returnLabel(value: number) {
|
||||
const option = refoundModeOptions.value.find((option) => option.value == value);
|
||||
return option ? option.label : "未知";
|
||||
}
|
||||
|
||||
let dataAll = reactive({
|
||||
dataList: [],
|
||||
tableData: [],
|
||||
pagingConfig: {
|
||||
total: 0, // 总数
|
||||
pageSize: 10, // 每页数据数量
|
||||
pageNumber: 1, // 当前页码
|
||||
},
|
||||
dataType: "",
|
||||
dataTitle: ""
|
||||
});
|
||||
|
||||
function sizeChange(val) {
|
||||
dataAll.pagingConfig.pageSize = val
|
||||
clickEvent(dataAll.dataType)
|
||||
}
|
||||
function currentChange(val) {
|
||||
dataAll.pagingConfig.pageNumber = val
|
||||
clickEvent(dataAll.dataType)
|
||||
}
|
||||
|
||||
async function clickEvent(key) {
|
||||
dataAll.dataType = key
|
||||
let obj = {}
|
||||
switch (key) {
|
||||
case 'inSumTotal':
|
||||
dataAll.dataTitle = '增加数据统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "in", inOutItem: "" }
|
||||
break;
|
||||
case 'winInNum':
|
||||
dataAll.dataTitle = '手动增加统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "in", inOutItem: "win-in" }
|
||||
break;
|
||||
case 'refundInNum':
|
||||
dataAll.dataTitle = '退货统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "in", inOutItem: "order-in" }
|
||||
break;
|
||||
case 'outSumTotal':
|
||||
dataAll.dataTitle = '减少数量统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "out", inOutItem: "" }
|
||||
break;
|
||||
case 'lossOutNum':
|
||||
dataAll.dataTitle = '手动减少统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "out", inOutItem: "loss-out" }
|
||||
break;
|
||||
case 'salesNum':
|
||||
dataAll.dataTitle = '销量统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: "", inOutType: "out", inOutItem: "order-out" }
|
||||
break;
|
||||
case 'damageNum':
|
||||
dataAll.dataTitle = '报损统计'
|
||||
obj = { page: dataAll.pagingConfig.pageNumber, size: dataAll.pagingConfig.pageSize, productId: datas.productId, inOutType: "out", inOutItem: "damage-out" }
|
||||
break;
|
||||
}
|
||||
dataAll.tableData = []
|
||||
|
||||
let res = await UserAPI.stockFlow(obj);
|
||||
dataAll.tableData = res.records
|
||||
dataAll.tableData.forEach((item, index) => {
|
||||
if (item.imgUrls.length > 7) {
|
||||
item.imagesone = JSON.parse(item.imgUrls)[0]
|
||||
}
|
||||
})
|
||||
dataAll.pagingConfig.total = res.totalRow
|
||||
dataAll.pagingConfig.pageSize = res.pageSize
|
||||
dataAll.pagingConfig.pageNumber = res.pageNumber
|
||||
myDialogRefRecord.value.open()
|
||||
}
|
||||
|
||||
const importDataRef = ref(null);
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
@@ -227,7 +336,7 @@ const form = reactive({
|
||||
let datas = reactive({
|
||||
number: 0,
|
||||
remark: "",
|
||||
images: [],
|
||||
imgUrls: [],
|
||||
productId: null, // Added productId property
|
||||
});
|
||||
|
||||
@@ -249,8 +358,8 @@ onMounted(async () => {
|
||||
// 获取耗材列表
|
||||
gethaocaiList();
|
||||
|
||||
const res = await UserAPI.getPage()
|
||||
form.warnLine = res.warnLine || ''
|
||||
const res = await UserAPI.getPage();
|
||||
form.warnLine = res.warnLine || "";
|
||||
// console.log('contentRef.value===', res);
|
||||
});
|
||||
|
||||
@@ -302,6 +411,11 @@ function getTongji(params: IObject | undefined) {
|
||||
});
|
||||
}
|
||||
|
||||
// 显示批量导入
|
||||
function handleUploadClick() {
|
||||
importDataRef.value.show();
|
||||
}
|
||||
|
||||
// 导出商品
|
||||
async function handleExportClick() {
|
||||
try {
|
||||
@@ -331,13 +445,25 @@ function createItem(val: IObject) {
|
||||
haocaiData.value.consList.push(item);
|
||||
}
|
||||
// 上架
|
||||
function handleSwitchChange(data: any) {
|
||||
async function handleSwitchChange(data: any) {
|
||||
console.log(data);
|
||||
let obj = {
|
||||
type: data.productId ? "sku" : "product",
|
||||
id: data.id,
|
||||
isSale: data.isSale,
|
||||
};
|
||||
UserAPI.onOff(obj);
|
||||
await UserAPI.onOff(obj);
|
||||
ElMessage.success("修改成功!");
|
||||
|
||||
if (data.productId) {
|
||||
//sku
|
||||
contentRef.value?.fetchPageData();
|
||||
} else {
|
||||
//product
|
||||
data.skuList.map((v) => {
|
||||
v.isSale = data.isSale;
|
||||
});
|
||||
}
|
||||
}
|
||||
// 售罄
|
||||
function handleSwitchChangeTwo(data: any) {
|
||||
@@ -347,7 +473,18 @@ function handleSwitchChangeTwo(data: any) {
|
||||
isSoldOut: data.isSoldStock,
|
||||
};
|
||||
UserAPI.markIsSoldOut(obj);
|
||||
ElMessage.success("修改成功!");
|
||||
}
|
||||
|
||||
// 自动售罄
|
||||
function handleSwitchChangeTwo2(e: any, data: any) {
|
||||
UserAPI.markIsAutoSoldOut({
|
||||
id: data.id,
|
||||
isAutoSoldStock: data.isAutoSoldStock
|
||||
});
|
||||
ElMessage.success("修改成功!");
|
||||
}
|
||||
|
||||
function handleSwitchChangethree(data: any) {
|
||||
let obj = {
|
||||
type: data.type == "sku" ? "sku" : "product",
|
||||
@@ -357,6 +494,18 @@ function handleSwitchChangethree(data: any) {
|
||||
UserAPI.markIsSoldOut(obj);
|
||||
}
|
||||
|
||||
async function isStockChange(data: any) {
|
||||
console.log(data);
|
||||
let obj = {
|
||||
type: "product",
|
||||
id: data.id,
|
||||
isSale: data.isStock,
|
||||
optType: "stock",
|
||||
};
|
||||
await UserAPI.onOff(obj);
|
||||
ElMessage.success("修改成功!");
|
||||
return;
|
||||
}
|
||||
// 退款退回
|
||||
async function handleSwitchhaocai(row: IObject) {
|
||||
let res = await UserAPI.refundToStock({ isReturn: row.isRefundStock, id: row.id });
|
||||
@@ -386,6 +535,9 @@ async function handleToolbarClick(name: string) {
|
||||
let res = await UserAPI.sync();
|
||||
ElMessage.success("操作成功,数据正在后台同步中...");
|
||||
}
|
||||
if (name === "upload") {
|
||||
importDataRef.value.show();
|
||||
}
|
||||
}
|
||||
async function confirm() {
|
||||
let res = await UserAPI.stockWarning(form.warnLine);
|
||||
@@ -430,15 +582,26 @@ function typeFilter(item: any) {
|
||||
}
|
||||
// 其他操作列
|
||||
async function handleOperatClick(data: IOperatData) {
|
||||
console.log(data);
|
||||
datas.productId = data.row.id;
|
||||
myDialogRefbaosun.value.open();
|
||||
datas.number = 1;
|
||||
datas.remark = "";
|
||||
switch (data.name) {
|
||||
case 'cons':
|
||||
myDialogRefbaosun.value.open();
|
||||
datas.number = 1;
|
||||
datas.remark = "";
|
||||
break;
|
||||
case 'consRecord':
|
||||
clickEvent('damageNum')
|
||||
// myDialogRefRecord.value.open()
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function gethaocaiList() {
|
||||
let res = await UserAPI.productcons({ id: route.query.id });
|
||||
options.value = res.records;
|
||||
let res = await UserAPI.productconsList({ id: route.query.id });
|
||||
options.value = res || [];
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div style="margin-top: 10px;">
|
||||
<el-table :data="props.list" border style="">
|
||||
<el-table-column prop="productName" align="center" label="商品名称/规格名称" />
|
||||
<el-table-column prop="beforeNumber" align="center" label="原库存" />
|
||||
<el-table-column prop="afterNumber" align="center" label="变动后库存" />
|
||||
<!-- <el-table-column prop="beforeNumber" align="center" label="原库存" />
|
||||
<el-table-column prop="afterNumber" align="center" label="变动后库存" /> -->
|
||||
<el-table-column prop="inOutNumber" align="center" label="报损数量" />
|
||||
<el-table-column prop="createUserName" align="center" label="报损人" />
|
||||
<el-table-column prop="remark" align="center" label="备注" />
|
||||
|
||||
@@ -1,185 +1,194 @@
|
||||
<template>
|
||||
<div class="addgoods">
|
||||
<div class="header-wrap">
|
||||
<el-radio-group v-model="addFormType" size="large">
|
||||
<el-radio-button label="基础信息" :value="1"></el-radio-button>
|
||||
<el-radio-button label="耗材设置" :value="2"></el-radio-button>
|
||||
<el-radio-button label="关联推荐商品" :value="3"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="150px" class="demo-ruleForm" status-icon>
|
||||
<el-form-item label="商品名称" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="ruleForm.name" placeholder="请输入商品名称" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品介绍">
|
||||
<el-col :span="12">
|
||||
<el-form-item>
|
||||
<el-input v-model="ruleForm.shortTitle" type="textarea" placeholder="请输入商品介绍" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="unitId">
|
||||
<el-select v-model="ruleForm.unitId" placeholder="请选择单位" :disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.Company" :key="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="region">
|
||||
<el-select v-model="ruleForm.categoryId" placeholder="请选择商品分类" :disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.classification" :key="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="商品图片" required prop="images">
|
||||
<div v-show="addFormType == 1">
|
||||
<el-form-item label="商品名称" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="ruleForm.name" placeholder="请输入商品名称" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品介绍">
|
||||
<el-col :span="12">
|
||||
<el-form-item>
|
||||
<el-input v-model="ruleForm.shortTitle" type="textarea" placeholder="请输入商品介绍"
|
||||
:disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="unitId">
|
||||
<el-select v-model="ruleForm.unitId" placeholder="请选择单位" :disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.Company" :key="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类" required>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="region">
|
||||
<el-select v-model="ruleForm.categoryId" placeholder="请选择商品分类" :disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.classification" :key="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="商品图片" required prop="images">
|
||||
<MultiImageUpload v-model="ruleForm.images" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="商品图片" required prop="images">
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
<div v-for="(item, index) in ruleForm.images" :key="index" style="position: relative" class="showStyle">
|
||||
<el-icon class="buttonstyle" @click="deleteEvent(item)">
|
||||
<DeleteFilled />
|
||||
</el-icon>
|
||||
<img style="width: 148px; height: 148px; margin-right: 6px" class="imgStyle" :src="item" alt="" />
|
||||
</div>
|
||||
<div class="upImgStyle" @click="addimgEvent">+</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="tips">注:第一张图为商品封面图,图片尺寸为750×750</div>
|
||||
</el-form-item>
|
||||
<!-- 选择图片 -->
|
||||
<AddImg ref="addImg" @successEvent="successEvent"></AddImg>
|
||||
|
||||
<el-form-item label="商品类型">
|
||||
<el-radio-group v-model="ruleForm.type" @change="changeTypeEnum(ruleForm.type)" :disabled="isSyncStatus()">
|
||||
<el-radio value="single">单规格商品</el-radio>
|
||||
<el-radio value="sku">多规格商品</el-radio>
|
||||
<el-radio value="package">套餐商品</el-radio>
|
||||
<el-radio value="weight">称重商品</el-radio>
|
||||
<!-- <el-radio label="coupon">团购券</el-radio> -->
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="套餐商品" v-if="ruleForm.type == 'package'">
|
||||
<div style="display: block; width: 100%">
|
||||
<div class="head-container">
|
||||
<el-radio-group v-model="ruleForm.groupType" @change="typeChange">
|
||||
<el-radio-button :label="0">固定套餐</el-radio-button>
|
||||
<el-radio-button :label="1">可选套餐</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div v-if="ruleForm.groupType == 0">
|
||||
<el-table border :data="item.goods" v-for="(item, index) in ruleForm.proGroupVo" :key="index">
|
||||
<el-table-column label="名称" prop="proName"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="price"></el-table-column>
|
||||
<el-table-column label="数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.number" :min="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150">
|
||||
<template #header>
|
||||
<el-button type="primary" @click="addgoods(-1)" :disabled="isSyncStatus()">
|
||||
添加商品
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" :disabled="scope.row.type != 'sku' && isSyncStatus()"
|
||||
@click="showSelectSkuHandle(scope.row, scope.$index, index)">设置规格</el-button>
|
||||
<el-button type="text"
|
||||
@click="ruleForm.proGroupVo[index].goods.splice(scope.$index, 1)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="ruleForm.groupType == 1">
|
||||
<div class="group_wrap" v-for="(item, index) in ruleForm.proGroupVo" :key="index">
|
||||
<el-form inline :model="item">
|
||||
<el-form-item label="规格组名">
|
||||
<el-input v-model="item.title" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="`本组菜品${item.goods.length}选`">
|
||||
<el-input v-model="item.number" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="ruleForm.proGroupVo.splice(index, 1)" :disabled="isSyncStatus()">
|
||||
删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="margin-top: 20px">
|
||||
<el-table border :data="item.goods">
|
||||
<el-table-column label="名称" prop="proName"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="price"></el-table-column>
|
||||
<el-table-column label="数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.number" :min="0" :disabled="isSyncStatus()" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150">
|
||||
<template #header>
|
||||
<el-button type="primary" @click="addgoods(index)" :disabled="isSyncStatus()">
|
||||
添加商品
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" :disabled="scope.row.type != 'sku' && isSyncStatus()"
|
||||
@click="showSelectSkuHandle(scope.row, scope.$index, index)">设置规格</el-button>
|
||||
<el-button type="text" @click="ruleForm.proGroupVo[index].goods.splice(scope.$index, 1)"
|
||||
:disabled="isSyncStatus()">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-form-item label="商品图片" required prop="images">
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
<div v-for="(item, index) in ruleForm.images" :key="index" style="position: relative" class="showStyle">
|
||||
<el-icon class="buttonstyle" @click="deleteEvent(item)">
|
||||
<DeleteFilled />
|
||||
</el-icon>
|
||||
<img style="width: 148px; height: 148px; margin-right: 6px" class="imgStyle" :src="item" alt="" />
|
||||
</div>
|
||||
<el-button type="primary" @click="addtaocan" :disabled="isSyncStatus()">
|
||||
添加套餐组
|
||||
</el-button>
|
||||
<div class="upImgStyle" @click="addimgEvent">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择规格" v-if="ruleForm.type == 'sku'">
|
||||
<el-select v-model="ruleForm.specId" placeholder="请选择规格" style="width: 500px" @change="selectSpecHandle"
|
||||
:disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.specificationsconfig"
|
||||
:key="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="ele.name" v-if="datas.selectSpeclist.length" v-for="ele in datas.selectSpeclist"
|
||||
:key="ele.name">
|
||||
<el-checkbox-group v-model="ele.selectSpecResult" @change="selectSpecResultChange">
|
||||
<el-checkbox :value="element.name" :label="element.name" v-for="(element, index) in ele.children"
|
||||
:key="index"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<!-- 规格属性 -->
|
||||
<!-- 单规格、称重 -->
|
||||
<SpecificationAttribute v-if="ruleForm.type != 'sku'" :info="ruleForm" :list="list"
|
||||
ref="specificationAttributeRef">
|
||||
</SpecificationAttribute>
|
||||
<SpecificationAttribute v-if="ruleForm.type == 'sku' && list.length" :specTableHeaders="datas.specTableHeaders"
|
||||
:info="ruleForm" :list="list" ref="specificationAttributeRef"></SpecificationAttribute>
|
||||
<el-form-item label="重量">
|
||||
<el-col :span="12">
|
||||
<div style="display: block">
|
||||
<el-input v-model="ruleForm.weight" placeholder="" :disabled="isSyncStatus()">
|
||||
<template #append>千克</template>
|
||||
</el-input>
|
||||
<!-- <div style="color: #999;">用于快递或配送运费计重</div> -->
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="tips">注:第一张图为商品封面图,图片尺寸为750×750</div>
|
||||
</el-form-item>
|
||||
<!-- 选择图片 -->
|
||||
<AddImg ref="addImg" @successEvent="successEvent"></AddImg>
|
||||
|
||||
<el-form-item label="商品类型">
|
||||
<el-radio-group v-model="ruleForm.type" @change="changeTypeEnum(ruleForm.type)" :disabled="isSyncStatus()">
|
||||
<el-radio value="single">单规格商品</el-radio>
|
||||
<el-radio value="sku">多规格商品</el-radio>
|
||||
<el-radio value="package">套餐商品</el-radio>
|
||||
<el-radio value="weight">称重商品</el-radio>
|
||||
<!-- <el-radio label="coupon">团购券</el-radio> -->
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="套餐商品" v-if="ruleForm.type == 'package'">
|
||||
<div style="display: block; width: 100%">
|
||||
<div class="head-container">
|
||||
<el-radio-group v-model="ruleForm.groupType" @change="typeChange">
|
||||
<el-radio-button :label="0">固定套餐</el-radio-button>
|
||||
<el-radio-button :label="1">可选套餐</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div v-if="ruleForm.groupType == 0">
|
||||
<el-table border :data="item.goods" v-for="(item, index) in ruleForm.proGroupVo" :key="index">
|
||||
<el-table-column label="名称" prop="proName"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="price"></el-table-column>
|
||||
<el-table-column label="数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.number" :min="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150">
|
||||
<template #header>
|
||||
<el-button type="primary" @click="addgoods(-1)" :disabled="isSyncStatus()">
|
||||
添加商品
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" :disabled="scope.row.type != 'sku' && isSyncStatus()"
|
||||
@click="showSelectSkuHandle(scope.row, scope.$index, index)">设置规格</el-button>
|
||||
<el-button type="text"
|
||||
@click="ruleForm.proGroupVo[index].goods.splice(scope.$index, 1)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="ruleForm.groupType == 1">
|
||||
<div class="group_wrap" v-for="(item, index) in ruleForm.proGroupVo" :key="index">
|
||||
<el-form inline :model="item">
|
||||
<el-form-item label="规格组名">
|
||||
<el-input v-model="item.title" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="`本组菜品${item.goods.length}选`">
|
||||
<el-input v-model="item.number" :disabled="isSyncStatus()" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="ruleForm.proGroupVo.splice(index, 1)" :disabled="isSyncStatus()">
|
||||
删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="margin-top: 20px">
|
||||
<el-table border :data="item.goods">
|
||||
<el-table-column label="名称" prop="proName"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="price"></el-table-column>
|
||||
<el-table-column label="数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.number" :min="0" :disabled="isSyncStatus()" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150">
|
||||
<template #header>
|
||||
<el-button type="primary" @click="addgoods(index)" :disabled="isSyncStatus()">
|
||||
添加商品
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" :disabled="scope.row.type != 'sku' && isSyncStatus()"
|
||||
@click="showSelectSkuHandle(scope.row, scope.$index, index)">设置规格</el-button>
|
||||
<el-button type="text" @click="ruleForm.proGroupVo[index].goods.splice(scope.$index, 1)"
|
||||
:disabled="isSyncStatus()">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="primary" @click="addtaocan" :disabled="isSyncStatus()">
|
||||
添加套餐组
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否允许临时改价">
|
||||
<el-radio-group v-model="ruleForm.isAllowTempModifyPrice" :disabled="isSyncStatus()">
|
||||
<el-radio :value="1">允许</el-radio>
|
||||
<el-radio :value="0">不允许</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="每日销量上限">
|
||||
</el-form-item>
|
||||
<el-form-item label="选择规格" v-if="ruleForm.type == 'sku'">
|
||||
<el-select v-model="ruleForm.specId" placeholder="请选择规格" style="width: 500px" @change="selectSpecHandle"
|
||||
:disabled="isSyncStatus()">
|
||||
<el-option :label="item.name" :value="item.id" v-for="item in datas.specificationsconfig"
|
||||
:key="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="ele.name" v-if="datas.selectSpeclist.length" v-for="ele in datas.selectSpeclist"
|
||||
:key="ele.name">
|
||||
<el-checkbox-group v-model="ele.selectSpecResult" @change="selectSpecResultChange">
|
||||
<el-checkbox :value="element.name" :label="element.name" v-for="(element, index) in ele.children"
|
||||
:key="index"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<!-- 规格属性 -->
|
||||
<!-- 单规格、称重 -->
|
||||
<SpecificationAttribute v-if="ruleForm.type != 'sku'" :info="ruleForm" :list="list"
|
||||
ref="specificationAttributeRef">
|
||||
</SpecificationAttribute>
|
||||
<SpecificationAttribute v-if="ruleForm.type == 'sku' && list.length" :specTableHeaders="datas.specTableHeaders"
|
||||
:info="ruleForm" :list="list" ref="specificationAttributeRef"></SpecificationAttribute>
|
||||
<el-form-item label="重量">
|
||||
<el-col :span="12">
|
||||
<div style="display: block">
|
||||
<el-input v-model="ruleForm.weight" placeholder="" :disabled="isSyncStatus()">
|
||||
<template #append>千克</template>
|
||||
</el-input>
|
||||
<!-- <div style="color: #999;">用于快递或配送运费计重</div> -->
|
||||
</div>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否允许临时改价">
|
||||
<el-radio-group v-model="ruleForm.isAllowTempModifyPrice" :disabled="isSyncStatus()">
|
||||
<el-radio :value="1">允许</el-radio>
|
||||
<el-radio :value="0">不允许</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="每日销量上限">
|
||||
<el-input-number v-model="ruleForm.dayLimit" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="每单限购">
|
||||
@@ -188,48 +197,127 @@
|
||||
<el-form-item label="每人限购">
|
||||
<el-input-number v-model="ruleForm.dayLimit" :min="0" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="定时上下架">
|
||||
<el-checkbox-group v-model="ruleForm.days">
|
||||
<el-checkbox v-for="(item, index) in datas.cycle" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-col :span="20">
|
||||
<!-- <el-time-picker v-model="ruleForm.useTime" is-range range-separator="至" start-placeholder="开始时间"
|
||||
<el-form-item label="定时上下架">
|
||||
<el-checkbox-group v-model="ruleForm.days">
|
||||
<el-checkbox v-for="(item, index) in datas.cycle" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-col :span="20">
|
||||
<!-- <el-time-picker v-model="ruleForm.useTime" is-range range-separator="至" start-placeholder="开始时间"
|
||||
end-placeholder="结束时间" value-format="HH:mm:ss" format="HH:mm:ss" />
|
||||
-->
|
||||
|
||||
<el-time-picker v-model="ruleForm.startTime" value-format="HH:mm:ss" format="HH:mm:ss" placeholder="选择开始时间">
|
||||
</el-time-picker>-
|
||||
<el-time-picker v-model="ruleForm.endTime" value-format="HH:mm:ss" format="HH:mm:ss" placeholder="选择结束时间">
|
||||
</el-time-picker>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="上架">
|
||||
<el-switch v-model="ruleForm.isSale" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="库存开关">
|
||||
<div style="display: block;">
|
||||
<el-switch v-model="ruleForm.isStock" :active-value="1" :inactive-value="0" :disabled="isSyncStatus()" />
|
||||
<div style="color: #999;">注:关闭则不计算出库数据</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="设为推荐" prop="delivery">
|
||||
<el-switch v-model="ruleForm.isHot" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="库存数量">
|
||||
<el-input-number v-model="ruleForm.stockNumber" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="打包费" prop="delivery">
|
||||
<div style="display: block;">
|
||||
<el-input-number v-model="ruleForm.packFee" controls-position="right"
|
||||
:disabled="isSyncStatus()"></el-input-number>
|
||||
<div style="color: #999;">单份商品打包费。注:店铺开启外卖模式下该数据才生效</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联推荐商品">
|
||||
<el-time-picker v-model="ruleForm.startTime" value-format="HH:mm:ss" format="HH:mm:ss" placeholder="选择开始时间">
|
||||
</el-time-picker>-
|
||||
<el-time-picker v-model="ruleForm.endTime" value-format="HH:mm:ss" format="HH:mm:ss" placeholder="选择结束时间">
|
||||
</el-time-picker>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="上架">
|
||||
<el-switch v-model="ruleForm.isSale" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="库存开关">
|
||||
<div style="display: block;">
|
||||
<el-switch v-model="ruleForm.isStock" :active-value="1" :inactive-value="0" :disabled="isSyncStatus()" />
|
||||
<div style="color: #999;">注:关闭则不计算出库数据</div>
|
||||
</div>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="设为推荐" prop="delivery">
|
||||
<el-switch v-model="ruleForm.isHot" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="库存数量">
|
||||
<el-input-number v-model="ruleForm.stockNumber" :min="0" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="打包费" prop="delivery">
|
||||
<div style="display: block;">
|
||||
<el-input-number v-model="ruleForm.packFee" controls-position="right"
|
||||
:disabled="isSyncStatus()"></el-input-number>
|
||||
<div style="color: #999;">单份商品打包费。注:店铺开启外卖模式下该数据才生效</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-show="addFormType == 2" style="padding-bottom: 20px;">
|
||||
<!-- 耗材绑定 -->
|
||||
<el-form-item label="绑定耗材"></el-form-item>
|
||||
<el-form-item label="商品名">{{ ruleForm.name }}</el-form-item>
|
||||
<el-form-item>
|
||||
<el-table :data="ruleForm.consList" border>
|
||||
<el-table-column label="序号" type="index" width="60"></el-table-column>
|
||||
<el-table-column label="耗材名称" prop="consInfoId">
|
||||
<template v-slot="scope">
|
||||
<el-select filterable v-model="scope.row.consInfoId" reserve-keyword placeholder="请输入关键词"
|
||||
@change="selectionChange($event, scope.row)">
|
||||
<el-option v-for="item in consOptions" :key="item.id" :label="item.conName"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
<!-- <div class="tips" v-if="scope.row.stockNumber">库存:{{ scope.row.stockNumber }}</div> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" prop="conUnit">
|
||||
<template v-slot="scope">
|
||||
<el-input v-model="scope.row.conUnit" readonly disabled placeholder="请选择耗材"></el-input>
|
||||
<!-- <el-select v-model="scope.row.conUnit" reserve-keyword placeholder="请输入关键词">
|
||||
<el-option
|
||||
v-for="item in returnConUnits(scope.row.consInfoId)"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
></el-option>
|
||||
</el-select> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="使用数量" prop="surplusStock" min-width="150px">
|
||||
<template v-slot="scope">
|
||||
<el-input-number v-model="scope.row.surplusStock" :min="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<template #header>
|
||||
<el-button type="primary" size="small" @click="createItem">添加</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<div class="table_btn_wrap">
|
||||
<div class="btn sub" @click="ruleForm.consList.splice(scope.$index, 1)">
|
||||
<el-icon>
|
||||
<RemoveFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
<!-- <div class="btn add" v-if="scope.$index == ruleForm.consList.length - 1"
|
||||
@click="createItem(scope.row)">
|
||||
<el-icon>
|
||||
<CirclePlusFilled />
|
||||
</el-icon>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<el-form-item label="自动售罄">
|
||||
<div class="center">
|
||||
<el-switch v-model="ruleForm.isAutoSoldStock" :active-value="1" :inactive-value="0"></el-switch>
|
||||
<el-text type="info">当绑定的任何一种耗材库存不足时,商品自动售罄</el-text>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="退菜是否退库存">
|
||||
<div class="column">
|
||||
<div>
|
||||
<el-radio-group v-model="ruleForm.refundMode">
|
||||
<el-radio label="退菜退库存" :value="1"></el-radio>
|
||||
<el-radio label="仅退菜不退库存" :value="2"></el-radio>
|
||||
<el-radio label="每次询问-退菜后弹窗提示,可手动选择" :value="3"></el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div>
|
||||
<el-text type="danger">当前店铺退菜退库存规则:{{ shopInfoTypeFilter(shopInfo.refundMode) }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="关联推荐商品" v-show="addFormType == 3">
|
||||
<div class="column">
|
||||
<div class="row">
|
||||
<div class="center">
|
||||
@@ -313,10 +401,62 @@ import Sortable from "sortablejs";
|
||||
import { useTagsViewStore } from "@/store";
|
||||
import selecProductDialog from "@/views/marketing_center/group_booking/components/selecProductDialog.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const selecProductDialogRef = ref(null)
|
||||
const goodsListMax = ref(9)
|
||||
|
||||
const addFormType = ref(1)
|
||||
|
||||
const consOptions = ref([])
|
||||
|
||||
// let haocaiData = ref({
|
||||
// consList: [
|
||||
// {
|
||||
// productId: '',
|
||||
// consInfoId: "",
|
||||
// surplusStock: "0",
|
||||
// }
|
||||
// ]
|
||||
// });
|
||||
|
||||
// 生成新商品绑定耗材关系项
|
||||
function createItem(val) {
|
||||
let item = {
|
||||
productId: '',
|
||||
consInfoId: "",
|
||||
surplusStock: "",
|
||||
};
|
||||
ruleForm.consList.push(item);
|
||||
}
|
||||
|
||||
// 商品选择耗材
|
||||
function selectionChange(e, row) {
|
||||
let item = consOptions.value.find((item) => item.id == e);
|
||||
row.name = item.conName;
|
||||
row.conUnit = item.conUnit;
|
||||
}
|
||||
|
||||
// 获取耗材列表
|
||||
async function gethaocaiList() {
|
||||
try {
|
||||
let res = await UserAPI3.productconsList({ id: route.query.id });
|
||||
console.log('获取耗材列表', res);
|
||||
consOptions.value = res || [];
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const shopInfo = ref('')
|
||||
|
||||
function shopInfoTypeFilter(t) {
|
||||
if (t == 1) return '跟随商品分类'
|
||||
if (t == 2) return '跟随单商品'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
shopInfo.value = JSON.parse(localStorage.getItem('userInfo'))
|
||||
gethaocaiList()
|
||||
// Sortable 需要在 el-table 渲染 tbody 后初始化,尝试多次以确保 DOM 可用
|
||||
const initSortable = async () => {
|
||||
await nextTick();
|
||||
@@ -520,7 +660,10 @@ const ruleForm = reactive<RuleForm>({
|
||||
// 排序值
|
||||
sort: 1,
|
||||
selectSpecInfo: {},
|
||||
relatedRecommendJson: [] // 关联推荐商品
|
||||
relatedRecommendJson: [], // 关联推荐商品
|
||||
consList: [], // 耗材列表
|
||||
refundMode: 1, // 退菜是否退库存 1退菜退库存 2仅退菜不退库存 3每次询问-退菜后弹窗提示
|
||||
isAutoSoldStock: 0, // 是否自动售罄
|
||||
});
|
||||
const rules = reactive<FormRules<RuleForm>>({
|
||||
name: [{ required: true, message: "请输入商品名称", trigger: "blur" }],
|
||||
@@ -584,6 +727,14 @@ async function tbProductGetDetail(id: any) {
|
||||
} else {
|
||||
list.value = ruleForm.skuList;
|
||||
}
|
||||
|
||||
// if (res.consList.length == 0) {
|
||||
// ruleForm.consList.push({
|
||||
// productId: '',
|
||||
// consInfoId: "",
|
||||
// surplusStock: "0",
|
||||
// })
|
||||
// }
|
||||
}
|
||||
// 选择套餐商品sku
|
||||
function selectSkuHandle(item: any, index: number) {
|
||||
@@ -1088,4 +1239,8 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-wrap {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -9,6 +9,7 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
table: {
|
||||
border: true,
|
||||
highlightCurrentRow: true,
|
||||
expandRowKeys: [],
|
||||
rowKey: 'id',
|
||||
treeProps: {
|
||||
children: 'skuList' // 指定子节点存储的字段为 customChildren
|
||||
@@ -72,20 +73,20 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
name: "sync",
|
||||
auth: "import",
|
||||
},
|
||||
{
|
||||
icon: "edit",
|
||||
text: "库存预警",
|
||||
type: "danger",
|
||||
name: "custom1",
|
||||
auth: "import",
|
||||
},
|
||||
// {
|
||||
// icon: "edit",
|
||||
// text: "库存预警",
|
||||
// type: "danger",
|
||||
// name: "custom1",
|
||||
// auth: "import",
|
||||
// },
|
||||
{
|
||||
icon: "Download",
|
||||
text: "导出",
|
||||
type: "",
|
||||
name: "export",
|
||||
auth: "import",
|
||||
},
|
||||
}
|
||||
],
|
||||
cols: [
|
||||
// { type: "selection", width: 50, align: "center" },
|
||||
@@ -97,15 +98,15 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
slotName: "type",
|
||||
},
|
||||
// { label: "库存", align: "center", prop: "stockNumber" },
|
||||
{ label: "库存", align: "center", slotName: "kucunedit", templet: "custom", prop: "stockNumber" },
|
||||
// { label: "库存", align: "center", slotName: "kucunedit", templet: "custom", prop: "stockNumber" },
|
||||
{ label: "耗材信息", align: "center", prop: "consName", slotName: "consumables", templet: "custom", },
|
||||
{
|
||||
label: "库存开关",
|
||||
align: "center",
|
||||
prop: "isStock",
|
||||
templet: "custom",
|
||||
slotName: "isStock",
|
||||
},
|
||||
// {
|
||||
// label: "库存开关",
|
||||
// align: "center",
|
||||
// prop: "isStock",
|
||||
// templet: "custom",
|
||||
// slotName: "isStock",
|
||||
// },
|
||||
{
|
||||
label: "上架",
|
||||
align: "center",
|
||||
@@ -121,9 +122,16 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
slotName: "sellOut",
|
||||
},
|
||||
{
|
||||
label: "退款退回库存",
|
||||
label: "自动售罄",
|
||||
align: "center",
|
||||
prop: "isRefundStock",
|
||||
prop: "isAutoSoldStock",
|
||||
templet: "custom",
|
||||
slotName: "autoSellOut",
|
||||
},
|
||||
{
|
||||
label: "退菜是否退库存",
|
||||
align: "center",
|
||||
prop: "refundMode",
|
||||
templet: "custom",
|
||||
slotName: "tuikuantuihui",
|
||||
},
|
||||
@@ -133,7 +141,11 @@ const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
fixed: "right",
|
||||
width: 280,
|
||||
templet: "tool",
|
||||
operat: [{ text: "报损", name: '' }, { text: "编辑", icon: 'edit', name: "edit" }, { text: "删除", icon: 'delete', type: 'danger', name: "delete" }],
|
||||
operat: [
|
||||
{ text: "报损", icon: '', name: 'cons' },
|
||||
{ text: "报损记录", name: 'consRecord' },
|
||||
{ text: "编辑", icon: 'edit', name: "edit" },
|
||||
{ text: "删除", icon: 'delete', type: 'danger', name: "delete" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -3,25 +3,14 @@
|
||||
<div>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="160px" label-position="left">
|
||||
<el-form-item label="门店名称" prop="shopName">
|
||||
<el-input
|
||||
v-model.trim="form.shopName"
|
||||
placeholder="请输入门店名称"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input v-model.trim="form.shopName" placeholder="请输入门店名称" style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="连锁店扩展店名">
|
||||
<el-input
|
||||
v-model.trim="form.chainName"
|
||||
placeholder="请输入连锁店扩展店名"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input v-model.trim="form.chainName" placeholder="请输入连锁店扩展店名" style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="门店logo">
|
||||
<div class="img_box">
|
||||
<single-image-upload
|
||||
style="width: 80px; height: 80px"
|
||||
v-model="form.logo"
|
||||
></single-image-upload>
|
||||
<single-image-upload style="width: 80px; height: 80px" v-model="form.logo"></single-image-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="门店照片">
|
||||
@@ -38,22 +27,14 @@
|
||||
<el-form-item label="门店收款码">
|
||||
<div class="img_box">
|
||||
<canvas ref="canvas" id="QRCode_header" style="width: 80px; height: 80px"></canvas>
|
||||
<el-button
|
||||
size="small"
|
||||
plain
|
||||
v-if="form.paymentQrcode"
|
||||
@click="downloadCanvas(form.paymentQrcode)"
|
||||
>
|
||||
<el-button size="small" plain v-if="form.paymentQrcode" @click="downloadCanvas(form.paymentQrcode)">
|
||||
下载
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="微信二维码">
|
||||
<div class="img_box">
|
||||
<single-image-upload
|
||||
style="width: 80px; height: 80px"
|
||||
v-model="form.shopQrcode"
|
||||
></single-image-upload>
|
||||
<single-image-upload style="width: 80px; height: 80px" v-model="form.shopQrcode"></single-image-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="店铺小程序码">
|
||||
@@ -71,11 +52,7 @@
|
||||
<el-radio value="after">餐饮版(先下单后支付)</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="是否允许用户自行支付"
|
||||
prop="isUserPay"
|
||||
v-if="form.registerType === 'after'"
|
||||
>
|
||||
<el-form-item label="是否允许用户自行支付" prop="isUserPay" v-if="form.registerType === 'after'">
|
||||
<div class="column">
|
||||
<div class="center" style="display: flex; align-items: center; gap: 14px">
|
||||
<el-switch v-model="form.isUserPay" :active-value="1" :inactive-value="0"></el-switch>
|
||||
@@ -92,6 +69,12 @@
|
||||
<el-checkbox value="take-out">允许打包</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="退菜退库存模式">
|
||||
<el-radio-group :model-value="form.refundMode" @change="refundModeChange">
|
||||
<el-radio label="跟随商品分类" :value="1"></el-radio>
|
||||
<el-radio label="跟随单商品" :value="2"></el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="积分群体">
|
||||
<el-radio-group v-model="form.consumeColony">
|
||||
<el-radio label="all">所有</el-radio>
|
||||
@@ -99,11 +82,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="联系电话" prop="phone">
|
||||
<el-input
|
||||
v-model.trim="form.phone"
|
||||
placeholder="请输入联系电话"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input v-model.trim="form.phone" placeholder="请输入联系电话" style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="外卖起送金额">
|
||||
<el-input-number v-model="form.takeaway_money" placeholder="0.00" controls-position="right"
|
||||
@@ -129,62 +108,30 @@
|
||||
<div style="color: #999">注:准确的定位便于用户导航到店铺</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="门店详细地址">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="form.address"
|
||||
placeholder="请输入门店详细地址"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input type="textarea" v-model.trim="form.address" placeholder="请输入门店详细地址" style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="营业时间">
|
||||
<div class="u-flex gap-2" style="width: 50%">
|
||||
<el-select v-model="form.businessStartDay" placeholder="周几开始">
|
||||
<el-option
|
||||
:value="item.label"
|
||||
:label="item.label"
|
||||
v-for="item in weeks"
|
||||
:key="item.value"
|
||||
></el-option>
|
||||
<el-option :value="item.label" :label="item.label" v-for="item in weeks" :key="item.value"></el-option>
|
||||
</el-select>
|
||||
<el-select v-model="form.businessEndDay" placeholder="周几结束">
|
||||
<el-option
|
||||
:value="item.label"
|
||||
:label="item.label"
|
||||
v-for="item in weeks"
|
||||
:key="item.value"
|
||||
></el-option>
|
||||
<el-option :value="item.label" :label="item.label" v-for="item in weeks" :key="item.value"></el-option>
|
||||
</el-select>
|
||||
<el-time-picker
|
||||
placeholder="起始时间"
|
||||
v-model="startTime"
|
||||
:picker-options="{
|
||||
selectableRange: '00:00:00 - 23:59:59',
|
||||
format: 'HH:mm',
|
||||
}"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
></el-time-picker>
|
||||
<el-time-picker
|
||||
placeholder="结束时间"
|
||||
v-model="endTime"
|
||||
:picker-options="{
|
||||
selectableRange: '00:00:00 - 23:59:59',
|
||||
}"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
></el-time-picker>
|
||||
<el-time-picker placeholder="起始时间" v-model="startTime" :picker-options="{
|
||||
selectableRange: '00:00:00 - 23:59:59',
|
||||
format: 'HH:mm',
|
||||
}" format="HH:mm" value-format="HH:mm"></el-time-picker>
|
||||
<el-time-picker placeholder="结束时间" v-model="endTime" :picker-options="{
|
||||
selectableRange: '00:00:00 - 23:59:59',
|
||||
}" format="HH:mm" value-format="HH:mm"></el-time-picker>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="桌位费/位/元">
|
||||
<el-input-number :disabled="!!form.isTableFee" v-model="form.tableFee" :min="0" />
|
||||
<!-- <el-checkbox v-model="form.isTableFee" :label="1">免餐位费</el-checkbox> -->
|
||||
<el-switch
|
||||
class="u-m-l-10"
|
||||
v-model.trim="form.isTableFee"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="免餐位费"
|
||||
></el-switch>
|
||||
<el-switch class="u-m-l-10" v-model.trim="form.isTableFee" :active-value="1" :inactive-value="0"
|
||||
active-text="免餐位费"></el-switch>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="是否开启8折活动">
|
||||
<el-switch v-model.trim="form.isOpenYhq" active-value="true" inactive-value="false"></el-switch>
|
||||
@@ -218,41 +165,24 @@
|
||||
</el-time-picker>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="店铺简介">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="form.detail"
|
||||
placeholder="请输入店铺简介"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input type="textarea" v-model.trim="form.detail" placeholder="请输入店铺简介" style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="台桌预订短信">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="form.bookingSms"
|
||||
placeholder="请输入台桌预订短信"
|
||||
style="width: 500px"
|
||||
></el-input>
|
||||
<el-input type="textarea" v-model.trim="form.bookingSms" placeholder="请输入台桌预订短信"
|
||||
style="width: 500px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电子围栏" prop="isOrderFence">
|
||||
<div class="column">
|
||||
<div class="center" style="display: flex; align-items: center; gap: 14px">
|
||||
<el-switch
|
||||
v-model="form.isOrderFence"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
></el-switch>
|
||||
<el-switch v-model="form.isOrderFence" :active-value="1" :inactive-value="0"></el-switch>
|
||||
<div class="tips" style="font-size: 14px; color: #999">
|
||||
开启后,用户只能在店铺附近xx公里内点餐
|
||||
</div>
|
||||
</div>
|
||||
<div class="center" v-if="form.isOrderFence == 1">
|
||||
<el-input
|
||||
v-model="form.orderFenceDistance"
|
||||
placeholder="请输入"
|
||||
@input="(e) => (form.orderFenceDistance = filterNumberInput(e))"
|
||||
style="width: 250px"
|
||||
input-style="text-align: center;"
|
||||
>
|
||||
<el-input v-model="form.orderFenceDistance" placeholder="请输入"
|
||||
@input="(e) => (form.orderFenceDistance = filterNumberInput(e))" style="width: 250px"
|
||||
input-style="text-align: center;">
|
||||
<template #prepend>限制:</template>
|
||||
<template #append>公里</template>
|
||||
</el-input>
|
||||
@@ -263,23 +193,15 @@
|
||||
<el-form-item label="上菜时间(分钟)" prop="isServeTimeControl">
|
||||
<div class="column">
|
||||
<div class="center" style="display: flex; align-items: center; gap: 14px">
|
||||
<el-switch
|
||||
v-model="form.isServeTimeControl"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
></el-switch>
|
||||
<el-switch v-model="form.isServeTimeControl" :active-value="1" :inactive-value="0"></el-switch>
|
||||
<div class="tips" style="font-size: 14px; color: #999">
|
||||
起菜到上菜的时间间隔,开启后会有超时提示
|
||||
</div>
|
||||
</div>
|
||||
<div class="center" v-if="form.isServeTimeControl == 1">
|
||||
<el-input
|
||||
v-model="form.serveTime"
|
||||
placeholder="请输入"
|
||||
@input="(e) => (form.serveTime = filterNumberInput(e))"
|
||||
style="width: 250px"
|
||||
input-style="text-align: center;"
|
||||
>
|
||||
<el-input v-model="form.serveTime" placeholder="请输入"
|
||||
@input="(e) => (form.serveTime = filterNumberInput(e))" style="width: 250px"
|
||||
input-style="text-align: center;">
|
||||
<template #prepend>限制:</template>
|
||||
<template #append>分钟</template>
|
||||
</el-input>
|
||||
@@ -304,24 +226,11 @@
|
||||
</el-form>
|
||||
</div>
|
||||
<ChooseAddress ref="refChooseAddress" @choose="chooseAddressConfirm"></ChooseAddress>
|
||||
<el-dialog
|
||||
v-model="showUpload"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
width="500px"
|
||||
@close="showUpload = false"
|
||||
>
|
||||
<el-upload
|
||||
:before-remove="handleBeforeRemove"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:file-list="fileList"
|
||||
:headers="headers"
|
||||
:action="qiNiuUploadApi"
|
||||
:limit="1"
|
||||
list-type="picture"
|
||||
class="upload-demo"
|
||||
>
|
||||
<el-dialog v-model="showUpload" :close-on-click-modal="false" append-to-body width="500px"
|
||||
@close="showUpload = false">
|
||||
<el-upload :before-remove="handleBeforeRemove" :on-success="handleSuccess" :on-error="handleError"
|
||||
:file-list="fileList" :headers="headers" :action="qiNiuUploadApi" :limit="1" list-type="picture"
|
||||
class="upload-demo">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<template #tip>
|
||||
<div style="display: block" class="el-upload__tip">请勿上传违法文件,且文件不超过15M</div>
|
||||
@@ -459,6 +368,24 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 切换退菜退库存模式
|
||||
refundModeChange(value) {
|
||||
console.log('refundModeChange===', value);
|
||||
const m = {
|
||||
1: {
|
||||
1: '跟随商品分类',
|
||||
2: '商品分类'
|
||||
},
|
||||
2: {
|
||||
1: '跟随单商品模式',
|
||||
2: '商品列表'
|
||||
}
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(`当前操作:将《退菜退库存》模式切换为「${m[value][1]}」本操作将会影响耗材库存数量的统计请谨慎操作修改后,可前往「商品管理-${m[value][2]}」中编辑/查看配置`, '提示', { showClose: false, showCancelButton: false }).then(() => {
|
||||
this.form.refundMode = value
|
||||
}).catch(() => { })
|
||||
},
|
||||
chooseAddressConfirm(e) {
|
||||
console.log(e);
|
||||
this.$refs.refChooseAddress.close();
|
||||
@@ -576,7 +503,7 @@ export default {
|
||||
handleBeforeRemove(file, fileList) {
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
if (this.files[i].uid === file.uid) {
|
||||
crudQiNiu.del([this.files[i].id]).then((res) => {});
|
||||
crudQiNiu.del([this.files[i].id]).then((res) => { });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,11 +110,21 @@
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="试用/正式">
|
||||
<el-form-item label="商户版本">
|
||||
<el-radio-group v-model="state.form.profiles">
|
||||
<el-radio-button value="probation">试用</el-radio-button>
|
||||
<el-radio-button value="release">正式</el-radio-button>
|
||||
</el-radio-group>
|
||||
<div class="tips">
|
||||
<el-alert
|
||||
title="请谨慎修改"
|
||||
type="warning"
|
||||
size="7"
|
||||
effect="dark"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="激活码">
|
||||
<el-input v-model="state.form.activateCode" placeholder="请输入激活码"></el-input>
|
||||
|
||||
@@ -3,19 +3,50 @@
|
||||
<div class="head-container">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="3">
|
||||
<el-input v-model="state.query.name" clearable placeholder="请输入店铺名称" style="width: 100%" class="filter-item"
|
||||
@keyup.enter="getTableData" />
|
||||
<el-input
|
||||
v-model="state.query.name"
|
||||
clearable
|
||||
placeholder="请输入店铺名称"
|
||||
style="width: 100%"
|
||||
class="filter-item"
|
||||
@keyup.enter="getTableData"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-input v-model="state.query.account" clearable placeholder="请输入商户号" style="width: 100%" class="filter-item"
|
||||
@keyup.enter="getTableData" />
|
||||
<el-input
|
||||
v-model="state.query.phone"
|
||||
clearable
|
||||
placeholder="请输入手机号"
|
||||
style="width: 100%"
|
||||
class="filter-item"
|
||||
@keyup.enter="getTableData"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-select v-model="state.query.status" placeholder="请选择店铺状态" style="width: 100%">
|
||||
<el-option v-for="item in state.status" :key="item.type" :label="item.label" :value="item.type" />
|
||||
<el-option
|
||||
v-for="item in state.status"
|
||||
:key="item.type"
|
||||
:label="item.label"
|
||||
:value="item.type"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="3">
|
||||
<el-select
|
||||
v-model="state.query.profiles"
|
||||
placeholder="请选择商户版本"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.profiles"
|
||||
:key="item.type"
|
||||
:label="item.label"
|
||||
:value="item.type"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-button type="primary" @click="getTableData">查询</el-button>
|
||||
<el-button @click="resetHandle">重置</el-button>
|
||||
</el-col>
|
||||
@@ -29,8 +60,10 @@
|
||||
<el-table-column label="店铺信息" width="200">
|
||||
<template v-slot="scope">
|
||||
<div class="shop_info">
|
||||
<el-image :src="scope.row.logo"
|
||||
style="width: 50px; height: 50px; border-radius: 4px; background-color: #efefef">
|
||||
<el-image
|
||||
:src="scope.row.logo"
|
||||
style="width: 50px; height: 50px; border-radius: 4px; background-color: #efefef"
|
||||
>
|
||||
<template #error>
|
||||
<div class="img_error">
|
||||
<i class="icon el-icon-document-delete" />
|
||||
@@ -57,7 +90,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="登录账号" prop="phone"></el-table-column>
|
||||
<el-table-column label="手机号" prop="phone"></el-table-column>
|
||||
<el-table-column prop="registerType" label="经营模式">
|
||||
<template v-slot="scope">
|
||||
<span v-if="scope.row.registerType == 'before'">快餐版</span>
|
||||
@@ -70,7 +103,8 @@
|
||||
<span v-if="scope.row.shopType == 'only'">单店</span>
|
||||
<span v-if="scope.row.shopType == 'chain'">连锁店</span>
|
||||
<span v-if="scope.row.shopType == 'join'">加盟店</span>
|
||||
<div v-if="scope.row.shopType != 'only' && scope.row.isHeadShop == 0">(主店:{{ scope.row.headShopName }})
|
||||
<div v-if="scope.row.shopType != 'only' && scope.row.isHeadShop == 0">
|
||||
(主店:{{ scope.row.headShopName }})
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -113,7 +147,9 @@
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="scope.row.isHeadShop == 1" :command="0">添加分店</el-dropdown-item>
|
||||
<el-dropdown-item v-if="scope.row.isHeadShop == 1" :command="0">
|
||||
添加分店
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :command="{ row: scope.row, command: 1 }">
|
||||
支付配置
|
||||
</el-dropdown-item>
|
||||
@@ -129,9 +165,14 @@
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="head-container">
|
||||
<el-pagination v-model:current-page="state.tableData.page" v-model:page-size="state.tableData.size"
|
||||
:total="state.tableData.total" :page-sizes="[10, 20, 30, 50, 100]"
|
||||
layout="total, sizes , prev, pager ,next, jumper " @current-change="paginationChange" />
|
||||
<el-pagination
|
||||
v-model:current-page="state.tableData.page"
|
||||
v-model:page-size="state.tableData.size"
|
||||
:total="state.tableData.total"
|
||||
:page-sizes="[10, 20, 30, 50, 100]"
|
||||
layout="total, sizes , prev, pager ,next, jumper "
|
||||
@current-change="paginationChange"
|
||||
/>
|
||||
</div>
|
||||
<addShop ref="refAddShop" @success="getTableData" />
|
||||
<!-- <detailModal ref="refDetailModal" /> -->
|
||||
@@ -149,7 +190,7 @@ import addShop from "./components/addShop.vue";
|
||||
import detailModal from "./components/detailModal.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter()
|
||||
const router = useRouter();
|
||||
|
||||
const refActivateCode = ref(null);
|
||||
function activateCodeShow(row) {
|
||||
@@ -162,8 +203,9 @@ function addShopShow(row) {
|
||||
const state = reactive({
|
||||
query: {
|
||||
name: "",
|
||||
account: "",
|
||||
phone: "",
|
||||
status: "",
|
||||
profiles: "",
|
||||
},
|
||||
status: [
|
||||
{
|
||||
@@ -175,6 +217,16 @@ const state = reactive({
|
||||
label: "关闭",
|
||||
},
|
||||
],
|
||||
profiles: [
|
||||
{
|
||||
type: "probation",
|
||||
label: "试用版",
|
||||
},
|
||||
{
|
||||
type: "release",
|
||||
label: "正式版",
|
||||
},
|
||||
],
|
||||
tableData: {
|
||||
list: [],
|
||||
page: 1,
|
||||
@@ -192,24 +244,24 @@ function dropdownClick(e, row) {
|
||||
console.log(e);
|
||||
console.log(row);
|
||||
if (e == 0) {
|
||||
refAddShop.value.show({ mainId: row.id, shopType: row.shopType, isHeadShop: 0 }, 'addBranch');
|
||||
refAddShop.value.show({ mainId: row.id, shopType: row.shopType, isHeadShop: 0 }, "addBranch");
|
||||
|
||||
return;
|
||||
}
|
||||
if (e.command == 1) {
|
||||
console.log('row===', row);
|
||||
console.log("row===", row);
|
||||
|
||||
// refDetailModal.value.show(e.row);
|
||||
router.push({
|
||||
name: 'pay_setting',
|
||||
name: "pay_setting",
|
||||
query: {
|
||||
shopId: row.id,
|
||||
shopType: row.shopType,
|
||||
isHeadShop: row.isHeadShop,
|
||||
mainId: row.mainId,
|
||||
shopName: row.shopName
|
||||
}
|
||||
})
|
||||
shopName: row.shopName,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (e == 5) {
|
||||
@@ -226,15 +278,16 @@ function dropdownClick(e, row) {
|
||||
});
|
||||
getTableData();
|
||||
})
|
||||
.catch(() => { });
|
||||
.catch(() => {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 重置查询
|
||||
function resetHandle() {
|
||||
state.query.name = "";
|
||||
state.query.account = "";
|
||||
state.query.phone = "";
|
||||
state.query.status = "";
|
||||
state.query.profiles = "";
|
||||
getTableData();
|
||||
}
|
||||
// 分页回调
|
||||
@@ -250,8 +303,9 @@ async function getTableData() {
|
||||
page: state.tableData.page,
|
||||
size: state.tableData.size,
|
||||
shopName: state.query.name,
|
||||
account: state.query.account,
|
||||
phone: state.query.phone,
|
||||
status: state.query.status,
|
||||
profiles: state.query.profiles,
|
||||
});
|
||||
state.tableData.loading = false;
|
||||
state.tableData.list = res.records;
|
||||
|
||||
@@ -4,38 +4,22 @@
|
||||
<template v-if="carts.list && carts.list.length >= 1">
|
||||
<!-- 当前购物车 -->
|
||||
<div v-for="(item, index) in carts.list" :key="index">
|
||||
<carts-item
|
||||
:item="item"
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
@changeNumber="changeNumber"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
<carts-item :item="item" :useVipPrice="carts.useVipPrice" @changeNumber="changeNumber"
|
||||
:selCart="carts.selCart" @itemClick="itemClick(item)" @editNote="editNote"></carts-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 赠菜 -->
|
||||
<div class="cart-title" v-if="carts.giftList.length > 0"><span>以下是优惠菜品</span></div>
|
||||
<div v-for="(item, index) in carts.giftList" :key="index">
|
||||
<carts-item
|
||||
:item="item"
|
||||
@changeNumber="changeNumber"
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
<carts-item :item="item" @changeNumber="changeNumber" :useVipPrice="carts.useVipPrice" :selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)" @editNote="editNote"></carts-item>
|
||||
</div>
|
||||
<el-empty :image-size="60" v-if="carts.isEmpty" description="点餐列表为空" />
|
||||
<!-- 打包费 -->
|
||||
<template v-if="carts.packNum > 0">
|
||||
<div class="cart-title"><span>打包费</span></div>
|
||||
<extra-fee
|
||||
name="打包费"
|
||||
:number="carts.packNum"
|
||||
:price="carts.orderCostSummary.packFee"
|
||||
></extra-fee>
|
||||
<extra-fee name="打包费" :number="carts.packNum" :price="carts.orderCostSummary.packFee"></extra-fee>
|
||||
</template>
|
||||
<!-- 餐位费 -->
|
||||
<template v-if="perpole >= 1 && carts.dinnerType == 'dine-in'">
|
||||
@@ -43,7 +27,7 @@
|
||||
<extra-fee name="餐位费" :number="perpole" :price="canWeiFee"></extra-fee>
|
||||
</template>
|
||||
<!-- 历史订单 -->
|
||||
<div class="u-flex u-row-between u-m-b-10" v-if="carts.oldOrder.id">
|
||||
<div class="u-flex u-row-between u-m-b-10" v-if="carts.oldOrder.id && !isEmptyObject(carts.oldOrder.detailMap)">
|
||||
<span class="u-font-14">历史订单</span>
|
||||
<el-button link size="small" type="danger" @click="clearOldOrder()">清空</el-button>
|
||||
</div>
|
||||
@@ -56,17 +40,9 @@
|
||||
</div>
|
||||
|
||||
<div v-for="(detaiItem, index) in item" :key="index">
|
||||
<carts-item
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
:canChangeNumber="false"
|
||||
isOld
|
||||
:dinerType="dinerType"
|
||||
:item="detaiItem"
|
||||
@changeNumber="changeNumber"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(detaiItem)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
<carts-item :useVipPrice="carts.useVipPrice" :canChangeNumber="false" isOld :dinerType="dinerType"
|
||||
:item="detaiItem" @changeNumber="changeNumber" :selCart="carts.selCart" @itemClick="itemClick(detaiItem)"
|
||||
@editNote="editNote"></carts-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -74,14 +50,9 @@
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="u-flex u-row-right">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
effect="light"
|
||||
popper-class="youhui-tips"
|
||||
:popper-options="{
|
||||
'background-color': '#fff',
|
||||
}"
|
||||
>
|
||||
<el-tooltip placement="top" effect="light" popper-class="youhui-tips" :popper-options="{
|
||||
'background-color': '#fff',
|
||||
}">
|
||||
<template #content>
|
||||
<div class="u-flex color-000 u-font-14 u-row-between">
|
||||
<span class="font-bold">会员优惠</span>
|
||||
@@ -111,28 +82,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group" v-if="isXianFuKuan">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('wx-aiplay')"
|
||||
>
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('wx-aiplay')">
|
||||
微信/支付宝
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('cash')"
|
||||
>
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('cash')">
|
||||
现金
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('more-pay')"
|
||||
>
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('more-pay')">
|
||||
更多支付
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -145,33 +101,20 @@
|
||||
<el-button type="primary" size="large" :disabled="disabledMorePay" @click="createOrder('to-pay')">
|
||||
去结账
|
||||
</el-button> -->
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="carts.list.length == 0 || carts.oldOrder.detailMap.length == 0"
|
||||
@click="createOrder('only-create')"
|
||||
>
|
||||
<el-button type="primary" size="large" :disabled="carts.list.length == 0" @click="createOrder('only-create')">
|
||||
仅下单
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
<el-button type="primary" size="large"
|
||||
:disabled="carts.list.length == 0 && isEmptyObject(carts.oldOrder.detailMap)"
|
||||
@click="createOrder('to-pay')"
|
||||
>
|
||||
@click="createOrder('to-pay')">
|
||||
去结账
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="default" size="large" @click="hideOrder()">加菜/返回</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!carts.isLinkFinshed"
|
||||
@click="createOrder('to-pay')"
|
||||
>
|
||||
<el-button type="warning" size="large" @click="hideOrder()">加菜/返回</el-button>
|
||||
<!-- <el-button type="primary" size="large" :disabled="!carts.isLinkFinshed" @click="createOrder('to-pay')">
|
||||
立即支付
|
||||
</el-button>
|
||||
</el-button> -->
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -188,11 +131,11 @@ import { useUserStore } from "@/store/modules/user";
|
||||
function isEmptyObject(obj) {
|
||||
// 步骤1:排除null和非对象类型
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// 步骤2:排除数组(数组也是对象,需单独判断)
|
||||
if (Array.isArray(obj)) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// 步骤3:判断自身可枚举属性是否为空
|
||||
return Object.keys(obj).length === 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="head-container">
|
||||
<el-form :model="query" inline>
|
||||
<el-form-item label="">
|
||||
<el-input v-model="query.name" placeholder="请输入昵称或手机号"></el-input>
|
||||
<el-input v-model="query.key" placeholder="请输入昵称或手机号"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
@@ -22,7 +22,10 @@
|
||||
<el-table-column label="用户" prop="headImg" width="200px">
|
||||
<template v-slot="scope">
|
||||
<div class="user_info">
|
||||
<el-image :src="scope.row.headImg" style="width: 40px; height: 40px; flex-shrink: 0">
|
||||
<el-image
|
||||
:src="scope.row.headImg"
|
||||
style="width: 40px; height: 40px; flex-shrink: 0"
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<i class="el-icon-user"></i>
|
||||
@@ -30,7 +33,14 @@
|
||||
</template>
|
||||
</el-image>
|
||||
<span class="name">{{ scope.row.nickName }}</span>
|
||||
<el-tag disable-transitions type="primary" style="margin-left: 10px;" v-if="scope.row.new">新</el-tag>
|
||||
<el-tag
|
||||
disable-transitions
|
||||
type="primary"
|
||||
style="margin-left: 10px"
|
||||
v-if="scope.row.new"
|
||||
>
|
||||
新
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -38,7 +48,9 @@
|
||||
|
||||
<el-table-column label="会员" prop="isVip" width="140">
|
||||
<template v-slot="scope">
|
||||
<el-tag type="warning" v-if="scope.row.isVip">会员等级{{ scope.row.memberLevelName }}</el-tag>
|
||||
<el-tag type="warning" v-if="scope.row.isVip">
|
||||
会员等级{{ scope.row.memberLevelName }}
|
||||
</el-tag>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -60,9 +72,14 @@
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="head-container">
|
||||
<el-pagination :total="tableData.total" :current-page="tableData.page" :page-size="tableData.size"
|
||||
@size-change="sizeChange" @current-change="paginationChange"
|
||||
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
|
||||
<el-pagination
|
||||
:total="tableData.total"
|
||||
:current-page="tableData.page"
|
||||
:page-size="tableData.size"
|
||||
@size-change="sizeChange"
|
||||
@current-change="paginationChange"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -71,13 +88,13 @@
|
||||
<script setup>
|
||||
import shopUserApi from "@/api/account/shopUser";
|
||||
import dayjs from "dayjs";
|
||||
import { multiplyAndFormat } from '@/utils'
|
||||
import { multiplyAndFormat } from "@/utils";
|
||||
let cacheData = {};
|
||||
|
||||
const state = reactive({
|
||||
show: false,
|
||||
query: {
|
||||
name: "",
|
||||
key: "",
|
||||
// isVip: 1,
|
||||
},
|
||||
tableData: {
|
||||
@@ -242,4 +259,4 @@ defineExpose({
|
||||
.gap-20 {
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
</div>
|
||||
<div class="status" v-if="
|
||||
item.isSoldStock ||
|
||||
item.isSoldOut ||
|
||||
!item.isSale ||
|
||||
!item.isSaleTime ||
|
||||
(item.isStock && item.stockNumber * 1 <= 0)
|
||||
@@ -37,8 +38,8 @@
|
||||
ElMessage.error('该商品不在可售时间内') ||
|
||||
isProductAvailable(item.days, item.startTime, item.endTime)
|
||||
" v-else-if="!item.isSaleTime" iconClass="no-sale" color="#fff" size="60"></svg-icon>
|
||||
<svg-icon @click="ElMessage.error('该商品已售罄')" v-else-if="item.isSoldStock" iconClass="shouqing" color="#fff"
|
||||
size="60"></svg-icon>
|
||||
<svg-icon @click="ElMessage.error('该商品已售罄')" v-else-if="item.isSoldStock || item.isSoldOut" iconClass="shouqing"
|
||||
color="#fff" size="60"></svg-icon>
|
||||
<svg-icon @click="ElMessage.error('库存不足')" v-else-if="item.isStock && item.stockNumber * 1 <= 0"
|
||||
iconClass="stock_null" color="#fff" size="60"></svg-icon>
|
||||
</div>
|
||||
|
||||
@@ -591,7 +591,7 @@ function pointsToMoney(val) {
|
||||
carts.orderCostSummary.pointDeductionAmount = finalMoney;
|
||||
}
|
||||
|
||||
const emits = defineEmits(["chooseUser", "paysuccess"]);
|
||||
const emits = defineEmits(["chooseUser", "paysuccess", 'createOrder']);
|
||||
function chooseUser() {
|
||||
emits("chooseUser");
|
||||
}
|
||||
@@ -672,6 +672,7 @@ function returnPayParams() {
|
||||
newCustomerDiscountAmount:
|
||||
carts.newUserDiscount !== null ? carts.newUserDiscount.amount : 0, // 新客立减金额
|
||||
vipDiscountAmount: carts.orderCostSummary.vipDiscountAmount, // 超级会员折扣
|
||||
remark: cashRemark.value, // 现金支付备注
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -700,29 +701,39 @@ async function getPaytype() {
|
||||
payTypes.sel = payTypes.list.findIndex((v) => v.payType == "cash");
|
||||
}
|
||||
}
|
||||
function nowPayClick(payType) {
|
||||
payType = payType || payTypes.list[payTypes.sel].payType;
|
||||
if (payType === "cash") {
|
||||
ElMessageBox.confirm("是否确认已现金收款:" + currentpayMoney.value + "元", "快捷支付", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
payOrder("cash");
|
||||
})
|
||||
.catch(() => { });
|
||||
return;
|
||||
}
|
||||
if (payType == "member-account") {
|
||||
if (!carts.vipUser.id) {
|
||||
return ElMessage.error("请先选择会员");
|
||||
}
|
||||
payOrder(payType);
|
||||
return;
|
||||
|
||||
const cashRemark = ref("");
|
||||
async function nowPayClick(payType) {
|
||||
if (carts.list.length) {
|
||||
await emits('createOrder', 'only-create')
|
||||
}
|
||||
|
||||
refScanPayOpen(payType);
|
||||
setTimeout(() => {
|
||||
payType = payType || payTypes.list[payTypes.sel].payType;
|
||||
if (payType === "cash") {
|
||||
ElMessageBox.prompt("是否确认已现金收款:" + currentpayMoney.value + "元", "快捷支付", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
inputPlaceholder: '请输入现金支付备注(选填)',
|
||||
})
|
||||
.then(({ value }) => {
|
||||
cashRemark.value = value || "";
|
||||
payOrder("cash");
|
||||
})
|
||||
.catch(() => { });
|
||||
return;
|
||||
}
|
||||
if (payType == "member-account") {
|
||||
if (!carts.vipUser.id) {
|
||||
return ElMessage.error("请先选择会员");
|
||||
}
|
||||
payOrder(payType);
|
||||
return;
|
||||
}
|
||||
|
||||
refScanPayOpen(payType);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
let authCode = "";
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
<el-form :rules="rules" ref="refForm" :model="form">
|
||||
<el-form-item label="转桌到" prop="targetTableCode">
|
||||
<el-select v-model="form.targetTableCode" placeholder="请选择转桌到" style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in tableList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.tableCode"
|
||||
></el-option>
|
||||
<el-option v-for="item in tableList" :key="item.id" :label="item.name" :value="item.tableCode"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="转入类型">
|
||||
@@ -59,6 +54,7 @@ const basicForm = {
|
||||
targetOrderId: "",
|
||||
targetTableCode: "",
|
||||
detailIds: [],
|
||||
allMerge: 0 // 是否全部转台
|
||||
};
|
||||
const form = reactive({
|
||||
...basicForm,
|
||||
@@ -120,6 +116,17 @@ function confirm() {
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
if (rottableType.value == 1) {
|
||||
form.allMerge = 1;
|
||||
} else {
|
||||
console.log('oldCartGoods.value===', oldCartGoods.value);
|
||||
const orderCount = Object.values(oldCartGoods.value).reduce((sum, arr) => {
|
||||
return sum + arr.length
|
||||
}, 0)
|
||||
form.allMerge = orderCount == detailIds.length ? 1 : 0
|
||||
}
|
||||
|
||||
emits(
|
||||
"confirm",
|
||||
{
|
||||
|
||||
@@ -41,13 +41,8 @@
|
||||
</div>
|
||||
|
||||
<div class="u-flex u-flex-wrap tags">
|
||||
<div
|
||||
class="tag"
|
||||
v-for="(tag, index) in tags"
|
||||
@click="changeSel(tag)"
|
||||
:key="index"
|
||||
:class="{ active: tag.checked }"
|
||||
>
|
||||
<div class="tag" v-for="(tag, index) in tags" @click="changeSel(tag)" :key="index"
|
||||
:class="{ active: tag.checked }">
|
||||
{{ tag.label }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,10 +59,15 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 退款退菜推库存的操作弹窗 -->
|
||||
<refundConsModal ref="refundConsModalRef" :list="refundList" @success="refundConsModalSuccess" />
|
||||
</template>
|
||||
<script>
|
||||
<script>
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useCartsStore } from '@/store/modules/carts'
|
||||
import refundConsModal from "@/components/refundConsModal.vue";
|
||||
export default {
|
||||
components: { refundConsModal },
|
||||
props: {
|
||||
modal: {
|
||||
type: Boolean,
|
||||
@@ -90,6 +90,9 @@ export default {
|
||||
goods: {
|
||||
productId: -999,
|
||||
},
|
||||
refundList: [],
|
||||
refundStock: '',
|
||||
note: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -132,34 +135,79 @@ export default {
|
||||
this.show = false;
|
||||
this.number = 1;
|
||||
},
|
||||
// 选择退库存模式后
|
||||
refundConsModalSuccess(e) {
|
||||
this.refundStock = e
|
||||
this.refundNext()
|
||||
},
|
||||
refundNext() {
|
||||
this.$emit("confirm", {
|
||||
refundReason: this.note,
|
||||
refundAmount: 0,
|
||||
refundDetails: [{ id: this.goods.id, num: this.number, returnAmount: 0 }],
|
||||
refundStock: this.refundStock
|
||||
});
|
||||
this.close();
|
||||
},
|
||||
// 确认退菜
|
||||
confirm() {
|
||||
const selTag = this.tags
|
||||
.filter((item) => item.checked)
|
||||
.map((item) => item.label)
|
||||
.join(",");
|
||||
const note = selTag + (this.note.length > 0 ? "," + this.note : "");
|
||||
console.log(note);
|
||||
if (!note) {
|
||||
this.note = selTag + (this.note.length > 0 ? "," + this.note : "");
|
||||
|
||||
if (!this.note) {
|
||||
return ElMessage.error("请输入退菜原因");
|
||||
}
|
||||
this.$emit("confirm", {
|
||||
refundReason: note,
|
||||
refundAmount: 0,
|
||||
refundDetails: [{ id: this.goods.id, num: this.number, returnAmount: 0 }],
|
||||
});
|
||||
this.close();
|
||||
|
||||
const carts = useCartsStore();
|
||||
let categorys = JSON.parse(localStorage.getItem('categorys'))
|
||||
let shopInfo = JSON.parse(localStorage.getItem('userInfo'))
|
||||
|
||||
// 在这里给订单的商品补全库存信息 start
|
||||
carts.goods.forEach(val => {
|
||||
if (this.goods.productId == val.id) {
|
||||
if (shopInfo.refundMode == 1) {
|
||||
// 跟随分类退款模式
|
||||
categorys.forEach(v => {
|
||||
if (val.categoryId == v.id) {
|
||||
this.goods.refundMode = v.refundMode
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 跟随商品退款模式及
|
||||
this.goods.refundMode = val.refundMode
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('this.goods===', this.goods);
|
||||
if (this.goods.refundMode == 3) {
|
||||
this.refundList = [
|
||||
{
|
||||
name: this.goods.product_name,
|
||||
num: this.number
|
||||
}
|
||||
]
|
||||
this.$refs.refundConsModalRef.show()
|
||||
return
|
||||
}
|
||||
// 在这里给订单的商品补全库存信息 end
|
||||
this.refundNext()
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() { },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
margin-bottom: 14px;
|
||||
margin-top: 14px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
:deep(.el-tag) {
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
@@ -169,6 +217,7 @@ export default {
|
||||
line-height: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
.tag {
|
||||
margin: 10px 10px 0 0;
|
||||
@@ -178,6 +227,7 @@ export default {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: #1890ff;
|
||||
background: #e8f4ff;
|
||||
@@ -185,10 +235,12 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.number-box .el-input__inner::-webkit-inner-spin-button) {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.number-box .el-input__inner::-webkit-outer-spin-button) {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
|
||||
@@ -84,10 +84,10 @@ export default {
|
||||
"https://zhyx.eingdong.com/qrcode/api.php?url=https%3A%2F%2Fzhyx.eingdong.com%2Fcopyright%2F%23%2Fpay%3Fid%3D139451580",
|
||||
pays: [
|
||||
{
|
||||
text: "主扫",
|
||||
text: "扫码收款",
|
||||
},
|
||||
{
|
||||
text: "被扫",
|
||||
text: "二维码收款",
|
||||
},
|
||||
],
|
||||
number: "0",
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
<div>
|
||||
<div class="u-flex">
|
||||
<div class="ft-13 color-000 no-wrap">{{ carts.vipUser.nickName }}</div>
|
||||
<div class="vip" v-if="carts.vipUser.isVip">{{ carts.vipUser.memberLevelName }}</div>
|
||||
<div class="vip" v-if="carts.vipUser.isVip">
|
||||
{{ carts.vipUser.memberLevelName }}
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 2px" class="no-wrap color-666 ft-12">
|
||||
余额:{{ carts.vipUser.amount }}
|
||||
@@ -41,7 +43,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<el-button>{{ carts.tableInfo.name ? "桌台号:" + carts.tableInfo.name : "选择桌号" }}</el-button>
|
||||
<el-button>
|
||||
{{ carts.tableInfo.name ? "桌台号:" + carts.tableInfo.name : "选择桌号" }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button type="warning" @click="refQuanHexiaoOpen">扫码验券</el-button>
|
||||
@@ -126,7 +130,7 @@
|
||||
</template>
|
||||
<!-- 订单信息展示 -->
|
||||
<Order ref="refOrder" :orderInfo="carts.oldOrder" @chooseUser="showChooseUser" @paysuccess="refresh"
|
||||
:table="carts.tableInfo" :perpole="perpole" v-else :user="user"></Order>
|
||||
:table="carts.tableInfo" :perpole="perpole" v-else :user="user" @create-order="createOrder"></Order>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,7 +218,9 @@ function rottableShow() {
|
||||
}
|
||||
async function rottableConfirm(form, cart_id) {
|
||||
carts.rotTable(form.targetTableCode, cart_id);
|
||||
const res = await orderApi.mergeOrder(form);
|
||||
if (form.detailIds.length) {
|
||||
await orderApi.mergeOrder(form);
|
||||
}
|
||||
ElNotification({
|
||||
title: "成功",
|
||||
message: "合并成功",
|
||||
@@ -246,7 +252,8 @@ async function refReturnCartConfirm(e) {
|
||||
if (res) {
|
||||
// 获取历史订单数据
|
||||
const res1 = await orderApi.getHistoryList({
|
||||
orderId: carts.oldOrder.id,
|
||||
// orderId: carts.oldOrder.id,
|
||||
tableCode: carts.table_code,
|
||||
});
|
||||
if (res1) {
|
||||
carts.setOldOrder(res1);
|
||||
@@ -354,7 +361,7 @@ async function createOrder(key) {
|
||||
placeNum: carts.oldOrder.placeNum * 1 + 1,
|
||||
waitCall: false,
|
||||
vipPrice: user.value.id && user.value.isVip,
|
||||
limitRate: carts.limitDiscountRes
|
||||
limitRate: carts.limitDiscountRes,
|
||||
});
|
||||
clearTimeout(loadingTimer);
|
||||
loading.close();
|
||||
@@ -370,7 +377,8 @@ async function createOrder(key) {
|
||||
if (res.id) {
|
||||
// 获取历史订单数据
|
||||
const res1 = await orderApi.getHistoryList({
|
||||
orderId: res.id,
|
||||
// orderId: carts.oldOrder.id,
|
||||
tableCode: carts.table_code,
|
||||
});
|
||||
if (res1) {
|
||||
carts.setOldOrder(res1);
|
||||
@@ -403,7 +411,8 @@ async function clearOldOrderCallback() {
|
||||
try {
|
||||
// 获取历史订单数据
|
||||
const res = await orderApi.getHistoryList({
|
||||
orderId: carts.oldOrder.id,
|
||||
// orderId: carts.oldOrder.id,
|
||||
tableCode: carts.table_code,
|
||||
});
|
||||
const noPayStatus = {
|
||||
cancelled: "订单已取消",
|
||||
@@ -415,16 +424,34 @@ async function clearOldOrderCallback() {
|
||||
showOrder.value = false;
|
||||
return;
|
||||
}
|
||||
if (res) {
|
||||
console.log("清空历史订单回调", res);
|
||||
|
||||
if (res.data !== null) {
|
||||
console.log("还有历史订单数据");
|
||||
carts.setOldOrder(res);
|
||||
} else {
|
||||
console.log("历史订单没数据了");
|
||||
carts.oldOrder = {
|
||||
detailMap: [],
|
||||
originAmount: 0,
|
||||
};
|
||||
carts.setOldOrder({
|
||||
detailMap: [],
|
||||
originAmount: 0,
|
||||
});
|
||||
// carts.clearHistory();
|
||||
// resetOldOrder();
|
||||
}
|
||||
carts.clearOldOrderCallback = false;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
carts.clearOldOrderCallback = false;
|
||||
}
|
||||
}
|
||||
// 取消历史订单
|
||||
async function clearOldOrder(params) {
|
||||
try {
|
||||
carts.isClearingOldOrder = true;
|
||||
const res1 = params.placeNum
|
||||
? await orderApi.rmPlaceOrder(params)
|
||||
: await orderApi.cancelOrder(params);
|
||||
@@ -510,7 +537,7 @@ async function tableClick(item) {
|
||||
carts.setOldOrder(res);
|
||||
}
|
||||
table.value = item;
|
||||
carts.changeTableInfo(item)
|
||||
carts.changeTableInfo(item);
|
||||
carts.changeTable(item.tableCode);
|
||||
refTable.value.hide();
|
||||
}
|
||||
@@ -638,6 +665,7 @@ function getCategoryList() {
|
||||
size: 200,
|
||||
})
|
||||
.then((res) => {
|
||||
localStorage.setItem('categorys', JSON.stringify(res))
|
||||
res.unshift({ name: "全部", id: "" });
|
||||
category.list = res;
|
||||
});
|
||||
@@ -730,12 +758,20 @@ function clearCarts() {
|
||||
});
|
||||
}
|
||||
function addCarts(item, isWeight = false) {
|
||||
console.log('index.addCarts===', item);
|
||||
console.log("index.addCarts===", item);
|
||||
if (isWeight) {
|
||||
carts.add({ pack_number: diners.sel ? 1 : 0, ...item, is_time_discount: item.isLimitDiscount ? 1 : 0 });
|
||||
carts.add({
|
||||
pack_number: diners.sel ? 1 : 0,
|
||||
...item,
|
||||
is_time_discount: item.isLimitDiscount ? 1 : 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
carts.add({ pack_number: diners.sel ? item.number : 0, ...item, is_time_discount: item.isLimitDiscount ? 1 : 0 });
|
||||
carts.add({
|
||||
pack_number: diners.sel ? item.number : 0,
|
||||
...item,
|
||||
is_time_discount: item.isLimitDiscount ? 1 : 0,
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
@@ -748,7 +784,7 @@ function init() {
|
||||
getTableList();
|
||||
getCategoryList();
|
||||
changeCartsDinerType();
|
||||
carts.init({ table_code: carts.tableInfo.tableCode }, carts.oldOrder);
|
||||
carts.init({ table_code: carts.tableInfo.tableCode });
|
||||
}
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
@@ -760,13 +796,24 @@ onMounted(async () => {
|
||||
const { id, tableCode, key } = route.query;
|
||||
if (id || tableCode) {
|
||||
// 获取历史订单数据
|
||||
const res = id
|
||||
? await orderApi.getHistoryList({
|
||||
// const res = id
|
||||
// ? await orderApi.getHistoryList({
|
||||
// orderId: id,
|
||||
// })
|
||||
// : await orderApi.getHistoryList({
|
||||
// tableCode,
|
||||
// });
|
||||
let res = ''
|
||||
if (id) {
|
||||
res = await orderApi.getHistoryList({
|
||||
orderId: id,
|
||||
})
|
||||
: await orderApi.getHistoryList({
|
||||
tableCode,
|
||||
} else {
|
||||
res = await orderApi.getHistoryList({
|
||||
tableCode: carts.table_code,
|
||||
});
|
||||
}
|
||||
|
||||
const noPayStatus = {
|
||||
cancelled: "订单已取消",
|
||||
done: "订单已关闭",
|
||||
@@ -783,7 +830,7 @@ onMounted(async () => {
|
||||
}
|
||||
if (res.tableCode) {
|
||||
table.value = { tableCode: res.tableCode };
|
||||
carts.changeTableInfo(res)
|
||||
carts.changeTableInfo(res);
|
||||
}
|
||||
if (res.userId) {
|
||||
const userRes = await shopUserApi.get({ userId: res.userId });
|
||||
@@ -795,10 +842,12 @@ onMounted(async () => {
|
||||
const tableRes = await tableApi.get({ tableCode: res.tableCode });
|
||||
if (tableRes.tableCode) {
|
||||
table.value = tableRes || {};
|
||||
carts.changeTableInfo(tableRes)
|
||||
carts.changeTableInfo(tableRes);
|
||||
}
|
||||
}
|
||||
if (res) {
|
||||
console.log("res31231231331-=====--", res);
|
||||
|
||||
carts.setOldOrder(res);
|
||||
showOrder.value = key == "isPayOrder" ? true : false;
|
||||
perpole.value = res.seatNum || 0;
|
||||
@@ -808,7 +857,7 @@ onMounted(async () => {
|
||||
const tableRes = await tableApi.get({ tableCode: tableCode });
|
||||
if (tableRes.tableCode) {
|
||||
table.value = tableRes || {};
|
||||
carts.changeTableInfo(tableRes)
|
||||
carts.changeTableInfo(tableRes);
|
||||
}
|
||||
}
|
||||
console.log(table.value);
|
||||
@@ -857,7 +906,7 @@ function refresh() {
|
||||
showOrder.value = false;
|
||||
user.value = {};
|
||||
table.value = {};
|
||||
carts.changeTableInfo({})
|
||||
carts.changeTableInfo({});
|
||||
router.replace(route.path);
|
||||
carts.dataReset();
|
||||
carts.init();
|
||||
@@ -1116,4 +1165,4 @@ $pl: 30px;
|
||||
margin-left: 10px;
|
||||
font-size: 10px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -40,15 +40,25 @@
|
||||
</el-button> -->
|
||||
</div>
|
||||
|
||||
<div class="u-flex u-p-b-15 u-font-14 u-m-t-16">
|
||||
<div v-for="(item, key) in status" :key="key" class="state u-m-r-24">
|
||||
<span
|
||||
class="dot"
|
||||
:style="{
|
||||
backgroundColor: status[key] ? status[key].type : '',
|
||||
}"
|
||||
/>
|
||||
{{ item.label }}
|
||||
<div class="u-flex" style="justify-content: space-between">
|
||||
<div class="u-flex u-p-b-15 u-font-14 u-m-t-16">
|
||||
<div v-for="(item, key) in status" :key="key" class="state u-m-r-24">
|
||||
<span
|
||||
class="dot"
|
||||
:style="{
|
||||
backgroundColor: status[key] ? status[key].type : '',
|
||||
}"
|
||||
/>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div style="color: #3f9eff; font-weight: 700; padding-right: 30px">
|
||||
<span style="color: #333; font-weight: 400">未结账:</span>
|
||||
<span>{{ totalOrder }}笔</span>
|
||||
<span>|</span>
|
||||
<span>{{ totalPerson }}人</span>
|
||||
<span>|</span>
|
||||
<span>¥{{ totalMoney }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -252,6 +262,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import status from "./status.js";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
const shopUser = useUserStore();
|
||||
@@ -362,7 +373,7 @@ function addTableShow(item) {
|
||||
const tableList = ref([]);
|
||||
const tablequery = reactive({
|
||||
page: 1,
|
||||
size: 100,
|
||||
size: 300,
|
||||
});
|
||||
|
||||
async function tableInit() {
|
||||
@@ -370,6 +381,35 @@ async function tableInit() {
|
||||
tableList.value = res.records;
|
||||
}
|
||||
|
||||
const totalOrder = computed(() => {
|
||||
return tableList.value.reduce((pre, cur) => {
|
||||
if (cur.status == "unsettled") {
|
||||
return pre + 1;
|
||||
}
|
||||
return pre;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
const totalPerson = computed(() => {
|
||||
return tableList.value.reduce((pre, cur) => {
|
||||
if (cur.status == "unsettled") {
|
||||
return pre + cur.personNum;
|
||||
}
|
||||
return pre;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
const totalMoney = computed(() => {
|
||||
return tableList.value
|
||||
.reduce((pre, cur) => {
|
||||
if (cur.status == "unsettled") {
|
||||
return pre + cur.orderAmount;
|
||||
}
|
||||
return pre;
|
||||
}, 0)
|
||||
.toFixed(2);
|
||||
});
|
||||
|
||||
// 区域
|
||||
let areaMap = ref({});
|
||||
const refAddEara = ref(null);
|
||||
|
||||
@@ -8,13 +8,18 @@
|
||||
// adminIn 管理员充值
|
||||
// adminOut管理员消费
|
||||
export const $bizCode = {
|
||||
cashIn: "现金充值",
|
||||
cashIn: "会员充值",
|
||||
cashback: "消费返现",
|
||||
cashback_refund: "消费返现扣减",
|
||||
freeIn: "霸王餐充值",
|
||||
awardIn: "充值奖励",
|
||||
wechatIn: "微信小程序充值",
|
||||
alipayIn: "支付宝小程序充值",
|
||||
awardIn: "充值奖励",
|
||||
rechargeRefund: "充值退款",
|
||||
orderPay: "订单消费",
|
||||
orderPay: "订单支付奖励",
|
||||
orderRefund: "订单退款",
|
||||
adminIn: "管理员充值",
|
||||
adminOut: "管理员消费",
|
||||
rechargeRefund: "充值退款",
|
||||
rechargeCashRefund: "会员现金退款",
|
||||
adminIn: "管理员手动增减余额",
|
||||
adminOut: "管理员退款充值",
|
||||
rechargeRedemption: "充值兑换码"
|
||||
}
|
||||
@@ -29,8 +29,11 @@
|
||||
</div>
|
||||
<!-- 列表 -->
|
||||
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
|
||||
@edit-click="handleEditClick" @export-click="handleExportClick" @search-click="handleSearchClick"
|
||||
@edit-click="handleEditClick" @export-click="handleExportClick" @upload-click="" @search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick" @operat-click="handleOperatClick" @filter-change="handleFilterChange">
|
||||
<template #custom>
|
||||
<importData ref="importDataRef" :type="6" @close="searchQueryClick" />
|
||||
</template>
|
||||
<template #status="scope">
|
||||
<el-link :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
@@ -146,6 +149,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import importData from "@/components/importData/index.vue";
|
||||
import UserCouponDialog from "./components/user-coupon-dialog.vue";
|
||||
import GiveCoupon from "./components/give-coupon.vue";
|
||||
import usePage from "@/components/CURD/usePage";
|
||||
@@ -159,6 +163,7 @@ import shopUserApi from "@/api/account/shopUser";
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { downloadFile } from "@/utils/index";
|
||||
|
||||
const editMoneyModalRef = ref(null);
|
||||
const userCouponDialogRef = ref(null);
|
||||
const GiveCouponRef = ref(null);
|
||||
@@ -250,6 +255,8 @@ function handleToolbarClick(name) {
|
||||
console.log(name);
|
||||
if (name === "custom1") {
|
||||
ElMessage.success("点击了自定义1按钮");
|
||||
} else if (name === "upload") {
|
||||
importDataRef.value.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ import { name, version, engines, dependencies, devDependencies } from "./package
|
||||
|
||||
import stripCode from 'vite-plugin-strip-code'; // 导入插件
|
||||
|
||||
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// 平台的名称、版本、运行所需的 node 版本、依赖、构建时间的类型提示
|
||||
const __APP_INFO__ = {
|
||||
pkg: { name, version, engines, dependencies, devDependencies },
|
||||
@@ -54,6 +57,13 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
target: env.VITE_APP_API_URL,
|
||||
rewrite: (path) => path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
|
||||
},
|
||||
// 代理 /dev-api 的请求
|
||||
'/import_api': {
|
||||
changeOrigin: true,
|
||||
// 代理目标地址:https://api.youlai.tech
|
||||
target: env.VITE_APP_API_PHP_IMPORT_URL,
|
||||
rewrite: (path) => path.replace(new RegExp("^" + env.VITE_APP_API_PHP_IMPORT_URL), ""),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
@@ -107,7 +117,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
// 注意:标记可以自定义,只要前后一致即可
|
||||
start_comment: 'DEV-START', // 开始标记(自定义)
|
||||
end_comment: 'DEV-END' // 结束标记(自定义)
|
||||
})
|
||||
}),
|
||||
// vueDevTools()
|
||||
],
|
||||
// 预加载项目必需的组件
|
||||
optimizeDeps: {
|
||||
|
||||