Compare commits

...

125 Commits

Author SHA1 Message Date
9be57ad750 Merge pull request 'test' (#47) from test into master
Reviewed-on: #47
2023-10-17 08:53:53 +08:00
f7313c5911 Merge pull request 'lb' (#46) from lb into test
Reviewed-on: #46
2023-10-17 08:38:26 +08:00
lb
a7e81ad8fb Merge branch 'test' into lb 2023-10-16 17:04:34 +08:00
lb
32cbf9076f update 更新设备类型上传 2023-10-16 17:03:29 +08:00
9a411cc663 Merge pull request 'dy' (#45) from dy into test
Reviewed-on: #45
2023-10-16 15:50:05 +08:00
helloDy
445a88e540 Merge branch 'test' into dy 2023-10-16 15:47:50 +08:00
helloDy
2b355aaf8f ui 2023-10-16 15:47:31 +08:00
lb
f60a46ed1d update 设备信息上传 2023-10-16 15:36:26 +08:00
2688896660 Merge pull request 'dy' (#44) from dy into test
Reviewed-on: #44
2023-10-13 17:12:02 +08:00
helloDy
4a67e226e1 merge 2023-10-13 17:09:07 +08:00
helloDy
11ee0d6541 Merge branch 'test' into dy 2023-10-13 17:06:35 +08:00
98b3237c9a Merge pull request 'lb' (#43) from lb into test
Reviewed-on: #43
2023-10-13 17:06:02 +08:00
helloDy
46aaa47e07 bug 2023-10-13 17:05:01 +08:00
lb
ca0f62b2eb Merge branch 'test' into lb 2023-10-13 17:04:18 +08:00
lb
5534104e87 update equipment edit 2023-10-13 17:01:49 +08:00
lb
b72fe1bfed update equipment edit 2023-10-13 16:08:31 +08:00
f4493bde1c Merge pull request 'dy' (#42) from dy into test
Reviewed-on: #42
2023-10-12 17:06:04 +08:00
helloDy
d682ecc91c Merge branch 'test' into dy 2023-10-12 17:05:03 +08:00
helloDy
2b76ef7d23 bug 2023-10-12 17:04:03 +08:00
lb
9ec13b35b8 update equipment 2023-10-12 17:03:07 +08:00
lb
7acccd3de0 bugfix zentao 2023-10-12 15:40:05 +08:00
e40f45a79a Merge pull request 'zjl' (#41) from zjl into test
Reviewed-on: #41
2023-10-12 14:43:24 +08:00
77083a84a1 merge test 2023-10-12 14:41:59 +08:00
9f53ea6981 10.12 2023-10-12 14:39:59 +08:00
lb
8f634d012c bugfix zentao 2023-10-12 11:08:51 +08:00
03c573d5b2 Merge pull request 'zjl' (#40) from zjl into test
Reviewed-on: #40
2023-10-11 14:34:26 +08:00
348714edaf merge test 2023-10-11 14:33:37 +08:00
814fe4605a UI样式修改能源&班组 2023-10-11 14:30:18 +08:00
bb6bfc5ab6 Merge pull request 'lb' (#39) from lb into test
Reviewed-on: #39
2023-10-11 10:33:08 +08:00
lb
0162f338ba Merge branch 'test' into lb 2023-10-11 10:30:25 +08:00
lb
8f99915720 add 设备看板 2023-10-11 10:29:26 +08:00
744e5d80be Merge pull request 'dy' (#38) from dy into test
Reviewed-on: #38
2023-10-10 17:08:40 +08:00
helloDy
d3b119ad9b Merge branch 'test' into dy 2023-10-10 17:07:02 +08:00
helloDy
69bdab75d4 bug 2023-10-10 17:06:39 +08:00
lb
af5e0333ed update ui 2023-10-10 17:01:57 +08:00
lb
b2ee61b8cb update 改为抽屉展示 2023-10-10 14:22:00 +08:00
lb
723d83cc02 update 设备分组 2023-10-10 10:04:23 +08:00
lb
769830c448 update 设备分组 2023-10-09 17:01:19 +08:00
lb
907db90e93 update 设备分组的抽屉 2023-10-09 16:27:44 +08:00
lb
6e390bf12a update 2023-10-09 13:32:33 +08:00
lb
b39f0625a1 update 2023-10-09 11:37:19 +08:00
lb
e985c73e00 update gantt 2023-10-08 17:14:18 +08:00
180fcf5ad8 Merge pull request 'dy' (#37) from dy into test
Reviewed-on: #37
2023-10-08 17:03:04 +08:00
helloDy
b1c0d21888 Merge branch 'test' into dy 2023-10-08 16:59:31 +08:00
helloDy
96d52fafee pdf 2023-10-08 16:59:09 +08:00
lb
4f7889ff60 done time sequence demo 2023-10-08 15:53:38 +08:00
lb
bc2c5a4787 update time sequence status 2023-10-08 15:00:38 +08:00
lb
ab8e9cb2a5 update 2023-10-08 14:30:50 +08:00
lb
57960ff8bf update print page 2023-10-08 10:18:08 +08:00
lb
b9e39dacf1 bugfix zentao 2023-10-08 09:31:02 +08:00
lb
80ad95be6e add print module 2023-10-07 14:29:43 +08:00
7dfaae02a8 Merge pull request 'lb' (#36) from lb into test
Reviewed-on: #36
2023-09-27 17:00:53 +08:00
lb
cf2d7af94b delete echarts 2023-09-27 17:00:33 +08:00
lb
a48b31dcbe Merge branch 'test' into lb 2023-09-27 16:58:28 +08:00
lb
96b0a9e503 update 产品质量分析 2023-09-27 16:57:57 +08:00
lb
9c257aa24a update demo 2023-09-27 16:19:55 +08:00
lb
7ab5f1b812 update demo 2023-09-27 14:42:38 +08:00
lb
5c796cd44f add custom echarts demo 2023-09-27 14:01:57 +08:00
lb
fe0b5538a8 update 设备产量时序图 2023-09-27 13:22:09 +08:00
lb
90695acefd update 检测信息记录 2023-09-27 10:14:24 +08:00
a90c5cca0c Merge pull request 'zjl' (#35) from zjl into test
Reviewed-on: #35
2023-09-27 09:38:02 +08:00
4d7e3c0e04 merge test 2023-09-27 09:36:20 +08:00
ee40707d2c 修改bug及能源分析样式 2023-09-27 09:33:28 +08:00
lb
20808c0975 update 产量时序图 2023-09-26 17:00:46 +08:00
lb
87f56dd9ac update responsejson 2023-09-26 15:12:41 +08:00
lb
24ffea330d update 设备产量分析 2023-09-26 14:56:00 +08:00
lb
a4594426c3 bugfix 2023-09-26 14:38:30 +08:00
lb
c899bb37e3 update quality inspection record 2023-09-26 11:03:34 +08:00
47e91d821b Merge pull request 'lb' (#34) from lb into test
Reviewed-on: #34
2023-09-25 17:14:23 +08:00
lb
d907d2f341 Merge branch 'test' into lb 2023-09-25 17:13:47 +08:00
lb
1116531aff update 2023-09-25 16:58:35 +08:00
lb
8dc5bbb4d8 update 2023-09-25 16:53:31 +08:00
lb
c24d22aedd update 2023-09-25 16:34:05 +08:00
lb
bbbfa9644d bugfix 2023-09-25 15:47:39 +08:00
db4ecc91d6 Merge pull request 'dy' (#33) from dy into test
Reviewed-on: #33
2023-09-22 16:59:55 +08:00
helloDy
699810f40a Merge branch 'test' into dy 2023-09-22 16:54:40 +08:00
helloDy
d454f20bd6 bug 2023-09-22 16:54:16 +08:00
lb
56f209a27e Merge branch 'test' into lb 2023-09-22 16:29:50 +08:00
lb
980f3468b7 update homepage 2023-09-22 16:29:31 +08:00
95da2191dd Merge pull request 'zjl' (#32) from zjl into test
Reviewed-on: #32
2023-09-22 11:09:34 +08:00
42550264c8 merge test 2023-09-22 11:08:58 +08:00
727f7d57c3 能源bug 2023-09-22 11:06:43 +08:00
aa32e4d3fb Merge pull request 'lb' (#31) from lb into test
Reviewed-on: #31
2023-09-22 10:54:56 +08:00
lb
dcda3a6294 bugfix 2023-09-22 10:54:21 +08:00
lb
f43b1c1eab update 设备加工数量 2023-09-22 10:29:28 +08:00
ca3965e8cb Merge pull request 'lb' (#30) from lb into test
Reviewed-on: #30
2023-09-22 09:57:16 +08:00
lb
ee3d6f9dc6 merge 2023-09-22 09:28:41 +08:00
lb
e2a777069e update 设备加工数量 2023-09-21 17:09:15 +08:00
lb
06fa7d40b3 update 设备加工数量 2023-09-21 17:03:07 +08:00
lb
f6f0480744 update 设备加工数量 2023-09-21 16:00:46 +08:00
lb
45e7f337bf update 设备加工数量 2023-09-21 15:54:11 +08:00
lb
8e0d63839a update 设备加工数量 2023-09-21 15:35:16 +08:00
lb
6c21f01fd7 update 设备加工数量 2023-09-21 15:14:38 +08:00
lb
52bc38499c update 设备效率分析 2023-09-21 14:54:16 +08:00
lb
c600d14f8f update 设备产量时序图 2023-09-20 17:03:39 +08:00
2265c549e6 Merge pull request 'zjl' (#29) from zjl into test
Reviewed-on: #29
2023-09-20 16:59:53 +08:00
a74242f3b3 mrege test 2023-09-20 16:59:13 +08:00
ebcf3d4d78 修改bug 2023-09-20 16:57:20 +08:00
lb
8ad84a4d61 update 设备产量时序图 2023-09-20 14:44:39 +08:00
ff9e93d264 Merge pull request 'dy' (#28) from dy into test
Reviewed-on: #28
2023-09-20 14:28:21 +08:00
lb
928258e509 update 设备状态时序图 2023-09-20 14:11:36 +08:00
helloDy
ee0affc78f Merge branch 'test' into dy 2023-09-20 13:58:36 +08:00
helloDy
dfec94be17 表格 2023-09-20 13:58:14 +08:00
lb
a12530b835 update 质量检测统计数据 2023-09-20 11:17:34 +08:00
lb
b3db8dcae8 update 检测统计数据chart 2023-09-20 10:49:17 +08:00
lb
24a0857808 update 质量检测统计数据 2023-09-20 09:50:38 +08:00
lb
e0cc022e34 update 产品质量分析样式 2023-09-20 09:11:31 +08:00
lb
71bcd14c72 update 产品质量分析chart 2023-09-19 17:06:19 +08:00
646859aeef Merge pull request '修bug' (#27) from zjl into test
Reviewed-on: #27
2023-09-19 15:47:12 +08:00
5a31498224 修bug 2023-09-19 15:45:16 +08:00
lb
c965dfbc5a bugfix 2023-09-18 17:01:44 +08:00
lb
c364162a2a update no-data-background 2023-09-18 15:14:18 +08:00
282ef45114 Merge pull request 'zjl' (#26) from zjl into test
Reviewed-on: #26
2023-09-18 14:49:52 +08:00
0371859d14 排班及bug 2023-09-18 14:49:03 +08:00
lb
7407b97f5a bugfix zentao 2023-09-18 13:52:36 +08:00
eff5e0d1e1 merge test 2023-09-18 08:50:53 +08:00
60dc449a27 排班 2023-09-18 08:41:14 +08:00
159d626b30 Merge pull request 'dy' (#25) from dy into test
Reviewed-on: #25
2023-09-16 18:00:34 +08:00
helloDy
bc5d3d44d5 页面 2023-09-16 17:51:09 +08:00
lb
a6d8a7a9da update 2023-09-15 15:45:37 +08:00
lb
7d2bfaea18 bugfix zentao 2 2023-09-15 14:49:31 +08:00
helloDy
e9538744c3 冲突 2023-09-15 14:38:43 +08:00
helloDy
8cf2f9f7e9 生产监控 2023-09-15 14:37:30 +08:00
lb
772a4b0633 bugfix zentao 1 2023-09-15 14:30:19 +08:00
lb
27ebe39a96 update image 2023-09-13 17:06:02 +08:00
149 changed files with 22760 additions and 11675 deletions

View File

@@ -1,20 +1,20 @@
###
# @Author: Do not edit
# @Date: 2023-08-29 09:40:39
# @LastEditTime: 2023-09-12 14:01:15
# @LastEditors: zhp
# @LastEditTime: 2023-10-16 09:22:52
# @LastEditors: DY
# @Description:
###
# 开发环境配置
ENV = 'development'
# 页面标题
VUE_APP_TITLE = 芋道管理系统
VUE_APP_TITLE = 产线监控系统
# 芋道管理系统/开发环境
VUE_APP_BASE_API = 'http://192.168.1.188:48080'
# VUE_APP_BASE_API = 'http://192.168.1.49:48080'
# VUE_APP_BASE_API = 'http://192.168.1.8:48080'
# VUE_APP_BASE_API = 'http://192.168.0.33:48080'
VUE_APP_BASE_API = 'http://192.168.0.33:48080'
# VUE_APP_BASE_API = 'http://192.168.1.188:48080'
# 路由懒加载

View File

@@ -2,7 +2,7 @@
ENV = 'development'
# 页面标题
VUE_APP_TITLE = 芋道管理系统
VUE_APP_TITLE = 产线监控系统
# 芋道管理系统/本地环境
VUE_APP_BASE_API = 'http://api-dashboard.yudao.iocoder.cn'

View File

@@ -2,7 +2,7 @@
ENV = 'production'
# 页面标题
VUE_APP_TITLE = 芋道管理系统
VUE_APP_TITLE = 产线监控系统
# 芋道管理系统/生产环境
VUE_APP_BASE_API = '/prod-api'

View File

@@ -1,7 +1,7 @@
NODE_ENV = production
# 页面标题
VUE_APP_TITLE = 芋道管理系统
VUE_APP_TITLE = 产线监控系统
# 测试环境配置
ENV = 'staging'

View File

@@ -4,7 +4,7 @@ NODE_ENV = development
ENV = 'staging'
# 页面标题
VUE_APP_TITLE = 芋道管理系统
VUE_APP_TITLE = 产线监控系统
# 芋道管理系统/测试环境
VUE_APP_BASE_API = 'http://127.0.0.1:48080'

1
.gitignore vendored
View File

@@ -20,3 +20,4 @@ selenium-debug.log
*.local
package-lock.json
echarts.js

View File

@@ -50,33 +50,40 @@
"code-brick-zj": "^1.0.2",
"core-js": "^3.26.0",
"crypto-js": "^4.0.0",
"diagram-js": "^12.3.0",
"echarts": "5.4.0",
"element-ui": "2.15.12",
"file-saver": "^2.0.5",
"fuse.js": "6.6.2",
"highlight.js": "9.18.5",
"html2canvas": "^1.4.1",
"js-beautify": "1.13.0",
"jsencrypt": "3.3.1",
"jspdf": "^2.5.1",
"min-dash": "3.5.2",
"mockjs": "^1.1.0",
"moment": "^2.29.4",
"nprogress": "0.2.0",
"qrcode.vue": "^1.7.0",
"qs": "^6.11.2",
"quill": "1.3.7",
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"throttle-debounce": "2.1.0",
"video.js": "^8.5.2",
"vue": "2.7.14",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.8",
"vue-meta": "^2.4.0",
"vue-plugin-hiprint": "0.0.54-fix",
"vue-quill-editor": "^3.0.6",
"vue-router": "3.4.9",
"vue-video-player": "^5.0.2",
"vuedraggable": "2.24.3",
"vuex": "3.6.2",
"xlsx": "^0.18.5",
"xml-js": "1.6.11"
"xml-js": "1.6.11",
"yorkie": "^2.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.5.18",
@@ -90,7 +97,7 @@
"chalk": "4.1.0",
"compression-webpack-plugin": "5.0.2",
"connect": "3.6.6",
"eslint": "7.15.0",
"eslint": "6.8.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^3.1.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,14 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<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="stylesheet" type="text/css" media="print" href="<%= BASE_URL %>print-lock.css">
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= webpackConfig.name %></title>
<title>
<%= webpackConfig.name %>
</title>
<!--[if lt IE 11]>
<script>
window.location.href = 'html/ie.html';
@@ -212,4 +214,5 @@
</div>
</div>
</body>
</html>

339
public/print-lock.css Normal file
View File

@@ -0,0 +1,339 @@
@media print {
body {
margin: 0px;
padding: 0px;
}
}
@page {
margin: 0;
}
.hiprint-printPaper * {
box-sizing: border-box;
-moz-box-sizing: border-box; /* Firefox */
-webkit-box-sizing: border-box; /* Safari */
}
.hiprint-printPaper *:focus {
outline: -webkit-focus-ring-color auto 0px;
}
.hiprint-printPaper {
position: relative;
padding: 0 0 0 0;
page-break-after: always;
-webkit-user-select: none; /* Chrome/Safari/Opera */
-moz-user-select: none; /* Firefox */
user-select: none;
overflow-x: hidden;
overflow: hidden;
}
.hiprint-printPaper .hiprint-printPaper-content {
position: relative;
}
/* 火狐浏览器打印 第一页过后 重叠问题 */
@-moz-document url-prefix() {
.hiprint-printPaper .hiprint-printPaper-content {
position: relative;
margin-top: 20px;
top: -20px
}
}
.hiprint-printPaper.design {
overflow: visible;
}
.hiprint-printTemplate .hiprint-printPanel {
page-break-after: always;
}
.hiprint-printPaper, hiprint-printPanel {
box-sizing: border-box;
border: 0px;
}
.hiprint-printPanel .hiprint-printPaper:last-child {
page-break-after: avoid;
}
.hiprint-printTemplate .hiprint-printPanel:last-child {
page-break-after: avoid;
}
.hiprint-printPaper .hideheaderLinetarget {
border-top: 0px dashed rgb(201, 190, 190) !important;
}
.hiprint-printPaper .hidefooterLinetarget {
border-top: 0px dashed rgb(201, 190, 190) !important;
}
.hiprint-printPaper.design {
border: 1px dashed rgba(170, 170, 170, 0.7);
}
.design .hiprint-printElement-table-content, .design .hiprint-printElement-longText-content {
overflow: hidden;
box-sizing: border-box;
}
.design .resize-panel {
box-sizing: border-box;
border: 1px dotted;
}
.hiprint-printElement-text {
background-color: transparent;
background-repeat: repeat;
padding: 0 0 0 0;
border: 0.75pt none rgb(0, 0, 0);
direction: ltr;
font-family: 'SimSun';
font-size: 9pt;
font-style: normal;
font-weight: normal;
padding-bottom: 0pt;
padding-left: 0pt;
padding-right: 0pt;
padding-top: 0pt;
text-align: left;
text-decoration: none;
line-height: 9.75pt;
box-sizing: border-box;
word-wrap: break-word;
word-break: break-all;
}
.design .hiprint-printElement-text-content {
border: 1px dashed rgb(206, 188, 188);
box-sizing: border-box;
}
.hiprint-printElement-longText {
background-color: transparent;
background-repeat: repeat;
border: 0.75pt none rgb(0, 0, 0);
direction: ltr;
font-family: 'SimSun';
font-size: 9pt;
font-style: normal;
font-weight: normal;
padding-bottom: 0pt;
padding-left: 0pt;
padding-right: 0pt;
padding-top: 0pt;
text-align: left;
text-decoration: none;
line-height: 9.75pt;
box-sizing: border-box;
word-wrap: break-word;
word-break: break-all;
/*white-space: pre-wrap*/
}
.hiprint-printElement-table {
background-color: transparent;
background-repeat: repeat;
color: rgb(0, 0, 0);
border-color: rgb(0, 0, 0);
border-style: none;
direction: ltr;
font-family: 'SimSun';
font-size: 9pt;
font-style: normal;
font-weight: normal;
padding-bottom: 0pt;
padding-left: 0pt;
padding-right: 0pt;
padding-top: 0pt;
text-align: left;
text-decoration: none;
padding: 0 0 0 0;
box-sizing: border-box;
line-height: 9.75pt;
}
.hiprint-printElement-table thead {
background: #e8e8e8;
font-weight: 700;
}
.hiprint-printElement-tableTarget, .hiprint-printElement-tableTarget tr, .hiprint-printElement-tableTarget td {
border-color: rgb(0, 0, 0);
/*border-style: none;*/
/*border: 1px solid rgb(0, 0, 0);*/
font-weight: normal;
direction: ltr;
padding-bottom: 0pt;
padding-left: 4pt;
padding-right: 4pt;
padding-top: 0pt;
text-decoration: none;
vertical-align: middle;
box-sizing: border-box;
word-wrap: break-word;
word-break: break-all;
/*line-height: 9.75pt;
font-size: 9pt;*/
}
.hiprint-printElement-tableTarget-border-all {
border: 1px solid;
}
.hiprint-printElement-tableTarget-border-none {
border: 0px solid;
}
.hiprint-printElement-tableTarget-border-lr {
border-left: 1px solid;
border-right: 1px solid;
}
.hiprint-printElement-tableTarget-border-left {
border-left: 1px solid;
}
.hiprint-printElement-tableTarget-border-right {
border-right: 1px solid;
}
.hiprint-printElement-tableTarget-border-tb {
border-top: 1px solid;
border-bottom: 1px solid;
}
.hiprint-printElement-tableTarget-border-top {
border-top: 1px solid;
}
.hiprint-printElement-tableTarget-border-bottom {
border-bottom: 1px solid;
}
.hiprint-printElement-tableTarget-border-td-none td {
border: 0px solid;
}
.hiprint-printElement-tableTarget-border-td-all td:not(:last-child) {
border-right: 1px solid;
}
/*.hiprint-printElement-tableTarget tr,*/
.hiprint-printElement-tableTarget td {
height: 18pt;
}
.hiprint-printPaper .hiprint-paperNumber {
font-size: 9pt;
}
.design .hiprint-printElement-table-handle {
position: absolute;
height: 21pt;
width: 21pt;
background: red;
z-index: 1;
}
.hiprint-printPaper .hiprint-paperNumber-disabled {
float: right !important;
right: 0 !important;
color: gainsboro !important;
}
.hiprint-printElement-vline, .hiprint-printElement-hline {
border: 0px none rgb(0, 0, 0);
}
.hiprint-printElement-vline {
border-left: 0.75pt solid #000;
border-right: 0px none rgb(0, 0, 0) !important;
border-bottom: 0px none rgb(0, 0, 0) !important;
border-top: 0px none rgb(0, 0, 0) !important;
}
.hiprint-printElement-hline {
border-top: 0.75pt solid #000;
border-right: 0px none rgb(0, 0, 0) !important;
border-bottom: 0px none rgb(0, 0, 0) !important;
border-left: 0px none rgb(0, 0, 0) !important;
}
.hiprint-printElement-oval, .hiprint-printElement-rect {
border: 0.75pt solid #000;
}
.hiprint-text-content-middle {
}
.hiprint-text-content-middle > div {
display: grid;
align-items: center;
}
.hiprint-text-content-bottom {
}
.hiprint-text-content-bottom > div {
display: grid;
align-items: flex-end;
}
.hiprint-text-content-wrap {
}
.hiprint-text-content-wrap .hiprint-text-content-wrap-nowrap {
white-space: nowrap;
}
.hiprint-text-content-wrap .hiprint-text-content-wrap-clip {
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
}
.hiprint-text-content-wrap .hiprint-text-content-wrap-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/*hi-grid-row */
.hi-grid-row {
position: relative;
height: auto;
margin-right: 0;
margin-left: 0;
zoom: 1;
display: block;
box-sizing: border-box;
}
.hi-grid-row::after, .hi-grid-row::before {
display: table;
content: '';
box-sizing: border-box;
}
.hi-grid-col {
display: block;
box-sizing: border-box;
position: relative;
float: left;
flex: 0 0 auto;
}
.table-grid-row {
margin-left: -0pt;
margin-right: -0pt;
}
.tableGridColumnsGutterRow {
padding-left: 0pt;
padding-right: 0pt;
}
.hiprint-gridColumnsFooter {
text-align: left;
clear: both;
}

View File

@@ -50,3 +50,11 @@ export function getCode() {
method: 'get'
})
}
// 获得可用的排班列表
export function listEnabled() {
return request({
url: '/base/group-team/listEnabled',
method: 'get'
})
}

View File

@@ -1,54 +1,28 @@
import request from '@/utils/request'
// 创建排班信息
export function createGroupTeamScheduling(data) {
// 获取某月预排班-已有排班
export function getPreset(query) {
return request({
url: '/base/group-team-scheduling/create',
method: 'post',
data: data
})
}
// 更新排班信息
export function updateGroupTeamScheduling(data) {
return request({
url: '/base/group-team-scheduling/update',
method: 'put',
data: data
})
}
// 删除排班信息
export function deleteGroupTeamScheduling(id) {
return request({
url: '/base/group-team-scheduling/delete?id=' + id,
method: 'delete'
})
}
// 获得排班信息
export function getGroupTeamScheduling(id) {
return request({
url: '/base/group-team-scheduling/get?id=' + id,
method: 'get'
})
}
// 获得排班信息分页
export function getGroupTeamSchedulingPage(query) {
return request({
url: '/base/group-team-scheduling/page',
url: '/base/group-team-scheduling/getPreset',
method: 'get',
params: query
})
}
// 导出排班信息 Excel
export function exportGroupTeamSchedulingExcel(query) {
// 批量创建-更新排班信息
export function createOrUpdateList(data) {
return request({
url: '/base/group-team-scheduling/export-excel',
method: 'get',
params: query,
responseType: 'blob'
url: '/base/group-team-scheduling/createOrUpdateList',
method: 'post',
data: data
})
}
// 自动排班,填充上月已有的排班
export function autoSet(query) {
return request({
url: '/base/group-team-scheduling/autoSet',
method: 'get',
params: query
})
}

View File

@@ -1,3 +1,10 @@
/*
* @Author: Do not edit
* @Date: 2023-08-28 15:30:53
* @LastEditTime: 2023-10-13 17:08:33
* @LastEditors: DY
* @Description:
*/
import request from '@/utils/request'
// 创建产线目前生产产品表 主要为更新
@@ -35,11 +42,11 @@ export function getLineBindProductLog(id) {
}
// 获得产线目前生产产品表 主要为更新分页
export function getLineBindProductLogPage(query) {
export function getLineBindProductLogPage(data) {
return request({
url: '/base/line-bind-product-log/page',
method: 'get',
params: query
method: 'post',
data: data
})
}

View File

@@ -0,0 +1,25 @@
/*
* @Author: Do not edit
* @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-13 16:11:41
* @LastEditors: DY
* @Description:
*/
import request from '@/utils/request'
// 获得工厂分页
export function getPdlAutoReport(data) {
return request({
url: '/monitoring/production-monitor/getPdlAutoReport',
method: 'post',
data: data
})
}
// 获得所有工厂产线列表
export function getPdList() {
return request({
url: '/base/production-line/listAll',
method: 'get'
})
}

View File

@@ -0,0 +1,25 @@
/*
* @Author: Do not edit
* @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-14 10:25:46
* @LastEditors: DY
* @Description:
*/
import request from '@/utils/request'
// 获得产线统计数据查询
export function getPdlDataSearch(data) {
return request({
url: '/monitoring/production-monitor/getPdlDataSearch',
method: 'post',
data: data
})
}
// 获得所有工厂产线列表
export function getPdList() {
return request({
url: '/base/production-line/listAll',
method: 'get'
})
}

View File

@@ -0,0 +1,17 @@
/*
* @Author: Do not edit
* @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-15 14:12:26
* @LastEditors: DY
* @Description:
*/
import request from '@/utils/request'
// 获得近24小时产线生产数据
export function getPdlDataOneDay(data) {
return request({
url: '/monitoring/production-monitor/getPdlDataOneDay',
method: 'post',
data: data
})
}

View File

@@ -0,0 +1,33 @@
/*
* @Author: Do not edit
* @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-14 14:01:12
* @LastEditors: DY
* @Description:
*/
import request from '@/utils/request'
// 获得工段自动统计数据查询
export function getSectionAutoReport(data) {
return request({
url: '/monitoring/production-monitor/getSectionAutoReport',
method: 'post',
data: data
})
}
// 获得所有工厂产线列表
export function getPdList() {
return request({
url: '/base/production-line/listAll',
method: 'get'
})
}
// 获得所有产线工段列表
export function getWorkshopSectionList() {
return request({
url: '/base/workshop-section/listAll',
method: 'get'
})
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>选择</title>
<g id="设备管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="设备监控-设备加工数量" transform="translate(-496.000000, -187.000000)" fill-rule="nonzero">
<g id="选择" transform="translate(496.000000, 187.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M13.8735116,4.65950813 C13.6725171,4.47101195 13.3555167,4.48001613 13.1670206,4.6815213 L6.49899208,11.7809972 L2.85649778,8.19199033 C2.65950812,7.99798414 2.34299153,8 2.14898534,8.19698966 C1.95497916,8.3934955 1.95747883,8.71049591 2.15449536,8.90399141 L6.16199434,12.8519823 C6.16349952,12.8534874 6.1654885,12.8539712 6.16699367,12.8554764 C6.16849884,12.8569816 6.16898266,12.8589706 6.17048783,12.8604757 C6.20198897,12.8904717 6.23999461,12.9074856 6.27649508,12.9274829 C6.29450341,12.9379922 6.3099852,12.953474 6.32898802,12.960973 C6.38798547,12.9839807 6.45047706,12.9959683 6.51248486,12.9959683 C6.57798681,12.9959683 6.64348875,12.9829593 6.70447519,12.9569682 C6.72498319,12.9484747 6.74097566,12.930977 6.75997848,12.919957 C6.79747344,12.8979438 6.83647358,12.8794517 6.86848541,12.8469561 C6.86999058,12.8454509 6.87047439,12.8429512 6.87197956,12.841446 C6.87297405,12.8399409 6.87498991,12.8394571 6.8764682,12.8379519 L13.8949604,5.36594544 C14.0849886,5.16548852 14.0745061,4.8489988 13.8735116,4.65950813 Z" id="路径" fill="#0B58FF"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>菜单</title>
<g id="设备管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="设备监控-设备加工数量" transform="translate(-284.000000, -164.000000)" fill-rule="nonzero">
<g id="编组-7" transform="translate(284.000000, 162.000000)">
<g id="菜单" transform="translate(0.000000, 2.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M3.00057813,4.49926562 L13.0025156,4.49926562 C13.2786563,4.49926562 13.5025156,4.27540625 13.5025156,3.99926563 C13.5025156,3.723125 13.2786563,3.49926563 13.0025156,3.49926563 L3.00057813,3.49926563 C2.7244375,3.49926563 2.50057813,3.723125 2.50057813,3.99926563 C2.50057813,4.27540625 2.7244375,4.49926562 3.00057813,4.49926562 Z M3.0004375,8.48703125 L12.9786875,8.48703125 C13.2548281,8.48703125 13.4786875,8.26317187 13.4786875,7.98703125 C13.4786875,7.71089062 13.2548281,7.48703125 12.9786875,7.48703125 L3.0004375,7.48703125 C2.72429687,7.48703125 2.5004375,7.71089062 2.5004375,7.98703125 C2.5004375,8.26317187 2.72429687,8.48703125 3.0004375,8.48703125 Z M13.0025156,11.4969063 L3.00057813,11.4969063 C2.7244375,11.4969063 2.50057813,11.7207656 2.50057813,11.9969063 C2.50057813,12.2730469 2.7244375,12.4969063 3.00057813,12.4969063 L13.0025156,12.4969063 C13.2786563,12.4969063 13.5025156,12.2730469 13.5025156,11.9969063 C13.5025156,11.7207656 13.2786563,11.4969063 13.0025156,11.4969063 L13.0025156,11.4969063 Z" id="形状" fill="#373738"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>状态切换备份 3</title>
<g id="页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="icon和插图" transform="translate(-877.000000, -246.000000)">
<g id="状态切换备份-3" transform="translate(885.000000, 254.000000) rotate(-270.000000) translate(-885.000000, -254.000000) translate(877.000000, 246.000000)">
<rect id="矩形" stroke="#979797" fill="#D8D8D8" opacity="0" x="0.5" y="0.5" width="15" height="15"></rect>
<g id="错误" transform="translate(0.000000, 0.000000)" fill-rule="nonzero">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="6.4293957e-15" width="16" height="16"></rect>
<path d="M8,1 C11.85,1 15,4.15 15,8 C15,11.85 11.85,15 8,15 C4.15,15 1,11.85 1,8 C1,4.15 4.15,1 8,1 Z M8,2.19926499 C4.80249503,2.19926499 2.18635461,4.80959575 2.18635461,8 C2.18635461,11.1904043 4.80249503,13.800735 8,13.800735 C11.197505,13.800735 13.8136454,11.1904043 13.8136454,8 C13.8136454,4.80959575 11.197505,2.19926499 8,2.19926499 Z M9.18342887,4.39602962 C9.42080763,4.39602962 9.61773566,4.56921978 9.65474747,4.7961346 L9.66099805,4.87359881 L9.66052938,9.97276858 L10.1621026,9.47231604 C10.3071657,9.32725295 10.5223305,9.29501672 10.6985498,9.37560733 L10.7713701,9.41705393 L10.837514,9.47231606 C11.0033004,9.63810246 11.0217211,9.89545015 10.8927761,10.0815835 L10.837514,10.1477274 L9.52115984,11.4640816 C9.38457467,11.600698 9.17913638,11.6415719 9.00066062,11.5676398 C8.84450229,11.5029526 8.73591407,11.3615296 8.71120699,11.1977853 L8.70585968,11.1264012 L8.70585968,4.87359881 C8.70585968,4.60984463 8.91967469,4.39602962 9.18342887,4.39602962 Z M6.99933939,4.43236016 C7.15549771,4.49704738 7.26408594,4.63847045 7.28879302,4.80221473 L7.29414032,4.87359881 L7.29414032,11.1264012 C7.29414032,11.2530604 7.24382515,11.374532 7.15426356,11.4640936 C7.06470196,11.5536552 6.94323037,11.6039704 6.81657114,11.6039704 C6.68991191,11.6039704 6.56844032,11.5536552 6.47887872,11.4640936 C6.40722945,11.3924443 6.36069788,11.3003726 6.34495123,11.2015604 L6.33900196,11.1264012 L6.33858601,6.02634681 L5.83789738,6.52768395 C5.69283427,6.67274705 5.47766955,6.70498329 5.30145018,6.62439268 L5.22862992,6.58294608 L5.162486,6.52768394 C4.9966996,6.36189754 4.97827889,6.10454984 5.10722387,5.91841648 L5.162486,5.85227257 L6.47884017,4.53591839 C6.61542534,4.39930202 6.82086362,4.35842813 6.99933939,4.43236016 Z" id="形状结合" fill="#0B58FF"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>收起箭头小备份 3</title>
<g id="能源管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="能源监控-同比分析" transform="translate(-848.000000, -392.000000)" fill-rule="nonzero">
<g id="收起箭头小备份-3" transform="translate(855.000000, 399.000000) scale(1, -1) translate(-855.000000, -399.000000) translate(848.000000, 392.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="14" height="14"></rect>
<path d="M6.60391666,1.57197282 L7.01633334,1.15897282 L12.70325,6.8441395 C12.9278333,7.06872283 12.93075,7.4408895 12.70325,7.6683895 C12.5941655,7.77825546 12.4457769,7.84009206 12.2909546,7.84020155 C12.1361323,7.84031104 11.9876564,7.77868438 11.8784167,7.66897282 L7.0175,2.8103895 L2.16066666,7.66955616 C2.05160439,7.77930978 1.90326864,7.84102718 1.74854166,7.84102718 C1.59381468,7.84102718 1.44547894,7.77930978 1.33641666,7.66955616 C1.10964988,7.4415567 1.1091291,7.07336285 1.33525,6.84472282 L6.58116666,1.59647282 L6.6045,1.57255616 L6.60391666,1.57197282 Z" id="路径" fill="#FFBD02"></path>
<path d="M6.60391666,6.57197282 L7.01633334,6.15897282 L12.70325,11.8441395 C12.9278333,12.0687228 12.93075,12.4408895 12.70325,12.6683895 C12.5941655,12.7782555 12.4457769,12.8400921 12.2909546,12.8402015 C12.1361323,12.840311 11.9876564,12.7786844 11.8784167,12.6689728 L7.0175,7.8103895 L2.16066666,12.6695562 C2.05160439,12.7793098 1.90326864,12.8410272 1.74854166,12.8410272 C1.59381468,12.8410272 1.44547894,12.7793098 1.33641666,12.6695562 C1.10964988,12.4415567 1.1091291,12.0733628 1.33525,11.8447228 L6.58116666,6.59647282 L6.6045,6.57255616 L6.60391666,6.57197282 Z" id="路径备份-2" fill="#FFBD02"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>下拉展开</title>
<g id="页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-43" transform="translate(-1870.000000, -119.000000)" fill-rule="nonzero">
<g id="下拉展开" transform="translate(1870.000000, 119.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="18" height="18"></rect>
<path d="M9.79014922,13.2165873 L16.1721224,6.15356667 C16.6092925,5.77338351 16.6092925,5.16518371 16.1721224,4.78500055 C15.964758,4.60350795 15.6800768,4.50112918 15.3827707,4.50112918 C15.0854647,4.50112918 14.8007835,4.60350795 14.5934191,4.78500055 L9.00013482,11.162609 L3.40552499,4.78387137 C3.19816065,4.60237877 2.91347942,4.5 2.61617336,4.5 C2.3188673,4.5 2.03418606,4.60237877 1.82682172,4.78387137 C1.39105943,5.16454327 1.39105943,5.77176559 1.82682172,6.15243749 L8.20879489,13.214329 C8.31400161,13.3066969 8.440317,13.3797143 8.57994259,13.4288732 C8.99637706,13.5753327 9.475517,13.4912854 9.79014922,13.2165873 Z" id="路径" fill="#0B58FF"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>切换</title>
<g id="1班组管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="切换" fill="#FFFFFF" fill-rule="nonzero">
<rect id="矩形" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M14.5,9.15 C14.969442,9.15 15.35,9.53055796 15.35,10 C15.35,10.4333311 15.0257376,10.7909267 14.6066222,10.8433773 L14.5,10.85 L3.523,10.8493636 L5.10448737,12.4305126 C5.26177017,12.5877954 5.34716031,12.7990496 5.34764236,13.015701 L5.34074746,13.1242515 L5.31933966,13.2323523 C5.24258033,13.518822 5.01882201,13.7425803 4.73235229,13.8193397 C4.48169128,13.8865041 4.21633806,13.832194 4.01342676,13.6770775 L3.93051263,13.6044874 L1.04232939,10.7055042 C0.831903536,10.5688042 0.689345737,10.3541899 0.656994192,10.1075365 L0.65,10 L0.65778959,9.88152374 C0.670925502,9.77175364 0.705946489,9.66606949 0.76033092,9.57061601 L0.821076439,9.47880032 L0.894170559,9.39517056 C1.02591288,9.26342824 1.19742791,9.1808136 1.37731459,9.15882561 L1.5,9.15 L14.5,9.15 Z M11.9865732,2.32292254 L12.0694874,2.39551263 L14.9508862,5.29019827 C15.1653597,5.42263107 15.3074642,5.64305498 15.3419246,5.89182346 L15.35,6 L15.3417548,6.1198336 C15.3282251,6.22918814 15.2930578,6.33441548 15.2387207,6.42946868 L15.1780851,6.52090655 L15.1052179,6.60421789 C14.9738843,6.73555151 14.8030912,6.81820523 14.622959,6.840766 L14.5,6.85 L1.5,6.85 C1.03055796,6.85 0.65,6.46944204 0.65,6 C0.65,5.56666889 0.974262406,5.20907332 1.39337781,5.15662271 L1.5,5.15 L12.475,5.14936355 L10.8955126,3.56948738 C10.7382298,3.41220459 10.6528397,3.20095039 10.6523576,2.98429905 L10.6592525,2.8757485 L10.6806603,2.76764771 C10.7478247,2.5169867 10.9275353,2.31433911 11.1633258,2.21617103 L11.2676477,2.18066033 C11.5183087,2.11349592 11.7836619,2.167806 11.9865732,2.32292254 Z" id="形状结合"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>收起箭头小备份 11</title>
<g id="能源管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="能源监控-同比分析" transform="translate(-848.000000, -269.000000)" fill-rule="nonzero">
<g id="收起箭头小备份-11" transform="translate(848.000000, 269.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="14" height="14"></rect>
<path d="M6.60391666,1.57197282 L7.01633334,1.15897282 L12.70325,6.8441395 C12.9278333,7.06872283 12.93075,7.4408895 12.70325,7.6683895 C12.5941655,7.77825546 12.4457769,7.84009206 12.2909546,7.84020155 C12.1361323,7.84031104 11.9876564,7.77868438 11.8784167,7.66897282 L7.0175,2.8103895 L2.16066666,7.66955616 C2.05160439,7.77930978 1.90326864,7.84102718 1.74854166,7.84102718 C1.59381468,7.84102718 1.44547894,7.77930978 1.33641666,7.66955616 C1.10964988,7.4415567 1.1091291,7.07336285 1.33525,6.84472282 L6.58116666,1.59647282 L6.6045,1.57255616 L6.60391666,1.57197282 Z" id="路径" fill="#37D97F"></path>
<path d="M6.60391666,6.57197282 L7.01633334,6.15897282 L12.70325,11.8441395 C12.9278333,12.0687228 12.93075,12.4408895 12.70325,12.6683895 C12.5941655,12.7782555 12.4457769,12.8400921 12.2909546,12.8402015 C12.1361323,12.840311 11.9876564,12.7786844 11.8784167,12.6689728 L7.0175,7.8103895 L2.16066666,12.6695562 C2.05160439,12.7793098 1.90326864,12.8410272 1.74854166,12.8410272 C1.59381468,12.8410272 1.44547894,12.7793098 1.33641666,12.6695562 C1.10964988,12.4415567 1.1091291,12.0733628 1.33525,11.8447228 L6.58116666,6.59647282 L6.6045,6.57255616 L6.60391666,6.57197282 Z" id="路径备份-2" fill="#37D97F"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>收起</title>
<g id="页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-43" transform="translate(-1870.000000, -485.000000)" fill-rule="nonzero">
<g id="编组-18备份" transform="translate(1.000000, 366.000000)">
<g id="收起" transform="translate(1878.000000, 128.000000) scale(1, -1) translate(-1878.000000, -128.000000) translate(1869.000000, 119.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="18" height="18"></rect>
<path d="M9.79014922,13.2165873 L16.1721224,6.15356667 C16.6092925,5.77338351 16.6092925,5.16518371 16.1721224,4.78500055 C15.964758,4.60350795 15.6800768,4.50112918 15.3827707,4.50112918 C15.0854647,4.50112918 14.8007835,4.60350795 14.5934191,4.78500055 L9.00013482,11.162609 L3.40552499,4.78387137 C3.19816065,4.60237877 2.91347942,4.5 2.61617336,4.5 C2.3188673,4.5 2.03418606,4.60237877 1.82682172,4.78387137 C1.39105943,5.16454327 1.39105943,5.77176559 1.82682172,6.15243749 L8.20879489,13.214329 C8.31400161,13.3066969 8.440317,13.3797143 8.57994259,13.4288732 C8.99637706,13.5753327 9.475517,13.4912854 9.79014922,13.2165873 Z" id="路径" fill="#0B58FF"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

BIN
src/assets/images/Qian.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/images/tuple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

View File

@@ -10,11 +10,21 @@ body {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
// label {
// font-weight: 700;
// }
.searchBarBox .el-form-item--medium .el-form-item__label {
line-height: 40px;
}
.searchBarBox .el-form-item--medium .el-form-item__content {
line-height: 40px;
}
.searchBarBox .el-range-editor--small.el-input__inner {
height: 34px;
}
html {
@@ -90,7 +100,7 @@ div:focus {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
content: ' ';
clear: both;
height: 0;
}
@@ -104,7 +114,8 @@ aside {
display: block;
line-height: 32px;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -130,7 +141,7 @@ aside {
}
.text-center {
text-align: center
text-align: center;
}
.sub-navbar {
@@ -141,7 +152,13 @@ aside {
text-align: right;
padding-right: 20px;
transition: 600ms ease position;
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
background: linear-gradient(
90deg,
rgba(32, 182, 249, 1) 0%,
rgba(32, 182, 249, 1) 0%,
rgba(33, 120, 241, 1) 100%,
rgba(33, 120, 241, 1) 100%
);
.subtitle {
font-size: 20px;
@@ -185,3 +202,21 @@ aside {
.multiselect--active {
z-index: 1000 !important;
}
.no-data-bg {
height: 240px;
background: url(../images/no-data-bg.png) 50% 100% / contain
no-repeat;
position: relative;
&::after {
content: '暂无数据';
position: absolute;
bottom: 12px;
left: 50%;
transform: translateX(-50%);
color: #ccc;
font-size: 18px;
letter-spacing: 1px;
}
}

View File

@@ -53,7 +53,18 @@
margin-left: 20px;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
.h1,
.h2,
.h3,
.h4,
.h5,
.h6,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
@@ -65,7 +76,8 @@
}
.el-dialog:not(.is-fullscreen) {
margin-top: 6vh !important;
// margin-top: 6vh !important;
margin-top: 12vh !important;
}
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
@@ -86,7 +98,8 @@
}
.el-table {
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
.el-table__header-wrapper,
.el-table__fixed-header-wrapper {
th {
word-break: break-word;
background-color: #f8f8f9;
@@ -96,7 +109,7 @@
}
}
.el-table__body-wrapper {
.el-button [class*="el-icon-"] + span {
.el-button [class*='el-icon-'] + span {
margin-left: 1px;
}
}
@@ -108,7 +121,7 @@
color: #6379bb;
border-bottom: 1px solid #ddd;
margin: 8px 10px 25px 10px;
padding-bottom:5px
padding-bottom: 5px;
}
/** 表格布局 **/
@@ -124,7 +137,7 @@
.tree-border {
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #FFFFFF none;
background: #ffffff none;
border-radius: 4px;
}
@@ -149,12 +162,14 @@
}
/** 表格更多操作下拉样式 */
.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
.el-table .el-dropdown-link,
.el-table .el-dropdown-selfdefine {
cursor: pointer;
margin-left: 5px;
}
.el-table .el-dropdown, .el-icon-arrow-down {
.el-table .el-dropdown,
.el-icon-arrow-down {
font-size: 12px;
}
@@ -209,22 +224,22 @@
/* button color */
.el-button--cyan.is-active,
.el-button--cyan:active {
background: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
background: #20b2aa;
border-color: #20b2aa;
color: #ffffff;
}
.el-button--cyan:focus,
.el-button--cyan:hover {
background: #48D1CC;
border-color: #48D1CC;
color: #FFFFFF;
background: #48d1cc;
border-color: #48d1cc;
color: #ffffff;
}
.el-button--cyan {
background-color: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
background-color: #20b2aa;
border-color: #20b2aa;
color: #ffffff;
}
/* text color */
@@ -279,7 +294,7 @@
/* 拖拽列样式 */
.sortable-ghost {
opacity: .8;
opacity: 0.8;
color: #fff !important;
background: #42b983 !important;
}

View File

@@ -10,6 +10,8 @@
ref="form"
:model="form"
:label-width="`${labelWidth}px`"
:size="size"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
@@ -46,23 +48,6 @@
:placeholder="`请选择${col.label}`"
value-format="timestamp"
v-bind="col.bind"></el-date-picker>
<el-upload
class="upload-in-dialog"
v-if="col.upload"
:file-list="uploadedFileList"
:action="col.url"
:on-success="handleUploadSuccess"
v-bind="col.bind">
<el-button
size="small"
type="primary"
:disabled="col.bind?.disabled || false">
点击上传
</el-button>
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips">
{{ col.uploadTips || '只能上传jpg/png文件大小不超过2MB' }}
</div>
</el-upload>
<el-switch
v-if="col.switch"
v-model="form[col.prop]"
@@ -74,6 +59,43 @@
:key="col.key"
:is="col.subcomponent"
:inlineStyle="col.style"></component>
<div
class="upload-area"
:class="uploadOpen ? '' : 'height-48'"
ref="uploadArea"
v-if="col.upload">
<span class="close-icon" :class="uploadOpen ? 'open' : ''">
<el-button
type="text"
icon="el-icon-arrow-right"
@click="handleFilesOpen" />
</span>
<!-- :file-list="uploadedFileList" -->
<el-upload
class="upload-in-dialog"
v-if="col.upload"
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
icon="el-icon-upload2"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
v-bind="col.bind">
<el-button size="mini" :disabled="col.bind?.disabled || false">
上传文件
</el-button>
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips">
{{ col.uploadTips || '只能上传jpg/png文件, 大小不超过2MB' }}
</div>
</el-upload>
<uploadedFile
class="file"
v-for="file in form[col.prop] || []"
:file="file"
@delete="handleDeleteFile(file)" />
</div>
</el-form-item>
</el-col>
</el-row>
@@ -81,6 +103,9 @@
</template>
<script>
import { getAccessToken } from '@/utils/auth';
import tupleImg from '@/assets/images/tuple.png';
/**
* 找到最长的label
* @param {*} options
@@ -89,6 +114,8 @@ function findMaxLabelWidth(rows) {
let max = 0;
rows.forEach((row) => {
row.forEach((opt) => {
// debugger;
if (!opt.label) return 0;
if (opt.label.length > max) {
max = opt.label.length;
}
@@ -97,6 +124,48 @@ function findMaxLabelWidth(rows) {
return max;
}
const uploadedFile = {
name: 'UploadedFile',
props: ['file'],
data() {
return {};
},
methods: {
handleDelete() {
console.log('emit delete event')
this.$emit('delete', this.file);
},
},
mounted() {},
render: function (h) {
return (
<div
title={this.file.fileName}
style={{
background: `url(${tupleImg}) no-repeat`,
backgroundSize: '14px',
backgroundPosition: '0 55%',
paddingLeft: '20px',
paddingRight: '24px',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
cursor: 'pointer',
display: 'inline-block',
}}>
{this.file.fileName}
<el-button
type="text"
icon="el-icon-close"
style="float: right; position: relative; top: 2px; left: 8px; z-index: 100"
class="dialog__upload_component__close"
onClick={this.handleDelete}
/>
</div>
);
},
};
export default {
name: 'DialogForm',
model: {
@@ -104,7 +173,7 @@ export default {
event: 'update',
},
emits: ['update'],
components: {},
components: { uploadedFile },
props: {
rows: {
type: Array,
@@ -114,13 +183,29 @@ export default {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'right',
},
size: {
type: String,
default: '',
},
},
data() {
return {
uploadOpen: false,
form: {},
formLoading: true,
optionListOf: {},
uploadedFileList: [],
dataLoaded: false,
uploadHeaders: { Authorization: 'Bearer ' + getAccessToken() },
uploadUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 上传有关的headersurl都是固定的
};
},
computed: {
@@ -130,16 +215,6 @@ export default {
return max * 20;
// return max * 20 + 'px';
},
form: {
get() {
// if (this.dataLoaded) return this.dataForm;
// else return {}
return this.dataForm;
},
set(val) {
console.log('set form', val);
},
},
},
watch: {
rows: {
@@ -152,6 +227,13 @@ export default {
deep: true,
immediate: false,
},
dataForm: {
handler(val) {
this.form = JSON.parse(JSON.stringify(val));
},
deep: true,
immediate: true,
},
},
mounted() {
// 处理 options
@@ -267,23 +349,27 @@ export default {
beforeUpload() {},
// 上传前的验证规则可通过 bind 属性传入
handleUploadSuccess(response, file, fileList) {
console.log(
'[dialogForm:handleUploadSuccess]',
response,
file,
fileList,
this.form
);
// 保存原始文件名
if ('fileNames' in this.form) this.form.fileNames.push(file.name);
// 保存完整地址
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.form.files.push({
fileName: file.name,
fileUrl: response.data,
fileType: 2,
});
this.$modal.msgSuccess('上传成功');
this.$emit('update', this.form);
},
getFileName(fileUrl) {
return fileUrl.split('/').pop();
},
handleFilesOpen() {
this.uploadOpen = !this.uploadOpen;
},
handleDeleteFile(file) {
this.form.files = this.form.files.filter(item => item.fileUrl != file.fileUrl);
this.$emit('update', this.form);
},
},
};
</script>
@@ -293,4 +379,52 @@ export default {
.el-select {
width: 100%;
}
.upload-area {
// background: #ccc;
// display: grid;
// grid-auto-rows: 34px;
// grid-template-columns: repeat(6, minmax(32px, max-content));
// gap: 8px;
// align-items: center;
position: relative;
overflow: hidden;
transition: height 0.3s ease-out;
}
.upload-in-dialog {
// display: inline-block;
margin-right: 24px;
// background: #ccc;
position: relative;
// top: -13px;
float: left;
}
.close-icon {
// background: #ccc;
position: absolute;
top: 0;
right: 12px;
z-index: 100;
transition: transform 0.3s ease-out;
}
.close-icon.open {
transform: rotateZ(90deg);
}
</style>
<style>
.dialog__upload_component__close {
color: #ccc;
}
.dialog__upload_component__close:hover {
/* color: #777; */
color: red;
}
.height-48 {
height: 35px !important;
}
</style>

View File

@@ -32,7 +32,7 @@ export default {
min-height: calc(100vh - 56px);
min-width: calc(100vh - 280px);
position: relative;
overflow: hidden;
overflow: visible;
margin: 8px 14px 0px 16px;
border-radius: 8px;
background-color: #fff;

View File

@@ -94,7 +94,7 @@ export default {
async logout() {
this.$modal.confirm('确定注销并退出系统吗?', '提示').then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = getPath('/index');
location.href = getPath('/');
})
}).catch(() => {});
}

View File

@@ -52,6 +52,13 @@ Vue.prototype.divide = divide;
Vue.prototype.tableHeight = function(n) {
return window.innerHeight - n
}
Vue.prototype.searchBarWidth = function(name, num) {
if (document.getElementById(name) && document.getElementById(name).offsetWidth < num) {
return true
} else {
return false
}
}
// 全局组件挂载
Vue.component('DictTag', DictTag);

View File

@@ -53,6 +53,9 @@ export default {
case 'delete':
this.handleDelete(data);
break;
case 'detail':
this.handleDetail(data);
break;
}
},
// 处理搜索栏按钮

View File

@@ -65,16 +65,22 @@ export const constantRoutes = [
hidden: true
},
{
path: '',
path: '/print-design',
component: (resolve) => require(['@/views/print/design'], resolve),
hidden: true
},
{
path: '/',
component: Layout,
redirect: 'index',
children: [{
path: 'index',
component: (resolve) => require(['@/views/index'], resolve),
name: '首页',
meta: {title: '首页', icon: 'dashboard', affix: true}
}
]
redirect: 'core/base/factory',
// children: [{
// path: 'index',
// redirect: 'core/base/factory',
// component: (resolve) => require(['@/views/index'], resolve),
// name: '首页',
// meta: { title: '首页', icon: 'dashboard', affix: true }
// }
// ]
},
{
path: '/user',

View File

@@ -1,3 +1,5 @@
import moment from 'moment';
/**
* 用于动态表结构的 tableProps 生成
* @param {*} nameData
@@ -16,10 +18,9 @@ export function handleNameData(nameData) {
function step1(tree1) {
return Array.from(new Set(tree1.map((item) => item.name)))
.sort()
.map((item) => ({
prop: item,
label: item,
align: 'center',
.map((time) => ({
prop: time,
label: moment(time).format('YYYY-MM-DD HH:mm:ss'),
children: [],
}));
}
@@ -33,7 +34,6 @@ function step2(firstTierProps, tree2) {
parent.children.push({
label: nd.name,
prop: `${parent.prop}-${nd.name}`,
align: 'center',
});
}
});

View File

@@ -0,0 +1,74 @@
<!--
filename: index.vue
author: liubin
date: 2023-10-11 09:32:04
description: 设备看板
-->
<template>
<div ref="dataBoard" class=""></div>
</template>
<script>
export default {
name: 'DataBoard',
components: {},
props: {},
data() {
return {
appMain: null, // dom
parentStyle: {
margin: '8px 14px 0px 16px',
minHeight: 'calc(100vh - 120px - 8px)',
}, // object
mainFooter: null, // dom
};
},
mounted() {
this.$nextTick(() => {
this.modify();
});
},
activated() {
this.modify();
},
deactivated() {
this.recover();
},
beforeDestroy() {
this.recover();
},
methods: {
modify() {
// 在这个页面临时修改下父类的margin结束时需还原
this.appMain = document.querySelector('.app-main');
// this.appMain.style.minHeight = 'calc(100vh - 90px)';
this.appMain.style.margin = 0;
// 在这个页面临时删除 main-footer 元素,结束时需还原
// this.mainFooter = document.querySelector('.main-footer').cloneNode(true);
// document.querySelector('.main-footer').remove();
this.$refs.dataBoard.classList.add('data-board');
},
recover() {
this.$refs.dataBoard.classList.remove('data-board');
this.$nextTick(() => {
this.appMain.style.margin = this.parentStyle.margin;
// this.appMain.style.minHeight = this.parentStyle.minHeight;
// this.appMain.insertAdjacentElement('afterend', this.mainFooter);
});
},
},
};
</script>
<style scoped lang="scss">
.data-board {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('../../../assets/images/DataBoard.png') 100% 100% / contain
no-repeat;
}
</style>

View File

@@ -0,0 +1,482 @@
<!--
filename: EquipmentDrawer.vue
author: liubin
date: 2023-08-22 14:38:56
description:
-->
<template>
<el-drawer
:visible="visible"
:show-close="false"
:wrapper-closable="false"
class="drawer"
custom-class="mes-drawer"
size="60%"
@closed="$emit('destroy')">
<SmallTitle slot="title">
{{
mode.includes('detail')
? '详情'
: mode.includes('edit')
? '编辑'
: '新增'
}}
</SmallTitle>
<div class="drawer-body flex">
<div class="drawer-body__content">
<section v-for="(section, index) in sections" :key="section.key">
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
<div class="form-part" v-if="section.key == 'base'">
<el-skeleton v-if="!showForm" animated />
<BaseInfoForm
key="drawer-dialog-form"
v-if="showForm"
ref="form"
:disabled="true"
:dataForm="form"
:rows="formRows" />
</div>
<div v-if="section.key == 'attrs'" style="margin-top: 12px">
<base-table
v-loading="attrListLoading"
:table-props="section.props"
:page="attrQuery?.params.pageNo || 1"
:limit="attrQuery?.params.pageSize || 10"
:table-data="list"
:add-button-show="mode.includes('detail') ? null : '添加属性'"
@emitButtonClick="handleAddAttr"
@emitFun="handleEmitFun">
<method-btn
v-if="section.tableBtn"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="attrQuery.params.pageNo"
:limit.sync="attrQuery.params.pageSize"
@pagination="getAttrList" />
</div>
</section>
</div>
<div class="drawer-body__footer">
<el-button style="" @click="handleCancel">取消</el-button>
<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
编辑
</el-button>
<el-button v-else type="primary" @click="handleCancel">确定</el-button>
<!-- sections的第二项必须是 属性列表 -->
<!-- <el-button
v-if="sections[1].allowAdd"
type="primary"
@click="handleAddAttr">
添加属性
</el-button> -->
</div>
</div>
<!-- 属性对话框 -->
<base-dialog
v-if="sections[1].allowAdd"
:dialogTitle="attrTitle"
:dialogVisible="attrFormVisible"
width="45%"
:append-to-body="true"
custom-class="baseDialog"
@close="closeAttrForm"
@cancel="closeAttrForm"
@confirm="submitAttrForm">
<DialogForm
v-if="attrFormVisible"
ref="attrForm"
:disabled="mode.includes('detail')"
v-model="attrForm"
:rows="attrRows" />
</base-dialog>
</el-drawer>
</template>
<script>
import BaseInfoForm from '@/components/DialogForm';
import DialogForm from './dialogForm';
const SmallTitle = {
name: 'SmallTitle',
props: ['size'],
data() {
return {};
},
methods: {},
render: function (h) {
return h(
'span',
{
class: 'small-title',
style: {
fontSize: '18px',
lineHeight:
this.size == 'lg' ? '24px' : this.size == 'sm' ? '18px' : '20px',
fontWeight: 500,
fontFamily: '微软雅黑, Microsoft YaHei, Arial, Helvetica, sans-serif',
},
},
this.$slots.default
);
},
};
export default {
components: { SmallTitle, DialogForm, BaseInfoForm },
props: ['sections', 'defaultMode', 'dataId'], // dataId 作为一个通用的存放id的字段
data() {
return {
mode: '',
visible: false,
showForm: false,
total: 0,
form: {},
list: [],
attrTitle: '',
attrForm: {
id: null,
equipmentGroupId: '',
code: '',
type: '',
grade: '',
alarmCode: '',
alarmContent: '',
plcParamName: '',
},
attrFormVisible: false,
attrRows: [
[
{
input: true,
label: '报警编码', // 自动生成
prop: 'code',
url: '/base/equipment-group-alarm/getCode',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
select: true,
label: '报警类型', // 固定选项
prop: 'type',
options: [
{ label: '布尔型', value: 2 },
{ label: '字符型', value: 1 },
],
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
select: true,
label: '报警级别', // 字典
prop: 'grade',
options: this.getDictDatas(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{
input: true,
label: '设备报警编码', // 对应到设备实际的报警编码
prop: 'alarmCode',
},
],
[
{
input: true,
label: '参数列名', // 在实时数据库的列名
prop: 'plcParamName',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
input: true,
label: '报警内容',
prop: 'alarmContent',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
],
attrQuery: {
params: {
pageNo: 1,
pageSize: 10,
},
}, // 属性列表的请求
infoQuery: null, // 基本信息的请求
attrFormSubmitting: false,
attrListLoading: false,
};
},
computed: {
formRows() {
return this.sections[0].rows.map((row) => {
return row.map((col) => {
return {
...col,
bind: {
// 详情 模式下,禁用各种输入
// disabled: this.mode == 'detail',
disabled: true,
},
};
});
});
},
tableBtn() {
return this.mode == 'detail' ? [] : this.sections[1].tableBtn;
},
},
mounted() {
this.mode = this.defaultMode || 'detail';
for (const section of this.sections) {
// 请求具体信息
if ('url' in section) {
const query = {
url: section.url,
method: section.method || 'get',
params: section.queryParams || null,
data: section.data || null,
};
// debugger;
this.$axios(query).then(({ data }) => {
if (section.key == 'base') {
this.form = data;
this.showForm = true;
this.infoQuery = query;
} else if (section.key == 'attrs') {
this.attrQuery = query;
this.list = data.list;
this.total = data.total;
}
});
}
}
},
methods: {
handleTableBtnClick({ type, data }) {
switch (type) {
case 'edit':
this.handleEditAttr(data.id);
break;
case 'delete':
this.handleDeleteAttr(data.id);
break;
}
},
handleEmitFun(val) {
console.log('handleEmitFun', val);
},
init() {
this.visible = true;
},
async getAttrList() {
this.attrListLoading = true;
const res = await this.$axios(this.attrQuery);
if (res.code == 0) {
this.list = res.data.list;
this.total = res.data.total;
}
this.attrListLoading = false;
},
// 保存表单
handleSave() {
this.$refs['form'][0].validate(async (valid) => {
if (valid) {
const isEdit = this.mode == 'edit';
await this.$axios({
url: this.sections[0][isEdit ? 'urlUpdate' : 'urlCreate'],
method: isEdit ? 'put' : 'post',
data: this.form,
});
this.$modal.msgSuccess(`${isEdit ? '更新' : '创建'}成功`);
this.visible = false;
this.$emit('refreshDataList');
}
});
},
handleCancel() {
this.visible = false;
},
// 开启编辑
toggleEdit() {
this.mode = 'edit';
},
// 新增属性
handleAddAttr() {
if (!this.dataId) return this.$message.error('请先创建设备分组信息');
this.attrForm = {
id: null,
equipmentGroupId: this.dataId,
code: '',
type: '',
grade: '',
alarmCode: '',
alarmContent: '',
plcParamName: '',
};
this.attrTitle = '添加设备分组报警';
this.attrFormVisible = true;
},
// 编辑属性
async handleEditAttr(attrId) {
const res = await this.$axios({
url: this.sections[1].urlDetail,
method: 'get',
params: { id: attrId },
});
if (res.code == 0) {
this.attrForm = res.data;
this.attrTitle = '编辑设备分组报警';
this.attrFormVisible = true;
}
},
// 删除属性
handleDeleteAttr(attrId) {
this.$confirm('确定删除该分组报警?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
const res = await this.$axios({
url: this.sections[1].urlDelete,
method: 'delete',
params: { id: attrId },
});
if (res.code == 0) {
this.$message({
message: '删除成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
})
.catch(() => {});
},
// 提交属性表
async submitAttrForm() {
this.$refs['attrForm'].validate((valid) => {
if (!valid) {
return;
}
});
console.log('this.attrform', this.attrForm);
const isEdit = this.attrForm.id != null;
this.attrFormSubmitting = true;
const res = await this.$axios({
url: isEdit ? this.sections[1].urlUpdate : this.sections[1].urlCreate,
method: isEdit ? 'put' : 'post',
data: this.attrForm,
});
if (res.code == 0) {
this.closeAttrForm();
this.$message({
message: `${isEdit ? '更新' : '创建'}成功`,
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
this.attrFormSubmitting = false;
},
closeAttrForm() {
this.attrFormVisible = false;
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(`确定删除该报警?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
deleteProductAttr(raw.data.id).then(({ data }) => {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getList();
},
});
});
})
.catch(() => {});
} else {
this.addNew(raw.data.id);
}
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 0px;
}
.small-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 22px;
border-radius: 1px;
margin-right: 8px;
background-color: #0b58ff;
}
.drawer-body {
display: flex;
flex-direction: column;
height: 100%;
}
.drawer-body__content {
flex: 1;
/* background: #eee; */
padding: 20px 30px;
overflow-y: auto;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@@ -0,0 +1,186 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-09-11 15:55:13
description: DialogForm for equipmentBindSection only
-->
<template>
<el-form
ref="form"
:model="dataForm"
label-width="100px"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.code"
@change="$emit('update', dataForm)"
placeholder="请输入工段排序" />
</el-form-item>
<!--
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.code"
placeholder="请选择产线"
@change="handleProductlineChange">
<el-option
v-for="opt in productionLineList"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item> -->
</el-col>
<el-col :span="12">
<el-form-item
label="报警类型"
prop="type"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
:disabled="disabled"
v-model="dataForm.type"
placeholder="请选择报警类型"
@change="handleTypeChange">
<el-option
v-for="opt in [
{ label: '布尔型', value: 2 },
{ label: '字符型', value: 1 },
]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警级别"
prop="grade"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
:disabled="disabled"
v-model="dataForm.grade"
placeholder="请选择报警级别"
@change="$emit('update', dataForm)">
<el-option
v-for="opt in getDictDatas(DICT_TYPE.EQU_ALARM_LEVEL)"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="+dataForm.type == 1"
label="设备报警编码"
prop="alarmCode">
<el-input
:disabled="disabled"
v-model="dataForm.alarmCode"
@change="$emit('update', dataForm)"
placeholder="请输入设备报警编码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="参数列名"
prop="plcParamName"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.plcParamName"
placeholder="请输入参数列名"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="报警内容"
prop="alarmContent"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.alarmContent"
placeholder="请输入报警内容"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
formLoading: true,
};
},
mounted() {
this.getCode('/base/equipment-group-alarm/getCode').then((code) => {
this.formLoading = false;
this.$emit('update', {
...this.dataForm,
code,
});
});
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
async handleTypeChange(id) {
this.dataForm.alarmCode = '';
this.$emit('update', this.dataForm);
},
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -39,6 +40,57 @@
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
</base-dialog>
<!-- 抽屉 详情 -->
<BasicDrawer
v-if="editVisible"
ref="drawer"
:default-mode="editMode"
:data-id="alarmForm.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: drawerBaseInfoRows,
url: '/base/equipment-group/get',
urlUpdate: '/base/equipment-group/update',
urlCreate: '/base/equipment-group/create',
queryParams: { id: alarmForm.id },
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/equipment-group-alarm/page',
urlCreate: '/base/equipment-group-alarm/create',
urlUpdate: '/base/equipment-group-alarm/update',
urlDelete: '/base/equipment-group-alarm/delete',
urlDetail: '/base/equipment-group-alarm/get',
queryParams: {
equipmentGroupId: alarmForm.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:equipment-group:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:equipment-group:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="editVisible = false"
@destroy="editVisible = false" />
</div>
</template>
@@ -54,16 +106,24 @@ import {
import { getEquipmentGroupPage } from '@/api/base/equipmentGroup';
import moment from 'moment';
import { publicFormatter } from '@/utils/dict';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import BasicDrawer from './components/BasicDrawer.vue';
export default {
name: 'EquipmentBindGroup',
components: {},
components: { BasicDrawer },
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['groupId', 'equipmentName'],
tableBtn: [
this.$auth.hasPermi('base:equipment-bind-group:update')
? {
type: 'detail',
btnName: '查看报警',
}
: undefined,
this.$auth.hasPermi('base:equipment-bind-group:update')
? {
type: 'edit',
@@ -85,35 +145,34 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'equipmentName', label: '设备', align: 'center' },
{ prop: 'groupName', label: '分组', align: 'center' },
{
_action: 'equipment-bind-group-show-alert',
label: '分组报警',
align: 'center',
subcomponent: {
props: ['injectData'],
render: function (h) {
const _this = this;
return h(
'el-button',
{
props: { type: 'text', size: 'mini' },
on: {
click: function () {
console.log('inejctdata', _this.injectData);
_this.$emit('emitData', {
action: _this.injectData._action,
value: _this.injectData,
});
},
},
},
'查看报警'
);
},
},
},
{ prop: 'equipmentName', label: '设备' },
{ prop: 'groupName', label: '分组' },
// {
// _action: 'equipment-bind-group-show-alert',
// label: '分组报警',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData._action,
// value: _this.injectData,
// });
// },
// },
// },
// '查看报警'
// );
// },
// },
// },
],
searchBarFormConfig: [
{
@@ -162,6 +221,9 @@ export default {
label: '设备',
url: '/base/equipment/page?pageNo=1&pageSize=100',
prop: 'equipmentId',
bind: {
filterable: true,
},
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
@@ -173,6 +235,9 @@ export default {
// depends: '__product_line', // 依赖产线获取数据
// depends: 'productionLineId',
prop: 'groupId',
bind: {
filterable: true,
},
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
@@ -190,6 +255,59 @@ export default {
form: {},
// 表单校验
rules: {},
//
alarmForm: {
id: undefined,
equipmentGroupCode: undefined,
equipmentGroupName: undefined,
},
editVisible: false,
editMode: '',
drawerBaseInfoRows: [
[
{
input: true,
label: '设备分组名称',
prop: 'name',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: this.editMode == 'detail', // some condition, like detail mode...
// }
},
{
input: true,
label: '设备分组编码',
prop: 'code',
// url: '/base/equipment/getCode',
},
],
],
drawerListProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ width: 240, prop: 'code', label: '报警编码' },
{
width: 100,
prop: 'type',
label: '报警类型',
filter: (val) =>
val != null ? ['-', '字符型', '布尔型', '-'][val] : '-',
},
{
width: 90,
prop: 'grade',
label: '报警级别',
filter: publicFormatter(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{ width: 180, prop: 'alarmCode', label: '设备报警编码' },
{ width: 128, prop: 'plcParamName', label: '参数列名' },
{ width: 128, prop: 'alarmContent', label: '报警内容' },
],
};
},
created() {
@@ -223,7 +341,6 @@ export default {
/** 查询列表 */
getList() {
this.loading = true;
_// 执行查询
getEquipmentBindGroupPage(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
@@ -293,11 +410,25 @@ export default {
});
});
},
// 查看报警
handleDetail(row) {
const { equipmentId, equipmentName, groupCode, groupId, groupName, id } =
row;
// 打开抽屉
this.editMode = 'detail';
this.alarmForm.id = groupId;
this.alarmForm.equipmentGroupCode = groupCode;
this.alarmForm.equipmentGroupName = groupName;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备与分组绑定编号为"' + id + '"的数据项?')
.confirm('是否确认删除分组绑定?')
.then(function () {
return deleteEquipmentBindGroup(id);
})

View File

@@ -20,6 +20,7 @@
<el-select
v-model="dataForm.productionLineId"
placeholder="请选择产线"
filterable
@change="handleProductlineChange">
<el-option
v-for="opt in productionLineList"
@@ -37,6 +38,7 @@
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.workshopSectionId"
filterable
placeholder="请选择工段"
@change="$emit('update', dataForm)">
<el-option
@@ -56,6 +58,7 @@
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.equipmentId"
filterable
placeholder="请选择设备"
@change="$emit('update', dataForm)">
<el-option
@@ -69,8 +72,11 @@
<el-col :span="12">
<el-form-item label="工段排序" prop="sort">
<el-input
<el-input-number
v-model="dataForm.sort"
filterable
min="0"
max="100"
@change="$emit('update', dataForm)"
placeholder="请输入工段排序" />
</el-form-item>

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -83,28 +84,26 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'productionLine', label: '产线名称', align: 'center' },
{ prop: 'workshopSection', label: '工段名称', align: 'center' },
{ prop: 'equipment', label: '设备名称', align: 'center' },
{ prop: 'sort', label: '工段中排序', align: 'center' },
{ prop: 'productionLine', label: '产线名称' },
{ prop: 'workshopSection', label: '工段名称' },
{ prop: 'equipment', label: '设备名称' },
{ prop: 'sort', label: '工段中排序' },
{
prop: 'lineDataType',
label: '产线数据类型',
align: 'center',
filter: (val) =>
val != null ? ['无类型', '进口计数', '出口计数'][val] : '-',
},
{
prop: 'sectionDataType',
label: '工段数据类型',
align: 'center',
filter: (val) =>
val != null ? ['无类型', '进口计数', '出口计数'][val] : '-',
},
// {
// action: 'show-alert',
// label: '报警',
// align: 'center',
// ,
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
@@ -135,6 +134,8 @@ export default {
label: '工段',
placeholder: '请选择工段',
param: 'workshopSectionId',
selectOptions: [],
filterable: true
},
{
type: 'input',
@@ -240,8 +241,24 @@ export default {
},
created() {
this.getList();
this.initWorksection();
},
methods: {
/** 准备工段数据 */
async initWorksection() {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 查询列表 */
getList() {
this.loading = true;
@@ -324,7 +341,7 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除工段设备绑定编号为"' + id + '"的数据项?')
.confirm('是否确认删除工段设备绑定设备名称为"' + row.equipment + '"的数据项?')
.then(function () {
return deleteEquipmentBindSection(id);
})

View File

@@ -0,0 +1,481 @@
<!--
filename: EquipmentDrawer.vue
author: liubin
date: 2023-08-22 14:38:56
description:
-->
<template>
<el-drawer
:visible="visible"
:show-close="false"
:wrapper-closable="false"
class="drawer"
custom-class="mes-drawer"
size="60%"
@closed="$emit('destroy')">
<SmallTitle slot="title">
{{
mode.includes('detail')
? '详情'
: mode.includes('edit')
? '编辑'
: '新增'
}}
</SmallTitle>
<div class="drawer-body flex">
<div class="drawer-body__content">
<section v-for="(section, index) in sections" :key="section.key">
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
<div class="form-part" v-if="section.key == 'base'">
<el-skeleton v-if="!showForm" animated />
<BaseInfoForm
key="drawer-dialog-form"
v-if="showForm"
ref="form"
:disabled="mode.includes('detail')"
:dataForm="form"
:rows="formRows" />
</div>
<div v-if="section.key == 'attrs'" style="margin-top: 12px">
<base-table
v-loading="attrListLoading"
:table-props="section.props"
:page="attrQuery?.params.pageNo || 1"
:limit="attrQuery?.params.pageSize || 10"
:table-data="list"
:add-button-show="mode.includes('detail') ? null : '添加属性'"
@emitButtonClick="handleAddAttr"
@emitFun="handleEmitFun">
<method-btn
v-if="section.tableBtn"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="attrQuery.params.pageNo"
:limit.sync="attrQuery.params.pageSize"
@pagination="getAttrList" />
</div>
</section>
</div>
<div class="drawer-body__footer">
<el-button style="" @click="handleCancel">取消</el-button>
<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
编辑
</el-button>
<el-button v-else type="primary" @click="handleCancel">确定</el-button>
<!-- sections的第二项必须是 属性列表 -->
<!-- <el-button
v-if="sections[1].allowAdd"
type="primary"
@click="handleAddAttr">
添加属性
</el-button> -->
</div>
</div>
<!-- 属性对话框 -->
<base-dialog
v-if="sections[1].allowAdd"
:dialogTitle="attrTitle"
:dialogVisible="attrFormVisible"
width="45%"
:append-to-body="true"
custom-class="baseDialog"
@close="closeAttrForm"
@cancel="closeAttrForm"
@confirm="submitAttrForm">
<DialogForm
v-if="attrFormVisible"
ref="attrForm"
:disabled="mode.includes('detail')"
v-model="attrForm"
:rows="attrRows" />
</base-dialog>
</el-drawer>
</template>
<script>
import BaseInfoForm from '@/components/DialogForm';
import DialogForm from './dialogForm';
const SmallTitle = {
name: 'SmallTitle',
props: ['size'],
data() {
return {};
},
methods: {},
render: function (h) {
return h(
'span',
{
class: 'small-title',
style: {
fontSize: '18px',
lineHeight:
this.size == 'lg' ? '24px' : this.size == 'sm' ? '18px' : '20px',
fontWeight: 500,
fontFamily: '微软雅黑, Microsoft YaHei, Arial, Helvetica, sans-serif',
},
},
this.$slots.default
);
},
};
export default {
components: { SmallTitle, DialogForm, BaseInfoForm },
props: ['sections', 'defaultMode', 'dataId'], // dataId 作为一个通用的存放id的字段
data() {
return {
mode: '',
visible: false,
showForm: false,
total: 0,
form: {},
list: [],
attrTitle: '',
attrForm: {
id: null,
equipmentGroupId: '',
code: '',
type: '',
grade: '',
alarmCode: '',
alarmContent: '',
plcParamName: '',
},
attrFormVisible: false,
attrRows: [
[
{
input: true,
label: '报警编码', // 自动生成
prop: 'code',
url: '/base/equipment-group-alarm/getCode',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
select: true,
label: '报警类型', // 固定选项
prop: 'type',
options: [
{ label: '布尔型', value: 2 },
{ label: '字符型', value: 1 },
],
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
select: true,
label: '报警级别', // 字典
prop: 'grade',
options: this.getDictDatas(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{
input: true,
label: '设备报警编码', // 对应到设备实际的报警编码
prop: 'alarmCode',
},
],
[
{
input: true,
label: '参数列名', // 在实时数据库的列名
prop: 'plcParamName',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
input: true,
label: '报警内容',
prop: 'alarmContent',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
],
attrQuery: {
params: {
pageNo: 1,
pageSize: 10,
},
}, // 属性列表的请求
infoQuery: null, // 基本信息的请求
attrFormSubmitting: false,
attrListLoading: false,
};
},
computed: {
formRows() {
return this.sections[0].rows.map((row) => {
return row.map((col) => {
return {
...col,
bind: {
// 详情 模式下,禁用各种输入
// disabled: this.mode == 'detail',
disabled: true
},
};
});
});
},
tableBtn() {
return this.mode == 'detail' ? [] : this.sections[1].tableBtn;
},
},
mounted() {
this.mode = this.defaultMode || 'detail';
for (const section of this.sections) {
// 请求具体信息
if ('url' in section) {
const query = {
url: section.url,
method: section.method || 'get',
params: section.queryParams || null,
data: section.data || null,
};
// debugger;
this.$axios(query).then(({ data }) => {
if (section.key == 'base') {
this.form = data;
this.showForm = true;
this.infoQuery = query;
} else if (section.key == 'attrs') {
this.attrQuery = query;
this.list = data.list;
this.total = data.total;
}
});
}
}
},
methods: {
handleTableBtnClick({ type, data }) {
switch (type) {
case 'edit':
this.handleEditAttr(data.id);
break;
case 'delete':
this.handleDeleteAttr(data.id);
break;
}
},
handleEmitFun(val) {
console.log('handleEmitFun', val);
},
init() {
this.visible = true;
},
async getAttrList() {
this.attrListLoading = true;
const res = await this.$axios(this.attrQuery);
if (res.code == 0) {
this.list = res.data.list;
this.total = res.data.total;
}
this.attrListLoading = false;
},
// 保存表单
handleSave() {
this.$refs['form'][0].validate(async (valid) => {
if (valid) {
const isEdit = this.mode == 'edit';
await this.$axios({
url: this.sections[0][isEdit ? 'urlUpdate' : 'urlCreate'],
method: isEdit ? 'put' : 'post',
data: this.form,
});
this.$modal.msgSuccess(`${isEdit ? '更新' : '创建'}成功`);
this.visible = false;
this.$emit('refreshDataList');
}
});
},
handleCancel() {
this.visible = false;
},
// 开启编辑
toggleEdit() {
this.mode = 'edit';
},
// 新增属性
handleAddAttr() {
if (!this.dataId) return this.$message.error('请先创建设备分组信息');
this.attrForm = {
id: null,
equipmentGroupId: this.dataId,
code: '',
type: '',
grade: '',
alarmCode: '',
alarmContent: '',
plcParamName: '',
};
this.attrTitle = '添加设备分组报警';
this.attrFormVisible = true;
},
// 编辑属性
async handleEditAttr(attrId) {
const res = await this.$axios({
url: this.sections[1].urlDetail,
method: 'get',
params: { id: attrId },
});
if (res.code == 0) {
this.attrForm = res.data;
this.attrTitle = '编辑设备分组报警';
this.attrFormVisible = true;
}
},
// 删除属性
handleDeleteAttr(attrId) {
this.$confirm('确定删除该分组报警?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
const res = await this.$axios({
url: this.sections[1].urlDelete,
method: 'delete',
params: { id: attrId },
});
if (res.code == 0) {
this.$message({
message: '删除成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
})
.catch(() => {});
},
// 提交属性表
async submitAttrForm() {
this.$refs['attrForm'].validate((valid) => {
if (!valid) {
return;
}
});
const isEdit = this.attrForm.id != null;
this.attrFormSubmitting = true;
const res = await this.$axios({
url: isEdit ? this.sections[1].urlUpdate : this.sections[1].urlCreate,
method: isEdit ? 'put' : 'post',
data: this.attrForm,
});
if (res.code == 0) {
this.closeAttrForm();
this.$message({
message: `${isEdit ? '更新' : '创建'}成功`,
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
this.attrFormSubmitting = false;
},
closeAttrForm() {
this.attrFormVisible = false;
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(`确定删除该报警?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
deleteProductAttr(raw.data.id).then(({ data }) => {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getList();
},
});
});
})
.catch(() => {});
} else {
this.addNew(raw.data.id);
}
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 0px;
}
.small-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 22px;
border-radius: 1px;
margin-right: 8px;
background-color: #0b58ff;
}
.drawer-body {
display: flex;
flex-direction: column;
height: 100%;
}
.drawer-body__content {
flex: 1;
/* background: #eee; */
padding: 20px 30px;
overflow-y: auto;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@@ -0,0 +1,187 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-09-11 15:55:13
description: DialogForm for equipmentBindSection only
-->
<template>
<el-form
ref="form"
:model="dataForm"
label-width="100px"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.code"
@change="$emit('update', dataForm)"
placeholder="请输入工段排序" />
</el-form-item>
<!--
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.code"
placeholder="请选择产线"
@change="handleProductlineChange">
<el-option
v-for="opt in productionLineList"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item> -->
</el-col>
<el-col :span="12">
<el-form-item
label="报警类型"
prop="type"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
:disabled="disabled"
v-model="dataForm.type"
placeholder="请选择报警类型"
@change="handleTypeChange">
<el-option
v-for="opt in [
{ label: '布尔型', value: 2 },
{ label: '字符型', value: 1 },
]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警级别"
prop="grade"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
:disabled="disabled"
v-model="dataForm.grade"
placeholder="请选择报警级别"
@change="$emit('update', dataForm)">
<el-option
v-for="opt in getDictDatas(DICT_TYPE.EQU_ALARM_LEVEL)"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="+dataForm.type == 1"
label="设备报警编码"
prop="alarmCode">
<el-input
:disabled="disabled"
v-model="dataForm.alarmCode"
@change="$emit('update', dataForm)"
placeholder="请输入设备报警编码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="参数列名"
prop="plcParamName"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.plcParamName"
placeholder="请输入参数列名"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="报警内容"
prop="alarmContent"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.alarmContent"
placeholder="请输入报警内容"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
formLoading: true,
};
},
mounted() {
this.getCode('/base/equipment-group-alarm/getCode').then((code) => {
this.formLoading = false;
this.$emit('update', {
...this.dataForm,
code,
});
});
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
async handleTypeChange(id) {
// debugger;
this.dataForm.alarmCode = '';
this.$emit('update', this.dataForm);
},
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -39,6 +40,57 @@
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
</base-dialog>
<!-- 抽屉 详情 -->
<BasicDrawer
v-if="editVisible"
ref="drawer"
:default-mode="editMode"
:data-id="alarmForm.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: drawerBaseInfoRows,
url: '/base/equipment-group/get',
urlUpdate: '/base/equipment-group/update',
urlCreate: '/base/equipment-group/create',
queryParams: { id: alarmForm.id },
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/equipment-group-alarm/page',
urlCreate: '/base/equipment-group-alarm/create',
urlUpdate: '/base/equipment-group-alarm/update',
urlDelete: '/base/equipment-group-alarm/delete',
urlDetail: '/base/equipment-group-alarm/get',
queryParams: {
equipmentGroupId: alarmForm.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:equipment-group:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:equipment-group:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="editVisible = false"
@destroy="editVisible = false" />
</div>
</template>
@@ -52,17 +104,27 @@ import {
exportEquipmentGroupExcel,
} from '@/api/base/equipmentGroup';
import moment from 'moment';
import { publicFormatter } from '@/utils/dict';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { getAccessToken } from '@/utils/auth';
// import { getAccessToken } from '@/utils/auth';
import BasicDrawer from './components/BasicDrawer.vue';
export default {
name: 'EquipmentGroup',
mixins: [basicPageMixin],
components: {},
components: { BasicDrawer },
data() {
return {
editVisible: false,
editMode: '',
searchBarKeys: ['name', 'code'],
tableBtn: [
this.$auth.hasPermi('base:equipment-group:update')
? {
type: 'detail',
btnName: '查看报警',
}
: undefined,
this.$auth.hasPermi('base:equipment-group:update')
? {
type: 'edit',
@@ -84,38 +146,87 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '设备分组名称', align: 'center' },
{ prop: 'code', label: '检测分组编码', align: 'center' },
{ prop: 'remark', label: '备注', align: 'center' },
{
_action: 'equipment-group-show-alert',
label: '报警',
align: 'center',
subcomponent: {
props: ['injectData'],
render: function (h) {
const _this = this;
return h(
'el-button',
{
props: { type: 'text', size: 'mini' },
on: {
click: function () {
console.log('inejctdata', _this.injectData);
_this.$emit('emitData', {
action: _this.injectData._action,
// value: _this.injectData.id,
value: _this.injectData,
});
},
},
},
'查看报警'
);
},
},
},
{ prop: 'name', label: '设备分组名称' },
{ prop: 'code', label: '设备分组编码' },
{ prop: 'remark', label: '备注' },
// {
// _action: 'equipment-group-show-alert',
// label: '报警',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData._action,
// // value: _this.injectData.id,
// value: _this.injectData,
// });
// },
// },
// },
// '查看报警'
// );
// },
// },
// },
],
drawerBaseInfoRows: [
[
{
input: true,
label: '设备分组名称',
prop: 'name',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: this.editMode == 'detail', // some condition, like detail mode...
// }
},
{
input: true,
label: '设备分组编码',
prop: 'code',
// url: '/base/equipment/getCode',
}
]
],
drawerListProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ width: 240, prop: 'code', label: '报警编码' },
{
width: 100,
prop: 'type',
label: '报警类型',
filter: (val) =>
val != null ? ['-', '字符型', '布尔型', '-'][val] : '-',
},
{
width: 90,
prop: 'grade',
label: '报警级别',
filter: publicFormatter(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{ width: 180, prop: 'alarmCode', label: '设备报警编码' },
{ width: 128, prop: 'plcParamName', label: '参数列名' },
{ width: 128, prop: 'alarmContent', label: '报警内容' },
],
alarmForm: {
id: undefined,
equipmentGroupCode: undefined,
equipmentGroupName: undefined,
},
searchBarFormConfig: [
{
type: 'input',
@@ -127,7 +238,7 @@ export default {
type: 'input',
label: '分组编码',
placeholder: '请输入设备分组编码',
param: 'codes',
param: 'code',
},
{
type: 'button',
@@ -172,6 +283,7 @@ export default {
label: '分组编码',
prop: 'code',
url: '/base/equipment-group/getCode',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
@@ -298,15 +410,25 @@ export default {
});
});
},
// 查看报警
handleDetail(row) {
// debugger;
const { id, code, name, createTime } = row;
// 打开抽屉
this.editMode = 'detail';
this.alarmForm.id = id;
this.alarmForm.equipmentGroupCode = code;
this.alarmForm.equipmentGroupName = name;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm(
'是否确认删除设备分组(用于同类型不同厂家的设备区分)编号为"' +
id +
'"的数据项?'
)
.confirm('是否确认删除设备分组 "' + row.name + '"?')
.then(function () {
return deleteEquipmentGroup(id);
})

View File

@@ -0,0 +1,187 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-09-11 15:55:13
description: DialogForm for equipmentBindSection only
-->
<template>
<el-form
ref="form"
:model="dataForm"
label-width="100px"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.code"
@change="$emit('update', dataForm)"
placeholder="请输入工段排序" />
</el-form-item>
<!--
<el-form-item
label="报警编码"
prop="code"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.code"
placeholder="请选择产线"
@change="handleProductlineChange">
<el-option
v-for="opt in productionLineList"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item> -->
</el-col>
<el-col :span="12">
<el-form-item
label="报警类型"
prop="type"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
v-model="dataForm.type"
:disabled="disabled"
placeholder="请选择报警类型"
@change="$emit('update', dataForm)">
<el-option
v-for="opt in [
{ label: '布尔型', value: 2 },
{ label: '字符型', value: 1 },
]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="报警级别"
prop="grade"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-select
:disabled="disabled"
v-model="dataForm.grade"
placeholder="请选择报警级别"
@change="$emit('update', dataForm)">
<el-option
v-for="opt in getDictDatas(DICT_TYPE.EQU_ALARM_LEVEL)"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="+dataForm.type == 1"
label="设备报警编码"
prop="alarmCode">
<el-input
:disabled="disabled"
v-model="dataForm.alarmCode"
@change="$emit('update', dataForm)"
placeholder="请输入设备报警编码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="参数列名"
prop="plcParamName"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.plcParamName"
placeholder="请输入参数列名"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="报警内容"
prop="alarmContent"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
:disabled="disabled"
v-model="dataForm.alarmContent"
placeholder="请输入报警内容"
@change="$emit('update', dataForm)"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
formLoading: true,
};
},
mounted() {
this.getCode('/base/equipment-group-alarm/getCode').then((code) => {
this.formLoading = false;
this.$emit('update', {
...this.dataForm,
code,
});
});
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
async handleProductlineChange(id) {
await this.getWorksectionList(id);
this.dataForm.workshopSectionId = null;
this.$emit('update', this.dataForm);
},
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -37,7 +38,7 @@
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
<DialogForm v-if="open" ref="form" v-model="form" :rows="rows" />
</base-dialog>
</div>
</template>
@@ -54,10 +55,11 @@ import {
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import moment from 'moment';
import { publicFormatter } from '@/utils/dict';
import DialogForm from './dialogForm.vue';
export default {
name: 'EquipmentGroupAlarm',
components: {},
components: { DialogForm },
mixins: [basicPageMixin],
data() {
return {
@@ -84,22 +86,27 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'code', label: '报警编码', align: 'center' },
{ prop: 'type', label: '报警类型', align: 'center' },
{ width: 240, prop: 'code', label: '报警编码' },
{
prop: 'type',
label: '报警类型',
filter: (val) =>
val != null ? ['-', '字符型', '布尔型', '-'][val] : '-',
},
{
prop: 'grade',
label: '报警级别',
align: 'center',
filter: publicFormatter(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{ prop: 'alarmCode', label: '设备报警编码', align: 'center' },
{ prop: 'plcParamName', label: '参数列名', align: 'center' },
{ prop: 'alarmContent', label: '报警内容', align: 'center' },
{ prop: 'alarmCode', label: '设备报警编码' },
{ prop: 'plcParamName', label: '参数列名' },
{ prop: 'alarmContent', label: '报警内容' },
],
searchBarFormConfig: [
{
type: 'input',
label: '设备分组编码',
width: '220',
placeholder: '/',
param: 'equipmentGroupCode',
defaultSelect: null,
@@ -181,14 +188,14 @@ export default {
},
// 表单参数
form: {
id: undefined,
equipmentGroupId: undefined,
code: undefined,
type: undefined,
grade: undefined,
alarmCode: undefined,
alarmContent: undefined,
plcParamName: undefined,
id: null,
equipmentGroupId: null,
code: null,
type: null,
grade: null,
alarmCode: null,
alarmContent: null,
plcParamName: null,
},
// // 表单校验
// rules: {
@@ -249,14 +256,14 @@ export default {
/** 表单重置 */
reset() {
this.form = {
id: undefined,
equipmentGroupId: undefined,
code: undefined,
type: undefined,
grade: undefined,
alarmCode: undefined,
alarmContent: undefined,
plcParamName: undefined,
id: null,
equipmentGroupId: null,
code: null,
type: null,
grade: null,
alarmCode: null,
alarmContent: null,
plcParamName: null,
};
this.resetForm('form');
},
@@ -321,7 +328,7 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备分组报警明细编号为"' + id + '"的数据项?')
.confirm('是否确认删除该报警?')
.then(function () {
return deleteEquipmentGroupAlarm(id);
})

View File

@@ -12,6 +12,7 @@
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
ref="pageTable"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
@@ -58,9 +59,12 @@ const switchBtn = {
name: 'SwitchBtn',
props: ['injectData'],
data() {
return {
active: +this.injectData[this.injectData.prop] == 1 ? true : false,
};
return {};
},
computed: {
active() {
return +this.injectData[this.injectData.prop] == 1 ? true : false;
},
},
methods: {},
render: function (h) {
@@ -72,8 +76,6 @@ const switchBtn = {
},
on: {
change: (newVal) => {
this.active = !this.active;
console.log('changed emit', newVal);
this.$emit('emitData', {
action: 'update-collect',
payload: {
@@ -95,6 +97,7 @@ export default {
components: {},
data() {
return {
tableKey: Math.random(),
searchBarKeys: ['name', 'plcTableName'],
tableBtn: [
this.$auth.hasPermi('base:equipment-plc:update')
@@ -118,17 +121,16 @@ export default {
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'code', label: '编码', align: 'center' },
{ prop: 'plcTableName', label: '关联表名', align: 'center' },
{ prop: 'name', label: '标识名称', align: 'center' },
{ prop: 'enName', label: '英文名称', align: 'center' },
{ prop: 'code', label: '编码' },
{ prop: 'plcTableName', label: '关联表名' },
{ prop: 'name', label: '标识名称' },
{ prop: 'enName', label: '英文名称' },
{
prop: 'collection',
label: '是否采集',
align: 'center',
subcomponent: switchBtn,
},
{ prop: 'description', label: '描述', align: 'center' },
{ prop: 'description', label: '描述' },
],
searchBarFormConfig: [
{
@@ -185,6 +187,7 @@ export default {
label: '编码',
prop: 'code',
url: '/base/equipment-group/getCode',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
@@ -192,7 +195,7 @@ export default {
input: true,
label: '标识',
prop: 'name',
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: true, // some condition, like detail mode...
// }
@@ -208,6 +211,7 @@ export default {
switch: true,
label: '是否采集', // 是否采集 0 代表不采集, 1 代表采集
prop: 'collection',
value: 1,
bind: {
'active-value': 1,
'inactive-value': 0,
@@ -267,6 +271,7 @@ export default {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
// this.tableKey = Math.random(); // method 1
});
},
/** 取消按钮 */

View File

@@ -0,0 +1,531 @@
<!--
filename: EquipmentDrawer.vue
author: liubin
date: 2023-08-22 14:38:56
description:
-->
<template>
<el-drawer
:visible="visible"
:show-close="false"
:wrapper-closable="false"
class="drawer"
custom-class="mes-drawer"
size="60%"
@closed="$emit('destroy')">
<SmallTitle slot="title">
{{
mode.includes('detail')
? '详情'
: mode.includes('edit')
? '编辑'
: '新增'
}}
</SmallTitle>
<div class="drawer-body flex">
<div class="drawer-body__content">
<section v-for="(section, index) in sections" :key="section.key">
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
<div class="form-part" v-if="section.key == 'base'">
<el-skeleton v-if="!showForm" animated />
<BaseInfoForm
key="drawer-dialog-form"
v-if="showForm"
ref="form"
:disabled="mode.includes('detail')"
:dataForm="form"
:rows="formRows" />
</div>
<div v-if="section.key == 'attrs'" style="margin-top: 12px">
<base-table
v-loading="attrListLoading"
:table-props="section.props"
:page="attrQuery?.params.pageNo || 1"
:limit="attrQuery?.params.pageSize || 10"
:table-data="list"
:add-button-show="mode.includes('detail') ? null : '添加属性'"
@emitButtonClick="handleAddAttr"
@emitFun="handleEmitFun">
<method-btn
v-if="section.tableBtn"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="attrQuery.params.pageNo"
:limit.sync="attrQuery.params.pageSize"
@pagination="getAttrList" />
</div>
</section>
</div>
<div class="drawer-body__footer">
<el-button style="" @click="handleCancel">取消</el-button>
<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
编辑
</el-button>
<el-button v-else type="primary" @click="handleCancel">确定</el-button>
<!-- sections的第二项必须是 属性列表 -->
<!-- <el-button
v-if="sections[1].allowAdd"
type="primary"
@click="handleAddAttr">
添加属性
</el-button> -->
</div>
</div>
<!-- 属性对话框 -->
<base-dialog
v-if="sections[1].allowAdd"
:dialogTitle="attrTitle"
:dialogVisible="attrFormVisible"
width="45%"
:append-to-body="true"
custom-class="baseDialog"
@close="closeAttrForm"
@cancel="closeAttrForm"
@confirm="submitAttrForm">
<DialogForm
v-if="attrFormVisible"
ref="attrForm"
:disabled="mode.includes('detail')"
v-model="attrForm"
:rows="attrRows" />
</base-dialog>
</el-drawer>
</template>
<script>
import BaseInfoForm from '@/components/DialogForm';
const SmallTitle = {
name: 'SmallTitle',
props: ['size'],
data() {
return {};
},
methods: {},
render: function (h) {
return h(
'span',
{
class: 'small-title',
style: {
fontSize: '18px',
lineHeight:
this.size == 'lg' ? '24px' : this.size == 'sm' ? '18px' : '20px',
fontWeight: 500,
fontFamily: '微软雅黑, Microsoft YaHei, Arial, Helvetica, sans-serif',
},
},
this.$slots.default
);
},
};
export default {
components: { SmallTitle, DialogForm: BaseInfoForm, BaseInfoForm },
props: ['sections', 'defaultMode', 'infoData'],
data() {
return {
mode: '',
visible: false,
showForm: false,
total: 0,
form: {},
list: [],
attrTitle: '',
attrForm: {
id: null,
name: '',
plcParamName: '',
unit: '',
collection: 1,
minValue: '',
maxValue: '',
defaultValue: '',
description: '',
remark: '',
alarmContent: '',
},
attrFormVisible: false,
attrRows: [
[
{
input: true,
label: '参数列名',
prop: 'plcParamName',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
input: true,
label: '参数名称',
prop: 'name',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
select: true,
label: '单位',
prop: 'unit',
options: this.getDictDatas(this.DICT_TYPE.UNIT_DICT),
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
switch: true,
label: '是否采集',
prop: 'collection',
bind: {
'active-value': 1,
'inactive-value': 0,
},
},
],
[
{
input: true,
label: '最小值',
prop: 'minValue',
rules: [
{
type: 'number',
message: '请输入正确的数字',
trigger: 'change',
transform: (val) => Number(val),
},
],
},
{
input: true,
label: '最大值',
prop: 'maxValue',
rules: [
{
required: false,
},
{
type: 'number',
message: '请输入正确的数字',
trigger: 'change',
transform: (val) => Number(val),
},
],
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
input: true,
label: '标准值',
prop: 'defaultValue',
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
{
input: true,
label: '描述',
prop: 'description',
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
input: true,
label: '备注',
prop: 'remark',
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
],
attrQuery: {
params: {
pageNo: 1,
pageSize: 10,
},
}, // 属性列表的请求
infoQuery: null, // 基本信息的请求
attrFormSubmitting: false,
attrListLoading: false,
};
},
computed: {
formRows() {
return this.sections[0].rows.map((row) => {
return row.map((col) => {
return {
...col,
bind: {
// 详情 模式下,禁用各种输入
// disabled: this.mode == 'detail',
disabled: true,
},
};
});
});
},
tableBtn() {
return this.mode == 'detail' ? [] : this.sections[1].tableBtn;
},
},
mounted() {
this.mode = this.defaultMode || 'detail';
for (const section of this.sections) {
// 请求具体信息
if ('url' in section) {
const query = {
url: section.url,
method: section.method || 'get',
params: section.queryParams || null,
data: section.data || null,
};
// debugger;
this.$axios(query).then(({ data }) => {
if (section.key == 'base') {
this.form = data;
this.showForm = true;
this.infoQuery = query;
} else if (section.key == 'attrs') {
this.attrQuery = query;
this.list = data.list;
this.total = data.total;
}
});
} else if (section.key == 'base') {
this.form = this.infoData;
this.showForm = true;
}
}
},
methods: {
handleTableBtnClick({ type, data }) {
switch (type) {
case 'edit':
this.handleEditAttr(data.id);
break;
case 'delete':
this.handleDeleteAttr(data.id);
break;
}
},
handleEmitFun(val) {
console.log('handleEmitFun', val);
},
init() {
this.visible = true;
},
async getAttrList() {
this.attrListLoading = true;
const res = await this.$axios(this.attrQuery);
if (res.code == 0) {
this.list = res.data.list;
this.total = res.data.total;
}
this.attrListLoading = false;
},
// 保存表单
handleSave() {
this.$refs['form'][0].validate(async (valid) => {
if (valid) {
const isEdit = this.mode == 'edit';
await this.$axios({
url: this.sections[0][isEdit ? 'urlUpdate' : 'urlCreate'],
method: isEdit ? 'put' : 'post',
data: this.form,
});
this.$modal.msgSuccess(`${isEdit ? '更新' : '创建'}成功`);
this.visible = false;
this.$emit('refreshDataList');
}
});
},
handleCancel() {
this.visible = false;
},
// 开启编辑
toggleEdit() {
this.mode = 'edit';
},
// 新增属性
handleAddAttr() {
this.attrForm = {
id: null,
name: '',
plcParamName: '',
unit: '',
collection: 1,
minValue: '',
maxValue: '',
defaultValue: '',
description: '',
remark: '',
alarmContent: '',
};
this.attrTitle = '添加设备绑定信息';
this.attrFormVisible = true;
},
// 编辑属性
async handleEditAttr(attrId) {
const res = await this.$axios({
url: this.sections[1].urlDetail,
method: 'get',
params: { id: attrId },
});
if (res.code == 0) {
this.attrForm = res.data;
this.attrTitle = '编辑设备绑定信息';
this.attrFormVisible = true;
}
},
// 删除属性
handleDeleteAttr(attrId) {
this.$confirm('确定删除该分组报警?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
const res = await this.$axios({
url: this.sections[1].urlDelete,
method: 'delete',
params: { id: attrId },
});
if (res.code == 0) {
this.$message({
message: '删除成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
})
.catch(() => {});
},
// 提交属性表
async submitAttrForm() {
this.$refs['attrForm'].validate((valid) => {
if (!valid) {
return;
}
});
const isEdit = this.attrForm.id != null;
this.attrFormSubmitting = true;
const res = await this.$axios({
url: isEdit ? this.sections[1].urlUpdate : this.sections[1].urlCreate,
method: isEdit ? 'put' : 'post',
data: {
...this.attrForm,
connectId: this.infoData.id
},
});
if (res.code == 0) {
this.closeAttrForm();
this.$message({
message: `${isEdit ? '更新' : '创建'}成功`,
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
this.attrFormSubmitting = false;
},
closeAttrForm() {
this.attrFormVisible = false;
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(`确定删除该报警?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
deleteProductAttr(raw.data.id).then(({ data }) => {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getList();
},
});
});
})
.catch(() => {});
} else {
this.addNew(raw.data.id);
}
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 0px;
}
.small-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 22px;
border-radius: 1px;
margin-right: 8px;
background-color: #0b58ff;
}
.drawer-body {
display: flex;
flex-direction: column;
height: 100%;
}
.drawer-body__content {
flex: 1;
/* background: #eee; */
padding: 20px 30px;
overflow-y: auto;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -39,6 +40,53 @@
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
</base-dialog>
<!-- 抽屉 详情 -->
<BasicDrawer
v-if="editVisible"
ref="drawer"
:default-mode="editMode"
:info-data="alarmForm"
:sections="[
{
name: '基本信息',
key: 'base',
rows: drawerBaseInfoRows,
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/equipment-plc-param/page',
urlCreate: '/base/equipment-plc-param/create',
urlUpdate: '/base/equipment-plc-param/update',
urlDelete: '/base/equipment-plc-param/delete',
urlDetail: '/base/equipment-plc-param/get',
queryParams: {
connectId: alarmForm.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:equipment-plc-param:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:equipment-plc-param:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="editVisible = false"
@destroy="editVisible = false" />
</div>
</template>
@@ -54,14 +102,16 @@ import {
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
// import './http';
import BasicDrawer from './components/BasicDrawer.vue';
import { publicFormatter } from '@/utils/dict';
export default {
name: 'EquipmentPlcConnect',
mixins: [basicPageMixin],
components: {},
components: { BasicDrawer },
data() {
return {
searchBarKeys: ['name', 'plcTableName'],
searchBarKeys: ['equipmentId', 'plcId'],
// tableBtn: [
// this.$auth.hasPermi('base:equipment-plc:update')
// ? {
@@ -77,6 +127,10 @@ export default {
// : undefined,
// ].filter((v) => v),
tableBtn: [
{
type: 'detail',
btnName: '参数绑定',
},
{
type: 'edit',
btnName: '修改',
@@ -98,54 +152,55 @@ export default {
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'productionLine', label: '产线', align: 'center' },
{ prop: 'workshopSection', label: '工段', align: 'center' },
{ prop: 'equipmentName', label: '设备名', align: 'center' },
{ prop: 'equipmentCode', label: '设备编码', align: 'center' },
{ prop: 'plcCode', label: '关联表编码', align: 'center' },
{ prop: 'plcTableName', label: '关联表名', align: 'center' },
{ prop: 'plcName', label: '标识名称', align: 'center' },
{ prop: 'bindingParameters', label: '绑定参数数量', align: 'center' },
{
_action: 'params-bind',
label: '查看绑定',
align: 'center',
subcomponent: {
props: ['injectData'],
render: function (h) {
const _this = this;
return h(
'el-button',
{
props: { type: 'text' },
on: {
click: function () {
console.log('inejctdata', _this.injectData);
_this.$emit('emitData', {
action: _this.injectData._action,
payload: _this.injectData,
});
},
},
},
'查看绑定'
);
},
},
},
{ prop: 'productionLine', label: '产线' },
{ prop: 'workshopSection', label: '工段' },
{ prop: 'equipmentName', label: '设备名' },
{ prop: 'equipmentCode', label: '设备编码' },
{ prop: 'plcCode', label: '关联表编码' },
{ prop: 'plcTableName', label: '关联表名' },
{ prop: 'plcName', label: '标识名称' },
{ prop: 'bindingParameters', label: '绑定参数数量' },
// {
// _action: 'params-bind',
// label: '查看绑定',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData._action,
// payload: _this.injectData,
// });
// },
// },
// },
// '查看绑定'
// );
// },
// },
// },
],
searchBarFormConfig: [
{
type: 'input',
type: 'select',
label: '设备名',
placeholder: '请输入设备',
placeholder: '请选择设备',
param: 'equipmentId',
selectOptions: [],
},
{
type: 'input',
type: 'select',
label: '编码',
placeholder: '请输入编码',
placeholder: '请选择编码',
param: 'plcId',
selectOptions: [],
},
{
type: 'button',
@@ -179,8 +234,12 @@ export default {
select: true,
label: '关联表名',
prop: 'plcId',
labelKey: `plcTableName`,
url: '/base/equipment-plc/listAll',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
bind: {
filterable: true,
},
},
],
[
@@ -190,6 +249,9 @@ export default {
prop: 'equipmentId',
url: '/base/equipment/page?pageNo=1&pageSize=99',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
bind: {
filterable: true,
},
},
],
],
@@ -203,12 +265,94 @@ export default {
},
// 表单参数
form: {},
// 查看绑定配置
editVisible: false,
editMode: '',
drawerBaseInfoRows: [
[
{
input: true,
label: '设备名',
prop: 'equipmentName',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: this.editMode == 'detail', // some condition, like detail mode...
// }
},
{
input: true,
label: '关联表名',
prop: 'plcTableName',
// url: '/base/equipment/getCode',
},
],
],
drawerListProps: [
{ prop: 'plcParamName', label: '参数列名' },
{ prop: 'name', label: '参数名称' },
{
prop: 'unit',
label: '单位',
filter: publicFormatter('unit_dict'),
},
{
prop: 'collection',
label: '是否采集',
filter: (val) => (val != null ? ['否', '是'][val] : '-'),
},
{ prop: 'minValue', label: '最小值' },
{ prop: 'maxValue', label: '最大值' },
{ prop: 'defaultValue', label: '标准值' },
{ prop: 'description', label: '描述' },
{ prop: 'remark', label: '备注' },
],
alarmForm: {
id: undefined,
equipmentName: undefined,
plcTableName: undefined,
},
};
},
created() {
this.getList();
this.initSearchOptions();
},
methods: {
async getEquipmentOptions() {
const res = await this.$axios({
url: '/base/equipment/listAll',
method: 'get',
});
return res.data;
},
async getPlcOptions() {
const res = await this.$axios({
url: '/base/equipment-plc/listAll',
method: 'get',
});
return res.data;
},
/** 初始化查询条件 */
async initSearchOptions() {
Promise.all([this.getEquipmentOptions(), this.getPlcOptions()]).then(
([eqList, plcList]) => {
this.searchBarFormConfig[0].selectOptions = eqList.map((item) => {
return {
name: item.name,
id: item.id,
};
});
this.searchBarFormConfig[1].selectOptions = plcList.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
);
},
/** 覆盖 handleEmitFun 的默认实现 */
handleEmitFun({ action, payload }) {
switch (action) {
@@ -308,15 +452,39 @@ export default {
});
});
},
// 查看报警
handleDetail(row) {
// debugger;
const {
id,
bindingParameters,
equipmentCode,
equipmentId,
equipmentName,
plcCode,
plcId,
plcName,
plcTableName,
productionLine,
workshopSection,
} = row;
// 打开抽屉
this.editMode = 'detail';
this.alarmForm.id = id;
this.alarmForm.plcTableName = plcTableName; // 关联表名
this.alarmForm.equipmentName = equipmentName;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm(
'是否确认删除设备与实时采集关系表(一对多)编号为"' +
id +
'"的数据项?'
)
.confirm('是否删除该配置?')
.then(function () {
return deleteEquipmentPlcConnect(id);
})
@@ -326,6 +494,7 @@ export default {
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
// 处理查询参数

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -68,29 +69,27 @@ export default {
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'plcParamName', label: '参数列名', align: 'center' },
{ prop: 'name', label: '参数名称', align: 'center' },
{ prop: 'plcParamName', label: '参数列名' },
{ prop: 'name', label: '参数名称' },
{
prop: 'unit',
label: '单位',
align: 'center',
filter: publicFormatter('unit_dict'),
},
{
prop: 'collection',
label: '是否采集',
align: 'center',
filter: (val) => (val != null ? ['否', '是'][val] : '-'),
},
{ prop: 'minValue', label: '最小值', align: 'center' },
{ prop: 'maxValue', label: '最大值', align: 'center' },
{ prop: 'defaultValue', label: '标准值', align: 'center' },
{ prop: 'description', label: '描述', align: 'center' },
{ prop: 'remark', label: '备注', align: 'center' },
{ prop: 'minValue', label: '最小值' },
{ prop: 'maxValue', label: '最大值' },
{ prop: 'defaultValue', label: '标准值' },
{ prop: 'description', label: '描述' },
{ prop: 'remark', label: '备注' },
// {
// _action: 'params-bind',
// label: '查看绑定',
// align: 'center',
// ,
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
@@ -157,7 +156,7 @@ export default {
{
type: 'number',
message: '请输入正确的数字',
trigger: 'blur',
trigger: 'change',
transform: (val) => Number(val),
},
],
@@ -167,10 +166,13 @@ export default {
label: '最大值',
prop: 'maxValue',
rules: [
{
required: false,
},
{
type: 'number',
message: '请输入正确的数字',
trigger: 'blur',
trigger: 'change',
transform: (val) => Number(val),
},
],
@@ -349,8 +351,8 @@ export default {
plcParamName: undefined,
name: undefined,
unit: undefined,
minValue: undefined,
maxValue: undefined,
minValue: null,
maxValue: null,
defaultValue: undefined,
collection: undefined,
description: undefined,
@@ -417,7 +419,7 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备数采详情编号为"' + id + '"的数据项?')
.confirm('是否确认删除"' + row.name + '"的参数绑定?')
.then(function () {
return deleteEquipmentPlcParam(id);
})

View File

@@ -1,8 +1,8 @@
<!--
* @Author: zhp
* @Date: 2023-09-13 09:02:25
* @LastEditTime: 2023-09-13 10:33:20
* @LastEditors: zhp
* @LastEditTime: 2023-10-16 14:56:58
* @LastEditors: DY
* @Description:
-->
<template>
@@ -61,11 +61,12 @@ export default {
// },
methods: {
initChart(xData, yData,lineName) {
console.log(xData,yData);
console.log( '打印结果', xData,yData, lineName);
this.chart = echarts.init(this.$el, 'macarons')
this.setOptions(xData, yData, lineName)
},
setOptions(xData, yData, lineName) {
console.log('da', lineName)
let seriesData = []
lineName.forEach((item,index) => {
seriesData.push({
@@ -86,7 +87,7 @@ export default {
type: 'value'
},
series: seriesData
})
}, true)
}
}
}

View File

@@ -1,8 +1,12 @@
<template>
<div class="app-container">
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" />
<base-table v-loading="dataListLoading" :table-props="tableProps" :table-data="tableData" />
<line-chart ref="lineChart" />
<div v-if="tableData.length">
<base-table v-loading="dataListLoading" :span-method="mergeColumnHandler" :table-props="tableProps" :table-data="tableData" />
<SearchBar :formConfigs="[{ label: '产线平衡分析图', type: 'title' }]" />
<balance-chart ref="lineChart" />
</div>
<div v-else class="no-data-bg"></div>
<!-- <pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
@@ -16,7 +20,8 @@
import { parseTime } from '../../mixins/code-filter';
import { getCT } from '@/api/core/analysis/index';
import { getProductionLinePage } from '@/api/core/base/productionLine';
import lineChart from '../LineChart'
import BalanceChart from '../balanceChart'
import { time } from 'echarts';
// import { getWorkshopSectionPage } from '@/api/core/base/workshopSection';
// const tableProps = [
@@ -42,7 +47,7 @@ import lineChart from '../LineChart'
export default {
components: {
lineChart,
BalanceChart
},
// mixins: [basicPage],
data() {
@@ -59,6 +64,8 @@ export default {
lineId:undefined,
startTime:undefined
},
timeList: [],
spanArr: [],
xData: [],
yData: [],
optionArrUrl: [getProductionLinePage],
@@ -69,23 +76,24 @@ export default {
selectOptions: [],
param: 'lineIds',
defaultSelect: '',
multiple: true,
multiple: false,
filterable: true,
},
{
type: 'datePicker',
label: '时间',
dateType: 'datetime',
dateType: 'datetimerange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
width: 350,
param: 'time',
},
{
type: 'button',
btnName: '搜索',
btnName: '查询',
name: 'search',
color: 'primary',
}
@@ -99,18 +107,47 @@ export default {
getArr() {
const params = {
page: 1,
limit: 500,
};
limit: 500
}
this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => {
this.formConfig[index].selectOptions = response.data.list
});
});
},
setRowSpan(arr) {
let count = 0
arr.forEach((item, index) => {
if(index === 0) {
this.spanArr.push(1)
} else {
if (item === arr[index - 1]) {
this.spanArr[count] += 1
this.spanArr.push(0)
} else {
count = index
this.spanArr.push(1)
}
}
})
},
/** 合并table列的规则 */
mergeColumnHandler({ row, column, rowIndex, columnIndex }) {
if (columnIndex == 0) {
if (this.spanArr[rowIndex]) {
return [
this.spanArr[rowIndex], // row span
1, // col span
];
} else {
return [0, 0];
}
}
},
getData() {
this.listQuery.lineId = '1672847052717821953'
this.listQuery.startTime = '1693497600000';
this.listQuery.endTime = '1693843200000';
// this.listQuery.lineId = '1672847052717821953'
// this.listQuery.startTime = '1693497600000';
// this.listQuery.endTime = '1693843200000';
this.urlOptions.getDataListURL(this.listQuery).then(res => {
console.log(res)
let arr = [
@@ -123,53 +160,60 @@ export default {
prop: 'equName',
label: '设备',
align: 'center',
},
}
]
let eqArr= []
let sectionArr= []
res.data.data.forEach((ele, index) => {
console.log(ele);
eqArr.push(ele.equName)
let tempData = []
let eqData = []
let plData = []
ele.data.forEach((item, index) => {
item.children.forEach(params => {
if (params.dynamicName === '设备CT') {
tempData[item.dynamicName + '_eq'] = params.dynamicValue
eqData[index] = params.dynamicValue
} else {
tempData[item.dynamicName + '_pl'] = params.dynamicValue
plData[index] = params.dynamicValue
}
})
console.log(eqArr)
// console.log(res.data.nameData.slice(1))
})
const equipment = {
name: ele.equName,
eqData: eqData,
plData: plData
}
tempData['equName'] = ele.equName
tempData['sectionName'] = ele.sectionName
this.tableData.push(tempData)
const { sectionName } = tempData
sectionArr.push(sectionName)
this.yData.push(equipment)
console.log('看看equ', this.yData)
})
this.setRowSpan(sectionArr)
res.data.nameData.forEach(item => {
if (eqArr[0] === item.parentId) {
const props = {
'prop': item.name,
'label': item.name,
'align': 'center'
}
}
arr[2].children.push(props)
this.timeList.push(item.name)
})
let obj = {
lineName: res.data.data[0].lineName,
sum: res.data.data[0].sum,
const timeArray = Array.from(new Set(this.timeList))
for (const times of timeArray) {
if (times !== '设备CT' && times !== '产线CT') {
const subprop = {
label: times,
align: 'center',
children: [
{ prop: times + '_eq', label: '设备CT', align: 'center' },
{ prop: times + '_pl', label: '产线CT', align: 'center' }
]
}
arr.push(subprop)
this.xData.push(times)
}
}
res.data.data[0].data[0].children.forEach((item, index) => {
console.log(item)
// let data = 'data' + Number(index+1)
obj['' + item.dynamicName + ''] = item.dynamicValue
})
this.tableData = [obj]
console.log(this.tableData)
console.log(arr)
this.tableProps = arr
let xData = []
res.data.nameData.forEach(item => {
xData.push(item.name)
// arr[2].children.push(props)
})
let yData = []
res.data.data[0].data[0].children.forEach((item, index) => {
// console.log(item)
yData.push(item.dynamicValue)
// let data = 'data' + Number(index+1)
// obj['' + item.dynamicName + ''] = item.dynamicValue
})
console.log(this.yData)
this.$refs.lineChart.initChart(xData, yData)
console.log('表格横坐标', this.xData)
this.$refs.lineChart.initChart(this.xData, this.yData)
// this.total = response.data.total;
// this.dataListLoading = false;
});
@@ -180,7 +224,23 @@ export default {
case 'search':
// this.listQuery.pageNo = 1;
// this.listQuery.pageSize = 10;
this.listQuery.lineId = val.lineIds
this.listQuery.startTime = val.time ? String(new Date(val.time[0]).getTime()) : undefined;
this.listQuery.endTime = val.time ? String(new Date(val.time[1]).getTime()) : undefined;
if (val.time && val.lineIds) {
this.tableData = []
this.xData = []
this.yData = []
this.tableProps = []
this.spanArr = []
this.timeList = []
this.getData()
} else {
this.$message({
message: '请选择产线和时间',
type: 'warning'
});
}
break;
case 'reset':
this.$refs.searchBarForm.resetForm();

View File

@@ -0,0 +1,134 @@
<!--
* @Author: zhp
* @Date: 2023-09-13 09:02:25
* @LastEditTime: 2023-10-08 16:36:37
* @LastEditors: DY
* @Description:
-->
<template>
<div>
<div style="margin: 20px">
<el-button v-for="(item, index) in buttonList" :key="index" :class="[item.actived ? 'activeButton': 'normalButton']" @click="changeChart(index)">{{ item.name }}</el-button>
</div>
<div ref="chartDiv" :class="className" :style="{height:height,width:width}" />
</div>
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
// import resize from './mixins/resize'
export default {
// mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
// autoResize: {
// type: Boolean,
// default: true
// }
},
data() {
return {
chart: null,
dataArray: [],
xDatas: [],
buttonList: []
}
},
mounted() {
},
methods: {
changeChart(index) {
this.setOptions(this.xDatas, this.dataArray[index])
this.buttonList.forEach((item, s) => {
if (index === s) {
// item.actived = true
this.$nextTick(() =>{
// item.actived = true
this.$set(item, 'actived', true)
})
} else {
// item.actived = false
this.$nextTick(() =>{
// item.actived = false
this.$set(item, 'actived', false)
})
// this.$set(item, 'actived', false)
}
})
console.log('看一下数22222据', this.dataArray)
},
initChart(xData, yData, lineName) {
this.dataArray = yData
this.buttonList = this.dataArray.map((item, index) => {
return {
'name': item.name,
'actived': index === 0 ? true : false
}
})
console.log('看一下数据', this.dataArray)
this.xDatas = xData
this.chart = echarts.init(this.$refs.chartDiv, 'macarons')
this.setOptions(xData, yData[0], lineName)
},
setOptions(xData, dataList, lineName) {
// let seriesData = []
// lineName.forEach((item,index) => {
// seriesData.push({
// name: item,
// data: yData[index],
// type: 'line',
// })
// })
this.chart.setOption({
xAxis: {
type: 'category',
data: xData
},
tooltip: {
trigger: 'axis'
},
legend: {
data:lineName
},
yAxis: {
type: 'value'
},
series: [
{
name: '设备CT',
data: dataList.eqData,
type: 'line',
},
{
name: '产线CT',
data: dataList.plData,
type: 'line',
}
]
})
}
}
}
</script>
<style scoped>
.activeButton {
background-color: rgb(93,159,255);
}
.normalButton {
background-color: none;
}
</style>

View File

@@ -1,8 +1,12 @@
<template>
<div class="app-container">
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" />
<div v-if="tableData.length">
<base-table v-loading="dataListLoading" :table-props="tableProps" :table-data="tableData" />
<SearchBar :formConfigs="[{ label: '产品产量对比图', type: 'title' }]" />
<line-chart ref="lineChart" />
</div>
<div v-else class="no-data-bg"></div>
<!-- <pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
@@ -57,8 +61,7 @@ export default {
lineIds: [],
time: ''
},
xData: [],
yData:[],
dateLabelList: [],
optionArrUrl: [getProductionLinePage ],
formConfig: [
{
@@ -73,7 +76,7 @@ export default {
{
type: 'datePicker',
label: '时间',
dateType: 'datetime',
dateType: 'month',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
@@ -83,7 +86,7 @@ export default {
},
{
type: 'button',
btnName: '搜索',
btnName: '查询',
name: 'search',
color: 'primary',
}
@@ -102,6 +105,8 @@ export default {
this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => {
this.formConfig[index].selectOptions = response.data.list
// this.formConfig[0].defaultSelect = response.data.list[0].id
this.$set(this.formConfig[0], 'defaultSelect', response.data.list[0].id)
});
});
},
@@ -114,31 +119,54 @@ export default {
{
prop: 'lineName',
label: '产线',
align: 'center',
fixed: 'left'
},
{
prop: 'sum',
label: '合计',
align: 'center',
fixed: 'left'
},
{
prop: res.data.nameData[0].name,
label: res.data.nameData[0].name,
prop: res.data ? res.data.nameData[0].name : undefined,
label: res.data ? res.data.nameData[0].name : undefined,
align: 'center',
children:[
]
}
]
console.log(res.data.nameData.slice(1))
res.data.nameData.slice(1).forEach(item => {
// console.log(res.data.nameData.slice(1))
let xData = []
let yAllData = []
let lineName = []
if (res.data) {
let tempDateList = []
res.data.nameData.forEach(date => {
tempDateList.push(date.name)
})
this.dateLabelList = Array.from(new Set(tempDateList))
this.dateLabelList.forEach(item => {
if (item.indexOf('年') === -1) {
// 构造表头
const props = {
'prop': item.name,
'label': item.name,
'align': 'center'
'prop': item,
'label': item
}
arr[2].children.push(props)
// 构造echarts横坐标
xData.push(item)
}
})
// res.data.nameData.slice(1).forEach(item => {
// const props = {
// 'prop': item.name,
// 'label': item.name,
// 'align': 'center'
// }
// arr[2].children.push(props)
// })
let tableDataArr =[]
res.data.data.forEach(item => {
let obj = {}
@@ -155,17 +183,15 @@ export default {
tableDataArr.push(obj)
});
this.tableData = tableDataArr
console.log(this.tableData)
console.log(arr)
this.tableProps = arr
let xData = []
res.data.nameData.slice(1).forEach(item => {
xData.push(item.name)
// arr[2].children.push(props)
})
let yAllData = []
let lineName = []
// let tempList = []
// res.data.nameData.slice(1).forEach(item => {
// tempList.push(item.name)
// // arr[2].children.push(props)
// })
// xData = Array.from(new Set(tempList))
res.data.data.forEach(item => {
let yData = []
lineName.push(item.lineName)
@@ -182,6 +208,13 @@ export default {
yAllData.push(yData)
});
console.log(lineName)
} else {
this.tableProps = arr
this.tableData = []
xData = []
yAllData = []
lineName = []
}
// res.data.data[0].data[0].children.forEach((item, index) => {
// // console.log(item)
// yData.push(item.dynamicValue)
@@ -195,7 +228,6 @@ export default {
});
},
buttonClick(val) {
// console.log(val)
switch (val.btnName) {
case 'search':
this.listQuery.lineIds = val.lineIds ? val.lineIds :undefined
@@ -203,7 +235,14 @@ export default {
this.listQuery.time = val.time ? new Date(val.time).getTime() : undefined
// this.listQuery.pageNo = 1;
// this.listQuery.pageSize = 10;
if (val.time) {
this.getData()
} else {
this.$message({
message: '请选择时间',
type: 'warning'
});
}
break;
case 'reset':
this.$refs.searchBarForm.resetForm();

View File

@@ -0,0 +1,412 @@
<!--
filename: AssetsUpload.vue
author: liubin
date: 2023-10-12 16:40:14
description: 上传资料/图片 组件
-->
<template>
<div class="assets-upload">
<section class="operations">
<el-button type="text" class="expand-btn" @click="expand = !expand">
<i class="el-icon-folder-opened" v-if="expand"></i>
<i class="el-icon-folder" v-else></i>
展开
</el-button>
<!-- <div class="preview-btn">
<i class="el-icon-view"></i>
预览
</div> -->
</section>
<section class="file-area">
<el-upload
class="equipment-upload"
:disabled="disabled"
drag
:action="uploadUrl"
:headers="headers"
multiple
:show-file-list="false"
:before-upload="beforeUpload"
:on-success="handleSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
<span>将文件拖到此处或</span>
<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">
{{
isPicMode ? '仅支持上传 .jpg .png 格式文件, 且' : ''
}}文件大小不超过2MB
</div>
</el-upload>
<!-- <div
class="file-list__item"
v-for="n in 9"
:key="n"
:style="{
display: n > 4 && !expand ? 'none' : 'block',
}"
:data-name="n"
:class="{ 'default-icon': !isPicMode }">
<i class="el-icon-delete"></i>
</div> -->
<div
class="file-list__item"
v-for="(file, index) in files"
:key="file.fileName"
:style="{
display: index > 3 && !expand ? 'none' : 'block',
background: isPicMode
? `url(${file.fileUrl}) no-repeat`
: `url(${defaultBg}) no-repeat`,
backgroundSize: isPicMode ? '100% 100%' : '64px',
backgroundPosition: isPicMode ? '0% 0%' : 'center',
}"
:data-name="file.fileName">
<el-button
v-if="!disabled"
type="text"
class="el-icon-delete"
style="padding: 0"
@click="(e) => handleDelete(file)" />
</div>
</section>
</div>
</template>
<script>
import { getAccessToken } from '@/utils/auth';
import defaultBg from '../../../../../assets/images/default-file-icon.png';
function checkSize(file, message) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('上传文件大小不能超过 2MB!');
}
return isLt2M;
}
function checkPic(file, message) {
const isJPG = file.type === 'image/jpeg';
const isPNG = file.type === 'image/png';
const isPic = isJPG || isPNG;
if (!isPic) {
message.error('上传图片只能是 JPG/PNG 格式!');
}
return isPic;
}
export default {
name: 'AssetsUpload',
components: {},
model: {
prop: 'dataSource',
event: 'update',
},
props: {
type: {
type: String,
default: 'image',
},
dataSource: {
type: Array,
default: () => [],
},
equipmentId: {
type: String,
default: '',
},
isPicMode: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
emits: ['update-filelist'],
data() {
return {
defaultBg,
expand: false,
headers: { Authorization: 'Bearer ' + getAccessToken() }, // 设置上传的请求头部
fileList: [],
uploadUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload',
files: [
// 服务器返回的结构
// {
// fileName: 'sf.docs',
// fileType: 'asset',
// fileUrl:
// 'https://hbimg.b0.upaiyun.com/cc7475787bd08ed926b68eaf53fa1f2c5473259115e3c-gJdObd_fw658',
// },
// {
// fileName: 'sddf.docs',
// fileType: 'asset',
// fileUrl: 'https://img0.sc115.com/wm/xqx/pic1/1501xofo4ssolji.jpg',
// },
// {
// fileName: 'jjj.docs',
// fileType: 'asset',
// fileUrl:
// 'https://www.mms591.com/www.mms591.com-photo/2013081823/1-130QR34544.jpg',
// },
// {
// fileName: 'asdfasdf.docs',
// fileType: 'asset',
// fileUrl:
// 'https://hbimg.b0.upaiyun.com/8f6bced5f2e38d3a021b2c48d5a98dfb6317e3e12c6a0-QmhJ5v_fw658',
// },
// {
// fileName: 'asdkj.docs',
// fileType: 'asset',
// fileUrl:
// 'https://www.mms591.com/www.mms591.com-photo/2013013021/1-130130212034.jpg',
// },
// {
// fileName: 'lkasjdf.docs',
// fileType: 'asset',
// fileUrl:
// 'https://www.mms591.com/www.mms591.com-photo/2013072122/1-130H1223057.jpg',
// },
// {
// fileName: 'asdf.docs',
// fileType: 'asset',
// fileUrl:
// 'https://img.1ppt.com/uploads/allimg/1212/1-1212101ZH5A2.jpg',
// },
// {
// fileName: 'afdffff.docs',
// fileType: 'asset',
// fileUrl:
// 'https://www.mms591.com/www.mms591.com-photo/2013051721/1-13051H11945.jpg',
// },
],
updateTimer: null,
};
},
watch: {
dataSource: {
handler(val) {
this.files = JSON.parse(JSON.stringify(val));
},
immediate: true,
deep: true,
},
},
mounted() {},
methods: {
// handle success, per file!
handleSuccess(response, file, fileList) {
this.$notify({
title: '成功',
message: '上传成功! 点击确认保存上传结果',
type: 'success',
});
if (
response == null ||
!('data' in response) ||
response.data == null ||
response.data.trim() == ''
) {
this.$message.error('上传出错了!');
return;
}
this.files.push({
fileName: file.name,
fileUrl: response.data,
fileType: this.isPicMode ? 1 : 2,
});
// debugger;
// 延时更新
if (this.updateTimer) {
clearTimeout(this.updateTimer);
}
this.updateTimer = setTimeout(() => {
console.log('[AssetsUpload] 更新上传列表');
this.emitFilelist();
clearTimeout(this.updateTimer);
this.updateTimer = null;
}, 500);
},
emitFilelist() {
this.$emit('update', this.files);
},
handleRemove(file, fileList) {
debugger;
},
handleDelete(file) {
// fileName fileType 都可能一样,但 fileUrl 一定不一样
this.files = this.files.filter((item) => item.fileUrl != file.fileUrl);
this.$notify({
title: '成功',
message: '删除成功! 需点击确认保存删除结果',
type: 'success',
});
this.emitFilelist();
},
beforeUpload(file) {
if (this.isPicMode) {
return checkPic(file, this.$message) && checkSize(file, this.$message);
}
return checkSize(file, this.$message);
},
handleUpload() {
switch (this.type) {
case 'image':
break;
case 'asset':
break;
}
},
updateFileList(appendFilelist) {
// Array
this.$emit('update-filelist', this.appendFilelist);
},
},
};
</script>
<style scoped lang="scss">
.assets-upload {
position: relative;
}
.operations {
position: absolute;
top: -36px;
right: 0;
display: flex;
align-items: center;
}
.expand-btn,
.preview-btn {
font-size: 14px;
line-height: 1.2;
display: inline-block;
padding-left: 20px;
cursor: pointer;
z-index: 1000;
}
.expand-btn {
margin-right: 12px;
}
.preview-btn {
color: #ccc;
}
.expand-btn,
.preview-btn:hover,
.preview-btn.active {
// color: #0042d0;
color: #0b58ff;
}
:deep(.equipment-upload) {
background: #ccc4;
.el-upload-dragger {
width: 188px;
height: 128px;
}
.el-icon-upload {
margin: 12px 0;
font-size: 48px;
}
.el-upload__text {
font-size: 12px;
line-height: 2px;
display: flex;
flex-direction: column;
em {
margin-top: 12px;
}
}
.el-upload__tip {
font-size: 12px;
line-height: 1.5;
color: #d1d1d1;
margin: 0 0 12px;
transform: translateY(-12px);
user-select: none;
}
}
.file-list {
padding: 12px;
border: 1px solid #ccc;
}
// custom
.file-area {
display: grid;
grid-template-columns: repeat(5, 188px);
grid-auto-rows: 128px;
gap: 24px 18px;
place-content: center;
}
.file-list__item {
background-color: #fff;
border: 1px dashed #d9d9d9;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-align: center;
cursor: pointer;
position: relative;
// overflow: hidden;
&:hover {
.el-icon-delete {
display: block;
}
}
.el-icon-delete {
color: #ccc;
position: absolute;
top: 8px;
right: 8px;
display: none;
&:hover {
color: rgb(210, 41, 41);
}
}
}
.file-list__item:hover {
border-color: #0b58ff;
}
.file-list__item::after {
content: attr(data-name);
position: absolute;
left: 0;
bottom: -26px;
font-size: 14px;
line-height: 2;
color: #616161;
}
.default-icon {
background: url(../../../../../assets/images/default-file-icon.png) no-repeat;
background-position: center;
background-size: 64px;
}
</style>

View File

@@ -0,0 +1,313 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
ref="form"
:model="form"
:label-width="`${labelWidth}px`"
:size="size"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
<el-input
v-if="col.input"
v-model="form[col.prop]"
@change="$emit('update', form)"
:placeholder="`请输入${col.label}`"
v-bind="col.bind" />
<el-input
v-if="col.textarea"
type="textarea"
v-model="form[col.prop]"
@change="$emit('update', form)"
:placeholder="`请输入${col.label}`"
v-bind="col.bind" />
<el-select
v-if="col.select"
v-model="form[col.prop]"
:placeholder="`请选择${col.label}`"
@change="$emit('update', form)"
v-bind="col.bind">
<el-option
v-for="opt in optionListOf[col.prop]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
<el-date-picker
v-if="col.datetime"
v-model="form[col.prop]"
type="datetime"
:placeholder="`请选择${col.label}`"
value-format="timestamp"
v-bind="col.bind"></el-date-picker>
<el-upload
class="upload-in-dialog"
v-if="col.upload"
:file-list="uploadedFileList"
:action="col.url"
:on-success="handleUploadSuccess"
v-bind="col.bind">
<el-button
size="small"
type="primary"
:disabled="col.bind?.disabled || false">
点击上传
</el-button>
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips">
{{ col.uploadTips || '只能上传jpg/png文件大小不超过2MB' }}
</div>
</el-upload>
<el-switch
v-if="col.switch"
v-model="form[col.prop]"
active-color="#0b58ff"
inactive-color="#e1e1e1"
v-bind="col.bind"></el-switch>
<component
v-if="col.subcomponent"
:key="col.key"
:is="col.subcomponent"
v-bind="col.bind"
:inlineStyle="col.style"></component>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
/**
* 找到最长的label
* @param {*} options
*/
function findMaxLabelWidth(rows) {
let max = 0;
rows.forEach((row) => {
row.forEach((opt) => {
// debugger;
if (!opt.label) return 0;
if (opt.label.length > max) {
max = opt.label.length;
}
});
});
return max;
}
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
rows: {
type: Array,
default: () => [],
},
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'right',
},
size: {
type: String,
default: '',
},
},
data() {
return {
formLoading: true,
optionListOf: {},
uploadedFileList: [],
dataLoaded: false,
};
},
computed: {
labelWidth() {
let max = findMaxLabelWidth(this.rows);
// 每个汉字占20px
return max * 20;
// return max * 20 + 'px';
},
form: {
get() {
// if (this.dataLoaded) return this.dataForm;
// else return {}
return this.dataForm;
},
set(val) {
console.log('set form', val);
},
},
},
watch: {
rows: {
handler() {
console.log('watch triggered!');
this.$nextTick(() => {
this.handleOptions('watch');
});
},
deep: true,
immediate: false,
},
},
mounted() {
// 处理 options
this.handleOptions();
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
async handleOptions(trigger = 'monuted') {
console.log('[dialogForm:handleOptions]');
const promiseList = [];
this.rows.forEach((cols) => {
cols.forEach((opt) => {
if (opt.value && !this.form[opt.prop]) {
// 默认值
this.form[opt.prop] = opt.value;
}
if (opt.options) {
this.$set(this.optionListOf, opt.prop, opt.options);
} else if (opt.url) {
// 如果有 depends则暂时先不获取注册一个watcher
if (opt.depends) {
console.log('[handleOptions] setting watch');
this.$watch(
() => this.form[opt.depends],
(id) => {
console.log('<', opt.depends, '>', 'changed', id);
if (id == null) return;
// 清空原有选项
this.form[opt.prop] = null;
// 获取新的选项
this.$axios({
url: `${opt.url}?id=${id}`,
}).then((res) => {
this.$set(
this.optionListOf,
opt.prop,
res.data.map((item) => ({
label: item[opt.labelKey ?? 'name'],
value: item[opt.valueKey ?? 'id'],
}))
);
});
},
{
immediate: true,
}
);
return;
}
// 如果是下拉框,或者新增模式下的输入框,才去请求
if (opt.select || (opt.input && !this.form?.id)) {
promiseList.push(async () => {
const response = await this.$axios(opt.url, {
method: opt.method ?? 'get',
});
console.log('[dialogForm:handleOptions:response]', response);
if (opt.select) {
// 处理下拉框选项
const list =
'list' in response.data
? response.data.list
: response.data;
this.$set(
this.optionListOf,
opt.prop,
list.map((item) => ({
label: item[opt.labelKey ?? 'name'],
value: item[opt.valueKey ?? 'id'],
}))
);
} else if (opt.input) {
console.log('setting code: ', response.data);
// 处理输入框数据
this.form[opt.prop] = response.data;
}
});
}
}
});
});
console.log('[dialogForm:handleOptions] done!');
// 如果是 watch 触发的,不需要执行进一步的请求
if (trigger == 'watch') {
this.formLoading = false;
return;
}
try {
await Promise.all(promiseList.map((fn) => fn()));
this.formLoading = false;
this.dataLoaded = true;
// console.log("[dialogForm:handleOptions:optionListOf]", this.optionListOf)
} catch (error) {
console.log('[dialogForm:handleOptions:error]', error);
this.formLoading = false;
}
if (!promiseList.length) this.formLoading = false;
},
// 上传成功的特殊处理
beforeUpload() {},
// 上传前的验证规则可通过 bind 属性传入
handleUploadSuccess(response, file, fileList) {
console.log(
'[dialogForm:handleUploadSuccess]',
response,
file,
fileList,
this.form
);
// 保存原始文件名
if ('fileNames' in this.form) this.form.fileNames.push(file.name);
// 保存完整地址
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.$modal.msgSuccess('上传成功');
},
getFileName(fileUrl) {
return fileUrl.split('/').pop();
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@@ -29,23 +29,28 @@
<section v-for="(section, index) in sections" :key="section.key">
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
<div class="form-part" v-if="section.key == 'base'">
<div
class="form-part"
v-if="section.key == 'base'"
style="margin-bottom: 32px">
<el-skeleton v-if="!showForm" animated />
<DialogForm
<EquipmentInfoForm
key="drawer-dialog-form"
v-if="showForm"
ref="form"
:dataForm="form"
:rows="formRows" />
:disabled="mode.includes('detail')"
:sync-filelist="syncFileListFlag"
v-model="form" />
</div>
<div v-if="section.key == 'attrs'" style="margin-top: 12px">
<base-table
v-loading="attrListLoading"
:table-props="section.props"
:page="section.pageNo || 1"
:limit="section.pageSize || 10"
:page="attrQuery?.params.pageNo || 1"
:limit="attrQuery?.params.pageSize || 10"
:table-data="list"
:add-button-show="mode.includes('detail') ? null : '添加属性'"
@emitButtonClick="handleAddAttr"
@emitFun="handleEmitFun">
<method-btn
v-if="section.tableBtn"
@@ -54,27 +59,31 @@
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="attrQuery.params.pageNo"
:limit.sync="attrQuery.params.pageSize"
@pagination="getAttrList" />
</div>
</section>
</div>
<div class="drawer-body__footer">
<el-button style="margin-right: 10px" @click="handleCancel">
返回
</el-button>
<el-button style="" @click="handleCancel">取消</el-button>
<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
编辑
</el-button>
<span v-else>
<el-button type="primary" @click="handleSave">保存</el-button>
<el-button v-else type="primary" @click="handleConfirm">确定</el-button>
<!-- sections的第二项必须是 属性列表 -->
<el-button
<!-- <el-button
v-if="sections[1].allowAdd"
type="primary"
@click="handleAddAttr">
添加属性
</el-button>
</span>
</el-button> -->
</div>
</div>
@@ -99,11 +108,13 @@
</template>
<script>
import DialogForm from '@/components/DialogForm';
import DialogForm from './DialogForm';
import EquipmentInfoForm from './EquipmentInfoForm.vue';
const SmallTitle = {
name: 'SmallTitle',
props: ['size'],
components: {},
data() {
return {};
},
@@ -127,12 +138,13 @@ const SmallTitle = {
};
export default {
components: { SmallTitle, DialogForm },
components: { SmallTitle, DialogForm, EquipmentInfoForm },
props: ['sections', 'mode', 'dataId'], // dataId 作为一个通用的存放id的字段
data() {
return {
visible: false,
showForm: false,
btnLoading: false,
total: 0,
form: {},
list: [],
@@ -161,10 +173,16 @@ export default {
},
],
],
attrQuery: null, // 属性列表的请求
attrQuery: {
params: {
pageNo: 1,
pageSize: 10,
},
}, // 属性列表的请求
infoQuery: null, // 基本信息的请求
attrFormSubmitting: false,
attrListLoading: false,
syncFileListFlag: null,
};
},
computed: {
@@ -175,15 +193,19 @@ export default {
// 重置图片的位置
return {
...col,
bind: {
...col.bind,
},
style: {
left: 0,
right: 'unset'
}
}
right: 'unset',
},
};
}
return {
...col,
bind: {
...col.bind,
// 详情 模式下,禁用各种输入
disabled: this.mode == 'detail',
},
@@ -208,9 +230,52 @@ export default {
this.$axios(query).then(({ data }) => {
if (section.key == 'base') {
this.form = data;
// this.form = {
// code: 'gj',
// name: '下片机',
// enName: 'unload',
// abbr: '',
// equipmentTypeId: 21084,
// remark: '备注',
// id: '1712367395052384257',
// createTime: 1697095176000,
// enterTime: 0,
// productionTime: 0,
// files: [
// {
// fileName: '测试.xlsx',
// fileUrl: 'https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0108%2F0f0c6f30j00r5cle9000sc000hs00gtc.jpg&thumbnail=660x2147483647&quality=80&type=jpg',
// fileType: 1
// },
// {
// fileName: '测试2.xlsx',
// fileUrl: 'https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0415%2F2cd23619j00racb96000kc000hs00hsc.jpg&thumbnail=660x2147483647&quality=80&type=jpg',
// fileType: 1
// },
// {
// fileName: '测试3.xlsx',
// fileUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1fea91a0-d088-409e-b145-e0e61254b28b%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700031689&t=2e0fe7d1de7f54adff3007efe133d67c',
// fileType: 1
// },
// {
// fileName: '测试4.xlsx',
// fileUrl: 'https://pics5.baidu.com/feed/b7003af33a87e950cdfb4b4546eed044faf2b40d.jpeg?token=1d7484cfe4b014dd201f8c8725cab945',
// fileType: 2
// },
// {
// fileName: '测试5.xlsx',
// fileUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Fe3500876-9c46-4b70-8d37-4799520cdd13%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700031689&t=4abc1df930e62730e5361a7d3765e0f2',
// fileType: 2
// },
// ],
// tvalue: 0,
// processingTime: 0,
// manufacturer: '',
// spec: '',
// description: '描述',
// };
this.showForm = true;
this.infoQuery = query;
console.log('setting form: ', this.form, data);
} else if (section.key == 'attrs') {
this.attrQuery = query;
this.list = data.list;
@@ -231,6 +296,24 @@ export default {
break;
}
},
async handleConfirm() {
this.btnLoading = true;
this.syncFileListFlag = Math.random();
this.$nextTick(async () => {
const { code, data } = await this.$axios({
url: this.sections[0].urlUpdate,
method: 'put',
data: this.form,
});
if (code == 0) {
this.$modal.msgSuccess('更新成功');
}
this.btnLoading = false;
this.handleCancel();
});
},
handleEmitFun(val) {
console.log('handleEmitFun', val);
@@ -273,7 +356,7 @@ export default {
// 开启编辑
toggleEdit() {
this.mode = 'edit';
this.$emit('update-mode', 'edit');
},
// 新增属性
@@ -331,17 +414,19 @@ export default {
},
// 提交属性表
async submitAttrForm() {
this.$refs['attrForm'].validate((valid) => {
submitAttrForm() {
this.$refs['attrForm'].validate(async (valid) => {
if (!valid) {
return;
}
});
console.log('this.attrform', this.attrForm);
try {
const isEdit = this.attrForm.id != null;
this.attrFormSubmitting = true;
const res = await this.$axios({
url: isEdit ? this.sections[1].urlUpdate : this.sections[1].urlCreate,
url: isEdit
? this.sections[1].urlUpdate
: this.sections[1].urlCreate,
method: isEdit ? 'put' : 'post',
data: this.attrForm,
});
@@ -358,6 +443,15 @@ export default {
});
}
this.attrFormSubmitting = false;
} catch (err) {
this.$message({
message: err,
type: 'error',
duration: 1500,
});
this.attrFormSubmitting = false;
}
});
},
closeAttrForm() {

View File

@@ -0,0 +1,337 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
class="equipment-info-form"
ref="form"
:model="form"
label-width="200px"
label-position="top"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item
label="设备名称"
prop="name"
:rules="[{ required: true, message: '不能为空', trigger: 'blur' }]">
<el-input
v-model="form.name"
:disabled="disabled"
placeholder="请输入设备名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备编码" prop="code" :rules="[]">
<el-input
v-model="form.code"
:disabled="disabled"
placeholder="请输入设备编码"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="英文名称" prop="enName" :rules="[]">
<el-input
v-model="form.enName"
:disabled="disabled"
placeholder="请输入英文名称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="缩写" prop="abbr" :rules="[]">
<el-input
v-model="form.abbr"
:disabled="disabled"
placeholder="请输入名称缩写"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备类型" prop="equipmentTypeId" :rules="[]">
<el-select
v-model="form.equipmentTypeId"
:disabled="disabled"
filterable
placeholder="请选择设备类型">
<el-option
v-for="eqType in eqTypeList"
:key="eqType.id"
:label="eqType.name"
:value="eqType.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注" prop="remark" :rules="[]">
<el-input
v-model="form.remark"
:disabled="disabled"
placeholder="请输入备注"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="生产日期" prop="productionTime" :rules="[]">
<el-date-picker
v-model="form.enterTime"
:disabled="disabled"
type="datetime"
placeholder="请选择生产日期"
value-format="timestamp"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="进场日期" prop="enterTime" :rules="[]">
<el-date-picker
v-model="form.enterTime"
:disabled="disabled"
type="datetime"
placeholder="请选择进场日期"
value-format="timestamp"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="设备TT值"
prop="tvalue"
:rules="[
{ required: true, message: '不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input
v-model="form.tvalue"
:disabled="disabled"
placeholder="请输入设备TT值"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item
label="产品加工时间(s)"
prop="processingTime"
:rules="[
{ required: true, message: '不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input
v-model="form.processingTime"
:disabled="disabled"
placeholder="请输入产品加工时间"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="制造商" prop="manufacturer" :rules="[]">
<el-input
v-model="form.manufacturer"
:disabled="disabled"
placeholder="请输入制造商"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备规格" prop="spec" :rules="[]">
<el-input
v-model="form.spec"
:disabled="disabled"
placeholder="请输入设备规格"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 功能描述 -->
<el-col>
<el-form-item label="功能描述" prop="description" :rules="[]">
<el-input
type="textarea"
:disabled="disabled"
v-model="form.description"
placeholder="请填写功能描述"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 上传资料 -->
<el-col>
<el-form-item label="上传资料" prop="assets" :rules="[]">
<AssetsUpload v-model="form.assets" :disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 上传图片 -->
<el-col>
<el-form-item label="上传图片" prop="pics" :rules="[]">
<AssetsUpload
:is-pic-mode="true"
v-model="form.pics"
:disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import AssetsUpload from './AssetsUpload.vue';
export default {
name: 'EquipmentInfoForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: { AssetsUpload },
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
syncFilelist: {
type: Number,
default: null,
required: false,
},
},
data() {
return {
formLoading: false,
form: {
name: '',
code: '',
enName: '',
abbr: '',
equipmentTypeId: '',
remark: '',
productionTime: '',
enterTime: '',
tvalue: '',
processingTime: '',
manufacturer: '',
spec: '',
description: '',
assets: [],
pics: [],
},
eqTypeList: [],
dataLoaded: false,
};
},
watch: {
dataForm: {
handler(val) {
// debugger;
this.form = JSON.parse(JSON.stringify(val));
this.form.assets =
this.form.files?.filter((item) => item.fileType == '2') || [];
this.form.pics =
this.form.files?.filter((item) => item.fileType == '1') || [];
delete this.form.files;
},
immediate: true,
deep: true,
},
syncFilelist: {
handler(val) {
if (val != null) {
this.updateForm();
}
},
immediate: true,
},
},
mounted() {
this.getEqTypeList();
},
methods: {
updateForm() {
console.log('update form ==> ');
this.form.files = [...this.form.assets, ...this.form.pics];
delete this.form.assets;
delete this.form.pics;
this.$emit('update', this.form);
},
async getEqTypeList() {
this.formLoading = true;
const { code, data } = await this.$axios(
'/base/equipment-type/page?pageNo=1&pageSize=100'
);
// debugger;
if (code == 0) {
this.eqTypeList = data.list;
}
this.formLoading = false;
},
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
// 上传成功的特殊处理
beforeUpload() {},
// 上传前的验证规则可通过 bind 属性传入
handleUploadSuccess(response, file, fileList) {
console.log(
'[dialogForm:handleUploadSuccess]',
response,
file,
fileList,
this.form
);
// 保存原始文件名
if ('fileNames' in this.form) this.form.fileNames.push(file.name);
// 保存完整地址
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.$modal.msgSuccess('上传成功');
},
getFileName(fileUrl) {
return fileUrl.split('/').pop();
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@@ -16,6 +16,7 @@
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
@@ -35,13 +36,16 @@
:dialogVisible="open"
@close="cancel"
@cancel="cancel"
width="60%"
@confirm="submitForm">
<DialogForm
v-if="open"
key="index-dialog-form"
ref="form"
label-position="top"
size="small"
:dataForm="form"
:rows="rows" />
:rows="computedRows" />
</base-dialog>
<!-- 设备 详情 - 编辑 -->
@@ -49,12 +53,13 @@
v-if="editVisible"
ref="drawer"
:mode="editMode"
@update-mode="editMode = $event"
:data-id="form.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: rows,
rows: computedRows,
url: '/base/equipment/get',
urlUpdate: '/base/equipment/update',
urlCreate: '/base/equipment/create',
@@ -92,8 +97,8 @@
},
]"
@refreshDataList="getList"
@cancel="editVisible = false"
@destroy="editVisible = false" />
@cancel="cancelEdit"
@destroy="cancelEdit" />
</div>
</template>
@@ -114,6 +119,7 @@ import {
exportEquipmentExcel,
} from '@/api/base/equipment';
import Editor from '@/components/Editor';
import AssetsUpload from './components/AssetsUpload.vue';
export default {
name: 'Equipment',
@@ -138,6 +144,12 @@ export default {
btnName: '删除',
}
: undefined,
this.$auth.hasPermi(`base:equipment:update`)
? {
type: 'detail',
btnName: '详情',
}
: undefined,
].filter((v) => v),
tableProps: [
{
@@ -147,38 +159,37 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '设备名称', align: 'center' },
{ prop: 'code', label: '检测编码', align: 'center' },
{ prop: 'equipmentType', label: '设备类型', align: 'center' },
{ prop: 'enName', label: '英文名称', align: 'center' },
{ prop: 'abbr', label: '缩写', align: 'center' },
{
action: 'show-detail',
label: '详情',
align: 'center',
subcomponent: {
props: ['injectData'],
render: function (h) {
const _this = this;
return h(
'el-button',
{
props: { type: 'text', size: 'mini' },
on: {
click: function () {
console.log('inejctdata', _this.injectData);
_this.$emit('emitData', {
action: _this.injectData.action,
value: _this.injectData.id,
});
},
},
},
'查看详情'
);
},
},
},
{ prop: 'name', label: '设备名称' },
{ width: 256, prop: 'code', label: '设备编码' },
{ prop: 'equipmentType', label: '设备类型' },
{ prop: 'enName', label: '英文名称' },
{ prop: 'abbr', label: '缩写' },
// {
// action: 'show-detail',
// label: '详情',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text', size: 'mini' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData.action,
// value: _this.injectData.id,
// });
// },
// },
// },
// '查看详情'
// );
// },
// },
// },
],
searchBarFormConfig: [
{
@@ -233,8 +244,6 @@ export default {
prop: 'code',
url: '/base/equipment/getCode',
},
],
[
{
input: true,
label: '英文名称',
@@ -244,6 +253,8 @@ export default {
// disabled: true, // some condition, like detail mode...
// }
},
],
[
{
input: true,
label: '缩写',
@@ -253,13 +264,15 @@ export default {
// disabled: true, // some condition, like detail mode...
// }
},
],
[
{
select: true,
label: '设备类型',
prop: 'equipmentTypeId',
url: '/base/equipment-type/page?pageNo=1&pageSize=100',
bind: {
filterable: true,
},
},
// {
// select: true,
@@ -280,8 +293,6 @@ export default {
label: '进厂日期',
prop: 'enterTime',
},
],
[
{
input: true,
prop: 'tvalue',
@@ -296,11 +307,14 @@ export default {
},
],
},
],
[
{
input: true,
label: '产品加工时间',
label: '产品加工时间s',
prop: 'processingTime',
rules: [
{ required: true, message: '不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
@@ -309,8 +323,7 @@ export default {
},
],
},
],
[
{
input: true,
label: '制造商',
@@ -331,40 +344,79 @@ export default {
prop: 'description',
},
],
[
{
upload: true,
label: '上传资料',
prop: 'uploadFiles',
url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址
bind: {
headers: { Authorization: 'Bearer ' + getAccessToken() },
'show-file-list': false,
},
},
],
[
{
diy: true,
key: 'eq-assets',
label: '设备资料',
prop: 'fileNames',
subcomponent: EquipmentAssets,
},
],
[
{
diy: true,
key: 'eq-pics',
label: '设备图片',
prop: 'fileUrls',
subcomponent: EquipmentPics,
pictures: async () => {
// some async request
return [];
},
},
],
// [
// {
// assetUpload: true,
// label: '上传资料',
// fieldName: 'assets',
// subcomponent: AssetsUpload
// },
// ],
// [
// {
// assetUpload: true,
// label: '上传图片',
// fieldName: 'images',
// subcomponent: AssetsUpload
// },
// ],
// [
// {
// upload: true,
// label: '上传资料',
// prop: 'uploadFiles',
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址
// uploadFnName: 'assetsUpload', // 上传方法名
// bind: {
// headers: { Authorization: 'Bearer ' + getAccessToken() },
// 'show-file-list': false,
// },
// },
// {
// diy: true,
// key: 'eq-assets',
// label: '设备资料',
// prop: 'fileNames',
// subcomponent: EquipmentAssets,
// },
// ],
// [
// {
// upload: true,
// label: '上传图片',
// prop: 'uploadImages',
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址
// uploadFnName: 'imagesUpload', // 上传方法名
// bind: {
// headers: { Authorization: 'Bearer ' + getAccessToken() },
// 'show-file-list': false,
// },
// },
// {
// diy: true,
// key: 'eq-pics',
// label: '设备图片',
// prop: 'fileUrls',
// subcomponent: EquipmentPics,
// pictures: async () => {
// // some async request
// return [];
// },
// },
// ],
// [
// {
// diy: true,
// key: 'eq-pics',
// label: '设备图片',
// prop: 'fileUrls',
// subcomponent: EquipmentPics,
// pictures: async () => {
// // some async request
// return [];
// },
// },
// ],
],
editVisible: false,
editMode: 'edit', // 'edit', 'detail'
@@ -377,8 +429,8 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '属性名称', align: 'center' },
{ prop: 'value', label: '属性值', align: 'center' },
{ prop: 'name', label: '属性名称' },
{ prop: 'value', label: '属性值' },
],
// 是否显示弹出层
open: false,
@@ -393,11 +445,49 @@ export default {
form: {
id: null,
},
showUploadComponents: false, // 是否显示上传组件
};
},
created() {
this.getList();
},
computed: {
computedRows() {
return this.showUploadComponents
? [
...this.rows,
[
{
assetUpload: true,
key: 'eq-assets', // 用于区分不同的上传组件
label: '上传资料',
fieldName: 'assets',
subcomponent: AssetsUpload,
prop: 'uploadedAssets',
default: [],
bind: {
'is-pic-mode': false,
},
},
],
[
{
assetUpload: true,
key: 'eq-pics', // 用于区分不同的上传组件
label: '上传图片',
fieldName: 'images',
subcomponent: AssetsUpload,
// prop: '',
// default: [],
bind: {
'is-pic-mode': true,
},
},
],
]
: this.rows;
},
},
methods: {
/** 查询列表 */
getList() {
@@ -414,6 +504,10 @@ export default {
this.open = false;
this.reset();
},
cancelEdit() {
this.showUploadComponents = false;
this.editVisible = false;
},
/** 表单重置 */
reset() {
this.form = {
@@ -439,11 +533,13 @@ export default {
handleAdd() {
this.reset();
this.open = true;
this.showUploadComponents = false;
this.title = '添加设备';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.showUploadComponents = true;
const id = row.id;
getEquipment(id).then((response) => {
this.form = response.data;
@@ -478,7 +574,7 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备编号为"' + id + '"的数据项?')
.confirm('是否确认删除设备名称为"' + row.name + '"的数据项?')
.then(function () {
return deleteEquipment(id);
})
@@ -510,6 +606,7 @@ export default {
viewDetail(id) {
this.reset();
this.editMode = 'detail';
this.showUploadComponents = true;
this.form.id = id;
this.editVisible = true;
this.$nextTick(() => {
@@ -518,11 +615,11 @@ export default {
},
// overwrite basicPageMixin 里的 处理表格按钮 方法
handleTableBtnClick({ data, type }) {
console.log('[handleTableBtnClick]', data, type);
switch (type) {
case 'edit':
this.reset();
this.editMode = 'edit';
this.showUploadComponents = true;
this.form.id = data.id;
this.editVisible = true;
this.$nextTick(() => {
@@ -532,6 +629,10 @@ export default {
case 'delete':
this.handleDelete(data);
break;
case 'detail':
const { id } = data;
this.viewDetail(id);
break;
}
},
},

View File

@@ -17,6 +17,7 @@
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="120"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
@@ -36,7 +37,7 @@
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
<DialogForm v-if="open" ref="form" v-model="form" :rows="rows" />
</base-dialog>
</div>
</template>
@@ -54,7 +55,7 @@ import {
exportEquipmentTypeExcel,
} from '@/api/base/equipmentType';
import { getAccessToken } from '@/utils/auth';
// import { getAccessToken } from '@/utils/auth';
export default {
name: 'EquipmentType',
@@ -85,9 +86,9 @@ export default {
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '设备类型名称', align: 'center' },
{ prop: 'code', label: '检测类型编码', align: 'center' },
{ prop: 'remark', label: '备注', align: 'center' },
{ prop: 'name', label: '设备类型名称' },
{ prop: 'code', label: '检测类型编码' },
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
@@ -148,15 +149,13 @@ export default {
prop: 'parentId',
url: '/base/equipment-type/page?pageNo=1&pageSize=100',
},
{},
],
[
{
upload: true,
label: '上传资料',
prop: 'uploadFiles',
url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址
bind: {
headers: { Authorization: 'Bearer ' + getAccessToken() },
'show-file-list': false,
},
prop: 'files',
},
],
[{ input: true, label: '备注', prop: 'remark' }],
@@ -235,6 +234,25 @@ export default {
const id = row.id;
getEquipmentType(id).then((response) => {
this.form = response.data;
// this.form = {
// code: 'SBLX20230925184444000041',
// name: '测试131',
// remark: '测试可删除',
// id: '1706258479729336322',
// files: [
// { fileName: '1.png', fileUrl: '', fileType: 2 },
// { fileName: '1.asdfaslkjfkasdf.png', fileUrl: '', fileType: 2 },
// { fileName: '2.txt', fileUrl: '', fileType: 2 },
// { fileName: '1.rar', fileUrl: '', fileType: 2 },
// { fileName: '1.kkk', fileUrl: '', fileType: 2 },
// { fileName: 'test.file', fileUrl: '', fileType: 2 },
// { fileName: '222', fileUrl: '', fileType: 2 },
// { fileName: 'g', fileUrl: '', fileType: 2 },
// ],
// createTime: 1695638697000,
// parentId: '1701869972319584257',
// };
// debugger;
this.open = true;
this.title = '修改设备类型';
});
@@ -266,7 +284,7 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备类型编号为"' + id + '"的数据项?')
.confirm('是否确认删除设备类型"' + row.name + '"?')
.then(function () {
return deleteEquipmentType(id);
})

View File

@@ -1,8 +1,8 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:59:06
* @LastEditors: DY
* @LastEditTime: 2023-10-16 11:16:48
* @Description:
-->
<template>
@@ -12,21 +12,30 @@
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="80px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工厂编码" prop="code">
<el-input
v-model="dataForm.code"
clearable
placeholder="请输入工厂编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工厂名称" prop="name">
<el-input
v-model="dataForm.name"
clearable
placeholder="请输入工厂名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="地址" prop="address">
<el-input v-model="dataForm.address" clearable placeholder="请输入地址" />
</el-form-item>
</el-col>
<!-- <el-form-item label="启用状态" prop="enabled">
<el-select
v-model="dataForm.enabled"
@@ -38,9 +47,12 @@
:value="dict.value" />
</el-select>
</el-form-item> -->
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="dataForm.remark" clearable placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

View File

@@ -29,7 +29,7 @@
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="70%">
width="50%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
@@ -50,29 +50,24 @@ import {
const tableProps = [
{
prop: 'code',
label: '工厂编码',
align: 'center',
label: '工厂编码'
},
{
prop: 'name',
label: '工厂名称',
align: 'center',
label: '工厂名称'
},
{
prop: 'address',
label: '地址',
align: 'center',
label: '地址'
},
{
prop: 'remark',
label: '备注',
align: 'center',
label: '备注'
},
{
prop: 'createTime',
label: '创建时间',
align: 'center',
filter: parseTime,
filter: parseTime
},
];
@@ -120,14 +115,14 @@ export default {
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '重置',
name: 'reset',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{
type: 'separate',
},

View File

@@ -1,16 +1,15 @@
<!--
* @Author: zwq
* @Date: 2023-08-02 15:12:42
* @LastEditors: zwq
* @LastEditTime: 2023-08-03 14:24:36
* @LastEditors: DY
* @LastEditTime: 2023-10-13 16:35:03
* @Description:
-->
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
:formConfigs="[{ label: '产线在制产品', type: 'title' }]"
ref="searchBarForm" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
@@ -36,20 +35,17 @@ import { getProductPage } from '@/api/core/base/product';
const tableProps = [
{
prop: 'lineName',
label: '产线',
align: 'center',
label: '产线'
},
{
prop: 'productName',
label: '在制产品',
align: 'center',
list: [],
subcomponent: selectProduct,
},
{
prop: 'recordTime',
label: '开始时间',
align: 'center',
filter: parseTime,
},
];
@@ -63,14 +59,14 @@ export default {
},
tableProps,
tableData: [],
formConfig: [
{
type: 'button',
btnName: '同步',
name: 'search',
color: 'primary',
},
],
// formConfig: [
// {
// type: 'button',
// btnName: '同步',
// name: 'search',
// color: 'primary',
// },
// ],
};
},
components: {},
@@ -81,6 +77,7 @@ export default {
};
getProductPage(params).then((response) => {
this.tableProps[1].list = response.data.list;
console.log('打印', this.tableProps[1].list)
});
},
methods: {

View File

@@ -1,13 +1,12 @@
<!--
* @Author: zwq
* @Date: 2023-08-03 14:09:18
* @LastEditors: zwq
* @LastEditTime: 2023-08-03 14:51:16
* @LastEditors: DY
* @LastEditTime: 2023-10-13 16:47:25
* @Description:
-->
<template>
<div class="tableInner">
<el-input readonly v-model="list.productName" style="width: 50%;" ></el-input>
<el-popover
placement="top"
title="切换在制产品"
@@ -28,8 +27,11 @@
确定
</el-button>
</div>
<el-button type="text" slot="reference">切换</el-button>
<el-button type="text" slot="reference">
<svg-icon icon-class="changelogo"/>
</el-button>
</el-popover>
<el-input readonly v-model="list.productName" style="width: 50%;margin-left: 5px" ></el-input>
</div>
</template>
<script>
@@ -48,6 +50,9 @@ export default {
visible: false,
};
},
mounted() {
console.log('hello', this.list)
},
methods: {
changeInput() {
const data = {
@@ -58,6 +63,7 @@ export default {
switchLineBindProduct(data).then((response) => {
this.$modal.msgSuccess('修改成功');
this.visible = false;
this.list.productName = this.list.string.split('+')[1]
this.$emit('emitData');
});
},

View File

@@ -28,24 +28,20 @@ import { getProductPage } from '@/api/core/base/product';
const tableProps = [
{
prop: 'productionLineName',
label: '产线',
align: 'center',
label: '产线'
},
{
prop: 'productName',
label: '在制产品',
align: 'center',
label: '在制产品'
},
{
prop: 'startTime',
label: '开始时间',
align: 'center',
filter: parseTime,
},
{
prop: 'endTime',
label: '结束时间',
align: 'center',
filter: parseTime,
},
];
@@ -86,7 +82,8 @@ export default {
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'createTime',
param: 'startTime',
valueFormat: 'timestamp'
},
{
type: 'button',
@@ -126,7 +123,7 @@ export default {
this.listQuery.pageSize = 10;
this.listQuery.productionLineId = val.productionLineId;
this.listQuery.productId = val.productId;
this.listQuery.createTime = val.createTime;
this.listQuery.startTime = val.startTime;
this.getDataList();
break;
case 'reset':

View File

@@ -111,6 +111,8 @@
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:add-button-show="isdetail ? null : '添加属性'"
@emitButtonClick="addNew()"
:table-data="productAttributeList">
<method-btn
v-if="!isdetail"
@@ -123,15 +125,15 @@
<pagination
v-show="listQuery.total > 0"
:total="listQuery.total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
:page.sync="listQuery.pageNo"
:limit.sync="listQuery.pageSize"
:page-sizes="[5, 10, 15]"
@pagination="getList" />
</div>
</div>
</div>
<div style="position: absolute; bottom: 24px; right: 24px">
<!-- <div style="position: absolute; bottom: 24px; right: 24px">
<el-button style="margin-right: 10px" @click="goback()">返回</el-button>
<el-button v-if="isdetail" type="primary" @click="goEdit()">
编辑
@@ -145,6 +147,14 @@
添加属性
</el-button>
</span>
</div> -->
<div class="drawer-body__footer">
<el-button style="" @click="goback()">取消</el-button>
<el-button v-if="isdetail" type="primary" @click="goEdit()">
编辑
</el-button>
<el-button v-else type="primary" @click="dataFormSubmit()">确定</el-button>
</div>
<product-attr-add
@@ -250,12 +260,12 @@ export default {
},
],
area: [
// {
// type: 'float',
// message: '单位平方数为浮点类型',
// trigger: 'blur',
// transfom: 'val => Float(val)',
// },
{
type: 'number',
message: '请输入正确的数值',
trigger: 'change',
transform: (val) => Number(val),
},
],
processTime: [
{
@@ -263,12 +273,12 @@ export default {
message: '完成单位产品用时不能为空',
trigger: 'blur',
},
// {
// type: 'number',
// message: '完成单位产品用时为浮点类型',
// trigger: 'blur',
// transfom: 'val => Number(val)',
// },
{
type: 'number',
message: '请输入正确的数值',
trigger: 'blur',
transform: (val) => Number(val),
},
],
},
isdetail: false,
@@ -277,6 +287,7 @@ export default {
methods: {
initData() {
this.productAttributeList.splice(0);
this.listQuery.total = 0;
},
init(id, isdetail) {
this.initData();
@@ -304,12 +315,10 @@ export default {
getList() {
// 获取产品的属性列表
const params = {
pageSize: 10,
pageNo: 1,
getProductAttrPage({
...this.listQuery,
productId: this.dataForm.id,
};
getProductAttrPage(params).then((response) => {
}).then((response) => {
this.productAttributeList = response.data.list;
this.listQuery.total = response.data.total;
});
@@ -390,6 +399,8 @@ export default {
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
display: flex;
flex-direction: column;
}
.drawer >>> .el-form-item__label {
@@ -400,14 +411,20 @@ export default {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 30px;
}
.drawer >>> .el-drawer__body {
flex: 1;
height: 1px;
display: flex;
flex-direction: column;
}
.drawer >>> .content {
padding: 0 24px 30px;
padding: 30px 24px;
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
/* height: 100%; */
}
.drawer >>> .visual-part {
@@ -422,4 +439,10 @@ export default {
.drawer >>> .attr-list {
padding: 0 16px;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@@ -1,8 +1,8 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 14:55:51
* @LastEditors: zwq
* @LastEditTime: 2023-08-03 15:22:53
* @LastEditors: DY
* @LastEditTime: 2023-10-13 10:27:00
* @Description:
-->
<template>
@@ -50,30 +50,25 @@ import {
const tableProps = [
{
prop: 'code',
label: '产品编码',
align: 'center',
label: '产品编码'
},
{
prop: 'name',
label: '产品名称',
align: 'center',
label: '产品名称'
},
{
prop: 'specifications',
label: '规格',
align: 'center',
label: '规格'
},
{
prop: 'unitDictValue',
label: '单位',
align: 'center',
subcomponent: unitDict,
},
{
prop: 'createTime',
label: '创建时间',
align: 'center',
filter: parseTime,
filter: parseTime
},
];
@@ -127,14 +122,14 @@ export default {
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '重置',
name: 'reset',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{
type: 'separate',
},

View File

@@ -1,53 +1,90 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 13:52:10
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:59:35
* @LastEditors: DY
* @LastEditTime: 2023-09-21 15:45:07
* @Description:
-->
<template>
<el-form
class="dialog-inner__form"
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="90px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产线编码" prop="code">
<el-input
v-model="dataForm.code"
clearable
placeholder="请输入产线编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产线名称" prop="name">
<el-input
v-model="dataForm.name"
clearable
placeholder="请输入产线名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="factoryId" label="工厂名称">
<el-select
v-model="dataForm.factoryId" filterable clearable placeholder="请选择工厂">
v-model="dataForm.factoryId"
filterable
clearable
placeholder="请选择工厂">
<el-option
v-for="item in urlOptions.optionArr.arr0"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产线TT值(h)" prop="tvalue">
<el-input v-model="dataForm.tvalue" clearable placeholder="请输入每小时下片数量" />
<el-input
v-model="dataForm.tvalue"
clearable
placeholder="请输入每小时下片数量" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="额外编码" prop="externalCode">
<el-input
v-model="dataForm.externalCode"
clearable
placeholder="请输入额外编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input
v-model="dataForm.remark"
clearable
placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="描述" prop="description">
<el-input
v-model="dataForm.description"
type="textarea"
placeholder="请输入内容" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="dataForm.remark" clearable placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
@@ -59,9 +96,7 @@ import {
getProductionLine,
getCode,
} from '@/api/core/base/productionLine';
import {
getFactoryPage,
} from '@/api/core/base/factory';
import { getFactoryPage } from '@/api/core/base/factory';
export default {
mixins: [basicAdd],
@@ -82,6 +117,7 @@ export default {
name: undefined,
tvalue: undefined,
factoryId: undefined,
externalCode: undefined,
remark: undefined,
description: undefined,
},
@@ -95,10 +131,23 @@ export default {
factoryId: [
{ required: true, message: '工厂不能为空', trigger: 'change' },
],
tvalue: [
{
type: 'number',
message: '请输入正确的数字',
trigger: 'change',
transform: (val) => Number(val),
},
],
},
};
},
methods: {
},
methods: {},
};
</script>
<style scoped>
.dialog-inner__form >>> .el-select {
width: 100%;
}
</style>

View File

@@ -29,7 +29,7 @@
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="70%">
width="50%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
@@ -52,45 +52,37 @@ import {
const tableProps = [
{
prop: 'code',
label: '产线编码',
align: 'center',
label: '产线编码'
},
{
prop: 'name',
label: '产线名称',
align: 'center',
label: '产线名称'
},
{
prop: 'factoryName',
label: '工厂',
align: 'center',
label: '工厂'
},
{
prop: 'externalCode',
label: '额外编码',
align: 'center',
label: '额外编码'
},
{
prop: 'status',
label: '当前状态',
align: 'center',
filter: codeFilter('lineStatus'),
},
{
prop: 'description',
label: '描述',
align: 'center',
label: '描述'
},
{
prop: 'remark',
label: '备注',
align: 'center',
label: '备注'
},
{
prop: 'createTime',
label: '创建时间',
align: 'center',
filter: parseTime,
filter: parseTime
},
];
@@ -132,14 +124,14 @@ export default {
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '重置',
name: 'reset',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{
type: 'separate',
},
@@ -173,7 +165,7 @@ export default {
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then((response) => {
this.total = response.data.total;
this.listQuery.total = response.data.total;
this.getStatus(response.data.list);
this.dataListLoading = false;
});
@@ -195,7 +187,7 @@ export default {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;.7
this.listQuery.pageSize = 10;
this.listQuery.name = val.name;
this.getDataList();
break;

View File

@@ -1,8 +1,8 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 13:52:10
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:58:44
* @LastEditors: DY
* @LastEditTime: 2023-10-16 13:40:00
* @Description:
-->
<template>
@@ -12,18 +12,26 @@
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="90px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工段编码" prop="code">
<el-input
v-model="dataForm.code"
clearable
placeholder="请输入工段编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工段名称" prop="name">
<el-input
v-model="dataForm.name"
clearable
placeholder="请输入工段名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="productionLineId" label="产线">
<el-select
v-model="dataForm.productionLineId" filterable clearable placeholder="请选择产线">
@@ -36,9 +44,13 @@
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序" prop="sort">
<el-input-number v-model="dataForm.sort" :min="1" clearable placeholder="请输入排序" />
<el-input-number v-model="dataForm.sort" :min="1" :max="100" clearable placeholder="请输入排序" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input v-model="dataForm.remark" clearable placeholder="请输入备注" />
</el-form-item>

View File

@@ -29,7 +29,7 @@
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="70%">
width="50%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
@@ -50,34 +50,28 @@ import {
const tableProps = [
{
prop: 'code',
label: '工段编码',
align: 'center',
label: '工段编码'
},
{
prop: 'name',
label: '工段名称',
align: 'center',
label: '工段名称'
},
{
prop: 'productionLineName',
label: '产线',
align: 'center',
label: '产线'
},
{
prop: 'sort',
label: '排序',
align: 'center',
label: '排序'
},
{
prop: 'remark',
label: '备注',
align: 'center',
label: '备注'
},
{
prop: 'createTime',
label: '创建时间',
align: 'center',
filter: parseTime,
filter: parseTime
},
];
@@ -119,14 +113,14 @@ export default {
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '重置',
name: 'reset',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{
type: 'separate',
},

View File

@@ -1,8 +1,8 @@
/*
* @Author: zwq
* @Date: 2022-08-24 11:19:43
* @LastEditors: zwq
* @LastEditTime: 2023-08-02 10:56:37
* @LastEditors: DY
* @LastEditTime: 2023-09-21 16:02:07
* @Description:
*/
export default {
@@ -38,7 +38,7 @@ export default {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data.list;
this.total = response.data.total;
this.listQuery.total = response.data.total;
this.dataListLoading = false;
});
},

View File

@@ -1,8 +1,8 @@
/*
* @Date: 2020-12-29 16:49:28
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 11:10:04
* @LastEditors: DY
* @LastEditTime: 2023-09-12 11:13:34
* @FilePath: \basic-admin\src\filters\basicData\index.js
* @Description:
*/
@@ -13,6 +13,11 @@ const table = {
2: '停止',
3: '未知',
},
reportType: {
1: '日',
2: '周',
3: '月'
}
}
// 日期格式化

View File

@@ -1,7 +1,7 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-09-11 15:52:20
* @LastEditTime: 2023-10-16 15:10:42
* @LastEditors: DY
* @Description:
-->
@@ -12,122 +12,99 @@
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:selectWidth="55"
:table-data="tableData"
:table-data="showData"
@selection-change="selectChange"
>
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<!-- <div>
<el-button @click="down()">1111</el-button>
<el-table :data="tableData1" stripe style="width: 100%">
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="address" label="地址" />
</el-table>
@pagination="getDataList"
/>
<!-- <div v-show="false" ref="pdf">
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="selectedList"
/>
</div> -->
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<el-button type="primary" @click="exportXlsx">xlsx</el-button>
<el-button type="success" @click="exportPdf">pdf</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { parseTime } from '../../mixins/code-filter';
import {
getFactoryPage,
exportFactoryExcel,
} from '@/api/core/base/factory';
import { getPdlAutoReport, getPdList } from '@/api/core/monitoring/auto'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
// import codeFilter from '../../mixins/code-filter'
import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
const tableData1 = [
{
date: '2016-05-03',
name: 'fom',
address: 'No'
},
{
date: '2016-05-02',
name: 'fom',
address: '189'
},
{
date: '2016-0225-03',
name: 'fom',
address: 'Ndddo'
},
{
date: '2016-04445-02',
name: 'fom',
address: '18edd9'
}
]
const tableProps = [
{
prop: 'code',
label: '报表类型',
align: 'center',
prop: 'reportType',
label: '报表类型'
},
{
prop: 'createTime',
prop: 'reportStartTime',
label: '统计开始时间',
align: 'center',
filter: parseTime,
},
{
prop: 'createTime3',
prop: 'reportEndTime',
label: '统计结束时间',
align: 'center',
filter: parseTime,
},
{
prop: 'name',
label: '产线名称',
align: 'center',
prop: 'proLineName',
label: '产线名称'
},
{
prop: 'address',
label: '投入数量/片',
align: 'center',
prop: 'inputNum',
label: '投入数量/片'
},
{
prop: 'remark44',
label: '产出数量/片',
align: 'center',
prop: 'outputNum',
label: '产出数量/片'
},
{
prop: 'remark23',
label: '产出面积/㎡',
align: 'center',
prop: 'outputArea',
label: '产出面积/㎡'
},
{
prop: 'remark145',
label: '损耗数量/片',
align: 'center',
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'remark22',
label: '损耗面积/㎡',
align: 'center',
prop: 'lossArea',
label: '损耗面积/㎡'
},
{
prop: 'remark1',
label: '损耗比例%',
align: 'center',
prop: 'lossRatio',
label: '损耗比例%'
}
];
@@ -135,27 +112,23 @@ export default {
data() {
return {
urlOptions: {
getDataListURL: getFactoryPage,
exportURL: exportFactoryExcel,
getDataListURL: getPdlAutoReport
},
urlOptions: {
getDataListURL: '',
deleteURL: '',
statusUrl: '',
exportURL: ''
},
tableData1,
listQuery: {
pageSize: 10,
pageNo: 1,
total: 1,
},
fileName: '',
exportLoading: false,
dataListLoading: false,
dialogVisible: false,
addOrEditTitle: '',
addOrUpdateVisible: false,
tableProps,
tableBtn: [],
showData: [],
selectedList: [],
// tableBtn: [
// this.$auth.hasPermi(`base:factory:update`)
// ? {
@@ -181,8 +154,21 @@ export default {
{
type: 'select',
label: '报表类型',
selectOptions: [],
param: 'name',
selectOptions: [
{
id: 1,
name: '日'
},
{
id: 2,
name: '周'
},
{
id: 3,
name: '月'
}
],
param: 'reportType',
},
{
type: 'datePicker',
@@ -211,44 +197,127 @@ export default {
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
color: 'primary',
plain: true
}
],
};
},
created() {},
created() {
this.getDataList()
this.getPdLineList()
},
methods: {
down() {
//选中导出时可更改此处数组
const selectedData = this.tableData1.slice(0, 2)
console.log('你好', selectedData, this.tableData1)
//构建导出的表格数据
const exportData = [
{date: '日期', name: '姓名', address: '地址'},
...selectedData
]
//注意表格上绑定id 获取dom元素
const worksheet = XLSX.utils.json_to_sheet(exportData, { skipHeader: true })
const workbook = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1")
const workbookOutput = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' })
try {
FileSaver.saveAs(new Blob([workbookOutput], { type: 'application/octet-stream' }), 'hihi.xlsx')
} catch (e) {
console.log(e)
test() {
var target = document.getElementsByClassName("right-aside")[0]
target.style.background = '#FFFFFF'
var that = this
setTimeout(() => {
html2canvas(target).then(function(canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度
var pageHeight = contentHeight / 592.28 * 841.89
// 未生成pdf的html页面高度
var leftHeight = contentHeight
// 页面偏移
var position = 0
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
console.log('nihc URL', leftHeight, pageHeight)
var pdf = new jsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight)
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.save(that.fileName + '产线产量.pdf')
})
}, 300)
},
exportPdf() {
this.test()
setTimeout(() =>{
this.dialogVisible = false
this.showData = this.tableData
}, 600)
},
exportXlsx() {
this.exportECL()
this.dialogVisible = false
this.showData = this.tableData
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
exportECL() {
let tables = document.querySelector('.el-table').cloneNode(true)
const fix = tables.querySelector('.el-table__fixed')
const fixRight = tables.querySelector('.el-table__fixed-right')
if (fix) {
tables.removeChild(tables.querySelector('.el-table__fixed'))
}
if (fixRight) {
tables.removeChild(tables.querySelector('.el-table__fixed-right'))
}
let exportTable = XLSX.utils.table_to_book(tables)
var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx', bookSST: true, type: 'array'
})
// sheetjs.xlsx为导出表格的标题名称
try {
FileSaver.saveAs(new Blob([exportTableOut], {
type: 'application/octet-stream'
}), this.fileName + '产线产量.xlsx')
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut)
}
return exportTableOut
},
selectChange(val) {
console.log(val)
this.selectedList = val
console.log('勾选数据', this.selectedList)
},
getPdLineList() {
getPdList().then((res) => {
this.formConfig[0].selectOptions = res.data || []
})
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name;
this.listQuery.code = val.code;
this.listQuery.lineId = val.line ? val.line : undefined;
this.listQuery.reportType = val.reportType ? val.reportType : undefined;
this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime()] : undefined;
this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
if (val.timeVal && val.timeVal.length > 0) {
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_'
}
this.getDataList();
break;
case 'export':
@@ -262,9 +331,13 @@ export default {
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data.list;
this.total = response.data.total;
this.tableData = response.data.list.map((item, index) => {
item.reportType = item.reportType === 1 ? '日' : item.reportType === 2 ? '周' : '月'
return item
});
this.listQuery.total = response.data.total;
this.dataListLoading = false;
this.showData = this.tableData
});
},
// 每页数
@@ -279,17 +352,10 @@ export default {
this.getDataList();
},
handleExport() {
// 处理查询参数
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal.confirm('是否确认导出所有数据项?').then(() => {
this.exportLoading = true;
return this.urlOptions.exportURL(params);
}).then(response => {
this.$download.excel(response, '工厂.xls');
this.exportLoading = false;
}).catch(() => { });
if (this.selectedList.length > 0) {
this.showData = this.selectedList
}
this.dialogVisible = true
}
},
};

View File

@@ -1,7 +1,7 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-08-31 15:15:31
* @LastEditTime: 2023-10-16 15:18:23
* @LastEditors: DY
* @Description:
-->
@@ -12,12 +12,14 @@
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:selectWidth="55"
:table-data="tableData"
:table-data="showData"
@selection-change="selectChange"
>
<method-btn
@@ -28,55 +30,62 @@
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<el-button type="primary" @click="exportXlsx">xlsx</el-button>
<el-button type="success" @click="exportPdf">pdf</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {
getFactoryPage,
exportFactoryExcel,
} from '@/api/core/base/factory';
import { getPdlDataSearch, getPdList } from '@/api/core/monitoring/data'
import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
const tableProps = [
{
prop: 'name',
label: '产线名称',
align: 'center',
prop: 'proLineName',
label: '产线名称'
},
{
prop: 'address',
label: '投入数量/片',
align: 'center',
prop: 'inputNum',
label: '投入数量/片'
},
{
prop: 'remark44',
label: '产出数量/片',
align: 'center',
prop: 'outputNum',
label: '产出数量/片'
},
{
prop: 'remark23',
label: '产出面积/㎡',
align: 'center',
prop: 'outputArea',
label: '产出面积/㎡'
},
{
prop: 'remark145',
label: '损耗数量/片',
align: 'center',
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'remark22',
label: '损耗面积/㎡',
align: 'center',
prop: 'lossArea',
label: '损耗面积/㎡'
},
{
prop: 'remark1',
label: '损耗比例%',
align: 'center',
prop: 'lossRate',
label: '损耗比例%'
}
];
@@ -84,28 +93,26 @@ export default {
data() {
return {
urlOptions: {
getDataListURL: getFactoryPage,
exportURL: exportFactoryExcel,
},
urlOptions: {
getDataListURL: '',
deleteURL: '',
statusUrl: '',
exportURL: ''
getDataListURL: getPdlDataSearch
},
tableData: [],
listQuery: {
pageSize: 10,
pageNo: 1,
total: 1,
proLineId: undefined
},
exportLoading: false,
dataListLoading: false,
dialogVisible: false,
addOrEditTitle: '',
addOrUpdateVisible: false,
tableProps,
tableBtn: [],
showData: [],
tableData: [],
selectedList: [],
fileName: '',
formConfig: [
{
type: 'select',
@@ -140,13 +147,115 @@ export default {
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
color: 'primary',
plain: true
}
],
};
},
created() {},
created() {
if (this.$route.params.startTime) {
this.formConfig[1].defaultSelect = [this.$route.params.startTime, this.$route.params.endTime]
}
// const time = new Date()
// this.formConfig[1].defaultSelect = [time, time]
this.getDataList()
this.getPdLineList()
},
methods: {
test() {
var target = document.getElementsByClassName("right-aside")[0]
target.style.background = '#FFFFFF'
var that = this
setTimeout(() => {
html2canvas(target).then(function(canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度
var pageHeight = contentHeight / 592.28 * 841.89
// 未生成pdf的html页面高度
var leftHeight = contentHeight
// 页面偏移
var position = 0
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
console.log('nihc URL', leftHeight, pageHeight)
var pdf = new jsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight)
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.save(that.fileName + '产线产量.pdf')
})
}, 300)
},
exportECL() {
let tables = document.querySelector('.el-table').cloneNode(true)
const fix = tables.querySelector('.el-table__fixed')
const fixRight = tables.querySelector('.el-table__fixed-right')
if (fix) {
tables.removeChild(tables.querySelector('.el-table__fixed'))
}
if (fixRight) {
tables.removeChild(tables.querySelector('.el-table__fixed-right'))
}
let exportTable = XLSX.utils.table_to_book(tables)
var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx', bookSST: true, type: 'array'
})
// sheetjs.xlsx为导出表格的标题名称
try {
FileSaver.saveAs(new Blob([exportTableOut], {
type: 'application/octet-stream'
}), this.fileName + '产线产量.xlsx')
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut)
}
return exportTableOut
},
exportPdf() {
this.test()
setTimeout(() =>{
this.dialogVisible = false
this.showData = this.tableData
}, 600)
},
exportXlsx() {
this.exportECL()
this.dialogVisible = false
this.showData = this.tableData
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
getPdLineList() {
getPdList().then((res) => {
this.formConfig[0].selectOptions = res.data || []
})
},
selectChange(val) {
console.log(val)
this.selectedList = val
@@ -156,8 +265,12 @@ export default {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name;
this.listQuery.code = val.code;
this.listQuery.proLineId = val.line ? val.line : undefined;
this.listQuery.startTime = val.timeVal ? new Date(val.timeVal[0]).getTime() : undefined;
this.listQuery.endTime = val.timeVal ? new Date(val.timeVal[1]).getTime() : undefined;
if (val.timeVal && val.timeVal.length > 0) {
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_'
}
this.getDataList();
break;
case 'export':
@@ -171,9 +284,10 @@ export default {
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data.list;
this.total = response.data.total;
this.tableData = response.data;
this.listQuery.total = response.data.length;
this.dataListLoading = false;
this.showData = this.tableData
});
},
// 每页数
@@ -188,17 +302,10 @@ export default {
this.getDataList();
},
handleExport() {
// 处理查询参数
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal.confirm('是否确认导出所有数据项?').then(() => {
this.exportLoading = true;
return this.urlOptions.exportURL(params);
}).then(response => {
this.$download.excel(response, '工厂.xls');
this.exportLoading = false;
}).catch(() => { });
if (this.selectedList.length > 0) {
this.showData = this.selectedList
}
this.dialogVisible = true
}
},
};

View File

@@ -0,0 +1,210 @@
<!--
filename: index.vue
author: liubin
date: 2023-08-04 14:44:58
description: 设备24小时生产记录
-->
<template>
<div class="app-container">
<SearchBar
:formConfigs="[{ label: '近24小时产线生产数据', type: 'title' }]"
ref="search-bar" />
<el-skeleton v-if="initing" :rows="6" animated />
<!-- :span-method="mergeColumnHandler" -->
<div v-else :class="{ 'no-data-bg': !tableData || tableData.length == 0 }">
<base-table
v-if="tableData && tableData.length > 0"
:table-props="tableProps"
:table-data="tableData"
@emitFun="handleEmitFun"
/>
</div>
</div>
</template>
<script>
import { getPdlDataOneDay } from '@/api/core/monitoring/data24'
export default {
name: 'productionLineData24',
components: {},
props: {},
data() {
return {
urlOptions: {
getDataListURL: getPdlDataOneDay
},
initing: false,
queryParams: {
pageNo: 1,
pageSize: 10,
},
list: [],
arr: [],
spanArr: [],
timeList: [],
tableData: [],
tableProps: [],
spanInfo: {},
};
},
computed: {},
mounted() {
this.getList();
},
methods: {
/** 构建tableProps - 依据第一个元素所提供的信息 */
buildProps(plData) {
plData.forEach(item => {
this.timeList.push(item.name)
})
const timeArray = Array.from(new Set(this.timeList))
console.log('nihc', timeArray)
for (const times of timeArray) {
if (times !== '投入数量' && times !== '产出数量' && times !== '报废数量' && times !== '产出面积') {
const subprop = {
label: times.slice(0, 10) + ' ' + times.slice(11),
align: 'center',
children: [
{ prop: times + '_in', label: '投入数量' },
{ prop: times + '_out', label: '产出数量' },
{ prop: times + '_junk', label: '报废数量' },
{ prop: times + '_area', label: '产出面积' }
]
}
this.arr.push(subprop)
}
}
this.tableProps = this.arr
},
setRowSpan(arr) {
let count = 0
arr.forEach((item, index) => {
if(index === 0) {
this.spanArr.push(1)
} else {
if (item === arr[index - 1]) {
this.spanArr[count] += 1
this.spanArr.push(0)
} else {
count = index
this.spanArr.push(1)
}
}
})
console.log('打印数组长度', this.spanArr)
},
/** 把 list 里的数据转换成 tableProps 对应的格式 */
convertList(list) {
let sectionArr= []
console.log('打印看下数据list', list)
list.forEach((ele, index) => {
let tempData = []
ele.data.forEach(item => {
item.children.forEach(params => {
if (params.dynamicName === '投入数量') {
tempData[item.dynamicName + '_in'] = params.dynamicValue
} else if (params.dynamicName === '产出数量') {
tempData[item.dynamicName + '_out'] = params.dynamicValue
} else if (params.dynamicName === '报废数量') {
tempData[item.dynamicName + '_junk'] = params.dynamicValue
} else {
tempData[item.dynamicName + '_area'] = params.dynamicValue
}
})
})
tempData['proLineName'] = ele.proLineName
tempData['spec'] = ele.spec
this.tableData.push(tempData)
console.log('看看数据', this.tableData, tempData)
const { proLineName } = tempData
sectionArr.push(proLineName)
})
this.setRowSpan(sectionArr)
console.log('工段名称列表', sectionArr)
},
buildData(data) {
this.convertList(data);
},
/** 合并table列的规则 */
mergeColumnHandler({ row, column, rowIndex, columnIndex }) {
if (columnIndex == 0) {
if (this.spanArr[rowIndex]) {
return [
this.spanArr[rowIndex], // row span
1, // col span
];
} else {
return [0, 0];
}
}
},
async getList() {
this.urlOptions.getDataListURL().then(res => {
console.log('看看数据', res)
this.arr = [
{
prop: 'proLineName',
label: '生产线',
fixed: 'left',
showOverflowTooltip: true
},
{
prop: 'spec',
label: '产品规格',
fixed: 'left',
showOverflowTooltip: true
}
]
this.buildProps(res.data.nameData);
this.buildData(res.data.data);
})
// // const data = this.res.data;
// // console.log('recent-24', data);
// this.initing = true;
// this.queryParams.pageSize = this.list.length;
// setTimeout(() => {
// this.initing = false;
// }, 1000);
},
handleEmitFun(payload) {
console.log('payload', payload);
},
},
};
</script>
<style scoped lang="scss">
::-webkit-scrollbar {
display: none;
}
pre {
margin: 10px;
background: #f6f8faf6;
border: 1px solid #e1e4e8;
padding: 12px;
border-radius: 12px;
position: fixed;
// top: 15vh;
top: 10vh;
left: 0;
max-height: 80vh;
overflow-y: auto;
z-index: 100000;
box-shadow: 0 0 32px 12px #0001;
}
code {
font-family: 'IntelOne Mono', 'Ubuntu', 'Courier New', Courier, monospace;
}
</style>

View File

@@ -1,23 +1,26 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-08-31 15:31:40
* @LastEditTime: 2023-10-16 15:19:04
* @LastEditors: DY
* @Description:
-->
<template>
<div class="app-container">
<!-- :isFold="true" 控制展开 -->
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:selectWidth="55"
:table-data="tableData"
:table-data="showData"
@selection-change="selectChange"
>
<method-btn
@@ -28,78 +31,81 @@
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<el-button type="primary" @click="exportXlsx">xlsx</el-button>
<el-button type="success" @click="exportPdf">pdf</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { parseTime } from '../../mixins/code-filter';
import {
getFactoryPage,
exportFactoryExcel,
} from '@/api/core/base/factory';
import { getWorkshopSectionList, getPdList, getSectionAutoReport } from '@/api/core/monitoring/sectionStatistics'
import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
const tableProps = [
{
prop: 'code',
label: '产线类型',
align: 'center',
prop: 'reportType',
label: '报表类型'
},
{
prop: 'createTime',
prop: 'reportStartTime',
label: '统计开始时间',
align: 'center',
filter: parseTime,
},
{
prop: 'createTime3',
prop: 'reportEndTime',
label: '统计结束时间',
align: 'center',
filter: parseTime,
},
{
prop: 'name',
label: '产线名称',
align: 'center',
prop: 'lineName',
label: '产线名称'
},
{
prop: 'name1',
label: '工段名称',
align: 'center',
prop: 'sectionName',
label: '工段名称'
},
{
prop: 'address',
label: '投入数量/片',
align: 'center',
prop: 'inputNum',
label: '投入数量/片'
},
{
prop: 'remark44',
label: '产出数量/片',
align: 'center',
prop: 'outputNum',
label: '产出数量/片'
},
{
prop: 'remark23',
label: '产出面积/㎡',
align: 'center',
prop: 'outputArea',
label: '产出面积/㎡'
},
{
prop: 'remark145',
label: '损耗数量/片',
align: 'center',
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'remark22',
label: '损耗面积/㎡',
align: 'center',
prop: 'lossArea',
label: '损耗面积/㎡'
},
{
prop: 'remark1',
label: '损耗比例%',
align: 'center',
prop: 'lossRatio',
label: '损耗比例%'
}
];
@@ -107,14 +113,7 @@ export default {
data() {
return {
urlOptions: {
getDataListURL: getFactoryPage,
exportURL: exportFactoryExcel,
},
urlOptions: {
getDataListURL: '',
deleteURL: '',
statusUrl: '',
exportURL: ''
getDataListURL: getSectionAutoReport
},
tableData: [],
listQuery: {
@@ -124,11 +123,15 @@ export default {
},
exportLoading: false,
dataListLoading: false,
selectedList: [],
dialogVisible: false,
addOrEditTitle: '',
addOrUpdateVisible: false,
tableProps,
tableBtn: [],
tableData: [],
showData: [],
fileName: '',
formConfig: [
{
type: 'select',
@@ -145,8 +148,21 @@ export default {
{
type: 'select',
label: '报表类型',
selectOptions: [],
param: 'name',
selectOptions: [
{
id: 1,
name: '日'
},
{
id: 2,
name: '周'
},
{
id: 3,
name: '月'
}
],
param: 'reportType',
},
{
type: 'datePicker',
@@ -158,8 +174,7 @@ export default {
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
defaultSelect: [],
width: 350
defaultSelect: []
},
{
type: 'button',
@@ -175,13 +190,114 @@ export default {
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
color: 'primary',
plain: true
}
],
};
},
created() {},
created() {
this.getDataList()
this.getPdLineList()
},
methods: {
test() {
var target = document.getElementsByClassName("right-aside")[0]
target.style.background = '#FFFFFF'
var that = this
setTimeout(() => {
html2canvas(target).then(function(canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度
var pageHeight = contentHeight / 592.28 * 841.89
// 未生成pdf的html页面高度
var leftHeight = contentHeight
// 页面偏移
var position = 0
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
console.log('nihc URL', leftHeight, pageHeight)
var pdf = new jsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight)
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.save(that.fileName + '工段统计.pdf')
})
}, 300)
},
exportECL() {
let tables = document.querySelector('.el-table').cloneNode(true)
const fix = tables.querySelector('.el-table__fixed')
const fixRight = tables.querySelector('.el-table__fixed-right')
if (fix) {
tables.removeChild(tables.querySelector('.el-table__fixed'))
}
if (fixRight) {
tables.removeChild(tables.querySelector('.el-table__fixed-right'))
}
let exportTable = XLSX.utils.table_to_book(tables)
var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx', bookSST: true, type: 'array'
})
// sheetjs.xlsx为导出表格的标题名称
try {
FileSaver.saveAs(new Blob([exportTableOut], {
type: 'application/octet-stream'
}), this.fileName + '工段统计.xlsx')
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut)
}
return exportTableOut
},
exportPdf() {
this.test()
setTimeout(() =>{
this.dialogVisible = false
this.showData = this.tableData
}, 600)
},
exportXlsx() {
this.exportECL()
this.dialogVisible = false
this.showData = this.tableData
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
getPdLineList() {
getPdList().then((res) => {
this.formConfig[0].selectOptions = res.data || []
})
// 获取工段list
getWorkshopSectionList().then((res) => {
this.formConfig[1].selectOptions = res.data || []
})
},
selectChange(val) {
console.log(val)
this.selectedList = val
@@ -191,8 +307,14 @@ export default {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name;
this.listQuery.code = val.code;
this.listQuery.lineId = val.line ? val.line : undefined;
this.listQuery.sectionId = val.section ? val.section : undefined;
this.listQuery.reportType = val.reportType ? val.reportType : undefined;
this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime()] : undefined;
this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
if (val.timeVal && val.timeVal.length > 0) {
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_'
}
this.getDataList();
break;
case 'export':
@@ -206,8 +328,12 @@ export default {
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data.list;
this.total = response.data.total;
this.tableData = response.data.list.map(item => {
item.reportType = item.reportType === 1 ? '日' : item.reportType === 2 ? '周' : '月'
return item
});
this.showData = this.tableData
this.listQuery.total = response.data.total;
this.dataListLoading = false;
});
},
@@ -223,17 +349,10 @@ export default {
this.getDataList();
},
handleExport() {
// 处理查询参数
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal.confirm('是否确认导出所有数据项?').then(() => {
this.exportLoading = true;
return this.urlOptions.exportURL(params);
}).then(response => {
this.$download.excel(response, '工厂.xls');
this.exportLoading = false;
}).catch(() => { });
if (this.selectedList.length > 0) {
this.showData = this.selectedList
}
this.dialogVisible = true
}
},
};

View File

@@ -3,61 +3,78 @@
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" />
<base-table
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:table-data="tableData" />
<!-- <pagination
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:selectWidth="55"
:table-data="showData"
@selection-change="selectChange"
/>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" /> -->
@pagination="getDataList" />
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<el-button type="primary" @click="exportXlsx">xlsx</el-button>
<el-button type="success" @click="exportPdf">pdf</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// import basicPage from '../../mixins/basic-page';
import { parseTime } from '../../mixins/code-filter';
import { getSectionDataSearch } from '@/api/core/monitoring';
import { getProductionLinePage } from '@/api/core/base/productionLine';
import { getWorkshopSectionPage } from '@/api/core/base/workshopSection';
import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
const tableProps = [
{
prop: 'proLineName',
label: '产线名称',
align: 'center',
label: '产线名称'
},
{
prop: 'sectionName',
label: '工段名称',
align: 'center',
label: '工段名称'
},
{
prop: 'inputNum',
label: '进片数量/片',
align: 'center',
label: '进片数量/片'
},
{
prop: 'outputNum',
label: '出片数量/片',
align: 'center',
label: '出片数量/片'
},
{
prop: 'lossNum',
label: '损耗数量/片',
align: 'center',
label: '损耗数量/片'
},
{
prop: 'lossArea',
label: '损耗面积/m²',
align: 'center',
label: '损耗面积/m²'
},
{
prop: 'lossRate',
label: '损耗比例/%',
align: 'center',
label: '损耗比例/%'
}
];
@@ -70,12 +87,18 @@ export default {
},
tableProps,
tableData: [],
showData: [],
selectedList: [],
listQuery: {
proLineId:undefined,
sectionId: undefined,
startTime: undefined,
endTime: undefined,
total: 0
},
dataListLoading: false,
dialogVisible: false,
fileName: [],
optionArrUrl: [getProductionLinePage, getWorkshopSectionPage],
formConfig: [
{
@@ -85,6 +108,7 @@ export default {
param: 'proLineId',
defaultSelect: '',
filterable: true,
onchange: true,
},
{
type: 'select',
@@ -107,15 +131,20 @@ export default {
},
{
type: 'button',
btnName: '搜索',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '导出',
name: 'export',
},
color: 'primary',
plain: true
}
],
};
},
@@ -123,9 +152,126 @@ export default {
},
created() {
this.getArr();
this.getDataList()
// this.getDataList()
},
methods: {
/** 根据产线获取工段 */
async getWorksectionById(lineId) {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listByParentId',
method: 'get',
params: {
id: lineId,
},
});
if (code == 0) {
this.formConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
handleSearchBarChanged({ param, value }) {
if (!value) {
this.formConfig[1].selectOptions = [];
return;
}
switch (param) {
case 'proLineId':
this.getWorksectionById(value);
break;
}
},
test() {
var target = document.getElementsByClassName("right-aside")[0]
target.style.background = '#FFFFFF'
var that = this
setTimeout(() => {
html2canvas(target).then(function(canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度
var pageHeight = contentHeight / 592.28 * 841.89
// 未生成pdf的html页面高度
var leftHeight = contentHeight
// 页面偏移
var position = 0
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
console.log('nihc URL', leftHeight, pageHeight)
var pdf = new jsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight)
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.save(that.fileName[0] + '-' + that.fileName[1] + '_工段统计.pdf')
})
}, 300)
},
exportECL() {
let tables = document.querySelector('.el-table').cloneNode(true)
const fix = tables.querySelector('.el-table__fixed')
const fixRight = tables.querySelector('.el-table__fixed-right')
if (fix) {
tables.removeChild(tables.querySelector('.el-table__fixed'))
}
if (fixRight) {
tables.removeChild(tables.querySelector('.el-table__fixed-right'))
}
let exportTable = XLSX.utils.table_to_book(tables)
var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx', bookSST: true, type: 'array'
})
// sheetjs.xlsx为导出表格的标题名称
try {
FileSaver.saveAs(new Blob([exportTableOut], {
type: 'application/octet-stream'
}), this.fileName[0] + '-' + this.fileName[1] + '_工段统计.xlsx')
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut)
}
return exportTableOut
},
exportPdf() {
this.test()
setTimeout(() =>{
this.dialogVisible = false
this.showData = this.tableData
}, 600)
},
exportXlsx() {
this.exportECL()
this.dialogVisible = false
this.showData = this.tableData
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
getArr() {
const params = {
page: 1,
@@ -143,9 +289,31 @@ export default {
// this.listQuery.endTime = '1693564257000'
this.urlOptions.getDataListURL(this.listQuery).then(res => {
this.tableData = res.data
// this.total = response.data.total;
this.listQuery.total = this.tableData.length;
this.dataListLoading = false;
this.showData = this.tableData;
});
},
// 每页数
sizeChangeHandle(val) {
this.listQuery.pageSize = val;
this.listQuery.pageNo = 1;
this.getDataList();
},
// 当前页
currentChangeHandle(val) {
this.listQuery.pageNo = val;
this.getDataList();
},
handleExport() {
if (this.selectedList.length > 0) {
this.showData = this.selectedList
}
this.dialogVisible = true
},
selectChange(val) {
console.log(val)
this.selectedList = val
},
buttonClick(val) {
console.log(val)
@@ -159,7 +327,16 @@ export default {
this.listQuery.sectionId = val.sectionId ? val.sectionId : undefined
this.listQuery.startTime = val.timeSlot ? new Date(val.timeSlot[0]).getTime() : undefined
this.listQuery.endTime = val.timeSlot ? new Date(val.timeSlot[1]).getTime() : undefined
this.getDataList();
if (val.timeSlot && val.timeSlot.length > 0) {
this.fileName[0] = val.timeSlot[0].slice(0, 10)
this.fileName[1] = val.timeSlot[1].slice(0, 10)
this.getDataList()
} else {
this.$message({
message: '请选择时间',
type: 'warning'
});
}
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
@@ -170,6 +347,16 @@ export default {
};
this.getDataList();
break;
case 'export':
if (val.timeSlot && val.timeSlot.length > 0) {
this.handleExport();
} else {
this.$message({
message: '请选择时间',
type: 'warning'
});
}
break;
default:
console.log(val);
}

View File

@@ -25,6 +25,10 @@ export default {
default: () => {
return []
}
},
timeDim: {
type: String,
default: ''
}
},
watch: {
@@ -58,32 +62,78 @@ export default {
tempArr = this.chartData[0].trendRespVOList
}
for (let k = 0; k < tempArr.length; k++) {
xData.push(tempArr[k].time)
let time = ''
if (this.timeDim === '3') {
let year = tempArr[k].time.slice(0,4)
let weak = tempArr[k].time.slice(4,6)
time = year+' 第 '+weak+' 周'
} else {
time = tempArr[k].time
}
xData.push(time)
}
for (let i = 0; i < this.chartData.length; i++) {
let obj = {
name: this.chartData[i].objName + this.chartData[i].objCode,
type: 'bar',
barMaxWidth: 20,
label: {
show: true,
position: 'top'
},
data: []
}
legendData.push(this.chartData[i].objName + this.chartData[i].objCode)
let temp = this.chartData[i].trendRespVOList
for (let j = 0; j < temp.length; j++) {
let num = temp[j].useNum ? temp[j].useNum : 0
let num = temp[j].useNum ? temp[j].useNum : ''
obj.data.push(num)
}
yData.push(obj)
}
var option = {
color:['#FFDC94','#8EF0AB','#63BDFF','#288AFF','#7164FF'],
tooltip: {
trigger: 'axis'
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
return (
params[0].axisValue +
`<br>` +
params.map((item) => {
let str = `<span style="display:inline-block;width:8px;height:8px;margin: 0 8px 0 -3px;border-radius:2px;background-color:${item.color};"></span>`
let seriesNameStr = `<span style="display:inline-block;">${item.seriesName}</span>`
let value = item.value ? item.value : '-'
let valueStr = `<span style="display:inline-block;margin-left:10px;color:rgba(0,0,0,0.45);">${value}</span>`
return `<span style="display:flex; justify-content:space-between; margin-bottom: 2px">
<span>${str}${seriesNameStr}</span>
<span>${valueStr}</span>
</span>`
}).join(``)
)
}
},
grid: {
left: '4%',
right: '1%',
bottom: '1%',
containLabel: true
},
legend: {
data: legendData
data: legendData,
right: '1%',
icon: 'rect',
itemHeight: 8,
itemWidth: 8
},
xAxis: {
type: 'category',
data: xData
data: xData,
axisLabel: {
rotate: "45"
}
},
yAxis: {
type: 'value'

View File

@@ -25,6 +25,10 @@ export default {
default: () => {
return []
}
},
timeDim: {
type: String,
default: ''
}
},
watch: {
@@ -58,7 +62,15 @@ export default {
tempArr = this.chartData[0].trendRespVOList
}
for (let k = 0; k < tempArr.length; k++) {
xData.push(tempArr[k].time)
let time = ''
if (this.timeDim === '3') {
let year = tempArr[k].time.slice(0,4)
let weak = tempArr[k].time.slice(4,6)
time = year+' 第 '+weak+' 周'
} else {
time = tempArr[k].time
}
xData.push(time)
}
for (let i = 0; i < this.chartData.length; i++) {
let obj = {
@@ -70,22 +82,36 @@ export default {
legendData.push(this.chartData[i].objName + this.chartData[i].objCode)
let temp = this.chartData[i].trendRespVOList
for (let j = 0; j < temp.length; j++) {
let num = temp[j].useNum ? temp[j].useNum : 0
let num = temp[j].useNum ? temp[j].useNum : ''
obj.data.push(num)
}
yData.push(obj)
}
var option = {
color:['#FFDC94','#8EF0AB','#63BDFF','#288AFF','#7164FF'],
tooltip: {
trigger: 'axis'
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
grid: {
left: '4%',
right: '1%',
bottom: '1%',
containLabel: true
},
legend: {
data: legendData
data: legendData,
right: '1%'
},
xAxis: {
type: 'category',
data: xData
data: xData,
axisLabel: {
rotate: "45"
}
},
yAxis: {
type: 'value'

View File

@@ -1,7 +1,9 @@
<template>
<div class="searchBarBox divHeight" ref="searchBarRef" :style="{ paddingRight: isFold ? '55px' : '0px' }">
<el-form :inline="true" class="demo-form-inline">
<span class="blue-block"></span>
<el-form-item label="能源类型">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择" style="width: 100px;">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择" style="width: 100px;" size="small">
<el-option
v-for="item in energyTypeList"
:key="item.id"
@@ -11,7 +13,7 @@
</el-select>
</el-form-item>
<el-form-item label="时间维度">
<el-select v-model="queryParams.timeDim" placeholder="请选择" style="width: 80px;">
<el-select v-model="queryParams.timeDim" placeholder="请选择" style="width: 80px;" size="small">
<el-option
v-for="item in getDictDatas(this.DICT_TYPE.TIME_DIM)"
:key="item.value"
@@ -33,6 +35,8 @@
:picker-options="pickerOptions"
popper-class="noneMinute"
@change="timeSelect"
size="small"
style='width:350px;'
:clearable="false"
>
</el-date-picker>
@@ -47,6 +51,8 @@
value-format="timestamp"
:picker-options="pickerOptions"
:clearable="false"
size="small"
style='width:350px;'
@change="timeSelect"
>
</el-date-picker>
@@ -56,10 +62,11 @@
v-model="weekValue1"
type="week"
format="yyyy 第 WW 周"
style='width:150px;'
style='width:170px;'
:picker-options="pickerOptionsWeek"
@change="startWeek"
:clearable="false"
size="small"
placeholder="选择周">
</el-date-picker>-
<el-date-picker
@@ -67,9 +74,10 @@
type="week"
format="yyyy 第 WW 周"
:picker-options="pickerOptionsWeek"
style='width:150px;'
style='width:170px;'
@change="endWeek"
:clearable="false"
size="small"
placeholder="选择周">
</el-date-picker>
</div>
@@ -83,37 +91,41 @@
value-format="timestamp"
:clearable="false"
:picker-options="pickerOptions"
size="small"
style='width:350px;'
@change="timeSelect"
>
</el-date-picker>
</div>
<div v-show="queryParams.timeDim === '5'">
<el-date-picker
style='width:100px;'
style='width:170px;'
v-model="yearValue1"
type="year"
:picker-options="pickerOptions"
value-format="timestamp"
placeholder="选择年"
@change="startYear"
size="small"
:clearable="false"
>
</el-date-picker>-
<el-date-picker
style='width:100px;'
style='width:170px;'
v-model="yearValue2"
type="year"
:picker-options="pickerOptions"
value-format="timestamp"
placeholder="选择年"
@change="endYear"
size="small"
:clearable="false"
>
</el-date-picker>
</div>
</el-form-item>
<el-form-item label="对象维度">
<el-select v-model="queryParams.objType" placeholder="请选择" style="width: 80px;" @change="selectObjs">
<el-select v-model="queryParams.objType" placeholder="请选择" style="width: 80px;" @change="selectObjs" size="small">
<el-option
v-for="item in getDictDatas(this.DICT_TYPE.OBJECT_TYPE)"
:key="item.value"
@@ -123,7 +135,7 @@
</el-select>
</el-form-item>
<el-form-item label="对象选择">
<el-select v-model="queryParams.objIds" placeholder="请选择" multiple collapse-tags style="width: 200px;">
<el-select v-model="queryParams.objIds" placeholder="请选择" multiple :multiple-limit='5' collapse-tags style="width: 200px;" size="small">
<el-option
v-for="item in objectList"
:key="item.id"
@@ -135,9 +147,14 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="primary" size="small" @click="search">查询</el-button>
</el-form-item>
</el-form>
<span v-if="isFold" class="foldClass" @click='switchMode'>
{{ isExpand ? '收起' : '展开' }}
<svg-icon :icon-class="isExpand ? 'upward' : 'downward'" />
</span>
</div>
</template>
<script>
import { getEnergyTypeListAll } from "@/api/base/energyType"
@@ -147,8 +164,15 @@ import { getEquipmentAll } from "@/api/base/equipment"
import moment from 'moment'
export default {
name: 'searchArea',
props: {
isFold: {// 多行模式(默认否)
type: Boolean,
default: false
}
},
data() {
return {
isExpand: false, // 展开收起
// 查询参数
queryParams: {
energyTypeId: null,
@@ -388,11 +412,20 @@ export default {
let newData = year+'-12-31 23:59:59'
let value = new Date(newData).getTime()
return value
},
switchMode() {// 展开和收起切换
this.isExpand = !this.isExpand
const element = this.$refs.searchBarRef
if (this.isExpand) {
element.classList.remove('divHeight')
} else {
element.classList.add('divHeight')
}
}
}
}
</script>
<style>
<style lang='scss'>
/* 时间整点 */
.noneMinute .el-time-spinner__wrapper {
width: 100%;
@@ -400,4 +433,42 @@ export default {
.noneMinute .el-scrollbar:nth-of-type(2) {
display: none;
}
.demo-form-inline {
.el-date-editor .el-range__icon {
font-size: 16px;
color: #0B58FF;
}
.el-input__prefix .el-icon-date {
font-size: 16px;
color: #0B58FF;
}
}
</style>
<style lang="scss" scoped>
.demo-form-inline {
.blue-block {
display: inline-block;
width: 4px;
height: 16px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
margin-top: 12px;
}
}
.searchBarBox .foldClass {
position: absolute;
top: 14px;
right: 0;
cursor: pointer;
font-size: 12px;
color:#0B58FF;
}
.searchBarBox .foldClass .iconfont {
font-size: 14px;
}
.divHeight {
height: 45px;
overflow: hidden;
}
</style>

View File

@@ -1,15 +1,17 @@
<template>
<div class="app-container">
<div class="app-container contrastAnalysisBox" id="contrastAnalysisBox">
<!-- 搜索工作栏 -->
<search-area @submit="getList"/>
<el-tabs v-model="activeName" @tab-click="switchChart">
<search-area :isFold="isFold" @submit="getList"/>
<el-tabs v-model="activeName" @tab-click="switchChart" v-show='chartData.length'>
<el-tab-pane label="柱状图" name="bar">
<bar-chart ref="analysisBarChart" :chartData="chartData" />
<bar-chart ref="analysisBarChart" :chartData="chartData" :timeDim="timeDim" />
</el-tab-pane>
<el-tab-pane label="折线图" name="line">
<line-chart ref="analysisLineChart" :chartData="chartData"/>
<line-chart ref="analysisLineChart" :chartData="chartData" :timeDim="timeDim"/>
</el-tab-pane>
</el-tabs>
<!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div>
</div>
</template>
<script>
@@ -23,13 +25,23 @@ export default {
components: { SearchArea, BarChart, LineChart },
data() {
return {
isFold: false,
activeName: 'bar',
chartData: []
chartData: [],
timeDim: ''
}
},
mounted() {},
mounted() {
window.addEventListener('resize', () => {
this.tableH = this.tableHeight(260)
this.isFold = this.searchBarWidth('contrastAnalysisBox', 1310)
// console.log(document.getElementById("contrastAnalysisBox").offsetWidth)
})
this.isFold = this.searchBarWidth('contrastAnalysisBox', 1310)
},
methods: {
getList(params) {
this.timeDim = params.timeDim
getCompare({ ...params }).then((res) => {
console.log(res)
if (res.code === 0) {
@@ -53,3 +65,32 @@ export default {
}
}
</script>
<style lang='scss'>
.contrastAnalysisBox {
.el-tabs__nav::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background-color: #e4e7ed;
/* z-index: 1; */
}
.el-tabs__nav-wrap::after {
width: 0;
}
.el-tabs__item {
padding: 0 10px;
}
.el-tabs__item:hover {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item.is-active {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item {
color: rgba(0, 0, 0, 0.45);
}
}
</style>

View File

@@ -15,7 +15,7 @@ export default {
return {
chartDom: '',
chart: '',
chartHeight: this.tableHeight(350)
chartHeight: this.tableHeight(370)
}
},
props: {
@@ -34,7 +34,7 @@ export default {
},
mounted() {
window.addEventListener('resize', () => {
this.chartHeight = this.tableHeight(350)
this.chartHeight = this.tableHeight(370)
})
},
methods: {
@@ -57,12 +57,22 @@ export default {
{
name: '本期',
type: 'bar',
data: []
data: [],
barWidth: 20,
label: {
show: true,
position: 'top'
}
},
{
name: '上期',
type: 'bar',
data: []
data: [],
barWidth: 20,
label: {
show: true,
position: 'top'
}
}
]
for (let j = 0; j < arr.length; j++) {
@@ -76,19 +86,38 @@ export default {
}
}
var option = {
// title: {
// text: 'World Population'
// },
color:['#288AFF','#8EF0AB'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
return (
params[0].axisValue +
`<br>` +
params.map((item) => {
let str = `<span style="display:inline-block;width:8px;height:8px;margin: 0 8px 0 -3px;border-radius:2px;background-color:${item.color};"></span>`
let seriesNameStr = `<span style="display:inline-block;">${item.seriesName}</span>`
let value = item.value ? item.value : '-'
let valueStr = `<span style="display:inline-block;margin-left:10px;color:rgba(0,0,0,0.45);">${value}</span>`
return `<span style="display:flex; justify-content:space-between; margin-bottom: 2px">
<span>${str}${seriesNameStr}</span>
<span>${valueStr}</span>
</span>`
}).join(``)
)
}
},
legend: {},
legend: {
right: '1%',
icon: 'rect',
itemHeight: 8,
itemWidth: 8
},
grid: {
left: '3%',
right: '4%',
left: '1%',
right: '1%',
bottom: '3%',
containLabel: true
},

View File

@@ -1,15 +1,18 @@
<template>
<el-form :inline="true" class="demo-form-inline">
<span class="blue-block"></span>
<el-form-item label="对象选择">
<el-cascader
v-model="objArr"
:options="objList"
:props="{ checkStrictly: true, value: 'id', label: 'name' }"
popper-class="cascaderParent"
size="small"
style="width: 250px;"
clearable></el-cascader>
</el-form-item>
<el-form-item label="时间维度">
<el-select v-model="queryParams.type" placeholder="请选择" style="width: 80px;">
<el-select v-model="queryParams.type" placeholder="请选择" style="width: 80px;" size="small">
<el-option
v-for="item in timeType"
:key="item.id"
@@ -27,6 +30,7 @@
:picker-options="pickerOptions"
@change="selectTime"
:clearable="false"
size="small"
placeholder="选择月">
</el-date-picker>
</div>
@@ -38,6 +42,7 @@
:picker-options="pickerOptionsWeek"
@change="selectTime"
:clearable="false"
size="small"
placeholder="选择周">
</el-date-picker>
</div>
@@ -48,18 +53,19 @@
:picker-options="pickerOptions"
@change="selectTime"
:clearable="false"
size="small"
placeholder="选择日">
</el-date-picker>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="primary" size="small" @click="search">查询</el-button>
</el-form-item>
<el-form-item>
<span class="separateStyle"></span>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="exportData" plain>导出</el-button>
<el-button type="primary" size="small" @click="exportData" plain>导出</el-button>
</el-form-item>
</el-form>
</template>
@@ -152,7 +158,31 @@ export default {
this.$emit('submit', this.queryParams)
},
exportData() {
this.$emit('exportD')
let name
if (this.queryParams.objId) {
name = this.getObjName(this.objList, this.queryParams.objId)
} else {
this.$modal.msgWarning("对象不能为空")
return false
}
this.$emit('exportD', {name: name})
},
// 递归取对象name
getObjName(list, id) {
let _this = this
for (let i = 0; i < list.length; i++) {
let a = list[i]
if (a.id === id) {
return a.name
} else {
if (a.children && a.children.length > 0) {
let res = _this.getObjName(a.children, id)
if (res) {
return res
}
}
}
}
},
transformTime(timeStamp) {// 本月最后一天
let year = moment(timeStamp).format('YYYY')
@@ -164,13 +194,23 @@ export default {
}
}
</script>
<style>
<style lang='scss'>
/* 级联选择器 */
.cascaderParent .el-cascader-panel .el-scrollbar:first-child .el-radio {
display: none;
}
.demo-form-inline {
.el-date-editor .el-range__icon {
font-size: 16px;
color: #0B58FF;
}
.el-input__prefix .el-icon-date {
font-size: 16px;
color: #0B58FF;
}
}
</style>
<style scoped>
<style lang="scss" scoped>
.separateStyle {
display: inline-block;
width: 1px;
@@ -178,4 +218,15 @@ export default {
background: #E8E8E8;
vertical-align: middle;
}
.demo-form-inline {
.blue-block {
display: inline-block;
width: 4px;
height: 16px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
margin-top: 10px;
}
}
</style>

View File

@@ -3,15 +3,20 @@
<!-- 搜索工作栏 -->
<search-area @submit="getList" @exportD="exportData"/>
<!-- 表格 -->
<div v-show="chartData.length">
<base-table
:table-props="tableProps"
:table-data="list"
class="qoq-out-table"
/>
<div style='width: 100%;height: 300px;padding-top: 30px;'>
<div class="chartTitle">环比分析图</div>
<div style='width: 100%'>
<line-chart ref="analysisLineChart" :chartData="chartData"/>
</div>
</div>
<!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div>
</div>
</template>
<script>
import { getQoq } from "@/api/analysis/energyAnalysis"
@@ -83,9 +88,10 @@ export default {
}
this.chartData = this.list
},
exportData() {
exportData(val) {
if (this.list.length > 0) {
var wb = XLSX.utils.table_to_book(document.querySelector(".qoq-out-table"))
let fileName = val.name + "环比分析.xlsx"
var wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
@@ -94,7 +100,7 @@ export default {
try {
FileSaver.saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
"环比分析.xlsx"
fileName
)
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
@@ -107,3 +113,20 @@ export default {
}
}
</script>
<style lang='scss' scoped>
.chartTitle {
font-size: 16px;
color: #000;
margin-top: 20px;
}
.chartTitle::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
vertical-align: bottom;
}
</style>

View File

@@ -25,6 +25,10 @@ export default {
default: () => {
return []
}
},
timeDim: {
type: String,
default: ''
}
},
watch: {
@@ -51,13 +55,31 @@ export default {
let xData = []
let yData = []
for (let i = 0; i < this.chartData.length; i++) {
xData.push(this.chartData[i].time)
let time = ""
if (this.timeDim === '3') {
let year = this.chartData[i].time.slice(0,4)
let weak = this.chartData[i].time.slice(4,6)
time = year+' 第 '+weak+' 周'
} else {
time = this.chartData[i].time
}
xData.push(time)
yData.push(this.chartData[i].useNum)
}
var option = {
color:['#288AFF'],
grid: {
left: '4%',
right: '1%',
bottom: '1%',
containLabel: true
},
xAxis: {
type: 'category',
data: xData
data: xData,
axisLabel: {
rotate: "45"
}
},
yAxis: {
type: 'value'
@@ -65,7 +87,12 @@ export default {
series: [
{
data: yData,
type: 'bar'
type: 'bar',
barMaxWidth: 20,
label: {
show: true,
position: 'top'
}
}
]
};

View File

@@ -8,6 +8,7 @@
<script>
import * as echarts from 'echarts'
import resize from '@/utils/chartMixins/resize'
import moment from 'moment'
export default {
name: "LineChart",
mixins: [resize],
@@ -25,6 +26,10 @@ export default {
default: () => {
return []
}
},
timeDim: {
type: String,
default: ''
}
},
watch: {
@@ -51,14 +56,35 @@ export default {
let xData = []
let yData = []
for (let i = 0; i < this.chartData.length; i++) {
xData.push(this.chartData[i].time)
let time = ""
if (this.timeDim === '3') {
let year = this.chartData[i].time.slice(0,4)
let weak = this.chartData[i].time.slice(4,6)
time = year+' 第 '+weak+' 周'
} else {
time = this.chartData[i].time
}
xData.push(time)
yData.push(this.chartData[i].useNum)
}
var option = {
color:['#288AFF'],
// tooltip: {
// trigger: 'axis'
// },
grid: {
left: '4%',
right: '1%',
bottom: '1%',
containLabel: true
},
xAxis: {
type: 'category',
data: xData
data: xData,
axisLabel: {
rotate: "45"
}
},
yAxis: {
type: 'value'

View File

@@ -1,7 +1,9 @@
<template>
<div class="searchBarBox divHeight" ref="searchBarRef" :style="{ paddingRight: isFold ? '55px' : '0px' }">
<el-form :inline="true" class="demo-form-inline">
<span class="blue-block"></span>
<el-form-item label="能源类型">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择" style="width: 100px;">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择" style="width: 100px;" size="small">
<el-option
v-for="item in energyTypeList"
:key="item.id"
@@ -16,15 +18,17 @@
:options="objList"
:props="{ checkStrictly: true, value: 'id', label: 'name' }"
popper-class="cascaderParent"
size="small"
clearable></el-cascader>
</el-form-item>
<el-form-item label="时间维度">
<el-select v-model="queryParams.timeDim" placeholder="请选择" style="width: 80px;">
<el-select v-model="queryParams.timeDim" placeholder="请选择" style="width: 80px;" size="small">
<el-option
v-for="item in getDictDatas(this.DICT_TYPE.TIME_DIM)"
:key="item.value"
:label="item.label"
:value="item.value">
:value="item.value"
size="small">
</el-option>
</el-select>
</el-form-item>
@@ -41,6 +45,8 @@
:picker-options="pickerOptions"
popper-class="noneMinute"
@change="timeSelect"
size="small"
style='width:350px;'
>
</el-date-picker>
</div>
@@ -54,6 +60,8 @@
value-format="timestamp"
:picker-options="pickerOptions"
@change="timeSelect"
size="small"
style='width:350px;'
>
</el-date-picker>
</div>
@@ -62,9 +70,10 @@
v-model="weekValue1"
type="week"
format="yyyy 第 WW 周"
style='width:150px;'
style='width:170px;'
:picker-options="pickerOptionsWeek"
@change="startWeek"
size="small"
placeholder="选择周">
</el-date-picker>-
<el-date-picker
@@ -72,8 +81,9 @@
type="week"
format="yyyy 第 WW 周"
:picker-options="pickerOptionsWeek"
style='width:150px;'
style='width:170px;'
@change="endWeek"
size="small"
placeholder="选择周">
</el-date-picker>
</div>
@@ -86,37 +96,46 @@
end-placeholder="结束日期"
value-format="timestamp"
:picker-options="pickerOptions"
size="small"
style='width:350px;'
@change="timeSelect"
>
</el-date-picker>
</div>
<div v-show="queryParams.timeDim === '5'">
<el-date-picker
style='width:100px;'
style='width:170px;'
v-model="yearValue1"
type="year"
:picker-options="pickerOptions"
value-format="timestamp"
placeholder="选择年"
size="small"
@change="startYear"
>
</el-date-picker>-
<el-date-picker
style='width:100px;'
style='width:170px;'
v-model="yearValue2"
type="year"
:picker-options="pickerOptions"
value-format="timestamp"
placeholder="选择年"
size="small"
@change="endYear"
>
</el-date-picker>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="primary" size="small" @click="search">查询</el-button>
</el-form-item>
</el-form>
<span v-if="isFold" class="foldClass" @click='switchMode'>
{{ isExpand ? '收起' : '展开' }}
<svg-icon :icon-class="isExpand ? 'upward' : 'downward'" />
</span>
</div>
</template>
<script>
import { getEnergyTypeListAll } from "@/api/base/energyType"
@@ -124,8 +143,15 @@ import { getTree } from '@/api/base/factory'
import moment from 'moment'
export default {
name: 'searchArea',
props: {
isFold: {// 多行模式(默认否)
type: Boolean,
default: false
}
},
data() {
return {
isExpand: false, // 展开收起
// 查询参数
queryParams: {
energyTypeId: null,
@@ -162,6 +188,7 @@ export default {
this.getTypeList()
this.getObjTree()
this.queryParams.timeDim = this.getDictDatas(this.DICT_TYPE.TIME_DIM)[0].value // 默认时
this.timeValue = [moment().startOf('day'), moment().endOf('day')-59*61*1000]
},
methods: {
getTypeList() {
@@ -266,7 +293,7 @@ export default {
this.$modal.msgError('请选择能源类型')
return false
}
if (!this.objArr.length === 0) {
if (this.objArr.length === 0) {
this.$modal.msgError('请选择对象')
return false
} else {
@@ -345,11 +372,20 @@ export default {
let newData = year+'-12-31 23:59:59'
let value = new Date(newData).getTime()
return value
},
switchMode() {// 展开和收起切换
this.isExpand = !this.isExpand
const element = this.$refs.searchBarRef
if (this.isExpand) {
element.classList.remove('divHeight')
} else {
element.classList.add('divHeight')
}
}
}
}
</script>
<style>
<style lang='scss'>
/* 级联选择器 */
.cascaderParent .el-cascader-panel .el-scrollbar:first-child .el-radio {
display: none;
@@ -361,4 +397,42 @@ export default {
.noneMinute .el-scrollbar:nth-of-type(2) {
display: none;
}
.demo-form-inline {
.el-date-editor .el-range__icon {
font-size: 16px;
color: #0B58FF;
}
.el-input__prefix .el-icon-date {
font-size: 16px;
color: #0B58FF;
}
}
</style>
<style lang="scss" scoped>
.demo-form-inline {
.blue-block {
display: inline-block;
width: 4px;
height: 16px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
margin-top: 12px;
}
}
.searchBarBox .foldClass {
position: absolute;
top: 14px;
right: 0;
cursor: pointer;
font-size: 12px;
color:#0B58FF;
}
.searchBarBox .foldClass .iconfont {
font-size: 14px;
}
.divHeight {
height: 45px;
overflow: hidden;
}
</style>

View File

@@ -1,15 +1,17 @@
<template>
<div class="app-container">
<div class="app-container trendAnalysisBox" id="trendAnalysisBox">
<!-- 搜索工作栏 -->
<search-area @submit="getList"/>
<el-tabs v-model="activeName" @tab-click="switchChart">
<search-area :isFold="isFold" @submit="getList"/>
<el-tabs v-model="activeName" @tab-click="switchChart" v-show='chartData.length'>
<el-tab-pane label="柱状图" name="bar">
<bar-chart ref="analysisBarChart" :chartData="chartData" />
<bar-chart ref="analysisBarChart" :chartData="chartData" :timeDim="timeDim"/>
</el-tab-pane>
<el-tab-pane label="折线图" name="line">
<line-chart ref="analysisLineChart" :chartData="chartData"/>
<line-chart ref="analysisLineChart" :chartData="chartData" :timeDim="timeDim"/>
</el-tab-pane>
</el-tabs>
<!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div>
</div>
</template>
<script>
@@ -23,13 +25,22 @@ export default {
components: { SearchArea, BarChart, LineChart },
data() {
return {
isFold: false,
activeName: 'bar',
chartData: []
chartData: [],
timeDim: ''
}
},
mounted() {},
mounted() {
window.addEventListener('resize', () => {
this.tableH = this.tableHeight(260)
this.isFold = this.searchBarWidth('trendAnalysisBox', 1146)
})
this.isFold = this.searchBarWidth('trendAnalysisBox', 1146)
},
methods: {
getList(params) {
this.timeDim = params.timeDim
getEnergyTrend({ ...params }).then((res) => {
if (res.code === 0) {
this.chartData = res.data
@@ -37,16 +48,6 @@ export default {
this.chartData = []
}
})
// getEnergyTrend({
// energyTypeId: "1681183397517406210",
// objId: "1679031282510532610",
// timeDim: "2",
// startTime: "1690732800000",
// endTime: "1690992000000"
// }).then((res) => {
// console.log(res)
// this.chartData = res.data
// })
},
switchChart() {
if (this.activeName === 'bar') {
@@ -62,3 +63,32 @@ export default {
}
}
</script>
<style lang='scss'>
.trendAnalysisBox {
.el-tabs__nav::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background-color: #e4e7ed;
/* z-index: 1; */
}
.el-tabs__nav-wrap::after {
width: 0;
}
.el-tabs__item {
padding: 0 10px;
}
.el-tabs__item:hover {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item.is-active {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item {
color: rgba(0, 0, 0, 0.45);
}
}
</style>

View File

@@ -75,15 +75,17 @@ export default {
}
}
var option = {
color:['#FFDC94','#8EF0AB','#63BDFF','#288AFF','#7164FF','#FF6860','#FF9747','#B0EB42','#D680FF','#0043D2'],
legend: {
data: keys
data: keys,
right:'1%'
},
tooltip: {
trigger: 'axis'
},
grid: {
left: '3%',
right: '4%',
left: '1%',
right: '1%',
bottom: '3%',
containLabel: true
},

View File

@@ -1,15 +1,17 @@
<template>
<el-form :inline="true" class="demo-form-inline">
<span class="blue-block"></span>
<el-form-item label="对象选择">
<el-cascader
v-model="objArr"
:options="objList"
:props="{ checkStrictly: true, value: 'id', label: 'name' }"
popper-class="cascaderParent"
size="small"
clearable></el-cascader>
</el-form-item>
<el-form-item label="时间维度">
<el-select v-model="queryParams.type" placeholder="请选择" style="width: 80px;">
<el-select v-model="queryParams.type" placeholder="请选择" style="width: 80px;" size="small">
<el-option
v-for="item in timeType"
:key="item.id"
@@ -27,6 +29,7 @@
:picker-options="pickerOptions"
@change="selectTime"
:clearable="false"
size="small"
placeholder="选择年">
</el-date-picker>
</div>
@@ -37,18 +40,19 @@
:picker-options="pickerOptions"
@change="selectTime"
:clearable="false"
size="small"
placeholder="选择月">
</el-date-picker>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="primary" size="small" @click="search">查询</el-button>
</el-form-item>
<el-form-item>
<span class="separateStyle"></span>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="exportData" plain>导出</el-button>
<el-button type="primary" size="small" @click="exportData" plain>导出</el-button>
</el-form-item>
</el-form>
</template>
@@ -121,7 +125,31 @@ export default {
this.$emit('submit', this.queryParams)
},
exportData() {
this.$emit('exportD')
let name
if (this.queryParams.objId) {
name = this.getObjName(this.objList, this.queryParams.objId)
} else {
this.$modal.msgWarning("对象不能为空")
return false
}
this.$emit('exportD', {name: name})
},
// 递归取对象name
getObjName(list, id) {
let _this = this
for (let i = 0; i < list.length; i++) {
let a = list[i]
if (a.id === id) {
return a.name
} else {
if (a.children && a.children.length > 0) {
let res = _this.getObjName(a.children, id)
if (res) {
return res
}
}
}
}
},
transformTime(timeStamp) {// 本月最后一天
let year = moment(timeStamp).format('YYYY')
@@ -139,13 +167,34 @@ export default {
}
}
</script>
<style>
<style lang='scss'>
/* 级联选择器 */
.cascaderParent .el-cascader-panel .el-scrollbar:first-child .el-radio {
display: none;
}
.demo-form-inline {
.el-date-editor .el-range__icon {
font-size: 16px;
color: #0B58FF;
}
.el-input__prefix .el-icon-date {
font-size: 16px;
color: #0B58FF;
}
}
</style>
<style scoped>
<style lang="scss" scoped>
.demo-form-inline {
.blue-block {
display: inline-block;
width: 4px;
height: 16px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
margin-top: 10px;
}
}
.separateStyle {
display: inline-block;
width: 1px;

View File

@@ -0,0 +1,18 @@
<template>
<div>
<svg-icon icon-class="upArrow" v-show='injectData[injectData.prop] > 0'/>
<svg-icon icon-class="downArrow" v-show='injectData[injectData.prop] < 0'/>
<span style="margin-left: 5px;">{{ injectData[injectData.prop] }}</span>
</div>
</template>
<script>
export default {
name: 'subRate',
props: {
injectData: {
type: Object,
default: () => ({})
}
}
}
</script>

View File

@@ -2,7 +2,9 @@
<div class="app-container">
<!-- 搜索工作栏 -->
<search-area @submit="getList" @exportD="exportData"/>
<div style='width: 100%;height: 300px;'>
<div v-show='chartData.length'>
<div class="chartTitle">同比分析图</div>
<div style='width: 100%;height: 400px;'>
<line-chart ref="analysisLineChart" :chartData="chartData"/>
</div>
<!-- 表格 -->
@@ -13,9 +15,13 @@
class="yoy-out-table"
/>
</div>
<!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div>
</div>
</template>
<script>
import { getYoy } from "@/api/analysis/energyAnalysis"
import subRate from "./components/subRate.vue"
import SearchArea from "./components/searchArea"
import LineChart from "./components/lineChart"
import FileSaver from "file-saver"
@@ -28,12 +34,12 @@ export default {
chartData: [],
tableProps: [],
list: [],
tableH: this.tableHeight(500)
tableH: this.tableHeight(640)
}
},
mounted() {
window.addEventListener('resize', () => {
this.tableH = this.tableHeight(500)
this.tableH = this.tableHeight(640)
})
},
methods: {
@@ -65,11 +71,15 @@ export default {
let obj = {}
obj.prop = tempX[j].prop + '_' + nameData[i].name
obj.label = nameData[i].name
if (obj.label.indexOf('同比')!= -1) {
obj.subcomponent = subRate
}
tempX[j].children.push(obj)
}
}
}
this.tableProps = [{prop: 'time',label: '时间'}].concat(tempX)
console.log(this.tableProps)
// 数据
this.list = []
for (let k = 0; k < data.length; k++) {
@@ -90,9 +100,10 @@ export default {
}
this.chartData = this.list
},
exportData() {
exportData(val) {
if (this.list.length > 0) {
var wb = XLSX.utils.table_to_book(document.querySelector(".yoy-out-table"))
let fileName = val.name + "同比分析.xlsx"
var wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
@@ -101,7 +112,7 @@ export default {
try {
FileSaver.saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
"同比分析.xlsx"
fileName
)
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
@@ -114,3 +125,19 @@ export default {
}
}
</script>
<style lang='scss' scoped>
.chartTitle {
font-size: 16px;
color: #000;
}
.chartTitle::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background-color: #0B58FF;
border-radius: 1px;
margin-right: 8px;
vertical-align: bottom;
}
</style>

Some files were not shown because too many files have changed in this diff Show More