Compare commits

25 Commits
master ... gyq

Author SHA1 Message Date
gyq
81b15c1afe 优化订单显示 2024-03-19 14:14:28 +08:00
gyq
3159d0b459 1.商品列表 添加分组 选择商品优化
2.订单列表修复详情没有规格
2024-03-18 15:40:35 +08:00
gyq
5ea9e7951f 新增订单详情 2024-03-16 17:47:15 +08:00
gyq
7d9e42ddef 优化库存数量不能修改 2024-03-15 09:00:24 +08:00
gyq
0998c30b1a 新增订单列表对接数据 2024-03-14 16:00:19 +08:00
gyq
87d084dfed 优化添加商品问题 新增添加设备 2024-03-13 09:05:08 +08:00
gyq
d0f69f9eb9 优化 2024-03-11 09:31:34 +08:00
gyq
273e20cccc 优化分类 2024-03-08 15:04:38 +08:00
gyq
bf60ee88e2 1.优化编辑商品规格选择,只能重新添加 2.优化商品列表新增字段shopid 3.修复添加商品图片不生效 4.修复用户登录404 2024-03-06 17:01:47 +08:00
gyq
799ee9a5b5 新增添加支付方式类型枚举 2024-03-04 15:53:44 +08:00
gyq
0c795bee95 支付方式新增图标 2024-03-02 16:10:03 +08:00
gyq
51f0c8233d 增加线上接口 2024-03-01 16:15:02 +08:00
gyq
08e7939a9f 新增支付方式添加与修改 2024-02-29 09:20:10 +08:00
gyq
43d33bdfe1 对接商家详情 2024-02-28 15:01:42 +08:00
gyq
435ca0ab6e 优化 2024-02-26 16:17:11 +08:00
gyq
889919f2fc 新增添加店铺、添加激活码 2024-02-23 18:29:40 +08:00
gyq
36f24888ba 优化 2024-02-08 18:42:02 +08:00
gyq
b31f6494b5 新增桌台 2024-02-06 15:23:47 +08:00
gyq
259aec07cd 新增桌台管理 2024-02-01 12:11:10 +08:00
gyq
640e3bb941 新增退货进账模块 2024-01-29 14:03:25 +08:00
gyq
122b979045 新增商品库存 2024-01-24 12:20:58 +08:00
gyq
966ef627bb 新增商品增加与编辑 2024-01-21 18:29:18 +08:00
gyq
26425e7f57 新增商品分组 2024-01-16 17:24:35 +08:00
gyq
6e62895adb 1.新增单位,规格 2024-01-10 14:58:57 +08:00
gyq
6b83cf4c84 新增店铺设置 2024-01-08 14:50:25 +08:00
81 changed files with 9497 additions and 835 deletions

View File

@@ -1,7 +1,11 @@
ENV = 'development' ENV = 'development'
# 接口地址 # 接口地址
VUE_APP_BASE_API = 'http://192.168.2.128:8000' # VUE_APP_BASE_API = 'http://192.168.2.128:8000' // 刘一帆
# VUE_APP_BASE_API = 'https://405465h7n2.vicp.fun ' // 公司测试
# VUE_APP_BASE_API = 'http://192.168.2.96:8000' // 阿伟
VUE_APP_BASE_API = 'https://cashieradmin.sxczgkj.cn'
# VUE_APP_BASE_API = 'http://192.168.2.16:8000'
VUE_APP_WS_API = 'ws://192.168.2.128:8000' VUE_APP_WS_API = 'ws://192.168.2.128:8000'
# 是否启用 babel-plugin-dynamic-import-node插件 # 是否启用 babel-plugin-dynamic-import-node插件

View File

@@ -2,6 +2,7 @@ ENV = 'production'
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇Nginx 配置 # 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇Nginx 配置
# 接口地址,注意协议,如果你没有配置 ssl需要将 https 改为 http # 接口地址,注意协议,如果你没有配置 ssl需要将 https 改为 http
VUE_APP_BASE_API = 'api' VUE_APP_BASE_API = 'https://cashieradmin.sxczgkj.cn'
# VUE_APP_BASE_API = 'http://192.168.2.98:8000'
# 如果接口是 http 形式, wss 需要改为 ws # 如果接口是 http 形式, wss 需要改为 ws
VUE_APP_WS_API = 'wss://123.56.110.252 VUE_APP_WS_API = 'wss://123.56.110.252

BIN
dist.zip Normal file

Binary file not shown.

View File

@@ -14,7 +14,6 @@
"svgo": "svgo -f src/assets/icons/svg --config=src/assets/icons/svgo.yml", "svgo": "svgo -f src/assets/icons/svg --config=src/assets/icons/svgo.yml",
"new": "plop", "new": "plop",
"dev_t": "set NODE_OPTIONS=\"--openssl-legacy-provider\" & npm run dev\n" "dev_t": "set NODE_OPTIONS=\"--openssl-legacy-provider\" & npm run dev\n"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -29,6 +28,7 @@
"clipboard": "2.0.4", "clipboard": "2.0.4",
"codemirror": "^5.49.2", "codemirror": "^5.49.2",
"core-js": "^2.6.12", "core-js": "^2.6.12",
"dayjs": "^1.11.10",
"echarts": "^4.2.1", "echarts": "^4.2.1",
"echarts-wordcloud": "^1.1.3", "echarts-wordcloud": "^1.1.3",
"element-ui": "^2.15.8", "element-ui": "^2.15.8",
@@ -47,11 +47,13 @@
"screenfull": "4.2.0", "screenfull": "4.2.0",
"sortablejs": "1.8.4", "sortablejs": "1.8.4",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-amap": "^0.5.10",
"vue-clipboard2": "^0.3.3",
"vue-count-to": "^1.0.13", "vue-count-to": "^1.0.13",
"vue-cropper": "0.4.9", "vue-cropper": "0.4.9",
"vue-echarts": "^5.0.0-beta.0", "vue-echarts": "^5.0.0-beta.0",
"vue-ele-upload-image": "^2.0.12", "vue-ele-upload-image": "^2.0.12",
"vue-image-crop-upload": "^2.5.0", "vue-image-crop-upload": "^3.0.3",
"vue-material": "^1.0.0-beta-15", "vue-material": "^1.0.0-beta-15",
"vue-router": "3.0.2", "vue-router": "3.0.2",
"vue-splitpane": "1.0.4", "vue-splitpane": "1.0.4",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -7,6 +7,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title> <title><%= webpackConfig.name %></title>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: "0547b69252ef0ed14e11f5c4ac152f07",
}
</script>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -9,3 +9,125 @@ export default {
name: 'App' name: 'App'
} }
</script> </script>
<style lang="scss">
/*定义滚动条高宽及背景
高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar {
width: 4px;
}
/*定义滚动条轨道
内阴影+圆角*/
::-webkit-scrollbar-track {
background-color: #F5F5F5;
}
/*定义滑块
内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: #d3d3d3;
}
.tips {
color: #999;
}
.img_error {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.icon {
font-size: 20px;
color: #999;
}
}
.filter_wrap {
display: flex;
align-items: center;
gap: 10px;
}
.shop_type_box {
display: flex;
&.disabled {
.item {
background-color: #f9f9f9;
&:hover {
cursor: not-allowed;
}
&.active {
border-color: #ececec;
}
.active_dot {
background-color: #ececec;
}
.s_title {
color: #999;
}
}
}
.item {
$borderColor: #1890FF;
margin-right: 14px;
border: 1px solid #ececec;
border-radius: 4px;
padding: 6px 24px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
&:hover {
cursor: pointer;
}
&.active {
border-color: $borderColor;
.active_dot {
display: flex;
}
}
.active_dot {
$size: 26px;
background-color: $borderColor;
color: #fff;
position: absolute;
top: 0;
right: 0;
width: $size;
height: $size;
clip-path: polygon(100% 0, 0 0, 100% 100%);
display: none;
justify-content: flex-end;
padding-right: 2px;
}
.s_title {
font-weight: bold;
color: #555;
}
.intro {
color: #999;
font-size: 12px;
margin-top: -10px;
}
}
}
</style>

32
src/api/devices.js Normal file
View File

@@ -0,0 +1,32 @@
import request from '@/utils/request'
/**
* 增加打印机
* @returns
*/
export function tbPrintMachine(data, method = 'post') {
return request({
url: '/api/tbPrintMachine',
method: method,
data: {
shopId: localStorage.getItem('shopId'),
...data
}
})
}
/**
* 打印机列表
* @returns
*/
export function tbPrintMachineGet(params) {
return request({
url: '/api/tbPrintMachine',
method: 'get',
params: {
shopId: localStorage.getItem('shopId'),
sort: '',
...params
}
})
}

92
src/api/home.js Normal file
View File

@@ -0,0 +1,92 @@
import request from '@/utils/request'
/**
* 汇总数据
* @returns
*/
export function summaryGet() {
return request({
url: '/api/summary',
method: 'get',
params: {
shopId: localStorage.getItem('shopId')
}
})
}
/**
* 今日数据
* @returns
*/
export function summaryTodayGet() {
return request({
url: '/api/summary/today',
method: 'get',
params: {
shopId: localStorage.getItem('shopId')
}
})
}
/**
* 今日数据
* @returns
*/
export function summaryDateGet(day) {
return request({
url: '/api/summary/date',
method: 'get',
params: {
shopId: localStorage.getItem('shopId'),
day: day
}
})
}
/**
* 销售额柱状图
* @returns
*/
export function dateAmount(day) {
return request({
url: '/api/summary/dateAmount',
method: 'get',
params: {
shopId: localStorage.getItem('shopId'),
day: day
}
})
}
/**
* 商品销售排行
* @returns
*/
export function dateProduct(day, page, size) {
return request({
url: '/api/summary/dateProduct',
method: 'get',
params: {
shopId: localStorage.getItem('shopId'),
day: day,
page: page,
size: size
}
})
}
/**
* 支付类型占比
* @returns
*/
export function datePayType(day) {
return request({
url: '/api/summary/datePayType',
method: 'get',
params: {
shopId: localStorage.getItem('shopId'),
day: day
}
})
}

146
src/api/invoicing.js Normal file
View File

@@ -0,0 +1,146 @@
import request from '@/utils/request'
/**
* 商品列表
* @returns
*/
export function tbProductGet(params) {
return request({
url: '/api/tbProduct',
method: 'get',
params
})
}
/**
* 进销存类型字典
* @returns
*/
export function dictDetail(params) {
return request({
url: `/api/dictDetail`,
method: 'get',
params
})
}
/**
* 库存记录列表
* @returns
*/
export function tbProductStockDetail(data) {
return request({
url: `/api/tbProductStockDetail/stock`,
method: 'post',
data
})
}
/**
* 变动数量
* @returns
*/
export function tbProductStockDetailSum(params) {
return request({
url: `/api/tbProductStockDetail/sum`,
method: 'get',
params
})
}
/**
* 供应商列表
* @returns
*/
export function tbShopPurveyorGet(params) {
return request({
url: `/api/tbShopPurveyor`,
method: 'get',
params
})
}
/**
* 增加供应商
* @returns
*/
export function tbShopPurveyor(data, method = 'post') {
return request({
url: `/api/tbShopPurveyor`,
method: method,
data
})
}
/**
* 进货/退货账目
* @returns
*/
export function tbShopPurveyorTransactGet(params) {
return request({
url: `/api/tbShopPurveyorTransact`,
method: 'get',
params
})
}
/**
* 进货账目详情
* @returns
*/
export function tbShopPurveyorTransactInfo(data) {
return request({
url: `/api/tbShopPurveyorTransact/info`,
method: 'post',
data
})
}
/**
* 进货账目汇总(单一供应商)
* @returns
*/
export function tbShopPurveyorTransactSum(params) {
return request({
url: `/api/tbShopPurveyorTransact/sum`,
method: 'get',
params
})
}
/**
* 操作记录
* @returns
*/
export function tbProductStockOperateList(data) {
return request({
url: `/api/tbProductStockOperate/list`,
method: 'post',
data
})
}
/**
* 操作记录详情
* @returns
*/
export function tbProductStockOperateDetail(id) {
return request({
url: `/api/tbProductStockOperate/${id}`,
method: 'get'
})
}
/**
* 操作出库/入库
* @returns
*/
export function tbProductStockOperateOutAndOn(data) {
return request({
url: `/api/tbProductStockOperate/outAndOn`,
method: 'post',
data
})
}

61
src/api/order.js Normal file
View File

@@ -0,0 +1,61 @@
import request from '@/utils/request'
/**
* 查询订单
* @param {*} data
* @returns
*/
export function tbOrderInfoData(data) {
return request({
url: '/api/tbOrderInfo/date',
method: 'post',
data: {
shopId: localStorage.getItem('shopId'),
...data
}
})
}
/**
* 导出数据
* @param {*} data
* @returns
*/
export function tbOrderInfoDownload(data) {
return request({
url: '/api/tbOrderInfo/download',
method: 'post',
data: {
shopId: localStorage.getItem('shopId'),
...data
},
responseType: 'blob'
})
}
/**
* 通过Id查询订单
* @param {*} id
* @returns
*/
export function tbOrderInfoDetail(id) {
return request({
url: `/api/tbOrderInfo/${id}`,
method: 'get'
})
}
/**
* 通过Id查询订单
* @param {*} id
* @returns
*/
export function payCount() {
return request({
url: `/api/tbOrderInfo/payCount`,
method: 'get',
params: {
shopId: localStorage.getItem('shopId')
}
})
}

25
src/api/setting.js Normal file
View File

@@ -0,0 +1,25 @@
import request from '@/utils/request'
/**
* 支付方式
* @returns
*/
export function tbShopPayTypeGet(params) {
return request({
url: '/api/tbShopPayType',
method: 'get',
params
})
}
/**
* 更改/增加支付方式
* @returns
*/
export function tbShopPayType(data, method = 'post') {
return request({
url: '/api/tbShopPayType',
method: method,
data
})
}

View File

@@ -11,3 +11,351 @@ export function tbProduct(params) {
params params
}) })
} }
/**
* 删除商品
* @returns
*/
export function tbProductDelete(data) {
return request({
url: '/api/tbProduct',
method: 'delete',
data
})
}
/**
* 商品单位列表
* @returns
*/
export function tbShopUnit(params) {
return request({
url: '/api/tbShopUnit',
method: 'get',
params
})
}
/**
* 店铺基本配置
* @returns
*/
export function tbShopCurrency(shopId) {
return request({
url: `/api/tbShopCurrency/${shopId}`,
method: 'get'
})
}
/**
* 修改店铺信息
* @returns
*/
export function tbShopCurrencyPut(data) {
return request({
url: `/api/tbShopCurrency`,
method: 'put',
data
})
}
/**
* 新增单位
* @returns
*/
export function tbShopUnitPost(data) {
return request({
url: `/api/tbShopUnit`,
method: 'post',
data
})
}
/**
* 更改单位
* @returns
*/
export function tbShopUnitPut(data) {
return request({
url: `/api/tbShopUnit`,
method: 'put',
data
})
}
/**
* 删除单位
* @returns
*/
export function tbShopUnitDelete(data) {
return request({
url: `/api/tbShopUnit`,
method: 'delete',
data
})
}
/**
* 店铺基本配置
* @returns
*/
export function tbShopCurrencyGet(params) {
return request({
url: `/api/tbShopUnit`,
method: 'get',
params
})
}
/**
* 商品分类列表
* @returns
*/
export function tbShopCategoryGet(params) {
return request({
url: `/api/tbShopCategory`,
method: 'get',
params
})
}
/**
* 新增、编辑分类/新增、编辑子分类
* @returns
*/
export function tbShopCategoryPost(data, method = 'post') {
return request({
url: `/api/tbShopCategory`,
method: method,
data
})
}
/**
* 删除商品分类
* @returns
*/
export function tbShopCategoryDelete(data) {
return request({
url: `/api/tbShopCategory`,
method: 'delete',
data
})
}
/**
* 规格增加
* @returns
*/
export function tbProductSpecPost(data) {
return request({
url: `/api/tbProductSpec`,
method: 'post',
data
})
}
/**
* 规格列表
* @returns
*/
export function tbProductSpecGet(params) {
return request({
url: `/api/tbProductSpec`,
method: 'get',
params
})
}
/**
* 规格更改
* @returns
*/
export function tbProductSpecPut(data) {
return request({
url: `/api/tbProductSpec`,
method: 'put',
data
})
}
/**
* 删除规格
* @returns
*/
export function tbProductSpecDelete(data) {
return request({
url: `/api/tbProductSpec`,
method: 'DELETE',
data
})
}
/**
* 新增分组
* @returns
*/
export function tbProductGroupPost(data) {
return request({
url: `/api/tbProductGroup`,
method: 'post',
data
})
}
/**
* 更改分组
* @returns
*/
export function tbProductGroupPut(data) {
return request({
url: `/api/tbProductGroup`,
method: 'PUT',
data
})
}
/**
* 商品分组列表
* @returns
*/
export function tbProductGroupGet(params) {
return request({
url: `/api/tbProductGroup`,
method: 'get',
params
})
}
/**
* 商品列表根据分组中的商品id
* @returns
*/
export function productListGet(productGroup) {
return request({
url: `/api/tbProductGroup/${productGroup}`,
method: 'get'
})
}
/**
* 删除分组
* @returns
*/
export function tbProductGroupDelete(data) {
return request({
url: `/api/tbProductGroup`,
method: 'DELETE',
data
})
}
/**
* 添加商品
* @returns
*/
export function tbProductPost(data) {
return request({
url: `/api/tbProduct`,
method: 'post',
data
})
}
/**
* 添加商品
* @returns
*/
export function tbProductPut(data) {
return request({
url: `/api/tbProduct`,
method: 'put',
data
})
}
/**
* 商品详情(单个商品)
* product 商品id
* @returns
*/
export function tbProductGetDetail(product) {
return request({
url: `/api/tbProduct/${product}`,
method: 'get'
})
}
/**
* 店铺列表
* @returns
*/
export function tbShopInfo(params) {
return request({
url: `/api/tbShopInfo`,
method: 'get',
params
})
}
/**
* 增加激活码
* @returns
*/
export function tbMerchantRegisterPost(data) {
return request({
url: `/api/tbMerchantRegister`,
method: 'post',
data
})
}
/**
* 激活码列表
* @returns
*/
export function tbMerchantRegisterList(data) {
return request({
url: `/api/tbMerchantRegister/list`,
method: 'post',
data
})
}
/**
* 增加/编辑店铺
* @returns
*/
export function tbShopInfoPost(data, method = 'post') {
return request({
url: `/api/tbShopInfo`,
method: method,
data
})
}
/**
* 详情(配置三方支付)
* @returns
*/
export function tbMerchantThirdApply(shopId) {
return request({
url: `/api/tbMerchantThirdApply/${shopId}`,
method: 'get'
})
}
/**
* 修改第三方配置
* @returns
*/
export function tbMerchantThirdApplyPut(data) {
return request({
url: `/api/tbMerchantThirdApply`,
method: 'put',
data
})
}

76
src/api/table.js Normal file
View File

@@ -0,0 +1,76 @@
// 桌台管理
import request from '@/utils/request'
/**
* 台桌列表
* @returns
*/
export function tbShopTableGet(params) {
return request({
url: `/api/tbShopTable`,
method: 'get',
params
})
}
/**
* 区域
* @returns
*/
export function tbShopAreaGet(params) {
return request({
url: `/api/tbShopArea`,
method: 'get',
params
})
}
/**
* 增加区域
* @returns
*/
export function tbShopArea(data, method) {
return request({
url: `/api/tbShopArea`,
method: method,
data
})
}
/**
* 删除区域
* @returns
*/
export function tbShopAreaDelete(data) {
return request({
url: `/api/tbShopArea`,
method: 'DELETE',
data
})
}
/**
* 增加台桌
* @returns
*/
export function tbShopTable(data, method) {
return request({
url: `/api/tbShopTable`,
method: method,
data
})
}
/**
* 删除台桌
* @returns
*/
export function tbShopTableDelete(data) {
return request({
url: `/api/tbShopTable`,
method: 'DELETE',
data
})
}

24
src/api/user.js Normal file
View File

@@ -0,0 +1,24 @@
import request from '@/utils/request'
/**
* 用户详情
* @returns
*/
export function tbShopInfo(shopId) {
return request({
url: `/api/tbShopInfo/${shopId}`,
method: 'get'
})
}
/**
* 修改店铺信息
* @returns
*/
export function tbShopInfoPut(data) {
return request({
url: `/api/tbShopInfo`,
method: 'put',
data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

View File

@@ -1,5 +1,5 @@
.head-container { .head-container {
padding-bottom: 10px; padding-bottom: 20px;
.filter-item { .filter-item {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;

View File

@@ -1,23 +1,23 @@
// base color // base color
$blue:#324157; $blue: #324157;
$light-blue:#3A71A8; $light-blue: #3a71a8;
$red:#C03639; $red: #c03639;
$pink: #E65D6E; $pink: #e65d6e;
$green: #30B08F; $green: #30b08f;
$tiffany: #4AB7BD; $tiffany: #4ab7bd;
$yellow:#FEC171; $yellow: #fec171;
$panGreen: #30B08F; $panGreen: #30b08f;
// sidebar // sidebar
$menuText:#bfcbd9; $menuText: #bfcbd9;
$menuActiveText:#409EFF; $menuActiveText: #409eff;
$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951 $subMenuActiveText: #f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156; $menuBg: #333;
$menuHover:#263445; $menuHover: #444;
$subMenuBg:#1f2d3d; $subMenuBg: #444;
$subMenuHover:#001528; $subMenuHover: #555;
$sideBarWidth: 205px; $sideBarWidth: 205px;

View File

@@ -0,0 +1,122 @@
<template>
<el-dialog title="选择分类" :visible.sync="dialogVisible">
<div class="list" v-loading="loading">
<div class="row" v-for="(item, index) in categorys" :key="item.id">
<div class="list_title">{{ item.name }}</div>
<div class="item_wrap">
<el-button :type="item.active ? 'primary' : ''" @click="selectHandle(item)">全部</el-button>
<el-button :type="val.active ? 'primary' : ''" v-for="val in item.childrenList" :key="val.id"
@click="selectHandle(val, index)">{{
val.name }}</el-button>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopCategoryGet } from '@/api/shop'
export default {
data() {
return {
dialogVisible: false,
loading: false,
categorys: []
}
},
mounted() {
this.tbShopCategoryGet()
},
methods: {
// 确认选择分类
onSubmitHandle() {
let categorys = []
for (let item of this.categorys) {
if (item.active) {
categorys.push({
name: `${item.name}`,
id: item.id
})
}
if (item.childrenList.length) {
for (let val of item.childrenList) {
if (val.active) {
categorys.push({
name: `${val.name}`,
id: val.id
})
}
}
}
}
this.$emit('success', categorys)
this.dialogVisible = false
},
// 选择分类
selectHandle(item, index = -1) {
console.log(item, index)
if (index != -1) {
this.categorys[index].active = false
} else {
item.childrenList.map(item => {
item.active = false
})
}
item.active = !item.active
},
// 获取分类
async tbShopCategoryGet() {
try {
this.loading = true
const res = await tbShopCategoryGet({
shopId: localStorage.getItem('shopId'),
sort: 'sort,desc',
page: 0,
size: 500
})
res.content.map(item => {
item.active = false
item.childrenList.map(item => {
item.active = false
})
})
this.categorys = res.content
setTimeout(() => {
this.loading = false
}, 300);
} catch (error) {
console.log(error)
this.loading = false
}
},
show() {
this.dialogVisible = true
this.tbShopCategoryGet()
}
}
}
</script>
<style scoped lang="scss">
.list {
min-height: 200px;
.row {
padding-bottom: 20px;
.list_title {
color: #999;
padding-bottom: 10px;
}
.item_wrap {
display: flex;
}
}
}
</style>

View File

@@ -0,0 +1,178 @@
<template>
<el-dialog title="选择商品" :visible.sync="dialogVisible" @open="resetHandle()">
<el-form :model="searhForm" inline>
<el-form-item>
<el-input v-model="searhForm.name" placeholder="商品名称"></el-input>
</el-form-item>
<el-form-item>
<el-select v-model="searhForm.category" placeholder="商品分类">
<el-option :label="item.name" :value="item.id" v-for="item in categoryList"
:key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-form-item>
</el-form>
<div class="head-container">
<el-table ref="table" :data="tableData.list" v-loading="tableData.loading">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column label="商品信息">
<template v-slot="scope">
<div class="shop_info">
<el-image :src="scope.row.coverImg" style="width: 30px;height: 30px;">
<div class="img_error" slot="error">
<i class="icon el-icon-document-delete"></i>
</div>
</el-image>
<span>{{ scope.row.name }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="售价">
<template v-slot="scope">
{{ scope.row.lowPrice }}
</template>
</el-table-column>
<el-table-column label="销量/库存">
<template v-slot="scope">
{{ scope.row.realSalesNumber }}/{{ scope.row.stockNumber }}
</template>
</el-table-column>
<el-table-column label="分类" prop="categoryName"></el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" @size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopCategoryGet, tbProduct } from "@/api/shop";
export default {
data() {
return {
dialogVisible: false,
searhForm: {
name: '',
category: ''
},
categoryList: [],
tableData: {
page: 0,
size: 10,
total: 0,
loading: false,
list: []
},
goods: []
}
},
methods: {
// 确定选商品
confirmHandle() {
let res = this.$refs.table.selection
this.$emit('success', res)
this.close()
},
// 重置查询
resetHandle() {
this.searhForm.name = ''
this.searhForm.category = ''
this.tableData.page = 0
this.tableData.size = 10
this.tableData.list = []
this.getTableData()
},
// 分页大小改变
sizeChange(e) {
this.tableData.size = e
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProduct({
page: this.tableData.page,
size: this.tableData.size,
name: this.searhForm.name,
categoryId: this.searhForm.category,
shopId: localStorage.getItem('shopId'),
sort: 'id',
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
if (this.goods.length) {
this.$nextTick(() => {
this.selection()
})
}
} catch (error) {
console.log(error)
}
},
// 商品分类
async tbShopCategoryGet() {
try {
const res = await tbShopCategoryGet({
page: 0,
size: 100,
sort: 'id',
shopId: localStorage.getItem('shopId')
})
this.categoryList = res.content
} catch (error) {
console.log(error)
}
},
show(goods) {
this.dialogVisible = true
if (goods && goods.length) {
this.goods = goods
} else {
this.goods = []
}
this.resetHandle()
this.tbShopCategoryGet()
this.getTableData()
},
close() {
this.dialogVisible = false
},
selection() {
this.goods.forEach(row => {
this.tableData.list.forEach((item, index) => {
if (row.id == item.id) {
this.$refs.table.toggleRowSelection(this.tableData.list[index]);
}
})
});
}
}
}
</script>
<style scoped lang="scss">
.shop_info {
display: flex;
align-items: center;
span {
margin-left: 10px;
}
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<div>
<el-upload ref="upload" :action="qiNiuUploadApi" :headers="headers" :file-list="fileList" :limit="limit"
:list-type="type" :on-preview="handlePictureCardPreview" :multiple="limit > 1" :on-success="handleSuccess"
:on-error="handleError" :on-exceed="onExceed" :on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible" :z-index="99">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import { Notification } from 'element-ui'
export default {
computed: {
...mapGetters([
'qiNiuUploadApi'
])
},
props: {
type: {
type: String,
default: 'picture-card'
},
limit: {
type: Number,
default: 1
}
},
data() {
return {
dialogImageUrl: '',
dialogVisible: false,
fileList: [],
files: [],
headers: {
'Authorization': getToken()
}
}
},
methods: {
handleSuccess(response, file, fileList) {
// console.log('上传成功', response)
this.files = response.data
this.$emit('success', response.data)
},
// 监听上传失败
handleError(e, file, fileList) {
// console.log(e)
const m = JSON.parse(e.message)
Notification.error({
title: m.message,
duration: 5000
})
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
onExceed() {
this.$notify.error({
title: '错误',
message: `最多上传${this.limit}张图片`
})
},
handleRemove(file, fileList) {
let arr = fileList.map(item => item.url)
this.$emit('remove', arr)
},
clearFiles() {
this.$refs.upload.clearFiles()
}
}
}
</script>

View File

@@ -1,39 +1,34 @@
<template> <template>
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container"
@toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> <breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <!-- <template v-if="device !== 'mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<el-tooltip content="项目文档" effect="dark" placement="bottom">
<!-- <el-tooltip content="项目文档" effect="dark" placement="bottom">
<Doc class="right-menu-item hover-effect" /> <Doc class="right-menu-item hover-effect" />
</el-tooltip> --> </el-tooltip>
<el-tooltip content="全屏缩放" effect="dark" placement="bottom"> <el-tooltip content="全屏缩放" effect="dark" placement="bottom">
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
<el-tooltip content="布局设置" effect="dark" placement="bottom"> <el-tooltip content="布局设置" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" /> <size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
</template> -->
</template> <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<img :src="user.avatarName ? baseApi + '/avatar/' + user.avatarName : Avatar" class="user-avatar"> <img :src="logo || Avatar" class="user-avatar">
<i class="el-icon-caret-bottom" /> <!-- <i class="el-icon-caret-bottom" /> -->
<span class="shop_name">{{ shopName }}</span>
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<span style="display:block;" @click="show = true"> <!-- <span style="display:block;" @click="show = true">
<el-dropdown-item> <el-dropdown-item>
布局设置 布局设置
</el-dropdown-item> </el-dropdown-item>
</span> </span> -->
<router-link to="/user/center"> <router-link to="/shop/shop/shop_configuration">
<el-dropdown-item> <el-dropdown-item>
个人中心 个人中心
</el-dropdown-item> </el-dropdown-item>
@@ -71,7 +66,9 @@ export default {
data() { data() {
return { return {
Avatar: Avatar, Avatar: Avatar,
dialogVisible: false dialogVisible: false,
logo: localStorage.getItem('logo'),
shopName: localStorage.getItem('shopName')
} }
}, },
computed: { computed: {
@@ -103,6 +100,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
localStorage.setItem('logoutHandle', true)
this.logout() this.logout()
}) })
}, },
@@ -121,7 +119,7 @@ export default {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: #fff; background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08); box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
.hamburger-container { .hamburger-container {
line-height: 46px; line-height: 46px;
@@ -129,7 +127,7 @@ export default {
float: left; float: left;
cursor: pointer; cursor: pointer;
transition: background .3s; transition: background .3s;
-webkit-tap-highlight-color:transparent; -webkit-tap-highlight-color: transparent;
&:hover { &:hover {
background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, .025)
@@ -173,17 +171,18 @@ export default {
} }
.avatar-container { .avatar-container {
margin-right: 30px; margin-right: 10px;
.avatar-wrapper { .avatar-wrapper {
margin-top: 5px;
position: relative; position: relative;
display: flex;
align-items: center;
.user-avatar { .user-avatar {
cursor: pointer; cursor: pointer;
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 10px; border-radius: 50%;
} }
.el-icon-caret-bottom { .el-icon-caret-bottom {
@@ -193,6 +192,11 @@ export default {
top: 25px; top: 25px;
font-size: 12px; font-size: 12px;
} }
.shop_name {
font-size: 16px;
margin-left: 10px;
}
} }
} }
} }

View File

@@ -27,6 +27,11 @@ import './router/index' // permission control
// 全局引入 // 全局引入
import EleUploadImage from 'vue-ele-upload-image' import EleUploadImage from 'vue-ele-upload-image'
import VueAMap from 'vue-amap';
import VueClipboard from 'vue-clipboard2'
Vue.component(EleUploadImage.name, EleUploadImage) Vue.component(EleUploadImage.name, EleUploadImage)
Vue.component('Editor', Editor) Vue.component('Editor', Editor)
@@ -36,6 +41,14 @@ Vue.use(dict)
Vue.use(Element, { Vue.use(Element, {
size: Cookies.get('size') || 'small' // set element-ui default size size: Cookies.get('size') || 'small' // set element-ui default size
}) })
Vue.use(VueAMap)
Vue.use(VueClipboard)
VueAMap.initAMapApiLoader({
key: '6033c97e67bf2e9ceac306e1a3fa35f8',
// securityJsCode: '0547b69252ef0ed14e11f5c4ac152f07',
plugin: ['AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor']
})
Vue.config.productionTip = false Vue.config.productionTip = false

View File

@@ -31,7 +31,7 @@ router.beforeEach((to, from, next) => {
location.reload() // 为了重新实例化vue-router对象 避免bug location.reload() // 为了重新实例化vue-router对象 避免bug
}) })
}) })
// 登录时未拉取 菜单,在此处拉取 // 登录时未拉取 菜单,在此处拉取
} else if (store.getters.loadMenus) { } else if (store.getters.loadMenus) {
// 修改成false防止死循环 // 修改成false防止死循环
store.dispatch('updateLoadMenus') store.dispatch('updateLoadMenus')
@@ -45,7 +45,7 @@ router.beforeEach((to, from, next) => {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入 if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next() next()
} else { } else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 next(localStorage.getItem('logoutHandle') ? '/login' : `/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
NProgress.done() NProgress.done()
} }
} }

View File

@@ -5,7 +5,8 @@ import Layout from '../layout/index'
Vue.use(Router) Vue.use(Router)
export const constantRouterMap = [ export const constantRouterMap = [
{ path: '/login', {
path: '/login',
meta: { title: '登录', noCache: true }, meta: { title: '登录', noCache: true },
component: (resolve) => require(['@/views/login'], resolve), component: (resolve) => require(['@/views/login'], resolve),
hidden: true hidden: true
@@ -34,13 +35,23 @@ export const constantRouterMap = [
{ {
path: '/', path: '/',
component: Layout, component: Layout,
redirect: '/dashboard', redirect: '/data_statistics',
meta: {
title: '数据统计',
icon: 'index'
},
children: [ children: [
{ {
path: 'dashboard', path: 'data_statistics',
component: (resolve) => require(['@/views/home'], resolve), component: (resolve) => require(['@/views/home/home'], resolve),
name: 'Dashboard', name: 'data_statistics',
meta: { title: '首页', icon: 'index', affix: true, noCache: true } meta: { title: '数据统计' }
},
{
path: 'data_forms',
component: (resolve) => require(['@/views/home/data_forms'], resolve),
name: 'data_forms',
meta: { title: '数据报表' }
} }
] ]
}, },

View File

@@ -42,5 +42,32 @@ module.exports = {
/** /**
* 备案号 * 备案号
*/ */
caseNumber: '陕ICP备2022008069号' caseNumber: '陕ICP备2022008069号',
typeEnum: [
{
label: '计量商品',
intro: '单价购买',
typeEnum: 'normal'
},
{
label: '多规格',
intro: '多种不同规格',
typeEnum: 'sku'
},
{
label: '套餐商品',
intro: '选职多种组合',
typeEnum: 'group'
},
{
label: '称重商品',
intro: '按重量售卖',
typeEnum: 'weight'
},
{
label: '时价商品',
intro: '收银端可更改价格',
typeEnum: 'currentPrice'
}
]
} }

View File

@@ -6,7 +6,7 @@ const state = {
withoutAnimation: false withoutAnimation: false
}, },
device: 'desktop', device: 'desktop',
size: Cookies.get('size') || 'small' size: Cookies.get('size') || 'default'
} }
const mutations = { const mutations = {

View File

@@ -11,6 +11,10 @@ const user = {
}, },
mutations: { mutations: {
// 是否为手动退出登录
SD_LOGOUT: (state, f) => {
state.sdLogout = f
},
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token
}, },
@@ -31,6 +35,11 @@ const user = {
const rememberMe = userInfo.rememberMe const rememberMe = userInfo.rememberMe
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(userInfo.username, userInfo.password, userInfo.code, userInfo.uuid).then(res => { login(userInfo.username, userInfo.password, userInfo.code, userInfo.uuid).then(res => {
// console.log('登录成功后返回===', res)
localStorage.setItem('logoutHandle', false)
localStorage.setItem('shopId', res.shopId)
localStorage.setItem('shopName', res.shopName)
localStorage.setItem('logo', res.logo)
setToken(res.token, rememberMe) setToken(res.token, rememberMe)
commit('SET_TOKEN', res.token) commit('SET_TOKEN', res.token)
setUserInfo(res.user, commit) setUserInfo(res.user, commit)

View File

@@ -39,7 +39,7 @@ export function parseTime(time, cFormat) {
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key] let value = formatObj[key]
// Note: getDay() returns 0 on Sunday // Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) { if (result.length > 0 && value < 10) {
value = '0' + value value = '0' + value
} }
@@ -165,12 +165,12 @@ export function param2Obj(url) {
} }
return JSON.parse( return JSON.parse(
'{"' + '{"' +
decodeURIComponent(search) decodeURIComponent(search)
.replace(/"/g, '\\"') .replace(/"/g, '\\"')
.replace(/&/g, '","') .replace(/&/g, '","')
.replace(/=/g, '":"') .replace(/=/g, '":"')
.replace(/\+/g, ' ') + .replace(/\+/g, ' ') +
'"}' '"}'
) )
} }
@@ -249,7 +249,7 @@ export function getTime(type) {
export function debounce(func, wait, immediate) { export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result let timeout, args, context, timestamp, result
const later = function() { const later = function () {
// 据上一次触发时间间隔 // 据上一次触发时间间隔
const last = +new Date() - timestamp const last = +new Date() - timestamp
@@ -266,7 +266,7 @@ export function debounce(func, wait, immediate) {
} }
} }
return function(...args) { return function (...args) {
context = this context = this
timestamp = +new Date() timestamp = +new Date()
const callNow = immediate && !timeout const callNow = immediate && !timeout
@@ -386,3 +386,15 @@ export function downloadFile(obj, name, suffix) {
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)
} }
/**
* 生成范围随机数
* @param {Object} Min
* @param {Object} Max
*/
export function RandomNumBoth(Max, Min = 0) {
var Range = Max - Min;
var Rand = Math.random();
var num = Min + Math.round(Rand * Range); //四舍五入
return num;
}

View File

@@ -8,7 +8,8 @@ import Cookies from 'js-cookie'
// 创建axios实例 // 创建axios实例
const service = axios.create({ const service = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/', // api 的 base_url // baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/',
baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url
timeout: Config.timeout // 请求超时时间 timeout: Config.timeout // 请求超时时间
}) })
@@ -19,9 +20,9 @@ service.interceptors.request.use(
config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
} }
config.headers['Content-Type'] = 'application/json' config.headers['Content-Type'] = 'application/json'
config.headers['loginName']='admin' config.headers['loginName'] = 'admin'
config.headers['token']='eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyVHlwZSI6Ik1HIiwiZXhwIjoxNjkwMTgwNzE2LCJ1c2VySWQiOiIyNDQiLCJpYXQiOjE2ODg3MDk0ODcsImxvZ2luTmFtZSI6ImFkbWluIn0.lqxxvv2-FcecQngMBorz4MpkB3mIJQDG-IUULQyV-KQ' config.headers['token'] = 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyVHlwZSI6Ik1HIiwiZXhwIjoxNjkwMTgwNzE2LCJ1c2VySWQiOiIyNDQiLCJpYXQiOjE2ODg3MDk0ODcsImxvZ2luTmFtZSI6ImFkbWluIn0.lqxxvv2-FcecQngMBorz4MpkB3mIJQDG-IUULQyV-KQ'
config.headers["userId"]='244' config.headers["userId"] = '244'
return config return config
}, },
error => { error => {
@@ -39,7 +40,7 @@ service.interceptors.response.use(
if (error.response.data instanceof Blob && error.response.data.type.toLowerCase().indexOf('json') !== -1) { if (error.response.data instanceof Blob && error.response.data.type.toLowerCase().indexOf('json') !== -1) {
const reader = new FileReader() const reader = new FileReader()
reader.readAsText(error.response.data, 'utf-8') reader.readAsText(error.response.data, 'utf-8')
reader.onload = function(e) { reader.onload = function (e) {
const errorMsg = JSON.parse(reader.result).message const errorMsg = JSON.parse(reader.result).message
Notification.error({ Notification.error({
title: errorMsg, title: errorMsg,

View File

@@ -0,0 +1,166 @@
<template>
<div>
<el-dialog title="添加云打印机" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="层级">
<el-select v-model="form.contentType">
<el-option :label="item.name" :value="item.value" v-for="item in devices"
:key="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备尺寸">
<el-radio-group v-model="form.config.width">
<el-radio-button label="58">58mm</el-radio-button>
<el-radio-button label="80">80mm</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="设备名称" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称"></el-input>
</el-form-item>
<el-form-item label="设备号" prop="address">
<el-input v-model="form.address" placeholder="请输入设备号"></el-input>
</el-form-item>
<el-form-item label="打印份数">
<el-select v-model="form.config.printerNum">
<el-option :label="item" :value="item" v-for="item in 4" :key="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出品模式">
<el-select v-model="form.config.model">
<el-option :label="item.name" :value="item.value" v-for="item in models"
:key="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="打印类型">
<el-select v-model="form.subType">
<el-option :label="item.name" :value="item.value" v-for="item in subTypes"
:key="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="尾部留空">
<el-radio-group v-model="form.config.feet">
<el-radio-button :label="`${item}`" v-for="item in feets" :key="item">{{ item
}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="自动切刀">
<el-switch v-model="form.config.autoCut" :active-value="0" :inactive-value="1"></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-item label="排序">
<el-input-number v-model="form.sort" controls-position="right" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="商品分类">
<div style="cursor: pointer;" @click="$refs.classify.show()">
<span style="color: #409eff;" v-for="item in form.config.categoryList">{{ item.name }},</span>
<span style="color: #e65d6e;" v-if="!form.config.categoryList.length">请选择分类</span>
</div>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
<classify ref="classify" @success="classifySuccess" />
</div>
</template>
<script>
import { devices, models, subTypes } from '../devices'
import { tbPrintMachine } from '@/api/devices'
import classify from '@/components/classify'
export default {
components: { classify },
data() {
return {
dialogVisible: false,
devices,
models,
subTypes,
feets: [0, 1, 2, 3, 4, 5, 8],
loading: false,
form: {
id: '',
contentType: '',
config: {
width: '80mm', // 设备尺寸
printerNum: 1, //打印份数
categoryList: '', // 商品分类
model: 'normal', // 出品模式,
feet: '0',
autoCut: 0
},
name: '',
subType: 'kitchen', // 打印类型
status: 0,
sort: ''
},
resetForm: '',
rules: {
name: [
{
required: true,
message: ' ',
trigger: 'blur'
}
],
address: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
}
}
},
mounted() {
this.resetForm = { ...this.form }
},
methods: {
// 确认选择商品分类
classifySuccess(e) {
this.form.config.categoryList = e
},
onSubmitHandle() {
console.log(this.form)
this.$refs.form.validate(async valid => {
if (valid) {
try {
this.loading = true
this.form.shopId = localStorage.getItem('shopId')
let res = await tbPrintMachine(this.form, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
this.loading = false
} catch (error) {
this.loading = false
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = { ...obj }
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form = { ...this.resetForm }
}
}
}
</script>

View File

@@ -0,0 +1,44 @@
export const devices = [
{
value: 'printer',
name: '本地'
},
{
value: 'yxyPrinter',
name: '云想印'
},
{
value: 'fePrinter',
name: '飞鹅'
}
]
export const models = [
{
value: 'normal',
name: '普通出单'
},
{
value: 'one',
name: '一菜一品'
},
{
value: 'category',
name: '分类出单'
}
]
export const subTypes = [
{
value: 'kitchen',
name: '出品'
},
{
value: 'cash',
name: '小票'
},
{
value: 'label',
name: '标签'
}
]

View File

@@ -0,0 +1,159 @@
<template>
<div class="app-container">
<div class="head-container">
<el-form :model="query" inline>
<el-form-item>
<el-input v-model="query.name" placeholder="请输入设备名称"></el-input>
</el-form-item>
<el-form-item>
<el-select v-model="query.type" placeholder="请选择设备类型">
<el-option :label="item.name" :value="item.value" v-for="item in devices" :key="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="head-container">
<el-button type="primary" icon="el-icon-plus" @click="$refs.addDevice.show()">
添加云打印机
</el-button>
</div>
<div class="head-container">
<el-table :data="tableData.data" v-loading="tableData.loading">
<el-table-column label="设备名称" prop="name"></el-table-column>
<el-table-column label="设备号" prop="address"></el-table-column>
<el-table-column label="品牌" prop="contentType">
<template v-slot="scope">
{{ scope.row.contentType | devicesName }}
</template>
</el-table-column>
<el-table-column label="出品模式" prop="config.model">
<template v-slot="scope">
{{ scope.row.config.model | modelsName }}
</template>
</el-table-column>
<el-table-column label="打印类型" prop="subType">
<template v-slot="scope">
{{ scope.row.subType | subTypesName }}
</template>
</el-table-column>
<el-table-column label="创建时间" sortable prop="createdAt">
<template v-slot="scope">
{{ scope.row.createdAt | timeFilter }}
</template>
</el-table-column>
<el-table-column label="排序" sortable prop="sort"></el-table-column>
<el-table-column label="状态" prop="status">
<template v-slot="scope">
<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0"
@change="statusChange($event, scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="text" icon="el-icon-edit"
@click="$refs.addDevice.show(scope.row)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="delTableHandle([scope.row.id])">
<el-button type="text" icon="el-icon-delete" style="margin-left: 20px !important;"
slot="reference">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total"></el-pagination>
</div>
<addDevice ref="addDevice" @success="getTableData" />
</div>
</template>
<script>
import { devices, models, subTypes } from './devices'
import addDevice from './components/addDevice'
import { tbPrintMachineGet, tbPrintMachine } from '@/api/devices'
import dayjs from 'dayjs'
export default {
components: {
addDevice
},
data() {
return {
query: {
name: '',
type: ''
},
devices,
tableData: {
data: [],
page: 0,
size: 10,
loading: false,
total: 0
}
}
},
filters: {
devicesName(value) {
return devices.find(item => item.value == value).name
},
modelsName(value) {
return models.find(item => item.value == value).name
},
subTypesName(value) {
return subTypes.find(item => item.value == value).name
},
timeFilter(s) {
return dayjs(s).format('YYYY-MM-DD HH:mm:ss')
}
},
mounted() {
this.getTableData()
},
methods: {
// 切换状态
async statusChange(e, row) {
try {
this.tableData.loading = true
const data = { ...row }
data.status = e
await tbPrintMachine(data, 'put')
this.getTableData()
} catch (error) {
console.log(error)
this.tableData.loading = false
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.type = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbPrintMachineGet({
name: this.query.name,
contentType: this.query.type
})
this.tableData.loading = false
this.tableData.data = res
this.tableData.total = res.length
} catch (error) {
console.log(error)
}
}
}
}
</script>

View File

@@ -1,115 +0,0 @@
<template>
<el-image :src="this.shouye"></el-image>
<!-- <div class="dashboard-container">
<div class="dashboard-editor-container">
<github-corner class="github-corner" />
<panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" />
</el-row>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<radar-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<pie-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<bar-chart />
</div>
</el-col>
</el-row>
</div>
</div> -->
</template>
<script>
import GithubCorner from '@/components/GithubCorner'
import PanelGroup from './dashboard/PanelGroup'
import LineChart from './dashboard/LineChart'
import RadarChart from '@/components/Echarts/RadarChart'
import PieChart from '@/components/Echarts/PieChart'
import BarChart from '@/components/Echarts/BarChart'
import shouye from '@/assets/images/background.webp'
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
export default {
name: 'Dashboard',
components: {
GithubCorner,
PanelGroup,
LineChart,
RadarChart,
PieChart,
BarChart
},
data() {
return {
shouye:shouye,
lineChartData: lineChartData.newVisitis
}
},
created(){
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.github-corner {
position: absolute;
top: 0;
border: 0;
right: 0;
}
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
</style>

View File

@@ -0,0 +1,3 @@
<template>
<div>数据报表</div>
</template>

828
src/views/home/home.vue Normal file
View File

@@ -0,0 +1,828 @@
<template>
<div class="app-container" style="padding-bottom: 100px;">
<div class="card_wrap">
<div class="card">
<div class="header">
<div class="card_title">总销售额</div>
<el-tooltip effect="dark" content="订单支付金额" placement="top">
<i class="icon el-icon-warning-outline"></i>
</el-tooltip>
</div>
<div class="number">{{ topData.totalSales || 0 }}</div>
<div class="row">平均每单{{ topData.averageSales || 0 }}</div>
<div class="row">今日销售额{{ topData.totalSalesToday || 0 }}</div>
</div>
<div class="card">
<div class="header">
<div class="card_title">支付笔数</div>
</div>
<div class="number">{{ topData.paymentsNumber }}</div>
<div class="row" ref="cardPayChart" style="padding-bottom: 2px;"></div>
<div class="row">今日支付笔数{{ topData.paymentsNumberToday || 0 }}</div>
</div>
<div class="card">
<div class="header">
<div class="card_title">访问量</div>
</div>
<div class="number">{{ topData.totalVisits }}</div>
<div class="row" ref="cardCountChart"></div>
<div class="row">
<div class="dot"></div> 今日访问 {{ topData.totalVisitsToday || 0 }}
</div>
</div>
<div class="card">
<div class="header">
<div class="card_title">用户数</div>
</div>
<div class="number">{{ topData.totalUser }}</div>
<div class="row" ref="cardUserChart" style="padding-bottom: 2px;"></div>
<div class="row">今日新增 {{ topData.userToday || 0 }} <i class="icon el-icon-caret-top"></i> </div>
</div>
</div>
<!-- 销售额 -->
<div class="chart_wrap">
<div class="item">
<div class="header">
<div class="tab_wrap">
<div class="item active">销售额</div>
</div>
<el-radio-group v-model="saleActive" @change="dateAmount">
<el-radio-button label="7">近7天</el-radio-button>
<el-radio-button label="30">30</el-radio-button>
</el-radio-group>
</div>
<div class="chart" ref="saleChart" v-loading="saleLoading" style="height: 400px;">
</div>
</div>
</div>
<div class="chart_wrap" style="display: flex;">
<!-- 商品销售排行 -->
<div class="item">
<div class="header">
<div class="tab_wrap">
<div class="item active">商品销售排行</div>
</div>
<el-radio-group v-model="saleTableActive" @change="rankChange">
<el-radio-button label="7">近7天</el-radio-button>
<el-radio-button label="30">30</el-radio-button>
</el-radio-group>
</div>
<div class="sale_data">
<div class="card">
<div class="sale_data_header">
<div class="card_title">销售数量</div>
</div>
<div class="number">{{ productCount }}</div>
<div class="product_chart_wrap" ref="productCountChart"></div>
</div>
<div class="card">
<div class="sale_data_header">
<div class="card_title">销售金额</div>
</div>
<div class="number">{{ productSum }}</div>
<div class="product_chart_wrap" ref="productSumChart"></div>
</div>
</div>
<div class="table">
<el-table :data="saleTable" v-loading="saleTableLoading">
<el-table-column label="排名" prop="productId"></el-table-column>
<el-table-column label="商品名称" prop="productName"></el-table-column>
<el-table-column label="数量" prop="productNum"></el-table-column>
<el-table-column label="金额" prop="amount"></el-table-column>
</el-table>
<div class="head-container" style="padding-top: 20px;display: flex;justify-content: flex-end;">
<el-pagination :total="saleTableTotal" :page-size="saleTableSize" :current-page="saleTablePage"
@current-change="paginationChange" layout="total, prev, pager, next, jumper"></el-pagination>
</div>
</div>
</div>
<!-- 支付类型占比 -->
<div class="item" style="margin-left: 20px;">
<div class="header">
<div class="tab_wrap">
<div class="item active">支付占比类型</div>
</div>
<el-radio-group v-model="payChartDay" @change="datePayType">
<el-radio-button label="7">近7天</el-radio-button>
<el-radio-button label="30">30</el-radio-button>
</el-radio-group>
</div>
<div style="height: 400px;margin-top: 30px;" ref="payChart" v-loading="payChartLoading"></div>
</div>
</div>
</div>
</template>
<script>
import { summaryGet, summaryTodayGet, dateProduct, dateAmount, datePayType, summaryDateGet } from '@/api/home'
import echarts from 'echarts'
import { debounce } from '@/utils'
export default {
name: 'home',
data() {
return {
topData: '',
saleTab: 'sale',
saleActive: '7',
cardPayChart: null,
cardCountChart: null,
cardUserChart: null,
saleLoading: false,
saleChart: null,
payChartDay: '7',
payChartLoading: false,
payChart: null,
chartType: 1,
productCount: 0,
productSum: 0,
saleTableActive: '7',
saleTable: [],
saleTableLoading: false,
saleTablePage: 1,
saleTableTotal: 0,
saleTableSize: 5,
__resizeHandler: null,
productCountChart: null,
productSumChart: null
}
},
mounted() {
this.summaryGet()
this.dateAmount()
this.dateProduct()
this.datePayType()
this.summaryDateGet()
this.__resizeHandler = debounce(() => {
if (this.saleChart) {
this.saleChart.resize()
}
if (this.payChart) {
this.payChart.resize()
}
if (this.cardPayChart) {
this.cardPayChart.resize()
}
if (this.cardUserChart) {
this.cardUserChart.resize()
}
if (this.productCountChart) {
this.productCountChart.resize()
}
if (this.productSumChart) {
this.productSumChart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
this.initCardUserChart()
},
methods: {
// 初始化支付笔数柱状图
initCardPayChart(time = [], data = []) {
this.cardPayChart = echarts.init(this.$refs.cardPayChart)
this.cardPayChart.setOption({
tooltip: {
trigger: 'axis'
},
grid: {
x: 0,
y: 0,
x2: 0,
y2: 0
},
xAxis: [{
type: 'category',
data: time,
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}
],
series: [
{
data: data,
type: 'bar',
barWidth: '30%'
}
]
})
},
// 初始化访问量柱状图
initCardCountChart(time = [], data = []) {
this.cardCountChart = echarts.init(this.$refs.cardCountChart)
this.cardCountChart.setOption({
tooltip: {
trigger: 'axis'
},
grid: {
x: 0,
y: 0,
x2: 0,
y2: 0
},
xAxis: [{
type: 'category',
data: time,
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}
],
series: [
{
data: data,
type: 'bar',
barWidth: '30%'
}
]
})
},
// 初始化用户数折线图
initCardUserChart(time = [], data = []) {
this.cardUserChart = echarts.init(this.$refs.cardUserChart)
this.cardUserChart.setOption({
tooltip: {
trigger: 'axis'
},
grid: {
x: 0,
y: 10,
x2: 0,
y2: 2
},
xAxis: [{
type: 'category',
data: time,
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}
],
series: [
{
data: data,
type: 'line',
symbol: 'none'
}
]
})
},
// 初始化销售额图标
initSaleChart(time, data) {
this.saleChart = null
this.saleChart = echarts.init(this.$refs.saleChart)
this.saleChart.setOption({
title: {
text: '销售趋势',
x: 'center'
},
tooltip: {
trigger: 'axis'
},
xAxis: [{
type: 'category',
data: time,
axisTick: {
alignWithLabel: true
},
axisLine: {
lineStyle: {
color: '#999'
}
},
axisLabel: {
rotate: time.length <= 7 ? 0 : 45,
interval: 0,
textStyle: {
fontSize: '9'
}
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
axisLine: {
lineStyle: {
color: '#999'
}
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#ececec'
}
}
}
],
series: [
{
data: data,
type: 'bar',
barWidth: time.length <= 7 ? '50%' : '30%'
}
]
})
},
// 初始化销售额图表
initPayChart(data) {
this.payChart = echarts.init(this.$refs.payChart)
this.payChart.setOption({
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
color: ['#409eff', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
series: [
{
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 20
}
},
labelLine: {
show: false
},
data: data
}
]
})
},
// 获取销售额柱状图数据
async dateAmount() {
try {
this.saleLoading = true
const res = await dateAmount(this.saleActive)
const data = res.total.map(item => item.amount)
const time = res.total.map(item => item.tradeDay)
this.initSaleChart(time, data)
setTimeout(() => {
this.saleLoading = false
}, 300);
} catch (error) {
console.log(error)
}
},
paginationChange(e) {
this.saleTablePage = e
this.dateProduct()
},
// 获取销售额排行表格数据
async dateProduct() {
try {
this.saleTableLoading = true
const res = await dateProduct(this.saleTableActive, this.saleTablePage, this.saleTableSize)
this.saleTable = res.totalProduct
this.saleTableTotal = res.total
this.productCount = res.productCount
this.productSum = res.productSum
setTimeout(() => {
this.saleTableLoading = false
}, 300);
} catch (error) {
console.log(error)
}
},
// 支付类型占比 饼图
async datePayType() {
try {
this.payChartLoading = true
const res = await datePayType(this.payChartDay)
const data = res.countPayType.map(item => {
return {
value: item.count,
name: item.payType
}
})
setTimeout(() => {
this.payChartLoading = false
}, 300);
this.initPayChart(data)
} catch (error) {
console.log(error)
}
},
// 汇总数据
async summaryGet() {
try {
const res1 = await summaryGet()
const res2 = await summaryTodayGet()
this.topData = {
...res1,
...res2
}
let payTime = res1.countDateList.map(item => item.tradeDay)
let payData = res1.countDateList.map(item => item.count)
let countTime = res1.visitsCountList.map(item => item.tradeDay)
let countData = res1.visitsCountList.map(item => item.count)
this.initCardPayChart(payTime, payData)
this.initCardCountChart(countTime, countData)
console.log(this.topData)
} catch (error) {
console.log(error)
}
},
rankChange() {
this.dateProduct()
this.summaryDateGet()
},
// 初始化销售图标
initProduceChart(p1, p2) {
this.productCountChart = echarts.init(this.$refs.productCountChart)
this.productSumChart = echarts.init(this.$refs.productSumChart)
this.productCountChart.setOption({
tooltip: {
trigger: 'axis'
},
grid: {
x: 0,
y: 0,
x2: 0,
y2: 0
},
xAxis: [{
boundaryGap: false,
type: 'category',
data: p1[0],
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}
],
series: [
{
data: p1[1],
type: 'line',
symbol: 'none',
smooth: true,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#409eff' // 渐变颜色
}, {
offset: 1,
color: '#409eff' // 渐变颜色
}])
}
}
]
})
this.productSumChart.setOption({
tooltip: {
trigger: 'axis'
},
grid: {
x: 0,
y: 0,
x2: 0,
y2: 0
},
xAxis: [{
boundaryGap: false,
type: 'category',
data: p2[0],
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}],
color: '#409eff',
yAxis: [
{
type: 'value',
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
axisTick: {
show: false // 不显示坐标轴刻度线
},
axisLine: {
show: false, // 不显示坐标轴线
},
axisLabel: {
show: false, // 不显示坐标轴上的文字
},
splitLine: {
show: false // 不显示网格线
}
}
],
series: [
{
data: p2[1],
type: 'line',
symbol: 'none',
smooth: true,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#409eff' // 渐变颜色
}, {
offset: 1,
color: '#409eff' // 渐变颜色
}])
}
}
]
})
},
// 日期汇总数据
async summaryDateGet() {
try {
const res = await summaryDateGet(this.saleTableActive)
let p1 = [res.numList.map(item => item.tradeDay), res.numList.map(item => item.count)]
let p2 = [res.amountList.map(item => item.tradeDay), res.amountList.map(item => item.count)]
this.initProduceChart(p1, p2)
} catch (error) {
console.log(error);
}
}
}
}
</script>
<style scoped lang="scss">
.app-container {
padding: 20px;
background-color: #F5F5F5;
}
.card_wrap {
display: flex;
flex-wrap: wrap;
gap: 20px;
.card {
flex: 1;
background-color: #fff;
border-radius: 2px;
padding: 0 20px;
.header {
display: flex;
justify-content: space-between;
color: #999;
padding-top: 20px;
.card_title {
font-size: 14px;
flex: 1;
}
}
.number {
padding: 20px 0 10px 0;
font-size: 24px;
height: 60px;
}
.row {
height: 50px;
color: #555;
font-size: 14px;
display: flex;
align-items: center;
&:not(:last-child) {
border-bottom: 1px solid #ececec;
}
.icon {
color: rgb(255, 85, 85);
margin-left: 4px;
}
.dot {
$size: 6px;
width: $size;
height: $size;
border-radius: 50%;
background-color: #1890FF;
margin-right: 6px;
}
}
}
}
.chart_wrap {
margin-top: 20px;
.sale_data {
display: flex;
.card {
flex: 1;
background-color: #fff;
border-radius: 2px;
padding: 0 20px;
.sale_data_header {
display: flex;
justify-content: space-between;
color: #999;
padding-top: 20px;
.card_title {
font-size: 14px;
flex: 1;
}
}
.number {
padding-top: 10px;
font-size: 24px;
height: 60px;
}
.product_chart_wrap {
height: 50px;
}
}
}
.item {
flex: 1;
background-color: #fff;
border-radius: 2px;
.header {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #ececec;
padding: 0 20px;
.tab_wrap {
display: flex;
$color: #1890FF;
.item {
padding: 0 10px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: $color;
&.active {
position: relative;
&::after {
content: "";
width: 100%;
border-bottom: 2px solid $color;
position: absolute;
bottom: 0;
left: 0;
}
}
}
}
}
.chart {
padding: 20px 0;
height: 300px;
}
.table {
padding: 20px;
}
}
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<el-dialog :title="`${form.id ? '编辑' : '添加'}供应商`" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="供应商" prop="purveyorName">
<el-input v-model="form.purveyorName" placeholder="请输入供应商名称"></el-input>
</el-form-item>
<el-form-item label="联系电话">
<el-input v-model="form.purveyorTelephone" placeholder="请输入联系电话"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input type="textarea" v-model="form.address" placeholder="请输入地址"></el-input>
</el-form-item>
<el-form-item label="标签">
<el-input v-model="form.tip" placeholder="请输入标签"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopPurveyor } from '@/api/invoicing'
export default {
data() {
return {
dialogVisible: false,
form: {
id: '',
purveyorName: '',
purveyorTelephone: '',
address: '',
tip: '',
remark: '',
},
rules: {
purveyorName: [
{
required: true,
message: '请输入供应商名称',
trigger: 'blur'
}
]
}
}
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
try {
let res = await tbShopPurveyor({
...this.form,
shopId: localStorage.getItem('shopId')
}, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = JSON.parse(JSON.stringify(obj))
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form.id = ''
this.form.purveyorName = ''
this.form.purveyorTelephone = ''
this.form.address = ''
this.form.tip = ''
this.form.remark = ''
}
}
}
</script>

View File

@@ -0,0 +1,178 @@
<!-- 进销存详情记录 -->
<template>
<el-dialog title="详情记录" width="80%" :visible.sync="dialogVisible" @close="dialogVisible = false">
<div class="head-container">
<el-select v-model="query.type" placeholder="选择类型">
<el-option :label="item.label" :value="item.value" v-for="item in typeList" :key="item.id"></el-option>
</el-select>
<el-date-picker v-model="query.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss">
</el-date-picker>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
<div class="head-container">
<div class="exchange_wrap">
<div class="item">
<span>{{ exchange || 0 }}</span>
<span>变动数量</span>
</div>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="变动数量" prop="stockNumber">
<template v-slot="scope">
<span class="num" :class="{ active: scope.row.stockNumber > 0 }">{{ scope.row.stockNumber }} {{
scope.row.unitName
}}</span>
</template>
</el-table-column>
<el-table-column label="类型">
<template v-slot="scope">
<el-tag type="info">{{ scope.row.tagName }}</el-tag>
</template>
</el-table-column>
<el-table-column label="剩余库存">
<template v-slot="scope">
{{ scope.row.leftNumber - scope.row.stockNumber }} {{ scope.row.unitName }}
</template>
</el-table-column>
<el-table-column label="操作时间" prop="updatedAt">
<template v-slot="scope">
{{ dayjs(scope.row.updatedAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</el-dialog>
</template>
<script>
import dayjs from 'dayjs'
import { dictDetail, tbProductStockDetail, tbProductStockDetailSum } from '@/api/invoicing'
export default {
data() {
return {
dayjs,
dialogVisible: false,
typeList: [],
query: {
type: '',
createdAt: []
},
goods: '',
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
},
exchange: 0
}
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProductStockDetail({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
shopId: localStorage.getItem('shopId'),
productId: this.goods.id,
type: this.query.type,
createdAt: this.query.createdAt
})
this.tableData.loading = false
this.tableData.list = res.content.map(item => {
item.tagName = this.typeList.find(val => val.value == item.type).label
return item
})
console.log(this.tableData.list)
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 重置查询
resetHandle() {
this.query.blurry = ''
this.tableData.page = 0
this.tableData.list = []
this.getTableData()
},
async show(obj) {
this.dialogVisible = true
this.goods = obj
this.tbProductStockDetailSum()
await this.dictDetail()
await this.getTableData()
},
async tbProductStockDetailSum() {
try {
const { exchange } = await tbProductStockDetailSum({
productId: this.goods.id
})
this.exchange = exchange
} catch (error) {
console.log(error);
}
},
async dictDetail() {
try {
const res = await dictDetail({
dictName: 'product_stock_type',
page: 0,
size: 100
})
this.typeList = res.content
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style scoped lang="scss">
.head-container {
display: flex;
align-items: center;
gap: 10px;
}
.num {
color: #67C23A;
&.active {
color: #F56C6C;
}
}
.exchange_wrap {
display: flex;
padding: 20px 30px;
.item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
span:nth-child(1) {
padding-bottom: 10px;
font-size: 24px;
}
}
}
</style>

View File

@@ -0,0 +1,66 @@
<template>
<el-dialog title="详情" width="80%" :visible.sync="dialogVisible" @close="dialogVisible = false">
<div class="head-container">
<span>退货出库</span>
</div>
<div class="head-container">
<el-table :data="tableData.detail.stockSnap" v-loading="tableData.loading" height="400px">
<el-table-column :label="`商品名称${tableData.detail.stockSnap.length}`" prop="name"></el-table-column>
<el-table-column label="变动数量" prop="number">
<template v-slot="scope">
{{ scope.row.number }}{{ scope.row.unitName }}
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<div class="row">备注{{ tableData.detail.remark }}</div>
<div class="row">操作人{{ tableData.detail.operatorSnap.name }}</div>
<div class="row">创建时间{{ tableData.detail.createdAt }}</div>
</div>
</el-dialog>
</template>
<script>
import dayjs from 'dayjs'
import { tbProductStockOperateDetail } from '@/api/invoicing'
export default {
data() {
return {
dayjs,
dialogVisible: false,
tableData: {
loading: false,
detail: {
stockSnap: [],
operatorSnap: {
name: ''
}
}
}
}
},
methods: {
show(id) {
this.dialogVisible = true
this.getTableData(id)
},
async getTableData(id) {
this.tableData.loading = true
try {
const res = await tbProductStockOperateDetail(id)
this.tableData.loading = false
this.tableData.detail = res
} catch (error) {
console.log(error);
}
}
}
}
</script>
<style scoped lang="scss">
.row {
padding-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div class="app-container">
<div class="head-container">
<el-row :gutter="20">
<el-col :span="6">
<el-input v-model="query.name" size="small" clearable placeholder="商品名称" style="width: 100%;"
class="filter-item" @keyup.enter.native="getTableData" />
</el-col>
<el-col :span="6">
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="商品信息">
<template v-slot="scope">
<div class="shop_info">
<el-image :src="scope.row.coverImg" class="cover">
<div class="img_error" slot="error">
<i class="icon el-icon-document-delete"></i>
</div>
</el-image>
<div class="info">
<span>{{ scope.row.name }}</span>
<div>
<el-tag type="primary">{{ scope.row.typeEnum | typeEnum }}</el-tag>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="库存" prop="stockNumber">
<template v-slot="scope">
{{ `${scope.row.stockNumber} ${scope.row.unitName}` }}
</template>
</el-table-column>
<el-table-column label="库存开关">
<template v-slot="scope">
<el-switch v-model="scope.row.isStock" :active-value="1" :inactive-value="0"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="scope">
<el-button type="text" size="mini"
@click="$refs.invoicingDetail.show(scope.row)">库存记录</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
<invoicingDetail ref="invoicingDetail" />
</div>
</template>
<script>
import { tbProductGet } from '@/api/invoicing'
import settings from '@/settings'
import invoicingDetail from './components/invoicingDetail'
export default {
components: {
invoicingDetail
},
data() {
return {
query: {
name: ''
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
}
}
},
filters: {
typeEnum(m) {
return settings.typeEnum.find(item => item.typeEnum == m).label
}
},
mounted() {
this.getTableData()
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProductGet({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
name: this.query.name,
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content.map(item => {
let stockNumber = 0
for (let i of item.skuList) {
stockNumber += i.stockNumber
}
item.stockNumber = stockNumber
return item
})
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 重置查询
resetHandle() {
this.query.blurry = ''
this.tableData.page = 0;
this.getTableData()
}
}
}
</script>
<style scoped lang="scss">
.shop_info {
display: flex;
align-items: center;
.cover {
$size: 50px;
width: $size;
height: $size;
border-radius: 2px;
background-color: #efefef;
}
.info {
display: flex;
flex-direction: column;
padding-left: 10px;
justify-content: space-between;
}
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div class="app-container">
<div class="head-container">
<div class="filter_wrap">
<el-date-picker v-model="query.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" @change="getTableData">
</el-date-picker>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="类型" prop="type">
<template v-slot="scope">
{{ scope.row.type == 'reject' ? '退货出库' : '供应商入库' }}
</template>
</el-table-column>
<el-table-column label="商品数量" prop="totalAmount">
<template v-slot="scope">
{{ scope.row.stockSnap.length }}
</template>
</el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="操作人" prop="status">
<template v-slot="scope">
{{ scope.row.operatorSnap.account }}
</template>
</el-table-column>
<el-table-column label="创建时间" prop="updatedAt">
<template v-slot="scope">
{{ dayjs(scope.row.stockTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template v-slot="scope">
<el-button type="text" size="mini" @click="$refs.operatingDetail.show(scope.row.id)">
详情
</el-button>
<!-- <el-button type="text" size="mini" @click="$refs.operatingDetail.show(scope.row.id)">
作废
</el-button> -->
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
<operatingDetail ref="operatingDetail" />
</div>
</template>
<script>
import dayjs from 'dayjs'
import { tbProductStockOperateList } from '@/api/invoicing'
import operatingDetail from './components/operatingDetail'
export default {
components: {
operatingDetail
},
data() {
return {
dayjs,
query: {
createdAt: []
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
}
}
},
mounted() {
this.getTableData()
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProductStockOperateList({
page: this.tableData.page,
size: this.tableData.size,
shopId: localStorage.getItem('shopId'),
createdAt: this.query.createdAt
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 重置查询
resetHandle() {
this.query.createdAt = []
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
}
}
}
</script>

View File

@@ -0,0 +1,276 @@
<template>
<div class="app-container">
<div class="head-container">
<el-form ref="queryForm" :model="queryForm" :rules="queryRules" label-position="left" label-width="80px">
<el-form-item label="出库类型">
<div class="shop_type_box">
<div class="item" v-for="(item, index) in shopTypes" :key="index"
:class="{ active: shopTypesActive == index }" @click="changeTypeEnum(index)">
<div class="s_title">{{ item.label }}</div>
<div class="active_dot">
<i class="el-icon-check"></i>
</div>
</div>
</div>
</el-form-item>
<el-row>
<el-col :span="8" v-if="shopTypes[shopTypesActive].value == 'purveyor'">
<el-form-item label="供应商" prop="purveyorId">
<el-select v-model="queryForm.purveyorId" placeholder="请选择供应商" style="width: 220px;">
<el-option :label="item.purveyorName" :value="item.id" v-for="item in purveyorList"
:key="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入库时间" prop="time">
<el-date-picker v-model="queryForm.time" type="date" format="yyyy-MM-dd"
value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 220px;">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="shopTypes[shopTypesActive].value == 'purveyor'">
<el-col :span="8">
<el-form-item label="应收金额">
<el-input v-model="queryForm.totalAmount" placeholder="请输入应收金额"
style="width: 220px;"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实收金额">
<el-input v-model="queryForm.paidAmount" placeholder="请输入实收金额"
style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="shopTypes[shopTypesActive].value == 'purveyor'">
<el-col :span="8">
<el-form-item label="付款时间">
<el-date-picker v-model="queryForm.paidAt" type="date" format="yyyy-MM-dd"
value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 220px;">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="批号">
<el-input v-model="queryForm.batchNumber" placeholder="请输入批号"
style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="queryForm.remark" placeholder="请输入备注" style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="$refs.shopList.show(tableData.list)">选择商品</el-button>
</el-form-item>
</el-form>
</div>
<div class="head-container">
<el-button type="primary" plain>
{{ tableData.list.length }}种商品金额合计<span style="color: red;">{{ queryForm.totalAmount }}</span>
</el-button>
</div>
<div class="head-container">
<el-table :data="tableData.list">
<el-table-column type="index" width="50"></el-table-column>
<el-table-column label="商品名称" prop="name">
<template v-slot="scope">
<div class="name_wrap">
<span class="name">{{ scope.row.name }}</span>
<el-tag type="info" v-if="scope.row.specSnap" size="mini">{{ scope.row.specSnap }}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="进价">
<template v-slot="scope">
<el-input-number v-model="scope.row.guidePrice" :min="0" controls-position="right"
@change="e => scope.row.totalAmount = e * scope.row.number"></el-input-number>
<div class="tips">成本价{{ scope.row.costPrice }}/{{ scope.row.unitName }}</div>
</template>
</el-table-column>
<el-table-column label="数量">
<template v-slot="scope">
<el-input-number v-model="scope.row.number" :min="0" controls-position="right"
@change="e => scope.row.totalAmount = e * scope.row.guidePrice"></el-input-number>
<div class="tips">入库前{{ scope.row.stockNumber }}{{ scope.row.unitName }}</div>
</template>
</el-table-column>
<el-table-column label="小计">
<template v-slot="scope">
<el-input-number v-model="scope.row.totalAmount" :min="0"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="变动后剩余库存">
<template v-slot="scope">
{{ scope.row.stockNumber + scope.row.number }}{{ scope.row.unitName }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<el-button type="text" @click="tableData.list.splice(scope.$index, 1)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div>
<el-button type="primary" @click="submitHandle" :loading="queryFormLoading">确定</el-button>
</div>
<shopList ref="shopList" @success="selectShop" />
<el-dialog :visible.sync="showResult" :show-close="false" :close-on-press-escape="false"
:close-on-click-modal="false">
<el-result icon="success" title="入库提交成功" :subTitle="`共操作${tableData.list.length}件商品`">
<template slot="extra">
<el-button type="primary" size="medium" @click="resetHandle">创建新的入库单</el-button>
<router-link to="/invoicing/operating_record">
<el-button size="medium">历史提交</el-button>
</router-link>
</template>
</el-result>
</el-dialog>
</div>
</template>
<script>
import dayjs from 'dayjs'
import shopList from '@/components/shopList'
import { tbShopPurveyorGet, tbProductStockOperateOutAndOn } from '@/api/invoicing'
export default {
components: {
shopList
},
data() {
return {
shopTypesActive: 0,
shopTypes: [
{
label: '供应商入库',
value: 'purveyor'
},
{
label: '其他入库',
value: 'purchase'
}
],
resetForm: '',
queryFormLoading: false,
queryForm: {
batchNumber: '',
list: [],
paidAmount: 0,
paidAt: '',
purveyorId: '',
purveyorName: '',
remark: '',
time: dayjs().format('YYYY-MM-DD'),
totalAmount: 0,
type: 'purveyor',
shopId: localStorage.getItem('shopId')
},
queryRules: {
purveyorId: [
{
required: true,
message: ' ',
trigger: 'change'
}
],
time: [
{
required: true,
message: ' ',
trigger: 'change'
}
]
},
purveyorList: [],
tableData: {
list: []
},
showResult: false
}
},
mounted() {
this.resetForm = { ...this.queryForm }
this.tbShopPurveyorGet()
},
methods: {
// 提交
submitHandle() {
this.$refs.queryForm.validate(async valid => {
if (valid) {
try {
this.queryFormLoading = true
this.queryForm.list = this.tableData.list
await tbProductStockOperateOutAndOn(this.queryForm)
this.queryFormLoading = false
this.showResult = true
} catch (error) {
console.log(error)
this.queryFormLoading = false
}
}
})
},
// 选择商品
selectShop(res) {
let arr = []
res.forEach(item => {
item.skuList.forEach(i => {
arr.push({
name: item.name,
unitName: item.unitName,
productId: item.id,
number: 0,
totalAmount: '',
...i
})
})
})
console.log(arr)
this.tableData.list = arr
},
// 初始化
resetHandle() {
this.showResult = false
this.queryForm = { ...this.resetForm }
this.tableData.list = []
},
// 切换类型
changeTypeEnum(index) {
this.shopTypesActive = index
this.queryForm.type = this.shopTypes[index].value
},
// 获取供应商列表
async tbShopPurveyorGet() {
try {
const res = await tbShopPurveyorGet({
shopId: localStorage.getItem('shopId'),
page: 0,
size: 100
})
this.purveyorList = res.content
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style scoped lang="scss">
.name_wrap {
display: flex;
align-items: center;
.name {
margin-right: 10px;
}
}
</style>

View File

@@ -0,0 +1,274 @@
<template>
<div class="app-container">
<div class="head-container">
<el-form ref="queryForm" :model="queryForm" :rules="queryRules" label-position="left" label-width="80px">
<el-form-item label="出库类型">
<div class="shop_type_box">
<div class="item" v-for="(item, index) in shopTypes" :key="index"
:class="{ active: shopTypesActive == index }" @click="changeTypeEnum(index)">
<div class="s_title">{{ item.label }}</div>
<div class="active_dot">
<i class="el-icon-check"></i>
</div>
</div>
</div>
</el-form-item>
<el-row>
<el-col :span="8" v-if="shopTypes[shopTypesActive].value == 'reject'">
<el-form-item label="供应商" prop="purveyorId">
<el-select v-model="queryForm.purveyorId" placeholder="请选择供应商" style="width: 220px;">
<el-option :label="item.purveyorName" :value="item.id" v-for="item in purveyorList"
:key="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出库时间" prop="time">
<el-date-picker v-model="queryForm.time" type="date" format="yyyy-MM-dd"
value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 220px;">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="shopTypes[shopTypesActive].value == 'reject'">
<el-col :span="8">
<el-form-item label="应收金额">
<el-input v-model="queryForm.totalAmount" placeholder="请输入应收金额"
style="width: 220px;"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实收金额">
<el-input v-model="queryForm.paidAmount" placeholder="请输入实收金额" style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="shopTypes[shopTypesActive].value == 'reject'">
<el-col :span="8">
<el-form-item label="付款时间">
<el-date-picker v-model="queryForm.paidAt" type="date" format="yyyy-MM-dd"
value-format="yyyy-MM-dd" placeholder="选择日期" style="width: 220px;">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="批号">
<el-input v-model="queryForm.batchNumber" placeholder="请输入批号" style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="queryForm.remark" placeholder="请输入备注" style="width: 220px;"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="$refs.shopList.show(tableData.list)">选择商品</el-button>
</el-form-item>
</el-form>
</div>
<div class="head-container">
<el-button type="primary" plain>
{{ tableData.list.length }}种商品金额合计<span style="color: red;">{{ queryForm.totalAmount }}</span>
</el-button>
</div>
<div class="head-container">
<el-table :data="tableData.list">
<el-table-column type="index" width="50"></el-table-column>
<el-table-column label="商品名称" prop="name">
<template v-slot="scope">
<div class="name_wrap">
<span class="name">{{ scope.row.name }}</span>
<el-tag type="info" v-if="scope.row.specSnap" size="mini">{{ scope.row.specSnap }}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="进价">
<template v-slot="scope">
<el-input-number v-model="scope.row.guidePrice" :min="0" controls-position="right"
@change="e => scope.row.totalAmount = e * scope.row.number"></el-input-number>
<div class="tips">成本价{{ scope.row.costPrice }}/{{ scope.row.unitName }}</div>
</template>
</el-table-column>
<el-table-column label="数量">
<template v-slot="scope">
<el-input-number v-model="scope.row.number" :min="0" controls-position="right"
@change="e => scope.row.totalAmount = e * scope.row.guidePrice"></el-input-number>
<div class="tips">出库前{{ scope.row.stockNumber }}{{ scope.row.unitName }}</div>
</template>
</el-table-column>
<el-table-column label="小计">
<template v-slot="scope">
<el-input-number v-model="scope.row.totalAmount" :min="0"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="变动后剩余库存">
<template v-slot="scope">
{{ scope.row.stockNumber - scope.row.number }}{{ scope.row.unitName }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<el-button type="text" @click="tableData.list.splice(scope.$index, 1)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div>
<el-button type="primary" @click="submitHandle" :loading="queryFormLoading">确定</el-button>
</div>
<shopList ref="shopList" @success="selectShop" />
<el-dialog :visible.sync="showResult" :show-close="false" :close-on-press-escape="false"
:close-on-click-modal="false">
<el-result icon="success" title="出库提交成功" :subTitle="`共操作${tableData.list.length}件商品`">
<template slot="extra">
<el-button type="primary" size="medium" @click="resetHandle">创建新的出库单</el-button>
<router-link to="/invoicing/operating_record">
<el-button size="medium">历史提交</el-button>
</router-link>
</template>
</el-result>
</el-dialog>
</div>
</template>
<script>
import dayjs from 'dayjs'
import shopList from '@/components/shopList'
import { tbShopPurveyorGet, tbProductStockOperateOutAndOn } from '@/api/invoicing'
export default {
components: {
shopList
},
data() {
return {
shopTypesActive: 0,
shopTypes: [
{
label: '供应商退货',
value: 'reject'
},
{
label: '其他出库',
value: 'other-out'
}
],
resetForm: '',
queryFormLoading: false,
queryForm: {
batchNumber: '',
list: [],
paidAmount: 0,
paidAt: '',
purveyorId: '',
purveyorName: '',
remark: '',
time: dayjs().format('YYYY-MM-DD'),
totalAmount: 0,
type: 'reject',
shopId: localStorage.getItem('shopId')
},
queryRules: {
purveyorId: [
{
required: true,
message: ' ',
trigger: 'change'
}
],
time: [
{
required: true,
message: ' ',
trigger: 'change'
}
]
},
purveyorList: [],
tableData: {
list: []
},
showResult: false
}
},
mounted() {
this.resetForm = { ...this.queryForm }
this.tbShopPurveyorGet()
},
methods: {
// 提交
submitHandle() {
this.$refs.queryForm.validate(async valid => {
if (valid) {
try {
this.queryFormLoading = true
this.queryForm.list = this.tableData.list
await tbProductStockOperateOutAndOn(this.queryForm)
this.queryFormLoading = false
this.showResult = true
} catch (error) {
console.log(error)
this.queryFormLoading = false
}
}
})
},
// 选择商品
selectShop(res) {
let arr = []
res.forEach(item => {
item.skuList.forEach(i => {
arr.push({
name: item.name,
unitName: item.unitName,
productId: item.id,
number: 0,
totalAmount: '',
...i
})
})
})
console.log(arr)
this.tableData.list = arr
},
// 初始化
resetHandle() {
this.showResult = false
this.queryForm = { ...this.resetForm }
this.tableData.list = []
},
// 切换类型
changeTypeEnum(index) {
this.shopTypesActive = index
this.queryForm.type = this.shopTypes[index].value
},
// 获取供应商列表
async tbShopPurveyorGet() {
try {
const res = await tbShopPurveyorGet({
shopId: localStorage.getItem('shopId'),
page: 0,
size: 100
})
this.purveyorList = res.content
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style scoped lang="scss">
.name_wrap {
display: flex;
align-items: center;
.name {
margin-right: 10px;
}
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<div class="app-container">
<div class="head-container">
<div class="filter_wrap">
<el-input v-model="query.name" clearable placeholder="供应商" @keyup.enter.native="getTableData"
style="width: 200px;" />
<el-select v-model="query.type" placeholder="付款状态">
<el-option :label="item.label" :value="item.value" v-for="item in types" :key="item.id"></el-option>
</el-select>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="供应商" prop="purveyorName"></el-table-column>
<el-table-column label="剩余付款金额" prop="waitAmount">
<template v-slot="scope">
<span class="num" v-if="scope.row.waitAmount > 0">{{ scope.row.waitAmount }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="待付款笔数" prop="waitCount">
<template v-slot="scope">
<template v-if="scope.row.waitCount > 0">
<span class="count">{{ scope.row.waitCount }}</span>未付
</template>
<template v-else>-</template>
</template>
</el-table-column>
<el-table-column label="状态" prop="type">
<template v-slot="scope">
<el-tag :type="scope.row.type == 0 ? 'warning' : 'success'">
{{ scope.row.type == 0 ? '待支付' : '已完结' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="上笔进货日期" prop="lastTransactAt">
<template v-slot="scope">
{{ dayjs(scope.row.lastTransactAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<router-link :to="{ name: 'purchase_detail', query: { purveyorId: scope.row.purveyorId } }">
<el-button type="text" size="mini">查看详情</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { tbShopPurveyorTransactGet, dictDetail } from '@/api/invoicing'
export default {
data() {
return {
dayjs,
types: [],
query: {
name: '',
type: ''
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
}
}
},
mounted() {
this.dictDetail()
this.getTableData()
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopPurveyorTransactGet({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
purveyorName: this.query.name,
status: this.query.type,
type: 'purveyor',
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.type = ''
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
async dictDetail() {
const { content } = await dictDetail({
dictName: 'purveyor_transact_status',
size: 100,
page: 0
})
this.types = content
}
}
}
</script>
<style scoped lang="scss">
.num {
color: #F56C6C;
font-weight: bold;
}
.count {
color: #409EFF;
}
</style>

View File

@@ -0,0 +1,350 @@
<template>
<div class="app-container">
<div class="head-container">
<el-radio-group v-model="query.time" @change="timeChange">
<el-radio-button :label="item.value" v-for="item in timeList" :key="item.label">{{ item.label
}}</el-radio-button>
</el-radio-group>
</div>
<div class="head-container" v-if="query.time == 'custom'">
<el-date-picker v-model="query.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" @change="getTableData">
</el-date-picker>
</div>
<div class="head-container">
<div class="filter_wrap">
<el-select v-model="query.type" placeholder="付款状态">
<el-option :label="item.label" :value="item.value" v-for="item in types" :key="item.id"></el-option>
</el-select>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
</div>
<div class="head-container">
<div class="info_list">
<div class="item">
<div class="icon_wrap" style="background-color: #F2D7FF;">
<i class="icon el-icon-info" style="color:#C978EE;"></i>
</div>
<div class="info">
<div class="n">{{ info.totalAmount }}</div>
<div class="intro">总交易{{ info.waitCount }}</div>
</div>
</div>
<div class="item">
<div class="icon_wrap" style="background-color: #DFFECC;">
<i class="icon el-icon-success" style="color:#47B505;"></i>
</div>
<div class="info">
<div class="n">{{ info.paidAmount }}</div>
<div class="intro">已支付金额</div>
</div>
</div>
<div class="item">
<div class="icon_wrap" style="background-color: #FFE7D6;">
<i class="icon el-icon-circle-plus" style="color: #FF6B00;"></i>
</div>
<div class="info">
<div class="n">{{ info.waitAmount }}</div>
<div class="intro">待支付金额</div>
</div>
</div>
<div class="item">
<div class="icon_wrap" style="background-color: #FFF1D5;">
<i class="icon el-icon-warning" style="color: #FEB420;"></i>
</div>
<div class="info">
<div class="n">{{ info.waitNumber }}</div>
<div class="intro">待支付笔数</div>
</div>
</div>
</div>
</div>
<div class="head-container">
<div class="select_count_wrap">
<div class="select_count">
<i class="icon el-icon-warning"></i>
已选中
<span class="n">{{ selectCount }}</span>
</div>
<el-button>批量付款</el-button>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading" @select="selectHandle"
@select-all="selectHandle">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column label="创建日期" prop="createdAt">
<template v-slot="scope">
{{ dayjs(scope.row.createdAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="类型" prop="type">
<template v-slot="scope">
进货单
</template>
</el-table-column>
<el-table-column label="总金额" prop="totalAmount">
<template v-slot="scope">
{{ scope.row.totalAmount }}
</template>
</el-table-column>
<el-table-column label="待付款金额" prop="waitAmount">
<template v-slot="scope">
<span class="num" v-if="scope.row.waitAmount > 0">{{ scope.row.waitAmount }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="状态" prop="status">
<template v-slot="scope">
<el-tag type="info">{{ types.find(item => item.value == scope.row.status).label }}</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="付款时间" prop="updatedAt">
<template v-slot="scope">
{{ scope.row.paidAt && dayjs(scope.row.paidAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<router-link :to="{ name: 'purchase_detail', query: { purveyorId: scope.row.purveyorId } }">
<el-button type="text" size="mini">查看详情</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { tbShopPurveyorTransactInfo, dictDetail, tbShopPurveyorTransactSum } from '@/api/invoicing'
export default {
data() {
return {
dayjs,
timeList: [
{
label: '全部',
value: 'all'
},
{
label: '今天',
value: '0'
},
{
label: '昨天',
value: '-1'
},
{
label: '最近7天',
value: '-7'
},
{
label: '最近30天',
value: '-30'
},
{
label: '本周',
value: 'week'
},
{
label: '本月',
value: 'moth'
},
{
label: '自定义',
value: 'custom'
}
],
types: [],
selectCount: 0,
query: {
type: '',
time: 'all',
createdAt: []
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
},
info: ''
}
},
mounted() {
this.dictDetail()
this.getTableData()
this.tbShopPurveyorTransactSum()
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopPurveyorTransactInfo({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
purveyorId: this.$route.query.purveyorId,
status: this.query.type,
type: 'purveyor',
createdAt: this.query.createdAt
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 重置查询
resetHandle() {
this.query.time = 'all'
this.query.createdAt = []
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
async dictDetail() {
const { content } = await dictDetail({
dictName: 'purveyor_transact_status',
size: 100,
page: 0
})
this.types = content
},
// 选择时间
timeChange(e) {
this.query.createdAt = []
const format0 = 'YYYY-MM-DD 00:00:00'
const format1 = 'YYYY-MM-DD 23:59:59'
switch (e) {
case '0':
this.query.createdAt = [dayjs().format(format0), dayjs().format(format1)]
break;
case '-1':
this.query.createdAt = [dayjs().add(-1, 'day').format(format0), dayjs().add(-1, 'day').format(format1)]
break;
case '-7':
this.query.createdAt = [dayjs().add(-7, 'day').format(format0), dayjs().format(format1)]
break;
case '-30':
this.query.createdAt = [dayjs().add(-30, 'day').format(format0), dayjs().format(format1)]
break;
case 'week':
this.query.createdAt = [dayjs().startOf('week').format(format0), dayjs().endOf('week').format(format1)]
break;
case 'moth':
this.query.createdAt = [dayjs().startOf('month').format(format0), dayjs().endOf('month').format(format1)]
break;
default:
break;
}
this.getTableData()
},
selectHandle(selection, row) {
this.selectCount = 0
this.selectCount = selection.length
},
async tbShopPurveyorTransactSum() {
this.info = await tbShopPurveyorTransactSum({ purveyorId: this.$route.query.purveyorId, type: 'purveyor' })
}
}
}
</script>
<style scoped lang="scss">
.select_count_wrap {
display: flex;
align-items: center;
.select_count {
display: flex;
align-items: center;
justify-content: center;
background-color: #e7f3ff;
width: 120px;
height: 40px;
font-size: 14px;
margin-right: 10px;
border-radius: 4px;
.icon {
margin-right: 4px;
}
.n {
margin: 0 4px;
}
.icon,
.n {
color: #409EFF;
}
}
}
.num {
color: #F56C6C;
font-weight: bold;
}
.count {
color: #409EFF;
}
.info_list {
display: flex;
gap: 20px;
.item {
flex: 1;
background-color: #fff;
padding: 20px;
display: flex;
align-items: center;
background-color: #f5f5f5;
.icon_wrap {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
padding: 2px;
.icon {
font-size: 40px;
}
}
.info {
flex: 1;
display: flex;
flex-direction: column;
padding-left: 20px;
.n {
font-size: 28px;
text-indent: -6px;
}
.intro {
font-size: 12px;
color: #999;
}
}
}
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<div class="app-container">
<div class="head-container">
<div class="filter_wrap">
<el-input v-model="query.name" clearable placeholder="供应商" @keyup.enter.native="getTableData"
style="width: 200px;" />
<el-select v-model="query.type" placeholder="付款状态">
<el-option :label="item.label" :value="item.value" v-for="item in types" :key="item.id"></el-option>
</el-select>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="供应商" prop="purveyorName"></el-table-column>
<el-table-column label="剩余付款金额" prop="waitAmount">
<template v-slot="scope">
<span class="num" v-if="scope.row.waitAmount > 0">{{ scope.row.waitAmount }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="待付款笔数" prop="waitCount">
<template v-slot="scope">
<template v-if="scope.row.waitCount > 0">
<span class="count">{{ scope.row.waitCount }}</span>未付
</template>
<template v-else>-</template>
</template>
</el-table-column>
<el-table-column label="状态" prop="type">
<template v-slot="scope">
<el-tag :type="scope.row.type == 0 ? 'warning' : 'success'">
{{ scope.row.type == 0 ? '待支付' : '已完结' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="上笔进货日期" prop="lastTransactAt">
<template v-slot="scope">
{{ dayjs(scope.row.lastTransactAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<router-link :to="{ name: 'purchase_detail', query: { purveyorId: scope.row.purveyorId } }">
<el-button type="text" size="mini">查看详情</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { tbShopPurveyorTransactGet, dictDetail } from '@/api/invoicing'
export default {
data() {
return {
dayjs,
types: [],
query: {
name: '',
type: ''
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
}
}
},
mounted() {
this.dictDetail()
this.getTableData()
},
methods: {
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopPurveyorTransactGet({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
purveyorName: this.query.name,
status: this.query.type,
type: 'reject',
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.type = ''
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
async dictDetail() {
const { content } = await dictDetail({
dictName: 'purveyor_transact_status',
size: 100,
page: 0
})
this.types = content
}
}
}
</script>
<style scoped lang="scss">
.num {
color: #F56C6C;
font-weight: bold;
}
.count {
color: #409EFF;
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div class="app-container">
<div class="head-container">
<div class="filter_wrap">
<el-input v-model="query.name" size="small" clearable placeholder="供应商" @keyup.enter.native="getTableData"
style="width: 200px;" />
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</div>
</div>
<div class="head-container">
<el-button type="primary" icon="el-icon-plus" @click="$refs.addSupplier.show()">添加供应商</el-button>
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="供应商" prop="purveyorName"></el-table-column>
<el-table-column label="联系电话" prop="purveyorTelephone"></el-table-column>
<el-table-column label="地址" prop="address"></el-table-column>
<el-table-column label="标签" prop="tip"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="text" size="mini" round icon="el-icon-edit"
@click="$refs.addSupplier.show(scope.row)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="delHandle([scope.row.id])">
<el-button type="text" size="mini" round icon="el-icon-delete" slot="reference">
删除
</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
<addSupplier ref="addSupplier" @success="getTableData" />
</div>
</template>
<script>
import { tbShopPurveyorGet, tbShopPurveyor } from '@/api/invoicing'
import addSupplier from '../components/addSupplier'
export default {
components: {
addSupplier
},
data() {
return {
query: {
name: ''
},
tableData: {
page: 0,
size: 10,
total: 0,
sort: 'id',
loading: false,
list: []
}
}
},
mounted() {
this.getTableData()
},
methods: {
// 删除
async delHandle(ids) {
try {
await tbShopPurveyor(ids, 'delete')
this.$notify({
title: '成功',
message: `删除成功`,
type: 'success'
});
this.getTableData()
} catch (error) {
console.log(error)
}
},
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopPurveyorGet({
page: this.tableData.page,
size: this.tableData.size,
sort: this.tableData.sort,
purveyorName: this.query.name,
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error);
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
}
}
}
</script>

View File

@@ -1,8 +1,9 @@
<template> <template>
<div class="login" :style="'background-image:url('+ Background +');'"> <div class="login" :style="'background-image:url(' + Background + ');'">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px"
class="login-form">
<h3 class="title"> <h3 class="title">
收银机后台 银收客后台管理
</h3> </h3>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
@@ -10,23 +11,28 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin"> <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
@keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="code"> <el-form-item prop="code">
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin"> <div class="code_wrap">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> <el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
</el-input> @keyup.enter.native="handleLogin">
<div class="login-code"> <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
<img :src="codeUrl" @click="getCode"> </el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode">
</div>
</div> </div>
</el-form-item> </el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;"> <el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;">
记住我 记住我
</el-checkbox> </el-checkbox>
<el-form-item style="width:100%;"> <el-form-item style="width:100%;">
<el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> <el-button :loading="loading" size="medium" type="primary" style="width:100%;"
@click.native.prevent="handleLogin">
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
<span v-else> 中...</span> <span v-else> 中...</span>
</el-button> </el-button>
@@ -47,7 +53,7 @@ import Config from '@/settings'
import { getCodeImg } from '@/api/login' import { getCodeImg } from '@/api/login'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import qs from 'qs' import qs from 'qs'
import Background from '@/assets/images/background.webp' import Background from '@/assets/images/background_img.jpg'
export default { export default {
name: 'Login', name: 'Login',
data() { data() {
@@ -56,8 +62,8 @@ export default {
codeUrl: '', codeUrl: '',
cookiePass: '', cookiePass: '',
loginForm: { loginForm: {
username: 'admin', username: '',
password: '123456', password: '',
rememberMe: false, rememberMe: false,
code: '', code: '',
uuid: '' uuid: ''
@@ -73,7 +79,7 @@ export default {
}, },
watch: { watch: {
$route: { $route: {
handler: function(route) { handler: function (route) {
const data = route.query const data = route.query
if (data && data.redirect) { if (data && data.redirect) {
this.redirect = data.redirect this.redirect = data.redirect
@@ -169,47 +175,60 @@ export default {
</script> </script>
<style rel="stylesheet/scss" lang="scss"> <style rel="stylesheet/scss" lang="scss">
.login { .login {
display: flex; display: flex;
justify-content: center; justify-content: flex-end;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-size: cover; background-size: cover;
} padding-right: 15%;
.title { }
margin: 0 auto 30px auto;
text-align: center; .title {
color: #707070; margin: 0 auto 50px auto;
text-align: center;
color: #707070;
font-size: 36px;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 500px;
padding: 50px 50px 50px 50px;
.el-input {
height: 38px;
input {
height: 38px;
}
} }
.login-form { .input-icon {
border-radius: 6px; height: 39px;
background: #ffffff; width: 14px;
width: 385px; margin-left: 2px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon{
height: 39px;width: 14px;margin-left: 2px;
}
} }
.login-tip { }
font-size: 13px;
text-align: center; .login-tip {
color: #bfbfbf; font-size: 13px;
} text-align: center;
.login-code { color: #bfbfbf;
width: 33%; }
display: inline-block; .code_wrap {
height: 38px; display: flex;
float: right; justify-content: space-between;
img{ }
cursor: pointer; .login-code {
vertical-align:middle width: 33%;
} display: inline-block;
height: 38px;
img {
cursor: pointer;
vertical-align: middle
} }
}
</style> </style>

View File

@@ -0,0 +1,340 @@
<template>
<el-drawer title="订单详情" size="50%" :visible.sync="drawer" direction="rtl" v-loading="loading">
<div class="header">
<div class="title">收银订单</div>
<div class="table">
<div class="item">
<div class="t">订单状态</div>
<div class="b">
<el-tag :type="detail.status == 'closed' ? 'success' : 'warning'">{{
detail.status |
statusFilter
}}</el-tag>
</div>
</div>
<div class="item">
<div class="t">订单金额</div>
<div class="b">
{{ detail.orderAmount }}
</div>
</div>
<div class="item">
<div class="t">订单时间</div>
<div class="b">
{{ detail.createdAt | timeFilter }}
</div>
</div>
</div>
</div>
<div class="container">
<el-tabs v-model="type" @tab-click="getTableData">
<el-tab-pane label="基本信息" name="1">
<div class="info_content">
<div class="item">
<div class="label">会员信息</div>
<div class="row">
<div>会员昵称-</div>
<div>联系电话-</div>
</div>
</div>
<div class="item">
<div class="label">收款详情</div>
<div class="row">
<div>商品金额{{ detail.productAmount }}</div>
<div>打包费{{ detail.packFee || '-' }}</div>
</div>
<div class="row">
<div>订单原价{{ detail.originAmount }}</div>
<div>优惠金额{{ detail.userCouponAmount || '-' }}</div>
<div>实收金额<span style="color: red;">{{ detail.payAmount }}</span> </div>
</div>
<div class="row">
<div>退款金额{{ detail.refundAmount }} <span style="color: #FF9731;cursor: pointer;"
v-if="detail.isRefund" @click="type = '3'">退款详情></span>
</div>
<div>支付方式现金</div>
</div>
</div>
<div class="item">
<div class="label">订单信息</div>
<div class="row">
<div>订单编号{{ detail.orderNo }}</div>
<div>订单类型{{ detail.sendType | sendTypeFilter }}</div>
<div>创建时间{{ detail.createdAt | timeFilter }}</div>
</div>
<div class="row">
<div>设备名称-</div>
<div>支付时间{{ detail.paidTime | timeFilter }}</div>
<div>更新时间{{ detail.updatedAt | timeFilter }}</div>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="商品信息" name="2">
<el-table :data="detail.detailList">
<el-table-column label="商品">
<template v-slot="scope">
<div class="shop_info">
<el-image :src="scope.row.productImg" style="width: 40px;height: 40px;"></el-image>
<div class="info">
<span>{{ scope.row.productName }}</span>
<span style="color: #999;">{{ scope.row.productSkuName }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="数量">
<template v-slot="scope">
x{{ scope.row.num }}
</template>
</el-table-column>
<el-table-column label="单价">
<template v-slot="scope">
{{ scope.row.price }}/
</template>
</el-table-column>
<el-table-column label="小计">
<template v-slot="scope">
{{ scope.row.priceAmount }}
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="退款详情" name="3" v-if="detail.isRefund">
<div class="refund_wrap">
<div class="row" v-for="item in refoundList" :key="item.id">
<div class="time">{{ item.createdAt | timeFilter }}</div>
<div class="list">
<div class="list_row" v-for="val in item.detailList">
<div class="item">
<el-image :src="val.productImg" style="width: 50px;height: 50px;"></el-image>
<span class="name">{{ val.productName }}</span>
</div>
<div class="item">
<span>退-{{ val.num }}</span>
</div>
<div class="item">
<span>{{ val.priceAmount }}</span>
</div>
<div class="item">
<span>-{{ val.priceAmount }}</span>
</div>
</div>
</div>
<div class="foot">退款-{{item.refundAmount}}</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-drawer>
</template>
<script>
import orderEnum from '../orderEnum';
import dayjs from 'dayjs'
import { tbOrderInfoDetail, tbOrderInfoData } from '@/api/order'
export default {
data() {
return {
orderEnum,
drawer: false,
type: '1',
detail: '',
loading: false,
refoundList: []
}
},
filters: {
orderTypeFilter(t) {
if (t) {
return t && orderEnum.orderType.find(item => item.key == t).label
} else {
return t
}
},
sendTypeFilter(t) {
if (t) {
return orderEnum.sendType.find(item => item.key == t).label
} else {
return t
}
},
statusFilter(t) {
if (t) {
return t && orderEnum.status.find(item => item.key == t).label
} else {
return t
}
},
timeFilter(t) {
if (t) {
return dayjs(t).format('YYYY-MM-DD HH:mm:ss')
} else {
return '-'
}
}
},
methods: {
// 切换类型
getTableData() {
if (this.type == '3') {
this.tbOrderInfoData()
}
},
// 获取退单列表
async tbOrderInfoData() {
try {
const res = await tbOrderInfoData({
source: this.detail.id,
page: 0,
pageSize: 500,
orderType: '0'
})
this.refoundList = res.content
} catch (error) {
console.log(error)
}
},
// 获取订单详情
async tbOrderInfoDetail(id) {
try {
this.loading = true
const res = await tbOrderInfoDetail(id)
this.detail = res
this.loading = false
} catch (error) {
console.log(error)
}
},
show(obj) {
this.drawer = true
this.type = '1'
this.detail = ''
this.tbOrderInfoDetail(obj.id)
}
}
}
</script>
<style scoped lang="scss">
.shop_info {
display: flex;
.info {
flex: 1;
display: flex;
flex-direction: column;
padding-left: 6px;
}
}
.header {
padding: 0 20px 0;
.title {
font-size: 20px;
color: #FF9731;
}
.table {
display: flex;
padding: 20px 0;
.item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 14px;
.b {
padding-top: 20px;
}
}
}
}
.container {
padding: 0 20px;
font-size: 14px;
.info_content {
padding: 20px 0;
.item {
border-bottom: 1px dashed #ececec;
padding-bottom: 20px;
&:not(:first-child) {
margin-top: 20px;
}
.label {
position: relative;
padding-left: 20px;
color: #333;
&::after {
content: "";
width: 4px;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: #1890FF;
}
}
.row {
display: flex;
color: #555;
padding-top: 20px;
div {
width: 33.333%;
}
}
}
}
.refund_wrap {
.row {
border-bottom: 1px dashed #ececec;
padding-bottom: 20px;
&:not(:first-child) {
margin-top: 20px;
}
.time {
font-weight: bold;
color: #333;
}
.list {
.list_row {
display: flex;
padding-top: 10px;
.item {
flex: 1;
display: flex;
color: #555;
.name {
margin-left: 6px;
}
}
}
}
.foot {
color: #333;
display: flex;
justify-content: flex-end;
}
}
}
}
</style>

View File

@@ -0,0 +1,84 @@
export default {
status: [
{
key: 'unpaid',
label: '待支付'
},
{
key: 'unsend',
label: '待发货'
},
{
key: 'closed',
label: '订单完成'
},
{
key: 'send',
label: '已发'
},
{
key: 'refunding',
label: '申请退单'
},
{
key: 'refund',
label: '退单'
},
{
key: 'cancelled',
label: '取消订单'
},
{
key: 'merge',
label: '合台'
},
{
key: 'pending',
label: '挂单'
},
{
key: 'activate',
label: '激活'
},
{
key: 'paying',
label: '支付中'
}
],
sendType: [
{
key: 'post',
label: '快递'
},
{
key: 'takeaway',
label: '外卖'
},
{
key: 'takeself',
label: '自提'
},
{
key: 'table',
label: '堂食'
}
],
orderType: [
{
key: 'cash',
label: '收银'
},
{
key: 'miniapp',
label: '小程序'
},
{
key: 'offline',
label: '线下'
},
{
key: 'return',
label: '退单'
}
]
}

View File

@@ -0,0 +1,446 @@
<template>
<div class="app-container">
<el-tabs v-model="orderType" @tab-click="getTableData">
<el-tab-pane label="全部订单" name=""></el-tab-pane>
<el-tab-pane label="收银订单" name="cash"></el-tab-pane>
<el-tab-pane label="小程序订单" name="miniapp"></el-tab-pane>
</el-tabs>
<div class="head-container">
<el-form :model="query" label-width="100px" label-position="left">
<el-form-item label="订单状态">
<el-radio-group v-model="query.status">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button :label="item.key" v-for="item in orderEnum.status" :key="item.key">
{{ item.label }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="支付方式">
<el-radio-group v-model="query.payType">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button :label="item.payType" v-for="item in payTypes" :key="item.payType">
{{ item.payName }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="创建时间">
<el-radio-group v-model="timeValue" @change="timeChange">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button label="0">今天</el-radio-button>
<el-radio-button label="-1">昨天</el-radio-button>
<el-radio-button label="-7">最近7天</el-radio-button>
<el-radio-button label="-30">最近30天</el-radio-button>
<el-radio-button label="week">本周</el-radio-button>
<el-radio-button label="month">本月</el-radio-button>
<el-radio-button label="custom">自定义</el-radio-button>
</el-radio-group>
<el-date-picker v-model="query.createdAt" type="daterange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']"
value-format="yyyy-MM-dd HH:mm:ss" v-if="timeValue == 'custom'">
</el-date-picker>
</el-form-item>
<el-form-item label="订单号">
<el-input v-model="query.orderNo" placeholder="请输入订单号" style="width: 300px;"></el-input>
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
<el-button icon="el-icon-download" v-loading="downloadLoading" @click="downloadHandle">
<span v-if="!downloadLoading">导出Excel</span>
<span v-else>下载中...</span>
</el-button>
</el-form-item>
</el-form>
</div>
<div class="head-container">
<div class="collect_wrap">
<div class="item">
<div class="icon_wrap" style="--bg-color:#C978EE">
<i class="icon el-icon-s-goods"></i>
</div>
<div class="info">
<div class="m">{{ payCountTotal }}</div>
<div class="t">总金额</div>
</div>
</div>
<div class="item" v-for="item in payCountList" :key="item.payType">
<div class="icon_wrap" style="--bg-color:#fff">
<el-image class="img" :src="item.icon"></el-image>
</div>
<div class="info">
<div class="m">{{ item.payAmount || 0 }}</div>
<div class="t">{{ item.payType }}</div>
</div>
</div>
</div>
</div>
<div class="head-container">
<el-table :data="tableData.data" v-loading="tableData.loading">
<el-table-column label="订单号信息">
<template v-slot="scope">
<div class="table_order_info">
<div class="order_no">{{ scope.row.orderNo }}</div>
<!-- <div>会员 {{ scope.row.orderNo }}</div> -->
<div class="type">{{ scope.row.orderType | orderTypeFilter }} {{ scope.row.sendType |
sendTypeFilter }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="商品信息">
<template v-slot="scope">
<div class="goods_info">
<div class="row" v-for="item in scope.row.detailList" :key="item.id">
<el-image :src="item.productImg" class="cover" lazy></el-image>
<div class="info">
<div class="name">{{ item.productName }} <span class="refund"
v-if="item.status == 'refunding' || item.status == 'refund'">(退 - {{
item.num }})</span></div>
<div class="sku">{{ item.productSkuName }} </div>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="订单金额">
<template v-slot="scope">
<div>{{ scope.row.orderType | orderTypeFilter }}</div>
<div class="refund" v-if="scope.row.status == 'refunding' || scope.row.status == 'refund'">
退款-{{
scope.row.refundAmount }}</div>
<div>{{ scope.row.productAmount }}</div>
</template>
</el-table-column>
<el-table-column label="状态">
<template v-slot="scope">
<template v-if="scope.row.status == 'refund' && scope.row.orderType != 'return'">
<el-tag type="primary">已完成</el-tag>
</template>
<template v-else>
<el-tag type="primary" v-if="scope.row.status == 'closed'">
{{ scope.row.status | statusFilter }}
</el-tag>
<el-tag type="warning" v-if="scope.row.status != 'closed'">
{{ scope.row.status | statusFilter }}
</el-tag>
</template>
</template>
</el-table-column>
<el-table-column label="创建时间">
<template v-slot="scope">
{{ scope.row.createdAt | timeFilter }}
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="scope">
<el-button type="text" @click="$refs.orderDetail.show(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" @size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
<orderDetail ref="orderDetail" />
</div>
</template>
<script>
import orderEnum from './orderEnum'
import { tbShopPayTypeGet } from '@/api/setting'
import { tbOrderInfoData, tbOrderInfoDownload, payCount } from '@/api/order'
import dayjs from 'dayjs'
import { downloadFile } from '@/utils/index'
import orderDetail from './components/orderDetail'
export default {
components: { orderDetail },
data() {
return {
orderEnum,
payTypes: [],
timeValue: '',
resetQuery: null,
orderType: "",
query: {
id: '',
status: '',
payType: '',
orderNo: '',
createdAt: []
},
tableData: {
data: [],
page: 0,
size: 10,
loading: false,
total: 0
},
downloadLoading: false,
payCountList: '',
payCountTotal: 0
}
},
filters: {
orderTypeFilter(t) {
if (t) {
return t && orderEnum.orderType.find(item => item.key == t).label
} else {
return t
}
},
sendTypeFilter(t) {
if (t) {
return orderEnum.sendType.find(item => item.key == t).label
} else {
return t
}
},
statusFilter(t) {
if (t) {
return t && orderEnum.status.find(item => item.key == t).label
} else {
return t
}
},
timeFilter(time) {
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
}
},
mounted() {
this.resetQuery = { ...this.query }
this.tbShopPayTypeGet()
this.getTableData()
this.payCount()
},
methods: {
// 获取订单汇总
async payCount() {
try {
const res = await payCount()
this.payCountList = res
let total = 0
res.map(item => {
total += item.payAmount
})
this.payCountTotal = Math.floor(total * 100) / 100
} catch (error) {
console.log(error);
}
},
// 导出Excel
async downloadHandle() {
try {
this.downloadLoading = true
const file = await tbOrderInfoDownload({
orderType: this.orderType,
shopId: localStorage.getItem('shopId'),
...this.query
})
downloadFile(file, '订单数据', 'xlsx')
this.downloadLoading = false
} catch (error) {
this.downloadLoading = false
console.log(error);
}
},
// 重置查询
resetHandle() {
this.timeValue = ''
this.query = { ...this.resetQuery }
this.page = 0
this.getTableData()
},
// 分页大小改变
sizeChange(e) {
this.tableData.size = e
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbOrderInfoData({
page: this.tableData.page,
pageSize: this.tableData.size,
orderType: this.orderType,
...this.query
})
this.tableData.loading = false
this.tableData.data = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
},
// 切换时间
timeChange(e) {
const format = ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']
switch (e) {
case '':
// 全部
this.query.createdAt = []
break;
case '0':
// 今天
this.query.createdAt = [dayjs().format(format[0]), dayjs().format(format[1])]
break;
case '-1':
// 昨天
this.query.createdAt = [dayjs().add(-1, 'd').format(format[0]), dayjs().add(-1, 'd').format(format[1])]
break;
case '-7':
// 最近7天
this.query.createdAt = [dayjs().add(-7, 'd').format(format[0]), dayjs().format(format[1])]
break;
case '-30':
// 最近7天
this.query.createdAt = [dayjs().add(-30, 'd').format(format[0]), dayjs().format(format[1])]
break;
case 'week':
// 本周
this.query.createdAt = [dayjs().startOf('week').format(format[0]), dayjs().endOf('week').format(format[1])]
break;
case 'month':
// 本周
this.query.createdAt = [dayjs().startOf('month').format(format[0]), dayjs().endOf('month').format(format[1])]
break;
case 'custom':
// 自定义
this.query.createdAt = []
break;
default:
break;
}
},
// 获取支付方式
async tbShopPayTypeGet() {
try {
const { content } = await tbShopPayTypeGet({
page: 0,
size: 100,
shopId: localStorage.getItem('shopId')
})
this.payTypes = content
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style scoped lang="scss">
.collect_wrap {
display: flex;
gap: 14px;
.item {
flex: 1;
display: flex;
align-items: center;
background-color: #f5f5f5;
padding: 20px;
.icon_wrap {
$size: 34px;
$border: 6px;
width: $size;
height: $size;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--bg-color);
border-radius: 50%;
position: relative;
&::after {
content: "";
width: $size + $border;
height: $size + $border;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--bg-color);
opacity: .3;
}
.icon {
font-size: 16px;
color: #fff;
}
.img {
width: 20px;
height: 20px;
}
}
.info {
flex: 1;
display: flex;
flex-direction: column;
padding-left: 10px;
.m {
font-weight: bold;
}
.t {
font-size: 12px;
color: #999;
padding-top: 4px;
}
}
}
}
.refund {
color: #FF9731;
font-weight: bold;
}
.table_order_info {
.order_no {
color: #999;
}
.type {
color: #E6A23C;
}
}
.goods_info {
.row {
display: flex;
&:not(:first-child) {
margin-top: 10px;
}
.cover {
width: 40px;
height: 40px;
}
.info {
flex: 1;
display: flex;
flex-direction: column;
padding-left: 10px;
.sku {
color: #999;
}
}
}
}
</style>

View File

@@ -0,0 +1,717 @@
<template>
<div class="app-container">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="商品类型" prop="typeEnum">
<div class="shop_type_box" :class="{ disabled: form.id }">
<div class="item" v-for="(item, index) in shopTypes" :key="index"
:class="{ active: shopTypesActive == index }" @click="changeTypeEnum(index)">
<div class="s_title">{{ item.label }}</div>
<div class="intro">{{ item.intro }}</div>
<div class="active_dot">
<i class="el-icon-check"></i>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="商品名称" prop="name">
<el-input v-model="form.name" placeholder="请输入商品名称" style="width: 500px;"></el-input>
</el-form-item>
<el-form-item label="单位">
<el-select v-model="form.unitId" placeholder="请选择单位" style="width: 500px;" @change="selectUnitt">
<el-option :label="item.name" :value="item.id" v-for="item in units" :key="item.id"></el-option>
</el-select>
<el-button type="primary" plain icon="el-icon-plus" @click="$refs.addUnitRef.show()">添加单位</el-button>
<addUnit ref="addUnitRef" @success="tbShopUnit" />
</el-form-item>
<el-form-item label="商品分类" prop="categoryId">
<el-select v-model="form.categoryId" placeholder="请选择商品分类" style="width: 500px;">
<el-option :label="item.name" :value="item.id" v-for="item in categorys" :key="item.id"></el-option>
</el-select>
<el-button type="primary" plain icon="el-icon-plus"
@click="$refs.addClassifyRef.show()">添加分类</el-button>
<addClassify ref="addClassifyRef" @success="tbShopCategoryGet" />
</el-form-item>
<el-form-item label="商品图片">
<uploadImg ref="uploadImg" :limit="9" @success="uploadSuccess" @remove="uploadRemove" />
<div class="tips">第一张图为商品封面图图片尺寸为750×750(可拖动图片排序)</div>
</el-form-item>
<el-form-item label="套餐商品" v-if="shopTypes[shopTypesActive].typeEnum == 'group'">
<el-table :data="form.groupSnap" border v-if="form.groupSnap.length">
<el-table-column label="标题" prop="title">
<template v-slot="scope">
<el-input v-model="scope.row.title" placeholder="请输入标题:自选小吃"></el-input>
</template>
</el-table-column>
<el-table-column label="商品信息">
<template v-slot="scope">
<div class="shop_list">
<div class="item" v-for="item in scope.row.goods" :key="item.id">
<span class="dot"></span>
<div class="name">
<div class="t">{{ item.name }}</div>
</div>
<i class="del el-icon-delete"></i>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="几选几">
<template v-slot="scope">
<span>{{ scope.row.goods.length }}</span>
<el-input-number v-model="scope.row.number" controls-position="right"
:min="1"></el-input-number>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template v-slot="scope">
<el-button type="text" @click="tableAddShop(scope.$index, scope.row.goods)">添加商品</el-button>
<el-button type="text" @click="form.groupSnap.splice(scope.$index, 1)">删除分组</el-button>
</template>
</el-table-column>
</el-table>
<el-button type="text" @click="$refs.shopListRef.show()">添加分组</el-button>
<shopList ref="shopListRef" @success="selectShopRes" />
</el-form-item>
<el-form-item label="规格属性" v-if="shopTypes[shopTypesActive].typeEnum != 'sku'">
<el-table :data="form.skuList" border>
<el-table-column label="售价" prop="salePrice">
<template v-slot="scope">
<el-input-number v-model="scope.row.salePrice" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="会员价" prop="memberPrice">
<template v-slot="scope">
<el-input-number v-model="scope.row.memberPrice"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="成本价" prop="costPrice">
<template v-slot="scope">
<el-input-number v-model="scope.row.costPrice" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="原价" prop="originPrice">
<template v-slot="scope">
<el-input-number v-model="scope.row.originPrice"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="库存数量" prop="stockNumber">
<template v-slot="scope">
<el-input-number v-model="scope.row.stockNumber" :disabled="!!form.id"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="分销金额" prop="firstShared">
<template v-slot="scope">
<el-input-number v-model="scope.row.firstShared"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="商品条码">
<template v-slot="scope">
<el-input v-model="scope.row.barCode" disabled></el-input>
</template>
</el-table-column>
</el-table>
<div class="tips" v-if="form.isShowMall">小程序商城必须设置库存数量大于0</div>
</el-form-item>
<el-form-item label="选择规格" v-if="shopTypes[shopTypesActive].typeEnum == 'sku' && !form.id">
<el-select v-model="form.specId" placeholder="请选择规格" style="width: 500px;" @change="selectSpecHandle">
<el-option :label="item.name" :value="item.id" v-for="item in specList" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item :label="item.name" v-if="selectSpec.length && !isEditor" v-for="item in selectSpec"
:key="item.name">
<el-checkbox-group v-model="item.selectSpecResult" @change="selectSpecResultChange">
<el-checkbox :label="item" v-for="(item, index) in item.value
" :key="index"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item v-if="selectSpecResult && shopTypes[shopTypesActive].typeEnum == 'sku'">
<el-table :data="form.skuList" border>
<el-table-column :label="item.label" :prop="item.value" v-for="(item, index) in specTableHeaders"
:key="index">
</el-table-column>
<el-table-column label="图片" prop="coverImg" width="80">
<template v-slot="scope">
<uploadImg type="text" :limit="1" @success="res => scope.row.coverImg = res[0]"
v-if="!scope.row.coverImg" />
<el-image style="width:30px;height:30px;" :src="scope.row.coverImg" v-else />
</template>
</el-table-column>
<el-table-column label="售价" prop="salePrice">
<template slot="header" slot-scope="scope">
<span>售价</span>
<i class="icon el-icon-edit" @click="batchNumber('salePrice')"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.salePrice" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="会员价" prop="memberPrice">
<template slot="header" slot-scope="scope">
<span>会员价</span>
<i class="icon el-icon-edit" @click="batchNumber('memberPrice')"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.memberPrice"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="成本价" prop="costPrice">
<template slot="header" slot-scope="scope">
<span>成本价</span>
<i class="icon el-icon-edit" @click="batchNumber('costPrice')"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.costPrice" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="原价" prop="originPrice">
<template slot="header" slot-scope="scope">
<span>原价</span>
<i class="icon el-icon-edit" @click="batchNumber('originPrice')"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.originPrice"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="库存数量" prop="stockNumber">
<template slot="header" slot-scope="scope">
<span>库存数量</span>
<i class="icon el-icon-edit" @click="batchNumber('stockNumber')" v-if="!form.id"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.stockNumber" :disabled="!!form.id"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="分销金额" prop="firstShared">
<template slot="header" slot-scope="scope">
<span>分销金额</span>
<i class="icon el-icon-edit" @click="batchNumber('firstShared')"></i>
</template>
<template slot-scope="scope">
<el-input-number v-model="scope.row.firstShared"
controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column label="商品条码">
<template v-slot="scope">
<el-input v-model="scope.row.barCode" disabled></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template v-slot="scope">
<el-button type="text" @click="form.skuList.splice(scope.$index, 1)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="tips" v-if="form.isShowMall">注小程序商城必须设置库存数量大于0</div>
</el-form-item>
<el-form-item label="上架区域">
<div class="shop_type_box">
<div class="item" :class="{ active: form.isShowCash }" @click="areaChange('isShowCash')">
<div class="s_title">收银台</div>
<div class="active_dot">
<i class="el-icon-check"></i>
</div>
</div>
<div class="item" :class="{ active: form.isShowMall }" @click="areaChange('isShowMall')">
<div class="s_title">小程序商城</div>
<div class="active_dot">
<i class="el-icon-check"></i>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="库存开关">
<el-switch v-model="form.isStock" :active-value="1" :inactive-value="0"></el-switch>
<div class="tips">注:关闭则不计算出入库数据</div>
</el-form-item>
<el-form-item label="标签打印">
<el-switch v-model="form.enableLabel" :active-value="1" :inactive-value="0"></el-switch>
<div class="tips">开启后: 收银完成后会自动打印对应数量的标签数</div>
</el-form-item>
<el-form-item label="打包费">
<el-input-number v-model="form.packFee" controls-position="right" :min="0"></el-input-number>
<div class="tips">单份商品打包费。注:店铺开启外卖模式下该数据才生效</div>
</el-form-item>
<el-form-item label="虚拟销量">
<el-input-number v-model="form.baseSalesNumber" controls-position="right" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="form.sort" controls-position="right" :min="0"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" v-loading="loading" @click="submitHandle">确定</el-button>
<el-button @click="$router.back()">取消</el-button>
</el-form-item>
</el-form>
<el-dialog title="批量修改" width="400px" :visible.sync="showBatchModal">
<el-form :model="batchNumberForm">
<el-form-item>
<el-input-number v-model="batchNumberForm.batchNumber" :min="0" controls-position="right"
style="width: 100%;"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="showBatchModal = false">取 消</el-button>
<el-button type="primary" @click="batchNumberFormConfirm">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { tbShopUnit, tbShopCategoryGet, tbProductPost, tbProductSpecGet, tbProductGetDetail, tbProductPut } from "@/api/shop";
import addUnit from './components/addUnit'
import addClassify from './components/addClassify'
import shopList from '@/components/shopList'
import uploadImg from '@/components/uploadImg'
import settings from '@/settings'
import dayjs from 'dayjs'
import { RandomNumBoth } from "@/utils";
export default {
components: {
addUnit,
addClassify,
uploadImg,
shopList
},
data() {
return {
shopTypesActive: 0,
shopTypes: settings.typeEnum,
specTableHeaders: [],
specTableBodys: [],
specId: '',
specList: [],
selectSpec: [],
selectSpecResult: false,
defaultSku: {
salePrice: 0,
memberPrice: 0,
costPrice: 0,
originPrice: 0,
stockNumber: 0,
firstShared: 0,
barCode: `${localStorage.getItem('shopId')}${dayjs().valueOf()}`
},
tableAddShopIndex: null,
isEditor: false,
loading: false,
form: {
id: '',
typeEnum: 'normal',
name: '',
unitId: '',
unitName: '',
categoryId: '', // 商品分类id
coverImg: '',
images: [],
shopId: localStorage.getItem('shopId'),
lowPrice: '',
skuList: [],
isShowMall: 1,
isShowCash: 1,
isStock: 0,
packFee: 0,
specId: '',
baseSalesNumber: 0,
sort: 0,
groupSnap: [],
specInfo: [],
selectSpec: [],
specTableHeaders: [],
skuSnap: ''
},
rules: {
typeEnum: [
{
required: true
}
],
name: [
{
required: true,
trigger: 'blur',
message: '请输入商品名称'
}
],
categoryId: [
{
required: true,
trigger: 'change',
message: '请选择商品分类'
}
]
},
units: [],
categorys: [],
// 批量修改规格
showBatchModal: false,
batchNumberKey: '',
batchNumberForm: {
batchNumber: 0
}
}
},
mounted() {
this.tbShopUnit()
this.tbShopCategoryGet()
this.changeTypeEnum(0)
if (this.$route.query.goods_id) {
this.tbProductGetDetail()
}
},
methods: {
// 修改商家区域
areaChange(key) {
if (this.form[key] == 1) {
this.form[key] = 0
} else {
this.form[key] = 1
}
},
selectUnitt(e) {
this.form.unitName = this.units.find(item => item.id == e).name
},
// 批量修改规格
batchNumber(key) {
this.batchNumberKey = key
this.showBatchModal = true
},
// 确认批量修改规格
batchNumberFormConfirm() {
this.form.skuList.map(item => {
item[this.batchNumberKey] = this.batchNumberForm.batchNumber
})
this.showBatchModal = false
this.batchNumberForm.batchNumber = 0
},
// 商品详情
async tbProductGetDetail() {
try {
const res = await tbProductGetDetail(this.$route.query.goods_id)
// 赋值商品类型
this.changeTypeEnum(this.shopTypes.findIndex(item => item.typeEnum == res.typeEnum))
this.specTableHeaders = JSON.parse(res.specTableHeaders)
this.selectSpec = JSON.parse(res.selectSpec)
// 初始化上传图片
this.$refs.uploadImg.fileList = res.images.map(item => {
return {
url: item
}
})
this.form = res
if (res.typeEnum == 'sku') {
let skuList = [...res.skuList]
let specInfo = JSON.parse(res.specInfo)
this.isEditor = true
this.form.skuList = skuList.map((item, index) => {
specInfo[index].id = item.id
return specInfo[index]
})
this.selectSpecResult = true
}
} catch (error) {
console.log(error)
}
},
// 提交
submitHandle() {
this.$refs.formRef.validate(async faild => {
try {
if (faild) {
this.loading = true
this.form.lowPrice = this.form.skuList[0].salePrice
this.form.coverImg = this.form.images[0]
this.form.selectSpec = JSON.stringify(this.selectSpec)
this.form.specTableHeaders = JSON.stringify(this.specTableHeaders)
this.form.specInfo = JSON.stringify(this.form.skuList)
if (this.form.id) {
await tbProductPut(this.form)
} else {
await tbProductPost(this.form)
}
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
this.$router.back()
this.loading = false
}
} catch (error) {
this.loading = false
console.log(error)
}
})
},
// 给分组添加商品
tableAddShop(index, goods) {
this.tableAddShopIndex = index
this.$refs.shopListRef.show([...goods])
},
// 分组选择商品
selectShopRes(res) {
if (this.tableAddShopIndex != null) {
this.form.groupSnap[this.tableAddShopIndex].goods = res;
this.tableAddShopIndex = null
} else {
this.form.groupSnap.push({
title: '',
goods: res,
number: 1
})
}
},
// 切换类型
changeTypeEnum(index) {
if (this.form.id) return
this.shopTypesActive = index
const typeEnum = this.shopTypes[index].typeEnum
this.form.typeEnum = typeEnum
if (typeEnum == 'sku') {
this.tbProductSpecGet()
} else {
this.specId = ''
this.form.specId = ''
this.selectSpec = []
this.selectSpecResult = ''
this.form.skuList = [JSON.parse(JSON.stringify(this.defaultSku))]
}
},
// 上传图片
uploadSuccess(res) {
this.form.images.push(res[0])
},
// 删除突破按
uploadRemove(arr) {
this.form.images = arr
},
// 选择规格属性
selectSpecResultChange() {
this.createSkuHeader()
this.createSkuBody()
},
// 生成多规格表体
createSkuBody() {
let bodys = []
let skuSnap = []
for (let item of this.selectSpec) {
if (item.selectSpecResult.length) {
let arr = []
for (let val of item.selectSpecResult) {
arr.push({
[item.name]: val
})
}
skuSnap.push({
name: item.name,
value: item.selectSpecResult.join(',')
})
bodys.push(arr)
}
}
this.form.skuSnap = JSON.stringify(skuSnap)
let arr = this.cartesian(bodys)
// console.log(arr)
let newarr = []
const m = {
coverImg: '',
...this.defaultSku
}
for (let item of arr) {
if (Array.isArray(item)) {
let obj = {}
let specSnap = []
for (let v of item) {
for (let key in v) {
obj[`${key}`] = v[key]
specSnap.push(v[key])
}
}
newarr.push({
specSnap: specSnap.join(','),
...m,
...obj,
barCode: `${dayjs().valueOf()}${RandomNumBoth(1, 9999)}`
})
} else {
let specSnap = []
for (let key in item) {
specSnap.push(item[key])
}
newarr.push({
specSnap: specSnap.join(','),
...m,
...item,
barCode: `${dayjs().valueOf()}${RandomNumBoth(1, 9999)}`
})
}
}
this.form.skuList = []
this.form.skuList = newarr
},
// 笛卡尔积算法
cartesian(arr) {
if (arr.length < 2) return arr[0] || [];
return [].reduce.call(arr, (col, set) => {
let res = [];
col.forEach(c => {
set.forEach(s => {
let t = [].concat(Array.isArray(c) ? c : [c]);
t.push(s);
res.push(t);
})
});
return res;
});
},
// 生成多规格表头
createSkuHeader() {
let i = 0
const headers = []
for (let item of this.selectSpec) {
if (item.selectSpecResult.length) {
i++
headers.push({
label: item.name,
value: item.name
})
}
}
this.selectSpecResult = i
this.specTableHeaders = headers
},
// 选择规格
selectSpecHandle(e) {
this.isEditor = false
const selectSpec = JSON.parse(JSON.stringify(this.specList.find(item => item.id == e).specList))
for (let item in selectSpec) {
selectSpec[item].selectSpecResult = []
}
this.selectSpec = selectSpec
this.form.skuList = []
},
// 获取规格列表
async tbProductSpecGet() {
try {
const res = await tbProductSpecGet({
shopId: localStorage.getItem('shopId'),
sort: 'id',
page: 0,
size: 100
})
this.specList = res.content
} catch (error) { }
},
// 获取单位
async tbShopUnit() {
try {
const res = await tbShopUnit({
shopId: localStorage.getItem('shopId'),
sort: 'id',
page: 0,
size: 100
})
this.units = res.content
} catch (error) { }
},
// 商品分类列表
async tbShopCategoryGet() {
try {
const res = await tbShopCategoryGet({
shopId: localStorage.getItem('shopId'),
sort: 'id',
page: 0,
size: 100
})
let categorys = []
for (let item of res.content) {
categorys.push({
name: `|----${item.name}`,
id: item.id
})
if (item.childrenList.length) {
for (let val of item.childrenList) {
categorys.push({
name: `|----|----${val.name}`,
id: val.id
})
}
}
}
this.categorys = categorys
} catch (error) {
console.log('商品分类列表', error)
}
}
}
}
</script>
<style scoped lang="scss">
.shop_list {
.item {
display: flex;
align-items: center;
.dot {
$size: 6px;
width: $size;
height: $size;
border-radius: 50%;
background-color: #1890FF;
}
.name {
flex: 1;
margin-left: 10px;
.t {
color: #333;
font-size: 14px;
max-width: 100px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.del {
font-size: 14px;
color: #999;
&:hover {
cursor: pointer;
color: #555;
}
}
}
}
.icon {
font-size: 14px;
color: #1890FF;
margin-left: 10px;
&:hover {
cursor: pointer;
}
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<div class="app-container">
<div class="head-container">
<el-button type="primary" icon="el-icon-plus" @click="$refs.addClassifyRef.show()">添加分类</el-button>
<addClassify ref="addClassifyRef" @success="getTableData" />
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading" row-key="id"
:tree-props="{ children: 'childrenList' }">
<el-table-column label="排序" prop="sort" sortable width="100"></el-table-column>
<el-table-column label="分类名称" prop="name"></el-table-column>
<el-table-column label="分类图片">
<template v-slot="scope">
<el-image :src="scope.row.pic"
style="width: 50px;height: 50px;border-radius: 4px;background-color: #efefef;">
<div class="img_error" slot="error">
<i class="icon el-icon-document-delete"></i>
</div>
</el-image>
</template>
</el-table-column>
<el-table-column label="状态">
<template v-slot="scope">
<el-switch v-model="scope.row.isShow" :active-value="1" :inactive-value="0"></el-switch>
</template>
</el-table-column>
<el-table-column label="颜色">
<template v-slot="scope">
<div
:style="{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: scope.row.style || '#efefef' }">
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template v-slot="scope">
<el-button type="text" size="mini" round icon="el-icon-plus"
@click="$refs.addClassifyRef.show({ pid: scope.row.id })"
v-if="!scope.row.pid">添加子分类</el-button>
<el-button type="text" size="mini" round icon="el-icon-edit"
@click="$refs.addClassifyRef.show(scope.row)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="delHandle([scope.row.id])">
<el-button type="text" size="mini" round icon="el-icon-delete" slot="reference">
删除
</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</div>
</template>
<script>
import addClassify from './components/addClassify'
import { tbShopCategoryGet, tbShopCategoryDelete } from '@/api/shop'
export default {
components: {
addClassify
},
data() {
return {
tableData: {
page: 0,
size: 10,
total: 0,
loading: false,
list: []
}
}
},
mounted() {
this.getTableData()
},
methods: {
// 添加子分类
addChildGatgory(row) {
},
// 查询table
toQuery() {
this.getTableData()
},// 重置查询
resetHandle() {
this.tableData.page = 0;
this.query.blurry = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e -1;
this.getTableData()
},
// 删除
async delHandle(ids) {
try {
await tbShopCategoryDelete(ids)
this.$notify({
title: '成功',
message: `删除成功`,
type: 'success'
});
this.getTableData()
} catch (error) {
console.log(error)
}
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopCategoryGet({
page: this.tableData.page,
size: this.tableData.size,
sort: 'id,desc',
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
}
}
}
</script>

View File

@@ -0,0 +1,120 @@
<template>
<el-dialog title="添加分类" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<!-- <el-form-item label="层级">
<el-select v-model="form.index">
<el-option label="顶级" :value="1"></el-option>
<el-option label="饮品" :value="2"></el-option>
<el-option label="烤串" :value="3"></el-option>
</el-select>
</el-form-item> -->
<el-form-item label="分类名称" prop="name">
<el-input v-model="form.name" placeholder="请输入分类名称"></el-input>
</el-form-item>
<el-form-item label="分类图片">
<uploadImg ref="uploadImg" @success="res => form.pic = res[0]" @remove="form.pic = ''" />
</el-form-item>
<el-form-item label="颜色标识">
<el-color-picker v-model="form.style"></el-color-picker>
<div style="color: #999;">
标识色用在无图模式时的商品点单按钮显示可以更有效的从视觉.上进行商品分组
</div>
</el-form-item>
<el-form-item label="开关">
<el-switch v-model="form.isShow" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="form.sort" controls-position="right" :min="0"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import uploadImg from '@/components/uploadImg'
import { tbShopCategoryPost } from '@/api/shop'
export default {
components: {
uploadImg
},
data() {
return {
dialogVisible: false,
form: {
id: '',
pid: '',
isShow: 1,
name: '',
sort: '',
style: '#000000',
pic: ''
},
resetForm: '',
rules: {
name: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
}
}
},
mounted() {
this.resetForm = { ...this.form }
},
methods: {
onSubmitHandle() {
console.log(this.form)
this.$refs.form.validate(async valid => {
if (valid) {
try {
this.form.shopId = localStorage.getItem('shopId')
let res = await tbShopCategoryPost(this.form, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
console.log(error)
}
}
})
},
show(obj) {
// console.log(obj)
this.dialogVisible = true
if (obj.pid) {
this.form.pid = obj.pid
}
if (obj && obj.id) {
this.form = obj
if (obj.pic) {
setTimeout(() => {
this.$refs.uploadImg.fileList = [
{
url: obj.pic
}
]
}, 100)
}
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form = { ...this.resetForm }
this.$refs.uploadImg.clearFiles()
}
}
}
</script>

View File

@@ -0,0 +1,222 @@
<template>
<div>
<el-dialog title="添加分组" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="分组名称" prop="name">
<el-input v-model="form.name" placeholder="请输入分组名称"></el-input>
</el-form-item>
<el-form-item label="选择商品">
<div>
<el-button type="primary" icon="el-icon-plus" @click="$refs.shopListRef.show([...productIds])">
添加商品
</el-button>
</div>
<div class="shop_list">
<div class="item_wrap" v-for="(item, index) in productIds" :key="item.id"
@click="productIds.splice(index, 1)">
<div class="item" :data-index="index + 1">
<el-image :src="item.coverImg" style="width: 100%;height: 100%;"></el-image>
</div>
<div class="name">{{ item.name }}</div>
</div>
</div>
</el-form-item>
<el-form-item label="分组状态">
<el-radio-group v-model="form.isShow">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分组排序">
<el-input-number v-model="form.sort" controls-position="right" :min="0"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="loading" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
<shopList ref="shopListRef" @success="slectShop" />
</div>
</template>
<script>
import { tbProductGroupPost, tbProductGroupPut, productListGet } from '@/api/shop'
import shopList from '@/components/shopList'
export default {
components: {
shopList
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id: '',
name: '',
isShow: 1,
sort: 0,
productIds: [],
shopId: localStorage.getItem('shopId')
},
rules: {
name: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
},
productIds: []
}
},
methods: {
slectShop(res) {
if (this.productIds.length) {
res.map(async item => {
if (!await this.checkShop(item.id)) {
this.productIds.push({ ...item })
}
})
} else {
this.productIds = res
}
},
// 判断是否存在重复商品
checkShop(id) {
let falg = false
this.productIds.map(item => {
if (item.id == id) {
falg = true
}
})
return falg
},
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
this.loading = true
try {
this.form.productIds = this.productIds.map(item => item.id);
let res = null
if (!this.form.id) {
await tbProductGroupPost(this.form)
} else {
await tbProductGroupPut(this.form)
}
this.loading = false
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
console.log(error)
}
}
})
},
async getProduts() {
try {
const res = await productListGet(this.form.id)
this.productIds = res
} catch (error) {
console.log(error)
}
},
show(obj) {
if (obj && obj.id) {
this.form.id = obj.id
this.form.isShow = obj.isShow
this.form.name = obj.name
this.form.sort = obj.sort
this.form.productIds = obj.productIds
this.getProduts()
}
this.dialogVisible = true
},
close() {
this.dialogVisible = false
},
reset() {
this.form.isShow = 1
this.form.name = ''
this.form.sort = 0
this.form.productIds = []
this.productIds = []
}
}
}
</script>
<style scoped lang="scss">
.shop_list {
display: flex;
flex-wrap: wrap;
.item_wrap {
$size: 80px;
.item {
$radius: 4px;
width: $size;
height: $size;
border-radius: $radius;
overflow: hidden;
position: relative;
margin-right: 10px;
margin-top: 10px;
&:hover {
cursor: pointer;
}
&::after {
content: attr(data-index);
font-size: 12px;
height: 20px;
display: flex;
padding: 0 10px;
border-radius: 0 0 $radius 0;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
color: #fff;
position: absolute;
top: 0;
left: 0;
z-index: 10;
}
&::before {
content: '删除';
font-size: 12px;
width: 100%;
height: 20px;
display: flex;
padding: 0 10px;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
color: #fff;
position: absolute;
bottom: 0;
left: 0;
z-index: 10;
transition: all .1s ease-in-out;
}
}
.name {
width: $size;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
</style>

View File

@@ -0,0 +1,203 @@
<template>
<el-dialog title="添加模板" width="840px" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="80px" label-position="left">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="模板名称,如:衣服"></el-input>
</el-form-item>
<el-form-item :label="item.name" v-for="(item, index) in form.specList" :key="index">
<div class="tag_wrap">
<el-tag v-for="(val, i) in item.value" :key="i" closable size="medium" :disable-transitions="true"
@close="handleClose(index, i)">
{{ val }}
</el-tag>
<el-input class="input-new-tag" v-show="item.inputVisible" v-model="item.inputValue" ref="saveTagInput"
size="small" placeholder="请输入规格值,回车添加" @keyup.enter.native="handleInputConfirm(index)"
@blur="handleInputConfirm(index)">
</el-input>
<el-button v-show="!item.inputVisible" size="mini" icon="el-icon-plus" plain @click="showInput(index)">
添加
</el-button>
<el-button size="mini" icon="el-icon-delete" plain @click="deleteTag(index)">删除</el-button>
</div>
</el-form-item>
</el-form>
<el-form ref="skuForm" :model="skuForm" :rules="skuRules" label-width="80px" label-position="left">
<el-row :gutter="20" v-if="showSkuForm">
<el-col :span="10">
<el-form-item label="规格" prop="skuValidate1">
<el-input v-model="skuForm.label" placeholder="规格,如:尺码"></el-input>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="规格值" prop="skuValidate2">
<el-input v-model="skuForm.value" placeholder="规格值S、M"></el-input>
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="addSkuSubmit">添加</el-button>
<el-button @click="showSkuForm = false">取消</el-button>
</el-col>
</el-row>
<el-form-item v-if="!showSkuForm">
<el-button type="primary" icon="el-icon-plus" @click="showSkuForm = true">添加规格</el-button>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbProductSpecPost, tbProductSpecPut } from '@/api/shop'
export default {
data() {
const validateSku1 = (rule, value, callback) => {
if (!this.skuForm.label) {
callback(new Error(' '))
} else {
callback()
}
}
const validateSku2 = (rule, value, callback) => {
if (!this.skuForm.value) {
callback(new Error(' '))
} else {
callback()
}
}
return {
dialogVisible: false,
showSkuForm: true,
skuForm: {
label: '',
value: ''
},
skuRules: {
skuValidate1: {
required: true,
validator: validateSku1,
trigger: 'blur'
},
skuValidate2: {
required: true,
validator: validateSku2,
trigger: 'blur'
}
},
form: {
id: '',
name: '',
shopId: localStorage.getItem('shopId'),
specList: []
},
rules: {
name: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
}
}
},
methods: {
onSubmitHandle() {
console.log(this.form)
this.$refs.form.validate(async valid => {
if (valid) {
try {
let res = null
if (!this.form.id) {
res = await tbProductSpecPost(this.form)
} else {
res = await tbProductSpecPut(this.form)
}
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.pid ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
const newObj = JSON.parse(JSON.stringify(obj));
this.form.id = newObj.id
this.form.name = newObj.name
const specList = newObj.specList
for (let item of specList) {
item.inputVisible = false
item.inputValue = ''
}
this.form.specList = specList
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form.id = ''
this.form.name = ''
this.form.specList = []
},
// sku from
addSkuSubmit() {
this.$refs.skuForm.validate(async valid => {
if (valid) {
this.form.specList.push({
name: this.skuForm.label,
value: [this.skuForm.value],
inputVisible: false,
inputValue: ''
})
this.skuForm.label = ''
this.skuForm.value = ''
this.showSkuForm = false
}
})
},
handleClose(index, i) {
this.form.specList[index].value.splice(i, 1);
},
showInput(index) {
this.form.specList[index].inputVisible = true;
},
handleInputConfirm(index) {
let inputValue = this.form.specList[index].inputValue;
if (inputValue) {
this.form.specList[index].value.push(inputValue);
}
this.form.specList[index].inputVisible = false;
this.form.specList[index].inputValue = '';
},
// 删除已添加的规格
deleteTag(index) {
this.form.specList.splice(index, 1);
}
}
}
</script>
<style scoped lang="scss">
.tag_wrap {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.input-new-tag {
width: 180px;
margin-left: 10px;
vertical-align: bottom;
}
</style>

View File

@@ -0,0 +1,86 @@
<template>
<el-dialog title="添加单位" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120" label-position="left">
<el-form-item label="单位名称" prop="name">
<el-input v-model="form.name" placeholder="单位名称"></el-input>
</el-form-item>
<el-form-item label="排序">
<el-input v-model="form.sort"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="formLoading" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopUnitPost, tbShopUnitPut } from '@/api/shop'
export default {
data() {
return {
dialogVisible: false,
formLoading: false,
form: {
id: '',
name: '',
sort: 0,
shopId: localStorage.getItem('shopId')
},
rules: {
name: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
}
}
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
try {
this.formLoading = true
let res = null
if (!this.form.id) {
res = await tbShopUnitPost(this.form)
} else {
res = await tbShopUnitPut(this.form)
}
this.close()
this.formLoading = false
this.$emit('success', res)
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
this.formLoading = false
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
// 编辑
this.form.name = obj.name
this.form.id = obj.id
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form.id = ''
this.form.name = ''
this.form.sort = 0
}
}
}
</script>

View File

@@ -1,128 +1,99 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!--工具栏-->
<div class="head-container"> <div class="head-container">
<!--如果想在工具栏加入更多按钮可以使用插槽方式 slot = 'left' or 'right'--> <el-button type="primary" icon="el-icon-plus" @click="$refs.addGroupRef.show()">
<crudOperation :permission="permission" /> 添加分组
<!--表单组件(增改)--> </el-button>
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> <addGroup ref="addGroupRef" @success="resetHandle" />
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> </div>
<el-form-item label="分组名称" prop="name"> <div class="head-container">
<el-input v-model="form.name" style="width: 370px;" /> <el-table :data="tableData.list" v-loading="tableData.loading">
</el-form-item> <el-table-column label="排序" sortable prop="sort"></el-table-column>
<el-form-item label="图标"> <el-table-column label="分组名称" prop="name"></el-table-column>
<el-input v-model="form.pic" style="width: 370px;" /> <el-table-column label="状态">
</el-form-item> <template v-slot="scope">
<el-form-item label="是否显示" prop="isShow"> <el-switch v-model="scope.row.isShow" :active-value="1" :inactive-value="0"></el-switch>
<el-input v-model="form.isShow" style="width: 370px;" /> </template>
</el-form-item> </el-table-column>
<el-form-item label="分类描述"> <el-table-column label="操作" width="200">
<el-input v-model="form.detail" style="width: 370px;" /> <template v-slot="scope">
</el-form-item> <el-button type="text" size="mini" round icon="el-icon-edit"
<el-form-item label="添加商品"> @click="$refs.addGroupRef.show(scope.row)">编辑</el-button>
<el-input v-model="form.productIds" style="width: 370px;" /> <el-popconfirm title="确定删除吗?" @confirm="delHandle([scope.row.id])">
</el-form-item> <el-button type="text" size="mini" round icon="el-icon-delete" slot="reference">
删除
<el-button type="primary" @click="addProduct">+添加商品 </el-button>
<el-dialog title="选择商品" :visible.sync="productClick"> </el-popconfirm>
<el-table :data="productList.content" style="width: 100%;">
<el-table-column type="selection" width="55" />
<el-table-column property="name" label="商品信息" width="150" />
<el-table-column property="lowPrice" label="售价" width="200" />
<el-table-column property="address" label="地址" />
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addProduct">确 定</el-button>
</span>
</el-dialog>
</el-button>
<el-form-item label="创建时间">
<el-input v-model="form.createdAt" style="width: 370px;" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--表格渲染(查)-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="分组名称" />
<el-table-column prop="pic" label="图标" />
<el-table-column prop="isShow" label="是否显示" />
<el-table-column prop="detail" label="分类描述" />
<el-table-column prop="productIds" label="商品列表" />
<el-table-column prop="createdAt" label="创建时间" />
<el-table-column v-if="checkPer(['admin','tbProductGroup:edit','tbProductGroup:del'])" label="操作" width="150px" align="center">
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--分页组件-->
<pagination />
</div> </div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div> </div>
</template> </template>
<script> <script>
import crudTbProductGroup from '@/api/tbProductGroup' import addGroup from '../components/addGroup'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import { tbProductGroupGet, tbProductGroupDelete } from '@/api/shop'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
import { addProduct } from '@/api/tbProductGroup'
const defaultForm = { id: null, name: null, merchantId: null, shopId: null, pic: null, isShow: null, detail: null, style: null, sort: null, productIds: null, createdAt: null, updatedAt: null }
export default { export default {
name: 'TbProductGroup', components: {
components: { pagination, crudOperation, rrOperation, udOperation }, addGroup
mixins: [presenter(), header(), form(defaultForm), crud()],
cruds() {
return CRUD({ title: 'product/group', url: 'api/tbProductGroup', idField: 'id', sort: 'id,desc', crudMethod: { ...crudTbProductGroup }})
}, },
data() { data() {
return { return {
permission: { tableData: {
add: ['admin', 'tbProductGroup:add'], page: 0,
edit: ['admin', 'tbProductGroup:edit'], size: 10,
del: ['admin', 'tbProductGroup:del'] total: 0,
}, loading: false,
rules: { list: []
name: [ }
{ required: true, message: '分组名称不能为空', trigger: 'blur' }
],
isShow: [
{ required: true, message: '是否显示1显示 0不显示不能为空', trigger: 'blur' }
]
},
productList: [],
productClick: false
} }
}, },
mounted() {
this.getTableData()
},
methods: { methods: {
// 钩子在获取表格数据之前执行false 则代表不获取数据 // 重置查询
[CRUD.HOOK.beforeRefresh]() { resetHandle() {
return true this.tableData.page = 0;
this.getTableData()
}, },
addProduct(data) { // 分页回调
this.productClick = true paginationChange(e) {
addProduct(data).then(res => { this.tableData.page = e - 1
this.productList = res this.getTableData()
}) },
// 删除
async delHandle(ids) {
try {
await tbProductGroupDelete(ids)
this.$notify({
title: '成功',
message: `删除成功`,
type: 'success'
});
this.getTableData()
} catch (error) {
console.log(error)
}
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProductGroupGet({
page: this.tableData.page,
size: this.tableData.size,
sort: 'id',
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) { }
} }
} }
} }
</script> </script>
<style scoped>
</style>

View File

@@ -3,30 +3,21 @@
<div class="head-container"> <div class="head-container">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="3"> <el-col :span="3">
<el-input <el-input v-model="query.name" size="small" clearable placeholder="请输入商品名称" style="width: 100%;"
v-model="query.blurry" class="filter-item" @keyup.enter.native="getTableData" />
size="small"
clearable
placeholder="请输入商品名称"
style="width: 100%;"
class="filter-item"
@keyup.enter.native="toQuery"
/>
</el-col> </el-col>
<el-col :span="3"> <el-col :span="3">
<el-select v-model="query.class" placeholder="请选择商品分类" style="width: 100%;"> <el-select v-model="query.categoryId" placeholder="请选择商品分类" style="width: 100%;">
<el-option label="饮品" :value="1" /> <el-option :label="item.name" :value="item.id" v-for="item in categorys" :key="item.id" />
<el-option label="烤串" :value="2" />
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="3"> <el-col :span="3">
<el-select v-model="query.sku" placeholder="请选择商品规格" style="width: 100%;"> <el-select v-model="query.typeEnum" placeholder="请选择商品规格" style="width: 100%;">
<el-option label="饮品" :value="1" /> <el-option :label="item.label" :value="item.typeEnum" v-for="item in typeEnums" :key="item.typeEnum" />
<el-option label="烤串" :value="2" />
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-button type="primary" @click="toQuery">查询</el-button> <el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button> <el-button @click="resetHandle">重置</el-button>
</el-col> </el-col>
</el-row> </el-row>
@@ -34,19 +25,23 @@
<div class="head-container"> <div class="head-container">
<el-row> <el-row>
<el-col> <el-col>
<el-button type="primary" icon="el-icon-plus">添加商品</el-button> <router-link :to="{ name: 'add_shop' }">
<el-button type="primary" icon="el-icon-plus">添加商品</el-button>
</router-link>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
<div class="head-container"> <div class="head-container">
<el-table :data="tableData.data"> <el-table :data="tableData.data" v-loading="tableData.loading">
<el-table-column label="商品信息"> <el-table-column label="商品信息">
<template v-slot="scope"> <template v-slot="scope">
<div class="shop_info"> <div class="shop_info">
<el-image <el-image :src="scope.row.coverImg"
:src="scope.row.coverImg" style="width: 50px;height: 50px;border-radius: 4px;background-color: #efefef;">
style="width: 50px;height: 50px;border-radius: 4px;background-color: #efefef;" <div class="img_error" slot="error">
/> <i class="icon el-icon-document-delete"></i>
</div>
</el-image>
<div class="info"> <div class="info">
<span>{{ scope.row.name }}</span> <span>{{ scope.row.name }}</span>
</div> </div>
@@ -60,77 +55,125 @@
</el-table-column> </el-table-column>
<el-table-column label="销量/库存"> <el-table-column label="销量/库存">
<template v-slot="scope"> <template v-slot="scope">
<span>{{ scope.row.xl }}/{{ scope.row.kc }}</span> <span>{{ scope.row.realSalesNumber }}/{{ scope.row.stockNumber }}</span>
</template>
</el-table-column>
<el-table-column label="上架区域">
<template v-slot="scope">
<div v-if="scope.row.isShowCash">收银端</div>
<div v-if="scope.row.isShowMall">小程序</div>
<div v-if="!scope.row.isShowCash && !scope.row.isShowMall">未上架</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="上架区域" prop="area" />
<el-table-column label="排序" prop="sort" sortable /> <el-table-column label="排序" prop="sort" sortable />
<el-table-column label="更新时间" prop="update" /> <el-table-column label="更新时间" prop="createdAt">
<template v-slot="scope">
{{ dayjs(scope.row.createdAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template v-slot="scope"> <template v-slot="scope">
<el-button type="primary" size="mini" round icon="el-icon-edit">编辑</el-button> <router-link :to="{ path: '/product/add_shop', query: { goods_id: scope.row.id } }">
<el-button type="danger" size="mini" round icon="el-icon-delete">删除</el-button> <el-button type="text" icon="el-icon-edit">编辑</el-button>
</router-link>
<el-popconfirm title="确定删除吗?" @confirm="delTableHandle([scope.row.id])">
<el-button type="text" icon="el-icon-delete" style="margin-left: 20px !important;"
slot="reference">删除</el-button>
</el-popconfirm>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</div> </div>
</template> </template>
<script> <script>
import { tbProduct } from '@/api/shop' import dayjs from 'dayjs'
import settings from '@/settings'
import { tbProduct, tbShopCategoryGet, tbProductDelete } from '@/api/shop'
export default { export default {
data() { data() {
return { return {
dayjs,
query: { query: {
blurry: '', name: '',
class: '', categoryId: '',
sku: '' typeEnum: ''
}, },
categorys: [],
typeEnums: settings.typeEnum,
tableData: { tableData: {
data: [ data: [],
{
url: 'https://cash-register.oss-cn-beijing.aliyuncs.com/shop/f12c3cc097e147daa33ac4b55aca8ef3/2023-08-21/20230821-110556-2425668054.png?x-oss-process=image/resize,w_50,h_50,m_fill',
title: '套餐商品',
class: '烤串',
price: 2,
xl: 0,
kc: 0,
area: '收银端',
sort: 0,
update: '2023-11-20 16:08'
}
],
page: 0, page: 0,
size: 10, size: 10,
loading: false loading: false,
total: 0
} }
} }
}, },
mounted() { mounted() {
this.tbProduct() this.getTableData()
this.tbShopCategoryGet()
}, },
methods: { methods: {
// 查询
toQuery() {
},
// 重置查询 // 重置查询
resetHandle() { resetHandle() {
this.query.blurry = '' this.query.name = ''
this.query.class = '' this.query.categoryId = ''
this.query.sku = '' this.query.typeEnum = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
}, },
// 获取商品列表 // 获取商品列表
async tbProduct() { async getTableData() {
this.tableData.loading = true
try { try {
const res = await tbProduct({ const res = await tbProduct({
page: this.tableData.page, page: this.tableData.page,
size: this.tableData.size size: this.tableData.size,
name: this.query.name,
categoryId: this.query.categoryId,
typeEnum: this.query.typeEnum,
shopId: localStorage.getItem('shopId')
}) })
this.tableData.loading = false
this.tableData.data = res.content this.tableData.data = res.content
} catch (error) { } this.tableData.total = res.totalElements
} } catch (error) {
console.log(error)
}
},
// 获取商品分类列表
async tbShopCategoryGet() {
try {
const res = await tbShopCategoryGet({
shopId: localStorage.getItem('shopId'),
page: 0,
size: 100,
sort: 'id'
})
this.categorys = res.content
} catch (error) {
console.log(error)
}
},
// 删除商品
async delTableHandle(ids) {
try {
await tbProductDelete(ids)
this.getTableData()
} catch (error) {
console.log(error)
}
},
} }
} }
</script> </script>
@@ -141,7 +184,13 @@ export default {
.info { .info {
flex: 1; flex: 1;
padding-left: 4px; padding-left: 8px;
display: flex;
flex-direction: column;
.tag_wrap {
display: flex;
}
} }
} }
</style> </style>

View File

@@ -0,0 +1,118 @@
<template>
<div class="app-container">
<div class="head-container">
<el-row :gutter="20">
<el-col :span="6">
<el-input v-model="query.blurry" size="small" clearable placeholder="请输入模板名称" style="width: 100%;"
class="filter-item" @keyup.enter.native="getTableData" />
</el-col>
<el-col :span="6">
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</div>
<div class="head-container">
<el-button type="primary" icon="el-icon-plus" @click="$refs.addSpecificationRef.show()">添加规格</el-button>
<addSpecification ref="addSpecificationRef" @success="getTableData" />
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="模板名称" prop="name"></el-table-column>
<el-table-column label="规格详情">
<template v-slot="scope">
<el-row v-for="(item, index) in scope.row.specList" :key="index">
<span>{{ item.name }}</span>
<span>{{ item.value.join('、') }}</span>
</el-row>
</template>
</el-table-column>
<el-table-column label="排序" sortable></el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="text" size="mini" round icon="el-icon-edit"
@click="$refs.addSpecificationRef.show(scope.row)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="delHandle([scope.row.id])">
<el-button type="text" size="mini" round icon="el-icon-delete" slot="reference">
删除
</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</div>
</template>
<script>
import addSpecification from './components/addSpecification'
import { tbProductSpecGet, tbProductSpecDelete } from '@/api/shop'
export default {
components: {
addSpecification
},
data() {
return {
query: {
blurry: '',
},
tableData: {
page: 0,
size: 10,
total: 0,
loading: false,
list: []
}
}
},
mounted() {
this.getTableData()
},
methods: {
// 重置查询
resetHandle() {
this.query.blurry = ''
this.tableData.page = 0;
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 删除
async delHandle(ids) {
try {
const res = await tbProductSpecDelete(ids)
this.$notify({
title: '成功',
message: `删除成功`,
type: 'success'
});
this.getTableData()
} catch (error) {
console.log(error)
}
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbProductSpecGet({
page: this.tableData.page,
size: this.tableData.size,
sort: 'id',
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) { }
}
}
}
</script>

112
src/views/product/unit.vue Normal file
View File

@@ -0,0 +1,112 @@
<template>
<div class="app-container">
<div class="head-container">
<el-row :gutter="20">
<el-col :span="6">
<el-input v-model="query.blurry" size="small" clearable placeholder="请输入单位名称" style="width: 100%;"
class="filter-item" @keyup.enter.native="toQuery" />
</el-col>
<el-col :span="6">
<el-button type="primary" @click="toQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</div>
<div class="head-container">
<el-button type="primary" icon="el-icon-plus" @click="$refs.addUnitRef.show()">添加单位</el-button>
<addUnit ref="addUnitRef" @success="getTableData()" />
</div>
<div class="head-container">
<el-table :data="tableData.list" v-loading="tableData.loading">
<el-table-column label="单位名称" prop="name"></el-table-column>
<el-table-column label="排序" prop="id" sortable></el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="text" size="mini" round icon="el-icon-edit"
@click="$refs.addUnitRef.show(scope.row)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="delHandle([scope.row.id])">
<el-button type="text" size="mini" round icon="el-icon-delete" slot="reference">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
</div>
</template>
<script>
import { tbShopCurrencyGet, tbShopUnitDelete } from '@/api/shop'
import addUnit from './components/addUnit'
export default {
components: {
addUnit
},
data() {
return {
query: {
blurry: ''
},
tableData: {
page: 0,
size: 10,
total: 0,
loading: false,
list: []
}
}
},
mounted() {
this.getTableData()
},
methods: {
// 查询table
toQuery() {
this.getTableData()
},// 重置查询
resetHandle() {
this.tableData.page = 0;
this.query.blurry = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1;
this.getTableData()
},
// 删除
async delHandle(ids) {
try {
await tbShopUnitDelete(ids)
this.$notify({
title: '成功',
message: `删除成功`,
type: 'success'
});
this.getTableData()
} catch (error) {
console.log(error)
}
},
// 获取商品列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopCurrencyGet({
page: this.tableData.page,
size: this.tableData.size,
sort: 'id',
shopId: localStorage.getItem('shopId'),
name: this.query.blurry
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) { }
}
}
}
</script>

View File

@@ -0,0 +1,80 @@
<template>
<el-dialog title="生产激活码" :visible.sync="dialogVisible" width="500px" @close="reset">
<el-form :model="form" :rules="rules" label-width="100px" label-position="left">
<el-form-item label="激活时长" prop="periodYear">
<el-input-number v-model="form.periodYear" controls-position="right" :min="1" :step="1"
step-strictly></el-input-number>
</el-form-item>
<el-form-item label="生产数量" prop="number">
<el-input-number v-model="form.number" controls-position="right" :min="1" :step="1"
step-strictly></el-input-number>
</el-form-item>
<!-- <el-form-item label="所属代理" prop="agent">
<el-input v-model="form.agent" placeholder="请输入完整的代理账号查找"></el-input>
</el-form-item> -->
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" v-loading="loading" @click="tbMerchantRegisterPost">生产激活码</el-button>
</div>
</el-dialog>
</template>
<script>
import { tbMerchantRegisterPost } from '@/api/shop.js'
export default {
data() {
return {
dialogVisible: false,
loading: false,
form: {
periodYear: 1,
number: 1,
agent: ''
},
rules: {
periodYear: [{
required: true,
message: ' ',
trigger: 'blur'
}],
number: [{
required: true,
message: ' ',
trigger: 'blur'
}]
}
}
},
methods: {
async tbMerchantRegisterPost() {
try {
this.loading = true
const res = await tbMerchantRegisterPost(this.form)
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `添加成功`,
type: 'success'
});
this.loading = false
} catch (error) {
this.loading = false
console.log(error)
}
},
show() {
this.dialogVisible = true
},
close() {
this.dialogVisible = false
},
reset() {
this.form.periodYear = 1
this.form.number = 1
this.form.agent = ''
}
}
}
</script>

View File

@@ -1,146 +1,160 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!--工具栏-->
<div class="head-container"> <div class="head-container">
<div v-if="crud.props.searchToggle"> <div class="filter_wrap">
<!-- 搜索 --> <!-- <el-input v-model="query.name" size="small" clearable placeholder="请输入完整的代理商账号查找" style="width: 250px"
<label class="el-form-item-label">id</label> @keyup.enter.native="getTableData" /> -->
<el-input v-model="query.id" clearable placeholder="id" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-select v-model="query.type" placeholder="请选择类型" style="width: 200px">
<label class="el-form-item-label">激活码</label> <el-option label="快餐版" value="munchies" />
<el-input v-model="query.registerCode" clearable placeholder="激活码" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-option label="餐饮版" value="restaurant" />
<label class="el-form-item-label">店铺名称</label> </el-select>
<el-input v-model="query.shopName" clearable placeholder="店铺名称" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-select v-model="query.status" placeholder="请选择状态" style="width: 200px">
<label class="el-form-item-label">版本类型</label> <el-option label="待激活" :value="0" />
<el-input v-model="query.type" clearable placeholder="版本类型" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-option label="已使用" :value="1" />
<label class="el-form-item-label">激活码金额</label> </el-select>
<el-input v-model="query.amount" clearable placeholder="激活码金额" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-date-picker v-model="query.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期"
<label class="el-form-item-label">激活时长</label> end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" style="width: 400px" @change="getTableData">
<el-input v-model="query.periodYear" clearable placeholder="激活时长(月)" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> </el-date-picker>
<label class="el-form-item-label">状态0未使用1已使用</label> <el-button type="primary" @click="getTableData">查询</el-button>
<el-input v-model="query.status" clearable placeholder="状态0未使用1已使用" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-button @click="resetHandle">重置</el-button>
<label class="el-form-item-label">创建时间</label>
<el-input v-model="query.createdAt" clearable placeholder="创建时间" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<rrOperation :crud="crud" />
</div> </div>
<!--如果想在工具栏加入更多按钮可以使用插槽方式 slot = 'left' or 'right'--> </div>
<crudOperation :permission="permission" /> <div class="head-container">
<!--表单组件--> <div class="filter_wrap">
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> <el-button type="primary" icon="el-icon-plus" @click="$refs.addActivationCode.show()">添加激活码</el-button>
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> <el-button icon="el-icon-download">导出Excel</el-button>
<el-form-item label="id" prop="id"> </div>
<el-input v-model="form.id" style="width: 370px;" /> </div>
</el-form-item> <div class="head-container">
<el-form-item label="激活码"> <el-table :data="tableData.list" v-loading="tableData.loading">
<el-input v-model="form.registerCode" style="width: 370px;" /> <el-table-column label="激活码" prop="registerCode" width="500px">
</el-form-item> <template v-slot="scope">
<el-form-item label="店铺名称"> <el-tooltip content="点击复制">
<el-input v-model="form.shopName" style="width: 370px;" /> <el-tag type="success" @click="copyHandle(scope.row.registerCode)">
</el-form-item> <i class="el-icon-paperclip"></i>
<el-form-item label="版本类型"> {{ scope.row.registerCode }}
<el-input v-model="form.type" style="width: 370px;" /> </el-tag>
</el-form-item> </el-tooltip>
<el-form-item label="激活码金额">
<el-input v-model="form.amount" style="width: 370px;" />
</el-form-item>
<el-form-item label="激活时长">
<el-input v-model="form.periodYear" style="width: 370px;" />
</el-form-item>
<el-form-item label="状态0未使用1已使用">
<el-input v-model="form.status" style="width: 370px;" />
</el-form-item>
<el-form-item label="创建时间">
<el-input v-model="form.createdAt" style="width: 370px;" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="id" />
<el-table-column prop="registerCode" label="激活码" />
<el-table-column prop="shopName" label="店铺名称" />
<el-table-column prop="type" label="版本类型">
<template slot-scope="scope">
{{ dict.label.register_type[scope.row.type] }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="amount" label="激活码金额" /> <el-table-column label="商户名称" prop="name"></el-table-column>
<el-table-column prop="periodYear" label="激活时长" /> <el-table-column label="联系电话" prop="telephone"></el-table-column>
<el-table-column prop="status" label="状态0未使用1已使用"> <el-table-column label="版本类型" prop="type">
<template slot-scope="scope"> <template v-slot="scope">
{{ dict.label.register_status[scope.row.status] }} <span v-if="scope.row.type == 'munchies'">快餐版</span>
<span v-if="scope.row.type == 'restaurant'">餐饮版</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createdAt" label="创建时间" /> <el-table-column label="激活时长" prop="periodYear"></el-table-column>
<el-table-column v-if="checkPer(['admin','viewRegister:edit','viewRegister:del'])" label="操作" width="150px" align="center"> <el-table-column label="状态" prop="status">
<template slot-scope="scope"> <template v-slot="scope">
<udOperation <el-tag type="info" v-if="scope.row.status == 0">待激活</el-tag>
:data="scope.row" <el-tag type="success" v-if="scope.row.status == 1">已使用</el-tag>
:permission="permission" </template>
/> </el-table-column>
<el-table-column label="创建时间" prop="createdAt">
<template v-slot="scope">
{{ scope.row.createdAt && dayjs(scope.row.createdAt).format('YYYY-MM-DD HH:mm:ss') }}
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--分页组件-->
<pagination />
</div> </div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
<addActivationCode ref="addActivationCode" @success="getTableData" />
</div> </div>
</template> </template>
<script> <script>
import crudViewRegister from '@/api/viewRegister' import dayjs from 'dayjs'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import { tbMerchantRegisterList } from '@/api/shop.js'
import rrOperation from '@crud/RR.operation' import addActivationCode from './components/addActivationCode'
import crudOperation from '@crud/CRUD.operation' import VueClipboard from 'vue-clipboard2'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
const defaultForm = { id: null, registerCode: null, shopName: null, type: null, amount: null, periodYear: null, status: null, createdAt: null }
export default { export default {
name: 'ViewRegister', components: { addActivationCode },
components: { pagination, crudOperation, rrOperation, udOperation },
mixins: [presenter(), header(), form(defaultForm), crud()],
dicts: ['register_type', 'register_status'],
cruds() {
return CRUD({ title: '/register', url: 'api/viewRegister', idField: 'id', sort: 'id,desc', crudMethod: { ...crudViewRegister }})
},
data() { data() {
return { return {
permission: { dayjs,
add: ['admin', 'viewRegister:add'], query: {
edit: ['admin', 'viewRegister:edit'], name: '',
del: ['admin', 'viewRegister:del'] type: '',
status: '',
createdAt: []
}, },
rules: { status: [
id: [ {
{ required: true, message: '不能为空', trigger: 'blur' } type: 1,
] label: '开启'
}, },
queryTypeOptions: [ {
{ key: 'id', display_name: 'id' }, type: 0,
{ key: 'registerCode', display_name: '激活码' }, label: '关闭'
{ key: 'shopName', display_name: '店铺名称' }, }
{ key: 'type', display_name: '版本类型' }, ],
{ key: 'amount', display_name: '激活码金额' }, tableData: {
{ key: 'periodYear', display_name: '激活时长(月)' }, list: [],
{ key: 'status', display_name: '状态0未使用1已使用' }, page: 0,
{ key: 'createdAt', display_name: '创建时间' } size: 10,
] loading: false,
total: 0
}
} }
}, },
mounted() {
this.getTableData()
},
methods: { methods: {
// 钩子在获取表格数据之前执行false 则代表不获取数据 copyHandle(text) {
[CRUD.HOOK.beforeRefresh]() { this.$copyText(text).then((e) => {
return true this.$notify({
title: '成功',
message: `复制成功`,
type: 'success'
});
})
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.account = ''
this.query.status = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
async getTableData() {
this.tableData.loading = true
try {
const res = await tbMerchantRegisterList({
page: this.tableData.page,
size: this.tableData.size,
type: this.query.type,
status: this.query.status,
createdAt: this.query.createdAt
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
} }
} }
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.shop_info {
display: flex;
</style> .info {
flex: 1;
padding-left: 4px;
}
}
</style>

View File

@@ -0,0 +1,351 @@
<template>
<el-dialog :title="form.id ? '编辑店铺' : '添加店铺'" :visible.sync="dialogVisible" @close="reset">
<div style="height: 50vh;overflow-y: auto;">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="店铺名称" prop="shopName">
<el-input v-model="form.shopName" placeholder="请输入门店名称"></el-input>
</el-form-item>
<el-form-item label="门店logo" prop="logo">
<el-image :src="form.logo || require('@/assets/images/upload.png')" fit="contain"
style="width: 80px;height: 80px;" @click="showUpload = true; uploadIndex = 1"></el-image>
</el-form-item>
<el-form-item label="门店照片">
<el-image :src="form.coverImg || require('@/assets/images/upload.png')" fit="contain"
style="width: 80px;height: 80px;" @click="showUpload = true; uploadIndex = 2"></el-image>
</el-form-item>
<el-form-item label="店铺类型">
<el-radio-group v-model="form.registerType">
<el-radio-button label="munchies">快餐版</el-radio-button>
<el-radio-button label="restaurant">餐饮版</el-radio-button>
</el-radio-group>
<div class="tips">请谨慎修改</div>
</el-form-item>
<el-form-item label="试用/正式">
<el-radio-group v-model="form.profiles">
<el-radio-button label="probation">试用</el-radio-button>
<el-radio-button label="release">正式</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="激活码">
<el-input v-model="form.registerCode" placeholder="请输入激活码"></el-input>
<div class="tips">输入有效激活码表示添加的同时直接激活该店铺</div>
</el-form-item>
<el-form-item label="登录账号" prop="account">
<el-input v-model="form.account" placeholder="请输入登录账号"></el-input>
</el-form-item>
<el-form-item label="登录密码" prop="password">
<el-input type="password" show-password v-model="form.password" placeholder="请输入登录密码"></el-input>
</el-form-item>
<el-form-item label="联系电话">
<el-input v-model="form.phone" placeholder="请输入联系电话"></el-input>
</el-form-item>
<el-form-item label="设备数量">
<el-input-number v-model="form.supportDeviceNumber" controls-position="right" :min="1" :step="1"
step-strictly></el-input-number>
</el-form-item>
<!-- <el-form-item label="外卖起送金额">
<el-input-number v-model="form.takeaway_money" placeholder="0.00" controls-position="right"
:min="0"></el-input-number>
</el-form-item> -->
<el-form-item label="店铺经度">
<el-row>
<el-col :span="4">
<el-input v-model="form.lng" placeholder="经度"></el-input>
</el-col>
<el-col :span="4">
<el-input v-model="form.lat" placeholder="纬度" style="margin-left: 10px;"></el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" plain icon="el-icon-place" style="margin-left: 20px;"
@click="showLocation = true">选择坐标</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="店铺详细地址">
<el-input type="textarea" v-model="form.address" placeholder="请输入门店详细地址"></el-input>
</el-form-item>
<el-form-item label="店铺简介">
<el-input type="textarea" v-model="form.detail" placeholder="请输入店铺简介"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<el-dialog title="选择地址" :visible.sync="showLocation" :modal="false" :modal-append-to-body="false">
<div class="map_box">
<div class="map">
<el-amap :center="amapOptions.center">
<el-amap-marker :position="amapOptions.center"></el-amap-marker>
</el-amap>
</div>
<div class="search_box">
<el-amap-search-box :search-option="searchOption"
:on-search-result="onSearchResult"></el-amap-search-box>
</div>
<div class="search_wrap">
<div class="item" v-for="item in locationSearchList" :key="item.id">
<div class="left">
<div class="name">{{ item.name }}-{{ item.address }}</div>
<div class="location">
经纬度{{ item.lng }},{{ item.lat }}
</div>
</div>
<div class="btn">
<el-button type="primary" @click="selectLocationHandle(item)">
选择
</el-button>
</div>
</div>
</div>
</div>
</el-dialog>
<el-dialog :visible.sync="showUpload" :close-on-click-modal="false" append-to-body width="500px"
@close="showUpload = false">
<el-upload :before-remove="handleBeforeRemove" :on-success="handleSuccess" :on-error="handleError"
:file-list="fileList" :headers="headers" :action="qiNiuUploadApi" class="upload-demo" multiple>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件且文件不超过15M</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="doSubmit">确认</el-button>
<el-button @click="uploadClose">取消</el-button>
</div>
</el-dialog>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</div>
</el-dialog>
</template>
<script>
import { getToken } from '@/utils/auth'
import { mapGetters } from 'vuex'
import crudQiNiu from '@/api/tools/qiniu'
import { tbShopInfoPost } from '@/api/shop'
export default {
computed: {
...mapGetters([
'qiNiuUploadApi'
])
},
data() {
const validateLogo = (rule, value, callback) => {
if (!this.form.logo) {
callback(new Error('请上传门店logo'))
} else {
callback()
}
}
return {
dialogVisible: false,
showLocation: false,
showUpload: false,
uploadIndex: 1,
startTime: '',
endTime: '',
formLoading: false,
form: {
id: '',
shopName: '',
registerType: 'restaurant',
profiles: 'release',
registerCode: '',
account: '',
password: '',
phone: '',
supportDeviceNumber: '',
lat: '',
lng: '',
address: '',
detail: '',
status: 1,
logo: '',
coverImg: ''
},
resetForm: '',
rules: {
shopName: [
{
required: true,
message: ' ',
trigger: 'blur'
}
],
logo: [
{
required: true,
validator: validateLogo,
trigger: 'change'
}
],
account: [
{
required: true,
message: ' ',
trigger: 'change'
}
],
password: [
{
required: true,
message: ' ',
trigger: 'change'
}
]
},
fileList: [],
files: [],
headers: {
'Authorization': getToken()
},
searchOption: {
city: '西安',
citylimit: false
},
locationSearchList: [],
amapOptions: {
center: [108.946465, 34.347984],
position: []
}
}
},
mounted() {
this.resetForm = { ...this.form }
},
methods: {
onSearchResult(res) {
this.locationSearchList = res
this.amapOptions.center = [res[0].lng, res[0].lat]
},
// 确认地址选择
selectLocationHandle(item) {
this.form.lng = item.lng
this.form.lat = item.lat
this.showLocation = false
},
// 保存
submitHandle() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.formLoading = true
try {
await tbShopInfoPost(this.form, this.form.id ? 'put' : 'post')
this.$emit('success')
this.formLoading = false
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
this.close()
} catch (error) {
this.formLoading = false
console.log(error)
}
}
})
},
handleSuccess(response, file, fileList) {
// const uid = file.uid
// const id = response.id
// this.files.push({ uid, id })
console.log('上传成功', response)
this.files = response.data
},
handleBeforeRemove(file, fileList) {
for (let i = 0; i < this.files.length; i++) {
if (this.files[i].uid === file.uid) {
crudQiNiu.del([this.files[i].id]).then(res => { })
return true
}
}
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
// 监听上传失败
handleError(e, file, fileList) {
const msg = JSON.parse(e.message)
this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR)
},
// 刷新列表数据
doSubmit() {
this.fileList = []
this.showUpload = false
switch (this.uploadIndex) {
case 1:
this.form.logo = this.files[0]
break;
case 2:
this.form.coverImg = this.files[0]
break;
default:
break;
}
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = { ...obj }
}
},
close() {
this.dialogVisible = false
},
uploadClose() {
this.showUpload = false
},
reset() {
this.form = { ...this.resetForm }
}
}
}
</script>
<style scoped lang="scss">
.map_box {
width: 100%;
position: relative;
.map {
height: 300px;
}
.search_box {
position: absolute;
top: 10px;
left: 10px;
}
.search_wrap {
padding: 6px 0;
.item {
display: flex;
padding: 12px 0;
.left {
flex: 1;
display: flex;
flex-direction: column;
padding-right: 20px;
.location {
color: #999;
padding-top: 4px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,107 @@
<template>
<el-dialog :visible.sync="dialogVisible" :show-close="false" @close="reset">
<el-tabs v-model="activeName">
<el-tab-pane label="聚合支付" name="pay">
<el-form ref="form" :model="form" label-width="120px" label-position="left">
<el-form-item label="商户号">
<el-input v-model="form.appId" placeholder="请输入商户号"></el-input>
</el-form-item>
<el-form-item label="商户密钥">
<el-input type="textarea" v-model="form.appToken" placeholder="请输入商户密钥"></el-input>
</el-form-item>
<el-form-item label="支付密码">
<el-input v-model="form.payPassword" placeholder="请输入支付密码"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="-1">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</div>
</el-dialog>
</template>
<script>
import { tbMerchantThirdApply, tbMerchantThirdApplyPut } from '@/api/shop'
export default ({
data() {
return {
dialogVisible: false,
activeName: 'pay',
formLoading: false,
form: {
appToken: '',
id: '',
payPassword: '',
status: 1,
appId: ''
}
}
},
methods: {
// 保存
async submitHandle() {
this.formLoading = true
try {
await tbMerchantThirdApplyPut(this.form)
this.$emit('success')
this.formLoading = false
this.$notify({
title: '成功',
message: `提交成功`,
type: 'success'
});
this.close()
} catch (error) {
this.formLoading = false
console.log(error)
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form.appToken = ''
this.form.id = ''
this.form.payPassword = ''
this.form.status = 1
this.form.appId = ''
},
// 详情(配置三方支付)
async getDetail(id) {
try {
const res = await tbMerchantThirdApply(id)
this.form.appToken = res.appToken
this.form.payPassword = res.payPassword
this.form.status = res.status
this.form.appId = res.appId
} catch (error) {
console.log(error)
}
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form.id = obj.merchantId
this.getDetail(obj.merchantId)
}
}
}
})
</script>
<style scoped lang="scss">
::v-deep(.el-dialog__header) {
padding: 0;
}
</style>

View File

@@ -0,0 +1,313 @@
<template>
<div>
<div>
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="门店名称" prop="shopName">
<el-input v-model="form.shopName" placeholder="请输入门店名称" style="width: 500px;"></el-input>
</el-form-item>
<el-form-item label="门店logo">
<el-image :src="form.logo || require('@/assets/images/upload.png')" fit="contain"
style="width: 80px;height: 80px;" @click="showUpload = true; uploadIndex = 1"></el-image>
</el-form-item>
<el-form-item label="门店照片">
<el-image :src="form.coverImg || require('@/assets/images/upload.png')" fit="contain"
style="width: 80px;height: 80px;" @click="showUpload = true; uploadIndex = 2"></el-image>
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="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"
:min="0"></el-input-number>
</el-form-item> -->
<el-form-item label="店铺经度">
<el-row>
<el-col :span="4">
<el-input v-model="form.lng" placeholder="经度"></el-input>
</el-col>
<el-col :span="4">
<el-input v-model="form.lat" placeholder="纬度" style="margin-left: 10px;"></el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" plain icon="el-icon-place" style="margin-left: 20px;"
@click="showLocation = true">选择坐标</el-button>
</el-col>
</el-row>
<div style="color: #999;">准确的定位便于用户导航到店铺</div>
</el-form-item>
<el-form-item label="门店详细地址">
<el-input type="textarea" v-model="form.address" placeholder="请输入门店详细地址"
style="width: 500px;"></el-input>
</el-form-item>
<el-form-item label="营业时间">
<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: `${startTime}:00 - 23:59:59`
}" format="HH:mm" value-format="HH:mm">
</el-time-picker>
</el-form-item>
<!-- <el-form-item label="结算类型">
<el-radio-group v-model="form.settleType">
<el-radio :label="0">今日</el-radio>
<el-radio :label="1">次日</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="结算时间" prop="settleTime">
<el-time-picker placeholder="请选择结算时间" v-model="form.settleTime" :picker-options="{
selectableRange: '00:00:00 - 23:59:59',
format: 'HH:mm'
}" format="HH:mm" value-format="HH:mm">
</el-time-picker>
</el-form-item>
<el-form-item label="店铺简介">
<el-input type="textarea" v-model="form.detail" placeholder="请输入店铺简介" style="width: 500px;"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio :label="1">营业中</el-radio>
<el-radio :label="2">休息中</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog title="选择地址" :visible.sync="showLocation">
<div class="map_box">
<div class="map">
<el-amap :center="amapOptions.center">
<el-amap-marker :position="amapOptions.center"></el-amap-marker>
</el-amap>
</div>
<div class="search_box">
<el-amap-search-box :search-option="searchOption"
:on-search-result="onSearchResult"></el-amap-search-box>
</div>
<div class="search_wrap">
<div class="item" v-for="item in locationSearchList" :key="item.id">
<div class="left">
<div class="name">{{ item.name }}-{{ item.address }}</div>
<div class="location">
经纬度{{ item.lng }},{{ item.lat }}
</div>
</div>
<div class="btn">
<el-button type="primary" @click="selectLocationHandle(item)">
选择
</el-button>
</div>
</div>
</div>
</div>
</el-dialog>
<el-dialog :visible.sync="showUpload" :close-on-click-modal="false" append-to-body width="500px"
@close="showUpload = false">
<el-upload :before-remove="handleBeforeRemove" :on-success="handleSuccess" :on-error="handleError"
:file-list="fileList" :headers="headers" :action="qiNiuUploadApi" class="upload-demo" multiple>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件且文件不超过15M</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="doSubmit">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { getToken } from '@/utils/auth'
import { mapGetters } from 'vuex'
import crudQiNiu from '@/api/tools/qiniu'
import { tbShopInfo, tbShopInfoPut } from '@/api/user'
export default {
computed: {
...mapGetters([
'qiNiuUploadApi'
])
},
data() {
return {
showLocation: false,
showUpload: false,
uploadIndex: 1,
startTime: '',
endTime: '',
formLoading: false,
form: {},
rules: {
shopName: [
{
required: true,
message: ' ',
trigger: 'blur'
}
],
phone: [
{
required: true,
message: ' ',
trigger: 'blur'
}
],
settleTime: [
{
required: true,
message: ' ',
trigger: 'blur'
}
]
},
fileList: [],
files: [],
headers: {
'Authorization': getToken()
},
searchOption: {
city: '西安',
citylimit: false
},
locationSearchList: [],
amapOptions: {
center: [108.946465, 34.347984],
position: []
}
}
},
mounted() {
this.tbShopInfo()
},
methods: {
onSearchResult(res) {
this.locationSearchList = res
this.amapOptions.center = [res[0].lng, res[0].lat]
},
// 确认地址选择
selectLocationHandle(item) {
this.form.lng = item.lng
this.form.lat = item.lat
this.showLocation = false
},
// 获取用户详情
async tbShopInfo() {
try {
const shopId = localStorage.getItem('shopId')
const res = await tbShopInfo(shopId)
this.form = res
if (res.businessTime) {
const businessTime = res.businessTime.split('-')
this.startTime = businessTime[0]
this.endTime = businessTime[1]
}
} catch (error) { }
},
// 保存
submitHandle() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.formLoading = true
try {
if (this.startTime && this.endTime) {
this.form.businessTime = `${this.startTime}-${this.endTime}`
}
console.log(this.startTime, this.endTime);
const res = await tbShopInfoPut(this.form)
this.formLoading = false
this.$notify({
title: '成功',
message: '提交成功',
type: 'success'
});
} catch (error) { }
}
})
},
handleSuccess(response, file, fileList) {
// const uid = file.uid
// const id = response.id
// this.files.push({ uid, id })
console.log('上传成功', response)
this.files = response.data
},
handleBeforeRemove(file, fileList) {
for (let i = 0; i < this.files.length; i++) {
if (this.files[i].uid === file.uid) {
crudQiNiu.del([this.files[i].id]).then(res => { })
return true
}
}
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
// 监听上传失败
handleError(e, file, fileList) {
const msg = JSON.parse(e.message)
this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR)
},
// 刷新列表数据
doSubmit() {
this.fileList = []
this.showUpload = false
switch (this.uploadIndex) {
case 1:
this.form.logo = this.files[0]
break;
case 2:
this.form.coverImg = this.files[0]
break;
default:
break;
}
},
}
}
</script>
<style scoped lang="scss">
.map_box {
width: 100%;
position: relative;
.map {
height: 300px;
}
.search_box {
position: absolute;
top: 10px;
left: 10px;
}
.search_wrap {
padding: 6px 0;
.item {
display: flex;
padding: 12px 0;
.left {
flex: 1;
display: flex;
flex-direction: column;
padding-right: 20px;
.location {
color: #999;
padding-top: 4px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,85 @@
<template>
<div>
<el-form ref="form" :model="form" label-width="120px" label-position="left">
<el-form-item label="货币单位">
<el-radio-group v-model="form.currency">
<el-radio-button label="¥"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备用金">
<el-input v-model="form.prepareAmount" placeholder="0.00" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="保留小数位">
<el-radio-group v-model="form.decimalsDigits">
<el-radio-button label="0"></el-radio-button>
<el-radio-button label="1"></el-radio-button>
<el-radio-button label="2"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="语音通知">
<el-switch v-model="form.voiceNotification" :active-value="1" :inactive-value="0"></el-switch>
<div style="color: #999;">开启后将语音播报待处理事件</div>
</el-form-item>
<el-form-item label="移动端支付">
<el-switch v-model="form.allowWebPay" :active-value="1" :inactive-value="0"></el-switch>
<div style="color: #999;">是否允许用户在小程序端支付订单</div>
</el-form-item>
<el-form-item label="自动锁屏">
<el-select v-model="form.autoLockScreen" placeholder="请选择锁屏时间">
<el-option label="不自动锁屏" :value="0"></el-option>
<el-option label="30s" value="30"></el-option>
<el-option label="1min" value="60s"></el-option>
<el-option label="2min" value="120s"></el-option>
<el-option label="5min" value="300s"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { tbShopCurrency, tbShopCurrencyPut } from '@/api/shop'
export default {
data() {
return {
formLoading: false,
form: {}
}
},
mounted() {
this.tbShopCurrency()
},
methods: {
// 保存
submitHandle() {
this.$refs.form.validate(async (valid) => {
if (valid) {
this.formLoading = true
try {
const res = await tbShopCurrencyPut(this.form)
this.formLoading = false
this.$notify({
title: '成功',
message: '提交成功',
type: 'success'
});
} catch (error) { }
}
})
},
// 获取基本配置
async tbShopCurrency() {
try {
const res = await tbShopCurrency(localStorage.getItem('shopId'))
this.form = res
} catch (error) { }
}
}
}
</script>

View File

@@ -1,135 +1,185 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!--工具栏-->
<div class="head-container"> <div class="head-container">
<!--如果想在工具栏加入更多按钮可以使用插槽方式 slot = 'left' or 'right'--> <el-row :gutter="20">
<crudOperation :permission="permission" /> <el-col :span="3">
<!--表单组件--> <el-input v-model="query.name" size="small" clearable placeholder="请输入店铺名称" style="width: 100%;"
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> class="filter-item" @keyup.enter.native="getTableData" />
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> </el-col>
<el-form-item label="自增id" prop="id"> <el-col :span="3">
<el-input v-model="form.id" style="width: 370px;" /> <el-input v-model="query.account" size="small" clearable placeholder="请输入商户号" style="width: 100%;"
</el-form-item> class="filter-item" @keyup.enter.native="getTableData" />
<el-form-item label="店铺帐号"> </el-col>
<el-input v-model="form.account" style="width: 370px;" /> <el-col :span="3">
</el-form-item> <el-select v-model="query.status" placeholder="请选择店铺状态" style="width: 100%;">
<el-form-item label="店铺名称" prop="shopName"> <el-option :label="item.label" :value="item.type" v-for="item in status" :key="item.type" />
<el-input v-model="form.shopName" style="width: 370px;" /> </el-select>
</el-form-item> </el-col>
<el-form-item label="联系电话"> <el-col :span="6">
<el-input v-model="form.phone" style="width: 370px;" /> <el-button type="primary" @click="getTableData">查询</el-button>
</el-form-item> <el-button @click="resetHandle">重置</el-button>
<el-form-item label="店铺log"> </el-col>
<el-input v-model="form.logo" style="width: 370px;" /> </el-row>
</el-form-item> </div>
<el-form-item label="封面图"> <div class="head-container">
<el-input v-model="form.coverImg" style="width: 370px;" /> <el-button type="primary" icon="el-icon-plus" @click="$refs.addShop.show()">添加店铺</el-button>
</el-form-item> </div>
<el-form-item label="详细地址"> <div class="head-container">
<el-input v-model="form.address" style="width: 370px;" /> <el-table :data="tableData.list" v-loading="tableData.loading">
</el-form-item> <el-table-column label="店铺信息" width="200">
<el-form-item label="营业时间"> <template v-slot="scope">
<el-input v-model="form.businessTime" style="width: 370px;" /> <div class="shop_info">
</el-form-item> <el-image :src="scope.row.coverImg"
<el-form-item label="到期时间"> style="width: 50px;height: 50px;border-radius: 4px;background-color: #efefef;">
<el-input v-model="form.expireAt" style="width: 370px;" /> <div class="img_error" slot="error">
</el-form-item> <i class="icon el-icon-document-delete"></i>
<el-form-item label="门店状态" prop="status"> </div>
<el-input v-model="form.status" style="width: 370px;" /> </el-image>
</el-form-item> <div class="info">
</el-form> <span>{{ scope.row.shopName }}</span>
<div slot="footer" class="dialog-footer"> <div class="tag_wrap">
<el-button type="text" @click="crud.cancelCU">取消</el-button> <el-tag type="info" effect="dark" v-if="scope.row.profiles == 'no'">未激活</el-tag>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> <el-tag type="warning" effect="dark" v-if="scope.row.profiles == 'probation'">试用</el-tag>
</div> <el-tag type="success" effect="dark" v-if="scope.row.profiles == 'release'">正式</el-tag>
</el-dialog> <el-tag type="primary" effect="dark" v-if="scope.row.isWxMaIndependent">独立小程序</el-tag>
<!--表格渲染--> </div>
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> </div>
<el-table-column type="selection" width="55" /> </div>
<el-table-column prop="id" label="自增id" />
<el-table-column prop="account" label="店铺帐号" />
<el-table-column prop="shopName" label="店铺名称" />
<el-table-column prop="phone" label="联系电话" />
<el-table-column prop="logo" label="店铺log" width="100px">
<template slot-scope="scope">
<img :src="scope.row.logo" width="80px" height="50px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="registerType" label="类型">
<el-table-column prop="coverImg" label="封面图" width="150px"> <template v-slot="scope">
<template slot-scope="scope"> <span v-if="scope.row.registerType == 'munchies'">快餐版</span>
<img :src="scope.row.coverImg" width="100px" height="100px" /> <span v-if="scope.row.registerType == 'restaurant'">餐饮版</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="address" label="商户号"></el-table-column>
<el-table-column prop="address" label="详细地址" /> <el-table-column prop="lowPrice" label="来源"></el-table-column>
<el-table-column prop="businessTime" label="营业时间" /> <el-table-column prop="lowPrice" label="认证状态">-</el-table-column>
<el-table-column prop="expireAt" label="到期时间" /> <el-table-column prop="status" label="店铺状态">
<el-table-column prop="status" label="门店状态"> <template v-slot="scope">
<template slot-scope="scope"> <el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0" disabled></el-switch>
{{ dict.label.shop_status[scope.row.status] }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="checkPer(['admin','tbShopInfo:edit','tbShopInfo:del'])" label="操作" width="150px" align="center"> <el-table-column prop="createdAt" label="到期时间">
<template slot-scope="scope"> <template v-slot="scope">
<udOperation {{ dayjs(scope.row.expireAt).format('YYYY-MM-DD HH:mm:ss') }}
:data="scope.row" </template>
:permission="permission" </el-table-column>
/> <el-table-column label="操作" width="150">
<template v-slot="scope">
<el-button type="text" icon="el-icon-edit" @click="$refs.addShop.show(scope.row)">编辑</el-button>
<el-dropdown @command="dropdownClick">
<el-button type="text">更多<i class="el-icon-arrow-down"></i></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{ row: scope.row, command: 1 }">详情</el-dropdown-item>
<el-dropdown-item :command="2">续费记录</el-dropdown-item>
<el-dropdown-item :command="3">前往店铺</el-dropdown-item>
<el-dropdown-item :command="4">重置密码</el-dropdown-item>
<el-dropdown-item divided :command="5">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--分页组件-->
<pagination />
</div> </div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
<addShop ref="addShop" @success="getTableData" />
<detailModal ref="detailModal" />
</div> </div>
</template> </template>
<script> <script>
import crudTbShopInfo from '@/api/tbShopInfo' import dayjs from 'dayjs'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import { tbShopInfo } from '@/api/shop.js'
import rrOperation from '@crud/RR.operation' import addShop from '../components/addShop'
import crudOperation from '@crud/CRUD.operation' import detailModal from '../components/detailModal'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
const defaultForm = { id: null, account: null, shopCode: null, subTitle: null, merchantId: null, shopName: null, chainName: null, backImg: null, frontImg: null, contactName: null, phone: null, logo: null, isDeposit: null, isSupply: null, coverImg: null, shareImg: null, view: null, detail: null, lat: null, lng: null, mchId: null, registerType: null, isWxMaIndependent: null, address: null, city: null, type: null, industry: null, industryName: null, businessTime: null, postTime: null, postAmountLine: null, onSale: null, settleType: null, settleTime: null, enterAt: null, expireAt: null, status: null, average: null, orderWaitPayMinute: null, supportDeviceNumber: null, distributeLevel: null, createdAt: null, updatedAt: null, proxyId: null }
export default { export default {
name: 'TbShopInfo', components: { addShop, detailModal },
components: { pagination, crudOperation, rrOperation, udOperation },
mixins: [presenter(), header(), form(defaultForm), crud()],
dicts: ['shop_status'],
cruds() {
return CRUD({ title: '/shop/list', url: 'api/tbShopInfo', idField: 'id', sort: 'id,desc', crudMethod: { ...crudTbShopInfo }})
},
data() { data() {
return { return {
permission: { dayjs,
add: ['admin', 'tbShopInfo:add'], query: {
edit: ['admin', 'tbShopInfo:edit'], name: '',
del: ['admin', 'tbShopInfo:del'] account: '',
status: ''
}, },
rules: { status: [
id: [ {
{ required: true, message: '自增id不能为空', trigger: 'blur' } type: 1,
], label: '开启'
shopName: [ },
{ required: true, message: '店铺名称不能为空', trigger: 'blur' } {
], type: 0,
status: [ label: '关闭'
{ required: true, message: '门店状态不能为空', trigger: 'blur' } }
] ],
} } tableData: {
list: [],
page: 0,
size: 10,
loading: false,
total: 0
}
}
},
mounted() {
this.getTableData()
}, },
methods: { methods: {
// 钩子在获取表格数据之前执行false 则代表不获取数据 dropdownClick(e) {
[CRUD.HOOK.beforeRefresh]() { switch (e.command) {
return true case 1:
this.$refs.detailModal.show(e.row)
break;
default:
break;
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.account = ''
this.query.status = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 获取商家列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopInfo({
page: this.tableData.page,
size: this.tableData.size,
shopName: this.query.name,
account: this.query.account,
status: this.query.status
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
} }
} }
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.shop_info {
display: flex;
</style> .info {
flex: 1;
padding-left: 4px;
}
}
</style>

View File

@@ -0,0 +1,26 @@
<template>
<div class="app-container">
<el-tabs v-model="activeName" type="card">
<el-tab-pane label="店铺信息" name="1"></el-tab-pane>
<el-tab-pane label="基础配置" name="2"></el-tab-pane>
</el-tabs>
<shopInfo v-if="activeName == 1" />
<shopSetting v-if="activeName == 2" />
</div>
</template>
<script>
import shopInfo from './components/shopInfo'
import shopSetting from './components/shopSetting'
export default {
components: {
shopInfo,
shopSetting
},
data() {
return {
activeName: '1',
}
}
}
</script>

View File

@@ -4,15 +4,17 @@
<div class="head-container"> <div class="head-container">
<div v-if="crud.props.searchToggle"> <div v-if="crud.props.searchToggle">
<!-- 搜索 --> <!-- 搜索 -->
<el-input v-model="query.blurry" clearable size="small" placeholder="模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-input v-model="query.blurry" clearable size="small" placeholder="模糊搜索" style="width: 200px;"
class="filter-item" @keyup.enter.native="crud.toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" /> <date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation /> <rrOperation />
</div> </div>
<crudOperation :permission="permission" /> <crudOperation :permission="permission" />
</div> </div>
<!--表单渲染--> <!--表单渲染-->
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="580px"> <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU"
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="80px"> :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="680px">
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="100px">
<el-form-item label="菜单类型" prop="type"> <el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="form.type" size="mini" style="width: 178px"> <el-radio-group v-model="form.type" size="mini" style="width: 178px">
<el-radio-button label="0">目录</el-radio-button> <el-radio-button label="0">目录</el-radio-button>
@@ -21,15 +23,11 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-show="form.type.toString() !== '2'" label="菜单图标" prop="icon"> <el-form-item v-show="form.type.toString() !== '2'" label="菜单图标" prop="icon">
<el-popover <el-popover placement="bottom-start" width="450" trigger="click" @show="$refs['iconSelect'].reset()">
placement="bottom-start"
width="450"
trigger="click"
@show="$refs['iconSelect'].reset()"
>
<IconSelect ref="iconSelect" @selected="selected" /> <IconSelect ref="iconSelect" @selected="selected" />
<el-input slot="reference" v-model="form.icon" style="width: 450px;" placeholder="点击选择图标" readonly> <el-input slot="reference" v-model="form.icon" style="width: 450px;" placeholder="点击选择图标" readonly>
<svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon" style="height: 32px;width: 16px;" /> <svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon"
style="height: 32px;width: 16px;" />
<i v-else slot="prefix" class="el-icon-search el-input__icon" /> <i v-else slot="prefix" class="el-icon-search el-input__icon" />
</el-input> </el-input>
</el-popover> </el-popover>
@@ -53,34 +51,37 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-if="form.type.toString() !== '2'" label="菜单标题" prop="title"> <el-form-item v-if="form.type.toString() !== '2'" label="菜单标题" prop="title">
<el-input v-model="form.title" :style=" form.type.toString() === '0' ? 'width: 450px' : 'width: 178px'" placeholder="菜单标题" /> <el-input v-model="form.title" :style="form.type.toString() === '0' ? 'width: 450px' : 'width: 178px'"
placeholder="菜单标题" />
</el-form-item> </el-form-item>
<el-form-item v-if="form.type.toString() === '2'" label="按钮名称" prop="title"> <el-form-item v-if="form.type.toString() === '2'" label="按钮名称" prop="title">
<el-input v-model="form.title" placeholder="按钮名称" style="width: 178px;" /> <el-input v-model="form.title" placeholder="按钮名称" style="width: 178px;" />
</el-form-item> </el-form-item>
<el-form-item v-show="form.type.toString() !== '0'" label="权限标识" prop="permission"> <el-form-item v-show="form.type.toString() !== '0'" label="权限标识" prop="permission">
<el-input v-model="form.permission" :disabled="form.iFrame.toString() === 'true'" placeholder="权限标识" style="width: 178px;" /> <el-input v-model="form.permission" :disabled="form.iFrame.toString() === 'true'" placeholder="权限标识"
style="width: 178px;" />
</el-form-item> </el-form-item>
<el-form-item v-if="form.type.toString() !== '2'" label="路由地址" prop="path"> <el-form-item v-if="form.type.toString() !== '2'" label="路由地址" prop="path">
<el-input v-model="form.path" placeholder="路由地址" style="width: 178px;" /> <el-input v-model="form.path" placeholder="路由地址" style="width: 178px;" />
</el-form-item> </el-form-item>
<el-form-item label="菜单排序" prop="menuSort"> <el-form-item label="菜单排序" prop="menuSort">
<el-input-number v-model.number="form.menuSort" :min="0" :max="999" controls-position="right" style="width: 178px;" /> <el-input-number v-model.number="form.menuSort" :min="0" :max="999" controls-position="right"
style="width: 178px;" />
</el-form-item> </el-form-item>
<el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件名称" prop="componentName"> <el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件名称"
prop="componentName">
<el-input v-model="form.componentName" style="width: 178px;" placeholder="匹配组件内Name字段" /> <el-input v-model="form.componentName" style="width: 178px;" placeholder="匹配组件内Name字段" />
</el-form-item> </el-form-item>
<el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件路径" prop="component"> <el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件路径"
prop="component">
<el-input v-model="form.component" style="width: 178px;" placeholder="组件路径" /> <el-input v-model="form.component" style="width: 178px;" placeholder="组件路径" />
</el-form-item> </el-form-item>
<el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="选中父级菜单">
<el-input v-model="form.activeMenu" placeholder="请输入父级菜单path" style="width: 178px;" />
</el-form-item>
<el-form-item label="上级类目" prop="pid"> <el-form-item label="上级类目" prop="pid">
<treeselect <treeselect v-model="form.pid" :options="menus" :load-options="loadMenus" style="width: 450px;"
v-model="form.pid" placeholder="选择上级类目" />
:options="menus"
:load-options="loadMenus"
style="width: 450px;"
placeholder="选择上级类目"
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@@ -89,18 +90,9 @@
</div> </div>
</el-dialog> </el-dialog>
<!--表格渲染--> <!--表格渲染-->
<el-table <el-table ref="table" v-loading="crud.loading" lazy :load="getMenus" :data="crud.data"
ref="table" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" row-key="id" @select="crud.selectChange"
v-loading="crud.loading" @select-all="crud.selectAllChange" @selection-change="crud.selectionChangeHandler">
lazy
:load="getMenus"
:data="crud.data"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
row-key="id"
@select="crud.selectChange"
@select-all="crud.selectAllChange"
@selection-change="crud.selectionChangeHandler"
>
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column :show-overflow-tooltip="true" label="菜单标题" width="125px" prop="title" /> <el-table-column :show-overflow-tooltip="true" label="菜单标题" width="125px" prop="title" />
<el-table-column prop="icon" label="图标" align="center" width="60px"> <el-table-column prop="icon" label="图标" align="center" width="60px">
@@ -134,13 +126,10 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createTime" label="创建日期" width="135px" /> <el-table-column prop="createTime" label="创建日期" width="135px" />
<el-table-column v-if="checkPer(['admin','menu:edit','menu:del'])" label="操作" width="130px" align="center" fixed="right"> <el-table-column v-if="checkPer(['admin', 'menu:edit', 'menu:del'])" label="操作" width="130px" align="center"
fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<udOperation <udOperation :data="scope.row" :permission="permission" msg="确定删除吗,如果存在下级节点则一并删除此操作不能撤销" />
:data="scope.row"
:permission="permission"
msg="确定删除吗,如果存在下级节点则一并删除此操作不能撤销"
/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -165,7 +154,7 @@ export default {
name: 'Menu', name: 'Menu',
components: { Treeselect, IconSelect, crudOperation, rrOperation, udOperation, DateRangePicker }, components: { Treeselect, IconSelect, crudOperation, rrOperation, udOperation, DateRangePicker },
cruds() { cruds() {
return CRUD({ title: '菜单', url: 'api/menus', crudMethod: { ...crudMenu }}) return CRUD({ title: '菜单', url: 'api/menus', crudMethod: { ...crudMenu } })
}, },
mixins: [presenter(), header(), form(defaultForm), crud()], mixins: [presenter(), header(), form(defaultForm), crud()],
data() { data() {
@@ -209,7 +198,7 @@ export default {
}, },
getSupDepts(id) { getSupDepts(id) {
crudMenu.getMenuSuperior(id).then(res => { crudMenu.getMenuSuperior(id).then(res => {
const children = res.map(function(obj) { const children = res.map(function (obj) {
if (!obj.leaf && !obj.children) { if (!obj.leaf && !obj.children) {
obj.children = null obj.children = null
} }
@@ -221,7 +210,7 @@ export default {
loadMenus({ action, parentNode, callback }) { loadMenus({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) { if (action === LOAD_CHILDREN_OPTIONS) {
crudMenu.getMenusTree(parentNode.id).then(res => { crudMenu.getMenusTree(parentNode.id).then(res => {
parentNode.children = res.map(function(obj) { parentNode.children = res.map(function (obj) {
if (!obj.leaf) { if (!obj.leaf) {
obj.children = null obj.children = null
} }
@@ -242,11 +231,14 @@ export default {
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
::v-deep .el-input-number .el-input__inner { ::v-deep .el-input-number .el-input__inner {
text-align: left; text-align: left;
} }
::v-deep .vue-treeselect__control,::v-deep .vue-treeselect__placeholder,::v-deep .vue-treeselect__single-value {
height: 30px; ::v-deep .vue-treeselect__control,
line-height: 30px; ::v-deep .vue-treeselect__placeholder,
} ::v-deep .vue-treeselect__single-value {
height: 30px;
line-height: 30px;
}
</style> </style>

View File

@@ -0,0 +1,163 @@
<template>
<el-dialog title="添加支付方式" :visible.sync="dialogVisible" :show-close="false" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="支付类型" prop="payType">
<el-select v-model="form.payType" placeholder="请选择支付类型" @change="typeChange">
<el-option :label="item.lable" :value="item.key" v-for="item in payTypes"
:key="item.key"></el-option>
</el-select>
</el-form-item>
<el-form-item label="支付方式" prop="payName" v-if="form.payType == 'virtual'">
<el-input v-model="form.payName" placeholder="请输入自定义支付方式"></el-input>
</el-form-item>
<!-- <el-form-item label="图标" prop="icon">
<uploadImg ref="uploadImg" :limit="9" @success="e => form.icon = e[0]" />
</el-form-item> -->
<el-form-item label="是否虚拟">
<el-radio-group v-model="form.isIdeal">
<el-radio :label="1">虚拟</el-radio>
<el-radio :label="0">非虚拟</el-radio>
</el-radio-group>
<div class="tips">虚拟微信支付宝支付等 非虚拟现金</div>
</el-form-item>
<el-form-item label="开钱箱权限">
<el-switch v-model="form.isOpenCashDrawer" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item label="是否生效">
<el-switch v-model="form.isDisplay" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="form.sorts" controls-position="right" :min="0"></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submitHandle" :loading="formLoading">
<span v-if="!formLoading">保存</span>
<span v-else>保存中...</span>
</el-button>
</div>
</el-dialog>
</template>
<script>
import uploadImg from '@/components/uploadImg'
import { tbShopPayType } from '@/api/setting'
import payTypes from '../payTypes'
export default ({
components: { uploadImg },
data() {
const validateIcon = (rule, value, callback) => {
if (!this.form.icon) {
callback(new Error('请上传图标'))
} else {
callback()
}
}
return {
payTypes,
dialogVisible: false,
formLoading: false,
resetForm: '',
form: {
id: '',
icon: '',
shopId: localStorage.getItem('shopId'),
payType: '',
payName: '',
isIdeal: 1,
isOpenCashDrawer: 1,
isDisplay: 1,
sorts: 0
},
rules: {
payType: [
{
required: true,
message: ' ',
triiger: 'blur'
}
],
payName: [
{
required: true,
message: ' ',
triiger: 'blur'
}
],
icon: [
{
required: true,
validator: validateIcon,
triiger: 'change'
}
]
}
}
},
mounted() {
this.resetForm = { ...this.form }
},
methods: {
typeChange(e) {
this.form.icon = payTypes.find(item => item.key == e).icon
if (e == 'virtual') {
this.form.payName = ''
} else {
this.form.payName = payTypes.find(item => item.key == e).lable
}
},
// 保存
submitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
try {
this.formLoading = true
await tbShopPayType(this.form, this.form.id ? 'put' : 'post')
this.$emit('success')
this.formLoading = false
this.$notify({
title: '成功',
message: `${this.form.pid ? '编辑' : '添加'}成功`,
type: 'success'
});
this.close()
} catch (error) {
this.formLoading = false
console.log(error)
}
}
})
},
close() {
this.dialogVisible = false
},
reset() {
this.form = { ...this.resetForm }
// this.$refs.uploadImg.fileList = []
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form.id = obj.id
this.form.icon = obj.icon
this.form.payType = obj.payType
this.form.payName = obj.payName
this.form.isIdeal = obj.isIdeal
this.form.isOpenCashDrawer = obj.isOpenCashDrawer
this.form.isDisplay = obj.isDisplay
this.form.sorts = obj.sorts
// if (obj.icon) {
// setTimeout(() => {
// this.$refs.uploadImg.fileList = [{
// url: obj.icon
// }]
// }, 100);
// }
}
}
}
})
</script>

View File

@@ -1,158 +1,130 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!--工具栏-->
<div class="head-container"> <div class="head-container">
<div v-if="crud.props.searchToggle"> <el-button type="primary" icon="el-icon-plus" @click="$refs.addPayType.show()">添加支付方式</el-button>
<!-- 搜索 --> </div>
<label class="el-form-item-label">自增id</label> <div class="head-container">
<el-input v-model="query.id" clearable placeholder="自增id" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-table :data="tableData.list" v-loading="tableData.loading"><el-table-column prop="icon" label="图标">
<label class="el-form-item-label">支付类型</label> <template v-slot="scope">
<el-input v-model="query.payType" clearable placeholder="支付类型" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> <el-image :src="scope.row.icon" style="width: 40px;height: 40px;"></el-image>
<label class="el-form-item-label">支付类型名称</label> </template>
<el-input v-model="query.payName" clearable placeholder="支付类型名称" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<label class="el-form-item-label">是否快捷展示</label>
<el-input v-model="query.isShowShortcut" clearable placeholder="是否快捷展示" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<label class="el-form-item-label">店铺id</label>
<el-input v-model="query.shopId" clearable placeholder="店铺id" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<label class="el-form-item-label">是否打开钱箱</label>
<el-input v-model="query.isOpenCashDrawer" clearable placeholder="是否打开钱箱" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<label class="el-form-item-label">createdAt</label>
<el-input v-model="query.createdAt" clearable placeholder="createdAt" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<label class="el-form-item-label">排序</label>
<el-input v-model="query.sorts" clearable placeholder="排序" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<rrOperation :crud="crud" />
</div>
<!--如果想在工具栏加入更多按钮可以使用插槽方式 slot = 'left' or 'right'-->
<crudOperation :permission="permission" />
<!--表单组件-->
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<el-form-item label="自增id" prop="id">
<el-input v-model="form.id" style="width: 370px;" />
</el-form-item>
<el-form-item label="支付类型">
<el-input v-model="form.payType" style="width: 370px;" />
</el-form-item>
<el-form-item label="支付类型名称">
<el-input v-model="form.payName" style="width: 370px;" />
</el-form-item>
<el-form-item label="是否快捷展示">
<el-radio-group v-model="form.isShowShortcut" style="width: 140px">
<el-radio label="1">是</el-radio>
<el-radio label="0">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="店铺id">
<el-input v-model="form.shopId" style="width: 370px;" />
</el-form-item>
<el-form-item label="是否打开钱箱">
<el-radio-group v-model="form.isOpenCashDrawer" style="width: 140px">
<el-radio label="1">是</el-radio>
<el-radio label="0">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="createdAt">
<el-input v-model="form.createdAt" style="width: 370px;" />
</el-form-item>
<el-form-item label="排序">
<el-input v-model="form.sorts" style="width: 370px;" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="自增id" />
<el-table-column prop="payType" label="支付类型" />
<el-table-column prop="payName" label="支付类型名称" />
<el-table-column prop="isShowShortcut" label="是否快捷展示" >
<template slot-scope="scope">
<span>{{ form.isShowShortcut == 1 ? '是' : '否' }}</span>
</template>
</el-table-column> </el-table-column>
<el-table-column prop="payName" label="支付方式"></el-table-column>
<el-table-column prop="shopId" label="店铺id" /> <el-table-column prop="payType" label="类型"></el-table-column>
<el-table-column prop="isOpenCashDrawer" label="开钱箱权限">
<el-table-column prop="isOpenCashDrawer" label="是否打开钱箱"> <template v-slot="scope">
<el-switch <el-switch v-model="scope.row.isOpenCashDrawer" :active-value="1" :inactive-value="0" disabled></el-switch>
v-model="form.isOpenCashDrawer" </template>
class="switch"
:active-value="1"
:inactive-value="0"
active-text=""
inactive-text=""
/>
</el-table-column> </el-table-column>
<el-table-column prop="createdAt" label="createdAt" /> <el-table-column prop="isDisplay" label="是否生效">
<el-table-column prop="sorts" label="排序" />
<el-table-column v-if="checkPer(['admin','tbShopPayType:edit','tbShopPayType:del'])" label="操作" width="150px" align="center"> <template v-slot="scope">
<template slot-scope="scope"> <el-switch v-model="scope.row.isDisplay" :active-value="1" :inactive-value="0" disabled></el-switch>
<udOperation </template>
:data="scope.row" </el-table-column>
:permission="permission" <el-table-column prop="sorts" label="条件排序"></el-table-column>
/> <el-table-column label="操作" width="150">
<template v-slot="scope">
<el-button type="text" icon="el-icon-edit" @click="$refs.addPayType.show(scope.row)">编辑</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--分页组件-->
<pagination />
</div> </div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
@current-change="paginationChange" layout="total, sizes, prev, pager, next, jumper"></el-pagination>
</div>
<addPayType ref="addPayType" @success="getTableData" />
</div> </div>
</template> </template>
<script> <script>
import crudTbShopPayType from '@/api/tbShopPayType' import dayjs from 'dayjs'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import { tbShopPayTypeGet } from '@/api/setting.js'
import rrOperation from '@crud/RR.operation' import addPayType from './components/addPayType'
import crudOperation from '@crud/CRUD.operation'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
const defaultForm = { id: null, payType: null, payName: null, isShowShortcut: null, shopId: null, isRefundable: null, isOpenCashDrawer: null, isSystem: null, isIdeal: null, isDisplay: null, createdAt: null, updatedAt: null, sorts: null }
export default { export default {
name: 'TbShopPayType', components: { addPayType },
components: { pagination, crudOperation, rrOperation, udOperation },
mixins: [presenter(), header(), form(defaultForm), crud()],
cruds() {
return CRUD({ title: '/merchant/system/paytype', url: 'api/tbShopPayType', idField: 'id', sort: 'id,desc', crudMethod: { ...crudTbShopPayType }})
},
data() { data() {
return { return {
permission: { dayjs,
add: ['admin', 'tbShopPayType:add'], query: {
edit: ['admin', 'tbShopPayType:edit'], name: '',
del: ['admin', 'tbShopPayType:del'] account: '',
status: ''
}, },
rules: { status: [
id: [ {
{ required: true, message: '自增id不能为空', trigger: 'blur' } type: 1,
] label: '开启'
}, },
queryTypeOptions: [ {
{ key: 'id', display_name: '自增id' }, type: 0,
{ key: 'payType', display_name: '支付类型' }, label: '关闭'
{ key: 'payName', display_name: '支付类型' }, }
{ key: 'isShowShortcut', display_name: '是否快捷展示' }, ],
{ key: 'shopId', display_name: '店铺id' }, tableData: {
{ key: 'isOpenCashDrawer', display_name: '是否打开钱箱' }, list: [],
{ key: 'createdAt', display_name: 'createdAt' }, page: 0,
{ key: 'sorts', display_name: '排序' } size: 10,
] loading: false,
total: 0
}
} }
}, },
mounted() {
this.getTableData()
},
methods: { methods: {
// 钩子在获取表格数据之前执行false 则代表不获取数据 dropdownClick(e) {
[CRUD.HOOK.beforeRefresh]() { switch (e.command) {
return true case 1:
this.$refs.detailModal.show(e.row)
break;
default:
break;
}
},
// 重置查询
resetHandle() {
this.query.name = ''
this.query.account = ''
this.query.status = ''
this.getTableData()
},
// 分页回调
paginationChange(e) {
this.tableData.page = e - 1
this.getTableData()
},
// 获取商家列表
async getTableData() {
this.tableData.loading = true
try {
const res = await tbShopPayTypeGet({
page: this.tableData.page,
size: this.tableData.size,
shopId: localStorage.getItem('shopId')
})
this.tableData.loading = false
this.tableData.list = res.content
this.tableData.total = res.totalElements
} catch (error) {
console.log(error)
}
} }
} }
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.shop_info {
display: flex;
</style> .info {
flex: 1;
padding-left: 4px;
}
}
</style>

View File

@@ -0,0 +1,32 @@
export default [
{
lable: '现金',
key: 'cash',
icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240302/2dab947729d640fba7709b7c0b42bfef.png'
},
{
lable: '银行卡',
key: 'bank',
icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240302/14b20cf721304b7fa2f01e6e75fab403.png'
},
{
lable: '扫码支付',
key: 'scanCode',
icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240302/9ff08224680446c8b3978844da99bbaa.png'
},
{
lable: '储值卡',
key: 'deposit',
icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240302/18d40f471a924d55b4eb13e5f553734d.png'
},
// {
// lable: '挂单',
// key: 'arrears',
// icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240304/fcf337b999f14a12ad75f76e74fcb344.png'
// },
{
lable: '自定义',
key: 'virtual',
icon: 'https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240304/6702fbf953504f89aa6a3db1f33d49b6.png'
}
]

View File

@@ -0,0 +1,73 @@
<template>
<el-dialog :title="form.id ? '编辑区域' : '添加区域'" :visible.sync="dialogVisible" @close="reset">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="left">
<el-form-item label="区域名称" prop="name">
<el-input v-model="form.name" placeholder="请输入区域名称"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="onSubmitHandle"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { tbShopArea } from '@/api/table'
export default {
data() {
return {
dialogVisible: false,
form: {
id: '',
name: ''
},
rules: {
name: [
{
required: true,
message: '请输入区域名称',
trigger: 'blur'
}
]
}
}
},
methods: {
onSubmitHandle() {
this.$refs.form.validate(async valid => {
if (valid) {
try {
let res = await tbShopArea({
...this.form,
shopId: localStorage.getItem('shopId')
}, this.form.id ? 'put' : 'post')
this.$emit('success', res)
this.close()
this.$notify({
title: '成功',
message: `${this.form.id ? '编辑' : '添加'}成功`,
type: 'success'
});
} catch (error) {
console.log(error)
}
}
})
},
show(obj) {
this.dialogVisible = true
if (obj && obj.id) {
this.form = JSON.parse(JSON.stringify(obj))
}
},
close() {
this.dialogVisible = false
},
reset() {
this.form.id = ''
this.form.name = ''
}
}
}
</script>

View File

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

View File

@@ -0,0 +1,61 @@
<template>
<div class="app-container">
<el-form :model="form" label-width="120px">
<el-form-item label="网络预定开关">
<el-switch v-model="form.yd" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item label="预定时间" v-if="form.timeList.length">
<div class="time_row" v-for="(item, index) in form.timeList" :key="index">
<el-time-picker is-range v-model="item.time" range-separator="至" start-placeholder="开始时间"
end-placeholder="结束时间" placeholder="选择时间范围">
</el-time-picker>
<i class="icon el-icon-delete" @click="form.timeList.splice(index, 1)"></i>
</div>
</el-form-item>
<el-form-item>
<el-button plain icon="el-icon-plus" @click="form.timeList.push({ time: [] })">添加时间段</el-button>
<div class="tips">结束时间不能小于开始时间</div>
</el-form-item>
<el-form-item label="允许预约天数">
<el-input-number v-model="form.dayMax" controls-position="right" :min="0"></el-input-number>
<div class="tips">最多预约几天后的日期</div>
</el-form-item>
<el-form-item label="允许预约天数">
<el-input type="textarea" v-model="form.info" placeholder="充值说明" style="width: 500px;"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
form: {
yd: 0,
timeList: [],
dayMax: 3,
info: ''
}
}
}
}
</script>
<style scoped lang="scss">
.time_row {
display: flex;
align-items: center;
&:not(:first-child) {
margin-top: 20px;
}
.icon {
margin-left: 20px;
}
}
</style>

View File

@@ -0,0 +1,256 @@
<template>
<div class="app-container">
<el-tabs v-model="tabVlaue" type="card" @tab-click="tabClick">
<el-tab-pane label="全部" name=""></el-tab-pane>
<el-tab-pane v-for="item in tabs" :key="item.id" :label="item.name" :name="`${item.id}`">
<div slot="label">
{{ item.name }}
<i class="icon el-icon-edit" @click.stop="$refs.addEara.show(item)"></i>
<el-popconfirm title="确定删除吗?" @confirm="delHandle([item.id])">
<i class="icon el-icon-delete" slot="reference" @click.stop=""></i>
</el-popconfirm>
</div>
</el-tab-pane>
</el-tabs>
<div class="head-container">
<div class="filter_wrap">
<el-button icon="el-icon-plus" @click="$refs.addEara.show()">添加区域</el-button>
<el-button type="primary" icon="el-icon-plus" @click="$refs.addTable.show()">添加台桌</el-button>
<el-button type="primary" icon="el-icon-download">下载台桌码</el-button>
<el-button type="primary" icon="el-icon-download">下载店铺码</el-button>
</div>
</div>
<div class="head-container">
<div class="table_list" v-loading="loading">
<div class="item" v-for="item in tableList" :key="item.id">
<div class="top">
<div class="row row1">
<span>{{ item.name }}</span>
<div class="state">
<span class="dot" :style="{ backgroundColor: status[item.status].type }"></span>
{{ status[item.status].label }}
</div>
</div>
<div class="row">
<el-tag type="warning" size="mini">{{ item.type == 0 ? '低消' : '计时' }}</el-tag>
<el-tag :type="item.isPredate == 1 ? '' : 'info'" size="mini">{{ item.isPredate == 1 ? '可预约' : '不可预约' }}</el-tag>
</div>
<div class="row">
<span class="tips">客座次数{{ item.maxCapacity }}</span>
</div>
</div>
<div class="btm">
<!-- <div class="btm_item">
<i class="i el-icon-edit"></i>
</div> -->
<div class="btm_item" @click="$refs.addTable.show(item)">
<i class="i el-icon-edit"></i>
</div>
<el-popconfirm title="确定删除吗?" @confirm="delTableHandle([item.id])" style="flex: 1;">
<div class="btm_item" slot="reference">
<i class="i el-icon-delete"></i>
</div>
</el-popconfirm>
</div>
</div>
<div class="empty_wrap">
<el-empty description="空空如也~" v-if="!tableList.length"></el-empty>
</div>
</div>
</div>
<addEara ref="addEara" @success="tbShopAreaGet" />
<addTable ref="addTable" @success="tbShopTableGet" />
</div>
</template>
<script>
import addEara from './components/addEara'
import addTable from './components/addTable'
import { tbShopTableGet, tbShopAreaGet, tbShopAreaDelete, tbShopTableDelete } from '@/api/table'
export default {
components: {
addEara,
addTable
},
data() {
return {
tabVlaue: '',
tabs: [],
loading: false,
tableList: [],
status: {
subscribe: {
label: '预定',
type: '#E6A23C'
},
closed: {
label: '关台',
type: '#F56C6C'
},
opening: {
label: '开台中',
type: '#67C23A'
},
cleaning: {
label: '台桌清理中',
type: '#909399'
}
}
}
},
mounted() {
this.tbShopAreaGet()
},
methods: {
tabClick() {
this.tbShopTableGet()
},
// 删除桌台
async delTableHandle(ids) {
try {
await tbShopTableDelete(ids)
this.tbShopTableGet()
} catch (error) {
console.log(error)
}
},
// 删除区域
async delHandle(ids) {
try {
await tbShopAreaDelete(ids)
this.tabVlaue = ''
this.tbShopAreaGet()
} catch (error) {
console.log(error)
}
},
// 台桌列表
async tbShopTableGet() {
this.loading = true
try {
const { content } = await tbShopTableGet({
shopId: localStorage.getItem('shopId'),
areaId: this.tabVlaue
})
this.tableList = content
setTimeout(() => {
this.loading = false
}, 300)
} catch (error) {
this.loading = false
console.log(error)
}
},
// 获取区域
async tbShopAreaGet() {
try {
const { content } = await tbShopAreaGet({
shopId: localStorage.getItem('shopId')
})
this.tabs = content
this.tbShopTableGet()
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style>
.el-tabs {
margin-bottom: 0;
}
</style>
<style scoped lang="scss">
.icon {
margin-left: 10px;
}
.table_list {
display: flex;
flex-wrap: wrap;
gap: 20px;
min-height: 150px;
.empty_wrap {
flex: 1;
display: flex;
justify-content: center;
}
.item {
border: 1px solid #ddd;
.top {
padding: 20px;
.row {
display: flex;
gap: 10px;
.tips {
font-size: 12px;
}
&:not(:first-child) {
margin-top: 20px;
}
&.row1 {
justify-content: space-between;
font-size: 14px;
.state {
display: flex;
align-items: center;
margin-left: 80px;
.dot {
$size: 6px;
width: $size;
height: $size;
border-radius: 50%;
margin-right: $size;
}
}
}
}
}
.btm {
border-top: 1px solid #ddd;
background-color: #efefef;
display: flex;
.btm_item {
flex: 1;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
&:hover {
cursor: pointer;
}
&:nth-child(1) {
&::before {
content: '';
height: 50%;
border-right: 1px solid #ddd;
position: absolute;
top: 25%;
right: 0;
}
}
.i {
color: #666;
}
}
}
}
}
</style>

View File

@@ -6,38 +6,27 @@
<div class="head-container"> <div class="head-container">
<div v-if="crud.props.searchToggle"> <div v-if="crud.props.searchToggle">
<!-- 搜索 --> <!-- 搜索 -->
<el-input v-model="query.key" clearable size="small" placeholder="输入文件名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> <el-input v-model="query.key" clearable size="small" placeholder="输入文件名称搜索" style="width: 200px;"
class="filter-item" @keyup.enter.native="toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" /> <date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation /> <rrOperation />
</div> </div>
<crudOperation :permission="permission"> <crudOperation :permission="permission">
<template slot="left"> <template slot="left">
<!-- 上传 --> <!-- 上传 -->
<el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload" @click="dialog = true">上传</el-button> <el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload"
@click="dialog = true">上传</el-button>
<!-- 同步 --> <!-- 同步 -->
<el-button :icon="icon" class="filter-item" size="mini" type="warning" @click="synchronize">同步</el-button> <el-button :icon="icon" class="filter-item" size="mini" type="warning" @click="synchronize">同步</el-button>
<!-- 配置 --> <!-- 配置 -->
<el-button <el-button class="filter-item" size="mini" type="success" icon="el-icon-s-tools"
class="filter-item" @click="doConfig">配置</el-button>
size="mini"
type="success"
icon="el-icon-s-tools"
@click="doConfig"
>配置</el-button>
</template> </template>
</crudOperation> </crudOperation>
<!-- 文件上传 --> <!-- 文件上传 -->
<el-dialog :visible.sync="dialog" :close-on-click-modal="false" append-to-body width="500px" @close="doSubmit"> <el-dialog :visible.sync="dialog" :close-on-click-modal="false" append-to-body width="500px" @close="doSubmit">
<el-upload <el-upload :before-remove="handleBeforeRemove" :on-success="handleSuccess" :on-error="handleError"
:before-remove="handleBeforeRemove" :file-list="fileList" :headers="headers" :action="qiNiuUploadApi" class="upload-demo" multiple>
:on-success="handleSuccess"
:on-error="handleError"
:file-list="fileList"
:headers="headers"
:action="qiNiuUploadApi"
class="upload-demo"
multiple
>
<el-button size="small" type="primary">点击上传</el-button> <el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件且文件不超过15M</div> <div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件且文件不超过15M</div>
</el-upload> </el-upload>
@@ -46,14 +35,17 @@
</div> </div>
</el-dialog> </el-dialog>
<!--表格渲染--> <!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;"
@selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column prop="name" :show-overflow-tooltip="true" label="文件名"> <el-table-column prop="name" :show-overflow-tooltip="true" label="文件名">
<template slot-scope="scope"> <template slot-scope="scope">
<a href="JavaScript:" class="el-link el-link--primary" target="_blank" type="primary" @click="download(scope.row.id)">{{ scope.row.key }}</a> <a href="JavaScript:" class="el-link el-link--primary" target="_blank" type="primary"
@click="download(scope.row.id)">{{ scope.row.key }}</a>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :show-overflow-tooltip="true" prop="suffix" label="文件类型" @selection-change="crud.selectionChangeHandler" /> <el-table-column :show-overflow-tooltip="true" prop="suffix" label="文件类型"
@selection-change="crud.selectionChangeHandler" />
<el-table-column prop="bucket" label="空间名称" /> <el-table-column prop="bucket" label="空间名称" />
<el-table-column prop="size" label="文件大小" /> <el-table-column prop="size" label="文件大小" />
<el-table-column prop="type" label="空间类型" /> <el-table-column prop="type" label="空间类型" />
@@ -79,7 +71,7 @@ import DateRangePicker from '@/components/DateRangePicker'
export default { export default {
components: { eForm, pagination, crudOperation, rrOperation, DateRangePicker }, components: { eForm, pagination, crudOperation, rrOperation, DateRangePicker },
cruds() { cruds() {
return CRUD({ title: '七牛云文件', url: 'api/qiNiuContent', crudMethod: { ...crudQiNiu }}) return CRUD({ title: '七牛云文件', url: 'api/qiNiuContent', crudMethod: { ...crudQiNiu } })
}, },
mixins: [presenter(), header(), crud()], mixins: [presenter(), header(), crud()],
data() { data() {
@@ -90,11 +82,11 @@ export default {
title: '文件', dialog: false, title: '文件', dialog: false,
icon: 'el-icon-refresh', icon: 'el-icon-refresh',
url: '', headers: { 'Authorization': getToken() }, url: '', headers: { 'Authorization': getToken() },
dialogImageUrl: '', dialogImageUrl: '',
dialogVisible: false, dialogVisible: false,
fileList: [], fileList: [],
files: [], files: [],
newWin: null newWin: null
} }
}, },
computed: { computed: {
@@ -132,7 +124,7 @@ export default {
handleBeforeRemove(file, fileList) { handleBeforeRemove(file, fileList) {
for (let i = 0; i < this.files.length; i++) { for (let i = 0; i < this.files.length; i++) {
if (this.files[i].uid === file.uid) { 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 return true
} }
} }
@@ -188,6 +180,4 @@ export default {
} }
</script> </script>
<style scoped> <style scoped></style>
</style>